cd: integrate new gfx code

This commit is contained in:
notaz 2013-09-22 03:44:42 +03:00
parent e53f0499fe
commit a93a80deda
14 changed files with 315 additions and 650 deletions

24
pico/cd/genplus_macros.h Normal file
View file

@ -0,0 +1,24 @@
#undef uint8
#undef uint16
#undef uint32
#undef int8
#undef int16
#undef int32
#define uint8 unsigned char
#define uint16 unsigned short
#define uint32 unsigned int
#define int8 signed char
#define int16 signed short
#define int32 signed int
#define READ_BYTE(BASE, ADDR) (BASE)[(ADDR)^1]
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[(ADDR)^1] = (VAL)
#define load_param(param, size) \
memcpy(param, &state[bufferptr], size); \
bufferptr += size;
#define save_param(param, size) \
memcpy(&state[bufferptr], param, size); \
bufferptr += size;

View file

@ -1,13 +0,0 @@
#undef uint8
#undef uint16
#undef uint32
#undef int8
#undef int16
#undef int32
#define uint8 unsigned char
#define uint16 unsigned short
#define uint32 unsigned int
#define int8 signed char
#define int16 signed short
#define int32 signed int

View file

@ -35,12 +35,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "genplus_types.h"
#include "../pico_int.h"
#include "genplus_macros.h"
typedef struct
{
uint32 cycles; /* current cycles count for graphics operation */
uint32 cyclesPerLine; /* current graphics operation timings */
//uint32 cycles; /* current cycles count for graphics operation */
//uint32 cyclesPerLine; /* current graphics operation timings */
uint32 dotMask; /* stamp map size mask */
uint16 *tracePtr; /* trace vector pointer */
uint16 *mapPtr; /* stamp map table base address */
@ -48,6 +49,7 @@ typedef struct
uint8 mapShift; /* stamp map table shift value (related to stamp map size) */
uint16 bufferOffset; /* image buffer column offset */
uint32 bufferStart; /* image buffer start index */
uint32 y_step; /* pico: render line step */
uint8 lut_prio[4][0x100][0x100]; /* WORD-RAM data writes priority lookup table */
uint8 lut_pixel[0x200]; /* Graphics operation dot offset lookup table */
uint8 lut_cell[0x100]; /* Graphics operation stamp offset lookup table */
@ -55,6 +57,8 @@ typedef struct
static gfx_t gfx;
static void gfx_schedule(void);
/***************************************************************/
/* Rotation / Scaling operation (2M Mode) */
/***************************************************************/
@ -62,7 +66,6 @@ static gfx_t gfx;
void gfx_init(void)
{
int i, j;
uint16 offset;
uint8 mask, row, col, temp;
memset(&gfx, 0, sizeof(gfx));
@ -124,41 +127,37 @@ void gfx_init(void)
}
}
void gfx_reset(void)
{
/* Reset cycle counter */
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.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;
tmp32 = (uint8 *)(gfx.tracePtr) - Pico_mcd->word_ram2M;
save_param(&tmp32, 4);
tmp32 = (uint8 *)(gfx.mapPtr) - scd.word_ram_2M;
tmp32 = (uint8 *)(gfx.mapPtr) - Pico_mcd->word_ram2M;
save_param(&tmp32, 4);
save_param(&gfx.y_step, sizeof(gfx.y_step));
return bufferptr;
}
int gfx_context_load(uint8 *state)
int gfx_context_load(const uint8 *state)
{
uint32 tmp32;
int bufferptr = 0;
load_param(&gfx.cycles, sizeof(gfx.cycles));
load_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
//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));
@ -166,19 +165,22 @@ int gfx_context_load(uint8 *state)
load_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
load_param(&tmp32, 4);
gfx.tracePtr = (uint16 *)(scd.word_ram_2M + tmp32);
gfx.tracePtr = (uint16 *)(Pico_mcd->word_ram2M + tmp32);
load_param(&tmp32, 4);
gfx.mapPtr = (uint16 *)(scd.word_ram_2M + tmp32);
gfx.mapPtr = (uint16 *)(Pico_mcd->word_ram2M + tmp32);
load_param(&gfx.y_step, sizeof(gfx.y_step));
return bufferptr;
}
INLINE void gfx_render(uint32 bufferIndex, uint32 width)
static void gfx_render(uint32 bufferIndex, uint32 width)
{
uint8 pixel_in, pixel_out;
uint16 stamp_data;
uint32 stamp_index;
uint32 reg;
/* pixel map start position for current line (13.3 format converted to 13.11) */
uint32 xpos = *gfx.tracePtr++ << 8;
@ -192,7 +194,7 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
while (width--)
{
/* check if stamp map is repeated */
if (scd.regs[0x58>>1].byte.l & 0x01)
if (Pico_mcd->s68k_regs[0x58+1] & 0x01)
{
/* stamp map range */
xpos &= gfx.dotMask;
@ -235,7 +237,9 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
/* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
/* s = stamp size (0=16x16, 1=32x32) */
/* hrr = HFLIP & ROTATION bits */
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_cell[
stamp_data | ((Pico_mcd->s68k_regs[0x58+1] & 0x02) << 2 )
| ((ypos >> 8) & 0xc0) | ((xpos >> 10) & 0x30)] << 6;
/* pixel offset (0-63) */
/* table entry = yyyxxxhrr (9 bits) */
@ -245,7 +249,7 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
stamp_index |= gfx.lut_pixel[stamp_data | ((xpos >> 8) & 0x38) | ((ypos >> 5) & 0x1c0)];
/* read pixel pair (2 pixels/byte) */
pixel_out = READ_BYTE(scd.word_ram_2M, stamp_index >> 1);
pixel_out = READ_BYTE(Pico_mcd->word_ram2M, stamp_index >> 1);
/* extract left or rigth pixel */
if (stamp_index & 1)
@ -265,7 +269,7 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
}
/* read out paired pixel data */
pixel_in = READ_BYTE(scd.word_ram_2M, bufferIndex >> 1);
pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1);
/* update left or rigth pixel */
if (bufferIndex & 1)
@ -278,10 +282,11 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
}
/* priority mode write */
pixel_out = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][pixel_in][pixel_out];
reg = (Pico_mcd->s68k_regs[2] << 8) | Pico_mcd->s68k_regs[3];
pixel_out = gfx.lut_prio[(reg >> 3) & 0x03][pixel_in][pixel_out];
/* write data to image buffer */
WRITE_BYTE(scd.word_ram_2M, bufferIndex >> 1, pixel_out);
WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_out);
/* check current pixel position */
if ((bufferIndex & 7) != 7)
@ -301,18 +306,19 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
}
}
void gfx_start(unsigned int base, int cycles)
void gfx_start(unsigned int base)
{
/* make sure 2M mode is enabled */
if (!(scd.regs[0x02>>1].byte.l & 0x04))
if (!(Pico_mcd->s68k_regs[3] & 0x04))
{
uint32 mask;
uint32 reg;
/* trace vector pointer */
gfx.tracePtr = (uint16 *)(scd.word_ram_2M + ((base << 2) & 0x3fff8));
gfx.tracePtr = (uint16 *)(Pico_mcd->word_ram2M + ((base << 2) & 0x3fff8));
/* stamps & stamp map size */
switch ((scd.regs[0x58>>1].byte.l >> 1) & 0x03)
switch ((Pico_mcd->s68k_regs[0x58+1] >> 1) & 0x03)
{
case 0:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
@ -344,78 +350,97 @@ void gfx_start(unsigned int base, int cycles)
}
/* stamp map table base address */
gfx.mapPtr = (uint16 *)(scd.word_ram_2M + ((scd.regs[0x5a>>1].w << 2) & mask));
reg = (Pico_mcd->s68k_regs[0x5a] << 8) | Pico_mcd->s68k_regs[0x5b];
gfx.mapPtr = (uint16 *)(Pico_mcd->word_ram2M + ((reg << 2) & mask));
/* image buffer column offset (64 pixels/cell, minus 7 pixels to restart at cell beginning) */
gfx.bufferOffset = (((scd.regs[0x5c>>1].byte.l & 0x1f) + 1) << 6) - 7;
gfx.bufferOffset = (((Pico_mcd->s68k_regs[0x5c+1] & 0x1f) + 1) << 6) - 7;
/* image buffer start index in dot units (2 pixels/byte) */
gfx.bufferStart = (scd.regs[0x5e>>1].w << 3) & 0x7ffc0;
reg = (Pico_mcd->s68k_regs[0x5e] << 8) | Pico_mcd->s68k_regs[0x5f];
gfx.bufferStart = (reg << 3) & 0x7ffc0;
/* add image buffer horizontal dot offset */
gfx.bufferStart += (scd.regs[0x60>>1].byte.l & 0x3f);
gfx.bufferStart += (Pico_mcd->s68k_regs[0x60+1] & 0x3f);
/* reset GFX chip cycle counter */
gfx.cycles = cycles;
//gfx.cycles = cycles;
/* update GFX chip timings (see AC3:Thunderhawk / Thunderstrike) */
gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
//gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
/* start graphics operation */
scd.regs[0x58>>1].byte.h = 0x80;
Pico_mcd->s68k_regs[0x58] = 0x80;
gfx_schedule();
}
}
void gfx_update(int cycles)
/* PicoDrive specific */
#define UPDATE_CYCLES 20000
static void gfx_schedule(void)
{
/* synchronize GFX chip with SUB-CPU */
cycles -= gfx.cycles;
int w, h, cycles;
int y_step;
/* make sure SUB-CPU is ahead */
if (cycles > 0)
w = (Pico_mcd->s68k_regs[0x62] << 8) | Pico_mcd->s68k_regs[0x63];
h = (Pico_mcd->s68k_regs[0x64] << 8) | Pico_mcd->s68k_regs[0x65];
cycles = 5 * w * h;
if (cycles > UPDATE_CYCLES)
y_step = (UPDATE_CYCLES + 5 * w - 1) / (5 * w);
else
y_step = h;
gfx.y_step = y_step;
pcd_event_schedule_s68k(PCD_EVENT_GFX, 5 * w * y_step);
}
void gfx_update(unsigned int cycles)
{
int lines, lines_reg;
int w;
if (!(Pico_mcd->s68k_regs[0x58] & 0x80))
return;
w = (Pico_mcd->s68k_regs[0x62] << 8) | Pico_mcd->s68k_regs[0x63];
lines = (Pico_mcd->s68k_regs[0x64] << 8) | Pico_mcd->s68k_regs[0x65];
lines_reg = lines - gfx.y_step;
if (lines_reg <= 0) {
Pico_mcd->s68k_regs[0x58] = 0;
Pico_mcd->s68k_regs[0x64] =
Pico_mcd->s68k_regs[0x65] = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
elprintf(EL_INTS|EL_CD, "s68k: gfx_cd irq 1");
SekInterruptS68k(1);
}
}
else {
Pico_mcd->s68k_regs[0x64] = lines_reg >> 8;
Pico_mcd->s68k_regs[0x65] = lines_reg;
if (lines > gfx.y_step)
lines = gfx.y_step;
pcd_event_schedule(cycles, PCD_EVENT_GFX, 5 * w * lines);
}
if (PicoOpt & POPT_EN_MCD_GFX)
{
/* number of lines to process */
unsigned int lines = (cycles + gfx.cyclesPerLine - 1) / gfx.cyclesPerLine;
/* check against remaining lines */
if (lines < scd.regs[0x64>>1].byte.l)
{
/* update Vdot remaining size */
scd.regs[0x64>>1].byte.l -= lines;
/* increment cycle counter */
gfx.cycles += lines * gfx.cyclesPerLine;
}
else
{
/* process remaining lines */
lines = scd.regs[0x64>>1].byte.l;
/* clear Vdot remaining size */
scd.regs[0x64>>1].byte.l = 0;
/* end of graphics operation */
scd.regs[0x58>>1].byte.h = 0;
/* level 1 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x02)
{
/* trigger level 1 interrupt */
scd.pending |= (1 << 1);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* render lines */
while (lines--)
{
/* process dots to image buffer */
gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w);
gfx_render(gfx.bufferStart, w);
/* increment image buffer start index for next line (8 pixels/line) */
gfx.bufferStart += 8;
}
}
}
// vim:shiftwidth=2:ts=2:expandtab

