diff --git a/core/vb.c b/core/vb.c index fb34d83..1da541e 100644 --- a/core/vb.c +++ b/core/vb.c @@ -126,13 +126,20 @@ struct VB { /* Pixel processor */ struct { - uint8_t f0bsy; /* Drawing into frame buffer 0 */ - uint8_t f1bsy; /* Drawing into frame buffer 1 */ - uint8_t overtime; /* Drawing extends into display interval */ - uint8_t sbcmp; /* Vertical output position compare */ - uint8_t sbcount; /* Current vertical output position */ - uint8_t sbout; /* Drawing specified vertical output position */ - uint8_t xpen; /* Drawing enabled */ + /* Hardware state */ + uint8_t f0bsy; /* Drawing into frame buffer 0 */ + uint8_t f1bsy; /* Drawing into frame buffer 1 */ + uint8_t overtime; /* Drawing extends into display interval */ + uint8_t sbcmp; /* Vertical output position compare */ + uint8_t sbcount; /* Current vertical output position */ + uint32_t sbout; /* Drawing specified vertical output position */ + uint8_t xpen; /* Drawing enabled */ + + /* Simulation state */ + uint32_t clocks; /* Master clocks to wait */ + int frame; /* FRMCYC counter */ + int step; /* Processing phase */ + uint32_t until; /* Clocks until interrupt condition */ } xp; /* Control state */ @@ -146,10 +153,10 @@ struct VB { uint16_t spt[4]; /* Object control */ /* Output frame buffers [buffer index][0=left, 1=right][pixel index] */ - uint8_t frames[2][2][384 * 224]; + uint8_t frames[2][2][384*224]; /* Other state */ - uint8_t ram[0x40000]; /* Video memory */ + uint8_t ram[0x40000]; /* Video memory */ } vip; /* Other state */ @@ -352,13 +359,13 @@ VBAPI vbOnWrite vbGetWriteCallback(VB *sim) { /* Initialize a simulation instance */ VBAPI VB* vbInit(VB *sim) { - sim->cart.ram = NULL; - sim->cart.rom = NULL; - sim->onExecute = NULL; - sim->onFetch = NULL; - sim->onFrame = NULL; - sim->onRead = NULL; - sim->onWrite = NULL; + sim->cart.ram = NULL; + sim->cart.rom = NULL; + sim->onExecute = NULL; + sim->onFetch = NULL; + sim->onFrame = NULL; + sim->onRead = NULL; + sim->onWrite = NULL; vbReset(sim); return sim; } diff --git a/core/vip.c b/core/vip.c index b97201c..20d1f50 100644 --- a/core/vip.c +++ b/core/vip.c @@ -12,23 +12,6 @@ /***************************** Module Functions ******************************/ -/* Precompute brightness values for image output */ -static void vipComputeBrightness(VB *sim) { - int32_t brt[4]; /* Working output */ - int32_t repeat; /* Multiplier from column table */ - int x; /* Iterator */ - - /* Compute brightness from hardware state */ - repeat = (int32_t) sim->vip.ram[sim->vip.dp.cta + 1] + 1; - brt[1] = repeat * sim->vip.brtRest[0]; - brt[2] = repeat * sim->vip.brtRest[1]; - brt[3] = repeat * sim->vip.brtRest[2] + brt[2] + brt[1]; - - /* Scale brightness values to 0..255 */ - for (x = 1; x < 4; x++) - sim->vip.dp.brt[x] = ((brt[x] > 127 ? 127 : brt[x]) * 510 + 127) / 254; -} - /* Read a palette */ static int32_t vipReadPalette(uint8_t *entries) { return entries[3] << 6 | entries[2] << 4 | entries[1] << 2; @@ -42,42 +25,6 @@ static void vipThrow(VB *sim, uint16_t cause) { sim->cpu.irq |= 0x0010; } -/* Transfer one column of frame buffer pixels to output */ -static void vipTransferColumn(VB *sim, int32_t eye) { - int32_t bits; /* Pixel bits from frame buffer */ - uint8_t *dest; /* Host frame image output */ - uint8_t *src; /* Simulation frame buffer input */ - int y, z; /* Iterators */ - - /* Select destination address in host memory */ - dest = &sim->vip.frames - [sim->vip.dp.buffer][eye][sim->vip.dp.column]; - - /* Output is disabled */ - if ((sim->vip.dp.disp & sim->vip.dp.synce) == 0) { - for (z = 0; z < 0x15000; z += 4) { - busWriteBuffer(dest, VB_S32, 0); - dest += 4; - } - return; - } - - /* Select source address in host memory */ - src = &sim->vip.ram[ - eye << 16 | - sim->vip.dp.buffer << 15 | - sim->vip.dp.column << 6 - ]; - - /* Transfer all rows as words */ - for (y = 0; y < 224; y += 4) { - bits = busReadBuffer(src, VB_S32); - for (z = 0; z < 1536; z += 384, bits >>= 2) - dest[z] = sim->vip.dp.brt[bits & 3]; - } - -} - /* Write a palette */ static void vipWritePalette(uint8_t *entries, int32_t mask, int32_t value) { if (mask & 0x00FF) @@ -157,7 +104,7 @@ static int32_t vipReadIO(VB *sim, uint32_t address, int type) { case 0x5F840>>1: /* XPSTTS */ value = - (int32_t) sim->vip.xp.sbout << 15 | + (int32_t) !!sim->vip.xp.sbout << 15 | (int32_t) sim->vip.xp.sbcount << 8 | (int32_t) sim->vip.xp.overtime << 4 | (int32_t) sim->vip.xp.f1bsy << 3 | @@ -378,6 +325,59 @@ static int vipOnFrame(VB *sim) { /***************************** Display Processor *****************************/ +/* Precompute brightness values for image output */ +static void vipComputeBrightness(VB *sim) { + int32_t brt[4]; /* Working output */ + int32_t repeat; /* Multiplier from column table */ + int x; /* Iterator */ + + /* Compute brightness from hardware state */ + repeat = (int32_t) sim->vip.ram[sim->vip.dp.cta + 1] + 1; + brt[1] = repeat * sim->vip.brtRest[0]; + brt[2] = repeat * sim->vip.brtRest[1]; + brt[3] = repeat * sim->vip.brtRest[2] + brt[2] + brt[1]; + + /* Scale brightness values to 0..255 */ + for (x = 1; x < 4; x++) + sim->vip.dp.brt[x] = ((brt[x] > 127 ? 127 : brt[x]) * 510 + 127) / 254; +} + +/* Transfer one column of frame buffer pixels to output */ +static void vipTransferColumn(VB *sim, int32_t eye) { + int32_t bits; /* Pixel bits from frame buffer */ + uint8_t *dest; /* Host frame image output */ + uint8_t *src; /* Simulation frame buffer input */ + int y, z; /* Iterators */ + + /* Select destination address in host memory */ + dest = &sim->vip.frames + [sim->vip.dp.buffer][eye][sim->vip.dp.column]; + + /* Output is disabled */ + if ((sim->vip.dp.disp & sim->vip.dp.synce) == 0) { + for (z = 0; z < 0x15000; z += 4) { + busWriteBuffer(dest, VB_S32, 0); + dest += 4; + } + return; + } + + /* Select source address in host memory */ + src = &sim->vip.ram[ + eye << 16 | + sim->vip.dp.buffer << 15 | + sim->vip.dp.column << 6 + ]; + + /* Transfer all rows as words */ + for (y = 0; y < 224; y += 16, src += 4) { + bits = busReadBuffer(src, VB_S32); + for (z = 0; z < 16; bits >>= 2, z++, dest += 384) + *dest = sim->vip.dp.brt[bits & 3]; + } + +} + /* Process sub-component */ static int vipEmulateDisplay(VB *sim, uint32_t clocks) { @@ -405,8 +405,26 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) { sim->vip.dp.step = 1; sim->vip.dp.until = vipClocksMs(8); vipThrow(sim, 0x0010); /* FRAMESTART */ - /* TODO: Initiate drawing, throw GAMESTART */ - /* ELSE: Set OVERTIME, throw TIMEERR */ + + /* Game frame */ + if (sim->vip.xp.frame >= sim->vip.frmcyc) { + sim->vip.xp.frame = 0; + + /* Initiate drawing procedure */ + if (sim->vip.xp.step == 0) { + sim->vip.xp.overtime = 0; + sim->vip.xp.step = 1; + vipThrow(sim, 0x0008); /* GAMESTART */ + } + + /* Drawing procedure has run into overtime */ + else { + sim->vip.xp.overtime = 1; + vipThrow(sim, 0x8000); /* TIMEERR */ + } + + } else sim->vip.xp.frame++; + break; /* 0ms-3ms - Idle */ @@ -500,10 +518,55 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) { /****************************** Pixel Processor ******************************/ +/* Draw every world into a group of 8 rows of pixels */ +static void vipDrawWorlds(VB *sim) { + (void) sim; +} + /* Process sub-component */ static void vipEmulateDrawing(VB *sim, uint32_t clocks) { - (void) sim; - (void) clocks; + + /* Process all clocks */ + for (;;) { + + /* The next event is after the time remaining */ + if (sim->vip.xp.clocks > clocks) { + sim->vip.xp.clocks -= clocks; + sim->vip.xp.until -= clocks; + return; + } + + /* Advance forward the component's number of clocks */ + clocks -= sim->vip.xp.clocks; + sim->vip.xp.until -= sim->vip.xp.clocks; + sim->vip.xp.clocks = 0; + + /* Processing by operation phase */ + switch (sim->vip.xp.step) { + + case 1: /* Initialize */ + sim->vip.xp.sbcount = 0; + + /* Fallthrough */ + case 2: /* Transition to a new row of halfwords */ + sim->vip.xp.sbout = 2240; /* 112us */ + sim->vip.xp.step = 3; + if (sim->vip.xp.sbcount == sim->vip.xp.sbcmp) + vipThrow(sim, 0x2000); /* SBHIT */ + break; + + case 3: /* Draw halfwords */ + vipDrawWorlds(sim); + sim->vip.xp.until = 2000; /* 100us */ + break; + + case 4: /* Finalize */ + sim->vip.xp.step = 0; + vipThrow(sim, 0x4000); /* XPEND */ + } + + } + } @@ -512,8 +575,18 @@ static void vipEmulateDrawing(VB *sim, uint32_t clocks) { /* Process component */ static int vipEmulate(VB *sim, uint32_t clocks) { + + /* Process sub-components */ int brk = vipEmulateDisplay(sim, clocks); vipEmulateDrawing(sim, clocks); + + /* Process SBOUT */ + if (sim->vip.xp.sbout != 0) { + if (sim->vip.xp.sbout <= clocks) { + sim->vip.xp.sbout = 0; + } else sim->vip.xp.sbout -= clocks; + } + return brk; } @@ -552,33 +625,20 @@ static void vipReset(VB *sim) { int x, y; /* Iterators */ /* Normal */ + sim->vip.intenb = 0x0000; sim->vip.dp.disp = 0; sim->vip.dp.re = 0; sim->vip.dp.synce = 0; - sim->vip.intenb = 0x0000; sim->vip.xp.xpen = 0; /* Extra (the hardware does not do this) */ - for (x = 0; x < 0x80000; x++) + sim->vip.bkcol = 0; + sim->vip.cta.cta_l = 0xFA; + sim->vip.cta.cta_r = 0xFA; + sim->vip.frmcyc = 0; + sim->vip.intpnd = 0x0000; + for (x = 0; x < 0x40000; x++) sim->vip.ram[x] = 0; - sim->vip.bkcol = 0; - sim->vip.cta.cta_l = 0xFA; - sim->vip.cta.cta_r = 0xFA; - sim->vip.frmcyc = 0; - sim->vip.intpnd = 0x0000; - sim->vip.dp.fclk = 0; - sim->vip.dp.l0bsy = 0; - sim->vip.dp.l1bsy = 0; - sim->vip.dp.lock = 0; - sim->vip.dp.r0bsy = 0; - sim->vip.dp.r1bsy = 0; - sim->vip.dp.scanrdy = 0; - sim->vip.xp.f0bsy = 0; - sim->vip.xp.f1bsy = 0; - sim->vip.xp.overtime = 0; - sim->vip.xp.sbcmp = 0; - sim->vip.xp.sbcount = 0; - sim->vip.xp.sbout = 0; for (x = 0; x < 4; x++) { sim->vip.brtRest[x] = 0; sim->vip.spt [x] = 0; @@ -588,10 +648,34 @@ static void vipReset(VB *sim) { } } - /* Other */ + /* Display processor extra (the hardware does not do this) */ + sim->vip.dp.fclk = 0; + sim->vip.dp.l0bsy = 0; + sim->vip.dp.l1bsy = 0; + sim->vip.dp.lock = 0; + sim->vip.dp.r0bsy = 0; + sim->vip.dp.r1bsy = 0; + sim->vip.dp.scanrdy = 0; + + /* Pixel processor extra (the hardware does not do this) */ + sim->vip.xp.f0bsy = 0; + sim->vip.xp.f1bsy = 0; + sim->vip.xp.overtime = 0; + sim->vip.xp.sbcmp = 0; + sim->vip.xp.sbcount = 0; + sim->vip.xp.sbout = 0; + + /* Display processor other */ sim->vip.dp.brt[0] = 0; + sim->vip.dp.buffer = 0; /* TODO: Hardware might actually do this */ sim->vip.dp.clocks = 0; sim->vip.dp.step = 0; + sim->vip.dp.until = 0; + + /* Pixel processor other */ + sim->vip.xp.clocks = 0; + sim->vip.xp.step = 0; + sim->vip.xp.until = 0; } /* Determine how many clocks are guaranteed to process */ diff --git a/makefile b/makefile index 5f01476..512f781 100644 --- a/makefile +++ b/makefile @@ -27,8 +27,8 @@ core: -Werror -std=c90 -Wall -Wextra -Wpedantic \ -D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \ -D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \ - -D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_READ=testRead \ - -D VB_DIRECT_WRITE=testWrite + -D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_FRAME=testFrame \ + -D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_READ=testRead # Clang generic @emcc core/vb.c -I core -c -o /dev/null \ -Werror -std=c90 -Wall -Wextra -Wpedantic @@ -37,8 +37,8 @@ core: -Werror -std=c90 -Wall -Wextra -Wpedantic \ -D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \ -D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \ - -D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_READ=testRead \ - -D VB_DIRECT_WRITE=testWrite + -D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_FRAME=testFrame \ + -D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_READ=testRead .PHONY: wasm wasm: