#include "shared.h"
void word_ram_0_dma_w(unsigned int words)
{
uint16 data;
uint16 src_index = cdc.dac.w & 0x3ffe;
uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x1fffe;
scd.regs[0x0a>>1].w += (words >> 2);
cdc.dac.w += (words << 1);
while (words--)
{
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
*(uint16 *)(scd.word_ram[0] + dst_index) = data ;
src_index = (src_index + 2) & 0x3ffe;
dst_index = (dst_index + 2) & 0x1fffe;
}
}
void word_ram_1_dma_w(unsigned int words)
{
uint16 data;
uint16 src_index = cdc.dac.w & 0x3ffe;
uint32 dst_index = ((scd.regs[0x0a>>1].w << 3) & 0x1fffe);
scd.regs[0x0a>>1].w += (words >> 2);
cdc.dac.w += (words << 1);
while (words--)
{
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
*(uint16 *)(scd.word_ram[1] + dst_index) = data ;
src_index = (src_index + 2) & 0x3ffe;
dst_index = (dst_index + 2) & 0x1fffe;
}
}
void word_ram_2M_dma_w(unsigned int words)
{
uint16 data;
uint16 src_index = cdc.dac.w & 0x3ffe;
uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x3fffe;
scd.regs[0x0a>>1].w += (words >> 2);
cdc.dac.w += (words << 1);
while (words--)
{
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
*(uint16 *)(scd.word_ram_2M + dst_index) = data ;
src_index = (src_index + 2) & 0x3ffe;
dst_index = (dst_index + 2) & 0x3fffe;
}
}
unsigned int dot_ram_0_read16(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
return ((data & 0x0f) | ((data << 4) & 0xf00));
}
unsigned int dot_ram_1_read16(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
return ((data & 0x0f) | ((data << 4) & 0xf00));
}
void dot_ram_0_write16(unsigned int address, unsigned int data)
{
uint8 prev;
address = (address >> 1) & 0x1ffff;
prev = READ_BYTE(scd.word_ram[0], address);
data = (data & 0x0f) | ((data >> 4) & 0xf0);
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[0], address, data);
}
void dot_ram_1_write16(unsigned int address, unsigned int data)
{
uint8 prev;
address = (address >> 1) & 0x1ffff;
prev = READ_BYTE(scd.word_ram[1], address);
data = (data & 0x0f) | ((data >> 4) & 0xf0);
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[1], address, data);
}
unsigned int dot_ram_0_read8(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
if (address & 1)
{
return (data & 0x0f);
}
return (data >> 4);
}
unsigned int dot_ram_1_read8(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
if (address & 1)
{
return (data & 0x0f);
}
return (data >> 4);
}
void dot_ram_0_write8(unsigned int address, unsigned int data)
{
uint8 prev = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
if (address & 1)
{
data = (prev & 0xf0) | (data & 0x0f);
}
else
{
data = (prev & 0x0f) | (data << 4);
}
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff, data);
}
void dot_ram_1_write8(unsigned int address, unsigned int data)
{
uint8 prev = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
if (address & 1)
{
data = (prev & 0xf0) | (data & 0x0f);
}
else
{
data = (prev & 0x0f) | (data << 4);
}
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff, data);
}
unsigned int cell_ram_0_read16(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
return *(uint16 *)(scd.word_ram[0] + address);
}
unsigned int cell_ram_1_read16(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
return *(uint16 *)(scd.word_ram[1] + address);
}
void cell_ram_0_write16(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
*(uint16 *)(scd.word_ram[0] + address) = data;
}
void cell_ram_1_write16(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
*(uint16 *)(scd.word_ram[1] + address) = data;
}
unsigned int cell_ram_0_read8(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
return READ_BYTE(scd.word_ram[0], address);
}
unsigned int cell_ram_1_read8(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
return READ_BYTE(scd.word_ram[1], address);
}
void cell_ram_0_write8(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
WRITE_BYTE(scd.word_ram[0], address, data);
}
void cell_ram_1_write8(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
WRITE_BYTE(scd.word_ram[1], address, data);
}
void gfx_init(void)
{
int i, j;
uint16 offset;
uint8 mask, row, col, temp;
memset(&gfx, 0, sizeof(gfx_t));
for (i=0; i<0x4000; i++)
{
offset = (i & 0x07) << 8;
offset = offset | (((i >> 8) & 0x3f) << 2);
offset = offset | (((i >> 3) & 0x1f) << 11);
gfx.lut_offset[i] = offset;
}
for (i=0x4000; i<0x6000; i++)
{
offset = (i & 0x07) << 8;
offset = offset | (((i >> 7) & 0x3f) << 2);
offset = offset | (((i >> 3) & 0x0f) << 11);
gfx.lut_offset[i] = offset;
}
for (i=0x6000; i<0x7000; i++)
{
offset = (i & 0x07) << 8;
offset = offset | (((i >> 6) & 0x3f) << 2);
offset = offset | (((i >> 3) & 0x07) << 11);
gfx.lut_offset[i] = offset | 0x8000;
}
for (i=0x7000; i<0x7800; i++)
{
offset = (i & 0x07) << 8;
offset = offset | (((i >> 5) & 0x3f) << 2);
offset = offset | (((i >> 3) & 0x03) << 11);
gfx.lut_offset[i] = offset | 0xc000;
}
for (i=0x7800; i<0x8000; i++)
{
offset = (i & 0x07) << 8;
offset = offset | (((i >> 5) & 0x3f) << 2);
offset = offset | (((i >> 3) & 0x03) << 11);
gfx.lut_offset[i] = offset | 0xe000;
}
for (i=0; i<0x100; i++)
{
for (j=0; j<0x100; j++)
{
gfx.lut_prio[0][i][j] = j;
gfx.lut_prio[1][i][j] = ((i & 0x0f) ? (i & 0x0f) : (j & 0x0f)) | ((i & 0xf0) ? (i & 0xf0) : (j & 0xf0));
gfx.lut_prio[2][i][j] = ((j & 0x0f) ? (j & 0x0f) : (i & 0x0f)) | ((j & 0xf0) ? (j & 0xf0) : (i & 0xf0));
gfx.lut_prio[3][i][j] = i;
}
}
for (i=0; i<0x100; i++)
{
mask = (i & 8) ? 3 : 1;
row = (i >> 6) & mask;
col = (i >> 4) & mask;
if (i & 4) { col = col ^ mask; }
if (i & 2) { col = col ^ mask; row = row ^ mask; }
if (i & 1) { temp = col; col = row ^ mask; row = temp; }
gfx.lut_cell[i] = row + col * (mask + 1);
}
for (i=0; i<0x200; i++)
{
row = (i >> 6) & 7;
col = (i >> 3) & 7;
if (i & 4) { col = col ^ 7; }
if (i & 2) { col = col ^ 7; row = row ^ 7; }
if (i & 1) { temp = col; col = row ^ 7; row = temp; }
gfx.lut_pixel[i] = col + row * 8;
}
}
void gfx_reset(void)
{
gfx.cycles = 0;
}
int gfx_context_save(uint8 *state)
{
uint32 tmp32;
int bufferptr = 0;
save_param(&gfx.cycles, sizeof(gfx.cycles));
save_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
save_param(&gfx.dotMask, sizeof(gfx.dotMask));
save_param(&gfx.stampShift, sizeof(gfx.stampShift));
save_param(&gfx.mapShift, sizeof(gfx.mapShift));
save_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
save_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
tmp32 = (uint8 *)(gfx.tracePtr) - scd.word_ram_2M;
save_param(&tmp32, 4);
tmp32 = (uint8 *)(gfx.mapPtr) - scd.word_ram_2M;
save_param(&tmp32, 4);
return bufferptr;
}
int gfx_context_load(uint8 *state)
{
uint32 tmp32;
int bufferptr = 0;
load_param(&gfx.cycles, sizeof(gfx.cycles));
load_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
load_param(&gfx.dotMask, sizeof(gfx.dotMask));
load_param(&gfx.stampShift, sizeof(gfx.stampShift));
load_param(&gfx.mapShift, sizeof(gfx.mapShift));
load_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
load_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
load_param(&tmp32, 4);
gfx.tracePtr = (uint16 *)(scd.word_ram_2M + tmp32);
load_param(&tmp32, 4);
gfx.mapPtr = (uint16 *)(scd.word_ram_2M + tmp32);
return bufferptr;
}
INLINE void gfx_render(uint32 bufferIndex, uint32 width)
{
uint8 pixel_in, pixel_out;
uint16 stamp_data;
uint32 stamp_index;
uint32 xpos = *gfx.tracePtr++ << 8;
uint32 ypos = *gfx.tracePtr++ << 8;
uint32 xoffset = (int16) *gfx.tracePtr++;
uint32 yoffset = (int16) *gfx.tracePtr++;
while (width--)
{
if (scd.regs[0x58>>1].byte.l & 0x01)
{
xpos &= gfx.dotMask;
ypos &= gfx.dotMask;
}
else
{
xpos &= 0xffffff;
ypos &= 0xffffff;
}
if ((xpos | ypos) & ~gfx.dotMask)
{
pixel_out = 0x00;
}
else
{
stamp_data = gfx.mapPtr[(xpos >> gfx.stampShift) | ((ypos >> gfx.stampShift) << gfx.mapShift)];
stamp_index = (stamp_data & 0x7ff) << 8;
if (stamp_index)
{
stamp_data = (stamp_data >> 13) & 7;
stamp_index |= gfx.lut_cell[stamp_data | ((scd.regs[0x58>>1].byte.l & 0x02) << 2 ) | ((ypos >> 8) & 0xc0) | ((xpos >> 10) & 0x30)] << 6;
stamp_index |= gfx.lut_pixel[stamp_data | ((xpos >> 8) & 0x38) | ((ypos >> 5) & 0x1c0)];
pixel_out = READ_BYTE(scd.word_ram_2M, stamp_index >> 1);
if (stamp_index & 1)
{
pixel_out &= 0x0f;
}
else
{
pixel_out >>= 4;
}
}
else
{
pixel_out = 0x00;
}
}
pixel_in = READ_BYTE(scd.word_ram_2M, bufferIndex >> 1);
if (bufferIndex & 1)
{
pixel_out |= (pixel_in & 0xf0);
}
else
{
pixel_out = (pixel_out << 4) | (pixel_in & 0x0f);
}
pixel_out = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][pixel_in][pixel_out];
WRITE_BYTE(scd.word_ram_2M, bufferIndex >> 1, pixel_out);
if ((bufferIndex & 7) != 7)
{
bufferIndex++;
}
else
{
bufferIndex += gfx.bufferOffset;
}
xpos += xoffset;
ypos += yoffset;
}
}
void gfx_start(unsigned int base, int cycles)
{
if (!(scd.regs[0x02>>1].byte.l & 0x04))
{
uint32 mask;
gfx.tracePtr = (uint16 *)(scd.word_ram_2M + ((base << 2) & 0x3fff8));
switch ((scd.regs[0x58>>1].byte.l >> 1) & 0x03)
{
case 0:
gfx.dotMask = 0x07ffff;
gfx.stampShift = 11 + 4;
gfx.mapShift = 4;
mask = 0x3fe00;
break;
case 1:
gfx.dotMask = 0x07ffff;
gfx.stampShift = 11 + 5;
gfx.mapShift = 3;
mask = 0x3ff80;
break;
case 2:
gfx.dotMask = 0x7fffff;
gfx.stampShift = 11 + 4;
gfx.mapShift = 8;
mask = 0x20000;
break;
case 3:
gfx.dotMask = 0x7fffff;
gfx.stampShift = 11 + 5;
gfx.mapShift = 7;
mask = 0x38000;
break;
}
gfx.mapPtr = (uint16 *)(scd.word_ram_2M + ((scd.regs[0x5a>>1].w << 2) & mask));
gfx.bufferOffset = (((scd.regs[0x5c>>1].byte.l & 0x1f) + 1) << 6) - 7;
gfx.bufferStart = (scd.regs[0x5e>>1].w << 3) & 0x7ffc0;
gfx.bufferStart += (scd.regs[0x60>>1].byte.l & 0x3f);
gfx.cycles = cycles;
gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
scd.regs[0x58>>1].byte.h = 0x80;
}
}
void gfx_update(int cycles)
{
cycles -= gfx.cycles;
if (cycles > 0)
{
unsigned int lines = (cycles + gfx.cyclesPerLine - 1) / gfx.cyclesPerLine;
if (lines < scd.regs[0x64>>1].byte.l)
{
scd.regs[0x64>>1].byte.l -= lines;
gfx.cycles += lines * gfx.cyclesPerLine;
}
else
{
lines = scd.regs[0x64>>1].byte.l;
scd.regs[0x64>>1].byte.l = 0;
scd.regs[0x58>>1].byte.h = 0;
if (s68k.stopped & (1<<0x08))
{
s68k.cycles = scd.cycles;
s68k.stopped = 0;
#ifdef LOG_SCD
error("s68k started from %d cycles\n", s68k.cycles);
#endif
}
if (scd.regs[0x32>>1].byte.l & 0x02)
{
scd.pending |= (1 << 1);
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
while (lines--)
{
gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w);
gfx.bufferStart += 8;
}
}
}