View file

@ -1,458 +0,0 @@
// This is a direct rewrite of gfx_cd.asm (x86 asm to C).
// You can even find some x86 register names :)
// Original code (c) 2002 by Stéphane Dallongeville
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
#include "../pico_int.h"
#undef dprintf
#define dprintf(...)
#define UPDATE_CYCLES 20000
#define _rot_comp Pico_mcd->rot_comp
static void gfx_do_line(unsigned int func, unsigned short *stamp_base,
unsigned int H_Dot);
static void gfx_cd_start(void)
{
int w, h, cycles;
int y_step;
w = _rot_comp.Reg_62;
h = _rot_comp.Reg_64;
if (w == 0 || h == 0) {
elprintf(EL_CD|EL_ANOMALY, "gfx_cd_start with %ux%u", w, h);
_rot_comp.Reg_64 = 0;
// irq?
return;
}
// _rot_comp.XD_Mul = ((_rot_comp.Reg_5C & 0x1f) + 1) * 4; // unused
_rot_comp.Function = (_rot_comp.Reg_58 & 7) | (Pico_mcd->s68k_regs[3] & 0x18); // Jmp_Adr
// _rot_comp.Buffer_Adr = (_rot_comp.Reg_5E & 0xfff8) << 2; // unused?
_rot_comp.YD = (_rot_comp.Reg_60 >> 3) & 7;
_rot_comp.Vector_Adr = (_rot_comp.Reg_66 & 0xfffe) << 2;
switch (_rot_comp.Reg_58 & 6) // Scr_16?
{
case 0: // ?
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xff80) << 2;
break;
case 2: // .Dot_32
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xffe0) << 2;
break;
case 4: // .Scr_16
_rot_comp.Stamp_Map_Adr = 0x20000;
break;
case 6: // .Scr_16_Dot_32
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xe000) << 2;
break;
}
_rot_comp.Reg_58 |= 0x8000; // Stamp_Size, we start a new GFX operation
cycles = 5 * w * h;
if (cycles > UPDATE_CYCLES)
y_step = (UPDATE_CYCLES + 5 * w - 1) / (5 * w);
else
y_step = h;
_rot_comp.y_step = y_step;
pcd_event_schedule_s68k(PCD_EVENT_GFX, 5 * w * y_step);
}
void gfx_cd_update(unsigned int cycles)
{
int w = _rot_comp.Reg_62;
int h, next;
if (!(Pico_mcd->rot_comp.Reg_58 & 0x8000))
return;
h = _rot_comp.Reg_64;
_rot_comp.Reg_64 -= _rot_comp.y_step;
if ((int)_rot_comp.Reg_64 <= 0) {
Pico_mcd->rot_comp.Reg_58 &= 0x7fff;
Pico_mcd->rot_comp.Reg_64 = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
elprintf(EL_INTS |EL_CD, "s68k: gfx_cd irq 1");
SekInterruptS68k(1);
}
}
else {
next = _rot_comp.Reg_64;
if (next > _rot_comp.y_step)
next = _rot_comp.y_step;
pcd_event_schedule(cycles, PCD_EVENT_GFX, 5 * w * next);
h = _rot_comp.y_step;
}
if (PicoOpt & POPT_EN_MCD_GFX)
{
unsigned int func = _rot_comp.Function;
unsigned short *stamp_base = (unsigned short *)
(Pico_mcd->word_ram2M + _rot_comp.Stamp_Map_Adr);
while (h--)
gfx_do_line(func, stamp_base, w);
}
}
PICO_INTERNAL_ASM unsigned int gfx_cd_read(unsigned int a)
{
unsigned int d = 0;
switch (a) {
case 0x58: d = _rot_comp.Reg_58; break;
case 0x5A: d = _rot_comp.Reg_5A; break;
case 0x5C: d = _rot_comp.Reg_5C; break;
case 0x5E: d = _rot_comp.Reg_5E; break;
case 0x60: d = _rot_comp.Reg_60; break;
case 0x62: d = _rot_comp.Reg_62; break;
case 0x64: d = _rot_comp.Reg_64; break;
case 0x66: break;
default: dprintf("gfx_cd_read FIXME: unexpected address: %02x", a); break;
}
dprintf("gfx_cd_read(%02x) = %04x", a, d);
return d;
}
static void gfx_do_line(unsigned int func, unsigned short *stamp_base,
unsigned int H_Dot)
{
unsigned int eax, ebx, ecx, edx, esi, edi, pixel;
unsigned int XD, Buffer_Adr;
int DYXS;
XD = _rot_comp.Reg_60 & 7;
Buffer_Adr = ((_rot_comp.Reg_5E & 0xfff8) + _rot_comp.YD) << 2;
ecx = *(unsigned int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr);
edx = ecx >> 16;
ecx = (ecx & 0xffff) << 8;
edx <<= 8;
DYXS = *(int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr + 4);
_rot_comp.Vector_Adr += 8;
// MAKE_IMAGE_LINE
while (H_Dot)
{
// MAKE_IMAGE_PIXEL
if (!(func & 1)) // NOT TILED
{
int mask = (func & 4) ? 0x00800000 : 0x00f80000;
if ((ecx | edx) & mask)
{
if (func & 0x18) goto Next_Pixel;
pixel = 0;
goto Pixel_Out;
}
}
if (func & 2) // mode 32x32 dot
{
if (func & 4) // 16x16 screen
{
ebx = ((ecx >> (11+5)) & 0x007f) |
((edx >> (11-2)) & 0x3f80);
}
else // 1x1 screen
{
ebx = ((ecx >> (11+5)) & 0x07) |
((edx >> (11+2)) & 0x38);
}
}
else // mode 16x16 dot
{
if (func & 4) // 16x16 screen
{
ebx = ((ecx >> (11+4)) & 0x00ff) |
((edx >> (11-4)) & 0xff00);
}
else // 1x1 screen
{
ebx = ((ecx >> (11+4)) & 0x0f) |
((edx >> (11+0)) & 0xf0);
}
}
edi = stamp_base[ebx];
esi = (edi & 0x7ff) << 7;
if (!esi) { pixel = 0; goto Pixel_Out; }
edi >>= (11+1);
edi &= (0x1c>>1);
eax = ecx;
ebx = edx;
if (func & 2) edi |= 1; // 32 dots?
switch (edi)
{
case 0x00: // No_Flip_0, 16x16 dots
ebx = (ebx >> 9) & 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 8) & 0x40) + ebx;
break;
case 0x01: // No_Flip_0, 32x32 dots
ebx = (ebx >> 9) & 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 7) & 0x180) + ebx;
break;
case 0x02: // No_Flip_90, 16x16 dots
eax = (eax >> 9) & 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap
eax += ((ebx >> 8) & 0x40) ^ 0x40;
break;
case 0x03: // No_Flip_90, 32x32 dots
eax = (eax >> 9) & 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap
eax += ((ebx >> 7) & 0x180) ^ 0x180;
break;
case 0x04: // No_Flip_180, 16x16 dots
ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap and flip
eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
break;
case 0x05: // No_Flip_180, 32x32 dots
ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap and flip
eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
break;
case 0x06: // No_Flip_270, 16x16 dots
eax = ((eax >> 9) & 0x3c) ^ 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap
eax += (ebx >> 8) & 0x40;
break;
case 0x07: // No_Flip_270, 32x32 dots
eax = ((eax >> 9) & 0x7c) ^ 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap
eax += (ebx >> 7) & 0x180;
break;
case 0x08: // Flip_0, 16x16 dots
ebx = (ebx >> 9) & 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
break;
case 0x09: // Flip_0, 32x32 dots
ebx = (ebx >> 9) & 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
break;
case 0x0a: // Flip_90, 16x16 dots
eax = ((eax >> 9) & 0x3c) ^ 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
eax += ((ebx >> 8) & 0x40) ^ 0x40;
break;
case 0x0b: // Flip_90, 32x32 dots
eax = ((eax >> 9) & 0x7c) ^ 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
eax += ((ebx >> 7) & 0x180) ^ 0x180;
break;
case 0x0c: // Flip_180, 16x16 dots
ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 8) & 0x40) + ebx;
break;
case 0x0d: // Flip_180, 32x32 dots
ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 7) & 0x180) + ebx;
break;
case 0x0e: // Flip_270, 16x16 dots
eax = (eax >> 9) & 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
eax += (ebx >> 8) & 0x40;
break;
case 0x0f: // Flip_270, 32x32 dots
eax = (eax >> 9) & 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
eax += (ebx >> 7) & 0x180;
break;
}
pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
if (!(edi & 0x800)) pixel >>= 4;
else pixel &= 0x0f;
Pixel_Out:
if (!pixel && (func & 0x18)) goto Next_Pixel;
esi = Buffer_Adr + ((XD>>1)^1); // pixel addr
eax = *(Pico_mcd->word_ram2M + esi); // old pixel
if (XD & 1)
{
if ((eax & 0x0f) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
*(Pico_mcd->word_ram2M + esi) = pixel | (eax & 0xf0);
}
else
{
if ((eax & 0xf0) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
*(Pico_mcd->word_ram2M + esi) = (pixel << 4) | (eax & 0xf);
}
Next_Pixel:
ecx += (DYXS << 16) >> 16; // _rot_comp.DXS;
edx += DYXS >> 16; // _rot_comp.DYS;
XD++;
if (XD >= 8)
{
Buffer_Adr += ((_rot_comp.Reg_5C & 0x1f) + 1) << 5;
XD = 0;
}
H_Dot--;
}
// end while
// nothing_to_draw:
_rot_comp.YD++;
// _rot_comp.V_Dot--; // will be done by caller
}
PICO_INTERNAL_ASM void gfx_cd_write16(unsigned int a, unsigned int d)
{
dprintf("gfx_cd_write16(%x, %04x)", a, d);
if (_rot_comp.Reg_58 & 0x8000)
elprintf(EL_CD|EL_ANOMALY, "cd: busy gfx reg write %02x %04x", a, d);
switch (a) {
case 0x58: // .Reg_Stamp_Size
_rot_comp.Reg_58 = d & 7;
return;
case 0x5A: // .Reg_Stamp_Adr
_rot_comp.Reg_5A = d & 0xffe0;
return;
case 0x5C: // .Reg_IM_VCell_Size
_rot_comp.Reg_5C = d & 0x1f;
return;
case 0x5E: // .Reg_IM_Adr
_rot_comp.Reg_5E = d & 0xFFF8;
return;
case 0x60: // .Reg_IM_Offset
_rot_comp.Reg_60 = d & 0x3f;
return;
case 0x62: // .Reg_IM_HDot_Size
_rot_comp.Reg_62 = d & 0x1ff;
return;
case 0x64: // .Reg_IM_VDot_Size
_rot_comp.Reg_64 = d & 0xff; // V_Dot, must be 32bit?
return;
case 0x66: // .Reg_Vector_Adr
_rot_comp.Reg_66 = d & 0xfffe;
if (Pico_mcd->s68k_regs[3]&4) return; // can't do tanformations in 1M mode
gfx_cd_start();
return;
default: dprintf("gfx_cd_write16 FIXME: unexpected address: %02x", a); return;
}
}
PICO_INTERNAL void gfx_cd_reset(void)
{
memset(&_rot_comp.Reg_58, 0, sizeof(_rot_comp));
}
// --------------------------------
#include "cell_map.c"
#ifndef UTYPES_DEFINED
typedef unsigned short u16;
#endif
// check: Heart of the alien, jaguar xj 220
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc)
{
unsigned char *base;
unsigned int asrc, a2;
u16 *r;
base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
switch (Pico.video.type)
{
case 1: // vram
r = Pico.vram;
for(; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
// if(a&1) d=(d<<8)|(d>>8); // ??
r[a>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a=(u16)(a+inc);
}
rendstatus |= PDRAW_SPRITES_MOVED;
break;
case 3: // cram
Pico.m.dirtyPal = 1;
r = Pico.cram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
r[a2>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a2+=inc;
// good dest?
if(a2 >= 0x80) break;
}
a=(a&0xff00)|a2;
break;
case 5: // vsram[a&0x003f]=d;
r = Pico.vsram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
r[a2>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a2+=inc;
// good dest?
if(a2 >= 0x80) break;
}
a=(a&0xff00)|a2;
break;
}
// remember addr
Pico.video.addr=(u16)a;
}

View file

@ -1,37 +0,0 @@
#ifndef _GFX_CD_H
#define _GFX_CD_H
typedef struct
{
unsigned int Reg_58; // Stamp_Size
unsigned int Reg_5A;
unsigned int Reg_5C;
unsigned int Reg_5E;
unsigned int Reg_60;
unsigned int Reg_62;
unsigned int Reg_64; // V_Dot
unsigned int Reg_66;
unsigned int Stamp_Map_Adr;
unsigned int Vector_Adr;
unsigned int Function; // Jmp_Adr;
unsigned int Float_Part;
unsigned int Draw_Speed;
unsigned int YD;
unsigned int y_step;
int pad[9];
} Rot_Comp;
PICO_INTERNAL_ASM unsigned int gfx_cd_read(unsigned int a);
PICO_INTERNAL_ASM void gfx_cd_write16(unsigned int a, unsigned int d);
void gfx_cd_update(unsigned int cycles);
PICO_INTERNAL void gfx_cd_reset(void);
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc);
#endif // _GFX_CD_H

79
pico/cd/gfx_dma.c Normal file
View file

@ -0,0 +1,79 @@
/*
* PicoDrive
* (C) notaz, 2007
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "cell_map.c"
#ifndef UTYPES_DEFINED
typedef unsigned short u16;
#endif
// check: Heart of the alien, jaguar xj 220
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc)
{
unsigned char *base;
unsigned int asrc, a2;
u16 *r;
base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
switch (Pico.video.type)
{
case 1: // vram
r = Pico.vram;
for(; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
// if(a&1) d=(d<<8)|(d>>8); // ??
r[a>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a=(u16)(a+inc);
}
rendstatus |= PDRAW_SPRITES_MOVED;
break;
case 3: // cram
Pico.m.dirtyPal = 1;
r = Pico.cram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
r[a2>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a2+=inc;
// good dest?
if(a2 >= 0x80) break;
}
a=(a&0xff00)|a2;
break;
case 5: // vsram[a&0x003f]=d;
r = Pico.vsram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
r[a2>>1] = *(u16 *)(base + asrc);
source += 2;
// AutoIncrement
a2+=inc;
// good dest?
if(a2 >= 0x80) break;
}
a=(a&0xff00)|a2;
break;
}
// remember addr
Pico.video.addr=(u16)a;
}

View file

@ -21,6 +21,7 @@ PICO_INTERNAL void PicoInitMCD(void)
{
SekInitS68k();
Init_CD_Driver();
gfx_init();
}
PICO_INTERNAL void PicoExitMCD(void)
@ -57,7 +58,6 @@ void pcd_soft_reset(void)
// Reset_CD(); // breaks Fahrenheit CD swap
LC89510_Reset();
gfx_cd_reset();
#ifdef _ASM_CD_MEMORY_C
//PicoMemResetCDdecode(1); // don't have to call this in 2M mode
#endif
@ -160,7 +160,7 @@ static unsigned int event_time_next;
static event_cb *pcd_event_cbs[PCD_EVENT_COUNT] = {
[PCD_EVENT_CDC] = pcd_cdc_event,
[PCD_EVENT_TIMER3] = pcd_int3_timer_event,
[PCD_EVENT_GFX] = gfx_cd_update,
[PCD_EVENT_GFX] = gfx_update,
[PCD_EVENT_DMA] = pcd_dma_event,
};
@ -341,12 +341,6 @@ void pcd_state_loaded(void)
pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_TIMER3,
Pico_mcd->s68k_regs[0x31] * 384);
if (Pico_mcd->rot_comp.Reg_58 & 0x8000) {
Pico_mcd->rot_comp.Reg_58 &= 0x7fff;
Pico_mcd->rot_comp.Reg_64 = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1)
SekInterruptS68k(1);
}
if (Pico_mcd->scd.Status_CDC & 0x08)
Update_CDC_TRansfer(Pico_mcd->s68k_regs[4] & 7);
}

View file

@ -9,8 +9,6 @@
#include "../pico_int.h"
#include "../memory.h"
#include "gfx_cd.h"
uptr s68k_read8_map [0x1000000 >> M68K_MEM_SHIFT];
uptr s68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];
uptr s68k_write8_map [0x1000000 >> M68K_MEM_SHIFT];
@ -429,6 +427,8 @@ void s68k_reg_write8(u32 a, u32 d)
Pico_mcd->s68k_regs[a] = (u8) d;
CDD_Import_Command();
return;
case 0x58:
return;
}
if ((a&0x1f0) == 0x20)
@ -450,6 +450,65 @@ write_comm:
Pico_mcd->m.m68k_poll_cnt = 0;
}
void s68k_reg_write16(u32 a, u32 d)
{
u8 *r = Pico_mcd->s68k_regs;
if ((a & 0x1f0) == 0x20)
goto write_comm;
switch (a) {
case 0x0e:
// special case, 2 byte writes would be handled differently
// TODO: verify
r[0xf] = d;
return;
case 0x58: // stamp data size
r[0x59] = d & 7;
return;
case 0x5a: // stamp map base address
r[0x5a] = d >> 8;
r[0x5b] = d & 0xe0;
return;
case 0x5c: // V cell size
r[0x5d] = d & 0x1f;
return;
case 0x5e: // image buffer start address
r[0x5e] = d >> 8;
r[0x5f] = d & 0xf8;
return;
case 0x60: // image buffer offset
r[0x61] = d & 0x3f;
return;
case 0x62: // h dot size
r[0x62] = (d >> 8) & 1;
r[0x63] = d;
return;
case 0x64: // v dot size
r[0x65] = d;
return;
case 0x66: // trace vector base address
d &= 0xfffe;
r[0x66] = d >> 8;
r[0x67] = d;
gfx_start(d);
return;
default:
break;
}
s68k_reg_write8(a, d >> 8);
s68k_reg_write8(a + 1, d & 0xff);
return;
write_comm:
r[a] = d >> 8;
r[a + 1] = d;
if (Pico_mcd->m.m68k_poll_cnt)
SekEndRunS68k(0);
Pico_mcd->m.m68k_poll_cnt = 0;
}
// -----------------------------------------------------------------
// Main 68k
// -----------------------------------------------------------------
@ -814,9 +873,7 @@ static u32 PicoReadS68k8_pr(u32 a)
s68k_poll_detect(a & ~1, d);
goto regs_done;
}
else if (a >= 0x58 && a < 0x68)
d = gfx_cd_read(a & ~1);
else d = s68k_reg_read16(a & ~1);
d = s68k_reg_read16(a & ~1);
if (!(a & 1))
d >>= 8;
@ -849,9 +906,7 @@ static u32 PicoReadS68k16_pr(u32 a)
// regs
if ((a & 0xfe00) == 0x8000) {
a &= 0x1fe;
if (0x58 <= a && a < 0x68)
d = gfx_cd_read(a);
else d = s68k_reg_read16(a);
d = s68k_reg_read16(a);
elprintf(EL_CDREGS, "s68k_regs r16: [%02x] %04x @%06x",
a, d, SekPcS68k);
@ -878,9 +933,10 @@ static void PicoWriteS68k8_pr(u32 a, u32 d)
if ((a & 0xfe00) == 0x8000) {
a &= 0x1ff;
elprintf(EL_CDREGS, "s68k_regs w8: [%02x] %02x @%06x", a, d, SekPcS68k);
if (0x58 <= a && a < 0x68)
gfx_cd_write16(a&~1, (d<<8)|d);
else s68k_reg_write8(a,d);
if (0x59 <= a && a < 0x68) // word regs
s68k_reg_write16(a & ~1, (d << 8) | d);
else
s68k_reg_write8(a, d);
return;
}
@ -903,18 +959,7 @@ static void PicoWriteS68k16_pr(u32 a, u32 d)
if ((a & 0xfe00) == 0x8000) {
a &= 0x1fe;
elprintf(EL_CDREGS, "s68k_regs w16: [%02x] %04x @%06x", a, d, SekPcS68k);
if (a >= 0x58 && a < 0x68)
gfx_cd_write16(a, d);
else {
if (a == 0xe) {
// special case, 2 byte writes would be handled differently
// TODO: verify
Pico_mcd->s68k_regs[0xf] = d;
return;
}
s68k_reg_write8(a, d >> 8);
s68k_reg_write8(a + 1, d & 0xff);
}
s68k_reg_write16(a, d);
return;
}

View file

@ -53,9 +53,8 @@
.extern m68k_reg_write8
.extern s68k_reg_read16
.extern s68k_reg_write8
.extern s68k_reg_write16
.extern s68k_poll_detect
.extern gfx_cd_read
.extern gfx_cd_write16
.extern pcd_pcm_write
.extern pcd_pcm_read
.extern PicoCpuCS68k
@ -420,14 +419,9 @@ m_s68k_read8_regs:
sub r2, r0, #0x0e
cmp r2, #(0x30-0x0e)
blo m_s68k_read8_comm
sub r2, r0, #0x58
cmp r2, #0x10
ldrlo r2, =gfx_cd_read
ldrhs r2, =s68k_reg_read16
stmfd sp!,{r0,lr}
bic r0, r0, #1
mov lr, pc
bx r2
bl s68k_reg_read16
ldmfd sp!,{r1,lr}
tst r1, #1
moveq r0, r0, lsr #8
@ -503,9 +497,6 @@ m_s68k_read16_regs:
bic r0, r0, #0xff0000
bic r0, r0, #0x008000
bic r0, r0, #0x000001
sub r2, r0, #0x58
cmp r2, #0x10
blo gfx_cd_read
cmp r0, #8
bne s68k_reg_read16
mov r0, #1
@ -580,12 +571,12 @@ m_s68k_write8_regs:
tst r0, #0x7e00
movne r0, #0
bxne lr
sub r2, r0, #0x58
cmp r2, #0x10
sub r2, r0, #0x59
cmp r2, #0x0f
bhs s68k_reg_write8
bic r0, r0, #1
orr r1, r1, r1, lsl #8
b gfx_cd_write16
b s68k_reg_write16
m_s68k_write8_pcm:
@ -697,17 +688,7 @@ m_s68k_write16_regs:
movne r0, #0
bxne lr
cmp r0, #0x0e
beq m_s68k_write16_regs_spec
sub r2, r0, #0x58
cmp r2, #0x10
blo gfx_cd_write16
and r3, r1, #0xff
add r2, r0, #1
stmfd sp!,{r2,r3,lr}
mov r1, r1, lsr #8
bl s68k_reg_write8
ldmfd sp!,{r0,r1,lr}
b s68k_reg_write8
bne s68k_reg_write16
m_s68k_write16_regs_spec: @ special case
ldr r2, =(Pico+0x22200)

View file

@ -376,7 +376,6 @@ struct PicoSRAM
// MCD
#include "cd/cd_sys.h"
#include "cd/LC89510.h"
#include "cd/gfx_cd.h"
#define PCM_MIXBUF_LEN ((12500000 / 384) / 50 + 1)
@ -446,7 +445,6 @@ typedef struct
CDD cdd;
CDC cdc;
_scd scd;
Rot_Comp rot_comp;
int pcm_mixbuf[PCM_MIXBUF_LEN * 2];
int pcm_mixpos;
int pcm_mixbuf_dirty;
@ -611,6 +609,16 @@ void PicoWrite16_io(unsigned int a, unsigned int d);
// pico/memory.c
PICO_INTERNAL void PicoMemSetupPico(void);
// cd/gfx.c
void gfx_init(void);
void gfx_start(unsigned int base);
void gfx_update(unsigned int cycles);
int gfx_context_save(unsigned char *state);
int gfx_context_load(const unsigned char *state);
// cd/gfx_dma.c
void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc);
// cd/memory.c
PICO_INTERNAL void PicoMemSetupCD(void);
unsigned int PicoRead8_mcd_io(unsigned int a);

View file

@ -175,6 +175,7 @@ typedef enum {
CHUNK_32X_LAST = CHUNK_32X_EVT,
// add new stuff here
CHUNK_CD_EVT = 50,
CHUNK_CD_GFX,
//
CHUNK_DEFAULT_COUNT,
CHUNK_CARTHW_ = CHUNK_CARTHW, // 64 (defined in PicoInt)
@ -258,6 +259,7 @@ static int state_save(void *file)
unsigned char buff[0x60], buff_z80[Z80_STATE_SIZE];
void *ym2612_regs = YM2612GetRegs();
int ver = 0x0170; // not really used..
int len;
areaWrite("PicoSEXT", 1, 8, file);
areaWrite(&ver, 1, 4, file);
@ -305,11 +307,12 @@ static int state_save(void *file)
CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);
CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc);
CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);
CHECKED_WRITE_BUFF(CHUNK_RC, Pico_mcd->rot_comp);
CHECKED_WRITE_BUFF(CHUNK_MISC_CD, Pico_mcd->m);
memset(buff, 0, 0x40);
memcpy(buff, pcd_event_times, sizeof(pcd_event_times));
CHECKED_WRITE(CHUNK_CD_EVT, 0x40, buff);
len = gfx_context_save(buff);
CHECKED_WRITE(CHUNK_CD_GFX, len, buff);
if (Pico_mcd->s68k_regs[3] & 4) // convert back
wram_2M_to_1M(Pico_mcd->word_ram2M);
@ -464,7 +467,6 @@ static int state_load(void *file)
case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;
case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break;
case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;
case CHUNK_RC: CHECKED_READ_BUFF(Pico_mcd->rot_comp); break;
case CHUNK_MISC_CD: CHECKED_READ_BUFF(Pico_mcd->m); break;
case CHUNK_CD_EVT:
@ -472,6 +474,11 @@ static int state_load(void *file)
memcpy(pcd_event_times, buff, sizeof(pcd_event_times));
break;
case CHUNK_CD_GFX:
CHECKED_READ2(0x18, buff);
gfx_context_load(buff);
break;
// 32x stuff
#ifndef NO_32X
case CHUNK_MSH2:

View file

@ -8,7 +8,6 @@
*/
#include "pico_int.h"
#include "cd/gfx_cd.h"
int line_base_cycles;
extern const unsigned char hcounts_32[];

View file

@ -509,7 +509,7 @@ CZ80 Z80 interpreter core
Reesy & FluBBa
DrZ80, the Z80 interpreter written in ARM assembly.
Homepage: http://reesy.gp32x.de/
Homepage: http://reesy.gp32x.de/ (defunct)
Tatsuyuki Satoh, Jarek Burczynski, MAME development
software implementation of Yamaha FM sound generator
@ -518,8 +518,11 @@ MAME development
Texas Instruments SN76489 / SN76496 programmable tone/noise generator
Homepage: http://www.mame.net/
Eke
CD graphics processor implementation (from Genesis Plus GX)
Stephane Dallongeville
Gens, MD/Mega CD/32X emulator. Most Sega CD code is based on this emu.
Gens, MD/Mega CD/32X emulator. Some Sega CD code is based on this emu.
#ifdef PSP
people @ ps2dev.org forums / PSPSDK crew
@ -562,6 +565,14 @@ Additional thanks
Changelog
---------
1.xx (2013-09-)
+ 32X+CD emulation has been implemented.
+ CD graphics processor code has been replaced with much cleaner Eke's
implamentation from Genesis Plus GX.
+ CD PCM code has been completely rewritten
* Various CD compatibility issues have been solved. Hopefully no more
regressions this time.
1.85 (2013-08-31)
* Lots of 32X compatibility and accuracy improvements. All commercial games
are booting now, but some still have issues.

View file

@ -94,8 +94,8 @@ endif
# CD
SRCS_COMMON += $(R)pico/cd/mcd.c $(R)pico/cd/memory.c $(R)pico/cd/sek.c \
$(R)pico/cd/LC89510.c $(R)pico/cd/cd_sys.c $(R)pico/cd/cd_file.c \
$(R)pico/cd/cue.c $(R)pico/cd/gfx_cd.c $(R)pico/cd/misc.c \
$(R)pico/cd/pcm.c $(R)pico/cd/buffering.c
$(R)pico/cd/cue.c $(R)pico/cd/gfx.c $(R)pico/cd/gfx_dma.c \
$(R)pico/cd/misc.c $(R)pico/cd/pcm.c $(R)pico/cd/buffering.c
# 32X
ifneq "$(no_32x)" "1"
SRCS_COMMON += $(R)pico/32x/32x.c $(R)pico/32x/memory.c $(R)pico/32x/draw.c \