diff --git a/Assets/dll/virtualjaguar.wbx.zst b/Assets/dll/virtualjaguar.wbx.zst index b2de670a4b..ddbabf85d2 100644 Binary files a/Assets/dll/virtualjaguar.wbx.zst and b/Assets/dll/virtualjaguar.wbx.zst differ diff --git a/waterbox/virtualjaguar/BizInterface.cpp b/waterbox/virtualjaguar/BizInterface.cpp index dbbb21579c..7bcfa307a7 100644 --- a/waterbox/virtualjaguar/BizInterface.cpp +++ b/waterbox/virtualjaguar/BizInterface.cpp @@ -38,10 +38,6 @@ static s16 latchL, latchR; EXPORT bool Init(BizSettings* bizSettings, u8* boot, u8* rom, u32 sz) { - vjs.GPUEnabled = true; - vjs.DSPEnabled = true; - vjs.usePipelinedDSP = false; - vjs.renderType = RT_NORMAL; vjs.hardwareTypeNTSC = bizSettings->hardwareTypeNTSC; vjs.useJaguarBIOS = bizSettings->useJaguarBIOS; vjs.useFastBlitter = bizSettings->useFastBlitter; diff --git a/waterbox/virtualjaguar/src/blitter.cpp b/waterbox/virtualjaguar/src/blitter.cpp index 7193daf19c..0883f6de62 100644 --- a/waterbox/virtualjaguar/src/blitter.cpp +++ b/waterbox/virtualjaguar/src/blitter.cpp @@ -25,46 +25,12 @@ #include #include #include "jaguar.h" -#include "log.h" -//#include "memory.h" #include "settings.h" -// Various conditional compilation goodies... - -//#define LOG_BLITS - -#define USE_ORIGINAL_BLITTER -//#define USE_MIDSUMMER_BLITTER -#define USE_MIDSUMMER_BLITTER_MKII - -#ifdef USE_ORIGINAL_BLITTER -#ifdef USE_MIDSUMMER_BLITTER_MKII -#define USE_BOTH_BLITTERS -#endif -#endif - - -// External global variables - -extern int jaguar_active_memory_dumps; - -// Local global variables - -int start_logging = 0; -uint8_t blitter_working = 0; -bool startConciseBlitLogging = false; -bool logBlit = false; - // Blitter register RAM (most of it is hidden from the user) static uint8_t blitter_ram[0x100]; -// Other crapola - -bool specialLog = false; -extern int effect_start; -extern int blit_start_log; -void BlitterMidsummer(uint32_t cmd); void BlitterMidsummer2(void); #define REG(A) (((uint32_t)blitter_ram[(A)] << 24) | ((uint32_t)blitter_ram[(A)+1] << 16) \ @@ -161,44 +127,32 @@ void BlitterMidsummer2(void); #define YADD1_A1 (REG(A1_FLAGS)&0x040000) #define YADD1_A2 (REG(A2_FLAGS)&0x040000) -/******************************************************************************* -********************** STUFF CUT BELOW THIS LINE! ****************************** -*******************************************************************************/ -#ifdef USE_ORIGINAL_BLITTER // We're ditching this crap for now... - -//Put 'em back, once we fix the problem!!! [KO] // 1 bpp pixel read #define PIXEL_SHIFT_1(a) (((~a##_x) >> 16) & 7) #define PIXEL_OFFSET_1(a) (((((uint32_t)a##_y >> 16) * a##_width / 8) + (((uint32_t)a##_x >> 19) & ~7)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 19) & 7)) #define READ_PIXEL_1(a) ((JaguarReadByte(a##_addr+PIXEL_OFFSET_1(a), BLITTER) >> PIXEL_SHIFT_1(a)) & 0x01) -//#define READ_PIXEL_1(a) ((JaguarReadByte(a##_addr+PIXEL_OFFSET_1(a)) >> PIXEL_SHIFT_1(a)) & 0x01) // 2 bpp pixel read #define PIXEL_SHIFT_2(a) (((~a##_x) >> 15) & 6) #define PIXEL_OFFSET_2(a) (((((uint32_t)a##_y >> 16) * a##_width / 4) + (((uint32_t)a##_x >> 18) & ~7)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 18) & 7)) #define READ_PIXEL_2(a) ((JaguarReadByte(a##_addr+PIXEL_OFFSET_2(a), BLITTER) >> PIXEL_SHIFT_2(a)) & 0x03) -//#define READ_PIXEL_2(a) ((JaguarReadByte(a##_addr+PIXEL_OFFSET_2(a)) >> PIXEL_SHIFT_2(a)) & 0x03) // 4 bpp pixel read #define PIXEL_SHIFT_4(a) (((~a##_x) >> 14) & 4) #define PIXEL_OFFSET_4(a) (((((uint32_t)a##_y >> 16) * (a##_width/2)) + (((uint32_t)a##_x >> 17) & ~7)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 17) & 7)) #define READ_PIXEL_4(a) ((JaguarReadByte(a##_addr+PIXEL_OFFSET_4(a), BLITTER) >> PIXEL_SHIFT_4(a)) & 0x0f) -//#define READ_PIXEL_4(a) ((JaguarReadByte(a##_addr+PIXEL_OFFSET_4(a)) >> PIXEL_SHIFT_4(a)) & 0x0f) // 8 bpp pixel read #define PIXEL_OFFSET_8(a) (((((uint32_t)a##_y >> 16) * a##_width) + (((uint32_t)a##_x >> 16) & ~7)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 16) & 7)) #define READ_PIXEL_8(a) (JaguarReadByte(a##_addr+PIXEL_OFFSET_8(a), BLITTER)) -//#define READ_PIXEL_8(a) (JaguarReadByte(a##_addr+PIXEL_OFFSET_8(a))) // 16 bpp pixel read #define PIXEL_OFFSET_16(a) (((((uint32_t)a##_y >> 16) * a##_width) + (((uint32_t)a##_x >> 16) & ~3)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 16) & 3)) #define READ_PIXEL_16(a) (JaguarReadWord(a##_addr+(PIXEL_OFFSET_16(a)<<1), BLITTER)) -//#define READ_PIXEL_16(a) (JaguarReadWord(a##_addr+(PIXEL_OFFSET_16(a)<<1))) // 32 bpp pixel read #define PIXEL_OFFSET_32(a) (((((uint32_t)a##_y >> 16) * a##_width) + (((uint32_t)a##_x >> 16) & ~1)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 16) & 1)) #define READ_PIXEL_32(a) (JaguarReadLong(a##_addr+(PIXEL_OFFSET_32(a)<<2), BLITTER)) -//#define READ_PIXEL_32(a) (JaguarReadLong(a##_addr+(PIXEL_OFFSET_32(a)<<2))) // pixel read #define READ_PIXEL(a,f) (\ @@ -212,14 +166,12 @@ void BlitterMidsummer2(void); // 16 bpp z data read #define ZDATA_OFFSET_16(a) (PIXEL_OFFSET_16(a) + a##_zoffs * 4) #define READ_ZDATA_16(a) (JaguarReadWord(a##_addr+(ZDATA_OFFSET_16(a)<<1), BLITTER)) -//#define READ_ZDATA_16(a) (JaguarReadWord(a##_addr+(ZDATA_OFFSET_16(a)<<1))) // z data read #define READ_ZDATA(a,f) (READ_ZDATA_16(a)) // 16 bpp z data write #define WRITE_ZDATA_16(a,d) { JaguarWriteWord(a##_addr+(ZDATA_OFFSET_16(a)<<1), d, BLITTER); } -//#define WRITE_ZDATA_16(a,d) { JaguarWriteWord(a##_addr+(ZDATA_OFFSET_16(a)<<1), d); } // z data write #define WRITE_ZDATA(a,f,d) WRITE_ZDATA_16(a,d); @@ -253,28 +205,21 @@ void BlitterMidsummer2(void); // 1 bpp pixel write #define WRITE_PIXEL_1(a,d) { JaguarWriteByte(a##_addr+PIXEL_OFFSET_1(a), (JaguarReadByte(a##_addr+PIXEL_OFFSET_1(a), BLITTER)&(~(0x01 << PIXEL_SHIFT_1(a))))|(d< 10 in base 10 (i.e., 1.01 with the decimal place -// being shifted to the right 3 places). -/*static uint32_t blitter_scanline_width[48] = -{ - 0, 0, 0, 0, // Note: This would really translate to 1, 1, 1, 1 - 2, 0, 0, 0, - 4, 0, 6, 0, - 8, 10, 12, 14, - 16, 20, 24, 28, - 32, 40, 48, 56, - 64, 80, 96, 112, - 128, 160, 192, 224, - 256, 320, 384, 448, - 512, 640, 768, 896, - 1024, 1280, 1536, 1792, - 2048, 2560, 3072, 3584 -};//*/ - -//static uint8_t * tom_ram_8; -//static uint8_t * paletteRam; static uint8_t src; static uint8_t dst; static uint8_t misc; @@ -354,10 +274,6 @@ static uint32_t inner_loop; static uint32_t a2_psize; static uint32_t a1_psize; static uint32_t gouraud_add; -//static uint32_t gouraud_data; -//static uint16_t gint[4]; -//static uint16_t gfrac[4]; -//static uint8_t gcolour[4]; static int gd_i[4]; static int gd_c[4]; static int gd_ia, gd_ca; @@ -367,57 +283,18 @@ static uint32_t z_i[4]; static int32_t a1_clip_x, a1_clip_y; -// In the spirit of "get it right first, *then* optimize" I've taken the liberty -// of removing all the unnecessary code caching. If it turns out to be a good way -// to optimize the blitter, then we may revisit it in the future... - // // Generic blit handler // void blitter_generic(uint32_t cmd) { -/* -Blit! (0018FA70 <- 008DDC40) count: 2 x 13, A1/2_FLAGS: 00014218/00013C18 [cmd: 1401060C] - CMD -> src: SRCENX dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: BCOMPEN BKGWREN - A1 step values: -2 (X), 1 (Y) - A2 step values: -1 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 192 (1E), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 100/12, A2 x/y: 106/0 Pattern: 000000F300000000 -*/ -//if (effect_start) -// specialLog = true; -/*if (cmd == 0x1401060C && blit_start_log) - specialLog = true;//*/ -//Testing only! -//uint32_t logGo = ((cmd == 0x01800E01 && REG(A1_BASE) == 0x898000) ? 1 : 0); uint32_t srcdata, srczdata, dstdata, dstzdata, writedata, inhibit; uint32_t bppSrc = (DSTA2 ? 1 << ((REG(A1_FLAGS) >> 3) & 0x07) : 1 << ((REG(A2_FLAGS) >> 3) & 0x07)); -if (specialLog) -{ - WriteLog("About to do n x m blit (BM width is ? pixels)...\n"); - WriteLog("A1_STEP_X/Y = %08X/%08X, A2_STEP_X/Y = %08X/%08X\n", a1_step_x, a1_step_y, a2_step_x, a2_step_y); -} -/* if (BCOMPEN) - { - if (DSTA2) - a1_xadd = 0; - else - a2_xadd = 0; - }//*/ - while (outer_loop--) { -if (specialLog) -{ - WriteLog(" A1_X/Y = %08X/%08X, A2_X/Y = %08X/%08X\n", a1_x, a1_y, a2_x, a2_y); -} uint32_t a1_start = a1_x, a2_start = a2_x, bitPos = 0; - //Kludge for Hover Strike... - //I wonder if this kludge is in conjunction with the SRCENX down below... - // This isn't so much a kludge but the way things work in BCOMPEN mode...! if (BCOMPEN && SRCENX) { if (n_pixels < bppSrc) @@ -427,34 +304,27 @@ if (specialLog) inner_loop = n_pixels; while (inner_loop--) { -if (specialLog) -{ - WriteLog(" A1_X/Y = %08X/%08X, A2_X/Y = %08X/%08X\n", a1_x, a1_y, a2_x, a2_y); -} srcdata = srczdata = dstdata = dstzdata = writedata = inhibit = 0; - if (!DSTA2) // Data movement: A1 <- A2 + if (!DSTA2) { - // load src data and Z -// if (SRCEN) - if (SRCEN || SRCENX) // Not sure if this is correct... (seems to be...!) + if (SRCEN || SRCENX) { srcdata = READ_PIXEL(a2, REG(A2_FLAGS)); if (SRCENZ) srczdata = READ_ZDATA(a2, REG(A2_FLAGS)); - else if (cmd & 0x0001C020) // PATDSEL | TOPBEN | TOPNEN | DSTWRZ + else if (cmd & 0x0001C020) srczdata = READ_RDATA(SRCZINT, a2, REG(A2_FLAGS), a2_phrase_mode); } - else // Use SRCDATA register... + else { srcdata = READ_RDATA(SRCDATA, a2, REG(A2_FLAGS), a2_phrase_mode); - if (cmd & 0x0001C020) // PATDSEL | TOPBEN | TOPNEN | DSTWRZ + if (cmd & 0x0001C020) srczdata = READ_RDATA(SRCZINT, a2, REG(A2_FLAGS), a2_phrase_mode); } - // load dst data and Z if (DSTEN) { dstdata = READ_PIXEL(a1, REG(A1_FLAGS)); @@ -472,143 +342,33 @@ if (specialLog) dstzdata = READ_RDATA(DSTZ, a1, REG(A1_FLAGS), a1_phrase_mode); } -/*This wasn't working... // a1 clipping - if (cmd & 0x00000040) - { - if (a1_x < 0 || a1_y < 0 || (a1_x >> 16) >= (REG(A1_CLIP) & 0x7FFF) - || (a1_y >> 16) >= ((REG(A1_CLIP) >> 16) & 0x7FFF)) - inhibit = 1; - }//*/ - if (GOURZ) srczdata = z_i[colour_index] >> 16; - // apply z comparator if (Z_OP_INF && srczdata < dstzdata) inhibit = 1; if (Z_OP_EQU && srczdata == dstzdata) inhibit = 1; if (Z_OP_SUP && srczdata > dstzdata) inhibit = 1; - // apply data comparator -// Note: DCOMPEN only works in 8/16 bpp modes! !!! FIX !!! -// Does BCOMPEN only work in 1 bpp mode??? -// No, but it always does a 1 bit expansion no matter what the BPP of the channel is set to. !!! FIX !!! -// This is bit tricky... We need to fix the XADD value so that it acts like a 1BPP value while inside -// an 8BPP space. if (DCOMPEN | BCOMPEN) { -//Temp, for testing Hover Strike -//Doesn't seem to do it... Why? -//What needs to happen here is twofold. First, the address generator in the outer loop has -//to honor the BPP when calculating the start address (which it kinda does already). Second, -//it has to step bit by bit when using BCOMPEN. How to do this??? - if (BCOMPEN) -//small problem with this approach: it's not accurate... We need a proper address to begin with -//and *then* we can do the bit stepping from there the way it's *supposed* to be done... !!! FIX !!! -//[DONE] - { - uint32_t pixShift = (~bitPos) & (bppSrc - 1); - srcdata = (srcdata >> pixShift) & 0x01; - - bitPos++; -// if (bitPos % bppSrc == 0) -// a2_x += 0x00010000; - } -/* -Interesting (Hover Strike--large letter): - -Blit! (0018FA70 <- 008DDC40) count: 2 x 13, A1/2_FLAGS: 00014218/00013C18 [cmd: 1401060C] - CMD -> src: SRCENX dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: BCOMPEN BKGWREN - A1 step values: -2 (X), 1 (Y) - A2 step values: -1 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 192 (1E), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 100/12, A2 x/y: 106/0 Pattern: 000000F300000000 - -Blit! (0018FA70 <- 008DDC40) count: 8 x 13, A1/2_FLAGS: 00014218/00013C18 [cmd: 1401060C] - CMD -> src: SRCENX dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: BCOMPEN BKGWREN - A1 step values: -8 (X), 1 (Y) - A2 step values: -1 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 192 (1E), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 102/12, A2 x/y: 107/0 Pattern: 000000F300000000 - -Blit! (0018FA70 <- 008DDC40) count: 1 x 13, A1/2_FLAGS: 00014218/00013C18 [cmd: 1401060C] - CMD -> src: SRCENX dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: BCOMPEN BKGWREN - A1 step values: -1 (X), 1 (Y) - A2 step values: -1 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 192 (1E), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 118/12, A2 x/y: 70/0 Pattern: 000000F300000000 - -Blit! (0018FA70 <- 008DDC40) count: 8 x 13, A1/2_FLAGS: 00014218/00013C18 [cmd: 1401060C] - CMD -> src: SRCENX dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: BCOMPEN BKGWREN - A1 step values: -8 (X), 1 (Y) - A2 step values: -1 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 192 (1E), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 119/12, A2 x/y: 71/0 Pattern: 000000F300000000 - -Blit! (0018FA70 <- 008DDC40) count: 1 x 13, A1/2_FLAGS: 00014218/00013C18 [cmd: 1401060C] - CMD -> src: SRCENX dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: BCOMPEN BKGWREN - A1 step values: -1 (X), 1 (Y) - A2 step values: -1 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 192 (1E), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 127/12, A2 x/y: 66/0 Pattern: 000000F300000000 - -Blit! (0018FA70 <- 008DDC40) count: 8 x 13, A1/2_FLAGS: 00014218/00013C18 [cmd: 1401060C] - CMD -> src: SRCENX dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: BCOMPEN BKGWREN - A1 step values: -8 (X), 1 (Y) - A2 step values: -1 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 8bpp, z-off: 0, width: 192 (1E), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 128/12, A2 x/y: 67/0 Pattern: 000000F300000000 -*/ + if (BCOMPEN) + { + uint32_t pixShift = (~bitPos) & (bppSrc - 1); + srcdata = (srcdata >> pixShift) & 0x01; + bitPos++; + } if (!CMPDST) { -//WriteLog("Blitter: BCOMPEN set on command %08X inhibit prev:%u, now:", cmd, inhibit); - // compare source pixel with pattern pixel -/* -Blit! (000B8250 <- 0012C3A0) count: 16 x 1, A1/2_FLAGS: 00014420/00012000 [cmd: 05810001] - CMD -> src: SRCEN dst: misc: a1ctl: mode: ity: PATDSEL z-op: op: LFU_REPLACE ctrl: BCOMPEN - A1 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 384 (22), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 1bpp, z-off: 0, width: 16 (10), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - x/y: 0/20 -... -*/ -// AvP is still wrong, could be cuz it's doing A1 -> A2... - -// Src is the 1bpp bitmap... DST is the PATTERN!!! -// This seems to solve at least ONE of the problems with MC3D... -// Why should this be inverted??? -// Bcuz it is. This is supposed to be used only for a bit -> pixel expansion... -/* if (srcdata == READ_RDATA(PATTERNDATA, a2, REG(A2_FLAGS), a2_phrase_mode)) -// if (srcdata != READ_RDATA(PATTERNDATA, a2, REG(A2_FLAGS), a2_phrase_mode)) - inhibit = 1;//*/ -/* uint32_t A2bpp = 1 << ((REG(A2_FLAGS) >> 3) & 0x07); - if (A2bpp == 1 || A2bpp == 16 || A2bpp == 8) - inhibit = (srcdata == 0 ? 1: 0); -// inhibit = !srcdata; - else - WriteLog("Blitter: Bad BPP (%u) selected for BCOMPEN mode!\n", A2bpp);//*/ -// What it boils down to is this: - if (srcdata == 0) - inhibit = 1;//*/ + inhibit = 1; } else { - // compare destination pixel with pattern pixel if (dstdata == READ_RDATA(PATTERNDATA, a1, REG(A1_FLAGS), a1_phrase_mode)) -// if (dstdata != READ_RDATA(PATTERNDATA, a1, REG(A1_FLAGS), a1_phrase_mode)) inhibit = 1; } - -// This is DEFINITELY WRONG -// if (a1_phrase_mode || a2_phrase_mode) -// inhibit = !inhibit; } if (CLIPA1) @@ -617,57 +377,18 @@ Blit! (000B8250 <- 0012C3A0) count: 16 x 1, A1/2_FLAGS: 00014420/00012000 [cmd: && (a1_y >> 16) < a1_clip_y && (a1_y >> 16) >= 0) ? 0 : 1); } - // compute the write data and store if (!inhibit) { -// Houston, we have a problem... -// Look here, at PATDSEL and GOURD. If both are active (as they are on the BIOS intro), then there's -// a conflict! E.g.: -//Blit! (00100000 <- 000095D0) count: 3 x 1, A1/2_FLAGS: 00014220/00004020 [cmd: 00011008] -// CMD -> src: dst: DSTEN misc: a1ctl: mode: GOURD ity: PATDSEL z-op: op: LFU_CLEAR ctrl: -// A1 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 320 (21), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD -// A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 256 (20), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD -// A1 x/y: 90/171, A2 x/y: 808/0 Pattern: 776D770077007700 - if (PATDSEL) { - // use pattern data for write data writedata = READ_RDATA(PATTERNDATA, a1, REG(A1_FLAGS), a1_phrase_mode); } else if (ADDDSEL) { -/*if (blit_start_log) - WriteLog("BLIT: ADDDSEL srcdata: %08X\, dstdata: %08X, ", srcdata, dstdata);//*/ - - // intensity addition -//Ok, this is wrong... Or is it? Yes, it's wrong! !!! FIX !!! -/* writedata = (srcdata & 0xFF) + (dstdata & 0xFF); - if (!(TOPBEN) && writedata > 0xFF) -// writedata = 0xFF; - writedata &= 0xFF; - writedata |= (srcdata & 0xF00) + (dstdata & 0xF00); - if (!(TOPNEN) && writedata > 0xFFF) -// writedata = 0xFFF; - writedata &= 0xFFF; - writedata |= (srcdata & 0xF000) + (dstdata & 0xF000);//*/ -//notneeded--writedata &= 0xFFFF; -/*if (blit_start_log) - WriteLog("writedata: %08X\n", writedata);//*/ -/* -Hover Strike ADDDSEL blit: - -Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cmd: 00020208] - CMD -> src: dst: DSTEN misc: a1ctl: UPDA1 mode: ity: ADDDSEL z-op: op: LFU_CLEAR ctrl: - A1 step values: -320 (X), 1 (Y) - A1 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 256 (20), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 0/0, A2 x/y: 3288/0 Pattern: 0000000000000000 SRCDATA: 00FD00FD00FD00FD -*/ writedata = (srcdata & 0xFF) + (dstdata & 0xFF); if (!TOPBEN) { -//This is correct now, but slow... int16_t s = (srcdata & 0xFF) | (srcdata & 0x80 ? 0xFF00 : 0x0000), d = dstdata & 0xFF; int16_t sum = s + d; @@ -680,7 +401,6 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm writedata = (uint32_t)sum; } -//This doesn't seem right... Looks like it would muck up the low byte... !!! FIX !!! writedata |= (srcdata & 0xF00) + (dstdata & 0xF00); if (!TOPNEN && writedata > 0xFFF) @@ -698,10 +418,6 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm if (LFU_A) writedata |= srcdata & dstdata; } -//Although, this looks like it's OK... (even if it is shitty!) -//According to JTRM, this is part of the four things the blitter does with the write data (the other -//three being PATDSEL, ADDDSEL, and LFU (default). I'm not sure which gets precedence, this or PATDSEL -//(see above blit example)... if (GOURD) writedata = ((gd_c[colour_index]) << 8) | (gd_i[colour_index] >> 16); @@ -725,42 +441,30 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm srczdata = dstzdata; } -//Tried 2nd below for Hover Strike: No dice. - if (/*a1_phrase_mode || */BKGWREN || !inhibit) -// if (/*a1_phrase_mode || BKGWREN ||*/ !inhibit) + if (BKGWREN || !inhibit) { -/*if (((REG(A1_FLAGS) >> 3) & 0x07) == 5) -{ - uint32_t offset = a1_addr+(PIXEL_OFFSET_32(a1)<<2); -// (((((uint32_t)a##_y >> 16) * a##_width) + (((uint32_t)a##_x >> 16) & ~1)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 16) & 1)) - if ((offset >= 0x1FF020 && offset <= 0x1FF03F) || (offset >= 0x1FF820 && offset <= 0x1FF83F)) - WriteLog("32bpp pixel write: A1 Phrase mode --> "); -}//*/ - // write to the destination WRITE_PIXEL(a1, REG(A1_FLAGS), writedata); if (DSTWRZ) WRITE_ZDATA(a1, REG(A1_FLAGS), srczdata); } } - else // if (DSTA2) // Data movement: A1 -> A2 + else { - // load src data and Z if (SRCEN) { srcdata = READ_PIXEL(a1, REG(A1_FLAGS)); if (SRCENZ) srczdata = READ_ZDATA(a1, REG(A1_FLAGS)); - else if (cmd & 0x0001C020) // PATDSEL | TOPBEN | TOPNEN | DSTWRZ + else if (cmd & 0x0001C020) srczdata = READ_RDATA(SRCZINT, a1, REG(A1_FLAGS), a1_phrase_mode); } else { srcdata = READ_RDATA(SRCDATA, a1, REG(A1_FLAGS), a1_phrase_mode); - if (cmd & 0x001C020) // PATDSEL | TOPBEN | TOPNEN | DSTWRZ + if (cmd & 0x001C020) srczdata = READ_RDATA(SRCZINT, a1, REG(A1_FLAGS), a1_phrase_mode); } - // load dst data and Z if (DSTEN) { dstdata = READ_PIXEL(a2, REG(A2_FLAGS)); @@ -779,48 +483,22 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm if (GOURZ) srczdata = z_i[colour_index] >> 16; - // apply z comparator if (Z_OP_INF && srczdata < dstzdata) inhibit = 1; if (Z_OP_EQU && srczdata == dstzdata) inhibit = 1; if (Z_OP_SUP && srczdata > dstzdata) inhibit = 1; - // apply data comparator -//NOTE: The bit comparator (BCOMPEN) is NOT the same at the data comparator! if (DCOMPEN | BCOMPEN) { if (!CMPDST) { - // compare source pixel with pattern pixel -// AvP: Numbers are correct, but sprites are not! -//This doesn't seem to be a problem... But could still be wrong... -/* if (srcdata == READ_RDATA(PATTERNDATA, a1, REG(A1_FLAGS), a1_phrase_mode)) -// if (srcdata != READ_RDATA(PATTERNDATA, a1, REG(A1_FLAGS), a1_phrase_mode)) - inhibit = 1;//*/ -// This is probably not 100% correct... It works in the 1bpp case -// (in A1 <- A2 mode, that is...) -// AvP: This is causing blocks to be written instead of bit patterns... -// Works now... -// NOTE: We really should separate out the BCOMPEN & DCOMPEN stuff! -/* uint32_t A1bpp = 1 << ((REG(A1_FLAGS) >> 3) & 0x07); - if (A1bpp == 1 || A1bpp == 16 || A1bpp == 8) - inhibit = (srcdata == 0 ? 1: 0); - else - WriteLog("Blitter: Bad BPP (%u) selected for BCOMPEN mode!\n", A1bpp);//*/ -// What it boils down to is this: if (srcdata == 0) - inhibit = 1;//*/ + inhibit = 1; } else { - // compare destination pixel with pattern pixel if (dstdata == READ_RDATA(PATTERNDATA, a2, REG(A2_FLAGS), a2_phrase_mode)) -// if (dstdata != READ_RDATA(PATTERNDATA, a2, REG(A2_FLAGS), a2_phrase_mode)) inhibit = 1; } - -// This is DEFINITELY WRONG -// if (a1_phrase_mode || a2_phrase_mode) -// inhibit = !inhibit; } if (CLIPA1) @@ -829,17 +507,14 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm && (a1_y >> 16) < a1_clip_y && (a1_y >> 16) >= 0) ? 0 : 1); } - // compute the write data and store if (!inhibit) { if (PATDSEL) { - // use pattern data for write data writedata = READ_RDATA(PATTERNDATA, a2, REG(A2_FLAGS), a2_phrase_mode); } else if (ADDDSEL) { - // intensity addition writedata = (srcdata & 0xFF) + (dstdata & 0xFF); if (!(TOPBEN) && writedata > 0xFF) writedata = 0xFF; @@ -883,15 +558,8 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm srczdata = dstzdata; } - if (/*a2_phrase_mode || */BKGWREN || !inhibit) + if (BKGWREN || !inhibit) { -/*if (logGo) -{ - uint32_t offset = a2_addr+(PIXEL_OFFSET_16(a2)<<1); -// (((((uint32_t)a##_y >> 16) * a##_width) + (((uint32_t)a##_x >> 16) & ~1)) * (1 + a##_pitch) + (((uint32_t)a##_x >> 16) & 1)) - WriteLog("[%08X:%04X] ", offset, writedata); -}//*/ - // write to the destination WRITE_PIXEL(a2, REG(A2_FLAGS), writedata); if (DSTWRZ) @@ -899,11 +567,8 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm } } - // Update x and y (inner loop) -//Now it does! But crappy, crappy, crappy! !!! FIX !!! [DONE] -//This is less than ideal, but it works... if (!BCOMPEN) - {//*/ + { a1_x += a1_xadd, a1_y += a1_yadd; a2_x = (a2_x + a2_xadd) & a2_mask_x, a2_y = (a2_y + a2_yadd) & a2_mask_y; } @@ -922,7 +587,7 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm if (bitPos % bppSrc == 0) a1_x += a1_xadd; } - }//*/ + } if (GOURZ) z_i[colour_index] += zadd; @@ -930,95 +595,30 @@ Blit! (00098D90 <- 0081DDC0) count: 320 x 287, A1/2_FLAGS: 00004220/00004020 [cm if (GOURD || SRCSHADE) { gd_i[colour_index] += gd_ia; -//Hmm, this doesn't seem to do anything... -//But it is correct according to the JTRM...! -if ((int32_t)gd_i[colour_index] < 0) - gd_i[colour_index] = 0; -if (gd_i[colour_index] > 0x00FFFFFF) - gd_i[colour_index] = 0x00FFFFFF;//*/ + + if ((int32_t)gd_i[colour_index] < 0) + gd_i[colour_index] = 0; + if (gd_i[colour_index] > 0x00FFFFFF) + gd_i[colour_index] = 0x00FFFFFF; gd_c[colour_index] += gd_ca; -if ((int32_t)gd_c[colour_index] < 0) - gd_c[colour_index] = 0; -if (gd_c[colour_index] > 0x000000FF) - gd_c[colour_index] = 0x000000FF;//*/ + if ((int32_t)gd_c[colour_index] < 0) + gd_c[colour_index] = 0; + if (gd_c[colour_index] > 0x000000FF) + gd_c[colour_index] = 0x000000FF; } if (GOURD || SRCSHADE || GOURZ) { if (a1_phrase_mode) -//This screws things up WORSE (for the BIOS opening screen) -// if (a1_phrase_mode || a2_phrase_mode) colour_index = (colour_index + 1) & 0x03; } } -/* -Here's the problem... The phrase mode code! -Blit! (00100000 -> 00148000) count: 327 x 267, A1/2_FLAGS: 00004420/00004420 [cmd: 41802E01] - CMD -> src: SRCEN dst: misc: a1ctl: UPDA1 UPDA2 mode: DSTA2 GOURZ ity: z-op: op: LFU_REPLACE ctrl: SRCSHADE - A1 step values: -327 (X), 1 (Y) - A2 step values: -327 (X), 1 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 384 (22), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 384 (22), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 28/58, A2 x/y: 28/58 Pattern: 00EA7BEA77EA77EA SRCDATA: 7BFF7BFF7BFF7BFF - -Below fixes it, but then borks: -; O - -Blit! (00110000 <- 0010B2A8) count: 12 x 12, A1/2_FLAGS: 000042E2/00000020 [cmd: 09800609] - CMD -> src: SRCEN dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: z-op: op: LFU_REPLACE ctrl: DCOMPEN - A1 step values: -15 (X), 1 (Y) - A2 step values: -4 (X), 0 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 173/144, A2 x/y: 4052/0 - -Lesse, with pre-add we'd have: - - oooooooooooo -00001111222233334444555566667777 - ^ ^starts here... - | ^ends here. - |rolls back to here. Hmm. - -*/ -//NOTE: The way to fix the CD BIOS is to uncomment below and comment the stuff after -// the phrase mode mucking around. But it fucks up everything else... -//#define SCREWY_CD_DEPENDENT -#ifdef SCREWY_CD_DEPENDENT - a1_x += a1_step_x; - a1_y += a1_step_y; - a2_x += a2_step_x; - a2_y += a2_step_y;//*/ -#endif - - //New: Phrase mode taken into account! :-p -/* if (a1_phrase_mode) // v1 + if (a1_phrase_mode) { - // Bump the pointer to the next phrase boundary - // Even though it works, this is crappy... Clean it up! uint32_t size = 64 / a1_psize; - // Crappy kludge... ('aligning' source to destination) - if (a2_phrase_mode && DSTA2) - { - uint32_t extra = (a2_start >> 16) % size; - a1_x += extra << 16; - } - - uint32_t newx = (a1_x >> 16) / size; - uint32_t newxrem = (a1_x >> 16) % size; - a1_x &= 0x0000FFFF; - a1_x |= (((newx + (newxrem == 0 ? 0 : 1)) * size) & 0xFFFF) << 16; - }//*/ - if (a1_phrase_mode) // v2 - { - // Bump the pointer to the next phrase boundary - // Even though it works, this is crappy... Clean it up! - uint32_t size = 64 / a1_psize; - - // Crappy kludge... ('aligning' source to destination) if (a2_phrase_mode && DSTA2) { uint32_t extra = (a2_start >> 16) % size; @@ -1029,33 +629,10 @@ Lesse, with pre-add we'd have: a1_x = (a1_x + pixelSize) & ~pixelSize; } -/* if (a2_phrase_mode) // v1 + if (a2_phrase_mode) { - // Bump the pointer to the next phrase boundary - // Even though it works, this is crappy... Clean it up! uint32_t size = 64 / a2_psize; - // Crappy kludge... ('aligning' source to destination) - // Prolly should do this for A1 channel as well... [DONE] - if (a1_phrase_mode && !DSTA2) - { - uint32_t extra = (a1_start >> 16) % size; - a2_x += extra << 16; - } - - uint32_t newx = (a2_x >> 16) / size; - uint32_t newxrem = (a2_x >> 16) % size; - a2_x &= 0x0000FFFF; - a2_x |= (((newx + (newxrem == 0 ? 0 : 1)) * size) & 0xFFFF) << 16; - }//*/ - if (a2_phrase_mode) // v1 - { - // Bump the pointer to the next phrase boundary - // Even though it works, this is crappy... Clean it up! - uint32_t size = 64 / a2_psize; - - // Crappy kludge... ('aligning' source to destination) - // Prolly should do this for A1 channel as well... [DONE] if (a1_phrase_mode && !DSTA2) { uint32_t extra = (a1_start >> 16) % size; @@ -1065,34 +642,15 @@ Lesse, with pre-add we'd have: uint32_t pixelSize = (size - 1) << 16; a2_x = (a2_x + pixelSize) & ~pixelSize; } - - //Not entirely: This still mucks things up... !!! FIX !!! - //Should this go before or after the phrase mode mucking around? -#ifndef SCREWY_CD_DEPENDENT - a1_x += a1_step_x; - a1_y += a1_step_y; - a2_x += a2_step_x; - a2_y += a2_step_y;//*/ -#endif } - // write values back to registers WREG(A1_PIXEL, (a1_y & 0xFFFF0000) | ((a1_x >> 16) & 0xFFFF)); WREG(A1_FPIXEL, (a1_y << 16) | (a1_x & 0xFFFF)); WREG(A2_PIXEL, (a2_y & 0xFFFF0000) | ((a2_x >> 16) & 0xFFFF)); -specialLog = false; } void blitter_blit(uint32_t cmd) { -//Apparently this is doing *something*, just not sure exactly what... -/*if (cmd == 0x41802E01) -{ - WriteLog("BLIT: Found our blit. Was: %08X ", cmd); - cmd = 0x01800E01; - WriteLog("Is: %08X\n", cmd); -}//*/ - uint32_t pitchValue[4] = { 0, 1, 3, 2 }; colour_index = 0; src = cmd & 0x07; @@ -1105,8 +663,6 @@ void blitter_blit(uint32_t cmd) op = (cmd >> 21) & 0x0F; ctrl = (cmd >> 25) & 0x3F; - // Addresses in A1/2_BASE are *phrase* aligned, i.e., bottom three bits are ignored! - // NOTE: This fixes Rayman's bad collision detection AND keeps T2K working! a1_addr = REG(A1_BASE) & 0xFFFFFFF8; a2_addr = REG(A2_BASE) & 0xFFFFFFF8; @@ -1124,87 +680,49 @@ void blitter_blit(uint32_t cmd) a1_x = (REG(A1_PIXEL) << 16) | (REG(A1_FPIXEL) & 0xFFFF); a1_y = (REG(A1_PIXEL) & 0xFFFF0000) | (REG(A1_FPIXEL) >> 16); -//According to the JTRM, X is restricted to 15 bits and Y is restricted to 12. -//But it seems to fuck up T2K! !!! FIX !!! -//Could it be sign extended??? Doesn't seem to be so according to JTRM -// a1_x &= 0x7FFFFFFF, a1_y &= 0x0FFFFFFF; -//Actually, it says that the X is 16 bits. But it still seems to mess with the Y when restricted to 12... -// a1_y &= 0x0FFFFFFF; -// a1_width = blitter_scanline_width[((REG(A1_FLAGS) & 0x00007E00) >> 9)]; -// According to JTRM, this must give a *whole number* of phrases in the current -// pixel size (this means the lookup above is WRONG)... !!! FIX !!! uint32_t m = (REG(A1_FLAGS) >> 9) & 0x03, e = (REG(A1_FLAGS) >> 11) & 0x0F; - a1_width = ((0x04 | m) << e) >> 2;//*/ + a1_width = ((0x04 | m) << e) >> 2; a2_x = (REG(A2_PIXEL) & 0x0000FFFF) << 16; a2_y = (REG(A2_PIXEL) & 0xFFFF0000); -//According to the JTRM, X is restricted to 15 bits and Y is restricted to 12. -//But it seems to fuck up T2K! !!! FIX !!! -// a2_x &= 0x7FFFFFFF, a2_y &= 0x0FFFFFFF; -//Actually, it says that the X is 16 bits. But it still seems to mess with the Y when restricted to 12... -// a2_y &= 0x0FFFFFFF; -// a2_width = blitter_scanline_width[((REG(A2_FLAGS) & 0x00007E00) >> 9)]; -// According to JTRM, this must give a *whole number* of phrases in the current -// pixel size (this means the lookup above is WRONG)... !!! FIX !!! m = (REG(A2_FLAGS) >> 9) & 0x03, e = (REG(A2_FLAGS) >> 11) & 0x0F; - a2_width = ((0x04 | m) << e) >> 2;//*/ + a2_width = ((0x04 | m) << e) >> 2; a2_mask_x = ((REG(A2_MASK) & 0x0000FFFF) << 16) | 0xFFFF; a2_mask_y = (REG(A2_MASK) & 0xFFFF0000) | 0xFFFF; - // Check for "use mask" flag if (!(REG(A2_FLAGS) & 0x8000)) { - a2_mask_x = 0xFFFFFFFF; // must be 16.16 - a2_mask_y = 0xFFFFFFFF; // must be 16.16 + a2_mask_x = 0xFFFFFFFF; + a2_mask_y = 0xFFFFFFFF; } a1_phrase_mode = 0; - // According to the official documentation, a hardware bug ties A2's yadd bit to A1's... a2_yadd = a1_yadd = (YADD1_A1 ? 1 << 16 : 0); if (YSIGNSUB_A1) a1_yadd = -a1_yadd; - // determine a1_xadd switch (xadd_a1_control) { - case XADDPHR: -// This is a documented Jaguar bug relating to phrase mode and truncation... Look into it! - // add phrase offset to X and truncate - a1_xadd = 1 << 16; - a1_phrase_mode = 1; - break; - case XADDPIX: - // add pixelsize (1) to X - a1_xadd = 1 << 16; - break; - case XADD0: - // add zero (for those nice vertical lines) - a1_xadd = 0; - break; - case XADDINC: - // add the contents of the increment register - a1_xadd = (REG(A1_INC) << 16) | (REG(A1_FINC) & 0x0000FFFF); - a1_yadd = (REG(A1_INC) & 0xFFFF0000) | (REG(A1_FINC) >> 16); - break; + case XADDPHR: + a1_xadd = 1 << 16; + a1_phrase_mode = 1; + break; + case XADDPIX: + a1_xadd = 1 << 16; + break; + case XADD0: + a1_xadd = 0; + break; + case XADDINC: + a1_xadd = (REG(A1_INC) << 16) | (REG(A1_FINC) & 0x0000FFFF); + a1_yadd = (REG(A1_INC) & 0xFFFF0000) | (REG(A1_FINC) >> 16); + break; } - -//Blit! (0011D000 -> 000B9600) count: 228 x 1, A1/2_FLAGS: 00073820/00064220 [cmd: 41802801] -// A1 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 128 (1C), addctl: XADDINC YADD1 XSIGNADD YSIGNADD -// A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 320 (21), addctl: XADD0 YADD1 XSIGNADD YSIGNADD -//if (YADD1_A1 && YADD1_A2 && xadd_a2_control == XADD0 && xadd_a1_control == XADDINC)// && -// uint32_t a1f = REG(A1_FLAGS), a2f = REG(A2_FLAGS); -//Ok, so this ISN'T it... Prolly the XADDPHR code above that's doing it... -//if (REG(A1_FLAGS) == 0x00073820 && REG(A2_FLAGS) == 0x00064220 && cmd == 0x41802801) -// A1 x/y: 14368/7, A2 x/y: 150/36 -//This is it... The problem... -//if ((a1_x >> 16) == 14368) // 14368 = $3820 -// return; //Lesse what we got... - if (XSIGNSUB_A1) a1_xadd = -a1_xadd; @@ -1213,37 +731,25 @@ void blitter_blit(uint32_t cmd) a2_phrase_mode = 0; - // determine a2_xadd switch (xadd_a2_control) { - case XADDPHR: - // add phrase offset to X and truncate - a2_xadd = 1 << 16; - a2_phrase_mode = 1; - break; - case XADDPIX: - // add pixelsize (1) to X - a2_xadd = 1 << 16; - break; - case XADD0: - // add zero (for those nice vertical lines) - a2_xadd = 0; - break; -//This really isn't a valid bit combo for A2... Shouldn't this cause the blitter to just say no? - case XADDINC: -WriteLog("BLIT: Asked to use invalid bit combo (XADDINC) for A2...\n"); - // add the contents of the increment register - // since there is no register for a2 we just add 1 -//Let's do nothing, since it's not listed as a valid bit combo... -// a2_xadd = 1 << 16; - break; + case XADDPHR: + a2_xadd = 1 << 16; + a2_phrase_mode = 1; + break; + case XADDPIX: + a2_xadd = 1 << 16; + break; + case XADD0: + a2_xadd = 0; + break; + case XADDINC: + break; } if (XSIGNSUB_A2) a2_xadd = -a2_xadd; - // Modify outer loop steps based on blitter command - a1_step_x = 0; a1_step_y = 0; a2_step_x = 0; @@ -1263,18 +769,13 @@ WriteLog("BLIT: Asked to use invalid bit combo (XADDINC) for A2...\n"); outer_loop = n_lines; - // Clipping... - if (CLIPA1) a1_clip_x = REG(A1_CLIP) & 0x7FFF, a1_clip_y = (REG(A1_CLIP) >> 16) & 0x7FFF; -// This phrase sizing is incorrect as well... !!! FIX !!! [NOTHING TO FIX] -// Err, this is pixel size... (and it's OK) a2_psize = 1 << ((REG(A2_FLAGS) >> 3) & 0x07); a1_psize = 1 << ((REG(A1_FLAGS) >> 3) & 0x07); - // Z-buffering if (GOURZ) { zadd = REG(ZINC); @@ -1283,7 +784,6 @@ WriteLog("BLIT: Asked to use invalid bit combo (XADDINC) for A2...\n"); z_i[v] = REG(PHRASEZ0 + v*4); } - // Gouraud shading if (GOURD || GOURZ || SRCSHADE) { gd_c[0] = blitter_ram[PATTERNDATA + 6]; @@ -1313,266 +813,27 @@ WriteLog("BLIT: Asked to use invalid bit combo (XADDINC) for A2...\n"); gd_ca = 0xFFFFFF00 | gd_ca; } - // Bit comparitor fixing... -/* if (BCOMPEN) - { - // Determine the data flow direction... - if (!DSTA2) - a2_step_x /= (1 << ((REG(A2_FLAGS) >> 3) & 0x07)); - else - ;//add this later - }//*/ -/* if (BCOMPEN)//Kludge for Hover Strike... !!! FIX !!! - { - // Determine the data flow direction... - if (!DSTA2) - a2_x <<= 3; - }//*/ - -#ifdef LOG_BLITS - if (start_logging) - { - WriteLog("Blit!\n"); - WriteLog(" cmd = 0x%.8x\n",cmd); - WriteLog(" a1_base = %08X\n", a1_addr); - WriteLog(" a1_pitch = %d\n", a1_pitch); - WriteLog(" a1_psize = %d\n", a1_psize); - WriteLog(" a1_width = %d\n", a1_width); - WriteLog(" a1_xadd = %f (phrase=%d)\n", (float)a1_xadd / 65536.0, a1_phrase_mode); - WriteLog(" a1_yadd = %f\n", (float)a1_yadd / 65536.0); - WriteLog(" a1_xstep = %f\n", (float)a1_step_x / 65536.0); - WriteLog(" a1_ystep = %f\n", (float)a1_step_y / 65536.0); - WriteLog(" a1_x = %f\n", (float)a1_x / 65536.0); - WriteLog(" a1_y = %f\n", (float)a1_y / 65536.0); - WriteLog(" a1_zoffs = %i\n",a1_zoffs); - - WriteLog(" a2_base = %08X\n", a2_addr); - WriteLog(" a2_pitch = %d\n", a2_pitch); - WriteLog(" a2_psize = %d\n", a2_psize); - WriteLog(" a2_width = %d\n", a2_width); - WriteLog(" a2_xadd = %f (phrase=%d)\n", (float)a2_xadd / 65536.0, a2_phrase_mode); - WriteLog(" a2_yadd = %f\n", (float)a2_yadd / 65536.0); - WriteLog(" a2_xstep = %f\n", (float)a2_step_x / 65536.0); - WriteLog(" a2_ystep = %f\n", (float)a2_step_y / 65536.0); - WriteLog(" a2_x = %f\n", (float)a2_x / 65536.0); - WriteLog(" a2_y = %f\n", (float)a2_y / 65536.0); - WriteLog(" a2_mask_x= 0x%.4x\n",a2_mask_x); - WriteLog(" a2_mask_y= 0x%.4x\n",a2_mask_y); - WriteLog(" a2_zoffs = %i\n",a2_zoffs); - - WriteLog(" count = %d x %d\n", n_pixels, n_lines); - - WriteLog(" command = %08X\n", cmd); - WriteLog(" dsten = %i\n",DSTEN); - WriteLog(" srcen = %i\n",SRCEN); - WriteLog(" patdsel = %i\n",PATDSEL); - WriteLog(" color = 0x%.8x\n",REG(PATTERNDATA)); - WriteLog(" dcompen = %i\n",DCOMPEN); - WriteLog(" bcompen = %i\n",BCOMPEN); - WriteLog(" cmpdst = %i\n",CMPDST); - WriteLog(" GOURZ = %i\n",GOURZ); - WriteLog(" GOURD = %i\n",GOURD); - WriteLog(" SRCSHADE= %i\n",SRCSHADE); - } -#endif - -//NOTE: Pitch is ignored! - -//This *might* be the altimeter blits (they are)... -//On captured screen, x-pos for black (inner) is 259, for pink is 257 -//Black is short by 3, pink is short by 1... -/* -Blit! (00110000 <- 000BF010) count: 9 x 31, A1/2_FLAGS: 000042E2/00010020 [cmd: 00010200] - CMD -> src: dst: misc: a1ctl: UPDA1 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 262/124, A2 x/y: 128/0 -Blit! (00110000 <- 000BF010) count: 5 x 38, A1/2_FLAGS: 000042E2/00010020 [cmd: 00010200] - CMD -> src: dst: misc: a1ctl: UPDA1 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 264/117, A2 x/y: 407/0 - -Blit! (00110000 <- 000BF010) count: 9 x 23, A1/2_FLAGS: 000042E2/00010020 [cmd: 00010200] - CMD -> src: dst: misc: a1ctl: UPDA1 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: - A1 step values: -10 (X), 1 (Y) - A1 -> pitch: 4(2) phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1(0) phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 262/132, A2 x/y: 129/0 -Blit! (00110000 <- 000BF010) count: 5 x 27, A1/2_FLAGS: 000042E2/00010020 [cmd: 00010200] - CMD -> src: dst: misc: a1ctl: UPDA1 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: - A1 step values: -8 (X), 1 (Y) - A1 -> pitch: 4(2) phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1(0) phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 264/128, A2 x/y: 336/0 - - 264v vCursor ends up here... - xxxxx...` - 111122223333 - -262v vCursor ends up here... - xxxxxxxxx.' - 1111222233334444 - -Fixed! Now for more: - -; This looks like the ship icon in the upper left corner... - -Blit! (00110000 <- 0010B2A8) count: 11 x 12, A1/2_FLAGS: 000042E2/00000020 [cmd: 09800609] - CMD -> src: SRCEN dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: z-op: op: LFU_REPLACE ctrl: DCOMPEN - A1 step values: -12 (X), 1 (Y) - A2 step values: 0 (X), 0 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 20/24, A2 x/y: 5780/0 - -Also fixed! - -More (not sure this is a blitter problem as much as it's a GPU problem): -All but the "M" are trashed... -This does *NOT* look like a blitter problem, as it's rendering properly... -Actually, if you look at the A1 step values, there IS a discrepancy! - -; D - -Blit! (00110000 <- 0010B2A8) count: 12 x 12, A1/2_FLAGS: 000042E2/00000020 [cmd: 09800609] - CMD -> src: SRCEN dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: z-op: op: LFU_REPLACE ctrl: DCOMPEN - A1 step values: -14 (X), 1 (Y) - A2 step values: -4 (X), 0 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 134/144, A2 x/y: 2516/0 -;129,146: +5,-2 - -; E - -Blit! (00110000 <- 0010B2A8) count: 12 x 12, A1/2_FLAGS: 000042E2/00000020 [cmd: 09800609] - CMD -> src: SRCEN dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: z-op: op: LFU_REPLACE ctrl: DCOMPEN - A1 step values: -13 (X), 1 (Y) - A2 step values: -4 (X), 0 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 147/144, A2 x/y: 2660/0 - -; M - -Blit! (00110000 <- 0010B2A8) count: 12 x 12, A1/2_FLAGS: 000042E2/00000020 [cmd: 09800609] - CMD -> src: SRCEN dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: z-op: op: LFU_REPLACE ctrl: DCOMPEN - A1 step values: -12 (X), 1 (Y) - A2 step values: 0 (X), 0 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 160/144, A2 x/y: 3764/0 - -; O - -Blit! (00110000 <- 0010B2A8) count: 12 x 12, A1/2_FLAGS: 000042E2/00000020 [cmd: 09800609] - CMD -> src: SRCEN dst: DSTEN misc: a1ctl: UPDA1 UPDA2 mode: ity: z-op: op: LFU_REPLACE ctrl: DCOMPEN - A1 step values: -15 (X), 1 (Y) - A2 step values: -4 (X), 0 (Y) [mask (unused): 00000000 - FFFFFFFF/FFFFFFFF] - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A1 x/y: 173/144, A2 x/y: 4052/0 - -*/ -//extern int op_start_log; -if (blit_start_log) -{ - const char * ctrlStr[4] = { "XADDPHR\0", "XADDPIX\0", "XADD0\0", "XADDINC\0" }; - const char * bppStr[8] = { "1bpp\0", "2bpp\0", "4bpp\0", "8bpp\0", "16bpp\0", "32bpp\0", "???\0", "!!!\0" }; - const char * opStr[16] = { "LFU_CLEAR", "LFU_NSAND", "LFU_NSAD", "LFU_NOTS", "LFU_SAND", "LFU_NOTD", "LFU_N_SXORD", "LFU_NSORND", - "LFU_SAD", "LFU_XOR", "LFU_D", "LFU_NSORD", "LFU_REPLACE", "LFU_SORND", "LFU_SORD", "LFU_ONE" }; - uint32_t /*src = cmd & 0x07, dst = (cmd >> 3) & 0x07, misc = (cmd >> 6) & 0x03, - a1ctl = (cmd >> 8) & 0x07,*/ mode = (cmd >> 11) & 0x07/*, ity = (cmd >> 14) & 0x0F, - zop = (cmd >> 18) & 0x07, op = (cmd >> 21) & 0x0F, ctrl = (cmd >> 25) & 0x3F*/; - uint32_t a1f = REG(A1_FLAGS), a2f = REG(A2_FLAGS); - uint32_t p1 = a1f & 0x07, p2 = a2f & 0x07, - d1 = (a1f >> 3) & 0x07, d2 = (a2f >> 3) & 0x07, - zo1 = (a1f >> 6) & 0x07, zo2 = (a2f >> 6) & 0x07, - w1 = (a1f >> 9) & 0x3F, w2 = (a2f >> 9) & 0x3F, - ac1 = (a1f >> 16) & 0x1F, ac2 = (a2f >> 16) & 0x1F; - uint32_t iw1 = ((0x04 | (w1 & 0x03)) << ((w1 & 0x3C) >> 2)) >> 2; - uint32_t iw2 = ((0x04 | (w2 & 0x03)) << ((w2 & 0x3C) >> 2)) >> 2; - WriteLog("Blit! (%08X %s %08X) count: %d x %d, A1/2_FLAGS: %08X/%08X [cmd: %08X]\n", a1_addr, (mode&0x01 ? "->" : "<-"), a2_addr, n_pixels, n_lines, a1f, a2f, cmd); -// WriteLog(" CMD -> src: %d, dst: %d, misc: %d, a1ctl: %d, mode: %d, ity: %1X, z-op: %d, op: %1X, ctrl: %02X\n", src, dst, misc, a1ctl, mode, ity, zop, op, ctrl); - - WriteLog(" CMD -> src: %s%s%s ", (cmd & 0x0001 ? "SRCEN " : ""), (cmd & 0x0002 ? "SRCENZ " : ""), (cmd & 0x0004 ? "SRCENX" : "")); - WriteLog("dst: %s%s%s ", (cmd & 0x0008 ? "DSTEN " : ""), (cmd & 0x0010 ? "DSTENZ " : ""), (cmd & 0x0020 ? "DSTWRZ" : "")); - WriteLog("misc: %s%s ", (cmd & 0x0040 ? "CLIP_A1 " : ""), (cmd & 0x0080 ? "???" : "")); - WriteLog("a1ctl: %s%s%s ", (cmd & 0x0100 ? "UPDA1F " : ""), (cmd & 0x0200 ? "UPDA1 " : ""), (cmd & 0x0400 ? "UPDA2" : "")); - WriteLog("mode: %s%s%s ", (cmd & 0x0800 ? "DSTA2 " : ""), (cmd & 0x1000 ? "GOURD " : ""), (cmd & 0x2000 ? "GOURZ" : "")); - WriteLog("ity: %s%s%s%s ", (cmd & 0x4000 ? "TOPBEN " : ""), (cmd & 0x8000 ? "TOPNEN " : ""), (cmd & 0x00010000 ? "PATDSEL" : ""), (cmd & 0x00020000 ? "ADDDSEL" : "")); - WriteLog("z-op: %s%s%s ", (cmd & 0x00040000 ? "ZMODELT " : ""), (cmd & 0x00080000 ? "ZMODEEQ " : ""), (cmd & 0x00100000 ? "ZMODEGT" : "")); - WriteLog("op: %s ", opStr[(cmd >> 21) & 0x0F]); - WriteLog("ctrl: %s%s%s%s%s%s\n", (cmd & 0x02000000 ? "CMPDST " : ""), (cmd & 0x04000000 ? "BCOMPEN " : ""), (cmd & 0x08000000 ? "DCOMPEN " : ""), (cmd & 0x10000000 ? "BKGWREN " : ""), (cmd & 0x20000000 ? "BUSHI " : ""), (cmd & 0x40000000 ? "SRCSHADE" : "")); - - if (UPDA1) - WriteLog(" A1 step values: %d (X), %d (Y)\n", a1_step_x >> 16, a1_step_y >> 16); - - if (UPDA2) - WriteLog(" A2 step values: %d (X), %d (Y) [mask (%sused): %08X - %08X/%08X]\n", a2_step_x >> 16, a2_step_y >> 16, (a2f & 0x8000 ? "" : "un"), REG(A2_MASK), a2_mask_x, a2_mask_y); - - WriteLog(" A1 -> pitch: %d phrases, depth: %s, z-off: %d, width: %d (%02X), addctl: %s %s %s %s\n", 1 << p1, bppStr[d1], zo1, iw1, w1, ctrlStr[ac1&0x03], (ac1&0x04 ? "YADD1" : "YADD0"), (ac1&0x08 ? "XSIGNSUB" : "XSIGNADD"), (ac1&0x10 ? "YSIGNSUB" : "YSIGNADD")); - WriteLog(" A2 -> pitch: %d phrases, depth: %s, z-off: %d, width: %d (%02X), addctl: %s %s %s %s\n", 1 << p2, bppStr[d2], zo2, iw2, w2, ctrlStr[ac2&0x03], (ac2&0x04 ? "YADD1" : "YADD0"), (ac2&0x08 ? "XSIGNSUB" : "XSIGNADD"), (ac2&0x10 ? "YSIGNSUB" : "YSIGNADD")); - WriteLog(" A1 x/y: %d/%d, A2 x/y: %d/%d Pattern: %08X%08X SRCDATA: %08X%08X\n", a1_x >> 16, a1_y >> 16, a2_x >> 16, a2_y >> 16, REG(PATTERNDATA), REG(PATTERNDATA + 4), REG(SRCDATA), REG(SRCDATA + 4)); -// blit_start_log = 0; -// op_start_log = 1; -} - - blitter_working = 1; -//#ifndef USE_GENERIC_BLITTER -// if (!blitter_execute_cached_code(blitter_in_cache(cmd))) -//#endif blitter_generic(cmd); - -/*if (blit_start_log) -{ - if (a1_addr == 0xF03000 && a2_addr == 0x004D58) - { - WriteLog("\nBytes at 004D58:\n"); - for(int i=0x004D58; i<0x004D58+(10*127*4); i++) - WriteLog("%02X ", JaguarReadByte(i)); - WriteLog("\nBytes at F03000:\n"); - for(int i=0xF03000; i<0xF03000+(6*127*4); i++) - WriteLog("%02X ", JaguarReadByte(i)); - WriteLog("\n\n"); - } -}//*/ - - blitter_working = 0; } -#endif // of the #if 0 near the top... -/******************************************************************************* -********************** STUFF CUT ABOVE THIS LINE! ****************************** -*******************************************************************************/ - void BlitterInit(void) { BlitterReset(); } - void BlitterReset(void) { memset(blitter_ram, 0x00, 0xA0); } - void BlitterDone(void) { - WriteLog("BLIT: Done.\n"); } - -uint8_t BlitterReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint8_t BlitterReadByte(uint32_t offset, uint32_t who) { offset &= 0xFF; - // status register -//This isn't cycle accurate--how to fix? !!! FIX !!! -//Probably have to do some multi-threaded implementation or at least a reentrant safe implementation... -//Real hardware returns $00000805, just like the JTRM says. if (offset == (0x38 + 0)) return 0x00; if (offset == (0x38 + 1)) @@ -1580,100 +841,76 @@ uint8_t BlitterReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) if (offset == (0x38 + 2)) return 0x08; if (offset == (0x38 + 3)) - return 0x05; // always idle/never stopped (collision detection ignored!) + return 0x05; -// CHECK HERE ONCE THIS FIX HAS BEEN TESTED: [X] -//Fix for AvP: if (offset >= 0x04 && offset <= 0x07) -//This is it. I wonder if it just ignores the lower three bits? -//No, this is a documented Jaguar I bug. It also bites the read at $F02230 as well... - return blitter_ram[offset + 0x08]; // A1_PIXEL ($F0220C) read at $F02204 + return blitter_ram[offset + 0x08]; if (offset >= 0x2C && offset <= 0x2F) - return blitter_ram[offset + 0x04]; // A2_PIXEL ($F02230) read at $F0222C + return blitter_ram[offset + 0x04]; return blitter_ram[offset]; } - -//Crappy! -uint16_t BlitterReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint16_t BlitterReadWord(uint32_t offset, uint32_t who) { return ((uint16_t)BlitterReadByte(offset, who) << 8) | (uint16_t)BlitterReadByte(offset+1, who); } - -//Crappy! -uint32_t BlitterReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint32_t BlitterReadLong(uint32_t offset, uint32_t who) { return (BlitterReadWord(offset, who) << 16) | BlitterReadWord(offset+2, who); } - -void BlitterWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) +void BlitterWriteByte(uint32_t offset, uint8_t data, uint32_t who) { -/*if (offset & 0xFF == 0x7B) - WriteLog("--> Wrote to B_STOP: value -> %02X\n", data);*/ offset &= 0xFF; -/*if ((offset >= PATTERNDATA) && (offset < PATTERNDATA + 8)) -{ - printf("--> %s wrote %02X to byte %u of PATTERNDATA...\n", whoName[who], data, offset - PATTERNDATA); - fflush(stdout); -}//*/ - // This handles writes to INTENSITY0-3 by also writing them to their proper places in - // PATTERNDATA & SOURCEDATA (should do the same for the Z registers! !!! FIX !!! [DONE]) if ((offset >= 0x7C) && (offset <= 0x9B)) { switch (offset) { - // INTENSITY registers 0-3 - case 0x7C: break; - case 0x7D: blitter_ram[PATTERNDATA + 7] = data; break; - case 0x7E: blitter_ram[SRCDATA + 6] = data; break; - case 0x7F: blitter_ram[SRCDATA + 7] = data; break; + case 0x7C: break; + case 0x7D: blitter_ram[PATTERNDATA + 7] = data; break; + case 0x7E: blitter_ram[SRCDATA + 6] = data; break; + case 0x7F: blitter_ram[SRCDATA + 7] = data; break; - case 0x80: break; - case 0x81: blitter_ram[PATTERNDATA + 5] = data; break; - case 0x82: blitter_ram[SRCDATA + 4] = data; break; - case 0x83: blitter_ram[SRCDATA + 5] = data; break; + case 0x80: break; + case 0x81: blitter_ram[PATTERNDATA + 5] = data; break; + case 0x82: blitter_ram[SRCDATA + 4] = data; break; + case 0x83: blitter_ram[SRCDATA + 5] = data; break; - case 0x84: break; - case 0x85: blitter_ram[PATTERNDATA + 3] = data; break; - case 0x86: blitter_ram[SRCDATA + 2] = data; break; - case 0x87: blitter_ram[SRCDATA + 3] = data; break; + case 0x84: break; + case 0x85: blitter_ram[PATTERNDATA + 3] = data; break; + case 0x86: blitter_ram[SRCDATA + 2] = data; break; + case 0x87: blitter_ram[SRCDATA + 3] = data; break; - case 0x88: break; - case 0x89: blitter_ram[PATTERNDATA + 1] = data; break; - case 0x8A: blitter_ram[SRCDATA + 0] = data; break; - case 0x8B: blitter_ram[SRCDATA + 1] = data; break; + case 0x88: break; + case 0x89: blitter_ram[PATTERNDATA + 1] = data; break; + case 0x8A: blitter_ram[SRCDATA + 0] = data; break; + case 0x8B: blitter_ram[SRCDATA + 1] = data; break; + case 0x8C: blitter_ram[SRCZINT + 6] = data; break; + case 0x8D: blitter_ram[SRCZINT + 7] = data; break; + case 0x8E: blitter_ram[SRCZFRAC + 6] = data; break; + case 0x8F: blitter_ram[SRCZFRAC + 7] = data; break; - // Z registers 0-3 - case 0x8C: blitter_ram[SRCZINT + 6] = data; break; - case 0x8D: blitter_ram[SRCZINT + 7] = data; break; - case 0x8E: blitter_ram[SRCZFRAC + 6] = data; break; - case 0x8F: blitter_ram[SRCZFRAC + 7] = data; break; + case 0x90: blitter_ram[SRCZINT + 4] = data; break; + case 0x91: blitter_ram[SRCZINT + 5] = data; break; + case 0x92: blitter_ram[SRCZFRAC + 4] = data; break; + case 0x93: blitter_ram[SRCZFRAC + 5] = data; break; - case 0x90: blitter_ram[SRCZINT + 4] = data; break; - case 0x91: blitter_ram[SRCZINT + 5] = data; break; - case 0x92: blitter_ram[SRCZFRAC + 4] = data; break; - case 0x93: blitter_ram[SRCZFRAC + 5] = data; break; + case 0x94: blitter_ram[SRCZINT + 2] = data; break; + case 0x95: blitter_ram[SRCZINT + 3] = data; break; + case 0x96: blitter_ram[SRCZFRAC + 2] = data; break; + case 0x97: blitter_ram[SRCZFRAC + 3] = data; break; - case 0x94: blitter_ram[SRCZINT + 2] = data; break; - case 0x95: blitter_ram[SRCZINT + 3] = data; break; - case 0x96: blitter_ram[SRCZFRAC + 2] = data; break; - case 0x97: blitter_ram[SRCZFRAC + 3] = data; break; - - case 0x98: blitter_ram[SRCZINT + 0] = data; break; - case 0x99: blitter_ram[SRCZINT + 1] = data; break; - case 0x9A: blitter_ram[SRCZFRAC + 0] = data; break; - case 0x9B: blitter_ram[SRCZFRAC + 1] = data; break; + case 0x98: blitter_ram[SRCZINT + 0] = data; break; + case 0x99: blitter_ram[SRCZINT + 1] = data; break; + case 0x9A: blitter_ram[SRCZFRAC + 0] = data; break; + case 0x9B: blitter_ram[SRCZFRAC + 1] = data; break; } } - - // It looks weird, but this is how the 64 bit registers are actually handled...! - else if ((offset >= SRCDATA + 0) && (offset <= SRCDATA + 3) || (offset >= DSTDATA + 0) && (offset <= DSTDATA + 3) || (offset >= DSTZ + 0) && (offset <= DSTZ + 3) @@ -1696,991 +933,26 @@ void BlitterWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) blitter_ram[offset] = data; } - -void BlitterWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) +void BlitterWriteWord(uint32_t offset, uint16_t data, uint32_t who) { -/*if (((offset & 0xFF) >= PATTERNDATA) && ((offset & 0xFF) < PATTERNDATA + 8)) -{ - printf("----> %s wrote %04X to byte %u of PATTERNDATA...\n", whoName[who], data, offset - (0xF02200 + PATTERNDATA)); - fflush(stdout); -}*/ -//#if 1 -/* if (offset & 0xFF == A1_PIXEL && data == 14368) - { - WriteLog("\n1\nA1_PIXEL written by %s (%u)...\n\n\n", whoName[who], data); -extern bool doGPUDis; -doGPUDis = true; - } - if ((offset & 0xFF) == (A1_PIXEL + 2) && data == 14368) - { - WriteLog("\n2\nA1_PIXEL written by %s (%u)...\n\n\n", whoName[who], data); -extern bool doGPUDis; -doGPUDis = true; - }//*/ -//#endif - BlitterWriteByte(offset + 0, data >> 8, who); BlitterWriteByte(offset + 1, data & 0xFF, who); if ((offset & 0xFF) == 0x3A) - // I.e., the second write of 32-bit value--not convinced this is the best way to do this! - // But then again, according to the Jaguar docs, this is correct...! -/*extern int blit_start_log; -extern bool doGPUDis; -if (blit_start_log) -{ - WriteLog("BLIT: Blitter started by %s...\n", whoName[who]); - doGPUDis = true; -}//*/ -#ifndef USE_BOTH_BLITTERS -#ifdef USE_ORIGINAL_BLITTER - blitter_blit(GET32(blitter_ram, 0x38)); -#endif -#ifdef USE_MIDSUMMER_BLITTER - BlitterMidsummer(GET32(blitter_ram, 0x38)); -#endif -#ifdef USE_MIDSUMMER_BLITTER_MKII - BlitterMidsummer2(); -#endif -#else { if (vjs.useFastBlitter) blitter_blit(GET32(blitter_ram, 0x38)); else BlitterMidsummer2(); } -#endif } -//F02278,9,A,B - -void BlitterWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/) +void BlitterWriteLong(uint32_t offset, uint32_t data, uint32_t who) { -/*if (((offset & 0xFF) >= PATTERNDATA) && ((offset & 0xFF) < PATTERNDATA + 8)) -{ - printf("------> %s wrote %08X to byte %u of PATTERNDATA...\n", whoName[who], data, offset - (0xF02200 + PATTERNDATA)); - fflush(stdout); -}//*/ -//#if 1 -/* if ((offset & 0xFF) == A1_PIXEL && (data & 0xFFFF) == 14368) - { - WriteLog("\n3\nA1_PIXEL written by %s (%u)...\n\n\n", whoName[who], data); -extern bool doGPUDis; -doGPUDis = true; - }//*/ -//#endif - BlitterWriteWord(offset + 0, data >> 16, who); BlitterWriteWord(offset + 2, data & 0xFFFF, who); } - -void LogBlit(void) -{ - const char * opStr[16] = { "LFU_CLEAR", "LFU_NSAND", "LFU_NSAD", "LFU_NOTS", "LFU_SAND", "LFU_NOTD", "LFU_N_SXORD", "LFU_NSORND", - "LFU_SAD", "LFU_XOR", "LFU_D", "LFU_NSORD", "LFU_REPLACE", "LFU_SORND", "LFU_SORD", "LFU_ONE" }; - uint32_t cmd = GET32(blitter_ram, 0x38); - uint32_t m = (REG(A1_FLAGS) >> 9) & 0x03, e = (REG(A1_FLAGS) >> 11) & 0x0F; - uint32_t a1_width = ((0x04 | m) << e) >> 2; - m = (REG(A2_FLAGS) >> 9) & 0x03, e = (REG(A2_FLAGS) >> 11) & 0x0F; - uint32_t a2_width = ((0x04 | m) << e) >> 2; - - WriteLog("Blit!\n"); - WriteLog(" COMMAND = %08X\n", cmd); - WriteLog(" a1_base = %08X\n", REG(A1_BASE)); - WriteLog(" a1_flags = %08X (%c %c %c %c%c . %c%c%c%c%c%c %c%c%c %c%c%c . %c%c)\n", REG(A1_FLAGS), - (REG(A1_FLAGS) & 0x100000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x080000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x040000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x020000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x010000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x004000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x002000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x001000 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000800 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000400 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000200 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000100 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000080 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000040 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000020 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000010 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000008 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000002 ? '1' : '0'), - (REG(A1_FLAGS) & 0x000001 ? '1' : '0')); - WriteLog(" pitch=%u, pixSz=%u, zOff=%u, width=%u, xCtrl=%u\n", - REG(A1_FLAGS) & 0x00003, (REG(A1_FLAGS) & 0x00038) >> 3, - (REG(A1_FLAGS) & 0x001C0) >> 6, a1_width, (REG(A1_FLAGS) & 0x30000) >> 16); - WriteLog(" a1_clip = %u, %u (%08X)\n", GET16(blitter_ram, A1_CLIP + 2), GET16(blitter_ram, A1_CLIP + 0), GET32(blitter_ram, A1_CLIP)); - WriteLog(" a1_pixel = %d, %d (%08X)\n", (int16_t)GET16(blitter_ram, A1_PIXEL + 2), (int16_t)GET16(blitter_ram, A1_PIXEL + 0), GET32(blitter_ram, A1_PIXEL)); - WriteLog(" a1_step = %d, %d (%08X)\n", (int16_t)GET16(blitter_ram, A1_STEP + 2), (int16_t)GET16(blitter_ram, A1_STEP + 0), GET32(blitter_ram, A1_STEP)); - WriteLog(" a1_fstep = %u, %u (%08X)\n", GET16(blitter_ram, A1_FSTEP + 2), GET16(blitter_ram, A1_FSTEP + 0), GET32(blitter_ram, A1_FSTEP)); - WriteLog(" a1_fpixel= %u, %u (%08X)\n", GET16(blitter_ram, A1_FPIXEL + 2), GET16(blitter_ram, A1_FPIXEL + 0), GET32(blitter_ram, A1_FPIXEL)); - WriteLog(" a1_inc = %d, %d (%08X)\n", (int16_t)GET16(blitter_ram, A1_INC + 2), (int16_t)GET16(blitter_ram, A1_INC + 0), GET32(blitter_ram, A1_INC)); - WriteLog(" a1_finc = %u, %u (%08X)\n", GET16(blitter_ram, A1_FINC + 2), GET16(blitter_ram, A1_FINC + 0), GET32(blitter_ram, A1_FINC)); - - WriteLog(" a2_base = %08X\n", REG(A2_BASE)); - WriteLog(" a2_flags = %08X (%c %c %c %c%c %c %c%c%c%c%c%c %c%c%c %c%c%c . %c%c)\n", REG(A2_FLAGS), - (REG(A2_FLAGS) & 0x100000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x080000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x040000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x020000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x010000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x008000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x004000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x002000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x001000 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000800 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000400 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000200 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000100 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000080 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000040 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000020 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000010 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000008 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000002 ? '1' : '0'), - (REG(A2_FLAGS) & 0x000001 ? '1' : '0')); - WriteLog(" pitch=%u, pixSz=%u, zOff=%u, width=%u, xCtrl=%u\n", - REG(A2_FLAGS) & 0x00003, (REG(A2_FLAGS) & 0x00038) >> 3, - (REG(A2_FLAGS) & 0x001C0) >> 6, a2_width, (REG(A2_FLAGS) & 0x30000) >> 16); - WriteLog(" a2_mask = %u, %u (%08X)\n", GET16(blitter_ram, A2_MASK + 2), GET16(blitter_ram, A2_MASK + 0), GET32(blitter_ram, A2_MASK)); - WriteLog(" a2_pixel = %d, %d (%08X)\n", (int16_t)GET16(blitter_ram, A2_PIXEL + 2), (int16_t)GET16(blitter_ram, A2_PIXEL + 0), GET32(blitter_ram, A2_PIXEL)); - WriteLog(" a2_step = %d, %d (%08X)\n", (int16_t)GET16(blitter_ram, A2_STEP + 2), (int16_t)GET16(blitter_ram, A2_STEP + 0), GET32(blitter_ram, A2_STEP)); - - WriteLog(" count = %d x %d\n", GET16(blitter_ram, PIXLINECOUNTER + 2), GET16(blitter_ram, PIXLINECOUNTER)); - - WriteLog(" SRCEN = %s\n", (SRCEN ? "1" : "0")); - WriteLog(" SRCENZ = %s\n", (SRCENZ ? "1" : "0")); - WriteLog(" SRCENX = %s\n", (SRCENX ? "1" : "0")); - WriteLog(" DSTEN = %s\n", (DSTEN ? "1" : "0")); - WriteLog(" DSTENZ = %s\n", (DSTENZ ? "1" : "0")); - WriteLog(" DSTWRZ = %s\n", (DSTWRZ ? "1" : "0")); - WriteLog(" CLIPA1 = %s\n", (CLIPA1 ? "1" : "0")); - WriteLog(" UPDA1F = %s\n", (UPDA1F ? "1" : "0")); - WriteLog(" UPDA1 = %s\n", (UPDA1 ? "1" : "0")); - WriteLog(" UPDA2 = %s\n", (UPDA2 ? "1" : "0")); - WriteLog(" DSTA2 = %s\n", (DSTA2 ? "1" : "0")); - WriteLog(" ZOP = %s %s %s\n", (Z_OP_INF ? "<" : ""), (Z_OP_EQU ? "=" : ""), (Z_OP_SUP ? ">" : "")); - WriteLog("+-LFUFUNC = %s\n", opStr[(cmd >> 21) & 0x0F]); - WriteLog("| PATDSEL = %s (PD=%08X%08X)\n", (PATDSEL ? "1" : "0"), REG(PATTERNDATA), REG(PATTERNDATA + 4)); - WriteLog("+-ADDDSEL = %s\n", (ADDDSEL ? "1" : "0")); - WriteLog(" CMPDST = %s\n", (CMPDST ? "1" : "0")); - WriteLog(" BCOMPEN = %s\n", (BCOMPEN ? "1" : "0")); - WriteLog(" DCOMPEN = %s\n", (DCOMPEN ? "1" : "0")); - WriteLog(" TOPBEN = %s\n", (TOPBEN ? "1" : "0")); - WriteLog(" TOPNEN = %s\n", (TOPNEN ? "1" : "0")); - WriteLog(" BKGWREN = %s\n", (BKGWREN ? "1" : "0")); - WriteLog(" GOURD = %s (II=%08X, SD=%08X%08X)\n", (GOURD ? "1" : "0"), REG(INTENSITYINC), REG(SRCDATA), REG(SRCDATA + 4)); - WriteLog(" GOURZ = %s (ZI=%08X, ZD=%08X%08X, SZ1=%08X%08X, SZ2=%08X%08X)\n", (GOURZ ? "1" : "0"), REG(ZINC), REG(DSTZ), REG(DSTZ + 4), - REG(SRCZINT), REG(SRCZINT + 4), REG(SRCZFRAC), REG(SRCZFRAC + 4)); - WriteLog(" SRCSHADE = %s\n", (SRCSHADE ? "1" : "0")); -} - - -#ifdef USE_MIDSUMMER_BLITTER -// -// Here's an attempt to write a blitter that conforms to the Midsummer specs--since -// it's supposedly backwards compatible, it should work well... -// -//#define LOG_BLITTER_MEMORY_ACCESSES - -#define DATINIT (false) -#define TXTEXT (false) -#define POLYGON (false) - -void BlitterMidsummer(uint32_t cmd) -{ -#ifdef LOG_BLITS - LogBlit(); -#endif -uint32_t outer_loop, inner_loop, a1_addr, a2_addr; -int32_t a1_x, a1_y, a2_x, a2_y, a1_width, a2_width; -uint8_t a1_phrase_mode, a2_phrase_mode; - - a1_addr = REG(A1_BASE) & 0xFFFFFFF8; - a2_addr = REG(A2_BASE) & 0xFFFFFFF8; - a1_x = (REG(A1_PIXEL) << 16) | (REG(A1_FPIXEL) & 0xFFFF); - a1_y = (REG(A1_PIXEL) & 0xFFFF0000) | (REG(A1_FPIXEL) >> 16); - uint32_t m = (REG(A1_FLAGS) >> 9) & 0x03, e = (REG(A1_FLAGS) >> 11) & 0x0F; - a1_width = ((0x04 | m) << e) >> 2;//*/ - a2_x = (REG(A2_PIXEL) & 0x0000FFFF) << 16; - a2_y = (REG(A2_PIXEL) & 0xFFFF0000); - m = (REG(A2_FLAGS) >> 9) & 0x03, e = (REG(A2_FLAGS) >> 11) & 0x0F; - a2_width = ((0x04 | m) << e) >> 2;//*/ - - a1_phrase_mode = a2_phrase_mode = 0; - - if ((blitter_ram[A1_FLAGS + 1] & 0x03) == 0) - a1_phrase_mode = 1; - - if ((blitter_ram[A2_FLAGS + 1] & 0x03) == 0) - a2_phrase_mode = 1; - -#define INNER0 (inner_loop == 0) -#define OUTER0 (outer_loop == 0) - -// $01800005 has SRCENX, may have to investigate further... -// $00011008 has GOURD & DSTEN. -// $41802F41 has SRCSHADE, CLIPA1 -/*bool logBlit = false; -if (cmd != 0x00010200 && cmd != 0x01800001 && cmd != 0x01800005 - && cmd != 0x00011008 && cmd !=0x41802F41) -{ - logBlit = true; - LogBlit(); -}//*/ - - uint64_t srcData = GET64(blitter_ram, SRCDATA), srcXtraData, - dstData = GET64(blitter_ram, DSTDATA), writeData; - uint32_t srcAddr, dstAddr; - uint8_t bitCount, a1PixelSize, a2PixelSize; - - // JTRM says phrase mode only works for 8BPP or higher, so let's try this... - uint32_t phraseOffset[8] = { 8, 8, 8, 8, 4, 2, 0, 0 }; - uint8_t pixelShift[8] = { 3, 2, 1, 0, 1, 2, 0, 0 }; - - a1PixelSize = (blitter_ram[A1_FLAGS + 3] >> 3) & 0x07; - a2PixelSize = (blitter_ram[A2_FLAGS + 3] >> 3) & 0x07; - - outer_loop = GET16(blitter_ram, PIXLINECOUNTER + 0); - - if (outer_loop == 0) - outer_loop = 0x10000; - - // We just list the states here and jump from state to state in order to - // keep things somewhat clear. Optimization/cleanups later. - -//idle: // Blitter is idle, and will not perform any bus activity -/* -idle Blitter is off the bus, and no activity takes place. -if GO if DATINIT goto init_if - else goto inner -*/ - if (DATINIT) - goto init_if; - else - goto inner; - -/* -inner Inner loop is active, read and write cycles are performed -*/ -inner: // Run inner loop state machine (asserts step from its idle state) - inner_loop = GET16(blitter_ram, PIXLINECOUNTER + 2); - - if (inner_loop == 0) - inner_loop = 0x10000; - -/* ------------------------------- -idle: Inactive, blitter is idle or passing round outer loop -idle Another state in the outer loop is active. No bus transfers are performed. -if STEP - if SRCENX goto sreadx - else if TXTEXT goto txtread - else if SRCEN goto sread - else if DSTEN goto dread - else if DSTENZ goto dzread - else goto dwrite -*/ - if (SRCENX) - goto sreadx; - else if (TXTEXT) - goto txtread; - else if (SRCEN) - goto sread; - else if (DSTEN) - goto dread; - else if (DSTENZ) - goto dzread; - else - goto dwrite; - -/* -sreadx Extra source data read at the start of an inner loop pass. -if STEP - if SRCENZ goto szreadx - else if TXTEXT goto txtread - else if SRCEN goto sread - else if DSTEN goto dread - else if DSTENZ goto dzread - else goto dwrite -*/ -sreadx: // Extra source data read - if (SRCENZ) - goto szreadx; - else if (TXTEXT) - goto txtread; - else if (SRCEN) - goto sread; - else if (DSTEN) - goto dread; - else if (DSTENZ) - goto dzread; - else - goto dwrite; - -/* -szreadx Extra source Z read as the start of an inner loop pass. -if STEP - if TXTEXT goto txtread - else goto sread -*/ -szreadx: // Extra source Z read - if (TXTEXT) - goto txtread; - else - goto sread; - -/* -txtread Read texture data from external memory. This state is only used for external texture. - TEXTEXT is the condition TEXTMODE=1. -if STEP - if SRCEN goto sread - else if DSTEN goto dread - else if DSTENZ goto dzread - else goto dwrite -*/ -txtread: // Read external texture data - if (SRCEN) - goto sread; - else if (DSTEN) - goto dread; - else if (DSTENZ) - goto dzread; - else - goto dwrite; - -/* -sread Source data read. -if STEP - if SRCENZ goto szread - else if DSTEN goto dread - else if DSTENZ goto dzread - else goto dwrite -*/ -sread: // Source data read -//The JTRM doesn't really specify the internal structure of the source data read, but I would -//imagine that if it's in phrase mode that it starts by reading the phrase that the window is -//pointing at. Likewise, the pixel (if in BPP 1, 2 & 4, chopped) otherwise. It probably still -//transfers an entire phrase even in pixel mode. -//Odd thought: Does it expand, e.g., 1 BPP pixels into 32 BPP internally? Hmm... -//No. -/* - a1_addr = REG(A1_BASE) & 0xFFFFFFF8; - a2_addr = REG(A2_BASE) & 0xFFFFFFF8; - a1_zoffs = (REG(A1_FLAGS) >> 6) & 7; - a2_zoffs = (REG(A2_FLAGS) >> 6) & 7; - xadd_a1_control = (REG(A1_FLAGS) >> 16) & 0x03; - xadd_a2_control = (REG(A2_FLAGS) >> 16) & 0x03; - a1_pitch = pitchValue[(REG(A1_FLAGS) & 0x03)]; - a2_pitch = pitchValue[(REG(A2_FLAGS) & 0x03)]; - n_pixels = REG(PIXLINECOUNTER) & 0xFFFF; - n_lines = (REG(PIXLINECOUNTER) >> 16) & 0xFFFF; - a1_x = (REG(A1_PIXEL) << 16) | (REG(A1_FPIXEL) & 0xFFFF); - a1_y = (REG(A1_PIXEL) & 0xFFFF0000) | (REG(A1_FPIXEL) >> 16); - a2_psize = 1 << ((REG(A2_FLAGS) >> 3) & 0x07); - a1_psize = 1 << ((REG(A1_FLAGS) >> 3) & 0x07); - a1_phrase_mode = 0; - a2_phrase_mode = 0; - a1_width = ((0x04 | m) << e) >> 2; - a2_width = ((0x04 | m) << e) >> 2; - - // write values back to registers - WREG(A1_PIXEL, (a1_y & 0xFFFF0000) | ((a1_x >> 16) & 0xFFFF)); - WREG(A1_FPIXEL, (a1_y << 16) | (a1_x & 0xFFFF)); - WREG(A2_PIXEL, (a2_y & 0xFFFF0000) | ((a2_x >> 16) & 0xFFFF)); -*/ - // Calculate the address to be read... - -//Need to fix phrase mode calcs here, since they should *step* by eight, not mulitply. -//Also, need to fix various differing BPP modes here, since offset won't be correct except -//for 8BPP. !!! FIX !!! - srcAddr = (DSTA2 ? a1_addr : a2_addr); - -/* if ((DSTA2 ? a1_phrase_mode : a2_phrase_mode) == 1) - { - srcAddr += (((DSTA2 ? a1_x : a2_x) >> 16) - + (((DSTA2 ? a1_y : a2_y) >> 16) * (DSTA2 ? a1_width : a2_width))); - } - else*/ - { -// uint32_t pixAddr = ((DSTA2 ? a1_x : a2_x) >> 16) -// + (((DSTA2 ? a1_y : a2_y) >> 16) * (DSTA2 ? a1_width : a2_width)); - int32_t pixAddr = (int16_t)((DSTA2 ? a1_x : a2_x) >> 16) - + ((int16_t)((DSTA2 ? a1_y : a2_y) >> 16) * (DSTA2 ? a1_width : a2_width)); - - if ((DSTA2 ? a1PixelSize : a2PixelSize) < 3) - pixAddr >>= pixelShift[(DSTA2 ? a1PixelSize : a2PixelSize)]; - else if ((DSTA2 ? a1PixelSize : a2PixelSize) > 3) - pixAddr <<= pixelShift[(DSTA2 ? a1PixelSize : a2PixelSize)]; - - srcAddr += pixAddr; - } - - // And read it! - - if ((DSTA2 ? a1_phrase_mode : a2_phrase_mode) == 1) - { - srcData = ((uint64_t)JaguarReadLong(srcAddr, BLITTER) << 32) - | (uint64_t)JaguarReadLong(srcAddr + 4, BLITTER); - } - else - { -//1,2,&4BPP are wrong here... !!! FIX !!! - if ((DSTA2 ? a1PixelSize : a2PixelSize) == 0) // 1 BPP - srcData = JaguarReadByte(srcAddr, BLITTER); - if ((DSTA2 ? a1PixelSize : a2PixelSize) == 1) // 2 BPP - srcData = JaguarReadByte(srcAddr, BLITTER); - if ((DSTA2 ? a1PixelSize : a2PixelSize) == 2) // 4 BPP - srcData = JaguarReadByte(srcAddr, BLITTER); - if ((DSTA2 ? a1PixelSize : a2PixelSize) == 3) // 8 BPP - srcData = JaguarReadByte(srcAddr, BLITTER); - if ((DSTA2 ? a1PixelSize : a2PixelSize) == 4) // 16 BPP - srcData = JaguarReadWord(srcAddr, BLITTER); - if ((DSTA2 ? a1PixelSize : a2PixelSize) == 5) // 32 BPP - srcData = JaguarReadLong(srcAddr, BLITTER); - } - -#ifdef LOG_BLITTER_MEMORY_ACCESSES -if (logBlit) - WriteLog("BLITTER: srcAddr=%08X, srcData=%08X %08X\n", srcAddr, (uint32_t)(srcData >> 32), (uint32_t)(srcData & 0xFFFFFFFF)); -#endif - - if (SRCENZ) - goto szread; - else if (DSTEN) - goto dread; - else if (DSTENZ) - goto dzread; - else - goto dwrite; - -szread: // Source Z read -/* -szread Source Z read. -if STEP - if DSTEN goto dread - else if DSTENZ goto dzread - else goto dwrite -*/ - if (DSTEN) - goto dread; - else if (DSTENZ) - goto dzread; - else - goto dwrite; - -dread: // Destination data read -/* -dread Destination data read. -if STEP - if DSTENZ goto dzread - else goto dwrite -*/ - // Calculate the destination address to be read... - -//Need to fix phrase mode calcs here, since they should *step* by eight, not mulitply. -//Also, need to fix various differing BPP modes here, since offset won't be correct except -//for 8BPP. !!! FIX !!! - dstAddr = (DSTA2 ? a2_addr : a1_addr); - - { -// uint32_t pixAddr = ((DSTA2 ? a2_x : a1_x) >> 16) -// + (((DSTA2 ? a2_y : a1_y) >> 16) * (DSTA2 ? a2_width : a1_width)); - int32_t pixAddr = (int16_t)((DSTA2 ? a2_x : a1_x) >> 16) - + ((int16_t)((DSTA2 ? a2_y : a1_y) >> 16) * (DSTA2 ? a2_width : a1_width)); - - if ((DSTA2 ? a2PixelSize : a1PixelSize) < 3) - pixAddr >>= pixelShift[(DSTA2 ? a2PixelSize : a1PixelSize)]; - else if ((DSTA2 ? a2PixelSize : a1PixelSize) > 3) - pixAddr <<= pixelShift[(DSTA2 ? a2PixelSize : a1PixelSize)]; - - dstAddr += pixAddr; - } - - // And read it! - - if ((DSTA2 ? a2_phrase_mode : a1_phrase_mode) == 1) - { - dstData = ((uint64_t)JaguarReadLong(srcAddr, BLITTER) << 32) - | (uint64_t)JaguarReadLong(srcAddr + 4, BLITTER); - } - else - { -//1,2,&4BPP are wrong here... !!! FIX !!! - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 0) // 1 BPP - dstData = JaguarReadByte(dstAddr, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 1) // 2 BPP - dstData = JaguarReadByte(dstAddr, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 2) // 4 BPP - dstData = JaguarReadByte(dstAddr, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 3) // 8 BPP - dstData = JaguarReadByte(dstAddr, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 4) // 16 BPP - dstData = JaguarReadWord(dstAddr, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 5) // 32 BPP - dstData = JaguarReadLong(dstAddr, BLITTER); - } - -#ifdef LOG_BLITTER_MEMORY_ACCESSES -if (logBlit) - WriteLog("BLITTER (dread): dstAddr=%08X, dstData=%08X %08X\n", dstAddr, (uint32_t)(dstData >> 32), (uint32_t)(dstData & 0xFFFFFFFF)); -#endif - - if (DSTENZ) - goto dzread; - else - goto dwrite; - -dzread: // Destination Z read -/* -dzread Destination Z read. -if STEP goto dwrite -*/ - goto dwrite; - -dwrite: // Destination data write -/* -dwrite Destination write. Every pass round the inner loop must go through this state.. -if STEP - if DSTWRZ goto dzwrite - else if INNER0 goto idle - else if TXTEXT goto txtread - else if SRCEN goto sread - else if DSTEN goto dread - else if DSTENZ goto dzread - else goto dwrite -*/ -/* -Blit! - a1_base = 00100000 - a1_pitch = 0 - a1_psize = 16 - a1_width = 320 - a1_xadd = 1.000000 (phrase=0) - a1_yadd = 0.000000 - a1_x = 159.000000 - a1_y = 1.000000 - a1_zoffs = 0 - a2_base = 000095D0 - a2_pitch = 0 - a2_psize = 16 - a2_width = 256 - a2_xadd = 1.000000 (phrase=1) - a2_yadd = 0.000000 - a2_x = 2.000000 - a2_y = 0.000000 - a2_mask_x= 0xFFFFFFFF - a2_mask_y= 0xFFFFFFFF - a2_zoffs = 0 - count = 2 x 1 - COMMAND = 00011008 - SRCEN = 0 - DSTEN = 1 - UPDA1F = 0 - UPDA1 = 0 - UPDA2 = 0 - DSTA2 = 0 ---LFUFUNC = LFU_CLEAR -| PATDSEL = 1 (PD=77C7 7700 7700 7700) ---ADDDSEL = 0 - GOURD = 1 (II=00FC 1A00, SD=FF00 0000 0000 0000) -*/ - -//Still need to do CLIPA1 and SRCSHADE and GOURD and GOURZ... - - // Check clipping... - - if (CLIPA1) - { - uint16_t x = a1_x >> 16, y = a1_y >> 16; - - if (x >= GET16(blitter_ram, A1_CLIP + 2) || y >= GET16(blitter_ram, A1_CLIP)) - goto inhibitWrite; - } - - // Figure out what gets written... - - if (PATDSEL) - { - writeData = GET64(blitter_ram, PATTERNDATA); -//GOURD works properly only in 16BPP mode... -//SRCDATA holds the intensity fractions... -//Does GOURD get calc'ed here or somewhere else??? -//Temporary testing kludge... -//if (GOURD) -// writeData >>= 48; -// writeData = 0xFF88; -//OK, it's not writing an entire strip of pixels... Why? -//bad incrementing, that's why! - } - else if (ADDDSEL) - { - // Apparently this only works with 16-bit pixels. Not sure if it works in phrase mode either. -//Also, take TOPBEN & TOPNEN into account here as well... - writeData = srcData + dstData; - } - else // LFUFUNC is the default... - { - writeData = 0; - - if (LFU_NAN) - writeData |= ~srcData & ~dstData; - if (LFU_NA) - writeData |= ~srcData & dstData; - if (LFU_AN) - writeData |= srcData & ~dstData; - if (LFU_A) - writeData |= srcData & dstData; - } - - // Calculate the address to be written... - - dstAddr = (DSTA2 ? a2_addr : a1_addr); - -/* if ((DSTA2 ? a2_phrase_mode : a1_phrase_mode) == 1) - { -//both of these calculate the wrong address because they don't take into account -//pixel sizes... - dstAddr += ((DSTA2 ? a2_x : a1_x) >> 16) - + (((DSTA2 ? a2_y : a1_y) >> 16) * (DSTA2 ? a2_width : a1_width)); - } - else*/ - { -/* dstAddr += ((DSTA2 ? a2_x : a1_x) >> 16) - + (((DSTA2 ? a2_y : a1_y) >> 16) * (DSTA2 ? a2_width : a1_width));*/ -// uint32_t pixAddr = ((DSTA2 ? a2_x : a1_x) >> 16) -// + (((DSTA2 ? a2_y : a1_y) >> 16) * (DSTA2 ? a2_width : a1_width)); - int32_t pixAddr = (int16_t)((DSTA2 ? a2_x : a1_x) >> 16) - + ((int16_t)((DSTA2 ? a2_y : a1_y) >> 16) * (DSTA2 ? a2_width : a1_width)); - - if ((DSTA2 ? a2PixelSize : a1PixelSize) < 3) - pixAddr >>= pixelShift[(DSTA2 ? a2PixelSize : a1PixelSize)]; - else if ((DSTA2 ? a2PixelSize : a1PixelSize) > 3) - pixAddr <<= pixelShift[(DSTA2 ? a2PixelSize : a1PixelSize)]; - - dstAddr += pixAddr; - } - - // And write it! - - if ((DSTA2 ? a2_phrase_mode : a1_phrase_mode) == 1) - { - JaguarWriteLong(dstAddr, writeData >> 32, BLITTER); - JaguarWriteLong(dstAddr + 4, writeData & 0xFFFFFFFF, BLITTER); - } - else - { -//1,2,&4BPP are wrong here... !!! FIX !!! - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 0) // 1 BPP - JaguarWriteByte(dstAddr, writeData, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 1) // 2 BPP - JaguarWriteByte(dstAddr, writeData, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 2) // 4 BPP - JaguarWriteByte(dstAddr, writeData, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 3) // 8 BPP - JaguarWriteByte(dstAddr, writeData, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 4) // 16 BPP - JaguarWriteWord(dstAddr, writeData, BLITTER); - if ((DSTA2 ? a2PixelSize : a1PixelSize) == 5) // 32 BPP - JaguarWriteLong(dstAddr, writeData, BLITTER); - } - -#ifdef LOG_BLITTER_MEMORY_ACCESSES -if (logBlit) - WriteLog("BLITTER: dstAddr=%08X, writeData=%08X %08X\n", dstAddr, (uint32_t)(writeData >> 32), (uint32_t)(writeData & 0xFFFFFFFF)); -#endif - -inhibitWrite://Should this go here? or on the other side of the X/Y incrementing? -//Seems OK here... for now. - -// Do funky X/Y incrementation here as well... !!! FIX !!! - - // Handle A1 channel stepping - - if ((blitter_ram[A1_FLAGS + 1] & 0x03) == 0) - a1_x += phraseOffset[a1PixelSize] << 16; - else if ((blitter_ram[A1_FLAGS + 1] & 0x03) == 1) - a1_x += (blitter_ram[A1_FLAGS + 1] & 0x08 ? -1 << 16 : 1 << 16); -/* else if ((blitter_ram[A1_FLAGS + 1] & 0x03) == 2) - a1_x += 0 << 16; */ - else if ((blitter_ram[A1_FLAGS + 1] & 0x03) == 3) - { -//Always add the FINC here??? That was the problem with the BIOS screen... So perhaps. - a1_x += GET16(blitter_ram, A1_FINC + 2); - a1_y += GET16(blitter_ram, A1_FINC + 0); - - a1_x += GET16(blitter_ram, A1_INC + 2) << 16; - a1_y += GET16(blitter_ram, A1_INC + 0) << 16; - } - - if ((blitter_ram[A1_FLAGS + 1] & 0x04) && (blitter_ram[A1_FLAGS + 1] & 0x03 != 3)) - a1_y += (blitter_ram[A1_FLAGS + 1] & 0x10 ? -1 << 16 : 1 << 16); - - // Handle A2 channel stepping - - if ((blitter_ram[A2_FLAGS + 1] & 0x03) == 0) - a2_x += phraseOffset[a2PixelSize] << 16; - else if ((blitter_ram[A2_FLAGS + 1] & 0x03) == 1) - a2_x += (blitter_ram[A2_FLAGS + 1] & 0x08 ? -1 << 16 : 1 << 16); -/* else if ((blitter_ram[A2_FLAGS + 1] & 0x03) == 2) - a2_x += 0 << 16; */ - - if (blitter_ram[A2_FLAGS + 1] & 0x04) - a2_y += (blitter_ram[A2_FLAGS + 1] & 0x10 ? -1 << 16 : 1 << 16); - -//Need to fix this so that it subtracts (saturating, of course) the correct number of pixels -//in phrase mode... !!! FIX !!! [DONE] -//Need to fix this so that it counts down the correct item. Does it count the -//source or the destination phrase mode??? -//It shouldn't matter, because we *should* end up processing the same amount -//the same number of pixels... Not sure though. - if ((DSTA2 ? a2_phrase_mode : a1_phrase_mode) == 1) - { - if (inner_loop < phraseOffset[DSTA2 ? a2PixelSize : a1PixelSize]) - inner_loop = 0; - else - inner_loop -= phraseOffset[DSTA2 ? a2PixelSize : a1PixelSize]; - } - else - inner_loop--; - - - if (DSTWRZ) - goto dzwrite; - else if (INNER0) - goto indone; - else if (TXTEXT) - goto txtread; - else if (SRCEN) - goto sread; - else if (DSTEN) - goto dread; - else if (DSTENZ) - goto dzread; - else - goto dwrite; - -dzwrite: // Destination Z write -/* -dzwrite Destination Z write. -if STEP - if INNER0 goto idle - else if TXTEXT goto txtread - else if SRCEN goto sread - else if DSTEN goto dread - else if DSTENZ goto dzread - else goto dwrite -*/ - if (INNER0) - goto indone; - else if (TXTEXT) - goto txtread; - else if (SRCEN) - goto sread; - else if (DSTEN) - goto dread; - else if (DSTENZ) - goto dzread; - else - goto dwrite; - -/* ------------------------------- -if INDONE if OUTER0 goto idle -else if UPDA1F goto a1fupdate -else if UPDA1 goto a1update -else if GOURZ.POLYGON goto zfupdate -else if UPDA2 goto a2update -else if DATINIT goto init_if -else restart inner -*/ -indone: - outer_loop--; - - - if (OUTER0) - goto blitter_done; - else if (UPDA1F) - goto a1fupdate; - else if (UPDA1) - goto a1update; -//kill this, for now... -// else if (GOURZ.POLYGON) -// goto zfupdate; - else if (UPDA2) - goto a2update; - else if (DATINIT) - goto init_if; - else - goto inner; - -a1fupdate: // Update A1 pointer fractions and more (see below) -/* -a1fupdate A1 step fraction is added to A1 pointer fraction - POLYGON true: A1 step delta X and Y fraction parts are added to the A1 - step X and Y fraction parts (the value prior to this add is used for - the step to pointer add). - POLYGON true: inner count step fraction is added to the inner count - fraction part - POLYGON.GOURD true: the I fraction step is added to the computed - intensity fraction parts + - POLYGON.GOURD true: the I fraction step delta is added to the I - fraction step -goto a1update -*/ -/* -#define A1_PIXEL ((uint32_t)0x0C) // Integer part of the pixel (Y.i and X.i) -#define A1_STEP ((uint32_t)0x10) // Integer part of the step -#define A1_FSTEP ((uint32_t)0x14) // Fractional part of the step -#define A1_FPIXEL ((uint32_t)0x18) // Fractional part of the pixel (Y.f and X.f) -*/ - -// This is all kinda murky. All we have are the Midsummer docs to give us any guidance, -// and it's incomplete or filled with errors (like above). Aarrrgggghhhhh! - -//This isn't right. Is it? I don't think the fractional parts are signed... -// a1_x += (int32_t)((int16_t)GET16(blitter_ram, A1_FSTEP + 2)); -// a1_y += (int32_t)((int16_t)GET16(blitter_ram, A1_FSTEP + 0)); - a1_x += GET16(blitter_ram, A1_FSTEP + 2); - a1_y += GET16(blitter_ram, A1_FSTEP + 0); - - goto a1update; - -a1update: // Update A1 pointer integers -/* -a1update A1 step is added to A1 pointer, with carry from the fractional add - POLYGON true: A1 step delta X and Y integer parts are added to the A1 - step X and Y integer parts, with carry from the corresponding - fractional part add (again, the value prior to this add is used for - the step to pointer add). - POLYGON true: inner count step is added to the inner count, with carry - POLYGON.GOURD true: the I step is added to the computed intensities, - with carry + - POLYGON.GOURD true: the I step delta is added to the I step, with - carry the texture X and Y step delta values are added to the X and Y - step values. -if GOURZ.POLYGON goto zfupdate -else if UPDA2 goto a2update -else if DATINIT goto init_if -else restart inner -*/ - a1_x += (int32_t)(GET16(blitter_ram, A1_STEP + 2) << 16); - a1_y += (int32_t)(GET16(blitter_ram, A1_STEP + 0) << 16); - - -//kill this, for now... -// if (GOURZ.POLYGON) - if (false) - goto zfupdate; - else if (UPDA2) - goto a2update; - else if (DATINIT) - goto init_if; - else - goto inner; - -zfupdate: // Update computed Z step fractions -/* -zfupdate the Z fraction step is added to the computed Z fraction parts + - the Z fraction step delta is added to the Z fraction step -goto zupdate -*/ - goto zupdate; - -zupdate: // Update computed Z step integers -/* -zupdate the Z step is added to the computed Zs, with carry + - the Z step delta is added to the Z step, with carry -if UPDA2 goto a2update -else if DATINIT goto init_if -else restart inner -*/ - if (UPDA2) - goto a2update; - else if (DATINIT) - goto init_if; - else - goto inner; - -a2update: // Update A2 pointer -/* -a2update A2 step is added to the A2 pointer -if DATINIT goto init_if -else restart inner -*/ - a2_x += (int32_t)(GET16(blitter_ram, A2_STEP + 2) << 16); - a2_y += (int32_t)(GET16(blitter_ram, A2_STEP + 0) << 16); - - - if (DATINIT) - goto init_if; - else - goto inner; - -init_if: // Initialise intensity fractions and texture X -/* -init_if Initialise the fractional part of the computed intensity fields, from - the increment and step registers. The texture X integer and fractional - parts can also be initialised. -goto init_ii -*/ - goto init_ii; - -init_ii: // Initialise intensity integers and texture Y -/* -init_ii Initialise the integer part of the computed intensity, and texture Y - integer and fractional parts -if GOURZ goto init_zf -else goto inner -*/ - if (GOURZ) - goto init_zf; - else - goto inner; - -init_zf: // Initialise Z fractions -/* -init_zf Initialise the fractional part of the computed Z fields. -goto init_zi -*/ - goto init_zi; - -init_zi: // Initialise Z integers -/* -init_zi Initialise the integer part of the computed Z fields. -goto inner -*/ - goto inner; - - -/* -The outer loop state machine fires off the inner loop, and controls the updating -process between passes through the inner loop. - -+ -- these functions are irrelevant if the DATINIT function is enabled, which it - will normally be. - -All these states will complete in one clock cycle, with the exception of the idle -state, which means the blitter is quiescent; and the inner state, which takes as -long as is required to complete one strip of pixels. It is therefore possible for -the blitter to spend a maximum of nine clock cycles of inactivity between passes -through the inner loop. -*/ - -blitter_done: - {} -} -#endif - - -// -// Here's attempt #2--taken from the Oberon chip specs! -// - -#ifdef USE_MIDSUMMER_BLITTER_MKII - void ADDRGEN(uint32_t &, uint32_t &, bool, bool, uint16_t, uint16_t, uint32_t, uint8_t, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t, uint32_t, uint8_t, uint8_t, uint8_t, uint8_t); @@ -2707,124 +979,11 @@ void DATA(uint64_t &wdata, uint8_t &dcomp, uint8_t &zcomp, bool &nowrite, void COMP_CTRL(uint8_t &dbinh, bool &nowrite, bool bcompen, bool big_pix, bool bkgwren, uint8_t dcomp, bool dcompen, uint8_t icount, uint8_t pixsize, bool phrase_mode, uint8_t srcd, uint8_t zcomp); -#define VERBOSE_BLITTER_LOGGING void BlitterMidsummer2(void) { -#ifdef LOG_BLITS - LogBlit(); -#endif - if (startConciseBlitLogging) - LogBlit(); - - // Here's what the specs say the state machine does. Note that this can probably be - // greatly simplified (also, it's different from what John has in his Oberon docs): -//Will remove stuff that isn't in Jaguar I once fully described (stuff like texture won't -//be described here at all)... - uint32_t cmd = GET32(blitter_ram, COMMAND); -#if 0 -logBlit = false; -if ( - cmd != 0x00010200 && // PATDSEL - cmd != 0x01800001 // SRCEN LFUFUNC=C - && cmd != 0x01800005 -//Boot ROM ATARI letters: - && cmd != 0x00011008 // DSTEN GOURD PATDSEL -//Boot ROM spinning cube: - && cmd != 0x41802F41 // SRCEN CLIP_A1 UPDA1 UPDA1F UPDA2 DSTA2 GOURZ ZMODE=0 LFUFUNC=C SRCSHADE -//T2K intro screen: - && cmd != 0x01800E01 // SRCEN UPDA1 UPDA2 DSTA2 LFUFUNC=C -//T2K TEMPEST letters: - && cmd != 0x09800741 // SRCEN CLIP_A1 UPDA1 UPDA1F UPDA2 LFUFUNC=C DCOMPEN -//Static letters on Cybermorph intro screen: - && cmd != 0x09800609 // SRCEN DSTEN UPDA1 UPDA2 LFUFUNC=C DCOMPEN -//Static pic on title screen: - && cmd != 0x01800601 // SRCEN UPDA1 UPDA2 LFUFUNC=C -//Turning letters on Cybermorph intro screen: -// && cmd != 0x09800F41 // SRCEN CLIP_A1 UPDA1 UPDA1F UPDA2 DSTA2 LFUFUNC=C DCOMPEN - && cmd != 0x00113078 // DSTEN DSTENZ DSTWRZ CLIP_A1 GOURD GOURZ PATDSEL ZMODE=4 - && cmd != 0x09900F39 // SRCEN DSTEN DSTENZ DSTWRZ UPDA1 UPDA1F UPDA2 DSTA2 ZMODE=4 LFUFUNC=C DCOMPEN - && cmd != 0x09800209 // SRCEN DSTEN UPDA1 LFUFUNC=C DCOMPEN - && cmd != 0x00011200 // UPDA1 GOURD PATDSEL -//Start of Hover Strike (clearing screen): - && cmd != 0x00010000 // PATDSEL -//Hover Strike text: - && cmd != 0x1401060C // SRCENX DSTEN UPDA1 UPDA2 PATDSEL BCOMPEN BKGWREN -//Hover Strike 3D stuff - && cmd != 0x01902839 // SRCEN DSTEN DSTENZ DSTWRZ DSTA2 GOURZ ZMODE=4 LFUFUNC=C -//Hover Strike darkening on intro to play (briefing) screen - && cmd != 0x00020208 // DSTEN UPDA1 ADDDSEL -//Trevor McFur stuff: - && cmd != 0x05810601 // SRCEN UPDA1 UPDA2 PATDSEL BCOMPEN - && cmd != 0x01800201 // SRCEN UPDA1 LFUFUNC=C -//T2K: - && cmd != 0x00011000 // GOURD PATDSEL - && cmd != 0x00011040 // CLIP_A1 GOURD PATDSEL -//Checkered flag: - && cmd != 0x01800000 // LFUFUNC=C - && cmd != 0x01800401 // - && cmd != 0x01800040 // - && cmd != 0x00020008 // -// && cmd != 0x09800F41 // SRCEN CLIP_A1 UPDA1 UPDA1F UPDA2 DSTA2 LFUFUNC=C DCOMPEN - ) - logBlit = true;//*/ -#else -logBlit = true; -#endif -if (blit_start_log == 0) // Wait for the signal... - logBlit = false;//*/ -//temp, for testing... -/*if (cmd != 0x49820609) - logBlit = false;//*/ - -/* -Some T2K unique blits: -logBlit = F, cmd = 00010200 * -logBlit = F, cmd = 00011000 -logBlit = F, cmd = 00011040 -logBlit = F, cmd = 01800005 * -logBlit = F, cmd = 09800741 * - -Hover Strike mission selection screen: -Blit! (CMD = 01902839) // SRCEN DSTEN DSTENZ DSTWRZ DSTA2 GOURZ ZMODE=4 LFUFUNC=C - -Checkered Flag blits in the screw up zone: -Blit! (CMD = 01800001) // SRCEN LFUFUNC=C -Blit! (CMD = 01800000) // LFUFUNC=C -Blit! (CMD = 00010000) // PATDSEL - -Wolfenstein 3D in the fuckup zone: -Blit! (CMD = 01800000) // LFUFUNC=C -*/ - -//printf("logBlit = %s, cmd = %08X\n", (logBlit ? "T" : "F"), cmd); -//fflush(stdout); -//logBlit = true; - -/* -Blit! (CMD = 00011040) -Flags: CLIP_A1 GOURD PATDSEL - count = 18 x 1 - a1_base = 00100000, a2_base = 0081F6A8 - a1_x = 00A7, a1_y = 0014, a1_frac_x = 0000, a1_frac_y = 0000, a2_x = 0001, a2_y = 0000 - a1_step_x = FE80, a1_step_y = 0001, a1_stepf_x = 0000, a1_stepf_y = 0000, a2_step_x = FFF8, a2_step_y = 0001 - a1_inc_x = 0001, a1_inc_y = 0000, a1_incf_x = 0000, a1_incf_y = 0000 - a1_win_x = 0180, a1_win_y = 0118, a2_mask_x = 0000, a2_mask_y = 0000 - a2_mask=F a1add=+phr/+0 a2add=+phr/+0 - a1_pixsize = 4, a2_pixsize = 4 -*/ -//Testing T2K... -/*logBlit = false; -if (cmd == 0x00011040 - && (GET16(blitter_ram, A1_PIXEL + 2) == 0x00A7) && (GET16(blitter_ram, A1_PIXEL + 0) == 0x0014) - && (GET16(blitter_ram, A2_PIXEL + 2) == 0x0001) && (GET16(blitter_ram, A2_PIXEL + 0) == 0x0000) - && (GET16(blitter_ram, PIXLINECOUNTER + 2) == 18)) - logBlit = true;*/ - - // Line states passed in via the command register - bool srcen = (SRCEN), srcenx = (SRCENX), srcenz = (SRCENZ), dsten = (DSTEN), dstenz = (DSTENZ), dstwrz = (DSTWRZ), clip_a1 = (CLIPA1), upda1 = (UPDA1), upda1f = (UPDA1F), upda2 = (UPDA2), dsta2 = (DSTA2), @@ -2833,48 +992,11 @@ if (cmd == 0x00011040 dcompen = (DCOMPEN), bkgwren = (BKGWREN), srcshade = (SRCSHADE); uint8_t zmode = (cmd & 0x01C0000) >> 18, lfufunc = (cmd & 0x1E00000) >> 21; -//Missing: BUSHI -//Where to find various lines: -// clip_a1 -> inner -// gourd -> dcontrol, inner, outer, state -// gourz -> dcontrol, inner, outer, state -// cmpdst -> blit, data, datacomp, state -// bcompen -> acontrol, inner, mcontrol, state -// dcompen -> inner, state -// bkgwren -> inner, state -// srcshade -> dcontrol, inner, state -// adddsel -> dcontrol -//NOTE: ADDDSEL takes precedence over PATDSEL, PATDSEL over LFU_FUNC -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ - char zfs[512], lfus[512]; - zfs[0] = lfus[0] = 0; - if (dstwrz || dstenz || gourz) - sprintf(zfs, " ZMODE=%X", zmode); - if (!(patdsel || adddsel)) - sprintf(lfus, " LFUFUNC=%X", lfufunc); - WriteLog("\nBlit! (CMD = %08X)\nFlags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", cmd, - (srcen ? " SRCEN" : ""), (srcenx ? " SRCENX" : ""), (srcenz ? " SRCENZ" : ""), - (dsten ? " DSTEN" : ""), (dstenz ? " DSTENZ" : ""), (dstwrz ? " DSTWRZ" : ""), - (clip_a1 ? " CLIP_A1" : ""), (upda1 ? " UPDA1" : ""), (upda1f ? " UPDA1F" : ""), - (upda2 ? " UPDA2" : ""), (dsta2 ? " DSTA2" : ""), (gourd ? " GOURD" : ""), - (gourz ? " GOURZ" : ""), (topben ? " TOPBEN" : ""), (topnen ? " TOPNEN" : ""), - (patdsel ? " PATDSEL" : ""), (adddsel ? " ADDDSEL" : ""), zfs, lfus, (cmpdst ? " CMPDST" : ""), - (bcompen ? " BCOMPEN" : ""), (dcompen ? " DCOMPEN" : ""), (bkgwren ? " BKGWREN" : ""), - (srcshade ? " SRCSHADE" : "")); - WriteLog(" count = %d x %d\n", GET16(blitter_ram, PIXLINECOUNTER + 2), GET16(blitter_ram, PIXLINECOUNTER)); -} -#endif - - // Lines that don't exist in Jaguar I (and will never be asserted) bool polygon = false, datinit = false, a1_stepld = false, a2_stepld = false, ext_int = false; bool istepadd = false, istepfadd = false, finneradd = false, inneradd = false; bool zstepfadd = false, zstepadd = false; - // Various state lines (initial state--basically the reset state of the FDSYNCs) - bool go = true, idle = true, inner = false, a1fupdate = false, a1update = false, zfupdate = false, zupdate = false, a2update = false, init_if = false, init_ii = false, init_zf = false, init_zi = false; @@ -2886,8 +1008,6 @@ if (logBlit) bool notgzandp = !(gourz && polygon); - // Various registers set up by user - uint16_t ocount = GET16(blitter_ram, PIXLINECOUNTER); uint8_t a1_pitch = blitter_ram[A1_FLAGS + 3] & 0x03; uint8_t a2_pitch = blitter_ram[A2_FLAGS + 3] & 0x03; @@ -2902,7 +1022,7 @@ if (logBlit) bool a1addy = blitter_ram[A1_FLAGS + 1] & 0x04, a2addy = blitter_ram[A2_FLAGS + 1] & 0x04; bool a1xsign = blitter_ram[A1_FLAGS + 1] & 0x08, a2xsign = blitter_ram[A2_FLAGS + 1] & 0x08; bool a1ysign = blitter_ram[A1_FLAGS + 1] & 0x10, a2ysign = blitter_ram[A2_FLAGS + 1] & 0x10; - uint32_t a1_base = GET32(blitter_ram, A1_BASE) & 0xFFFFFFF8; // Phrase aligned by ignoring bottom 3 bits + uint32_t a1_base = GET32(blitter_ram, A1_BASE) & 0xFFFFFFF8; uint32_t a2_base = GET32(blitter_ram, A2_BASE) & 0xFFFFFFF8; uint16_t a1_win_x = GET16(blitter_ram, A1_CLIP + 2) & 0x7FFF; @@ -2936,189 +1056,26 @@ if (logBlit) uint64_t srcz2 = GET64(blitter_ram, SRCZFRAC); uint64_t dstz = GET64(blitter_ram, DSTZ); uint32_t zinc = GET32(blitter_ram, ZINC); - uint32_t collision = GET32(blitter_ram, COLLISIONCTRL);// 0=RESUME, 1=ABORT, 2=STOPEN + uint32_t collision = GET32(blitter_ram, COLLISIONCTRL); - uint8_t pixsize = (dsta2 ? a2_pixsize : a1_pixsize); // From ACONTROL + uint8_t pixsize = (dsta2 ? a2_pixsize : a1_pixsize); -//Testing Trevor McFur--I *think* it's the circle on the lower RHS of the screen... -/*logBlit = false; -if (cmd == 0x05810601 && (GET16(blitter_ram, PIXLINECOUNTER + 2) == 96) - && (GET16(blitter_ram, PIXLINECOUNTER + 0) == 72)) - logBlit = true;//*/ -//Testing... -//if (cmd == 0x1401060C) patd = 0xFFFFFFFFFFFFFFFFLL; -//if (cmd == 0x1401060C) patd = 0x00000000000000FFLL; -//If it's still not working (bcompen-patd) then see who's writing what to patd and where... -//Still not OK. Check to see who's writing what to where in patd! -//It looks like M68K is writing to the top half of patd... Hmm... -/* -----> M68K wrote 0000 to byte 15737344 of PATTERNDATA... ---> M68K wrote 00 to byte 0 of PATTERNDATA... ---> M68K wrote 00 to byte 1 of PATTERNDATA... -----> M68K wrote 00FF to byte 15737346 of PATTERNDATA... ---> M68K wrote 00 to byte 2 of PATTERNDATA... ---> M68K wrote FF to byte 3 of PATTERNDATA... -logBlit = F, cmd = 1401060C + a2addy = a1addy; -Wren0 := ND6 (wren\[0], gpua\[5], gpua\[6..8], bliten, gpu_memw); -Wren1 := ND6 (wren\[1], gpua[5], gpua\[6..8], bliten, gpu_memw); -Wren2 := ND6 (wren\[2], gpua\[5], gpua[6], gpua\[7..8], bliten, gpu_memw); -Wren3 := ND6 (wren\[3], gpua[5], gpua[6], gpua\[7..8], bliten, gpu_memw); - ---> 0 000x xx00 -Dec0 := D38GH (a1baseld, a1flagld, a1winld, a1ptrld, a1stepld, a1stepfld, a1fracld, a1incld, gpua[2..4], wren\[0]); ---> 0 001x xx00 -Dec1 := D38GH (a1incfld, a2baseld, a2flagld, a2maskld, a2ptrldg, a2stepld, cmdldt, countldt, gpua[2..4], wren\[1]); ---> 0 010x xx00 -Dec2 := D38GH (srcd1ldg[0..1], dstdldg[0..1], dstzldg[0..1], srcz1ldg[0..1], gpua[2..4], wren\[2]); ---> 0 011x xx00 -Dec3 := D38GH (srcz2ld[0..1], patdld[0..1], iincld, zincld, stopld, intld[0], gpua[2..4], wren\[3]); - -wren[3] is asserted when gpu address bus = 0 011x xx00 -patdld[0] -> 0 0110 1000 -> $F02268 (lo 32 bits) -patdld[1] -> 0 0110 1100 -> $F0226C (hi 32 bits) - -So... It's reversed! The data organization of the patd register is [low 32][high 32]! !!! FIX !!! [DONE] -And fix all the other 64 bit registers [DONE] -*/ -/*if (cmd == 0x1401060C) -{ - printf("logBlit = %s, cmd = %08X\n", (logBlit ? "T" : "F"), cmd); - fflush(stdout); -}*/ -/*logBlit = false; -if ((cmd == 0x00010200) && (GET16(blitter_ram, PIXLINECOUNTER + 2) == 9)) - logBlit = true; - -; Pink altimeter bar - -Blit! (00110000 <- 000BF010) count: 9 x 23, A1/2_FLAGS: 000042E2/00010020 [cmd: 00010200] - CMD -> src: dst: misc: a1ctl: UPDA1 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: - A1 step values: -10 (X), 1 (Y) - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 262/132, A2 x/y: 129/0 -;x-coord is 257 in pic, so add 5 -;20 for ship, 33 for #... Let's see if we can find 'em! - -; Black altimeter bar - -Blit! (00110000 <- 000BF010) count: 5 x 29, A1/2_FLAGS: 000042E2/00010020 [cmd: 00010200] - CMD -> src: dst: misc: a1ctl: UPDA1 mode: ity: PATDSEL z-op: op: LFU_CLEAR ctrl: - A1 step values: -8 (X), 1 (Y) - A1 -> pitch: 4 phrases, depth: 16bpp, z-off: 3, width: 320 (21), addctl: XADDPHR YADD0 XSIGNADD YSIGNADD - A2 -> pitch: 1 phrases, depth: 16bpp, z-off: 0, width: 1 (00), addctl: XADDPIX YADD0 XSIGNADD YSIGNADD - A1 x/y: 264/126, A2 x/y: 336/0 - -Here's the pink bar--note that it's phrase mode without dread, so how does this work??? -Not sure, but I *think* that somehow it MUXes the data at the write site in on the left or right side -of the write data when masked in phrase mode. I'll have to do some tracing to see if this is the mechanism -it uses or not... - -Blit! (CMD = 00010200) -Flags: UPDA1 PATDSEL - count = 9 x 11 - a1_base = 00110010, a2_base = 000BD7E0 - a1_x = 0106, a1_y = 0090, a1_frac_x = 0000, a1_frac_y = 8000, a2_x = 025A, a2_y = 0000 - a1_step_x = FFF6, a1_step_y = 0001, a1_stepf_x = 5E00, a1_stepf_y = D100, a2_step_x = FFF7, a2_step_y = 0001 - a1_inc_x = 0001, a1_inc_y = FFFF, a1_incf_x = 0000, a1_incf_y = E000 - a1_win_x = 0000, a1_win_y = 0000, a2_mask_x = 0000, a2_mask_y = 0000 - a2_mask=F a1add=+phr/+0 a2add=+1/+0 - a1_pixsize = 4, a2_pixsize = 4 - srcd=BAC673AC2C92E578 dstd=0000000000000000 patd=74C074C074C074C0 iinc=0002E398 - srcz1=7E127E12000088DA srcz2=DBE06DF000000000 dstz=0000000000000000 zinc=FFFE4840, coll=0 - Phrase mode is ON - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... - Entering DWRITE state... - Dest write address/pix address: 0016A830/0 [dstart=20 dend=40 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] [7400000074C074C0] (icount=0007, inc=2) - Entering A1_ADD state [a1_x=0106, a1_y=0090, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 0016A850/0 [dstart=0 dend=40 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] [74C074C074C074C0] (icount=0003, inc=4) - Entering A1_ADD state [a1_x=0108, a1_y=0090, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 0016A870/0 [dstart=0 dend=30 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] [74C074C074C00000] (icount=FFFF, inc=4) - Entering A1_ADD state [a1_x=010C, a1_y=0090, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering IDLE_INNER state... - Leaving INNER state... (ocount=000A) - [in=F a1f=F a1=T zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering A1UPDATE state... (272/144 -> 262/145) - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... -*/ - - // Bugs in Jaguar I - - a2addy = a1addy; // A2 channel Y add bit is tied to A1's - -//if (logBlit && (ocount > 20)) logBlit = false; -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ - WriteLog(" a1_base = %08X, a2_base = %08X\n", a1_base, a2_base); - WriteLog(" a1_x = %04X, a1_y = %04X, a1_frac_x = %04X, a1_frac_y = %04X, a2_x = %04X, a2_y = %04X\n", (uint16_t)a1_x, (uint16_t)a1_y, a1_frac_x, a1_frac_y, (uint16_t)a2_x, (uint16_t)a2_y); - WriteLog(" a1_step_x = %04X, a1_step_y = %04X, a1_stepf_x = %04X, a1_stepf_y = %04X, a2_step_x = %04X, a2_step_y = %04X\n", (uint16_t)a1_step_x, (uint16_t)a1_step_y, a1_stepf_x, a1_stepf_y, (uint16_t)a2_step_x, (uint16_t)a2_step_y); - WriteLog(" a1_inc_x = %04X, a1_inc_y = %04X, a1_incf_x = %04X, a1_incf_y = %04X\n", (uint16_t)a1_inc_x, (uint16_t)a1_inc_y, a1_incf_x, a1_incf_y); - WriteLog(" a1_win_x = %04X, a1_win_y = %04X, a2_mask_x = %04X, a2_mask_y = %04X\n", a1_win_x, a1_win_y, a2_mask_x, a2_mask_y); - char x_add_str[4][4] = { "phr", "1", "0", "inc" }; - WriteLog(" a2_mask=%s a1add=%s%s/%s%s a2add=%s%s/%s%s\n", (a2_mask ? "T" : "F"), (a1xsign ? "-" : "+"), x_add_str[a1addx], - (a1ysign ? "-" : "+"), (a1addy ? "1" : "0"), (a2xsign ? "-" : "+"), x_add_str[a2addx], - (a2ysign ? "-" : "+"), (a2addy ? "1" : "0")); - WriteLog(" a1_pixsize = %u, a2_pixsize = %u\n", a1_pixsize, a2_pixsize); - WriteLog(" srcd=%08X%08X dstd=%08X%08X patd=%08X%08X iinc=%08X\n", - (uint32_t)(srcd1 >> 32), (uint32_t)(srcd1 & 0xFFFFFFFF), - (uint32_t)(dstd >> 32), (uint32_t)(dstd & 0xFFFFFFFF), - (uint32_t)(patd >> 32), (uint32_t)(patd & 0xFFFFFFFF), iinc); - WriteLog(" srcz1=%08X%08X srcz2=%08X%08X dstz=%08X%08X zinc=%08X, coll=%X\n", - (uint32_t)(srcz1 >> 32), (uint32_t)(srcz1 & 0xFFFFFFFF), - (uint32_t)(srcz2 >> 32), (uint32_t)(srcz2 & 0xFFFFFFFF), - (uint32_t)(dstz >> 32), (uint32_t)(dstz & 0xFFFFFFFF), zinc, collision); -} -#endif - - // Various state lines set up by user - - bool phrase_mode = ((!dsta2 && a1addx == 0) || (dsta2 && a2addx == 0) ? true : false); // From ACONTROL -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Phrase mode is %s\n", (phrase_mode ? "ON" : "off")); -#endif -//logBlit = false; - - // Stopgap vars to simulate various lines + bool phrase_mode = ((!dsta2 && a1addx == 0) || (dsta2 && a2addx == 0) ? true : false); uint16_t a1FracCInX = 0, a1FracCInY = 0; while (true) { - // IDLE - if ((idle && !go) || (inner && outer0 && indone)) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering IDLE state...\n"); -#endif idlei = true; - -//Instead of a return, let's try breaking out of the loop... -break; -// return; + break; } else idlei = false; - // INNER LOOP ACTIVE -/* - Entering DWRITE state... (icount=0000, inc=4) - Entering IDLE_INNER state... - Leaving INNER state... (ocount=00EF) - [in=T a1f=F a1=T zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... -Now: - [in=F a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] -*/ - if ((idle && go && !datinit) || (inner && !indone) || (inner && indone && !outer0 && !upda1f && !upda1 && notgzandp && !upda2 && !datinit) @@ -3133,8 +1090,6 @@ Now: else inneri = false; - // A1 FRACTION UPDATE - if (inner && indone && !outer0 && upda1f) { a1fupdatei = true; @@ -3142,8 +1097,6 @@ Now: else a1fupdatei = false; - // A1 POINTER UPDATE - if ((a1fupdate) || (inner && indone && !outer0 && !upda1f && upda1)) { @@ -3152,8 +1105,6 @@ Now: else a1updatei = false; - // Z FRACTION UPDATE - if ((a1update && gourz && polygon) || (inner && indone && !outer0 && !upda1f && !upda1 && gourz && polygon)) { @@ -3162,8 +1113,6 @@ Now: else zfupdatei = false; - // Z INTEGER UPDATE - if (zfupdate) { zupdatei = true; @@ -3171,8 +1120,6 @@ Now: else zupdatei = false; - // A2 POINTER UPDATE - if ((a1update && upda2 && notgzandp) || (zupdate && upda2) || (inner && indone && !outer0 && !upda1f && notgzandp && !upda1 && upda2)) @@ -3182,8 +1129,6 @@ Now: else a2updatei = false; - // INITIALIZE INTENSITY FRACTION - if ((zupdate && !upda2 && datinit) || (a1update && !upda2 && datinit && notgzandp) || (inner && indone && !outer0 && !upda1f && !upda1 && notgzandp && !upda2 && datinit) @@ -3195,8 +1140,6 @@ Now: else init_ifi = false; - // INITIALIZE INTENSITY INTEGER - if (init_if) { init_iii = true; @@ -3204,8 +1147,6 @@ Now: else init_iii = false; - // INITIALIZE Z FRACTION - if (init_ii && gourz) { init_zfi = true; @@ -3213,8 +1154,6 @@ Now: else init_zfi = false; - // INITIALIZE Z INTEGER - if (init_zf) { init_zii = true; @@ -3222,105 +1161,45 @@ Now: else init_zii = false; -// Here we move the fooi into their foo counterparts in order to simulate the moving -// of data into the various FDSYNCs... Each time we loop we simulate one clock cycle... - idle = idlei; inner = inneri; a1fupdate = a1fupdatei; a1update = a1updatei; - zfupdate = zfupdatei; // * - zupdate = zupdatei; // * + zfupdate = zfupdatei; + zupdate = zupdatei; a2update = a2updatei; - init_if = init_ifi; // * - init_ii = init_iii; // * - init_zf = init_zfi; // * - init_zi = init_zii; // * -// * denotes states that will never assert for Jaguar I -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" [in=%c a1f=%c a1=%c zf=%c z=%c a2=%c iif=%c iii=%c izf=%c izi=%c]\n", - (inner ? 'T' : 'F'), (a1fupdate ? 'T' : 'F'), (a1update ? 'T' : 'F'), - (zfupdate ? 'T' : 'F'), (zupdate ? 'T' : 'F'), (a2update ? 'T' : 'F'), - (init_if ? 'T' : 'F'), (init_ii ? 'T' : 'F'), (init_zf ? 'T' : 'F'), - (init_zi ? 'T' : 'F')); -#endif - -// Now, depending on how we want to handle things, we could either put the implementation -// of the various pieces up above, or handle them down below here. - -// Let's try postprocessing for now... + init_if = init_ifi; + init_ii = init_iii; + init_zf = init_zfi; + init_zi = init_zii; if (inner) { indone = false; -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering INNER state...\n"); -#endif + uint16_t icount = GET16(blitter_ram, PIXLINECOUNTER + 2); bool idle_inner = true, step = true, sreadx = false, szreadx = false, sread = false, szread = false, dread = false, dzread = false, dwrite = false, dzwrite = false; bool inner0 = false; bool idle_inneri, sreadxi, szreadxi, sreadi, szreadi, dreadi, dzreadi, dwritei, dzwritei; - // State lines that will never assert in Jaguar I - bool textext = false, txtread = false; -//other stuff -uint8_t srcshift = 0; -bool sshftld = true; // D flipflop (D -> Q): instart -> sshftld -//NOTE: sshftld probably is only asserted at the beginning of the inner loop. !!! FIX !!! -/* -Blit! (CMD = 01800005) -Flags: SRCEN SRCENX LFUFUNC=C - count = 626 x 1 - a1_base = 00037290, a2_base = 000095D0 - a1_x = 0000, a1_y = 0000, a2_x = 0002, a2_y = 0000 - a1_pixsize = 4, a2_pixsize = 4 - srcd=0000000000000000, dstd=0000000000000000, patd=0000000000000000 - Phrase mode is ON - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... - Entering SREADX state... [dstart=0 dend=20 pwidth=8 srcshift=20] - Source extra read address/pix address: 000095D4/0 [0000001C00540038] - Entering A2_ADD state [a2_x=0002, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering SREAD state... [dstart=0 dend=20 pwidth=8 srcshift=0] - Source read address/pix address: 000095D8/0 [0054003800009814] - Entering A2_ADD state [a2_x=0004, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 00037290/0 [dstart=0 dend=20 pwidth=8 srcshift=0] (icount=026E, inc=4) - Entering A1_ADD state [a1_x=0000, a1_y=0000, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering SREAD state... [dstart=0 dend=20 pwidth=8 srcshift=0] - Source read address/pix address: 000095E0/0 [00009968000377C7] - Entering A2_ADD state [a2_x=0008, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 00037298/0 [dstart=0 dend=20 pwidth=8 srcshift=0] (icount=026A, inc=4) - Entering A1_ADD state [a1_x=0004, a1_y=0000, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... -*/ + uint8_t srcshift = 0; + bool sshftld = true; -// while (!idle_inner) while (true) { - // IDLE - if ((idle_inner && !step) || (dzwrite && step && inner0) || (dwrite && step && !dstwrz && inner0)) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering IDLE_INNER state...\n"); -#endif idle_inneri = true; -break; + break; } else idle_inneri = false; - // EXTRA SOURCE DATA READ - if ((idle_inner && step && srcenx) || (sreadx && !step)) { @@ -3329,8 +1208,6 @@ break; else sreadxi = false; - // EXTRA SOURCE ZED READ - if ((sreadx && step && srcenz) || (szreadx && !step)) { @@ -3339,10 +1216,6 @@ break; else szreadxi = false; - // TEXTURE DATA READ (not implemented because not in Jaguar I) - - // SOURCE DATA READ - if ((szreadx && step && !textext) || (sreadx && step && !srcenz && srcen) || (idle_inner && step && !srcenx && !textext && srcen) @@ -3356,8 +1229,6 @@ break; else sreadi = false; - // SOURCE ZED READ - if ((sread && step && srcenz) || (szread && !step)) { @@ -3366,8 +1237,6 @@ break; else szreadi = false; - // DESTINATION DATA READ - if ((szread && step && dsten) || (sread && step && !srcenz && dsten) || (sreadx && step && !srcenz && !textext && !srcen && dsten) @@ -3382,8 +1251,6 @@ break; else dreadi = false; - // DESTINATION ZED READ - if ((dread && step && dstenz) || (szread && step && !dsten && dstenz) || (sread && step && !srcenz && !dsten && dstenz) @@ -3399,8 +1266,6 @@ break; else dzreadi = false; - // DESTINATION DATA WRITE - if ((dzread && step) || (dread && step && !dstenz) || (szread && step && !dsten && !dstenz) @@ -3417,7 +1282,6 @@ break; else dwritei = false; - // DESTINATION ZED WRITE if ((dzwrite && !step) || (dwrite && step && dstwrz)) @@ -3427,12 +1291,7 @@ break; else dzwritei = false; -//Kludge: A QnD way to make sure that sshftld is asserted only for the first -// cycle of the inner loop... -sshftld = idle_inner; - -// Here we move the fooi into their foo counterparts in order to simulate the moving -// of data into the various FDSYNCs... Each time we loop we simulate one clock cycle... + sshftld = idle_inner; idle_inner = idle_inneri; sreadx = sreadxi; @@ -3444,8 +1303,6 @@ sshftld = idle_inner; dwrite = dwritei; dzwrite = dzwritei; -// Here's a few more decodes--not sure if they're supposed to go here or not... - bool srca_addi = (sreadxi && !srcenz) || (sreadi && !srcenz) || szreadxi || szreadi; bool dsta_addi = (dwritei && !dstwrz) || dzwritei; @@ -3456,54 +1313,16 @@ sshftld = idle_inner; bool zaddr = szreadx || szread || dzread || dzwrite; -// Some stuff from MCONTROL.NET--not sure if this is the correct use of this decode or not... -/*Fontread\ := OND1 (fontread\, sread[1], sreadx[1], bcompen); -Fontread := INV1 (fontread, fontread\); -Justt := NAN3 (justt, fontread\, phrase_mode, tactive\); -Justify := TS (justify, justt, busen);*/ -bool fontread = (sread || sreadx) && bcompen; -bool justify = !(!fontread && phrase_mode /*&& tactive*/); + bool fontread = (sread || sreadx) && bcompen; + bool justify = !(!fontread && phrase_mode); -/* Generate inner loop update enables */ -/* -A1_addi := MX2 (a1_addi, dsta_addi, srca_addi, dsta2); -A2_addi := MX2 (a2_addi, srca_addi, dsta_addi, dsta2); -A1_add := FD1 (a1_add, a1_add\, a1_addi, clk); -A2_add := FD1 (a2_add, a2_add\, a2_addi, clk); -A2_addb := BUF1 (a2_addb, a2_add); -*/ bool a1_add = (dsta2 ? srca_addi : dsta_addi); bool a2_add = (dsta2 ? dsta_addi : srca_addi); -/* Address adder input A register selection -000 A1 step integer part -001 A1 step fraction part -010 A1 increment integer part -011 A1 increment fraction part -100 A2 step - -bit 2 = a2update -bit 1 = /a2update . (a1_add . a1addx[0..1]) -bit 0 = /a2update . ( a1fupdate - + a1_add . atick[0] . a1addx[0..1]) -The /a2update term on bits 0 and 1 is redundant. -Now look-ahead based -*/ uint8_t addasel = (a1fupdate || (a1_add && a1addx == 3) ? 0x01 : 0x00); addasel |= (a1_add && a1addx == 3 ? 0x02 : 0x00); addasel |= (a2update ? 0x04 : 0x00); -/* Address adder input A X constant selection -adda_xconst[0..2] generate a power of 2 in the range 1-64 or all -zeroes when they are all 1 -Remember - these are pixels, so to add one phrase the pixel size -has to be taken into account to get the appropriate value. -for A1 - if a1addx[0..1] are 00 set 6 - pixel size - if a1addx[0..1] are 01 set the value 000 - if a1addx[0..1] are 10 set the value 111 -similarly for A2 -JLH: Also, 11 will likewise set the value to 111 -*/ + uint8_t a1_xconst = 6 - a1_pixsize, a2_xconst = 6 - a2_pixsize; if (a1addx == 1) @@ -3517,1082 +1336,378 @@ JLH: Also, 11 will likewise set the value to 111 a2_xconst = 7; uint8_t adda_xconst = (a2_add ? a2_xconst : a1_xconst); -/* Address adder input A Y constant selection -22 June 94 - This was erroneous, because only the a1addy bit was reflected here. -Therefore, the selection has to be controlled by a bug fix bit. -JLH: Bug fix bit in Jaguar II--not in Jaguar I! -*/ + bool adda_yconst = a1addy; -/* Address adder input A register versus constant selection -given by a1_add . a1addx[0..1] - + a1update - + a1fupdate - + a2_add . a2addx[0..1] - + a2update -*/ + bool addareg = ((a1_add && a1addx == 3) || a1update || a1fupdate || (a2_add && a2addx == 3) || a2update ? true : false); -/* The adders can be put into subtract mode in add pixel size -mode when the corresponding flags are set */ + bool suba_x = ((a1_add && a1xsign && a1addx == 1) || (a2_add && a2xsign && a2addx == 1) ? true : false); bool suba_y = ((a1_add && a1addy && a1ysign) || (a2_add && a2addy && a2ysign) ? true : false); -/* Address adder input B selection -00 A1 pointer -01 A2 pointer -10 A1 fraction -11 Zero -Bit 1 = a1fupdate - + (a1_add . atick[0] . a1addx[0..1]) - + a1fupdate . a1_stepld - + a1update . a1_stepld - + a2update . a2_stepld -Bit 0 = a2update + a2_add - + a1fupdate . a1_stepld - + a1update . a1_stepld - + a2update . a2_stepld -*/ uint8_t addbsel = (a2update || a2_add || (a1fupdate && a1_stepld) || (a1update && a1_stepld) || (a2update && a2_stepld) ? 0x01 : 0x00); addbsel |= (a1fupdate || (a1_add && a1addx == 3) || (a1fupdate && a1_stepld) || (a1update && a1_stepld) || (a2update && a2_stepld) ? 0x02 : 0x00); -/* The modulo bits are used to align X onto a phrase boundary when -it is being updated by one phrase -000 no mask -001 mask bit 0 -010 mask bits 1-0 -.. -110 mask bits 5-0 - -Masking is enabled for a1 when a1addx[0..1] is 00, and the value -is 6 - the pixel size (again!) -*/ uint8_t maska1 = (a1_add && a1addx == 0 ? 6 - a1_pixsize : 0); uint8_t maska2 = (a2_add && a2addx == 0 ? 6 - a2_pixsize : 0); uint8_t modx = (a2_add ? maska2 : maska1); -/* Generate load strobes for the increment updates */ -/*A1pldt := NAN2 (a1pldt, atick[1], a1_add); -A1ptrldi := NAN2 (a1ptrldi, a1update\, a1pldt); - -A1fldt := NAN4 (a1fldt, atick[0], a1_add, a1addx[0..1]); -A1fracldi := NAN2 (a1fracldi, a1fupdate\, a1fldt); - -A2pldt := NAN2 (a2pldt, atick[1], a2_add); -A2ptrldi := NAN2 (a2ptrldi, a2update\, a2pldt);*/ bool a1fracldi = a1fupdate || (a1_add && a1addx == 3); -// Some more from DCONTROL... -// atick[] just MAY be important here! We're assuming it's true and dropping the term... -// That will probably screw up some of the lower terms that seem to rely on the timing of it... -#warning srcdreadd is not properly initialized! -bool srcdreadd = false; // Set in INNER.NET -//Shadeadd\ := NAN2H (shadeadd\, dwrite, srcshade); -//Shadeadd := INV2 (shadeadd, shadeadd\); -bool shadeadd = dwrite && srcshade; -/* Data adder control, input A selection -000 Destination data -001 Initialiser pixel value -100 Source data - computed intensity fraction -101 Pattern data - computed intensity -110 Source zed 1 - computed zed -111 Source zed 2 - computed zed fraction -Bit 0 = dwrite . gourd . atick[1] - + dzwrite . gourz . atick[0] - + istepadd - + zstepfadd - + init_if + init_ii + init_zf + init_zi -Bit 1 = dzwrite . gourz . (atick[0] + atick[1]) - + zstepadd - + zstepfadd -Bit 2 = (gourd + gourz) . /(init_if + init_ii + init_zf + init_zi) - + dwrite . srcshade -*/ -uint8_t daddasel = ((dwrite && gourd) || (dzwrite && gourz) || istepadd || zstepfadd - || init_if || init_ii || init_zf || init_zi ? 0x01 : 0x00); -daddasel |= ((dzwrite && gourz) || zstepadd || zstepfadd ? 0x02 : 0x00); -daddasel |= (((gourd || gourz) && !(init_if || init_ii || init_zf || init_zi)) - || (dwrite && srcshade) ? 0x04 : 0x00); -/* Data adder control, input B selection -0000 Source data -0001 Data initialiser increment -0100 Bottom 16 bits of I increment repeated four times -0101 Top 16 bits of I increment repeated four times -0110 Bottom 16 bits of Z increment repeated four times -0111 Top 16 bits of Z increment repeated four times -1100 Bottom 16 bits of I step repeated four times -1101 Top 16 bits of I step repeated four times -1110 Bottom 16 bits of Z step repeated four times -1111 Top 16 bits of Z step repeated four times + bool srcdreadd = false; -Bit 0 = dwrite . gourd . atick[1] - + dzwrite . gourz . atick[1] - + dwrite . srcshade - + istepadd - + zstepadd - + init_if + init_ii + init_zf + init_zi -Bit 1 = dzwrite . gourz . (atick[0] + atick[1]) - + zstepadd - + zstepfadd -Bit 2 = dwrite . gourd . (atick[0] + atick[1]) - + dzwrite . gourz . (atick[0] + atick[1]) - + dwrite . srcshade - + istepadd + istepfadd + zstepadd + zstepfadd -Bit 3 = istepadd + istepfadd + zstepadd + zstepfadd -*/ -uint8_t daddbsel = ((dwrite && gourd) || (dzwrite && gourz) || (dwrite && srcshade) - || istepadd || zstepadd || init_if || init_ii || init_zf || init_zi ? 0x01 : 0x00); -daddbsel |= ((dzwrite && gourz) || zstepadd || zstepfadd ? 0x02 : 0x00); -daddbsel |= ((dwrite && gourd) || (dzwrite && gourz) || (dwrite && srcshade) - || istepadd || istepfadd || zstepadd || zstepfadd ? 0x04 : 0x00); -daddbsel |= (istepadd && istepfadd && zstepadd && zstepfadd ? 0x08 : 0x00); -/* Data adder mode control -000 16-bit normal add -001 16-bit saturating add with carry -010 8-bit saturating add with carry, carry into top byte is - inhibited (YCrCb) -011 8-bit saturating add with carry, carry into top byte and - between top nybbles is inhibited (CRY) -100 16-bit normal add with carry -101 16-bit saturating add -110 8-bit saturating add, carry into top byte is inhibited -111 8-bit saturating add, carry into top byte and between top - nybbles is inhibited + bool shadeadd = dwrite && srcshade; -The first five are used for Gouraud calculations, the latter three -for adding source and destination data + uint8_t daddasel = ((dwrite && gourd) || (dzwrite && gourz) || istepadd || zstepfadd + || init_if || init_ii || init_zf || init_zi ? 0x01 : 0x00); + daddasel |= ((dzwrite && gourz) || zstepadd || zstepfadd ? 0x02 : 0x00); + daddasel |= (((gourd || gourz) && !(init_if || init_ii || init_zf || init_zi)) + || (dwrite && srcshade) ? 0x04 : 0x00); -Bit 0 = dzwrite . gourz . atick[1] - + dwrite . gourd . atick[1] . /topnen . /topben . /ext_int - + dwrite . gourd . atick[1] . topnen . topben . /ext_int - + zstepadd - + istepadd . /topnen . /topben . /ext_int - + istepadd . topnen . topben . /ext_int - + /gourd . /gourz . /topnen . /topben - + /gourd . /gourz . topnen . topben - + shadeadd . /topnen . /topben - + shadeadd . topnen . topben - + init_ii . /topnen . /topben . /ext_int - + init_ii . topnen . topben . /ext_int - + init_zi + uint8_t daddbsel = ((dwrite && gourd) || (dzwrite && gourz) || (dwrite && srcshade) + || istepadd || zstepadd || init_if || init_ii || init_zf || init_zi ? 0x01 : 0x00); + daddbsel |= ((dzwrite && gourz) || zstepadd || zstepfadd ? 0x02 : 0x00); + daddbsel |= ((dwrite && gourd) || (dzwrite && gourz) || (dwrite && srcshade) + || istepadd || istepfadd || zstepadd || zstepfadd ? 0x04 : 0x00); + daddbsel |= (istepadd && istepfadd && zstepadd && zstepfadd ? 0x08 : 0x00); -Bit 1 = dwrite . gourd . atick[1] . /topben . /ext_int - + istepadd . /topben . /ext_int - + /gourd . /gourz . /topben - + shadeadd . /topben - + init_ii . /topben . /ext_int + uint8_t daddmode = ((dzwrite && gourz) || (dwrite && gourd && !topnen && !topben && !ext_int) + || (dwrite && gourd && topnen && topben && !ext_int) || zstepadd + || (istepadd && !topnen && !topben && !ext_int) + || (istepadd && topnen && topben && !ext_int) || (!gourd && !gourz && !topnen && !topben) + || (!gourd && !gourz && topnen && topben) || (shadeadd && !topnen && !topben) + || (shadeadd && topnen && topben) || (init_ii && !topnen && !topben && !ext_int) + || (init_ii && topnen && topben && !ext_int) || init_zi ? 0x01 : 0x00); + daddmode |= ((dwrite && gourd && !topben && !ext_int) || (istepadd && !topben && !ext_int) + || (!gourd && !gourz && !topben) || (shadeadd && !topben) + || (init_ii && !topben && !ext_int) ? 0x02 : 0x00); + daddmode |= ((!gourd && !gourz) || shadeadd || (dwrite && gourd && ext_int) + || (istepadd && ext_int) || (init_ii && ext_int) ? 0x04 : 0x00); -Bit 2 = /gourd . /gourz - + shadeadd - + dwrite . gourd . atick[1] . ext_int - + istepadd . ext_int - + init_ii . ext_int -*/ -uint8_t daddmode = ((dzwrite && gourz) || (dwrite && gourd && !topnen && !topben && !ext_int) - || (dwrite && gourd && topnen && topben && !ext_int) || zstepadd - || (istepadd && !topnen && !topben && !ext_int) - || (istepadd && topnen && topben && !ext_int) || (!gourd && !gourz && !topnen && !topben) - || (!gourd && !gourz && topnen && topben) || (shadeadd && !topnen && !topben) - || (shadeadd && topnen && topben) || (init_ii && !topnen && !topben && !ext_int) - || (init_ii && topnen && topben && !ext_int) || init_zi ? 0x01 : 0x00); -daddmode |= ((dwrite && gourd && !topben && !ext_int) || (istepadd && !topben && !ext_int) - || (!gourd && !gourz && !topben) || (shadeadd && !topben) - || (init_ii && !topben && !ext_int) ? 0x02 : 0x00); -daddmode |= ((!gourd && !gourz) || shadeadd || (dwrite && gourd && ext_int) - || (istepadd && ext_int) || (init_ii && ext_int) ? 0x04 : 0x00); -/* Data add load controls -Pattern fraction (dest data) is loaded on - dwrite . gourd . atick[0] - + istepfadd . /datinit - + init_if -Pattern data is loaded on - dwrite . gourd . atick[1] - + istepadd . /datinit . /datinit - + init_ii -Source z1 is loaded on - dzwrite . gourz . atick[1] - + zstepadd . /datinit . /datinit - + init_zi -Source z2 is loaded on - dzwrite . gourz . atick[0] - + zstepfadd - + init_zf -Texture map shaded data is loaded on - srcdreadd . srcshade -*/ -bool patfadd = (dwrite && gourd) || (istepfadd && !datinit) || init_if; -bool patdadd = (dwrite && gourd) || (istepadd && !datinit) || init_ii; -bool srcz1add = (dzwrite && gourz) || (zstepadd && !datinit) || init_zi; -bool srcz2add = (dzwrite && gourz) || zstepfadd || init_zf; -bool srcshadd = srcdreadd && srcshade; -bool daddq_sel = patfadd || patdadd || srcz1add || srcz2add || srcshadd; -/* Select write data -This has to be controlled from stage 1 of the pipe-line, delayed -by one tick, as the write occurs in the cycle after the ack. + bool patfadd = (dwrite && gourd) || (istepfadd && !datinit) || init_if; + bool patdadd = (dwrite && gourd) || (istepadd && !datinit) || init_ii; + bool srcz1add = (dzwrite && gourz) || (zstepadd && !datinit) || init_zi; + bool srcz2add = (dzwrite && gourz) || zstepfadd || init_zf; + bool srcshadd = srcdreadd && srcshade; + bool daddq_sel = patfadd || patdadd || srcz1add || srcz2add || srcshadd; -00 pattern data -01 lfu data -10 adder output -11 source zed + uint8_t data_sel = ((!patdsel && !adddsel) || dzwrite ? 0x01 : 0x00) + | (adddsel || dzwrite ? 0x02 : 0x00); -Bit 0 = /patdsel . /adddsel - + dzwrite1d -Bit 1 = adddsel - + dzwrite1d -*/ -uint8_t data_sel = ((!patdsel && !adddsel) || dzwrite ? 0x01 : 0x00) - | (adddsel || dzwrite ? 0x02 : 0x00); + uint32_t address, pixAddr; + ADDRGEN(address, pixAddr, gena2i, zaddr, + a1_x, a1_y, a1_base, a1_pitch, a1_pixsize, a1_width, a1_zoffset, + a2_x, a2_y, a2_base, a2_pitch, a2_pixsize, a2_width, a2_zoffset); -uint32_t address, pixAddr; -ADDRGEN(address, pixAddr, gena2i, zaddr, - a1_x, a1_y, a1_base, a1_pitch, a1_pixsize, a1_width, a1_zoffset, - a2_x, a2_y, a2_base, a2_pitch, a2_pixsize, a2_width, a2_zoffset); + if (!justify) + address &= 0xFFFFF8; -//Here's my guess as to how the addresses get truncated to phrase boundaries in phrase mode... -if (!justify) - address &= 0xFFFFF8; + uint8_t dstxp = (dsta2 ? a2_x : a1_x) & 0x3F; + uint8_t srcxp = (dsta2 ? a1_x : a2_x) & 0x3F; + uint8_t shftv = ((dstxp - srcxp) << pixsize) & 0x3F; -/* Generate source alignment shift - ------------------------------- -The source alignment shift for data move is the difference between -the source and destination X pointers, multiplied by the pixel -size. Only the low six bits of the pointers are of interest, as -pixel sizes are always a power of 2 and window rows are always -phrase aligned. + uint8_t pobb = 0; -When not in phrase mode, the top 3 bits of the shift value are -set to zero (2/26). + if (pixsize == 3) + pobb = dstxp & 0x07; + if (pixsize == 4) + pobb = dstxp & 0x03; + if (pixsize == 5) + pobb = dstxp & 0x01; -Source shifting is also used to extract bits for bit-to-byte -expansion in phrase mode. This involves only the bottom three -bits of the shift value, and is based on the offset within the -phrase of the destination X pointer, in pixels. + bool pobbsel = phrase_mode && bcompen; + uint8_t loshd = (pobbsel ? pobb : shftv) & 0x07; + uint8_t shfti = (srcen || pobbsel ? (sshftld ? loshd : srcshift & 0x07) : 0); -Source shifting is disabled when srcen is not set. -*/ -uint8_t dstxp = (dsta2 ? a2_x : a1_x) & 0x3F; -uint8_t srcxp = (dsta2 ? a1_x : a2_x) & 0x3F; -uint8_t shftv = ((dstxp - srcxp) << pixsize) & 0x3F; -/* The phrase mode alignment count is given by the phrase offset -of the first pixel, for bit to byte expansion */ -uint8_t pobb = 0; - -if (pixsize == 3) - pobb = dstxp & 0x07; -if (pixsize == 4) - pobb = dstxp & 0x03; -if (pixsize == 5) - pobb = dstxp & 0x01; - -bool pobbsel = phrase_mode && bcompen; -uint8_t loshd = (pobbsel ? pobb : shftv) & 0x07; -uint8_t shfti = (srcen || pobbsel ? (sshftld ? loshd : srcshift & 0x07) : 0); -/* Enable for high bits is srcen . phrase_mode */ -shfti |= (srcen && phrase_mode ? (sshftld ? shftv & 0x38 : srcshift & 0x38) : 0); -srcshift = shfti; + shfti |= (srcen && phrase_mode ? (sshftld ? shftv & 0x38 : srcshift & 0x38) : 0); + srcshift = shfti; if (sreadx) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering SREADX state..."); -#endif -//uint32_t srcAddr, pixAddr; -//ADDRGEN(srcAddr, pixAddr, gena2i, zaddr, -// a1_x, a1_y, a1_base, a1_pitch, a1_pixsize, a1_width, a1_zoffset, -// a2_x, a2_y, a2_base, a2_pitch, a2_pixsize, a2_width, a2_zoffset); srcd2 = srcd1; srcd1 = ((uint64_t)JaguarReadLong(address + 0, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); -//Kludge to take pixel size into account... -//Hmm. If we're not in phrase mode, this is most likely NOT going to be used... -//Actually, it would be--because of BCOMPEN expansion, for example... -if (!phrase_mode) -{ - if (bcompen) - srcd1 >>= 56; - else - { - if (pixsize == 5) - srcd1 >>= 32; - else if (pixsize == 4) - srcd1 >>= 48; - else - srcd1 >>= 56; - } -}//*/ -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Source extra read address/pix address: %08X/%1X [%08X%08X]\n", - address, pixAddr, (uint32_t)(srcd1 >> 32), (uint32_t)(srcd1 & 0xFFFFFFFF)); -#endif + + if (!phrase_mode) + { + if (bcompen) + srcd1 >>= 56; + else + { + if (pixsize == 5) + srcd1 >>= 32; + else if (pixsize == 4) + srcd1 >>= 48; + else + srcd1 >>= 56; + } + } } if (szreadx) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering SZREADX state..."); -#endif srcz2 = srcz1; srcz1 = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Src Z extra read address/pix address: %08X/%1X [%08X%08X]\n", address, pixAddr, - (uint32_t)(dstz >> 32), (uint32_t)(dstz & 0xFFFFFFFF)); -#endif } if (sread) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering SREAD state..."); -#endif -//uint32_t srcAddr, pixAddr; -//ADDRGEN(srcAddr, pixAddr, gena2i, zaddr, -// a1_x, a1_y, a1_base, a1_pitch, a1_pixsize, a1_width, a1_zoffset, -// a2_x, a2_y, a2_base, a2_pitch, a2_pixsize, a2_width, a2_zoffset); -srcd2 = srcd1; -srcd1 = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); -//Kludge to take pixel size into account... -if (!phrase_mode) -{ - if (bcompen) - srcd1 >>= 56; - else - { - if (pixsize == 5) - srcd1 >>= 32; - else if (pixsize == 4) - srcd1 >>= 48; - else - srcd1 >>= 56; - } -} -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" Source read address/pix address: %08X/%1X [%08X%08X]\n", address, pixAddr, - (uint32_t)(srcd1 >> 32), (uint32_t)(srcd1 & 0xFFFFFFFF)); -//fflush(stdout); -} -#endif + srcd2 = srcd1; + srcd1 = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); + + if (!phrase_mode) + { + if (bcompen) + srcd1 >>= 56; + else + { + if (pixsize == 5) + srcd1 >>= 32; + else if (pixsize == 4) + srcd1 >>= 48; + else + srcd1 >>= 56; + } + } } if (szread) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" Entering SZREAD state..."); -//fflush(stdout); -} -#endif srcz2 = srcz1; srcz1 = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); -//Kludge to take pixel size into account... I believe that it only has to take 16BPP mode into account. Not sure tho. -if (!phrase_mode && pixsize == 4) - srcz1 >>= 48; -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ - WriteLog(" Src Z read address/pix address: %08X/%1X [%08X%08X]\n", address, pixAddr, - (uint32_t)(dstz >> 32), (uint32_t)(dstz & 0xFFFFFFFF)); -} -#endif + if (!phrase_mode && pixsize == 4) + srcz1 >>= 48; } if (dread) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering DREAD state..."); -#endif -//uint32_t dstAddr, pixAddr; -//ADDRGEN(dstAddr, pixAddr, gena2i, zaddr, -// a1_x, a1_y, a1_base, a1_pitch, a1_pixsize, a1_width, a1_zoffset, -// a2_x, a2_y, a2_base, a2_pitch, a2_pixsize, a2_width, a2_zoffset); -dstd = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); -//Kludge to take pixel size into account... -if (!phrase_mode) -{ - if (pixsize == 5) - dstd >>= 32; - else if (pixsize == 4) - dstd >>= 48; - else - dstd >>= 56; -} -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Dest read address/pix address: %08X/%1X [%08X%08X]\n", address, - pixAddr, (uint32_t)(dstd >> 32), (uint32_t)(dstd & 0xFFFFFFFF)); -#endif + dstd = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); + + if (!phrase_mode) + { + if (pixsize == 5) + dstd >>= 32; + else if (pixsize == 4) + dstd >>= 48; + else + dstd >>= 56; + } } if (dzread) { -// Is Z always 64 bit read? Or sometimes 16 bit (dependent on phrase_mode)? -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering DZREAD state..."); -#endif dstz = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); -//Kludge to take pixel size into account... I believe that it only has to take 16BPP mode into account. Not sure tho. -if (!phrase_mode && pixsize == 4) - dstz >>= 48; -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Dest Z read address/pix address: %08X/%1X [%08X%08X]\n", address, - pixAddr, (uint32_t)(dstz >> 32), (uint32_t)(dstz & 0xFFFFFFFF)); -#endif + if (!phrase_mode && pixsize == 4) + dstz >>= 48; } -// These vars should probably go further up in the code... !!! FIX !!! -// We can't preassign these unless they're static... -//uint64_t srcz = 0; // These are assigned to shut up stupid compiler warnings--dwrite is ALWAYS asserted -//bool winhibit = false; -uint64_t srcz; -bool winhibit; -//NOTE: SRCSHADE requires GOURZ to be set to work properly--another Jaguar I bug + uint64_t srcz; + bool winhibit; + if (dwrite) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Entering DWRITE state..."); -#endif -//Counter is done on the dwrite state...! (We'll do it first, since it affects dstart/dend calculations.) -//Here's the voodoo for figuring the correct amount of pixels in phrase mode (or not): - int8_t inct = -((dsta2 ? a2_x : a1_x) & 0x07); // From INNER_CNT + int8_t inct = -((dsta2 ? a2_x : a1_x) & 0x07); uint8_t inc = 0; inc = (!phrase_mode || (phrase_mode && (inct & 0x01)) ? 0x01 : 0x00); inc |= (phrase_mode && (((pixsize == 3 || pixsize == 4) && (inct & 0x02)) || pixsize == 5 && !(inct & 0x01)) ? 0x02 : 0x00); inc |= (phrase_mode && ((pixsize == 3 && (inct & 0x04)) || (pixsize == 4 && !(inct & 0x03))) ? 0x04 : 0x00); inc |= (phrase_mode && pixsize == 3 && !(inct & 0x07) ? 0x08 : 0x00); - uint16_t oldicount = icount; // Save icount to detect underflow... + uint16_t oldicount = icount; icount -= inc; if (icount == 0 || ((icount & 0x8000) && !(oldicount & 0x8000))) inner0 = true; -// X/Y stepping is also done here, I think...No. It's done when a1_add or a2_add is asserted... -//********************************************************************************* -//Start & end write mask computations... -//********************************************************************************* + uint8_t dstart = 0; -uint8_t dstart = 0; + if (pixsize == 3) + dstart = (dstxp & 0x07) << 3; + if (pixsize == 4) + dstart = (dstxp & 0x03) << 4; + if (pixsize == 5) + dstart = (dstxp & 0x01) << 5; -if (pixsize == 3) - dstart = (dstxp & 0x07) << 3; -if (pixsize == 4) - dstart = (dstxp & 0x03) << 4; -if (pixsize == 5) - dstart = (dstxp & 0x01) << 5; + dstart = (phrase_mode ? dstart : pixAddr & 0x07); -dstart = (phrase_mode ? dstart : pixAddr & 0x07); + uint16_t dstxwr = (dsta2 ? a2_x : a1_x) & 0x7FFE; + uint16_t pseq = dstxwr ^ (a1_win_x & 0x7FFE); + pseq = (pixsize == 5 ? pseq : pseq & 0x7FFC); + pseq = ((pixsize & 0x06) == 4 ? pseq : pseq & 0x7FF8); + bool penden = clip_a1 && (pseq == 0); + uint8_t window_mask = 0; -//This is the other Jaguar I bug... Normally, should ALWAYS select a1_x here. -uint16_t dstxwr = (dsta2 ? a2_x : a1_x) & 0x7FFE; -uint16_t pseq = dstxwr ^ (a1_win_x & 0x7FFE); -pseq = (pixsize == 5 ? pseq : pseq & 0x7FFC); -pseq = ((pixsize & 0x06) == 4 ? pseq : pseq & 0x7FF8); -bool penden = clip_a1 && (pseq == 0); -uint8_t window_mask = 0; + if (pixsize == 3) + window_mask = (a1_win_x & 0x07) << 3; + if (pixsize == 4) + window_mask = (a1_win_x & 0x03) << 4; + if (pixsize == 5) + window_mask = (a1_win_x & 0x01) << 5; -if (pixsize == 3) - window_mask = (a1_win_x & 0x07) << 3; -if (pixsize == 4) - window_mask = (a1_win_x & 0x03) << 4; -if (pixsize == 5) - window_mask = (a1_win_x & 0x01) << 5; + window_mask = (penden ? window_mask : 0); -window_mask = (penden ? window_mask : 0); + uint8_t inner_mask = 0; -/* - Entering SREADX state... [dstart=0 dend=20 pwidth=8 srcshift=20] - Source extra read address/pix address: 000095D0/0 [000004E40000001C] - Entering A2_ADD state [a2_x=0002, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering SREAD state... [dstart=0 dend=20 pwidth=8 srcshift=20] - Source read address/pix address: 000095D8/0 [0054003800009814] - Entering A2_ADD state [a2_x=0004, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 00037290/0 [dstart=0 dend=20 pwidth=8 srcshift=20][daas=0 dabs=0 dam=7 ds=1 daq=F] [0000001C00000000] (icount=026E, inc=4) - Entering A1_ADD state [a1_x=0000, a1_y=0000, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... + if (pixsize == 3) + inner_mask = (icount & 0x07) << 3; + if (pixsize == 4) + inner_mask = (icount & 0x03) << 4; + if (pixsize == 5) + inner_mask = (icount & 0x01) << 5; + if (!inner0) + inner_mask = 0; -(icount=026E, inc=4) -icount & 0x03 = 0x02 - << 4 = 0x20 + window_mask = (window_mask == 0 ? 0x40 : window_mask); + inner_mask = (inner_mask == 0 ? 0x40 : inner_mask); + uint8_t emask = (window_mask > inner_mask ? inner_mask : window_mask); + uint8_t pma = pixAddr + (1 << pixsize); + uint8_t dend = (phrase_mode ? emask : pma); -window_mask = 0x1000 + uint8_t pwidth = (((dend | dstart) & 0x07) == 0 ? 0x08 : (dend - dstart) & 0x07); -Therefore, it chooses the inner_mask over the window_mask every time! Argh! -This is because we did this wrong: -Innerm[3-5] := AN2 (inner_mask[3-5], imb[3-5], inner0); -NOTE! This doesn't fix the problem because inner0 is asserted too late to help here. !!! FIX !!! [Should be DONE] -*/ + if (phrase_mode && !dsten) + dstd = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); -/* The mask to be used if within one phrase of the end of the inner -loop, similarly */ -uint8_t inner_mask = 0; + uint64_t srcd = (srcd2 << (64 - srcshift)) | (srcd1 >> srcshift); -if (pixsize == 3) - inner_mask = (icount & 0x07) << 3; -if (pixsize == 4) - inner_mask = (icount & 0x03) << 4; -if (pixsize == 5) - inner_mask = (icount & 0x01) << 5; -if (!inner0) - inner_mask = 0; -/* The actual mask used should be the lesser of the window masks and -the inner mask, where is all cases 000 means 1000. */ -window_mask = (window_mask == 0 ? 0x40 : window_mask); -inner_mask = (inner_mask == 0 ? 0x40 : inner_mask); -uint8_t emask = (window_mask > inner_mask ? inner_mask : window_mask); -/* The mask to be used for the pixel size, to which must be added -the bit offset */ -uint8_t pma = pixAddr + (1 << pixsize); -/* Select the mask */ -uint8_t dend = (phrase_mode ? emask : pma); + if (srcshift == 0) + srcd = srcd1; -/* The cycle width in phrase mode is normally one phrase. However, -at the start and end it may be narrower. The start and end masks -are used to generate this. The width is given by: + if (!phrase_mode && srcshift != 0) + srcd = ((srcd2 & 0xFF) << (8 - srcshift)) | ((srcd1 & 0xFF) >> srcshift); - 8 - start mask - (8 - end mask) -= end mask - start mask + if (gourz) + { + uint16_t addq[4]; + uint8_t initcin[4] = { 0, 0, 0, 0 }; + ADDARRAY(addq, 7, 6, 0, 0, 0, initcin, 0, 0, 0, 0, 0, srcz1, srcz2, zinc, 0); + srcz2 = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; + ADDARRAY(addq, 6, 7, 1, 0, 0, initcin, 0, 0, 0, 0, 0, srcz1, srcz2, zinc, 0); + srcz1 = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; + } -This is only used for writes in phrase mode. -Start and end from the address level of the pipeline are used. -*/ -uint8_t pwidth = (((dend | dstart) & 0x07) == 0 ? 0x08 : (dend - dstart) & 0x07); + uint8_t zSrcShift = srcshift & 0x30; + srcz = (srcz2 << (64 - zSrcShift)) | (srcz1 >> zSrcShift); -//uint32_t dstAddr, pixAddr; -//ADDRGEN(dstAddr, pixAddr, gena2i, zaddr, -// a1_x, a1_y, a1_base, a1_pitch, a1_pixsize, a1_width, a1_zoffset, -// a2_x, a2_y, a2_base, a2_pitch, a2_pixsize, a2_width, a2_zoffset); -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" Dest write address/pix address: %08X/%1X", address, pixAddr); -#endif + if (zSrcShift == 0) + srcz = srcz1; -//More testing... This is almost certainly wrong, but how else does this work??? -//Seems to kinda work... But still, this doesn't seem to make any sense! -if (phrase_mode && !dsten) - dstd = ((uint64_t)JaguarReadLong(address, BLITTER) << 32) | (uint64_t)JaguarReadLong(address + 4, BLITTER); + if (srcshade) + { + uint16_t addq[4]; + uint8_t initcin[4] = { 0, 0, 0, 0 }; + ADDARRAY(addq, 4, 5, 7, dstd, iinc, initcin, 0, 0, 0, patd, srcd, 0, 0, 0, 0); + srcd = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; + } -//Testing only... for now... -//This is wrong because the write data is a combination of srcd and dstd--either run -//thru the LFU or in PATDSEL or ADDDSEL mode. [DONE now, thru DATA module] -// Precedence is ADDDSEL > PATDSEL > LFU. -//Also, doesn't take into account the start & end masks, or the phrase width... -//Now it does! + if (patfadd) + { + uint16_t addq[4]; + uint8_t initcin[4] = { 0, 0, 0, 0 }; + ADDARRAY(addq, 4, 4, 0, dstd, iinc, initcin, 0, 0, 0, patd, srcd, 0, 0, 0, 0); + srcd1 = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; + } -// srcd2 = xxxx xxxx 0123 4567, srcd = 8901 2345 xxxx xxxx, srcshift = $20 (32) -uint64_t srcd = (srcd2 << (64 - srcshift)) | (srcd1 >> srcshift); -//bleh, ugly ugly ugly -if (srcshift == 0) - srcd = srcd1; + uint64_t wdata; + uint8_t dcomp, zcomp; + DATA(wdata, dcomp, zcomp, winhibit, + true, cmpdst, daddasel, daddbsel, daddmode, daddq_sel, data_sel, 0, + dend, dstart, dstd, iinc, lfufunc, patd, patdadd, + phrase_mode, srcd, false, false, srcz2add, zmode, + bcompen, bkgwren, dcompen, icount & 0x07, pixsize, + srcz, dstz, zinc); -//NOTE: This only works with pixel sizes less than 8BPP... -//DOUBLE NOTE: Still need to do regression testing to ensure that this doesn't break other stuff... !!! CHECK !!! -if (!phrase_mode && srcshift != 0) - srcd = ((srcd2 & 0xFF) << (8 - srcshift)) | ((srcd1 & 0xFF) >> srcshift); + if (clip_a1 && ((a1_x & 0x8000) || (a1_y & 0x8000) || (a1_x >= a1_win_x) || (a1_y >= a1_win_y))) + winhibit = true; -//Z DATA() stuff done here... And it has to be done before any Z shifting... -//Note that we need to have phrase mode start/end support here... (Not since we moved it from dzwrite...!) -/* -Here are a couple of Cybermorph blits with Z: -$00113078 // DSTEN DSTENZ DSTWRZ CLIP_A1 GOURD GOURZ PATDSEL ZMODE=4 -$09900F39 // SRCEN DSTEN DSTENZ DSTWRZ UPDA1 UPDA1F UPDA2 DSTA2 ZMODE=4 LFUFUNC=C DCOMPEN - -We're having the same phrase mode overwrite problem we had with the pixels... !!! FIX !!! -Odd. It's equating 0 with 0... Even though ZMODE is $04 (less than)! -*/ -if (gourz) -{ -/* -void ADDARRAY(uint16_t * addq, uint8_t daddasel, uint8_t daddbsel, uint8_t daddmode, - uint64_t dstd, uint32_t iinc, uint8_t initcin[], uint64_t initinc, uint16_t initpix, - uint32_t istep, uint64_t patd, uint64_t srcd, uint64_t srcz1, uint64_t srcz2, - uint32_t zinc, uint32_t zstep) -*/ - uint16_t addq[4]; - uint8_t initcin[4] = { 0, 0, 0, 0 }; - ADDARRAY(addq, 7/*daddasel*/, 6/*daddbsel*/, 0/*daddmode*/, 0, 0, initcin, 0, 0, 0, 0, 0, srcz1, srcz2, zinc, 0); - srcz2 = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; - ADDARRAY(addq, 6/*daddasel*/, 7/*daddbsel*/, 1/*daddmode*/, 0, 0, initcin, 0, 0, 0, 0, 0, srcz1, srcz2, zinc, 0); - srcz1 = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; - -#if 0//def VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog("\n[srcz1=%08X%08X, srcz2=%08X%08X, zinc=%08X", - (uint32_t)(srcz1 >> 32), (uint32_t)(srcz1 & 0xFFFFFFFF), - (uint32_t)(srcz2 >> 32), (uint32_t)(srcz2 & 0xFFFFFFFF), zinc); -#endif -} - -uint8_t zSrcShift = srcshift & 0x30; -srcz = (srcz2 << (64 - zSrcShift)) | (srcz1 >> zSrcShift); -//bleh, ugly ugly ugly -if (zSrcShift == 0) - srcz = srcz1; - -#if 0//def VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog(" srcz=%08X%08X]\n", (uint32_t)(srcz >> 32), (uint32_t)(srcz & 0xFFFFFFFF)); -#endif - -//When in SRCSHADE mode, it adds the IINC to the read source (from LFU???) -//According to following line, it gets LFU mode. But does it feed the source into the LFU -//after the add? -//Dest write address/pix address: 0014E83E/0 [dstart=0 dend=10 pwidth=8 srcshift=0][daas=4 dabs=5 dam=7 ds=1 daq=F] [0000000000006505] (icount=003F, inc=1) -//Let's try this: -if (srcshade) -{ -//NOTE: This is basically doubling the work done by DATA--since this is what -// ADDARRAY is loaded with when srschshade is enabled... !!! FIX !!! -// Also note that it doesn't work properly unless GOURZ is set--there's the clue! - uint16_t addq[4]; - uint8_t initcin[4] = { 0, 0, 0, 0 }; - ADDARRAY(addq, 4/*daddasel*/, 5/*daddbsel*/, 7/*daddmode*/, dstd, iinc, initcin, 0, 0, 0, patd, srcd, 0, 0, 0, 0); - srcd = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; -} -//Seems to work... Not 100% sure tho. -//end try this - -//Temporary kludge, to see if the fractional pattern does anything... -//This works, BTW -//But it seems to mess up in Cybermorph... the shading should be smooth but it isn't... -//Seems the carry out is lost again... !!! FIX !!! [DONE--see below] -if (patfadd) -{ - uint16_t addq[4]; - uint8_t initcin[4] = { 0, 0, 0, 0 }; - ADDARRAY(addq, 4/*daddasel*/, 4/*daddbsel*/, 0/*daddmode*/, dstd, iinc, initcin, 0, 0, 0, patd, srcd, 0, 0, 0, 0); - srcd1 = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; -} - -//Note that we still don't take atick[0] & [1] into account here, so this will skip half of the data needed... !!! FIX !!! -//Not yet enumerated: dbinh, srcdread, srczread -//Also, should do srcshift on the z value in phrase mode... !!! FIX !!! [DONE] -//As well as add a srcz variable we can set external to this state... !!! FIX !!! [DONE] - -uint64_t wdata; -uint8_t dcomp, zcomp; -DATA(wdata, dcomp, zcomp, winhibit, - true, cmpdst, daddasel, daddbsel, daddmode, daddq_sel, data_sel, 0/*dbinh*/, - dend, dstart, dstd, iinc, lfufunc, patd, patdadd, - phrase_mode, srcd, false/*srcdread*/, false/*srczread*/, srcz2add, zmode, - bcompen, bkgwren, dcompen, icount & 0x07, pixsize, - srcz, dstz, zinc); -/* -Seems that the phrase mode writes with DCOMPEN and DSTEN are corrupting inside of DATA: !!! FIX !!! -It's fairly random as well. 7CFE -> 7DFE, 7FCA -> 78CA, 7FA4 -> 78A4, 7F88 -> 8F88 -It could be related to an uninitialized variable, like the zmode bug... -[DONE] -It was a bug in the dech38el data--it returned $FF for ungated instead of $00... - -Blit! (CMD = 09800609) -Flags: SRCEN DSTEN UPDA1 UPDA2 LFUFUNC=C DCOMPEN - count = 10 x 12 - a1_base = 00110000, a2_base = 0010B2A8 - a1_x = 004B, a1_y = 00D8, a1_frac_x = 0000, a1_frac_y = 0000, a2_x = 0704, a2_y = 0000 - a1_step_x = FFF3, a1_step_y = 0001, a1_stepf_x = 0000, a1_stepf_y = 0000, a2_step_x = FFFC, a2_step_y = 0000 - a1_inc_x = 0000, a1_inc_y = 0000, a1_incf_x = 0000, a1_incf_y = 0000 - a1_win_x = 0000, a1_win_y = 0000, a2_mask_x = 0000, a2_mask_y = 0000 - a2_mask=F a1add=+phr/+0 a2add=+phr/+0 - a1_pixsize = 4, a2_pixsize = 4 - srcd=0000000000000000 dstd=0000000000000000 patd=0000000000000000 iinc=00000000 - srcz1=0000000000000000 srcz2=0000000000000000 dstz=0000000000000000 zinc=00000000, coll=0 - Phrase mode is ON - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... - Entering SREAD state... Source read address/pix address: 0010C0B0/0 [0000000078047804] - Entering A2_ADD state [a2_x=0704, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DREAD state... - Dest read address/pix address: 00197240/0 [0000000000000028] - Entering DWRITE state... - Dest write address/pix address: 00197240/0 [dstart=30 dend=40 pwidth=8 srcshift=30][daas=0 dabs=0 dam=7 ds=1 daq=F] [0000000000000028] (icount=0009, inc=1) - Entering A1_ADD state [a1_x=004B, a1_y=00D8, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering SREAD state... Source read address/pix address: 0010C0B8/0 [7804780478047804] - Entering A2_ADD state [a2_x=0708, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DREAD state... - Dest read address/pix address: 00197260/0 [0028000000200008] - Entering DWRITE state... - Dest write address/pix address: 00197260/0 [dstart=0 dend=40 pwidth=8 srcshift=30][daas=0 dabs=0 dam=7 ds=1 daq=F] [0028780478047804] (icount=0005, inc=4) - Entering A1_ADD state [a1_x=004C, a1_y=00D8, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering SREAD state... Source read address/pix address: 0010C0C0/0 [0000000000000000] - Entering A2_ADD state [a2_x=070C, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DREAD state... - Dest read address/pix address: 00197280/0 [0008001800180018] - Entering DWRITE state... - Dest write address/pix address: 00197280/0 [dstart=0 dend=40 pwidth=8 srcshift=30][daas=0 dabs=0 dam=7 ds=1 daq=F] [7804780478040018] (icount=0001, inc=4) - Entering A1_ADD state [a1_x=0050, a1_y=00D8, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering SREAD state... Source read address/pix address: 0010C0C8/0 [000078047BFE7BFE] - Entering A2_ADD state [a2_x=0710, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering DREAD state... - Dest read address/pix address: 001972A0/0 [0008002000000000] - Entering DWRITE state... - Dest write address/pix address: 001972A0/0 [dstart=0 dend=10 pwidth=8 srcshift=30][daas=0 dabs=0 dam=7 ds=1 daq=F] [0008002000000000] (icount=FFFD, inc=4) - Entering A1_ADD state [a1_x=0054, a1_y=00D8, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering IDLE_INNER state... -*/ - -//Why isn't this taken care of in DATA? Because, DATA is modifying its local copy instead of the one used here. -//!!! FIX !!! [DONE] -//if (patdadd) -// patd = wdata; - -//if (patfadd) -// srcd1 = wdata; - -/* -DEF ADDRCOMP ( - a1_outside // A1 pointer is outside window bounds - :OUT; -INT16/ a1_x -INT16/ a1_y -INT15/ a1_win_x -INT15/ a1_win_y - :IN); -BEGIN - -// The address is outside if negative, or if greater than or equal -// to the window size - -A1_xcomp := MAG_15 (a1xgr, a1xeq, a1xlt, a1_x{0..14}, a1_win_x{0..14}); -A1_ycomp := MAG_15 (a1ygr, a1yeq, a1ylt, a1_y{0..14}, a1_win_y{0..14}); -A1_outside := OR6 (a1_outside, a1_x{15}, a1xgr, a1xeq, a1_y{15}, a1ygr, a1yeq); -*/ -//NOTE: There seems to be an off-by-one bug here in the clip_a1 section... !!! FIX !!! -// Actually, seems to be related to phrase mode writes... -// Or is it? Could be related to non-15-bit compares as above? -if (clip_a1 && ((a1_x & 0x8000) || (a1_y & 0x8000) || (a1_x >= a1_win_x) || (a1_y >= a1_win_y))) - winhibit = true; - -if (!winhibit) -{ - if (phrase_mode) - { - JaguarWriteLong(address + 0, wdata >> 32, BLITTER); - JaguarWriteLong(address + 4, wdata & 0xFFFFFFFF, BLITTER); - } - else - { - if (pixsize == 5) - JaguarWriteLong(address, wdata & 0xFFFFFFFF, BLITTER); - else if (pixsize == 4) - JaguarWriteWord(address, wdata & 0x0000FFFF, BLITTER); - else - JaguarWriteByte(address, wdata & 0x000000FF, BLITTER); - } -} - -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ - WriteLog(" [%08X%08X]%s", (uint32_t)(wdata >> 32), (uint32_t)(wdata & 0xFFFFFFFF), (winhibit ? "[X]" : "")); - WriteLog(" (icount=%04X, inc=%u)\n", icount, (uint16_t)inc); - WriteLog(" [dstart=%X dend=%X pwidth=%X srcshift=%X]", dstart, dend, pwidth, srcshift); - WriteLog("[daas=%X dabs=%X dam=%X ds=%X daq=%s]\n", daddasel, daddbsel, daddmode, data_sel, (daddq_sel ? "T" : "F")); -} -#endif + if (!winhibit) + { + if (phrase_mode) + { + JaguarWriteLong(address + 0, wdata >> 32, BLITTER); + JaguarWriteLong(address + 4, wdata & 0xFFFFFFFF, BLITTER); + } + else + { + if (pixsize == 5) + JaguarWriteLong(address, wdata & 0xFFFFFFFF, BLITTER); + else if (pixsize == 4) + JaguarWriteWord(address, wdata & 0x0000FFFF, BLITTER); + else + JaguarWriteByte(address, wdata & 0x000000FF, BLITTER); + } + } } if (dzwrite) { -// OK, here's the big insight: When NOT in GOURZ mode, srcz1 & 2 function EXACTLY the same way that -// srcd1 & 2 work--there's an implicit shift from srcz1 to srcz2 whenever srcz1 is read. -// OTHERWISE, srcz1 is the integer for the computed Z and srcz2 is the fractional part. -// Writes to srcz1 & 2 follow the same pattern as the other 64-bit registers--low 32 at the low address, -// high 32 at the high address (little endian!). -// NOTE: GOURZ is still not properly supported. Check patd/patf handling... -// Phrase mode start/end masks are not properly supported either... -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ - WriteLog(" Entering DZWRITE state..."); - WriteLog(" Dest Z write address/pix address: %08X/%1X [%08X%08X]\n", address, - pixAddr, (uint32_t)(srcz >> 32), (uint32_t)(srcz & 0xFFFFFFFF)); -} -#endif -//This is not correct... !!! FIX !!! -//Should be OK now... We'll see... -//Nope. Having the same starstep write problems in phrase mode as we had with pixels... !!! FIX !!! -//This is not causing the problem in Hover Strike... :-/ -//The problem was with the SREADX not shifting. Still problems with Z comparisons & other text in pregame screen... -if (!winhibit) -{ - if (phrase_mode) - { - JaguarWriteLong(address + 0, srcz >> 32, BLITTER); - JaguarWriteLong(address + 4, srcz & 0xFFFFFFFF, BLITTER); - } - else - { - if (pixsize == 4) - JaguarWriteWord(address, srcz & 0x0000FFFF, BLITTER); - } -}//*/ -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -// printf(" [%08X%08X]\n", (uint32_t)(srcz >> 32), (uint32_t)(srcz & 0xFFFFFFFF)); -// fflush(stdout); -//printf(" [dstart=%X dend=%X pwidth=%X srcshift=%X]", dstart, dend, pwidth, srcshift); - WriteLog(" [dstart=? dend=? pwidth=? srcshift=%X]", srcshift); - WriteLog("[daas=%X dabs=%X dam=%X ds=%X daq=%s]\n", daddasel, daddbsel, daddmode, data_sel, (daddq_sel ? "T" : "F")); -// fflush(stdout); -} -#endif + + if (!winhibit) + { + if (phrase_mode) + { + JaguarWriteLong(address + 0, srcz >> 32, BLITTER); + JaguarWriteLong(address + 4, srcz & 0xFFFFFFFF, BLITTER); + } + else + { + if (pixsize == 4) + JaguarWriteWord(address, srcz & 0x0000FFFF, BLITTER); + } + } } -/* -This is because the address generator was using only 15 bits of the X when it should have -used 16! - -There's a slight problem here: The X pointer isn't wrapping like it should when it hits -the edge of the window... Notice how the X isn't reset at the edge of the window: - -Blit! (CMD = 00010000) -Flags: PATDSEL - count = 160 x 261 - a1_base = 000E8008, a2_base = 0001FA68 - a1_x = 0000, a1_y = 0000, a1_frac_x = 0000, a1_frac_y = 0000, a2_x = 0000, a2_y = 0000 - a1_step_x = 0000, a1_step_y = 0000, a1_stepf_x = 0000, a1_stepf_y = 0000, a2_step_x = 0000, a2_step_y = 0000 - a1_inc_x = 0000, a1_inc_y = 0000, a1_incf_x = 0000, a1_incf_y = 0000 - a1_win_x = 0000, a1_win_y = 0000, a2_mask_x = 0000, a2_mask_y = 0000 - a2_mask=F a1add=+phr/+0 a2add=+phr/+0 - a1_pixsize = 5, a2_pixsize = 5 - srcd=7717771777177717 dstd=0000000000000000 patd=7730773077307730 iinc=00000000 - srcz1=0000000000000000 srcz2=0000000000000000 dstz=0000000000000000 zinc=00000000, coll=0 - Phrase mode is ON - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... - Entering DWRITE state... Dest write address/pix address: 000E8008/0 [7730773077307730] (icount=009E, inc=2) - srcz=0000000000000000][dcomp=AA zcomp=00 dbinh=00] -[srcz=0000000000000000 dstz=0000000000000000 zwdata=0000000000000000 mask=7FFF] - [dstart=0 dend=40 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] - Entering A1_ADD state [a1_x=0000, a1_y=0000, addasel=0, addbsel=0, modx=1, addareg=F, adda_xconst=1, adda_yconst=0]... - Entering DWRITE state... Dest write address/pix address: 000E8018/0 [7730773077307730] (icount=009C, inc=2) - srcz=0000000000000000][dcomp=AA zcomp=00 dbinh=00] -[srcz=0000000000000000 dstz=0000000000000000 zwdata=0000000000000000 mask=7FFF] - [dstart=0 dend=40 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] - Entering A1_ADD state [a1_x=0002, a1_y=0000, addasel=0, addbsel=0, modx=1, addareg=F, adda_xconst=1, adda_yconst=0]... - -... - - Entering A1_ADD state [a1_x=009C, a1_y=0000, addasel=0, addbsel=0, modx=1, addareg=F, adda_xconst=1, adda_yconst=0]... - Entering DWRITE state... Dest write address/pix address: 000E84F8/0 [7730773077307730] (icount=0000, inc=2) - srcz=0000000000000000][dcomp=AA zcomp=00 dbinh=00] -[srcz=0000000000000000 dstz=0000000000000000 zwdata=0000000000000000 mask=7FFF] - [dstart=0 dend=40 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] - Entering A1_ADD state [a1_x=009E, a1_y=0000, addasel=0, addbsel=0, modx=1, addareg=F, adda_xconst=1, adda_yconst=0]... - Entering IDLE_INNER state... - - Leaving INNER state... (ocount=0104) - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - - Entering INNER state... - Entering DWRITE state... Dest write address/pix address: 000E8508/0 [7730773077307730] (icount=009E, inc=2) - srcz=0000000000000000][dcomp=AA zcomp=00 dbinh=00] -[srcz=0000000000000000 dstz=0000000000000000 zwdata=0000000000000000 mask=7FFF] - [dstart=0 dend=40 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] - Entering A1_ADD state [a1_x=00A0, a1_y=0000, addasel=0, addbsel=0, modx=1, addareg=F, adda_xconst=1, adda_yconst=0]... - Entering DWRITE state... Dest write address/pix address: 000E8518/0 [7730773077307730] (icount=009C, inc=2) - srcz=0000000000000000][dcomp=AA zcomp=00 dbinh=00] -[srcz=0000000000000000 dstz=0000000000000000 zwdata=0000000000000000 mask=7FFF] - [dstart=0 dend=40 pwidth=8 srcshift=0][daas=0 dabs=0 dam=7 ds=0 daq=F] - Entering A1_ADD state [a1_x=00A2, a1_y=0000, addasel=0, addbsel=0, modx=1, addareg=F, adda_xconst=1, adda_yconst=0]... - -*/ - if (a1_add) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -//printf(" Entering A1_ADD state [addasel=%X, addbsel=%X, modx=%X, addareg=%s, adda_xconst=%u, adda_yconst=%s]...\n", addasel, addbsel, modx, (addareg ? "T" : "F"), adda_xconst, (adda_yconst ? "1" : "0")); -WriteLog(" Entering A1_ADD state [a1_x=%04X, a1_y=%04X, addasel=%X, addbsel=%X, modx=%X, addareg=%s, adda_xconst=%u, adda_yconst=%s]...\n", a1_x, a1_y, addasel, addbsel, modx, (addareg ? "T" : "F"), adda_xconst, (adda_yconst ? "1" : "0")); -//fflush(stdout); -} -#endif -int16_t adda_x, adda_y, addb_x, addb_y, data_x, data_y, addq_x, addq_y; -ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y, - a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y); -ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y); -ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y); + int16_t adda_x, adda_y, addb_x, addb_y, data_x, data_y, addq_x, addq_y; + ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y, + a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y); + ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y); + ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y); -#if 0//def VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" [adda_x=%d, adda_y=%d, addb_x=%d, addb_y=%d, addq_x=%d, addq_y=%d]\n", adda_x, adda_y, addb_x, addb_y, addq_x, addq_y); -//fflush(stdout); -} -#endif -//Now, write to what??? -//a2ptrld comes from a2ptrldi... -//I believe it's addbsel that determines the writeback... -// This is where atick[0] & [1] come in, in determining which part (fractional, integer) -// gets written to... -//a1_x = addq_x; -//a1_y = addq_y; -//Kludge, to get A1 channel increment working... -if (a1addx == 3) -{ - a1_frac_x = addq_x, a1_frac_y = addq_y; + if (a1addx == 3) + { + a1_frac_x = addq_x, a1_frac_y = addq_y; -addasel = 2, addbsel = 0, a1fracldi = false; -ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y, - a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y); -ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y); -ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y); + addasel = 2, addbsel = 0, a1fracldi = false; + ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y, + a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y); + ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y); + ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y); - a1_x = addq_x, a1_y = addq_y; -} -else - a1_x = addq_x, a1_y = addq_y; + a1_x = addq_x, a1_y = addq_y; + } + else + a1_x = addq_x, a1_y = addq_y; } if (a2_add) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -//printf(" Entering A2_ADD state [addasel=%X, addbsel=%X, modx=%X, addareg=%s, adda_xconst=%u, adda_yconst=%s]...\n", addasel, addbsel, modx, (addareg ? "T" : "F"), adda_xconst, (adda_yconst ? "1" : "0")); -WriteLog(" Entering A2_ADD state [a2_x=%04X, a2_y=%04X, addasel=%X, addbsel=%X, modx=%X, addareg=%s, adda_xconst=%u, adda_yconst=%s]...\n", a2_x, a2_y, addasel, addbsel, modx, (addareg ? "T" : "F"), adda_xconst, (adda_yconst ? "1" : "0")); -//fflush(stdout); -} -#endif -//void ADDAMUX(int16_t &adda_x, int16_t &adda_y, uint8_t addasel, int16_t a1_step_x, int16_t a1_step_y, -// int16_t a1_stepf_x, int16_t a1_stepf_y, int16_t a2_step_x, int16_t a2_step_y, -// int16_t a1_inc_x, int16_t a1_inc_y, int16_t a1_incf_x, int16_t a1_incf_y, uint8_t adda_xconst, -// bool adda_yconst, bool addareg, bool suba_x, bool suba_y) -//void ADDBMUX(int16_t &addb_x, int16_t &addb_y, uint8_t addbsel, int16_t a1_x, int16_t a1_y, -// int16_t a2_x, int16_t a2_y, int16_t a1_frac_x, int16_t a1_frac_y) -//void ADDRADD(int16_t &addq_x, int16_t &addq_y, bool a1fracldi, -// int16_t adda_x, int16_t adda_y, int16_t addb_x, int16_t addb_y, uint8_t modx, bool suba_x, bool suba_y) -//void DATAMUX(int16_t &data_x, int16_t &data_y, uint32_t gpu_din, int16_t addq_x, int16_t addq_y, bool addqsel) -int16_t adda_x, adda_y, addb_x, addb_y, data_x, data_y, addq_x, addq_y; -ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y, - a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y); -ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y); -ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y); + int16_t adda_x, adda_y, addb_x, addb_y, data_x, data_y, addq_x, addq_y; + ADDAMUX(adda_x, adda_y, addasel, a1_step_x, a1_step_y, a1_stepf_x, a1_stepf_y, a2_step_x, a2_step_y, + a1_inc_x, a1_inc_y, a1_incf_x, a1_incf_y, adda_xconst, adda_yconst, addareg, suba_x, suba_y); + ADDBMUX(addb_x, addb_y, addbsel, a1_x, a1_y, a2_x, a2_y, a1_frac_x, a1_frac_y); + ADDRADD(addq_x, addq_y, a1fracldi, adda_x, adda_y, addb_x, addb_y, modx, suba_x, suba_y); -#if 0//def VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" [adda_x=%d, adda_y=%d, addb_x=%d, addb_y=%d, addq_x=%d, addq_y=%d]\n", adda_x, adda_y, addb_x, addb_y, addq_x, addq_y); -//fflush(stdout); -} -#endif -//Now, write to what??? -//a2ptrld comes from a2ptrldi... -//I believe it's addbsel that determines the writeback... -a2_x = addq_x; -a2_y = addq_y; + a2_x = addq_x; + a2_y = addq_y; } } -/* -Flags: SRCEN CLIP_A1 UPDA1 UPDA1F UPDA2 DSTA2 GOURZ ZMODE=0 LFUFUNC=C SRCSHADE - count = 64 x 55 - a1_base = 0015B000, a2_base = 0014B000 - a1_x = 0000, a1_y = 0000, a1_frac_x = 8000, a1_frac_y = 8000, a2_x = 001F, a2_y = 0038 - a1_step_x = FFFFFFC0, a1_step_y = 0001, a1_stepf_x = 0000, a1_stepf_y = 2AAA, a2_step_x = FFFFFFC0, a2_step_y = 0001 - a1_inc_x = 0001, a1_inc_y = 0000, a1_incf_x = 0000, a1_incf_y = 0000 - a1_win_x = 0040, a1_win_y = 0040, a2_mask_x = 0000, a2_mask_y = 0000 - a2_mask=F a1add=+inc/+0 a2add=+1/+0 - a1_pixsize = 4, a2_pixsize = 4 - srcd=FF00FF00FF00FF00 dstd=0000000000000000 patd=0000000000000000 iinc=00000000 - srcz1=0000000000000000 srcz2=0000000000000000 dstz=0000000000000000 zinc=00000000, col=0 - Phrase mode is off - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... - Entering SREAD state... Source read address/pix address: 0015B000/0 [6505650565056505] - Entering A1_ADD state [a1_x=0000, a1_y=0000, addasel=3, addbsel=2, modx=0, addareg=T, adda_xconst=7, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 0014E83E/0 [dstart=0 dend=10 pwidth=8 srcshift=0][daas=4 dabs=5 dam=7 ds=1 daq=F] [0000000000006505] (icount=003F, inc=1) - Entering A2_ADD state [a2_x=001F, a2_y=0038, addasel=0, addbsel=1, modx=0, addareg=F, adda_xconst=0, adda_yconst=0]... - Entering SREAD state... Source read address/pix address: 0015B000/0 [6505650565056505] - Entering A1_ADD state [a1_x=FFFF8000, a1_y=FFFF8000, addasel=3, addbsel=2, modx=0, addareg=T, adda_xconst=7, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 0014E942/0 [dstart=0 dend=10 pwidth=8 srcshift=0][daas=4 dabs=5 dam=7 ds=1 daq=F] [0000000000006505] (icount=003E, inc=1) - Entering A2_ADD state [a2_x=0021, a2_y=0039, addasel=0, addbsel=1, modx=0, addareg=F, adda_xconst=0, adda_yconst=0]... - Entering SREAD state... Source read address/pix address: 0015B000/0 [6505650565056505] - Entering A1_ADD state [a1_x=FFFF8000, a1_y=FFFF8000, addasel=3, addbsel=2, modx=0, addareg=T, adda_xconst=7, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 0014EA46/0 [dstart=0 dend=10 pwidth=8 srcshift=0][daas=4 dabs=5 dam=7 ds=1 daq=F] [0000000000006505] (icount=003D, inc=1) - Entering A2_ADD state [a2_x=0023, a2_y=003A, addasel=0, addbsel=1, modx=0, addareg=F, adda_xconst=0, adda_yconst=0]... - Entering SREAD state... Source read address/pix address: 0015B000/0 [6505650565056505] - Entering A1_ADD state [a1_x=FFFF8000, a1_y=FFFF8000, addasel=3, addbsel=2, modx=0, addareg=T, adda_xconst=7, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 0014EB4A/0 [dstart=0 dend=10 pwidth=8 srcshift=0][daas=4 dabs=5 dam=7 ds=1 daq=F] [0000000000006505] (icount=003C, inc=1) - Entering A2_ADD state [a2_x=0025, a2_y=003B, addasel=0, addbsel=1, modx=0, addareg=F, adda_xconst=0, adda_yconst=0]... - ... - Entering SREAD state... Source read address/pix address: 0015B000/0 [6505650565056505] - Entering A1_ADD state [a1_x=FFFF8000, a1_y=FFFF8000, addasel=3, addbsel=2, modx=0, addareg=T, adda_xconst=7, adda_yconst=0]... - Entering DWRITE state... - Dest write address/pix address: 0015283A/0 [dstart=0 dend=10 pwidth=8 srcshift=0][daas=4 dabs=5 dam=7 ds=1 daq=F] [0000000000006505] (icount=0000, inc=1) - Entering A2_ADD state [a2_x=009D, a2_y=0077, addasel=0, addbsel=1, modx=0, addareg=F, adda_xconst=0, adda_yconst=0]... - Entering IDLE_INNER state... - Leaving INNER state... (ocount=0036) - [in=F a1f=T a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering A1FUPDATE state... - [in=F a1f=F a1=T zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering A1UPDATE state... (-32768/-32768 -> 32704/-32767) - [in=F a1f=F a1=F zf=F z=F a2=T iif=F iii=F izf=F izi=F] - Entering A2UPDATE state... (159/120 -> 95/121) - [in=T a1f=F a1=F zf=F z=F a2=F iif=F iii=F izf=F izi=F] - Entering INNER state... -*/ -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" Leaving INNER state..."); -//fflush(stdout); -} -#endif indone = true; -// The outer counter is updated here as well on the clock cycle... - -/* the inner loop is started whenever another state is about to -cause the inner state to go active */ -//Instart := ND7 (instart, innert[0], innert[2..7]); - -//Actually, it's done only when inner gets asserted without the 2nd line of conditions -//(inner AND !indone) -//fixed now... -//Since we don't get here until the inner loop is finished (indone = true) we can get -//away with doing it here...! ocount--; if (ocount == 0) outer0 = true; -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" (ocount=%04X)\n", ocount); -//fflush(stdout); -} -#endif } if (a1fupdate) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" Entering A1FUPDATE state...\n"); -//fflush(stdout); -} -#endif uint32_t a1_frac_xt = (uint32_t)a1_frac_x + (uint32_t)a1_stepf_x; uint32_t a1_frac_yt = (uint32_t)a1_frac_y + (uint32_t)a1_stepf_y; a1FracCInX = a1_frac_xt >> 16; @@ -4603,167 +1718,35 @@ WriteLog(" Entering A1FUPDATE state...\n"); if (a1update) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" Entering A1UPDATE state... (%d/%d -> ", a1_x, a1_y); -//fflush(stdout); -} -#endif a1_x += a1_step_x + a1FracCInX; a1_y += a1_step_y + a1FracCInY; -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog("%d/%d)\n", a1_x, a1_y); -//fflush(stdout); -} -#endif } if (a2update) { -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" Entering A2UPDATE state... (%d/%d -> ", a2_x, a2_y); -//fflush(stdout); -} -#endif a2_x += a2_step_x; a2_y += a2_step_y; -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog("%d/%d)\n", a2_x, a2_y); -//fflush(stdout); -} -#endif } } -// We never get here! !!! FIX !!! - -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ - WriteLog("Done!\na1_x=%04X a1_y=%04X a1_frac_x=%04X a1_frac_y=%04X a2_x=%04X a2_y%04X\n", - GET16(blitter_ram, A1_PIXEL + 2), - GET16(blitter_ram, A1_PIXEL + 0), - GET16(blitter_ram, A1_FPIXEL + 2), - GET16(blitter_ram, A1_FPIXEL + 0), - GET16(blitter_ram, A2_PIXEL + 2), - GET16(blitter_ram, A2_PIXEL + 0)); -// fflush(stdout); -} -#endif - - // Write values back to registers (in real blitter, these are continuously updated) SET16(blitter_ram, A1_PIXEL + 2, a1_x); SET16(blitter_ram, A1_PIXEL + 0, a1_y); SET16(blitter_ram, A1_FPIXEL + 2, a1_frac_x); SET16(blitter_ram, A1_FPIXEL + 0, a1_frac_y); SET16(blitter_ram, A2_PIXEL + 2, a2_x); SET16(blitter_ram, A2_PIXEL + 0, a2_y); - -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) -{ - WriteLog("Writeback!\na1_x=%04X a1_y=%04X a1_frac_x=%04X a1_frac_y=%04X a2_x=%04X a2_y%04X\n", - GET16(blitter_ram, A1_PIXEL + 2), - GET16(blitter_ram, A1_PIXEL + 0), - GET16(blitter_ram, A1_FPIXEL + 2), - GET16(blitter_ram, A1_FPIXEL + 0), - GET16(blitter_ram, A2_PIXEL + 2), - GET16(blitter_ram, A2_PIXEL + 0)); -// fflush(stdout); } -#endif -} - - -/* - int16_t a1_x = (int16_t)GET16(blitter_ram, A1_PIXEL + 2); - int16_t a1_y = (int16_t)GET16(blitter_ram, A1_PIXEL + 0); - uint16_t a1_frac_x = GET16(blitter_ram, A1_FPIXEL + 2); - uint16_t a1_frac_y = GET16(blitter_ram, A1_FPIXEL + 0); - int16_t a2_x = (int16_t)GET16(blitter_ram, A2_PIXEL + 2); - int16_t a2_y = (int16_t)GET16(blitter_ram, A2_PIXEL + 0); - -Seems that the ending a1_x should be written between blits, but it doesn't seem to be... - -Blit! (CMD = 01800000) -Flags: LFUFUNC=C - count = 28672 x 1 - a1_base = 00050000, a2_base = 00070000 - a1_x = 0000, a1_y = 0000, a1_frac_x = 49CD, a1_frac_y = 0000, a2_x = 0033, a2_y = 0001 - a1_step_x = 0000, a1_step_y = 0000, a1_stepf_x = 939A, a1_stepf_y = 0000, a2_step_x = 0000, a2_step_y = 0000 - a1_inc_x = 0000, a1_inc_y = 0000, a1_incf_x = 0000, a1_incf_y = 0000 - a1_win_x = 0100, a1_win_y = 0020, a2_mask_x = 0000, a2_mask_y = 0000 - a2_mask=F a1add=+phr/+0 a2add=+phr/+0 - a1_pixsize = 4, a2_pixsize = 3 - srcd=DEDEDEDEDEDEDEDE dstd=0000000000000000 patd=0000000000000000 iinc=00000000 - srcz1=0000000000000000 srcz2=0000000000000000 dstz=0000000000000000 zinc=00000000, coll=0 - Phrase mode is ON - -Blit! (CMD = 01800000) -Flags: LFUFUNC=C - count = 28672 x 1 - a1_base = 00050000, a2_base = 00070000 - a1_x = 0000, a1_y = 0000, a1_frac_x = 49CD, a1_frac_y = 0000, a2_x = 0033, a2_y = 0001 - a1_step_x = 0000, a1_step_y = 0000, a1_stepf_x = 939A, a1_stepf_y = 0000, a2_step_x = 0000, a2_step_y = 0000 - a1_inc_x = 0000, a1_inc_y = 0000, a1_incf_x = 0000, a1_incf_y = 0000 - a1_win_x = 0100, a1_win_y = 0020, a2_mask_x = 0000, a2_mask_y = 0000 - a2_mask=F a1add=+phr/+0 a2add=+phr/+0 - a1_pixsize = 4, a2_pixsize = 3 - srcd=D6D6D6D6D6D6D6D6 dstd=0000000000000000 patd=0000000000000000 iinc=00000000 - srcz1=0000000000000000 srcz2=0000000000000000 dstz=0000000000000000 zinc=00000000, coll=0 - Phrase mode is ON -*/ - - - -// Various pieces of the blitter puzzle are teased out here... - - - -/* -DEF ADDRGEN ( -INT24/ address // byte address - pixa[0..2] // bit part of address, un-pipe-lined - :OUT; -INT16/ a1_x -INT16/ a1_y -INT21/ a1_base - a1_pitch[0..1] - a1_pixsize[0..2] - a1_width[0..5] - a1_zoffset[0..1] -INT16/ a2_x -INT16/ a2_y -INT21/ a2_base - a2_pitch[0..1] - a2_pixsize[0..2] - a2_width[0..5] - a2_zoffset[0..1] - apipe // load address pipe-line latch - clk // co-processor clock - gena2 // generate A2 as opposed to A1 - zaddr // generate Z address - :IN); -*/ void ADDRGEN(uint32_t &address, uint32_t &pixa, bool gena2, bool zaddr, uint16_t a1_x, uint16_t a1_y, uint32_t a1_base, uint8_t a1_pitch, uint8_t a1_pixsize, uint8_t a1_width, uint8_t a1_zoffset, uint16_t a2_x, uint16_t a2_y, uint32_t a2_base, uint8_t a2_pitch, uint8_t a2_pixsize, uint8_t a2_width, uint8_t a2_zoffset) { -// uint16_t x = (gena2 ? a2_x : a1_x) & 0x7FFF; - uint16_t x = (gena2 ? a2_x : a1_x) & 0xFFFF; // Actually uses all 16 bits to generate address...! + uint16_t x = (gena2 ? a2_x : a1_x) & 0xFFFF; uint16_t y = (gena2 ? a2_y : a1_y) & 0x0FFF; uint8_t width = (gena2 ? a2_width : a1_width); uint8_t pixsize = (gena2 ? a2_pixsize : a1_pixsize); uint8_t pitch = (gena2 ? a2_pitch : a1_pitch); - uint32_t base = (gena2 ? a2_base : a1_base) >> 3;//Only upper 21 bits are passed around the bus? Seems like it... + uint32_t base = (gena2 ? a2_base : a1_base) >> 3; uint8_t zoffset = (gena2 ? a2_zoffset : a1_zoffset); uint32_t ytm = ((uint32_t)y << 2) + (width & 0x02 ? (uint32_t)y << 1 : 0) + (width & 0x01 ? (uint32_t)y : 0); @@ -4772,211 +1755,20 @@ void ADDRGEN(uint32_t &address, uint32_t &pixa, bool gena2, bool zaddr, uint32_t pa = ya + x; - /*uint32*/ pixa = pa << pixsize; + pixa = pa << pixsize; uint8_t pt = ((pitch & 0x01) && !(pitch & 0x02) ? 0x01 : 0x00) | (!(pitch & 0x01) && (pitch & 0x02) ? 0x02 : 0x00); -// uint32_t phradr = pixa << pt; uint32_t phradr = (pixa >> 6) << pt; uint32_t shup = (pitch == 0x03 ? (pixa >> 6) : 0); uint8_t za = (zaddr ? zoffset : 0) & 0x03; -// uint32_t addr = za + (phradr & 0x07) + (shup << 1) + base; uint32_t addr = za + phradr + (shup << 1) + base; - /*uint32*/ address = ((pixa & 0x38) >> 3) | ((addr & 0x1FFFFF) << 3); -#if 0//def VERBOSE_BLITTER_LOGGING -if (logBlit) -{ -WriteLog(" [gena2=%s, x=%04X, y=%04X, w=%1X, pxsz=%1X, ptch=%1X, b=%08X, zoff=%1X]\n", (gena2 ? "T" : "F"), x, y, width, pixsize, pitch, base, zoffset); -WriteLog(" [ytm=%X, ya=%X, pa=%X, pixa=%X, pt=%X, phradr=%X, shup=%X, za=%X, addr=%X, address=%X]\n", ytm, ya, pa, pixa, pt, phradr, shup, za, addr, address); -//fflush(stdout); -} -#endif + address = ((pixa & 0x38) >> 3) | ((addr & 0x1FFFFF) << 3); + pixa &= 0x07; -/* - Entering INNER state... - [gena2=T, x=0002, y=0000, w=20, pxsz=4, ptch=0, b=000012BA, zoff=0] - [ytm=0, ya=0, pa=2, pixa=20, pt=0, phradr=0, shup=0, za=0, addr=12BA, address=95D4] - Entering SREADX state... [dstart=0 dend=20 pwidth=8 srcshift=20] - Source extra read address/pix address: 000095D4/0 [0000001C00540038] - Entering A2_ADD state [a2_x=0002, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - [gena2=T, x=0004, y=0000, w=20, pxsz=4, ptch=0, b=000012BA, zoff=0] - [ytm=0, ya=0, pa=4, pixa=40, pt=0, phradr=1, shup=0, za=0, addr=12BB, address=95D8] - Entering SREAD state... [dstart=0 dend=20 pwidth=8 srcshift=0] - Source read address/pix address: 000095D8/0 [0054003800009814] - Entering A2_ADD state [a2_x=0004, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - [gena2=F, x=0000, y=0000, w=20, pxsz=4, ptch=0, b=00006E52, zoff=0] - [ytm=0, ya=0, pa=0, pixa=0, pt=0, phradr=0, shup=0, za=0, addr=6E52, address=37290] - Entering DWRITE state... - Dest write address/pix address: 00037290/0 [dstart=0 dend=20 pwidth=8 srcshift=0] (icount=026E, inc=4) - Entering A1_ADD state [a1_x=0000, a1_y=0000, addasel=0, addbsel=0, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - [gena2=T, x=0008, y=0000, w=20, pxsz=4, ptch=0, b=000012BA, zoff=0] - [ytm=0, ya=0, pa=8, pixa=80, pt=0, phradr=2, shup=0, za=0, addr=12BC, address=95E0] -*/ -/* -Obviously wrong: - Entering SREAD state... - [gena2=T, x=0004, y=0000, w=20, pxsz=4, ptch=0, b=000010AC, zoff=0] - [ytm=0, ya=0, pa=4, pixa=0, pt=0, phradr=40, shup=0, za=0, addr=10AC, address=8560] - Source read address/pix address: 00008560/0 [8C27981B327E00F0] - -2nd pass (still wrong): - Entering SREAD state... - [gena2=T, x=0004, y=0000, w=20, pxsz=4, ptch=0, b=000010AC, zoff=0] - [ytm=0, ya=0, pa=4, pixa=0, pt=0, phradr=40, shup=0, za=0, addr=10EC, address=8760] - Source read address/pix address: 00008760/0 [00E06DC04581880C] - -Correct!: - Entering SREAD state... - [gena2=T, x=0004, y=0000, w=20, pxsz=4, ptch=0, b=000010AC, zoff=0] - [ytm=0, ya=0, pa=4, pixa=0, pt=0, phradr=1, shup=0, za=0, addr=10AD, address=8568] - Source read address/pix address: 00008568/0 [6267981A327C00F0] - -OK, now we're back into incorrect (or is it?): - Entering SREADX state... [dstart=0 dend=20 pwidth=8 srcshift=20] - Source extra read address/pix address: 000095D4/0 [0000 001C 0054 0038] - Entering A2_ADD state [a2_x=0002, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... - Entering SREAD state... [dstart=0 dend=20 pwidth=8 srcshift=0] - Source read address/pix address: 000095D8/0 [0054 0038 0000 9814] - Entering A2_ADD state [a2_x=0004, a2_y=0000, addasel=0, addbsel=1, modx=2, addareg=F, adda_xconst=2, adda_yconst=0]... -I think this may be correct...! -*/ } -/* -// source and destination address update conditions - -Sraat0 := AN2 (sraat[0], sreadxi, srcenz\); -Sraat1 := AN2 (sraat[1], sreadi, srcenz\); -Srca_addi := OR4 (srca_addi, szreadxi, szreadi, sraat[0..1]); -Srca_add := FD1Q (srca_add, srca_addi, clk); - -Dstaat := AN2 (dstaat, dwritei, dstwrz\); -Dsta_addi := OR2 (dsta_addi, dzwritei, dstaat); -// Dsta_add := FD1Q (dsta_add, dsta_addi, clk); - -// source and destination address generate conditions - -Gensrc := OR4 (gensrc, sreadxi, szreadxi, sreadi, szreadi); -Gendst := OR4 (gendst, dreadi, dzreadi, dwritei, dzwritei); -Dsta2\ := INV1 (dsta2\, dsta2); -Gena2t0 := NAN2 (gena2t[0], gensrc, dsta2\); -Gena2t1 := NAN2 (gena2t[1], gendst, dsta2); -Gena2i := NAN2 (gena2i, gena2t[0..1]); -Gena2 := FD1QU (gena2, gena2i, clk); - -Zaddr := OR4 (zaddr, szreadx, szread, dzread, dzwrite); -*/ - -/*void foo(void) -{ - // Basically, the above translates to: - bool srca_addi = (sreadxi && !srcenz) || (sreadi && !srcenz) || szreadxi || szreadi; - - bool dsta_addi = (dwritei && !dstwrz) || dzwritei; - - bool gensrc = sreadxi || szreadxi || sreadi || szreadi; - bool gendst = dreadi || szreadi || dwritei || dzwritei; - bool gena2i = (gensrc && !dsta2) || (gendst && dsta2); - - bool zaddr = szreadx || szread || dzread || dzwrite; -}*/ - -/* -// source data reads - -Srcdpset\ := NAN2 (srcdpset\, readreq, sread); -Srcdpt1 := NAN2 (srcdpt[1], srcdpend, srcdack\); -Srcdpt2 := NAN2 (srcdpt[2], srcdpset\, srcdpt[1]); -Srcdpend := FD2Q (srcdpend, srcdpt[2], clk, reset\); - -Srcdxpset\ := NAN2 (srcdxpset\, readreq, sreadx); -Srcdxpt1 := NAN2 (srcdxpt[1], srcdxpend, srcdxack\); -Srcdxpt2 := NAN2 (srcdxpt[2], srcdxpset\, srcdxpt[1]); -Srcdxpend := FD2Q (srcdxpend, srcdxpt[2], clk, reset\); - -Sdpend := OR2 (sdpend, srcdxpend, srcdpend); -Srcdreadt := AN2 (srcdreadt, sdpend, read_ack); - -//2/9/92 - enhancement? -//Load srcdread on the next tick as well to modify it in srcshade - -Srcdreadd := FD1Q (srcdreadd, srcdreadt, clk); -Srcdread := AOR1 (srcdread, srcshade, srcdreadd, srcdreadt); - -// source zed reads - -Srczpset\ := NAN2 (srczpset\, readreq, szread); -Srczpt1 := NAN2 (srczpt[1], srczpend, srczack\); -Srczpt2 := NAN2 (srczpt[2], srczpset\, srczpt[1]); -Srczpend := FD2Q (srczpend, srczpt[2], clk, reset\); - -Srczxpset\ := NAN2 (srczxpset\, readreq, szreadx); -Srczxpt1 := NAN2 (srczxpt[1], srczxpend, srczxack\); -Srczxpt2 := NAN2 (srczxpt[2], srczxpset\, srczxpt[1]); -Srczxpend := FD2Q (srczxpend, srczxpt[2], clk, reset\); - -Szpend := OR2 (szpend, srczpend, srczxpend); -Srczread := AN2 (srczread, szpend, read_ack); - -// destination data reads - -Dstdpset\ := NAN2 (dstdpset\, readreq, dread); -Dstdpt0 := NAN2 (dstdpt[0], dstdpend, dstdack\); -Dstdpt1 := NAN2 (dstdpt[1], dstdpset\, dstdpt[0]); -Dstdpend := FD2Q (dstdpend, dstdpt[1], clk, reset\); -Dstdread := AN2 (dstdread, dstdpend, read_ack); - -// destination zed reads - -Dstzpset\ := NAN2 (dstzpset\, readreq, dzread); -Dstzpt0 := NAN2 (dstzpt[0], dstzpend, dstzack\); -Dstzpt1 := NAN2 (dstzpt[1], dstzpset\, dstzpt[0]); -Dstzpend := FD2Q (dstzpend, dstzpt[1], clk, reset\); -Dstzread := AN2 (dstzread, dstzpend, read_ack); -*/ - -/*void foo2(void) -{ - // Basically, the above translates to: - bool srcdpend = (readreq && sread) || (srcdpend && !srcdack); - bool srcdxpend = (readreq && sreadx) || (srcdxpend && !srcdxack); - bool sdpend = srcxpend || srcdpend; - bool srcdread = ((sdpend && read_ack) && srcshade) || (sdpend && read_ack);//the latter term is lookahead - -}*/ - - -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// -// Here's an important bit: The source data adder logic. Need to track down the inputs!!! // -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// - -/* -DEF ADDARRAY ( -INT16/ addq[0..3] - :OUT; - clk - daddasel[0..2] // data adder input A selection - daddbsel[0..3] - daddmode[0..2] -INT32/ dstd[0..1] -INT32/ iinc - initcin[0..3] // carry into the adders from the initializers - initinc[0..63] // the initialisation increment - initpix[0..15] // Data initialiser pixel value -INT32/ istep -INT32/ patd[0..1] -INT32/ srcdlo -INT32/ srcdhi -INT32/ srcz1[0..1] -INT32/ srcz2[0..1] - reset\ -INT32/ zinc -INT32/ zstep - :IN); -*/ void ADDARRAY(uint16_t * addq, uint8_t daddasel, uint8_t daddbsel, uint8_t daddmode, uint64_t dstd, uint32_t iinc, uint8_t initcin[], uint64_t initinc, uint16_t initpix, uint32_t istep, uint64_t patd, uint64_t srcd, uint64_t srcz1, uint64_t srcz2, @@ -5037,7 +1829,7 @@ void ADDARRAY(uint16_t * addq, uint8_t daddasel, uint8_t daddbsel, uint8_t daddm uint8_t cinsel = (daddmode >= 1 && daddmode <= 4 ? 1 : 0); -static uint8_t co[4];//These are preserved between calls... + static uint8_t co[4]; uint8_t cin[4]; for(int i=0; i<4; i++) @@ -5047,32 +1839,12 @@ static uint8_t co[4];//These are preserved between calls... bool sat = daddmode & 0x03; bool hicinh = ((daddmode & 0x03) == 0x03); -//Note that the carry out is saved between calls to this function... for(int i=0; i<4; i++) ADD16SAT(addq[i], co[i], adda[i], addb[i], cin[i], sat, eightbit, hicinh); } - -/* -DEF ADD16SAT ( -INT16/ r // result - co // carry out - :IO; -INT16/ a -INT16/ b - cin - sat - eightbit - hicinh - :IN); -*/ void ADD16SAT(uint16_t &r, uint8_t &co, uint16_t a, uint16_t b, uint8_t cin, bool sat, bool eightbit, bool hicinh) { -/*if (logBlit) -{ - printf("--> [sat=%s 8b=%s hicinh=%s] %04X + %04X (+ %u) = ", (sat ? "T" : "F"), (eightbit ? "T" : "F"), (hicinh ? "T" : "F"), a, b, cin); - fflush(stdout); -}*/ uint8_t carry[4]; uint32_t qt = (a & 0xFF) + (b & 0xFF) + cin; carry[0] = (qt & 0x0100 ? 1 : 0); @@ -5091,22 +1863,11 @@ void ADD16SAT(uint16_t &r, uint8_t &co, uint16_t a, uint16_t b, uint8_t cin, boo bool saturate = sat && (btop ^ ctop); bool hisaturate = saturate && !eightbit; -/*if (logBlit) -{ - printf("bt=%u ct=%u s=%u hs=%u] ", btop, ctop, saturate, hisaturate); - fflush(stdout); -}*/ r = (saturate ? (ctop ? 0x00FF : 0x0000) : q & 0x00FF); r |= (hisaturate ? (ctop ? 0xFF00 : 0x0000) : q & 0xFF00); -/*if (logBlit) -{ - printf("%04X (co=%u)\n", r, co); - fflush(stdout); -}*/ } - /** ADDAMUX - Address adder input A selection ******************* This module generates the data loaded into the address adder input A. This is @@ -5133,99 +1894,27 @@ suba_x, suba_y complement the X and Y values */ -/* -DEF ADDAMUX ( -INT16/ adda_x -INT16/ adda_y - :OUT; - addasel[0..2] -INT16/ a1_step_x -INT16/ a1_step_y -INT16/ a1_stepf_x -INT16/ a1_stepf_y -INT16/ a2_step_x -INT16/ a2_step_y -INT16/ a1_inc_x -INT16/ a1_inc_y -INT16/ a1_incf_x -INT16/ a1_incf_y - adda_xconst[0..2] - adda_yconst - addareg - suba_x - suba_y :IN); -*/ void ADDAMUX(int16_t &adda_x, int16_t &adda_y, uint8_t addasel, int16_t a1_step_x, int16_t a1_step_y, int16_t a1_stepf_x, int16_t a1_stepf_y, int16_t a2_step_x, int16_t a2_step_y, int16_t a1_inc_x, int16_t a1_inc_y, int16_t a1_incf_x, int16_t a1_incf_y, uint8_t adda_xconst, bool adda_yconst, bool addareg, bool suba_x, bool suba_y) { - -/*INT16/ addac_x, addac_y, addar_x, addar_y, addart_x, addart_y, -INT16/ addas_x, addas_y, suba_x16, suba_y16 -:LOCAL; -BEGIN - -Zero := TIE0 (zero);*/ - -/* Multiplex the register terms */ - -/*Addaselb[0-2] := BUF8 (addaselb[0-2], addasel[0-2]); -Addart_x := MX4 (addart_x, a1_step_x, a1_stepf_x, a1_inc_x, a1_incf_x, addaselb[0..1]); -Addar_x := MX2 (addar_x, addart_x, a2_step_x, addaselb[2]); -Addart_y := MX4 (addart_y, a1_step_y, a1_stepf_y, a1_inc_y, a1_incf_y, addaselb[0..1]); -Addar_y := MX2 (addar_y, addart_y, a2_step_y, addaselb[2]);*/ - -////////////////////////////////////// C++ CODE ////////////////////////////////////// int16_t xterm[4], yterm[4]; xterm[0] = a1_step_x, xterm[1] = a1_stepf_x, xterm[2] = a1_inc_x, xterm[3] = a1_incf_x; yterm[0] = a1_step_y, yterm[1] = a1_stepf_y, yterm[2] = a1_inc_y, yterm[3] = a1_incf_y; int16_t addar_x = (addasel & 0x04 ? a2_step_x : xterm[addasel & 0x03]); int16_t addar_y = (addasel & 0x04 ? a2_step_y : yterm[addasel & 0x03]); -////////////////////////////////////////////////////////////////////////////////////// -/* Generate a constant value - this is a power of 2 in the range -0-64, or zero. The control bits are adda_xconst[0..2], when they -are all 1 the result is 0. -Constants for Y can only be 0 or 1 */ - -/*Addac_xlo := D38H (addac_x[0..6], unused[0], adda_xconst[0..2]); -Unused[0] := DUMMY (unused[0]); - -Addac_x := JOIN (addac_x, addac_x[0..6], zero, zero, zero, zero, zero, zero, zero, zero, zero); -Addac_y := JOIN (addac_y, adda_yconst, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, - zero, zero, zero, zero, zero);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// int16_t addac_x = (adda_xconst == 0x07 ? 0 : 1 << adda_xconst); int16_t addac_y = (adda_yconst ? 0x01 : 0); -////////////////////////////////////////////////////////////////////////////////////// -/* Select between constant value and register value */ - -/*Addas_x := MX2 (addas_x, addac_x, addar_x, addareg); -Addas_y := MX2 (addas_y, addac_y, addar_y, addareg);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// int16_t addas_x = (addareg ? addar_x : addac_x); int16_t addas_y = (addareg ? addar_y : addac_y); -////////////////////////////////////////////////////////////////////////////////////// -/* Complement these values (complement flag gives adder carry in)*/ - -/*Suba_x16 := JOIN (suba_x16, suba_x, suba_x, suba_x, suba_x, suba_x, suba_x, suba_x, suba_x, suba_x, - suba_x, suba_x, suba_x, suba_x, suba_x, suba_x, suba_x); -Suba_y16 := JOIN (suba_y16, suba_y, suba_y, suba_y, suba_y, suba_y, suba_y, suba_y, suba_y, suba_y, - suba_y, suba_y, suba_y, suba_y, suba_y, suba_y, suba_y); -Adda_x := EO (adda_x, suba_x16, addas_x); -Adda_y := EO (adda_y, suba_y16, addas_y);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// adda_x = addas_x ^ (suba_x ? 0xFFFF : 0x0000); adda_y = addas_y ^ (suba_y ? 0xFFFF : 0x0000); -////////////////////////////////////////////////////////////////////////////////////// - -//END; } - /** ADDBMUX - Address adder input B selection ******************* This module selects the register to be updated by the address @@ -5234,77 +1923,27 @@ pointers, or the A1 fractional part. It can also be zero, so that the step registers load directly into the pointers. */ -/*DEF ADDBMUX ( -INT16/ addb_x -INT16/ addb_y - :OUT; - addbsel[0..1] -INT16/ a1_x -INT16/ a1_y -INT16/ a2_x -INT16/ a2_y -INT16/ a1_frac_x -INT16/ a1_frac_y - :IN); -INT16/ zero16 :LOCAL; -BEGIN*/ void ADDBMUX(int16_t &addb_x, int16_t &addb_y, uint8_t addbsel, int16_t a1_x, int16_t a1_y, int16_t a2_x, int16_t a2_y, int16_t a1_frac_x, int16_t a1_frac_y) { - -/*Zero := TIE0 (zero); -Zero16 := JOIN (zero16, zero, zero, zero, zero, zero, zero, zero, - zero, zero, zero, zero, zero, zero, zero, zero, zero); -Addbselb[0-1] := BUF8 (addbselb[0-1], addbsel[0-1]); -Addb_x := MX4 (addb_x, a1_x, a2_x, a1_frac_x, zero16, addbselb[0..1]); -Addb_y := MX4 (addb_y, a1_y, a2_y, a1_frac_y, zero16, addbselb[0..1]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// int16_t xterm[4], yterm[4]; xterm[0] = a1_x, xterm[1] = a2_x, xterm[2] = a1_frac_x, xterm[3] = 0; yterm[0] = a1_y, yterm[1] = a2_y, yterm[2] = a1_frac_y, yterm[3] = 0; addb_x = xterm[addbsel & 0x03]; addb_y = yterm[addbsel & 0x03]; -////////////////////////////////////////////////////////////////////////////////////// - -//END; } - /** DATAMUX - Address local data bus selection ****************** Select between the adder output and the input data bus */ -/*DEF DATAMUX ( -INT16/ data_x -INT16/ data_y - :OUT; -INT32/ gpu_din -INT16/ addq_x -INT16/ addq_y - addqsel - :IN); - -INT16/ gpu_lo, gpu_hi -:LOCAL; -BEGIN*/ void DATAMUX(int16_t &data_x, int16_t &data_y, uint32_t gpu_din, int16_t addq_x, int16_t addq_y, bool addqsel) { -/*Gpu_lo := JOIN (gpu_lo, gpu_din{0..15}); -Gpu_hi := JOIN (gpu_hi, gpu_din{16..31}); - -Addqselb := BUF8 (addqselb, addqsel); -Data_x := MX2 (data_x, gpu_lo, addq_x, addqselb); -Data_y := MX2 (data_y, gpu_hi, addq_y, addqselb);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// data_x = (addqsel ? addq_x : (int16_t)(gpu_din & 0xFFFF)); data_y = (addqsel ? addq_y : (int16_t)(gpu_din >> 16)); -////////////////////////////////////////////////////////////////////////////////////// - -//END; } - /****************************************************************** addradd 29/11/90 @@ -5325,145 +1964,22 @@ modx[0..2] take values ******************************************************************/ -/*IMPORT duplo, tosh; - -DEF ADDRADD ( -INT16/ addq_x -INT16/ addq_y - :OUT; - a1fracldi // propagate address adder carry -INT16/ adda_x -INT16/ adda_y -INT16/ addb_x -INT16/ addb_y - clk[0] // co-processor clock - modx[0..2] - suba_x - suba_y - :IN); - -BEGIN - -Zero := TIE0 (zero);*/ void ADDRADD(int16_t &addq_x, int16_t &addq_y, bool a1fracldi, uint16_t adda_x, uint16_t adda_y, uint16_t addb_x, uint16_t addb_y, uint8_t modx, bool suba_x, bool suba_y) { - -/* Perform the addition */ - -/*Adder_x := ADD16 (addqt_x[0..15], co_x, adda_x{0..15}, addb_x{0..15}, ci_x); -Adder_y := ADD16 (addq_y[0..15], co_y, adda_y{0..15}, addb_y{0..15}, ci_y);*/ - -/* latch carry and propagate if required */ - -/*Cxt0 := AN2 (cxt[0], co_x, a1fracldi); -Cxt1 := FD1Q (cxt[1], cxt[0], clk[0]); -Ci_x := EO (ci_x, cxt[1], suba_x); - -yt0 := AN2 (cyt[0], co_y, a1fracldi); -Cyt1 := FD1Q (cyt[1], cyt[0], clk[0]); -Ci_y := EO (ci_y, cyt[1], suba_y);*/ - -////////////////////////////////////// C++ CODE ////////////////////////////////////// -//I'm sure the following will generate a bunch of warnings, but will have to do for now. - static uint16_t co_x = 0, co_y = 0; // Carry out has to propogate between function calls... + static uint16_t co_x = 0, co_y = 0; uint16_t ci_x = co_x ^ (suba_x ? 1 : 0); uint16_t ci_y = co_y ^ (suba_y ? 1 : 0); uint32_t addqt_x = adda_x + addb_x + ci_x; uint32_t addqt_y = adda_y + addb_y + ci_y; co_x = ((addqt_x & 0x10000) && a1fracldi ? 1 : 0); co_y = ((addqt_y & 0x10000) && a1fracldi ? 1 : 0); -////////////////////////////////////////////////////////////////////////////////////// -/* Mask low bits of X to 0 if required */ - -/*Masksel := D38H (unused[0], masksel[0..4], maskbit[5], unused[1], modx[0..2]); - -Maskbit[0-4] := OR2 (maskbit[0-4], masksel[0-4], maskbit[1-5]); - -Mask[0-5] := MX2 (addq_x[0-5], addqt_x[0-5], zero, maskbit[0-5]); - -Addq_x := JOIN (addq_x, addq_x[0..5], addqt_x[6..15]); -Addq_y := JOIN (addq_y, addq_y[0..15]);*/ - -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint16_t mask[8] = { 0xFFFF, 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, 0xFFE0, 0xFFC0, 0x0000 }; addq_x = addqt_x & mask[modx]; addq_y = addqt_y & 0xFFFF; -////////////////////////////////////////////////////////////////////////////////////// - -//Unused[0-1] := DUMMY (unused[0-1]); - -//END; } - -/* -DEF DATA ( - wdata[0..63] // co-processor write data bus - :BUS; - dcomp[0..7] // data byte equal flags - srcd[0..7] // bits to use for bit to byte expansion - zcomp[0..3] // output from Z comparators - :OUT; - a1_x[0..1] // low two bits of A1 X pointer - big_pix // pixel organisation is big-endian - blitter_active // blitter is active - clk // co-processor clock - cmpdst // compare dest rather than source - colorld // load the pattern color fields - daddasel[0..2] // data adder input A selection - daddbsel[0..3] // data adder input B selection - daddmode[0..2] // data adder mode - daddq_sel // select adder output vs. GPU data - data[0..63] // co-processor read data bus - data_ena // enable write data - data_sel[0..1] // select data to write - dbinh\[0..7] // byte oriented changed data inhibits - dend[0..5] // end of changed write data zone - dpipe[0..1] // load computed data pipe-line latch - dstart[0..5] // start of changed write data zone - dstdld[0..1] // dest data load (two halves) - dstzld[0..1] // dest zed load (two halves) - ext_int // enable extended precision intensity calculations -INT32/ gpu_din // GPU data bus - iincld // I increment load - iincldx // alternate I increment load - init_if // initialise I fraction phase - init_ii // initialise I integer phase - init_zf // initialise Z fraction phase - intld[0..3] // computed intensities load - istepadd // intensity step integer add - istepfadd // intensity step fraction add - istepld // I step load - istepdld // I step delta load - lfu_func[0..3] // LFU function code - patdadd // pattern data gouraud add - patdld[0..1] // pattern data load (two halves) - pdsel[0..1] // select pattern data type - phrase_mode // phrase write mode - reload // transfer contents of double buffers - reset\ // system reset - srcd1ld[0..1] // source register 1 load (two halves) - srcdread // source data read load enable - srczread // source zed read load enable - srcshift[0..5] // source alignment shift - srcz1ld[0..1] // source zed 1 load (two halves) - srcz2add // zed fraction gouraud add - srcz2ld[0..1] // source zed 2 load (two halves) - textrgb // texture mapping in RGB mode - txtd[0..63] // data from the texture unit - zedld[0..3] // computed zeds load - zincld // Z increment load - zmode[0..2] // Z comparator mode - zpipe[0..1] // load computed zed pipe-line latch - zstepadd // zed step integer add - zstepfadd // zed step fraction add - zstepld // Z step load - zstepdld // Z step delta load - :IN); -*/ - void DATA(uint64_t &wdata, uint8_t &dcomp, uint8_t &zcomp, bool &nowrite, bool big_pix, bool cmpdst, uint8_t daddasel, uint8_t daddbsel, uint8_t daddmode, bool daddq_sel, uint8_t data_sel, uint8_t dbinh, uint8_t dend, uint8_t dstart, uint64_t dstd, uint32_t iinc, uint8_t lfu_func, uint64_t &patd, bool patdadd, @@ -5471,71 +1987,13 @@ void DATA(uint64_t &wdata, uint8_t &dcomp, uint8_t &zcomp, bool &nowrite, bool bcompen, bool bkgwren, bool dcompen, uint8_t icount, uint8_t pixsize, uint64_t &srcz, uint64_t dstz, uint32_t zinc) { -/* - Stuff we absolutely *need* to have passed in/out: -IN: - patdadd, dstd, srcd, patd, daddasel, daddbsel, daddmode, iinc, srcz1, srcz2, big_pix, phrase_mode, cmpdst -OUT: - changed patd (wdata I guess...) (Nope. We pass it back directly now...) -*/ - -// Source data registers - -/*Data_src := DATA_SRC (srcdlo, srcdhi, srcz[0..1], srczo[0..1], srczp[0..1], srcz1[0..1], srcz2[0..1], big_pix, - clk, gpu_din, intld[0..3], local_data0, local_data1, srcd1ld[0..1], srcdread, srczread, srcshift[0..5], - srcz1ld[0..1], srcz2add, srcz2ld[0..1], zedld[0..3], zpipe[0..1]); -Srcd[0-7] := JOIN (srcd[0-7], srcdlo{0-7}); -Srcd[8-31] := JOIN (srcd[8-31], srcdlo{8-31}); -Srcd[32-63] := JOIN (srcd[32-63], srcdhi{0-31});*/ - -// Destination data registers - -/*Data_dst := DATA_DST (dstd[0..63], dstz[0..1], clk, dstdld[0..1], dstzld[0..1], load_data[0..1]); -Dstdlo := JOIN (dstdlo, dstd[0..31]); -Dstdhi := JOIN (dstdhi, dstd[32..63]);*/ - -// Pattern and Color data registers - -// Looks like this is simply another register file for the pattern data registers. No adding or anything funky -// going on. Note that patd & patdv will output the same info. -// Patdldl/h (patdld[0..1]) can select the local_data bus to overwrite the current pattern data... -// Actually, it can be either patdld OR patdadd...! -/*Data_pat := DATA_PAT (colord[0..15], int0dp[8..10], int1dp[8..10], int2dp[8..10], int3dp[8..10], mixsel[0..2], - patd[0..63], patdv[0..1], clk, colorld, dpipe[0], ext_int, gpu_din, intld[0..3], local_data0, local_data1, - patdadd, patdld[0..1], reload, reset\); -Patdlo := JOIN (patdlo, patd[0..31]); -Patdhi := JOIN (patdhi, patd[32..63]);*/ - -// Multiplying data Mixer (NOT IN JAGUAR I) - -/*Datamix := DATAMIX (patdo[0..1], clk, colord[0..15], dpipe[1], dstd[0..63], int0dp[8..10], int1dp[8..10], - int2dp[8..10], int3dp[8..10], mixsel[0..2], patd[0..63], pdsel[0..1], srcd[0..63], textrgb, txtd[0..63]);*/ - -// Logic function unit - -/*Lfu := LFU (lfu[0..1], srcdlo, srcdhi, dstdlo, dstdhi, lfu_func[0..3]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint64_t funcmask[2] = { 0, 0xFFFFFFFFFFFFFFFFLL }; uint64_t func0 = funcmask[lfu_func & 0x01]; uint64_t func1 = funcmask[(lfu_func >> 1) & 0x01]; uint64_t func2 = funcmask[(lfu_func >> 2) & 0x01]; uint64_t func3 = funcmask[(lfu_func >> 3) & 0x01]; uint64_t lfu = (~srcd & ~dstd & func0) | (~srcd & dstd & func1) | (srcd & ~dstd & func2) | (srcd & dstd & func3); -////////////////////////////////////////////////////////////////////////////////////// -// Increment and Step Registers - -// Does it do anything without the step add lines? Check it! -// No. This is pretty much just a register file without the Jaguar II lines... -/*Inc_step := INC_STEP (iinc, istep[0..31], zinc, zstep[0..31], clk, ext_int, gpu_din, iincld, iincldx, istepadd, - istepfadd, istepld, istepdld, reload, reset\, zincld, zstepadd, zstepfadd, zstepld, zstepdld); -Istep := JOIN (istep, istep[0..31]); -Zstep := JOIN (zstep, zstep[0..31]);*/ - -// Pixel data comparator - -/*Datacomp := DATACOMP (dcomp[0..7], cmpdst, dstdlo, dstdhi, patdlo, patdhi, srcdlo, srcdhi);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// dcomp = 0; uint64_t cmpd = patd ^ (cmpdst ? dstd : srcd); @@ -5555,21 +2013,7 @@ Zstep := JOIN (zstep, zstep[0..31]);*/ dcomp |= 0x40; if ((cmpd & 0xFF00000000000000LL) == 0) dcomp |= 0x80; -////////////////////////////////////////////////////////////////////////////////////// -// Zed comparator for Z-buffer operations - -/*Zedcomp := ZEDCOMP (zcomp[0..3], srczp[0..1], dstz[0..1], zmode[0..2]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// -//srczp is srcz pipelined, also it goes through a source shift as well... -/*The shift is basically like so (each piece is 16 bits long): - - 0 1 2 3 4 5 6 - srcz1lolo srcz1lohi srcz1hilo srcz1hihi srcrz2lolo srcz2lohi srcz2hilo - -with srcshift bits 4 & 5 selecting the start position -*/ -//So... basically what we have here is: zcomp = 0; if ((((srcz & 0x000000000000FFFFLL) < (dstz & 0x000000000000FFFFLL)) && (zmode & 0x01)) @@ -5592,111 +2036,18 @@ with srcshift bits 4 & 5 selecting the start position || (((srcz & 0xFFFF000000000000LL) > (dstz & 0xFFFF000000000000LL)) && (zmode & 0x04))) zcomp |= 0x08; -//TEMP, TO TEST IF ZCOMP IS THE CULPRIT... -//Nope, this is NOT the problem... -//zcomp=0; -// We'll do the comparison/bit/byte inhibits here, since that's they way it happens -// in the real thing (dcomp goes out to COMP_CTRL and back into DATA through dbinh)... -#if 1 uint8_t dbinht; -// bool nowrite; COMP_CTRL(dbinht, nowrite, - bcompen, true/*big_pix*/, bkgwren, dcomp, dcompen, icount, pixsize, phrase_mode, srcd & 0xFF, zcomp); + bcompen, true, bkgwren, dcomp, dcompen, icount, pixsize, phrase_mode, srcd & 0xFF, zcomp); dbinh = dbinht; -// dbinh = 0x00; -#endif -#if 1 -#ifdef VERBOSE_BLITTER_LOGGING -if (logBlit) - WriteLog("\n[dcomp=%02X zcomp=%02X dbinh=%02X]\n", dcomp, zcomp, dbinh); -#endif -#endif -////////////////////////////////////////////////////////////////////////////////////// - -// 22 Mar 94 -// The data initializer - allows all four initial values to be computed from one (NOT IN JAGUAR I) - -/*Datinit := DATINIT (initcin[0..3], initinc[0..63], initpix[0..15], a1_x[0..1], big_pix, clk, iinc, init_if, init_ii, - init_zf, istep[0..31], zinc, zstep[0..31]);*/ - -// Adder array for Z and intensity increments - -/*Addarray := ADDARRAY (addq[0..3], clk, daddasel[0..2], daddbsel[0..3], daddmode[0..2], dstdlo, dstdhi, iinc, - initcin[0..3], initinc[0..63], initpix[0..15], istep, patdv[0..1], srcdlo, srcdhi, srcz1[0..1], - srcz2[0..1], reset\, zinc, zstep);*/ -/*void ADDARRAY(uint16_t * addq, uint8_t daddasel, uint8_t daddbsel, uint8_t daddmode, - uint64_t dstd, uint32_t iinc, uint8_t initcin[], uint64_t initinc, uint16_t initpix, - uint32_t istep, uint64_t patd, uint64_t srcd, uint64_t srcz1, uint64_t srcz2, - uint32_t zinc, uint32_t zstep)*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint16_t addq[4]; uint8_t initcin[4] = { 0, 0, 0, 0 }; ADDARRAY(addq, daddasel, daddbsel, daddmode, dstd, iinc, initcin, 0, 0, 0, patd, srcd, 0, 0, 0, 0); - //This is normally done asynchronously above (thru local_data) when in patdadd mode... -//And now it's passed back to the caller to be persistent between calls...! -//But it's causing some serious fuck-ups in T2K now... !!! FIX !!! [DONE--???] -//Weird! It doesn't anymore...! if (patdadd) patd = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; -////////////////////////////////////////////////////////////////////////////////////// -// Local data bus multiplexer - -/*Local_mux := LOCAL_MUX (local_data[0..1], load_data[0..1], - addq[0..3], gpu_din, data[0..63], blitter_active, daddq_sel); -Local_data0 := JOIN (local_data0, local_data[0]); -Local_data1 := JOIN (local_data1, local_data[1]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// - -// Data output multiplexer and tri-state drive - -/*Data_mux := DATA_MUX (wdata[0..63], addq[0..3], big_pix, dstdlo, dstdhi, dstz[0..1], data_sel[0..1], data_ena, - dstart[0..5], dend[0..5], dbinh\[0..7], lfu[0..1], patdo[0..1], phrase_mode, srczo[0..1]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// -// NOTE: patdo comes from DATAMIX and can be considered the same as patd for Jaguar I - -////////////////////////////////////////////////////////////////////////////////////// -//} - -/*DEF DATA_MUX ( - wdata[0..63] // co-processor rwrite data bus - :BUS; -INT16/ addq[0..3] - big_pix // Pixel organisation is big-endian -INT32/ dstdlo -INT32/ dstdhi -INT32/ dstzlo -INT32/ dstzhi - data_sel[0..1] // source of write data - data_ena // enable write data onto read/write bus - dstart[0..5] // start of changed write data - dend[0..5] // end of changed write data - dbinh\[0..7] // byte oriented changed data inhibits -INT32/ lfu[0..1] -INT32/ patd[0..1] - phrase_mode // phrase write mode -INT32/ srczlo -INT32/ srczhi - :IN);*/ - -/*INT32/ addql[0..1], ddatlo, ddathi zero32 -:LOCAL; -BEGIN - -Phrase_mode\ := INV1 (phrase_mode\, phrase_mode); -Zero := TIE0 (zero); -Zero32 := JOIN (zero32, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero, zero);*/ - -/* Generate a changed data mask */ - -/*Edis := OR6 (edis\, dend[0..5]); -Ecoarse := DECL38E (e_coarse\[0..7], dend[3..5], edis\); -E_coarse[0] := INV1 (e_coarse[0], e_coarse\[0]); -Efine := DECL38E (unused[0], e_fine\[1..7], dend[0..2], e_coarse[0]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint8_t decl38e[2][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F } }; uint8_t dech38[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; @@ -5704,22 +2055,13 @@ Efine := DECL38E (unused[0], e_fine\[1..7], dend[0..2], e_coarse[0]);*/ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; int en = (dend & 0x3F ? 1 : 0); - uint8_t e_coarse = decl38e[en][(dend & 0x38) >> 3]; // Actually, this is e_coarse inverted... + uint8_t e_coarse = decl38e[en][(dend & 0x38) >> 3]; uint8_t e_fine = decl38e[(e_coarse & 0x01) ^ 0x01][dend & 0x07]; e_fine &= 0xFE; -////////////////////////////////////////////////////////////////////////////////////// -/*Scoarse := DECH38 (s_coarse[0..7], dstart[3..5]); -Sfen\ := INV1 (sfen\, s_coarse[0]); -Sfine := DECH38EL (s_fine[0..7], dstart[0..2], sfen\);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint8_t s_coarse = dech38[(dstart & 0x38) >> 3]; uint8_t s_fine = dech38el[(s_coarse & 0x01) ^ 0x01][dstart & 0x07]; -////////////////////////////////////////////////////////////////////////////////////// -/*Maskt[0] := BUF1 (maskt[0], s_fine[0]); -Maskt[1-7] := OAN1P (maskt[1-7], maskt[0-6], s_fine[1-7], e_fine\[1-7]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint16_t maskt = s_fine & 0x0001; maskt |= (((maskt & 0x0001) || (s_fine & 0x02)) && (e_fine & 0x02) ? 0x0002 : 0x0000); maskt |= (((maskt & 0x0002) || (s_fine & 0x04)) && (e_fine & 0x04) ? 0x0004 : 0x0000); @@ -5728,14 +2070,7 @@ Maskt[1-7] := OAN1P (maskt[1-7], maskt[0-6], s_fine[1-7], e_fine\[1-7]);*/ maskt |= (((maskt & 0x0010) || (s_fine & 0x20)) && (e_fine & 0x20) ? 0x0020 : 0x0000); maskt |= (((maskt & 0x0020) || (s_fine & 0x40)) && (e_fine & 0x40) ? 0x0040 : 0x0000); maskt |= (((maskt & 0x0040) || (s_fine & 0x80)) && (e_fine & 0x80) ? 0x0080 : 0x0000); -////////////////////////////////////////////////////////////////////////////////////// -/* Produce a look-ahead on the ripple carry: -masktla = s_coarse[0] . /e_coarse[0] */ -/*Masktla := AN2 (masktla, s_coarse[0], e_coarse\[0]); -Maskt[8] := OAN1P (maskt[8], masktla, s_coarse[1], e_coarse\[1]); -Maskt[9-14] := OAN1P (maskt[9-14], maskt[8-13], s_coarse[2-7], e_coarse\[2-7]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// maskt |= (((s_coarse & e_coarse & 0x01) || (s_coarse & 0x02)) && (e_coarse & 0x02) ? 0x0100 : 0x0000); maskt |= (((maskt & 0x0100) || (s_coarse & 0x04)) && (e_coarse & 0x04) ? 0x0200 : 0x0000); maskt |= (((maskt & 0x0200) || (s_coarse & 0x08)) && (e_coarse & 0x08) ? 0x0400 : 0x0000); @@ -5743,34 +2078,9 @@ Maskt[9-14] := OAN1P (maskt[9-14], maskt[8-13], s_coarse[2-7], e_coarse\[2-7]);* maskt |= (((maskt & 0x0800) || (s_coarse & 0x20)) && (e_coarse & 0x20) ? 0x1000 : 0x0000); maskt |= (((maskt & 0x1000) || (s_coarse & 0x40)) && (e_coarse & 0x40) ? 0x2000 : 0x0000); maskt |= (((maskt & 0x2000) || (s_coarse & 0x80)) && (e_coarse & 0x80) ? 0x4000 : 0x0000); -////////////////////////////////////////////////////////////////////////////////////// -/* The bit terms are mirrored for big-endian pixels outside phrase -mode. The byte terms are mirrored for big-endian pixels in phrase -mode. */ - -/*Mirror_bit := AN2M (mir_bit, phrase_mode\, big_pix); -Mirror_byte := AN2H (mir_byte, phrase_mode, big_pix); - -Masktb[14] := BUF1 (masktb[14], maskt[14]); -Masku[0] := MX4 (masku[0], maskt[0], maskt[7], maskt[14], zero, mir_bit, mir_byte); -Masku[1] := MX4 (masku[1], maskt[1], maskt[6], maskt[14], zero, mir_bit, mir_byte); -Masku[2] := MX4 (masku[2], maskt[2], maskt[5], maskt[14], zero, mir_bit, mir_byte); -Masku[3] := MX4 (masku[3], maskt[3], maskt[4], masktb[14], zero, mir_bit, mir_byte); -Masku[4] := MX4 (masku[4], maskt[4], maskt[3], masktb[14], zero, mir_bit, mir_byte); -Masku[5] := MX4 (masku[5], maskt[5], maskt[2], masktb[14], zero, mir_bit, mir_byte); -Masku[6] := MX4 (masku[6], maskt[6], maskt[1], masktb[14], zero, mir_bit, mir_byte); -Masku[7] := MX4 (masku[7], maskt[7], maskt[0], masktb[14], zero, mir_bit, mir_byte); -Masku[8] := MX2 (masku[8], maskt[8], maskt[13], mir_byte); -Masku[9] := MX2 (masku[9], maskt[9], maskt[12], mir_byte); -Masku[10] := MX2 (masku[10], maskt[10], maskt[11], mir_byte); -Masku[11] := MX2 (masku[11], maskt[11], maskt[10], mir_byte); -Masku[12] := MX2 (masku[12], maskt[12], maskt[9], mir_byte); -Masku[13] := MX2 (masku[13], maskt[13], maskt[8], mir_byte); -Masku[14] := MX2 (masku[14], maskt[14], maskt[0], mir_byte);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// - bool mir_bit = true/*big_pix*/ && !phrase_mode; - bool mir_byte = true/*big_pix*/ && phrase_mode; + bool mir_bit = !phrase_mode; + bool mir_byte = phrase_mode; uint16_t masku = maskt; if (mir_bit) @@ -5806,46 +2116,17 @@ Masku[14] := MX2 (masku[14], maskt[14], maskt[0], mir_byte);*/ masku |= (maskt << 5) & 0x2000; masku |= (maskt << 7) & 0x4000; } -////////////////////////////////////////////////////////////////////////////////////// -/* The maskt terms define the area for changed data, but the byte -inhibit terms can override these */ - -/*Mask[0-7] := AN2 (mask[0-7], masku[0-7], dbinh\[0]); -Mask[8-14] := AN2H (mask[8-14], masku[8-14], dbinh\[1-7]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint16_t mask = masku & (!(dbinh & 0x01) ? 0xFFFF : 0xFF00); mask &= ~(((uint16_t)dbinh & 0x00FE) << 7); -////////////////////////////////////////////////////////////////////////////////////// -/*Addql[0] := JOIN (addql[0], addq[0..1]); -Addql[1] := JOIN (addql[1], addq[2..3]); - -Dsel0b[0-1] := BUF8 (dsel0b[0-1], data_sel[0]); -Dsel1b[0-1] := BUF8 (dsel1b[0-1], data_sel[1]); -Ddatlo := MX4 (ddatlo, patd[0], lfu[0], addql[0], zero32, dsel0b[0], dsel1b[0]); -Ddathi := MX4 (ddathi, patd[1], lfu[1], addql[1], zero32, dsel0b[1], dsel1b[1]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// uint64_t dmux[4]; dmux[0] = patd; dmux[1] = lfu; dmux[2] = ((uint64_t)addq[3] << 48) | ((uint64_t)addq[2] << 32) | ((uint64_t)addq[1] << 16) | (uint64_t)addq[0]; dmux[3] = 0; uint64_t ddat = dmux[data_sel]; -////////////////////////////////////////////////////////////////////////////////////// -/*Zed_sel := AN2 (zed_sel, data_sel[0..1]); -Zed_selb[0-1] := BUF8 (zed_selb[0-1], zed_sel); - -Dat[0-7] := MX4 (dat[0-7], dstdlo{0-7}, ddatlo{0-7}, dstzlo{0-7}, srczlo{0-7}, mask[0-7], zed_selb[0]); -Dat[8-15] := MX4 (dat[8-15], dstdlo{8-15}, ddatlo{8-15}, dstzlo{8-15}, srczlo{8-15}, mask[8], zed_selb[0]); -Dat[16-23] := MX4 (dat[16-23], dstdlo{16-23}, ddatlo{16-23}, dstzlo{16-23}, srczlo{16-23}, mask[9], zed_selb[0]); -Dat[24-31] := MX4 (dat[24-31], dstdlo{24-31}, ddatlo{24-31}, dstzlo{24-31}, srczlo{24-31}, mask[10], zed_selb[0]); -Dat[32-39] := MX4 (dat[32-39], dstdhi{0-7}, ddathi{0-7}, dstzhi{0-7}, srczhi{0-7}, mask[11], zed_selb[1]); -Dat[40-47] := MX4 (dat[40-47], dstdhi{8-15}, ddathi{8-15}, dstzhi{8-15}, srczhi{8-15}, mask[12], zed_selb[1]); -Dat[48-55] := MX4 (dat[48-55], dstdhi{16-23}, ddathi{16-23}, dstzhi{16-23}, srczhi{16-23}, mask[13], zed_selb[1]); -Dat[56-63] := MX4 (dat[56-63], dstdhi{24-31}, ddathi{24-31}, dstzhi{24-31}, srczhi{24-31}, mask[14], zed_selb[1]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// wdata = ((ddat & mask) | (dstd & ~mask)) & 0x00000000000000FFLL; wdata |= (mask & 0x0100 ? ddat : dstd) & 0x000000000000FF00LL; wdata |= (mask & 0x0200 ? ddat : dstd) & 0x0000000000FF0000LL; @@ -5854,15 +2135,7 @@ Dat[56-63] := MX4 (dat[56-63], dstdhi{24-31}, ddathi{24-31}, dstzhi{24-31}, srcz wdata |= (mask & 0x1000 ? ddat : dstd) & 0x0000FF0000000000LL; wdata |= (mask & 0x2000 ? ddat : dstd) & 0x00FF000000000000LL; wdata |= (mask & 0x4000 ? ddat : dstd) & 0xFF00000000000000LL; -/*if (logBlit) -{ - printf("\n[ddat=%08X%08X dstd=%08X%08X wdata=%08X%08X mask=%04X]\n", - (uint32_t)(ddat >> 32), (uint32_t)(ddat & 0xFFFFFFFF), - (uint32_t)(dstd >> 32), (uint32_t)(dstd & 0xFFFFFFFF), - (uint32_t)(wdata >> 32), (uint32_t)(wdata & 0xFFFFFFFF), mask); - fflush(stdout); -}//*/ -//This is a crappy way of handling this, but it should work for now... + uint64_t zwdata; zwdata = ((srcz & mask) | (dstz & ~mask)) & 0x00000000000000FFLL; zwdata |= (mask & 0x0100 ? srcz : dstz) & 0x000000000000FF00LL; @@ -5872,27 +2145,10 @@ Dat[56-63] := MX4 (dat[56-63], dstdhi{24-31}, ddathi{24-31}, dstzhi{24-31}, srcz zwdata |= (mask & 0x1000 ? srcz : dstz) & 0x0000FF0000000000LL; zwdata |= (mask & 0x2000 ? srcz : dstz) & 0x00FF000000000000LL; zwdata |= (mask & 0x4000 ? srcz : dstz) & 0xFF00000000000000LL; -if (logBlit) -{ - WriteLog("\n[srcz=%08X%08X dstz=%08X%08X zwdata=%08X%08X mask=%04X]\n", - (uint32_t)(srcz >> 32), (uint32_t)(srcz & 0xFFFFFFFF), - (uint32_t)(dstz >> 32), (uint32_t)(dstz & 0xFFFFFFFF), - (uint32_t)(zwdata >> 32), (uint32_t)(zwdata & 0xFFFFFFFF), mask); -// fflush(stdout); -}//*/ + srcz = zwdata; -////////////////////////////////////////////////////////////////////////////////////// - -/*Data_enab[0-1] := BUF8 (data_enab[0-1], data_ena); -Datadrv[0-31] := TS (wdata[0-31], dat[0-31], data_enab[0]); -Datadrv[32-63] := TS (wdata[32-63], dat[32-63], data_enab[1]); - -Unused[0] := DUMMY (unused[0]); - -END;*/ } - /** COMP_CTRL - Comparator output control logic ***************** This block is responsible for taking the comparator outputs and @@ -5923,134 +2179,25 @@ performed. The is taken care of within the zed comparator by pipe-lining the comparator inputs where appropriate. */ -//#define LOG_COMP_CTRL -/*DEF COMP_CTRL ( - dbinh\[0..7] // destination byte inhibit lines - nowrite // suppress inner loop write operation - :OUT; - bcompen // bit selector inhibit enable - big_pix // pixels are big-endian - bkgwren // enable dest data write in pix inhibit - clk // co-processor clock - dcomp[0..7] // output of data byte comparators - dcompen // data comparator inhibit enable - icount[0..2] // low bits of inner count - pixsize[0..2] // destination pixel size - phrase_mode // phrase write mode - srcd[0..7] // bits to use for bit to byte expansion - step_inner // inner loop advance - zcomp[0..3] // output of word zed comparators - :IN);*/ void COMP_CTRL(uint8_t &dbinh, bool &nowrite, bool bcompen, bool big_pix, bool bkgwren, uint8_t dcomp, bool dcompen, uint8_t icount, uint8_t pixsize, bool phrase_mode, uint8_t srcd, uint8_t zcomp) { -//BEGIN - -/*Bkgwren\ := INV1 (bkgwren\, bkgwren); -Phrase_mode\ := INV1 (phrase_mode\, phrase_mode); -Pixsize\[0-2] := INV2 (pixsize\[0-2], pixsize[0-2]);*/ - -/* The bit comparator bits are derived from the source data, which -will have been suitably aligned for phrase mode. The contents of -the inner counter are used to select which bit to use. - -When not in phrase mode the inner count value is used to select -one bit. It is assumed that the count has already occurred, so, -7 selects bit 0, etc. In big-endian pixel mode, this turns round, -so that a count of 7 selects bit 7. - -In phrase mode, the eight bits are used directly, and this mode is -only applicable to 8-bit pixel mode (2/34) */ - -/*Bcompselt[0-2] := EO (bcompselt[0-2], icount[0-2], big_pix); -Bcompbit := MX8 (bcompbit, srcd[7], srcd[6], srcd[5], - srcd[4], srcd[3], srcd[2], srcd[1], srcd[0], bcompselt[0..2]); -Bcompbit\ := INV1 (bcompbit\, bcompbit);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("\n [bcompen=%s dcompen=%s phrase_mode=%s bkgwren=%s dcomp=%02X zcomp=%02X]", (bcompen ? "T" : "F"), (dcompen ? "T" : "F"), (phrase_mode ? "T" : "F"), (bkgwren ? "T" : "F"), dcomp, zcomp); - WriteLog("\n "); -// fflush(stdout); -} -#endif uint8_t bcompselt = (big_pix ? ~icount : icount) & 0x07; uint8_t bitmask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; bool bcompbit = srcd & bitmask[bcompselt]; -////////////////////////////////////////////////////////////////////////////////////// -/* pipe-line the count */ -/*Bcompsel[0-2] := FDSYNC (bcompsel[0-2], bcompselt[0-2], step_inner, clk); -Bcompbt := MX8 (bcompbitpt, srcd[7], srcd[6], srcd[5], - srcd[4], srcd[3], srcd[2], srcd[1], srcd[0], bcompsel[0..2]); -Bcompbitp := FD1Q (bcompbitp, bcompbitpt, clk); -Bcompbitp\ := INV1 (bcompbitp\, bcompbitp);*/ - -/* For pixel mode, generate the write inhibit signal for all modes -on bit inhibit, for 8 and 16 bit modes on comparator inhibit, and -for 16 bit mode on Z inhibit - -Nowrite = bcompen . /bcompbit . /phrase_mode - + dcompen . dcomp[0] . /phrase_mode . pixsize = 011 - + dcompen . dcomp[0..1] . /phrase_mode . pixsize = 100 - + zcomp[0] . /phrase_mode . pixsize = 100 -*/ - -/*Nowt0 := NAN3 (nowt[0], bcompen, bcompbit\, phrase_mode\); -Nowt1 := ND6 (nowt[1], dcompen, dcomp[0], phrase_mode\, pixsize\[2], pixsize[0..1]); -Nowt2 := ND7 (nowt[2], dcompen, dcomp[0..1], phrase_mode\, pixsize[2], pixsize\[0..1]); -Nowt3 := NAN5 (nowt[3], zcomp[0], phrase_mode\, pixsize[2], pixsize\[0..1]); -Nowt4 := NAN4 (nowt[4], nowt[0..3]); -Nowrite := AN2 (nowrite, nowt[4], bkgwren\);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// nowrite = ((bcompen && !bcompbit && !phrase_mode) || (dcompen && (dcomp & 0x01) && !phrase_mode && (pixsize == 3)) || (dcompen && ((dcomp & 0x03) == 0x03) && !phrase_mode && (pixsize == 4)) || ((zcomp & 0x01) && !phrase_mode && (pixsize == 4))) && !bkgwren; -////////////////////////////////////////////////////////////////////////////////////// -/*Winht := NAN3 (winht, bcompen, bcompbitp\, phrase_mode\); -Winhibit := NAN4 (winhibit, winht, nowt[1..3]);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// -//This is the same as above, but with bcompbit delayed one tick and called 'winhibit' -//Small difference: Besides the pipeline effect, it's also not using !bkgwren... -// bool winhibit = (bcompen && ! bool winhibit = (bcompen && !bcompbit && !phrase_mode) || (dcompen && (dcomp & 0x01) && !phrase_mode && (pixsize == 3)) || (dcompen && ((dcomp & 0x03) == 0x03) && !phrase_mode && (pixsize == 4)) || ((zcomp & 0x01) && !phrase_mode && (pixsize == 4)); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[nw=%s wi=%s]", (nowrite ? "T" : "F"), (winhibit ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/* For phrase mode, generate the byte inhibit signals for eight bit -mode 011, or sixteen bit mode 100 -dbinh\[0] = pixsize[2] . zcomp[0] - + pixsize[2] . dcomp[0] . dcomp[1] . dcompen - + /pixsize[2] . dcomp[0] . dcompen - + /srcd[0] . bcompen - -Inhibits 0-3 are also used when not in phrase mode to write back -destination data. -*/ - -/*Srcd\[0-7] := INV1 (srcd\[0-7], srcd[0-7]); - -Di0t0 := NAN2H (di0t[0], pixsize[2], zcomp[0]); -Di0t1 := NAN4H (di0t[1], pixsize[2], dcomp[0..1], dcompen); -Di0t2 := NAN2 (di0t[2], srcd\[0], bcompen); -Di0t3 := NAN3 (di0t[3], pixsize\[2], dcomp[0], dcompen); -Di0t4 := NAN4 (di0t[4], di0t[0..3]); -Dbinh[0] := ANR1P (dbinh\[0], di0t[4], phrase_mode, winhibit);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// dbinh = 0; bool di0t0_1 = ((pixsize & 0x04) && (zcomp & 0x01)) || ((pixsize & 0x04) && (dcomp & 0x01) && (dcomp & 0x02) && dcompen); @@ -6058,175 +2205,47 @@ Dbinh[0] := ANR1P (dbinh\[0], di0t[4], phrase_mode, winhibit);*/ || (!(srcd & 0x01) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x01) && dcompen); dbinh |= (!((di0t4 && phrase_mode) || winhibit) ? 0x01 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di0t0_1=%s di0t4=%s]", (di0t0_1 ? "T" : "F"), (di0t4 ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/*Di1t0 := NAN3 (di1t[0], pixsize\[2], dcomp[1], dcompen); -Di1t1 := NAN2 (di1t[1], srcd\[1], bcompen); -Di1t2 := NAN4 (di1t[2], di0t[0..1], di1t[0..1]); -Dbinh[1] := ANR1 (dbinh\[1], di1t[2], phrase_mode, winhibit);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// bool di1t2 = di0t0_1 || (!(srcd & 0x02) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x02) && dcompen); dbinh |= (!((di1t2 && phrase_mode) || winhibit) ? 0x02 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di1t2=%s]", (di1t2 ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/*Di2t0 := NAN2H (di2t[0], pixsize[2], zcomp[1]); -Di2t1 := NAN4H (di2t[1], pixsize[2], dcomp[2..3], dcompen); -Di2t2 := NAN2 (di2t[2], srcd\[2], bcompen); -Di2t3 := NAN3 (di2t[3], pixsize\[2], dcomp[2], dcompen); -Di2t4 := NAN4 (di2t[4], di2t[0..3]); -Dbinh[2] := ANR1 (dbinh\[2], di2t[4], phrase_mode, winhibit);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// -//[bcompen=F dcompen=T phrase_mode=T bkgwren=F][nw=F wi=F] -//[di0t0_1=F di0t4=F][di1t2=F][di2t0_1=T di2t4=T][di3t2=T][di4t0_1=F di2t4=F][di5t2=F][di6t0_1=F di6t4=F][di7t2=F] -//[dcomp=$00 dbinh=$0C][7804780400007804] (icount=0005, inc=4) bool di2t0_1 = ((pixsize & 0x04) && (zcomp & 0x02)) || ((pixsize & 0x04) && (dcomp & 0x04) && (dcomp & 0x08) && dcompen); bool di2t4 = di2t0_1 || (!(srcd & 0x04) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x04) && dcompen); dbinh |= (!((di2t4 && phrase_mode) || winhibit) ? 0x04 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di2t0_1=%s di2t4=%s]", (di2t0_1 ? "T" : "F"), (di2t4 ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/*Di3t0 := NAN3 (di3t[0], pixsize\[2], dcomp[3], dcompen); -Di3t1 := NAN2 (di3t[1], srcd\[3], bcompen); -Di3t2 := NAN4 (di3t[2], di2t[0..1], di3t[0..1]); -Dbinh[3] := ANR1 (dbinh\[3], di3t[2], phrase_mode, winhibit);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// bool di3t2 = di2t0_1 || (!(srcd & 0x08) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x08) && dcompen); dbinh |= (!((di3t2 && phrase_mode) || winhibit) ? 0x08 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di3t2=%s]", (di3t2 ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/*Di4t0 := NAN2H (di4t[0], pixsize[2], zcomp[2]); -Di4t1 := NAN4H (di4t[1], pixsize[2], dcomp[4..5], dcompen); -Di4t2 := NAN2 (di4t[2], srcd\[4], bcompen); -Di4t3 := NAN3 (di4t[3], pixsize\[2], dcomp[4], dcompen); -Di4t4 := NAN4 (di4t[4], di4t[0..3]); -Dbinh[4] := NAN2 (dbinh\[4], di4t[4], phrase_mode);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// bool di4t0_1 = ((pixsize & 0x04) && (zcomp & 0x04)) || ((pixsize & 0x04) && (dcomp & 0x10) && (dcomp & 0x20) && dcompen); bool di4t4 = di4t0_1 || (!(srcd & 0x10) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x10) && dcompen); dbinh |= (!(di4t4 && phrase_mode) ? 0x10 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di4t0_1=%s di2t4=%s]", (di4t0_1 ? "T" : "F"), (di4t4 ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/*Di5t0 := NAN3 (di5t[0], pixsize\[2], dcomp[5], dcompen); -Di5t1 := NAN2 (di5t[1], srcd\[5], bcompen); -Di5t2 := NAN4 (di5t[2], di4t[0..1], di5t[0..1]); -Dbinh[5] := NAN2 (dbinh\[5], di5t[2], phrase_mode);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// bool di5t2 = di4t0_1 || (!(srcd & 0x20) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x20) && dcompen); dbinh |= (!(di5t2 && phrase_mode) ? 0x20 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di5t2=%s]", (di5t2 ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/*Di6t0 := NAN2H (di6t[0], pixsize[2], zcomp[3]); -Di6t1 := NAN4H (di6t[1], pixsize[2], dcomp[6..7], dcompen); -Di6t2 := NAN2 (di6t[2], srcd\[6], bcompen); -Di6t3 := NAN3 (di6t[3], pixsize\[2], dcomp[6], dcompen); -Di6t4 := NAN4 (di6t[4], di6t[0..3]); -Dbinh[6] := NAN2 (dbinh\[6], di6t[4], phrase_mode);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// bool di6t0_1 = ((pixsize & 0x04) && (zcomp & 0x08)) || ((pixsize & 0x04) && (dcomp & 0x40) && (dcomp & 0x80) && dcompen); bool di6t4 = di6t0_1 || (!(srcd & 0x40) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x40) && dcompen); dbinh |= (!(di6t4 && phrase_mode) ? 0x40 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di6t0_1=%s di6t4=%s]", (di6t0_1 ? "T" : "F"), (di6t4 ? "T" : "F")); -// fflush(stdout); -} -#endif -////////////////////////////////////////////////////////////////////////////////////// -/*Di7t0 := NAN3 (di7t[0], pixsize\[2], dcomp[7], dcompen); -Di7t1 := NAN2 (di7t[1], srcd\[7], bcompen); -Di7t2 := NAN4 (di7t[2], di6t[0..1], di7t[0..1]); -Dbinh[7] := NAN2 (dbinh\[7], di7t[2], phrase_mode);*/ -////////////////////////////////////// C++ CODE ////////////////////////////////////// bool di7t2 = di6t0_1 || (!(srcd & 0x80) && bcompen) || (!(pixsize & 0x04) && (dcomp & 0x80) && dcompen); dbinh |= (!(di7t2 && phrase_mode) ? 0x80 : 0x00); -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[di7t2=%s]", (di7t2 ? "T" : "F")); -// fflush(stdout); + + dbinh = ~dbinh; } -#endif -////////////////////////////////////////////////////////////////////////////////////// - -//END; -//kludge -dbinh = ~dbinh; -#ifdef LOG_COMP_CTRL -if (logBlit) -{ - WriteLog("[dcomp=$%02X dbinh=$%02X]\n ", dcomp, dbinh); -// fflush(stdout); -} -#endif -} - - -////////////////////////////////////// C++ CODE ////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// - -// !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! -// !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! -// !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! TESTING !!! - -#endif - diff --git a/waterbox/virtualjaguar/src/blitter.h b/waterbox/virtualjaguar/src/blitter.h index d57e866f98..7ccc23da39 100644 --- a/waterbox/virtualjaguar/src/blitter.h +++ b/waterbox/virtualjaguar/src/blitter.h @@ -5,7 +5,6 @@ #ifndef __BLITTER_H__ #define __BLITTER_H__ -//#include "types.h" #include "memory.h" void BlitterInit(void); @@ -22,9 +21,4 @@ void BlitterWriteLong(uint32_t, uint32_t, uint32_t who = UNKNOWN); uint32_t blitter_reg_read(uint32_t offset); void blitter_reg_write(uint32_t offset, uint32_t data); -extern uint8_t blitter_working; - -//For testing only... -void LogBlit(void); - #endif // __BLITTER_H__ diff --git a/waterbox/virtualjaguar/src/cdintf.cpp b/waterbox/virtualjaguar/src/cdintf.cpp index 1cf2ee2e2d..300eb5aa3d 100644 --- a/waterbox/virtualjaguar/src/cdintf.cpp +++ b/waterbox/virtualjaguar/src/cdintf.cpp @@ -11,151 +11,28 @@ // JLH 01/16/2010 Created this log ;-) // -// -// This now uses the supposedly cross-platform libcdio to do the necessary -// low-level CD twiddling we need that libsdl can't do currently. Jury is -// still out on whether or not to make this a conditional compilation or not. -// - -// Comment this out if you don't have libcdio installed -// (Actually, this is defined in the Makefile to prevent having to edit -// things too damn much. Jury is still out whether or not to make this -// change permanent.) -//#define HAVE_LIB_CDIO - -#include "cdintf.h" // Every OS has to implement these - -#ifdef HAVE_LIB_CDIO -#include // Now using OS agnostic CD access routines! -#endif -#include "log.h" - - -/* -static void TestCDIO(void) -{ - // See what (if anything) is installed. - CdIo_t * p_cdio = cdio_open(0, DRIVER_DEVICE); - driver_id_t driver_id; - - if (p_cdio != NULL) - { - WriteLog("CDIO: The driver selected is %s.\n", cdio_get_driver_name(p_cdio)); - WriteLog("CDIO: The default device for this driver is %s.\n\n", cdio_get_default_device(p_cdio)); - cdio_destroy(p_cdio); - } - else - { - WriteLog("CDIO: A suitable CD-ROM driver was not found.\n\n"); - } -} -*/ - -// -// *** OK, here's where we're going to attempt to put the platform agnostic CD interface *** -// - -#ifdef HAVE_LIB_CDIO -static CdIo_t * cdioPtr = NULL; -#endif - +#include "cdintf.h" bool CDIntfInit(void) { -#ifdef HAVE_LIB_CDIO - cdioPtr = cdio_open(NULL, DRIVER_DEVICE); - - if (cdioPtr == NULL) - { -#endif - WriteLog("CDINTF: No suitable CD-ROM driver found.\n"); - return false; -#ifdef HAVE_LIB_CDIO - } - - WriteLog("CDINTF: Successfully opened CD-ROM interface.\n"); - - return true; -#endif -} - - -void CDIntfDone(void) -{ - WriteLog("CDINTF: Shutting down CD-ROM subsystem.\n"); - -#ifdef HAVE_LIB_CDIO - if (cdioPtr) - cdio_destroy(cdioPtr); -#endif -} - - -bool CDIntfReadBlock(uint32_t sector, uint8_t * buffer) -{ -#warning "!!! FIX !!! CDIntfReadBlock not implemented!" - // !!! FIX !!! - WriteLog("CDINTF: ReadBlock unimplemented!\n"); return false; } - -uint32_t CDIntfGetNumSessions(void) +void CDIntfDone(void) { -#warning "!!! FIX !!! CDIntfGetNumSessions not implemented!" - // !!! FIX !!! - // Still need relevant code here... !!! FIX !!! - return 2; } - -void CDIntfSelectDrive(uint32_t driveNum) +bool CDIntfReadBlock(uint32_t sector, uint8_t * buffer) { -#warning "!!! FIX !!! CDIntfSelectDrive not implemented!" - // !!! FIX !!! - WriteLog("CDINTF: SelectDrive unimplemented!\n"); + return false; } - -uint32_t CDIntfGetCurrentDrive(void) -{ -#warning "!!! FIX !!! CDIntfGetCurrentDrive not implemented!" - // !!! FIX !!! - WriteLog("CDINTF: GetCurrentDrive unimplemented!\n"); - return 0; -} - - -const uint8_t * CDIntfGetDriveName(uint32_t driveNum) -{ -#warning "!!! FIX !!! CDIntfGetDriveName driveNum is currently ignored!" - // driveNum is currently ignored... !!! FIX !!! - -#ifdef HAVE_LIB_CDIO - uint8_t * driveName = (uint8_t *)cdio_get_default_device(cdioPtr); - WriteLog("CDINTF: The drive name for the current driver is %s.\n", driveName); - - return driveName; -#else - return (uint8_t *)"NONE"; -#endif -} - - uint8_t CDIntfGetSessionInfo(uint32_t session, uint32_t offset) { -#warning "!!! FIX !!! CDIntfGetSessionInfo not implemented!" - // !!! FIX !!! - WriteLog("CDINTF: GetSessionInfo unimplemented!\n"); return 0xFF; } - uint8_t CDIntfGetTrackInfo(uint32_t track, uint32_t offset) { -#warning "!!! FIX !!! CDIntfTrackInfo not implemented!" - // !!! FIX !!! - WriteLog("CDINTF: GetTrackInfo unimplemented!\n"); return 0xFF; } - diff --git a/waterbox/virtualjaguar/src/cdintf.h b/waterbox/virtualjaguar/src/cdintf.h index 83c021b1e5..ebce8fa929 100644 --- a/waterbox/virtualjaguar/src/cdintf.h +++ b/waterbox/virtualjaguar/src/cdintf.h @@ -12,10 +12,6 @@ bool CDIntfInit(void); void CDIntfDone(void); bool CDIntfReadBlock(uint32_t, uint8_t *); -uint32_t CDIntfGetNumSessions(void); -void CDIntfSelectDrive(uint32_t); -uint32_t CDIntfGetCurrentDrive(void); -const uint8_t * CDIntfGetDriveName(uint32_t); uint8_t CDIntfGetSessionInfo(uint32_t, uint32_t); uint8_t CDIntfGetTrackInfo(uint32_t, uint32_t); diff --git a/waterbox/virtualjaguar/src/cdrom.cpp b/waterbox/virtualjaguar/src/cdrom.cpp index 8823d43c8e..c04fc3bf33 100644 --- a/waterbox/virtualjaguar/src/cdrom.cpp +++ b/waterbox/virtualjaguar/src/cdrom.cpp @@ -15,146 +15,10 @@ #include "cdrom.h" -#include // For memset, etc. -//#include "jaguar.h" // For GET32/SET32 macros -//#include "m68k.h" //??? -//#include "memory.h" -#include "cdintf.h" // System agnostic CD interface functions -#include "log.h" +#include +#include "cdintf.h" #include "dac.h" -//#define CDROM_LOG // For CDROM logging, obviously - -/* -BUTCH equ $DFFF00 ; base of Butch=interrupt control register, R/W -DSCNTRL equ BUTCH+4 ; DSA control register, R/W -DS_DATA equ BUTCH+$A ; DSA TX/RX data, R/W -I2CNTRL equ BUTCH+$10 ; i2s bus control register, R/W -SBCNTRL equ BUTCH+$14 ; CD subcode control register, R/W -SUBDATA equ BUTCH+$18 ; Subcode data register A -SUBDATB equ BUTCH+$1C ; Subcode data register B -SB_TIME equ BUTCH+$20 ; Subcode time and compare enable (D24) -FIFO_DATA equ BUTCH+$24 ; i2s FIFO data -I2SDAT1 equ BUTCH+$24 ; i2s FIFO data -I2SDAT2 equ BUTCH+$28 ; i2s FIFO data - equ BUTCH+$2C ; CD EEPROM interface - -; -; Butch's hardware registers -; -;BUTCH equ $DFFF00 ;base of Butch=interrupt control register, R/W -; -; When written (Long): -; -; bit0 - set to enable interrupts -; bit1 - enable CD data FIFO half full interrupt -; bit2 - enable CD subcode frame-time interrupt (@ 2x spped = 7ms.) -; bit3 - enable pre-set subcode time-match found interrupt -; bit4 - CD module command transmit buffer empty interrupt -; bit5 - CD module command receive buffer full -; bit6 - CIRC failure interrupt -; -; bit7-31 reserved, set to 0 -; -; When read (Long): -; -; bit0-8 reserved -; -; bit9 - CD data FIFO half-full flag pending -; bit10 - Frame pending -; bit11 - Subcode data pending -; bit12 - Command to CD drive pending (trans buffer empty if 1) -; bit13 - Response from CD drive pending (rec buffer full if 1) -; bit14 - CD uncorrectable data error pending -; -; Offsets from BUTCH -; -O_DSCNTRL equ 4 ; DSA control register, R/W -O_DS_DATA equ $A ; DSA TX/RX data, R/W -; -O_I2CNTRL equ $10 ; i2s bus control register, R/W -; -; When read: -; -; b0 - I2S data from drive is ON if 1 -; b1 - I2S path to Jerry is ON if 1 -; b2 - reserved -; b3 - host bus width is 16 if 1, else 32 -; b4 - FIFO state is not empty if 1 -; -O_SBCNTRL equ $14 ; CD subcode control register, R/W -O_SUBDATA equ $18 ; Subcode data register A -O_SUBDATB equ $1C ; Subcode data register B -O_SB_TIME equ $20 ; Subcode time and compare enable (D24) -O_FIFODAT equ $24 ; i2s FIFO data -O_I2SDAT2 equ $28 ; i2s FIFO data (old) -*/ - -/* -Commands sent through DS_DATA: - -$01nn - ? Play track nn ? Seek to track nn ? -$0200 - Stop CD -$03nn - Read session nn TOC (short) -$0400 - Pause CD -$0500 - Unpause CD -$10nn - Goto (min?) -$11nn - Goto (sec?) -$12nn - Goto (frm?) -$14nn - Read session nn TOC (full) -$15nn - Set CD mode -$18nn - Spin up CD to session nn -$5000 - ? -$5100 - Mute CD (audio mode only) -$51FF - Unmute CD (audio mode only) -$5400 - Read # of sessions on CD -$70nn - Set oversampling mode - -Commands send through serial bus: - -$100 - ? Acknowledge ? (Erase/Write disable) -$130 - ? (Seems to always prefix the $14n commands) (Erase/Write enable) -$140 - Returns ACK (1) (Write to NVRAM?) (Write selected register) -$141 - Returns ACK (1) -$142 - Returns ACK (1) -$143 - Returns ACK (1) -$144 - Returns ACK (1) -$145 - Returns ACK (1) -$180 - Returns 16-bit value (NVRAM?) (read from EEPROM) -$181 - Returns 16-bit value -$182 - Returns 16-bit value -$183 - Returns 16-bit value -$184 - Returns 16-bit value -$185 - Returns 16-bit value - -; The BUTCH interface for the CD-ROM module is a long-word register, -; where only the least signifigant 4 bits are used -; -eeprom equ $DFFF2c ;interface to CD-eeprom -; -; bit3 - busy if 0 after write cmd, or Data In after read cmd -; bit2 - Data Out -; bit1 - clock -; bit0 - Chip Select (CS) -; -; -; Commands specific to the National Semiconductor NM93C14 -; -; -; 9-bit commands.. -; 876543210 -eREAD equ %110000000 ;read from EEPROM -eEWEN equ %100110000 ;Erase/write Enable -eERASE equ %111000000 ;Erase selected register -eWRITE equ %101000000 ;Write selected register -eERAL equ %100100000 ;Erase all registers -eWRAL equ %100010000 ;Writes all registers -eEWDS equ %100000000 ;Erase/Write disable (default) - -So... are there $40 words of memory? 128 bytes? - -*/ - // Private function prototypes static void CDROMBusWrite(uint16_t); @@ -172,77 +36,16 @@ static uint16_t CDROMBusRead(void); #define I2SDAT2 BUTCH + 0x28 // i2s FIFO data (old) #define UNKNOWN BUTCH + 0x2C // Seems to be some sort of I2S interface -const char * BReg[12] = { "BUTCH", "DSCNTRL", "DS_DATA", "???", "I2CNTRL", - "SBCNTRL", "SUBDATA", "SUBDATB", "SB_TIME", "FIFO_DATA", "I2SDAT2", - "UNKNOWN" }; -//extern const char * whoName[9]; - - static uint8_t cdRam[0x100]; static uint16_t cdCmd = 0, cdPtr = 0; static bool haveCDGoodness; static uint32_t min, sec, frm, block; static uint8_t cdBuf[2352 + 96]; static uint32_t cdBufPtr = 2352; -//Also need to set up (save/restore) the CD's NVRAM - -//extern bool GetRawTOC(void); void CDROMInit(void) { haveCDGoodness = CDIntfInit(); - -//GetRawTOC(); -/*uint8_t buf[2448]; -uint32_t sec = 18667 - 150; -memset(buf, 0, 2448); -if (!CDIntfReadBlock(sec, buf)) -{ - WriteLog("CDROM: Attempt to read with subchannel data failed!\n"); - return; -} - -//24x98+96 -//96=4x24=4x4x6 -WriteLog("\nCDROM: Read sector %u...\n\n", sec); -for(int i=0; i<98; i++) -{ - WriteLog("%04X: ", i*24); - for(int j=0; j<24; j++) - { - WriteLog("%02X ", buf[j + (i*24)]); - } - WriteLog("\n"); -} -WriteLog("\nRaw P-W subchannel data:\n\n"); -for(int i=0; i<6; i++) -{ - WriteLog("%02X: ", i*16); - for(int j=0; j<16; j++) - { - WriteLog("%02X ", buf[2352 + j + (i*16)]); - } - WriteLog("\n"); -} -WriteLog("\nP subchannel data: "); -for(int i=0; i<96; i+=8) -{ - uint8_t b = 0; - for(int j=0; j<8; j++) - b |= ((buf[2352 + i + j] & 0x80) >> 7) << (7 - j); - - WriteLog("%02X ", b); -} -WriteLog("\nQ subchannel data: "); -for(int i=0; i<96; i+=8) -{ - uint8_t b = 0; - for(int j=0; j<8; j++) - b |= ((buf[2352 + i + j] & 0x40) >> 6) << (7 - j); - - WriteLog("%02X ", b); -} -WriteLog("\n\n");//*/ } void CDROMReset(void) @@ -256,7 +59,6 @@ void CDROMDone(void) CDIntfDone(); } - // // This approach is probably wrong, but let's do it for now. // What's needed is a complete overhaul of the interrupt system so that @@ -265,51 +67,20 @@ void CDROMDone(void) // void BUTCHExec(uint32_t cycles) { -#if 1 -// We're chickening out for now... -return; -#else -// extern uint8_t * jerry_ram_8; // Hmm. - - // For now, we just do the FIFO interrupt. Timing is also likely to be WRONG as well. - uint32_t cdState = GET32(cdRam, BUTCH); - - if (!(cdState & 0x01)) // No BUTCH interrupts enabled - return; - - if (!(cdState & 0x22)) - return; // For now, we only handle FIFO/buffer full interrupts... - - // From what I can make out, it seems that each FIFO is 32 bytes long - -// DSPSetIRQLine(DSPIRQ_EXT, ASSERT_LINE); -//I'm *sure* this is wrong--prolly need to generate DSP IRQs as well! - if (jerry_ram_8[0x23] & 0x3F) // Only generate an IRQ if enabled! - GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE); -#endif } - // // CD-ROM memory access functions // -uint8_t CDROMReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint8_t CDROMReadByte(uint32_t offset, uint32_t who) { -#ifdef CDROM_LOG - if ((offset & 0xFF) < 12 * 4) - WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]); - WriteLog("CDROM: %s reading byte $%02X from $%08X [68K PC=$%08X]\n", whoName[who], offset, cdRam[offset & 0xFF], m68k_get_reg(NULL, M68K_REG_PC)); -#endif return cdRam[offset & 0xFF]; } static uint8_t trackNum = 1, minTrack, maxTrack; -//static uint8_t minutes[16] = { 0, 0, 2, 5, 7, 10, 12, 15, 17, 20, 22, 25, 27, 30, 32, 35 }; -//static uint8_t seconds[16] = { 0, 0, 30, 0, 30, 0, 30, 0, 30, 0, 30, 0, 30, 0, 30, 0 }; -//static uint8_t frames[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -//static uint16_t sd = 0; -uint16_t CDROMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) + +uint16_t CDROMReadWord(uint32_t offset, uint32_t who) { offset &= 0xFF; @@ -318,165 +89,53 @@ uint16_t CDROMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) if (offset == BUTCH) data = 0x0000; else if (offset == BUTCH + 2) -// We need to fix this so it's not as brain-dead as it is now--i.e., make it so that when -// a command is sent to the CDROM, we control here whether or not it succeeded or whether -// the command is still being carried out, etc. - -// bit12 - Command to CD drive pending (trans buffer empty if 1) -// bit13 - Response from CD drive pending (rec buffer full if 1) -// data = (haveCDGoodness ? 0x3000 : 0x0000); // DSA RX Interrupt pending bit (0 = pending) -//This only returns ACKs for interrupts that are set: -//This doesn't work for the initial code that writes $180000 to BUTCH. !!! FIX !!! data = (haveCDGoodness ? cdRam[BUTCH + 3] << 8 : 0x0000); -// else if (offset == SUBDATA + 2) -// data = sd++ | 0x0010; // Have no idea what this is... else if (offset == DS_DATA && haveCDGoodness) { - if ((cdCmd & 0xFF00) == 0x0100) // ??? + if ((cdCmd & 0xFF00) == 0x0100) { -//Not sure how to acknowledge the ???... -// data = 0x0400;//?? 0x0200; cdPtr++; switch (cdPtr) { - case 1: - data = 0x0000; - break; - case 2: - data = 0x0100; - break; - case 3: - data = 0x0200; - break; - case 4: - data = 0x0300; - break; - case 5: - data = 0x0400; - }//*/ - //WriteLog("CDROM: Reading DS_DATA (???), cdCmd=$%04X\n", cdCmd); + case 1: + data = 0x0000; + break; + case 2: + data = 0x0100; + break; + case 3: + data = 0x0200; + break; + case 4: + data = 0x0300; + break; + case 5: + data = 0x0400; + } } - else if ((cdCmd & 0xFF00) == 0x0200) // Stop CD + else if ((cdCmd & 0xFF00) == 0x0200) { -//Not sure how to acknowledge the stop... - data = 0x0400;//?? 0x0200; -/* cdPtr++; - switch (cdPtr) - { - case 1: - data = 0x00FF; - break; - case 2: - data = 0x01FF; - break; - case 3: - data = 0x02FF; - break; - case 4: - data = 0x03FF; - break; - case 5: - data = 0x0400; - }//*/ - WriteLog("CDROM: Reading DS_DATA (stop), cdCmd=$%04X\n", cdCmd); + data = 0x0400; } - else if ((cdCmd & 0xFF00) == 0x0300) // Read session TOC (overview?) + else if ((cdCmd & 0xFF00) == 0x0300) { - -/* -TOC: [Sess] [adrCtl] [?] [point] [?] [?] [?] [?] [pmin] [psec] [pframe] -TOC: 1 10 00 a0 00:00:00 00 01:00:00 -TOC: 1 10 00 a1 00:00:00 00 01:00:00 -TOC: 1 10 00 a2 00:00:00 00 03:42:42 -TOC: 1 10 00 1 00:00:00 00 00:02:00 <-- Track #1 -TOC: 1 50 00 b0 06:12:42 02 79:59:74 -TOC: 1 50 00 c0 128:00:32 00 97:18:06 -TOC: 2 10 00 a0 00:00:00 00 02:00:00 -TOC: 2 10 00 a1 00:00:00 00 11:00:00 -TOC: 2 10 00 a2 00:00:00 00 54:32:18 -TOC: 2 10 00 2 00:00:00 00 06:14:42 <-- Track #2 -TOC: 2 10 00 3 00:00:00 00 06:24:42 <-- Track #3 -TOC: 2 10 00 4 00:00:00 00 17:42:00 <-- Track #4 -TOC: 2 10 00 5 00:00:00 00 22:26:15 <-- Track #5 -TOC: 2 10 00 6 00:00:00 00 29:50:16 <-- Track #6 -TOC: 2 10 00 7 00:00:00 00 36:01:49 <-- Track #7 -TOC: 2 10 00 8 00:00:00 00 40:37:59 <-- Track #8 -TOC: 2 10 00 9 00:00:00 00 45:13:70 <-- Track #9 -TOC: 2 10 00 a 00:00:00 00 49:50:06 <-- Track #10 -TOC: 2 10 00 b 00:00:00 00 54:26:17 <-- Track #11 -*/ - -//Should do something like so: -// data = GetSessionInfo(cdCmd & 0xFF, cdPtr); data = CDIntfGetSessionInfo(cdCmd & 0xFF, cdPtr); - if (data == 0xFF) // Failed... + if (data == 0xFF) { data = 0x0400; - WriteLog("CDROM: Requested invalid session #%u (or failed to load TOC, or bad cdPtr value)\n", cdCmd & 0xFF); } else { data |= (0x20 | cdPtr++) << 8; - WriteLog("CDROM: Reading DS_DATA (session #%u TOC byte #%u): $%04X\n", cdCmd & 0xFF, cdPtr, data); } - -/* bool isValidSession = ((cdCmd & 0xFF) == 0 ? true : false);//Hardcoded... !!! FIX !!! -//NOTE: This should return error condition if the requested session doesn't exist! ($0400?) - if (isValidSession) - { - cdPtr++; - switch (cdPtr) - { - case 1: - data = 0x2001; // Min track for this session? - break; - case 2: - data = 0x210A; // Max track for this session? - break; - case 3: - data = 0x2219; // Max lead-out time, absolute minutes - break; - case 4: - data = 0x2319; // Max lead-out time, absolute seconds - break; - case 5: - data = 0x2419; // Max lead-out time, absolute frames - break; - default: - data = 0xFFFF; - -//; +0 - unused, reserved (0) -//; +1 - unused, reserved (0) -//; +2 - minimum track number -//; +3 - maximum track number -//; +4 - total number of sessions -//; +5 - start of last lead-out time, absolute minutes -//; +6 - start of last lead-out time, absolute seconds -//; +7 - start of last lead-out time, absolute frames - - } - WriteLog("CDROM: Reading DS_DATA (session #%u TOC byte #%u): $%04X\n", cdCmd & 0xFF, cdPtr, data); - } - else - { - data = 0x0400; - WriteLog("CDROM: Requested invalid session #%u\n", cdCmd & 0xFF); - }*/ } - // Seek to m, s, or f position else if ((cdCmd & 0xFF00) == 0x1000 || (cdCmd & 0xFF00) == 0x1100 || (cdCmd & 0xFF00) == 0x1200) - data = 0x0100; // Success, though this doesn't take error handling into account. - // Ideally, we would also set the bits in BUTCH to let the processor know that - // this is ready to be read... !!! FIX !!! - else if ((cdCmd & 0xFF00) == 0x1400) // Read "full" session TOC + data = 0x0100; + else if ((cdCmd & 0xFF00) == 0x1400) { -//Need to be a bit more tricky here, since it's reading the "session" TOC instead of the -//full TOC--so we need to check for the min/max tracks for each session here... [DONE] - if (trackNum > maxTrack) { data = 0x400; -WriteLog("CDROM: Requested invalid track #%u for session #%u\n", trackNum, cdCmd & 0xFF); } else { @@ -485,79 +144,34 @@ WriteLog("CDROM: Requested invalid track #%u for session #%u\n", trackNum, cdCmd else if (cdPtr < 0x65) data = (cdPtr << 8) | CDIntfGetTrackInfo(trackNum, (cdPtr - 2) & 0x0F); -WriteLog("CDROM: Reading DS_DATA (session #%u, full TOC byte #%u): $%04X\n", cdCmd & 0xFF, (cdPtr+1) & 0x0F, data); - cdPtr++; if (cdPtr == 0x65) cdPtr = 0x60, trackNum++; } - - // Note that it seems to return track info in sets of 4 (or is it 5?) -/* -; +0 - track # (must be non-zero) -; +1 - absolute minutes (0..99), start of track -; +2 - absolute seconds (0..59), start of track -; +3 - absolute frames, (0..74), start of track -; +4 - session # (0..99) -; +5 - track duration minutes -; +6 - track duration seconds -; +7 - track duration frames -*/ - // Seems to be the following format: $60xx -> Track #xx - // $61xx -> min? (trk?) - // $62xx -> sec? (min?) - // $63xx -> frame? (sec?) - // $64xx -> ? (frame?) -/* cdPtr++; - switch (cdPtr) - { - case 1: - data = 0x6000 | trackNum; // Track # - break; - case 2: - data = 0x6100 | trackNum; // Track # (again?) - break; - case 3: - data = 0x6200 | minutes[trackNum]; // Minutes - break; - case 4: - data = 0x6300 | seconds[trackNum]; // Seconds - break; - case 5: - data = 0x6400 | frames[trackNum]; // Frames - trackNum++; - cdPtr = 0; - }//*/ } - else if ((cdCmd & 0xFF00) == 0x1500) // Read CD mode + else if ((cdCmd & 0xFF00) == 0x1500) { - data = cdCmd | 0x0200; // ?? not sure ?? [Seems OK] - WriteLog("CDROM: Reading DS_DATA (mode), cdCmd=$%04X\n", cdCmd); + data = cdCmd | 0x0200; } - else if ((cdCmd & 0xFF00) == 0x1800) // Spin up session # + else if ((cdCmd & 0xFF00) == 0x1800) { data = cdCmd; - WriteLog("CDROM: Reading DS_DATA (spin up session), cdCmd=$%04X\n", cdCmd); } - else if ((cdCmd & 0xFF00) == 0x5400) // Read # of sessions + else if ((cdCmd & 0xFF00) == 0x5400) { - data = cdCmd | 0x00; // !!! Hardcoded !!! FIX !!! - WriteLog("CDROM: Reading DS_DATA (# of sessions), cdCmd=$%04X\n", cdCmd); + data = cdCmd | 0x00; } - else if ((cdCmd & 0xFF00) == 0x7000) // Read oversampling + else if ((cdCmd & 0xFF00) == 0x7000) { -//NOTE: This setting will probably affect the # of DSP interrupts that need to happen. !!! FIX !!! data = cdCmd; - WriteLog("CDROM: Reading DS_DATA (oversampling), cdCmd=$%04X\n", cdCmd); } else { data = 0x0400; - WriteLog("CDROM: Reading DS_DATA, unhandled cdCmd=$%04X\n", cdCmd); } } else if (offset == DS_DATA && !haveCDGoodness) - data = 0x0400; // No CD interface present, so return error + data = 0x0400; else if (offset >= FIFO_DATA && offset <= FIFO_DATA + 3) { } @@ -567,117 +181,71 @@ WriteLog("CDROM: Reading DS_DATA (session #%u, full TOC byte #%u): $%04X\n", cdC else data = GET16(cdRam, offset); -//Returning $00000008 seems to cause it to use the starfield. Dunno why. -// It looks like it's getting the CD_mode this way... -//Temp, for testing... -//Very interesting...! Seems to control sumthin' or other... -/*if (offset == 0x2C || offset == 0x2E) - data = 0xFFFF;//*/ -/*if (offset == 0x2C) - data = 0x0000; -if (offset == 0x2E) - data = 0;//0x0008;//*/ if (offset == UNKNOWN + 2) data = CDROMBusRead(); -#ifdef CDROM_LOG - if ((offset & 0xFF) < 11 * 4) - WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]); - if (offset != UNKNOWN && offset != UNKNOWN + 2) - WriteLog("CDROM: %s reading word $%04X from $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC)); -#endif return data; } -void CDROMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) +void CDROMWriteByte(uint32_t offset, uint8_t data, uint32_t who) { offset &= 0xFF; cdRam[offset] = data; - -#ifdef CDROM_LOG - if ((offset & 0xFF) < 12 * 4) - WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]); - WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC)); -#endif } -void CDROMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) +void CDROMWriteWord(uint32_t offset, uint16_t data, uint32_t who) { offset &= 0xFF; SET16(cdRam, offset, data); - // Command register -//Lesse what this does... Seems to work OK...! if (offset == DS_DATA) { cdCmd = data; - if ((data & 0xFF00) == 0x0200) // Stop CD + if ((data & 0xFF00) == 0x0200) { cdPtr = 0; - WriteLog("CDROM: Stopping CD\n", data & 0xFF); } - else if ((data & 0xFF00) == 0x0300) // Read session TOC (short? overview?) + else if ((data & 0xFF00) == 0x0300) { cdPtr = 0; - WriteLog("CDROM: Reading TOC for session #%u\n", data & 0xFF); } -//Not sure how these three acknowledge... - else if ((data & 0xFF00) == 0x1000) // Seek to minute position + else if ((data & 0xFF00) == 0x1000) { min = data & 0x00FF; } - else if ((data & 0xFF00) == 0x1100) // Seek to second position + else if ((data & 0xFF00) == 0x1100) { sec = data & 0x00FF; } - else if ((data & 0xFF00) == 0x1200) // Seek to frame position + else if ((data & 0xFF00) == 0x1200) { frm = data & 0x00FF; block = (((min * 60) + sec) * 75) + frm; - cdBufPtr = 2352; // Ensure that SSI read will do so immediately - WriteLog("CDROM: Seeking to %u:%02u:%02u [block #%u]\n", min, sec, frm, block); + cdBufPtr = 2352; } - else if ((data & 0xFF00) == 0x1400) // Read "full" TOC for session + else if ((data & 0xFF00) == 0x1400) { cdPtr = 0x60, minTrack = CDIntfGetSessionInfo(data & 0xFF, 0), maxTrack = CDIntfGetSessionInfo(data & 0xFF, 1); trackNum = minTrack; - WriteLog("CDROM: Reading \"full\" TOC for session #%u (min=%u, max=%u)\n", data & 0xFF, minTrack, maxTrack); } - else if ((data & 0xFF00) == 0x1500) // Set CDROM mode + else if ((data & 0xFF00) == 0x1500) { - // Mode setting is as follows: bit 0 set -> single speed, bit 1 set -> double, - // bit 3 set -> multisession CD, bit 3 unset -> audio CD - WriteLog("CDROM: Setting mode $%02X\n", data & 0xFF); } - else if ((data & 0xFF00) == 0x1800) // Spin up session # + else if ((data & 0xFF00) == 0x1800) { - WriteLog("CDROM: Spinning up session #%u\n", data & 0xFF); } - else if ((data & 0xFF00) == 0x5400) // Read # of sessions + else if ((data & 0xFF00) == 0x5400) { - WriteLog("CDROM: Reading # of sessions\n", data & 0xFF); } - else if ((data & 0xFF00) == 0x7000) // Set oversampling rate + else if ((data & 0xFF00) == 0x7000) { - // 1 = none, 2 = 2x, 3 = 4x, 4 = 8x - uint32_t rates[5] = { 0, 1, 2, 4, 8 }; - WriteLog("CDROM: Setting oversample rate to %uX\n", rates[(data & 0xFF)]); } - else - WriteLog("CDROM: Unknown command $%04X\n", data); - }//*/ + } if (offset == UNKNOWN + 2) CDROMBusWrite(data); - -#ifdef CDROM_LOG - if ((offset & 0xFF) < 11 * 4) - WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]); - if (offset != UNKNOWN && offset != UNKNOWN + 2) - WriteLog("CDROM: %s writing word $%04X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC)); -#endif } // @@ -695,142 +263,87 @@ static bool firstTime = false; static void CDROMBusWrite(uint16_t data) { -//This is kinda lame. What we should do is check for a 0->1 transition on either bits 0 or 1... -//!!! FIX !!! - -#ifdef CDROM_LOG - if (data & 0xFFF0) - WriteLog("CDROM: BusWrite write on unknown line: $%04X\n", data); -#endif - switch (currentState) { - case ST_INIT: - currentState = ST_RISING; - break; - case ST_RISING: - if (data & 0x0001) // Command coming - { - cmdTx = true; - counter = 0; - busCmd = 0; - } - else - { - if (cmdTx) + case ST_INIT: + currentState = ST_RISING; + break; + case ST_RISING: + if (data & 0x0001) { - busCmd <<= 1; // Make room for next bit - busCmd |= (data & 0x04); // & put it in - counter++; - - if (counter == 9) - { - busCmd >>= 2; // Because we ORed bit 2, we need to shift right by 2 - cmdTx = false; - -//What it looks like: -//It seems that the $18x series reads from NVRAM while the -//$130, $14x, $100 series writes values to NVRAM... - if (busCmd == 0x180) - rxData = 0x0024;//1234; - else if (busCmd == 0x181) - rxData = 0x0004;//5678; - else if (busCmd == 0x182) - rxData = 0x0071;//9ABC; - else if (busCmd == 0x183) - rxData = 0xFF67;//DEF0; - else if (busCmd == 0x184) - rxData = 0xFFFF;//892F; - else if (busCmd == 0x185) - rxData = 0xFFFF;//8000; - else - rxData = 0x0001; -// rxData = 0x8349;//8000;//0F67; - - counter = 0; - firstTime = true; - txData = 0; -#ifdef CDROM_LOG - WriteLog("CDROM: *** BusWrite got command $%04X\n", busCmd); -#endif - } + cmdTx = true; + counter = 0; + busCmd = 0; } else { - txData = (txData << 1) | ((data & 0x04) >> 2); -//WriteLog("[%s]", data & 0x04 ? "1" : "0"); + if (cmdTx) + { + busCmd <<= 1; + busCmd |= (data & 0x04); + counter++; - rxDataBit = (rxData & 0x8000) >> 12; - rxData <<= 1; - counter++; -#ifdef CDROM_LOG - if (counter == 16) - WriteLog("CDROM: *** BusWrite got extra command $%04X\n", txData); -#endif + if (counter == 9) + { + busCmd >>= 2; + cmdTx = false; + + if (busCmd == 0x180) + rxData = 0x0024; + else if (busCmd == 0x181) + rxData = 0x0004; + else if (busCmd == 0x182) + rxData = 0x0071; + else if (busCmd == 0x183) + rxData = 0xFF67; + else if (busCmd == 0x184) + rxData = 0xFFFF; + else if (busCmd == 0x185) + rxData = 0xFFFF; + else + rxData = 0x0001; + + counter = 0; + firstTime = true; + txData = 0; + } + } + else + { + txData = (txData << 1) | ((data & 0x04) >> 2); + + rxDataBit = (rxData & 0x8000) >> 12; + rxData <<= 1; + counter++; + } } - } - currentState = ST_FALLING; - break; - case ST_FALLING: - currentState = ST_INIT; - break; + currentState = ST_FALLING; + break; + case ST_FALLING: + currentState = ST_INIT; + break; } } static uint16_t CDROMBusRead(void) { -// It seems the counter == 0 simply waits for a single bit acknowledge-- !!! FIX !!! -// Or does it? Hmm. It still "pumps" 16 bits through above, so how is this special? -// Seems to be because it sits and looks at it as if it will change. Dunno! -#ifdef CDROM_LOG - if ((counter & 0x0F) == 0) - { - if (counter == 0 && rxDataBit == 0) - { - if (firstTime) - { - firstTime = false; - WriteLog("0...\n"); - } - } - else - WriteLog("%s\n", rxDataBit ? "1" : "0"); - } - else - WriteLog("%s", rxDataBit ? "1" : "0"); -#endif - return rxDataBit; } -// -// This simulates a read from BUTCH over the SSI to JERRY. Uses real reading! -// -//temp, until I can fix my CD image... Argh! static uint8_t cdBuf2[2532 + 96], cdBuf3[2532 + 96]; -uint16_t GetWordFromButchSSI(uint32_t offset, uint32_t who/*= UNKNOWN*/) + +uint16_t GetWordFromButchSSI(uint32_t offset, uint32_t who) { bool go = ((offset & 0x0F) == 0x0A || (offset & 0x0F) == 0x0E ? true : false); if (!go) return 0x000; -// The problem comes in here. Really, we should generate the IRQ once we've stuffed -// our values into the DAC L/RRXD ports... -// But then again, the whole IRQ system needs an overhaul in order to make it more -// cycle accurate WRT to the various CPUs. Right now, it's catch-as-catch-can, which -// means that IRQs get serviced on scanline boundaries instead of when they occur. cdBufPtr += 2; if (cdBufPtr >= 2352) { -WriteLog("CDROM: %s reading block #%u...\n", whoName[who], block); - //No error checking. !!! FIX !!! -//NOTE: We have to subtract out the 1st track start as well (in cdintf_foo.cpp)! -// CDIntfReadBlock(block - 150, cdBuf); - -//Crappy kludge for shitty shit. Lesse if it works! CDIntfReadBlock(block - 150, cdBuf2); CDIntfReadBlock(block - 149, cdBuf3); for(int i=0; i<2352-4; i+=4) @@ -843,523 +356,34 @@ WriteLog("CDROM: %s reading block #%u...\n", whoName[who], block); cdBuf[2348] = cdBuf3[0]; cdBuf[2349] = cdBuf3[1]; cdBuf[2350] = cdBuf2[2350]; - cdBuf[2351] = cdBuf2[2351];//*/ + cdBuf[2351] = cdBuf2[2351]; block++, cdBufPtr = 0; } -/*extern bool doDSPDis; -if (block == 244968) - doDSPDis = true;//*/ - -WriteLog("[%04X:%01X]", GET16(cdBuf, cdBufPtr), offset & 0x0F); -if (cdBufPtr % 32 == 30) - WriteLog("\n"); - -// return GET16(cdBuf, cdBufPtr); -//This probably isn't endian safe... -// But then again... It seems that even though the data on the CD is organized as -// LL LH RL RH the way it expects to see the data is RH RL LH LL. -// D'oh! It doesn't matter *how* the data comes in, since it puts each sample into -// its own left or right side queue, i.e. it reads them 32 bits at a time and puts -// them into their L/R channel queues. It does seem, though, that it expects the -// right channel to be the upper 16 bits and the left to be the lower 16. return (cdBuf[cdBufPtr + 1] << 8) | cdBuf[cdBufPtr + 0]; } bool ButchIsReadyToSend(void) { -#ifdef LOG_CDROM_VERBOSE -WriteLog("Butch is%s ready to send...\n", cdRam[I2CNTRL + 3] & 0x02 ? "" : " not"); -#endif return (cdRam[I2CNTRL + 3] & 0x02 ? true : false); } -// -// This simulates a read from BUTCH over the SSI to JERRY. Uses real reading! -// void SetSSIWordsXmittedFromButch(void) { - -// The problem comes in here. Really, we should generate the IRQ once we've stuffed -// our values into the DAC L/RRXD ports... -// But then again, the whole IRQ system needs an overhaul in order to make it more -// cycle accurate WRT to the various CPUs. Right now, it's catch-as-catch-can, which -// means that IRQs get serviced on scanline boundaries instead of when they occur. - -// NOTE: The CD BIOS uses the following SMODE: -// DAC: M68K writing to SMODE. Bits: WSEN FALLING [68K PC=00050D8C] cdBufPtr += 4; if (cdBufPtr >= 2352) { -WriteLog("CDROM: Reading block #%u...\n", block); - //No error checking. !!! FIX !!! -//NOTE: We have to subtract out the 1st track start as well (in cdintf_foo.cpp)! -// CDIntfReadBlock(block - 150, cdBuf); - -//Crappy kludge for shitty shit. Lesse if it works! -//It does! That means my CD is WRONG! FUCK! - -// But, then again, according to Belboz at AA the two zeroes in front *ARE* necessary... -// So that means my CD is OK, just this method is wrong! -// It all depends on whether or not the interrupt occurs on the RISING or FALLING edge -// of the word strobe... !!! FIX !!! - -// When WS rises, left channel was done transmitting. When WS falls, right channel is done. -// CDIntfReadBlock(block - 150, cdBuf2); -// CDIntfReadBlock(block - 149, cdBuf3); CDIntfReadBlock(block, cdBuf2); CDIntfReadBlock(block + 1, cdBuf3); memcpy(cdBuf, cdBuf2 + 2, 2350); cdBuf[2350] = cdBuf3[0]; - cdBuf[2351] = cdBuf3[1];//*/ + cdBuf[2351] = cdBuf3[1]; block++, cdBufPtr = 0; - -/*extern bool doDSPDis; -static int foo = 0; -if (block == 244968) -{ - foo++; -WriteLog("\n***** foo = %u, block = %u *****\n\n", foo, block); - if (foo == 2) - doDSPDis = true; -}//*/ } - -WriteLog("[%02X%02X %02X%02X]", cdBuf[cdBufPtr+1], cdBuf[cdBufPtr+0], cdBuf[cdBufPtr+3], cdBuf[cdBufPtr+2]); -if (cdBufPtr % 32 == 28) - WriteLog("\n"); - -//This probably isn't endian safe... -// But then again... It seems that even though the data on the CD is organized as -// LL LH RL RH the way it expects to see the data is RH RL LH LL. -// D'oh! It doesn't matter *how* the data comes in, since it puts each sample into -// its own left or right side queue, i.e. it reads them 32 bits at a time and puts -// them into their L/R channel queues. It does seem, though, that it expects the -// right channel to be the upper 16 bits and the left to be the lower 16. - -// This behavior is strictly a function of *where* the WS creates an IRQ. If the data -// is shifted by two zeroes (00 00 in front of the data file) then this *is* the -// correct behavior, since the left channel will be xmitted followed by the right - -// Now we have definitive proof: The MYST CD shows a word offset. So that means we have -// to figure out how to make that work here *without* having to load 2 sectors, offset, etc. -// !!! FIX !!! lrxd = (cdBuf[cdBufPtr + 3] << 8) | cdBuf[cdBufPtr + 2], rrxd = (cdBuf[cdBufPtr + 1] << 8) | cdBuf[cdBufPtr + 0]; } - -/* -[18667] -TOC for MYST - -CDINTF: Disc summary - # of sessions: 2, # of tracks: 10 - Session info: - 1: min track= 1, max track= 1, lead out= 1:36:67 - 2: min track= 2, max track=10, lead out=55:24:71 - Track info: - 1: start= 0:02:00 - 2: start= 4:08:67 - 3: start= 4:16:65 - 4: start= 4:29:19 - 5: start=29:31:03 - 6: start=33:38:50 - 7: start=41:38:60 - 8: start=44:52:18 - 9: start=51:51:22 - 10: start=55:18:73 - -CDROM: Read sector 18517 (18667 - 150)... - -0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0078: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00A8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00D8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0108: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0138: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0168: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0198: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -01B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -01C8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -01E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -01F8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0228: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0258: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -02A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -02B8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -02D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -02E8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0318: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0348: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0378: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -03A8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -03C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -03D8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -03F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0408: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0438: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0468: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0498: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -04B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -04C8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -04E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -04F8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0528: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0558: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0588: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -05A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -05B8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -05D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -05E8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0618: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0648: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0678: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -06A8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -06C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -06D8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -06F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0708: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0738: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0768: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -0798: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -07B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -07C8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[54 41 49 52]54 41 -07E0: 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 -07F8: 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 -0810: 49 52 54 41 49 52[54 41 49 52]54 41 52 41 20 49 50 41 52 50 56 4F 44 45 -0828: 44 20 54 41 20 41 45 48 44 41 52 45 41 20 52 54 20 49[00 00 00 50]01 00 -0840: 80 83 FC 23 07 00 07 00 F0 00 0C 21 FC 23 07 00 07 00 F1 00 0C A1 FC 33 -0858: FF FF F0 00 4E 00 7C 2E 1F 00 FC FF 00 61 08 00 F9 4E 00 00 00 51 E7 48 -0870: 00 FE 39 30 F1 00 02 40 40 02 10 00 00 67 1C 00 79 42 01 00 8C D3 3C 34 -0888: 37 03 3C 30 81 05 3C 3C 0A 01 3C 38 F1 00 00 60 1A 00 FC 33 01 00 01 00 -08A0: 8C D3 3C 34 4B 03 3C 30 65 05 3C 3C 42 01 3C 38 1F 01 C0 33 01 00 88 D3 -08B8: C4 33 01 00 8A D3 00 32 41 E2 41 94 7C D4 04 00 7C 92 01 00 41 00 00 04 -08D0: C1 33 01 00 82 D3 C1 33 F0 00 3C 00 C2 33 01 00 80 D3 C2 33 F0 00 38 00 -08E8: C2 33 F0 00 3A 00 06 3A 44 9A C5 33 01 00 84 D3 44 DC C6 33 01 00 86 D3 -0900: F9 33 01 00 84 D3 F0 00 46 00 FC 33 FF FF F0 00 48 00 FC 23 00 00 00 00 -0918: F0 00 2A 00 FC 33 00 00 F0 00 58 00 DF 4C 7F 00 75 4E 00 00 00 00 00 00 - -Raw P-W subchannel data: - -00: 80 80 C0 80 80 80 80 C0 80 80 80 80 80 80 C0 80 -10: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 -20: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 C0 -30: 80 80 80 80 80 80 80 80 80 80 80 80 80 C0 80 80 -40: 80 80 80 80 C0 80 80 80 80 C0 C0 80 80 C0 C0 80 -50: C0 80 80 C0 C0 C0 80 80 C0 80 80 80 C0 80 80 80 - -P subchannel data: FF FF FF FF FF FF FF FF FF FF FF FF -Q subchannel data: 21 02 00 00 00 01 00 04 08 66 9C 88 - -Run address: $5000, Length: $18380 -*/ - - -/* -CD_read function from the CD BIOS: Note that it seems to direct the EXT1 interrupt -to the GPU--so that would mean *any* interrupt that BUTCH generates would be routed -to the GPU... - -read: - btst.l #31,d0 - bne.w .play - subq.l #4,a0 ; Make up for ISR pre-increment - move.l d0,-(sp) - move.l BUTCH,d0 - and.l #$ffff0000,d0 - move.l d0,BUTCH ; NO INTERRUPTS!!!!!!!!!!! - move.l (sp)+,d0 -; move.l #0,BUTCH - - move.w #$101,J_INT - - move.l d1,-(sp) - move.l I2CNTRL,d1 ;Read I2S Control Register - bclr #2,d1 ; Stop data - move.l d1,I2CNTRL - move.l (sp)+,d1 - - move.l PTRLOC,a2 - move.l a0,(a2)+ - move.l a1,(a2)+ - move.l #0,(a2)+ - - btst.b #7,INITTYPE - beq .not_bad - move.l PTRLOC,a0 - asl.l #5,d2 - - move.l d2,-(sp) - - or.l #$089a3c1a,d2 ; These instructions include the bclr - move.l d2,188(a0) - - move.l (sp)+,d2 - - swap d2 - or.l #$3c1a1838,d2 ; These instructions include the bclr - move.l d2,196(a0) - - move.l #16,(a2)+ - move.l d1,(a2) - -.not_bad: - - move.w DS_DATA,d1 ; Clear any pending DSARX states - move.l I2CNTRL,d1 ; Clear any pending errors - -; Drain the FIFO so that we don't get overloaded - -.dump: - move.l FIFO_DATA,d1 - move.l I2CNTRL,d1 - btst #4,d1 - bne.b .dump - -.butch_go: - move.l BUTCH,d1 - and.l #$FFFF0000,d1 - or.l #%000100001,d1 ;Enable DSARX interrupt - move.l d1,BUTCH -; move.l #%000100001,BUTCH ;Enable DSARX interrupt - -; Do a play @ - -.play: move.l d0,d1 ; mess with copy in d1 - lsr.l #8,d1 ; shift the byte over - lsr.w #8,d1 - or.w #$1000,d1 ; format it for goto - move.w d1,DS_DATA ; DSA tx - bsr.b DSA_tx - - move.l d0,d1 ; mess with copy in d1 - lsr.w #8,d1 - or.w #$1100,d1 ; format it for goto - move.w d1,DS_DATA ; DSA tx - bsr.b DSA_tx - - move.l d0,d1 ; mess with copy in d1 - and.w #$00FF,d1 ; mask for minutes - or.w #$1200,d1 ; format it for goto - move.w d1,DS_DATA ; DSA tx - bsr.b DSA_tx - - rts - - -**************************** -* Here's the GPU interrupt * -**************************** - -JERRY_ISR: - movei #G_FLAGS,r30 - load (r30),r29 ;read the flags - - movei #BUTCH,r24 - -make_ptr: - move pc,Ptrloc - movei #(make_ptr-PTRPOS),TEMP - sub TEMP,Ptrloc - -HERE: - move pc,r25 - movei #(EXIT_ISR-HERE),r27 - add r27,r25 - -; Is this a DSARX interrupt? - - load (r24),r27 ;check for DSARX int pending - btst #13,r27 - jr z,fifo_read ; This should ALWAYS fall thru the first time - -; Set the match bit, to allow data -; moveq #3,r26 ; enable FIFO only -; Don't just jam a value -; Clear the DSARX and set FIFO - bclr #5,r27 - bset #1,r27 - store r27,(r24) - addq #$10,r24 - load (r24),r27 - bset #2,r27 - store r27,(r24) ; Disable SUBCODE match - -; Now we clear the DSARX interrupt in Butch - - subq #12,r24 ; does what the above says - load (r24),r26 ;Clears DSA pending interrupt - addq #6,r24 - loadw (r24),r27 ; Read DSA response - btst #10,r27 ; Check for error - jr nz,error - or r26,r26 - jump (r25) -; nop - -fifo_read: -; Check for ERROR!!!!!!!!!!!!!!!!!!!!! - btst #14,r27 - jr z,noerror - bset #31,r27 -error: - addq #$10,r24 - load (r24),TEMP - or TEMP,TEMP - subq #$10,r24 - load (Ptrloc),TEMP - addq #8,Ptrloc - store TEMP,(Ptrloc) - subq #8,Ptrloc -noerror: - load (Ptrloc),Dataptr ;get pointer - -; Check to see if we should stop - addq #4,Ptrloc - load (Ptrloc),TEMP - subq #4,Ptrloc - cmp Dataptr,TEMP - jr pl,notend -; nop - bclr #0,r27 - store r27,(r24) - -notend: - movei #FIFO_DATA,CDdata - move CDdata,r25 - addq #4,CDdata -loptop: - load (CDdata),TEMP - load (r25),r30 - load (CDdata),r21 - load (r25),r22 - load (CDdata),r24 - load (r25),r20 - load (CDdata),r19 - load (r25),r18 - addq #4,Dataptr - store TEMP,(Dataptr) - addqt #4,Dataptr - store r30,(Dataptr) - addqt #4,Dataptr - store r21,(Dataptr) - addqt #4,Dataptr - store r22,(Dataptr) - addqt #4,Dataptr - store r24,(Dataptr) - addqt #4,Dataptr - store r20,(Dataptr) - addqt #4,Dataptr - store r19,(Dataptr) - addqt #4,Dataptr - store r18,(Dataptr) - - store Dataptr,(Ptrloc) - -exit_isr: - movei #J_INT,r24 ; Acknowledge in Jerry - moveq #1,TEMP - bset #8,TEMP - storew TEMP,(r24) - -.if FLAG -; Stack r18 - load (r31),r18 - addq #4,r31 - -; Stack r19 - load (r31),r19 - addq #4,r31 - -; Stack r20 - load (r31),r20 - addq #4,r31 - -; Stack r21 - load (r31),r21 - addq #4,r31 - -; Stack r22 - load (r31),r22 - addq #4,r31 - -; Stack r23 - load (r31),r23 - addq #4,r31 - -; Stack r26 - load (r31),r26 - addq #4,r31 - -; Stack r27 - load (r31),r27 - addq #4,r31 - -; Stack r24 - load (r31),r24 - addq #4,r31 - -; Stack r25 - load (r31),r25 - addq #4,r31 -.endif - - movei #G_FLAGS,r30 - -;r29 already has flags - bclr #3,r29 ;IMASK - bset #10,r29 ;Clear DSP int bit in TOM - - load (r31),r28 ;Load return address - - - addq #2,r28 ;Fix it up - addq #4,r31 - jump (r28) ;Return - store r29,(r30) ;Restore broken flags - - - align long - -stackbot: - ds.l 20 -STACK: - - -*/ - diff --git a/waterbox/virtualjaguar/src/cdrom.h b/waterbox/virtualjaguar/src/cdrom.h index c7d32b2716..6c0524d2a8 100644 --- a/waterbox/virtualjaguar/src/cdrom.h +++ b/waterbox/virtualjaguar/src/cdrom.h @@ -5,7 +5,6 @@ #ifndef __CDROM_H__ #define __CDROM_H__ -//#include "types.h" #include "memory.h" void CDROMInit(void); diff --git a/waterbox/virtualjaguar/src/crc32.cpp b/waterbox/virtualjaguar/src/crc32.cpp index 1886971ef7..9544a1986c 100644 --- a/waterbox/virtualjaguar/src/crc32.cpp +++ b/waterbox/virtualjaguar/src/crc32.cpp @@ -51,7 +51,6 @@ static unsigned long crctable[256] = 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL }; - int crc32_calcCheckSum(unsigned char * data, unsigned int length) { unsigned long crc = 0xFFFFFFFF; diff --git a/waterbox/virtualjaguar/src/dac.cpp b/waterbox/virtualjaguar/src/dac.cpp index 78bd4f8059..9a05bb9f1d 100644 --- a/waterbox/virtualjaguar/src/dac.cpp +++ b/waterbox/virtualjaguar/src/dac.cpp @@ -47,14 +47,9 @@ #include "event.h" #include "jerry.h" #include "jaguar.h" -#include "log.h" #include "m68000/m68kinterface.h" -//#include "memory.h" #include "settings.h" - -//#define DEBUG_DAC - #define BUFFER_SIZE 0x10000 // Make the DAC buffers 64K x 16 bits #define DAC_AUDIO_RATE 48000 // Set the audio rate to 48 KHz @@ -67,59 +62,29 @@ #define SCLK 0xF1A150 #define SMODE 0xF1A154 -// Global variables - -// These are defined in memory.h/cpp -//uint16_t lrxd, rrxd; // I2S ports (into Jaguar) - -// Local variables - -//static uint8_t SCLKFrequencyDivider = 19; // Default is roughly 22 KHz (20774 Hz in NTSC mode) -// /*static*/ uint16_t serialMode = 0; - // Private function prototypes void DSPSampleCallback(void); - -// -// Initialize the SDL sound system -// void DACInit(void) { ltxd = lrxd = 0; - sclk = 19; // Default is roughly 22 KHz + sclk = 19; uint32_t riscClockRate = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL); uint32_t cyclesPerSample = riscClockRate / DAC_AUDIO_RATE; - WriteLog("DAC: RISC clock = %u, cyclesPerSample = %u\n", riscClockRate, cyclesPerSample); } - // // Reset the sound buffer FIFOs // void DACReset(void) { -// LeftFIFOHeadPtr = LeftFIFOTailPtr = 0, RightFIFOHeadPtr = RightFIFOTailPtr = 1; ltxd = lrxd = 0; } - -// -// Pause/unpause the SDL audio thread -// -void DACPauseAudioThread(bool state/*= true*/) -{ -} - - -// -// Close down the SDL sound subsystem -// void DACDone(void) { - WriteLog("DAC: Done.\n"); } @@ -133,15 +98,17 @@ void DACDone(void) // If the DSP isn't running, then fill the buffer with L/RTXD and exit. // -// SDL callback routine to fill audio buffer +// Callback routine to fill audio buffer // // Note: The samples are packed in the buffer in 16 bit left/16 bit right pairs. // Also, length is the length of the buffer in BYTES // + static uint16_t * sampleBuffer; static int bufferIndex = 0; static int numberOfSamples = 0; static bool bufferDone = false; + void SoundCallback(uint16_t * buffer, int length) { // 1st, check to see if the DSP is running. If not, fill the buffer with L/RXTD and exit. @@ -157,37 +124,18 @@ void SoundCallback(uint16_t * buffer, int length) return; } - // The length of time we're dealing with here is 1/48000 s, so we multiply this - // by the number of cycles per second to get the number of cycles for one sample. -// uint32_t riscClockRate = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL); -// uint32_t cyclesPerSample = riscClockRate / DAC_AUDIO_RATE; - // This is the length of time -// timePerSample = (1000000.0 / (double)riscClockRate) * (); - - // Now, run the DSP for that length of time for each sample we need to make - bufferIndex = 0; sampleBuffer = buffer; -// If length is the length of the sample buffer in BYTES, then shouldn't the # of -// samples be / 4? No, because we bump the sample count by 2, so this is OK. + numberOfSamples = length / 2; bufferDone = false; SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY); - // These timings are tied to NTSC, need to fix that in event.cpp/h! [FIXED] do { double timeToNextEvent = GetTimeToNextEvent(EVENT_JERRY); - - if (vjs.DSPEnabled) - { - if (vjs.usePipelinedDSP) - DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); - else - DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); - } - + DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); HandleNextEvent(EVENT_JERRY); } while (!bufferDone); @@ -209,34 +157,16 @@ void DSPSampleCallback(void) SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY); } - -#if 0 -// -// Calculate the frequency of SCLK * 32 using the divider -// -int GetCalculatedFrequency(void) -{ - int systemClockFrequency = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL); - - // We divide by 32 here in order to find the frequency of 32 SCLKs in a row (transferring - // 16 bits of left data + 16 bits of right data = 32 bits, 1 SCLK = 1 bit transferred). - return systemClockFrequency / (32 * (2 * (SCLKFrequencyDivider + 1))); -} -#endif - - // // LTXD/RTXD/SCLK/SMODE ($F1A148/4C/50/54) // -void DACWriteByte(uint32_t offset, uint8_t data, uint32_t who/*= UNKNOWN*/) +void DACWriteByte(uint32_t offset, uint8_t data, uint32_t who) { - WriteLog("DAC: %s writing BYTE %02X at %08X\n", whoName[who], data, offset); if (offset == SCLK + 3) DACWriteWord(offset - 3, (uint16_t)data); } - -void DACWriteWord(uint32_t offset, uint16_t data, uint32_t who/*= UNKNOWN*/) +void DACWriteWord(uint32_t offset, uint16_t data, uint32_t who) { if (offset == LTXD + 2) { @@ -246,10 +176,8 @@ void DACWriteWord(uint32_t offset, uint16_t data, uint32_t who/*= UNKNOWN*/) { rtxd = data; } - else if (offset == SCLK + 2) // Sample rate + else if (offset == SCLK + 2) { - WriteLog("DAC: Writing %u to SCLK (by %s)...\n", data, whoName[who]); - sclk = data & 0xFF; JERRYI2SInterruptTimer = -1; RemoveCallback(JERRYI2SCallback); @@ -257,38 +185,20 @@ void DACWriteWord(uint32_t offset, uint16_t data, uint32_t who/*= UNKNOWN*/) } else if (offset == SMODE + 2) { -// serialMode = data; smode = data; - WriteLog("DAC: %s writing to SMODE. Bits: %s%s%s%s%s%s [68K PC=%08X]\n", whoName[who], - (data & 0x01 ? "INTERNAL " : ""), (data & 0x02 ? "MODE " : ""), - (data & 0x04 ? "WSEN " : ""), (data & 0x08 ? "RISING " : ""), - (data & 0x10 ? "FALLING " : ""), (data & 0x20 ? "EVERYWORD" : ""), - m68k_get_reg(NULL, M68K_REG_PC)); } } - // // LRXD/RRXD/SSTAT ($F1A148/4C/50) // -uint8_t DACReadByte(uint32_t offset, uint32_t who/*= UNKNOWN*/) +uint8_t DACReadByte(uint32_t offset, uint32_t who) { -// WriteLog("DAC: %s reading byte from %08X\n", whoName[who], offset); return 0xFF; } - -//static uint16_t fakeWord = 0; -uint16_t DACReadWord(uint32_t offset, uint32_t who/*= UNKNOWN*/) +uint16_t DACReadWord(uint32_t offset, uint32_t who) { -// WriteLog("DAC: %s reading word from %08X\n", whoName[who], offset); -// return 0xFFFF; -// WriteLog("DAC: %s reading WORD %04X from %08X\n", whoName[who], fakeWord, offset); -// return fakeWord++; -//NOTE: This only works if a bunch of things are set in BUTCH which we currently don't -// check for. !!! FIX !!! -// Partially fixed: We check for I2SCNTRL in the JERRY I2S routine... -// return GetWordFromButchSSI(offset, who); if (offset == LRXD || offset == RRXD) return 0x0000; else if (offset == LRXD + 2) @@ -296,6 +206,6 @@ uint16_t DACReadWord(uint32_t offset, uint32_t who/*= UNKNOWN*/) else if (offset == RRXD + 2) return rrxd; - return 0xFFFF; // May need SSTAT as well... (but may be a Jaguar II only feature) + return 0xFFFF; } diff --git a/waterbox/virtualjaguar/src/dac.h b/waterbox/virtualjaguar/src/dac.h index 52a9324dab..5515dcd665 100644 --- a/waterbox/virtualjaguar/src/dac.h +++ b/waterbox/virtualjaguar/src/dac.h @@ -9,9 +9,7 @@ void DACInit(void); void DACReset(void); -void DACPauseAudioThread(bool state = true); void DACDone(void); -//int GetCalculatedFrequency(void); // DAC memory access @@ -20,7 +18,6 @@ void DACWriteWord(uint32_t offset, uint16_t data, uint32_t who = UNKNOWN); uint8_t DACReadByte(uint32_t offset, uint32_t who = UNKNOWN); uint16_t DACReadWord(uint32_t offset, uint32_t who = UNKNOWN); - // DAC defines #define SMODE_INTERNAL 0x01 diff --git a/waterbox/virtualjaguar/src/dsp.cpp b/waterbox/virtualjaguar/src/dsp.cpp index 7ce82eef79..aec6800a40 100644 --- a/waterbox/virtualjaguar/src/dsp.cpp +++ b/waterbox/virtualjaguar/src/dsp.cpp @@ -22,175 +22,8 @@ #include "jagdasm.h" #include "jaguar.h" #include "jerry.h" -#include "log.h" #include "m68000/m68kinterface.h" -//#include "memory.h" - -// Seems alignment in loads & stores was off... -#define DSP_CORRECT_ALIGNMENT -//#define DSP_CORRECT_ALIGNMENT_STORE - -//#define DSP_DEBUG -//#define DSP_DEBUG_IRQ -//#define DSP_DEBUG_PL2 -//#define DSP_DEBUG_STALL -//#define DSP_DEBUG_CC -#define NEW_SCOREBOARD - -// Disassembly definitions - -#if 0 -#define DSP_DIS_ABS -#define DSP_DIS_ADD -#define DSP_DIS_ADDC -#define DSP_DIS_ADDQ -#define DSP_DIS_ADDQMOD -#define DSP_DIS_ADDQT -#define DSP_DIS_AND -#define DSP_DIS_BCLR -#define DSP_DIS_BSET -#define DSP_DIS_BTST -#define DSP_DIS_CMP -#define DSP_DIS_CMPQ -#define DSP_DIS_IMACN -#define DSP_DIS_IMULT -#define DSP_DIS_IMULTN -#define DSP_DIS_ILLEGAL -#define DSP_DIS_JR -#define DSP_DIS_JUMP -#define DSP_DIS_LOAD -#define DSP_DIS_LOAD14I -#define DSP_DIS_LOAD14R -#define DSP_DIS_LOAD15I -#define DSP_DIS_LOAD15R -#define DSP_DIS_LOADB -#define DSP_DIS_LOADW -#define DSP_DIS_MOVE -#define DSP_DIS_MOVEI -#define DSP_DIS_MOVEQ -#define DSP_DIS_MOVEFA -#define DSP_DIS_MOVEPC // Pipeline only! -#define DSP_DIS_MOVETA -#define DSP_DIS_MULT -#define DSP_DIS_NEG -#define DSP_DIS_NOP -#define DSP_DIS_NOT -#define DSP_DIS_OR -#define DSP_DIS_RESMAC -#define DSP_DIS_ROR -#define DSP_DIS_RORQ -#define DSP_DIS_SHARQ -#define DSP_DIS_SHLQ -#define DSP_DIS_SHRQ -#define DSP_DIS_STORE -#define DSP_DIS_STORE14I -#define DSP_DIS_STORE15I -#define DSP_DIS_STOREB -#define DSP_DIS_STOREW -#define DSP_DIS_SUB -#define DSP_DIS_SUBC -#define DSP_DIS_SUBQ -#define DSP_DIS_SUBQT -#define DSP_DIS_XOR -//*/ -bool doDSPDis = false; -//bool doDSPDis = true; -#endif -bool doDSPDis = false; -//#define DSP_DIS_JR -//#define DSP_DIS_JUMP - -/* -No dis yet: -+ subqt 4560 -+ mult 1472 -+ imultn 395024 -+ resmac 395024 -+ imacn 395024 -+ addqmod 93328 - -dsp opcodes use: -+ add 1672497 -+ addq 4366576 -+ addqt 44405640 -+ sub 94833 -+ subq 111769 -+ and 47416 -+ btst 94521 -+ bset 2277826 -+ bclr 3223372 -+ mult 47104 -+ imult 237080 -+ shlq 365464 -+ shrq 141624 -+ sharq 318368 -+ cmp 45175078 -+ move 2238994 -+ moveq 335305 -+ moveta 19 -+ movefa 47406440 -+ movei 1920664 -+ loadb 94832 -+ load 4031281 -+ load_r15_indexed 284500 -+ store 2161732 -+ store_r15_indexed 47416 -+ jump 3872424 -+ jr 46386967 -+ nop 3300029 -+ load_r14_ri 1229448 -*/ - -// Pipeline structures - -const bool affectsScoreboard[64] = -{ - true, true, true, true, - true, true, true, true, - true, true, true, true, - true, false, true, true, - - true, true, false, true, - false, true, true, true, - true, true, true, true, - true, true, false, false, - - true, true, true, true, - false, true, true, true, - true, true, true, true, - true, false, false, false, - - true, false, false, true, - false, false, true, true, - true, false, true, true, - false, false, false, true -}; - -struct PipelineStage -{ - uint16_t instruction; - uint8_t opcode, operand1, operand2; - uint32_t reg1, reg2, areg1, areg2; - uint32_t result; - uint8_t writebackRegister; - // General memory store... - uint32_t address; - uint32_t value; - uint8_t type; -}; - -#define TYPE_BYTE 0 -#define TYPE_WORD 1 -#define TYPE_DWORD 2 -#define PIPELINE_STALL 64 // Set to # of opcodes + 1 -#ifndef NEW_SCOREBOARD -bool scoreboard[32]; -#else -uint8_t scoreboard[32]; -#endif -uint8_t plPtrFetch, plPtrRead, plPtrExec, plPtrWrite; -PipelineStage pipeline[4]; bool IMASKCleared = false; // DSP flags (old--have to get rid of this crap) @@ -241,9 +74,6 @@ bool IMASKCleared = false; #define VERSION 0x0F000 #define INT_LAT5 0x10000 -extern uint32_t jaguar_mainRom_crc32; - -// Is opcode 62 *really* a NOP? Seems like it... static void dsp_opcode_abs(void); static void dsp_opcode_add(void); static void dsp_opcode_addc(void); @@ -309,24 +139,6 @@ static void dsp_opcode_subqmod(void); static void dsp_opcode_subqt(void); static void dsp_opcode_illegal(void); -/*uint8_t dsp_opcode_cycles[64] = -{ - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 1, 3, 1, 18, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 2, 2, 2, 3, 4, - 5, 4, 5, 6, 6, 1, 1, 1, - 1, 2, 2, 2, 1, 1, 9, 3, - 3, 1, 6, 6, 2, 2, 3, 3 -};//*/ -//Here's a QnD kludge... -//This is wrong, wrong, WRONG, but it seems to work for the time being... -//(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!) -//What's needed here is a way to take pipeline effects into account (including pipeline stalls!)... -// Yup, without cheating like this, the sound in things like Rayman, FACTS, & -// Tripper Getem get starved for time and sounds like crap. So we have to figure -// out how to fix that. :-/ uint8_t dsp_opcode_cycles[64] = { 1, 1, 1, 1, 1, 1, 1, 1, @@ -337,7 +149,7 @@ uint8_t dsp_opcode_cycles[64] = 2, 2, 2, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 3, 3, 1, 1, 1, 1 -};//*/ +}; void (* dsp_opcode[64])() = { @@ -359,31 +171,8 @@ void (* dsp_opcode[64])() = dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_illegal, dsp_opcode_addqmod, }; -uint32_t dsp_opcode_use[65]; - -const char * dsp_opcode_str[65]= -{ - "add", "addc", "addq", "addqt", - "sub", "subc", "subq", "subqt", - "neg", "and", "or", "xor", - "not", "btst", "bset", "bclr", - "mult", "imult", "imultn", "resmac", - "imacn", "div", "abs", "sh", - "shlq", "shrq", "sha", "sharq", - "ror", "rorq", "cmp", "cmpq", - "subqmod", "sat16s", "move", "moveq", - "moveta", "movefa", "movei", "loadb", - "loadw", "load", "sat32s", "load_r14_indexed", - "load_r15_indexed", "storeb", "storew", "store", - "mirror", "store_r14_indexed","store_r15_indexed","move_pc", - "jump", "jr", "mmult", "mtoi", - "normi", "nop", "load_r14_ri", "load_r15_ri", - "store_r14_ri", "store_r15_ri", "illegal", "addqmod", - "STALL" -}; - uint32_t dsp_pc; -static uint64_t dsp_acc; // 40 bit register, NOT 32! +static uint64_t dsp_acc; static uint32_t dsp_remain; static uint32_t dsp_modulo; static uint32_t dsp_flags; @@ -433,40 +222,13 @@ static uint8_t dsp_ram_8[0x2000]; static uint32_t dsp_in_exec = 0; static uint32_t dsp_releaseTimeSlice_flag = 0; -FILE * dsp_fp; - -#ifdef DSP_DEBUG_CC -// Comparison core vars (used only for core comparison! :-) -static uint64_t count = 0; -static uint8_t ram1[0x2000], ram2[0x2000]; -static uint32_t regs1[64], regs2[64]; -static uint32_t ctrl1[14], ctrl2[14]; -#endif - -// Private function prototypes - -void DSPDumpRegisters(void); -void DSPDumpDisassembly(void); -void FlushDSPPipeline(void); - - -void dsp_reset_stats(void) -{ - for(int i=0; i<65; i++) - dsp_opcode_use[i] = 0; -} - - void DSPReleaseTimeslice(void) { -//This does absolutely nothing!!! !!! FIX !!! dsp_releaseTimeSlice_flag = 1; } - void dsp_build_branch_condition_table(void) { - // Fill in the mirror table for(int i=0; i<65536; i++) { mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) @@ -479,7 +241,6 @@ void dsp_build_branch_condition_table(void) | ((i << 13) & 0x4000) | ((i << 15) & 0x8000); } - // Fill in the condition table for(int i=0; i<8; i++) { for(int j=0; j<32; j++) @@ -503,20 +264,8 @@ void dsp_build_branch_condition_table(void) } } - -uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint8_t DSPReadByte(uint32_t offset, uint32_t who) { - if (offset >= 0xF1A000 && offset <= 0xF1A0FF) - WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]); -// battlemorph -// if ((offset==0xF1CFE0)||(offset==0xF1CFE2)) -// return(0xffff); - // mutant penguin -/* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9)) - { - if (offset==0xF1CFE0) - return(0xff); - }*/ if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF)) return dsp_ram_8[offset - DSP_WORK_RAM_BASE]; @@ -537,19 +286,13 @@ uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) return JaguarReadByte(offset, who); } - -uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint16_t DSPReadWord(uint32_t offset, uint32_t who) { - if (offset >= 0xF1A000 && offset <= 0xF1A0FF) - WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]); - //??? offset &= 0xFFFFFFFE; if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF) { offset -= DSP_WORK_RAM_BASE; -/* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]); - return data;*/ return GET16(dsp_ram_8, offset); } else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset= 0xF1A000 && offset <= 0xF1A0FF) - WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]); - - // ??? WHY ??? offset &= 0xFFFFFFFC; -/*if (offset == 0xF1BCF4) -{ - WriteLog("DSPReadLong: Reading from 0xF1BCF4... -> %08X [%02X %02X %02X %02X][%04X %04X]\n", GET32(dsp_ram_8, 0x0CF4), dsp_ram_8[0x0CF4], dsp_ram_8[0x0CF5], dsp_ram_8[0x0CF6], dsp_ram_8[0x0CF7], JaguarReadWord(0xF1BCF4, DSP), JaguarReadWord(0xF1BCF6, DSP)); - DSPDumpDisassembly(); -}*/ + if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF) { offset -= DSP_WORK_RAM_BASE; return GET32(dsp_ram_8, offset); } -//NOTE: Didn't return DSP_ACCUM!!! -//Mebbe it's not 'spose to! Yes, it is! + if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23) { offset &= 0x3F; switch (offset) { - case 0x00: - dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z; - return dsp_flags & 0xFFFFC1FF; - case 0x04: return dsp_matrix_control; - case 0x08: return dsp_pointer_to_matrix; - case 0x0C: return dsp_data_organization; - case 0x10: return dsp_pc; - case 0x14: return dsp_control; - case 0x18: return dsp_modulo; - case 0x1C: return dsp_remain; - case 0x20: - return (int32_t)((int8_t)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended + case 0x00: + dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z; + return dsp_flags & 0xFFFFC1FF; + case 0x04: return dsp_matrix_control; + case 0x08: return dsp_pointer_to_matrix; + case 0x0C: return dsp_data_organization; + case 0x10: return dsp_pc; + case 0x14: return dsp_control; + case 0x18: return dsp_modulo; + case 0x1C: return dsp_remain; + case 0x20: + return (int32_t)((int8_t)(dsp_acc >> 32)); } - // unaligned long read-- !!! FIX !!! + return 0xFFFFFFFF; } return JaguarReadLong(offset, who); } - -void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) +void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who) { - if (offset >= 0xF1A000 && offset <= 0xF1A0FF) - WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]); - if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000)) { offset -= DSP_WORK_RAM_BASE; dsp_ram_8[offset] = data; -//This is rather stupid! !!! FIX !!! -/* if (dsp_in_exec == 0) - { - m68k_end_timeslice(); - dsp_releaseTimeslice(); - }*/ return; } if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20)) @@ -637,53 +360,26 @@ void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3)); else { -//This looks funky. !!! FIX !!! uint32_t old_data = DSPReadLong(offset&0xFFFFFFC, who); - bytenum = 3 - bytenum; // convention motorola !!! + bytenum = 3 - bytenum; old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3)); DSPWriteLong(offset & 0xFFFFFFC, old_data, who); } return; } -// WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset); -//Should this *ever* happen??? Shouldn't we be saying "unknown" here??? -// Well, yes, it can. There are 3 MMU users after all: 68K, GPU & DSP...! + JaguarWriteByte(offset, data, who); } - -void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) +void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who) { - if (offset >= 0xF1A000 && offset <= 0xF1A0FF) - WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]); offset &= 0xFFFFFFFE; -/*if (offset == 0xF1BCF4) -{ - WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data); -}*/ -// WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset); + if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000)) { -/*if (offset == 0xF1B2F4) -{ - WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc); -}//*/ offset -= DSP_WORK_RAM_BASE; dsp_ram_8[offset] = data >> 8; dsp_ram_8[offset+1] = data & 0xFF; -//This is rather stupid! !!! FIX !!! -/* if (dsp_in_exec == 0) - { -// WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE); - m68k_end_timeslice(); - dsp_releaseTimeslice(); - }*/ -//CC only! -#ifdef DSP_DEBUG_CC -SET16(ram1, offset, data), -SET16(ram2, offset, data); -#endif -//!!!!!!!! return; } else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20)) @@ -713,33 +409,14 @@ SET16(ram2, offset, data); JaguarWriteWord(offset, data, who); } - -//bool badWrite = false; -void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/) +void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who) { - if (offset >= 0xF1A000 && offset <= 0xF1A0FF) - WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]); - // ??? WHY ??? offset &= 0xFFFFFFFC; -/*if (offset == 0xF1BCF4) -{ - WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data); -}*/ -// WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset); + if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF) { -/*if (offset == 0xF1BE2C) -{ - WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2); -}//*/ offset -= DSP_WORK_RAM_BASE; SET32(dsp_ram_8, offset, data); -//CC only! -#ifdef DSP_DEBUG_CC -SET32(ram1, offset, data), -SET32(ram2, offset, data); -#endif -//!!!!!!!! return; } else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F)) @@ -747,154 +424,79 @@ SET32(ram2, offset, data); offset &= 0x1F; switch (offset) { - case 0x00: - { -#ifdef DSP_DEBUG - WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not ")); -#endif -// bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK); - IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK); - // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the - // IRQ logic can set it. So we mask it out here to prevent problems... - dsp_flags = data & (~IMASK); - dsp_flag_z = dsp_flags & 0x01; - dsp_flag_c = (dsp_flags >> 1) & 0x01; - dsp_flag_n = (dsp_flags >> 2) & 0x01; - DSPUpdateRegisterBanks(); - dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3); - dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1); - break; - } - case 0x04: - dsp_matrix_control = data; - break; - case 0x08: - // According to JTRM, only lines 2-11 are addressable, the rest being - // hardwired to $F1Bxxx. - dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC); - break; - case 0x0C: - dsp_data_organization = data; - break; - case 0x10: - dsp_pc = data; -#ifdef DSP_DEBUG - WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/ -#endif -//CC only! -#ifdef DSP_DEBUG_CC -if (who != DSP) - ctrl1[0] = ctrl2[0] = data; -#endif -//!!!!!!!! - break; - case 0x14: - { -//#ifdef DSP_DEBUG -WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc); -//#endif - bool wasRunning = DSP_RUNNING; -// uint32_t dsp_was_running = DSP_RUNNING; - // Check for DSP -> CPU interrupt - if (data & CPUINT) + case 0x00: { -#ifdef DSP_DEBUG - WriteLog("DSP: DSP -> CPU interrupt\n"); -#endif + IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK); -#warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!" - if (JERRYIRQEnabled(IRQ2_DSP)) + dsp_flags = data & (~IMASK); + dsp_flag_z = dsp_flags & 0x01; + dsp_flag_c = (dsp_flags >> 1) & 0x01; + dsp_flag_n = (dsp_flags >> 2) & 0x01; + DSPUpdateRegisterBanks(); + dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3); + dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1); + break; + } + case 0x04: + dsp_matrix_control = data; + break; + case 0x08: + dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC); + break; + case 0x0C: + dsp_data_organization = data; + break; + case 0x10: + dsp_pc = data; + break; + case 0x14: + { + bool wasRunning = DSP_RUNNING; + if (data & CPUINT) { - JERRYSetPendingIRQ(IRQ2_DSP); - DSPReleaseTimeslice(); - m68k_set_irq(2); // Set 68000 IPL 2... + if (JERRYIRQEnabled(IRQ2_DSP)) + { + JERRYSetPendingIRQ(IRQ2_DSP); + DSPReleaseTimeslice(); + m68k_set_irq(2); + } + data &= ~CPUINT; } - data &= ~CPUINT; - } - // Check for CPU -> DSP interrupt - if (data & DSPINT0) - { -#ifdef DSP_DEBUG - WriteLog("DSP: CPU -> DSP interrupt\n"); -#endif - m68k_end_timeslice(); - DSPReleaseTimeslice(); - DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE); - data &= ~DSPINT0; - } - // single stepping - if (data & SINGLE_STEP) - { -// WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not ")); - } - // Protect writes to VERSION and the interrupt latches... - uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5; - dsp_control = (dsp_control & mask) | (data & ~mask); -//CC only! -#ifdef DSP_DEBUG_CC -if (who != DSP) - ctrl1[8] = ctrl2[8] = dsp_control; -#endif -//!!!!!!!! - - // if dsp wasn't running but is now running - // execute a few cycles -//This is just plain wrong, wrong, WRONG! -#ifndef DSP_SINGLE_STEPPING -/* if (!dsp_was_running && DSP_RUNNING) - { - DSPExec(200); - }*/ -#else -//This is WRONG! !!! FIX !!! - if (dsp_control & 0x18) - DSPExec(1); -#endif -#ifdef DSP_DEBUG -if (DSP_RUNNING) - WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]); -else - WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc); -WriteLog("\n"); -#endif // DSP_DEBUG -//This isn't exactly right either--we don't know if it was the M68K or the DSP writing here... -// !!! FIX !!! [DONE] - if (DSP_RUNNING) - { - if (who == M68K) + if (data & DSPINT0) + { m68k_end_timeslice(); - else if (who == DSP) DSPReleaseTimeslice(); + DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE); + data &= ~DSPINT0; + } - if (!wasRunning) - FlushDSPPipeline(); -//DSPDumpDisassembly(); + uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5; + dsp_control = (dsp_control & mask) | (data & ~mask); + + if (DSP_RUNNING) + { + if (who == M68K) + m68k_end_timeslice(); + else if (who == DSP) + DSPReleaseTimeslice(); + } + break; } - break; - } - case 0x18: -WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]); - dsp_modulo = data; - break; - case 0x1C: - dsp_div_control = data; - break; -// default: // unaligned long read - //__asm int 3 + case 0x18: + dsp_modulo = data; + break; + case 0x1C: + dsp_div_control = data; + break; } + return; } -//We don't have to break this up like this! We CAN do 32 bit writes! -// JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP); -// JaguarWriteWord(offset+2, data & 0xFFFF, DSP); -//if (offset > 0xF1FFFF) -// badWrite = true; JaguarWriteLong(offset, data, who); } - // // Update the DSP register file pointers depending on REGPAGE bit // @@ -909,200 +511,25 @@ void DSPUpdateRegisterBanks(void) dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0; else dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1; - -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0")); -#endif } - // // Check for and handle any asserted DSP IRQs // -void DSPHandleIRQs(void) -{ - if (dsp_flags & IMASK) // Bail if we're already inside an interrupt - return; - - // Get the active interrupt bits (latches) & interrupt mask (enables) - uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F), - mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F); - -// WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask); - bits &= mask; - - if (!bits) // Bail if nothing is enabled - return; - - int which = 0; // Determine which interrupt - - if (bits & 0x01) - which = 0; - if (bits & 0x02) - which = 1; - if (bits & 0x04) - which = 2; - if (bits & 0x08) - which = 3; - if (bits & 0x10) - which = 4; - if (bits & 0x20) - which = 5; - -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Generating interrupt #%i...", which); -#endif -//temp... !!!!! -//if (which == 0) doDSPDis = true; - - // NOTE: Since the actual Jaguar hardware injects the code sequence below - // directly into the pipeline, it has the side effect of ensuring that the - // instruction interrupted also gets to do its writeback. We simulate that - // behavior here. -/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - scoreboard[pipeline[plPtrWrite].operand2] = false; - }//*/ -//This should be execute (or should it?--not sure now!) -//Actually, the way this is called now, this should be correct (i.e., the plPtrs advance, -//and what just executed is now in the Write position...). So why didn't it do the -//writeback into register 0? -#ifdef DSP_DEBUG_IRQ -WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]); -#endif - if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFE) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - else - { - if (pipeline[plPtrWrite].type == TYPE_BYTE) - JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else if (pipeline[plPtrWrite].type == TYPE_WORD) - JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else - JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - } - } - -#ifndef NEW_SCOREBOARD - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - scoreboard[pipeline[plPtrWrite].operand2] = false; -#else -//Yup, sequential MOVEQ # problem fixing (I hope!)... - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - if (scoreboard[pipeline[plPtrWrite].operand2]) - scoreboard[pipeline[plPtrWrite].operand2]--; -#endif - } - - dsp_flags |= IMASK; -//CC only! -#ifdef DSP_DEBUG_CC -ctrl2[4] = dsp_flags; -#endif -//!!!!!!!! - DSPUpdateRegisterBanks(); -#ifdef DSP_DEBUG_IRQ -// WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]); - WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), dsp_reg[31]); -#endif - - // subqt #4,r31 ; pre-decrement stack pointer - // move pc,r30 ; address of interrupted code - // store r30,(r31) ; store return address - dsp_reg[31] -= 4; -//CC only! -#ifdef DSP_DEBUG_CC -regs2[31] -= 4; -#endif -//!!!!!!!! -//This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!! -//But, then again, JTRM says that it adds two regardless of what the instruction was... -//It missed the place that it was supposed to come back to, so this is WRONG! -// -// Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz): -// -// R -> baz (<- PC points here) -// E -> bar (when it should point here!) -// W -> foo -// -// 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz' -// which means (assuming they're all 2 bytes long) that the code below will come back on -// instruction 'baz' instead of 'bar' which is the next instruction to execute in the -// instruction stream... - -// DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP); - DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP); -//CC only! -#ifdef DSP_DEBUG_CC -SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2))); -#endif -//!!!!!!!! - - // movei #service_address,r30 ; pointer to ISR entry - // jump (r30) ; jump to ISR - // nop - dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10); -//CC only! -#ifdef DSP_DEBUG_CC -ctrl2[0] = regs2[30] = dsp_pc; -#endif -//!!!!!!!! - FlushDSPPipeline(); -} - - -// -// Non-pipelined version... -// void DSPHandleIRQsNP(void) { -//CC only! -#ifdef DSP_DEBUG_CC - memcpy(dsp_ram_8, ram1, 0x2000); - memcpy(dsp_reg_bank_0, regs1, 32 * 4); - memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4); - dsp_pc = ctrl1[0]; - dsp_acc = ctrl1[1]; - dsp_remain = ctrl1[2]; - dsp_modulo = ctrl1[3]; - dsp_flags = ctrl1[4]; - dsp_matrix_control = ctrl1[5]; - dsp_pointer_to_matrix = ctrl1[6]; - dsp_data_organization = ctrl1[7]; - dsp_control = ctrl1[8]; - dsp_div_control = ctrl1[9]; - IMASKCleared = ctrl1[10]; - dsp_flag_z = ctrl1[11]; - dsp_flag_n = ctrl1[12]; - dsp_flag_c = ctrl1[13]; -DSPUpdateRegisterBanks(); -#endif -//!!!!!!!! - if (dsp_flags & IMASK) // Bail if we're already inside an interrupt + if (dsp_flags & IMASK) return; - // Get the active interrupt bits (latches) & interrupt mask (enables) uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F), mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F); -// WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask); bits &= mask; - if (!bits) // Bail if nothing is enabled + if (!bits) return; - int which = 0; // Determine which interrupt + int which = 0; if (bits & 0x01) which = 0; if (bits & 0x02) @@ -1116,110 +543,44 @@ DSPUpdateRegisterBanks(); if (bits & 0x20) which = 5; - dsp_flags |= IMASK; // Force Bank #0 -//CC only! -#ifdef DSP_DEBUG_CC -ctrl1[4] = dsp_flags; -#endif -//!!!!!!!! -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]); - WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]); -#endif + dsp_flags |= IMASK; + DSPUpdateRegisterBanks(); -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]); - WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]); -#endif -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Generating interrupt #%i...", which); - WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]); -#endif - - // subqt #4,r31 ; pre-decrement stack pointer - // move pc,r30 ; address of interrupted code - // store r30,(r31) ; store return address dsp_reg[31] -= 4; - dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already + dsp_reg[30] = dsp_pc - 2; -//CC only! -#ifdef DSP_DEBUG_CC -regs1[31] -= 4; -#endif -//!!!!!!!! -// DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP); DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP); -//CC only! -#ifdef DSP_DEBUG_CC -SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2); -#endif -//!!!!!!!! - // movei #service_address,r30 ; pointer to ISR entry - // jump (r30) ; jump to ISR - // nop dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10); -//CC only! -#ifdef DSP_DEBUG_CC -ctrl1[0] = regs1[30] = dsp_pc; -#endif -//!!!!!!!! } - // // Set the specified DSP IRQ line to a given state // void DSPSetIRQLine(int irqline, int state) { -//NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!! uint32_t mask = INT_LAT0 << irqline; - dsp_control &= ~mask; // Clear the latch bit -//CC only! -#ifdef DSP_DEBUG_CC -ctrl1[8] = ctrl2[8] = dsp_control; -#endif -//!!!!!!!! + dsp_control &= ~mask; if (state) { - dsp_control |= mask; // Set the latch bit -#warning !!! No checking done to see if we are using pipelined DSP or not !!! -// DSPHandleIRQs(); + dsp_control |= mask; DSPHandleIRQsNP(); -//CC only! -#ifdef DSP_DEBUG_CC -ctrl1[8] = ctrl2[8] = dsp_control; -DSPHandleIRQsNP(); -#endif -//!!!!!!!! } - - // Not sure if this is correct behavior, but according to JTRM, - // the IRQ output of JERRY is fed to this IRQ in the GPU... -// Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts! -// GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE); } - bool DSPIsRunning(void) { return (DSP_RUNNING ? true : false); } - void DSPInit(void) { -// memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM"); -// memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs"); -// memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs"); - dsp_build_branch_condition_table(); DSPReset(); } - void DSPReset(void) { dsp_pc = 0x00F1B000; @@ -1230,7 +591,7 @@ void DSPReset(void) dsp_matrix_control = 0x00000000; dsp_pointer_to_matrix = 0x00000000; dsp_data_organization = 0xFFFFFFFF; - dsp_control = 0x00002000; // Report DSP version 2 + dsp_control = 0x00002000; dsp_div_control = 0x00000000; dsp_in_exec = 0; @@ -1242,1135 +603,336 @@ void DSPReset(void) CLR_ZNC; IMASKCleared = false; - FlushDSPPipeline(); - dsp_reset_stats(); - // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents for(uint32_t i=0; i<8192; i+=4) *((uint32_t *)(&dsp_ram_8[i])) = rand(); } - -void DSPDumpDisassembly(void) -{ - char buffer[512]; - - WriteLog("\n---[DSP code at 00F1B000]---------------------------\n"); - uint32_t j = 0xF1B000; - - while (j <= 0xF1CFFF) - { - uint32_t oldj = j; - j += dasmjag(JAGUAR_DSP, buffer, j); - WriteLog("\t%08X: %s\n", oldj, buffer); - } -} - - -void DSPDumpRegisters(void) -{ -//Shoud add modulus, etc to dump here... - WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc); - WriteLog("\nRegisters bank 0\n"); - - for(int j=0; j<8; j++) - { - WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", - (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0], - (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1], - (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2], - (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]); - } - - WriteLog("Registers bank 1\n"); - - for(int j=0; j<8; j++) - { - WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", - (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0], - (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1], - (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2], - (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]); - } -} - - void DSPDone(void) { - WriteLog("\n\n---------------------------------------------------------------------\n"); - WriteLog("DSP I/O Registers\n"); - WriteLog("---------------------------------------------------------------------\n"); - WriteLog("F1%04X (D_FLAGS): $%06X\n", 0xA100, (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z); - WriteLog("F1%04X (D_MTXC): $%04X\n", 0xA104, dsp_matrix_control); - WriteLog("F1%04X (D_MTXA): $%04X\n", 0xA108, dsp_pointer_to_matrix); - WriteLog("F1%04X (D_END): $%02X\n", 0xA10C, dsp_data_organization); - WriteLog("F1%04X (D_PC): $%06X\n", 0xA110, dsp_pc); - WriteLog("F1%04X (D_CTRL): $%06X\n", 0xA114, dsp_control); - WriteLog("F1%04X (D_MOD): $%08X\n", 0xA118, dsp_modulo); - WriteLog("F1%04X (D_REMAIN): $%08X\n", 0xA11C, dsp_remain); - WriteLog("F1%04X (D_DIVCTRL): $%02X\n", 0xA11C, dsp_div_control); - WriteLog("F1%04X (D_MACHI): $%02X\n", 0xA120, (dsp_acc >> 32) & 0xFF); - WriteLog("---------------------------------------------------------------------\n\n\n"); - - WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't")); - WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not ")); - - // Get the active interrupt bits - int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F); - // Get the interrupt mask - int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F); - - WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask, - (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""), - (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""), - (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : "")); - DSPDumpRegisters(); - WriteLog("\n"); - - static char buffer[512]; - int j = DSP_WORK_RAM_BASE; - - while (j <= 0xF1CFFF) - { - uint32_t oldj = j; - j += dasmjag(JAGUAR_DSP, buffer, j); - WriteLog("\t%08X: %s\n", oldj, buffer); - } - - WriteLog("DSP opcodes use:\n"); - - for(int i=0; i<64; i++) - { - if (dsp_opcode_use[i]) - WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]); - } } - - -// -// DSP comparison core... -// -#ifdef DSP_DEBUG_CC -static uint16_t lastExec; -void DSPExecComp(int32_t cycles) -{ - while (cycles > 0 && DSP_RUNNING) - { - // Load up vars for non-pipelined core - memcpy(dsp_ram_8, ram1, 0x2000); - memcpy(dsp_reg_bank_0, regs1, 32 * 4); - memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4); - dsp_pc = ctrl1[0]; - dsp_acc = ctrl1[1]; - dsp_remain = ctrl1[2]; - dsp_modulo = ctrl1[3]; - dsp_flags = ctrl1[4]; - dsp_matrix_control = ctrl1[5]; - dsp_pointer_to_matrix = ctrl1[6]; - dsp_data_organization = ctrl1[7]; - dsp_control = ctrl1[8]; - dsp_div_control = ctrl1[9]; - IMASKCleared = ctrl1[10]; - dsp_flag_z = ctrl1[11]; - dsp_flag_n = ctrl1[12]; - dsp_flag_c = ctrl1[13]; -DSPUpdateRegisterBanks(); - - // Decrement cycles based on non-pipelined core... - uint16_t instr1 = DSPReadWord(dsp_pc, DSP); - cycles -= dsp_opcode_cycles[instr1 >> 10]; - -//WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc); - DSPExec(1); // Do *one* instruction - - // Save vars - memcpy(ram1, dsp_ram_8, 0x2000); - memcpy(regs1, dsp_reg_bank_0, 32 * 4); - memcpy(®s1[32], dsp_reg_bank_1, 32 * 4); - ctrl1[0] = dsp_pc; - ctrl1[1] = dsp_acc; - ctrl1[2] = dsp_remain; - ctrl1[3] = dsp_modulo; - ctrl1[4] = dsp_flags; - ctrl1[5] = dsp_matrix_control; - ctrl1[6] = dsp_pointer_to_matrix; - ctrl1[7] = dsp_data_organization; - ctrl1[8] = dsp_control; - ctrl1[9] = dsp_div_control; - ctrl1[10] = IMASKCleared; - ctrl1[11] = dsp_flag_z; - ctrl1[12] = dsp_flag_n; - ctrl1[13] = dsp_flag_c; - - // Load up vars for pipelined core - memcpy(dsp_ram_8, ram2, 0x2000); - memcpy(dsp_reg_bank_0, regs2, 32 * 4); - memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4); - dsp_pc = ctrl2[0]; - dsp_acc = ctrl2[1]; - dsp_remain = ctrl2[2]; - dsp_modulo = ctrl2[3]; - dsp_flags = ctrl2[4]; - dsp_matrix_control = ctrl2[5]; - dsp_pointer_to_matrix = ctrl2[6]; - dsp_data_organization = ctrl2[7]; - dsp_control = ctrl2[8]; - dsp_div_control = ctrl2[9]; - IMASKCleared = ctrl2[10]; - dsp_flag_z = ctrl2[11]; - dsp_flag_n = ctrl2[12]; - dsp_flag_c = ctrl2[13]; -DSPUpdateRegisterBanks(); - -//WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc); - DSPExecP2(1); // Do *one* instruction - - // Save vars - memcpy(ram2, dsp_ram_8, 0x2000); - memcpy(regs2, dsp_reg_bank_0, 32 * 4); - memcpy(®s2[32], dsp_reg_bank_1, 32 * 4); - ctrl2[0] = dsp_pc; - ctrl2[1] = dsp_acc; - ctrl2[2] = dsp_remain; - ctrl2[3] = dsp_modulo; - ctrl2[4] = dsp_flags; - ctrl2[5] = dsp_matrix_control; - ctrl2[6] = dsp_pointer_to_matrix; - ctrl2[7] = dsp_data_organization; - ctrl2[8] = dsp_control; - ctrl2[9] = dsp_div_control; - ctrl2[10] = IMASKCleared; - ctrl2[11] = dsp_flag_z; - ctrl2[12] = dsp_flag_n; - ctrl2[13] = dsp_flag_c; - - if (instr1 != lastExec) - { -// WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count); - -// uint32_t ppc = ctrl2[0] - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)) - (pipeline[plPtrWrite].opcode == 38 ? 6 : (pipeline[plPtrWrite].opcode == PIPELINE_STALL ? 0 : 2)); -//WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc); -// if (ctrl1[0] < ppc) // P ran ahead of NP -//How to test this crap??? -// if (1) - { - DSPExecP2(1); // Do one more instruction - - // Save vars - memcpy(ram2, dsp_ram_8, 0x2000); - memcpy(regs2, dsp_reg_bank_0, 32 * 4); - memcpy(®s2[32], dsp_reg_bank_1, 32 * 4); - ctrl2[0] = dsp_pc; - ctrl2[1] = dsp_acc; - ctrl2[2] = dsp_remain; - ctrl2[3] = dsp_modulo; - ctrl2[4] = dsp_flags; - ctrl2[5] = dsp_matrix_control; - ctrl2[6] = dsp_pointer_to_matrix; - ctrl2[7] = dsp_data_organization; - ctrl2[8] = dsp_control; - ctrl2[9] = dsp_div_control; - ctrl2[10] = IMASKCleared; - ctrl2[11] = dsp_flag_z; - ctrl2[12] = dsp_flag_n; - ctrl2[13] = dsp_flag_c; - } -// else // NP ran ahead of P - if (instr1 != lastExec) // Must be the other way... - - { - // Load up vars for non-pipelined core - memcpy(dsp_ram_8, ram1, 0x2000); - memcpy(dsp_reg_bank_0, regs1, 32 * 4); - memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4); - dsp_pc = ctrl1[0]; - dsp_acc = ctrl1[1]; - dsp_remain = ctrl1[2]; - dsp_modulo = ctrl1[3]; - dsp_flags = ctrl1[4]; - dsp_matrix_control = ctrl1[5]; - dsp_pointer_to_matrix = ctrl1[6]; - dsp_data_organization = ctrl1[7]; - dsp_control = ctrl1[8]; - dsp_div_control = ctrl1[9]; - IMASKCleared = ctrl1[10]; - dsp_flag_z = ctrl1[11]; - dsp_flag_n = ctrl1[12]; - dsp_flag_c = ctrl1[13]; -DSPUpdateRegisterBanks(); - -for(int k=0; k<2; k++) -{ - // Decrement cycles based on non-pipelined core... - instr1 = DSPReadWord(dsp_pc, DSP); - cycles -= dsp_opcode_cycles[instr1 >> 10]; - -//WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc); - DSPExec(1); // Do *one* instruction -} - - // Save vars - memcpy(ram1, dsp_ram_8, 0x2000); - memcpy(regs1, dsp_reg_bank_0, 32 * 4); - memcpy(®s1[32], dsp_reg_bank_1, 32 * 4); - ctrl1[0] = dsp_pc; - ctrl1[1] = dsp_acc; - ctrl1[2] = dsp_remain; - ctrl1[3] = dsp_modulo; - ctrl1[4] = dsp_flags; - ctrl1[5] = dsp_matrix_control; - ctrl1[6] = dsp_pointer_to_matrix; - ctrl1[7] = dsp_data_organization; - ctrl1[8] = dsp_control; - ctrl1[9] = dsp_div_control; - ctrl1[10] = IMASKCleared; - ctrl1[11] = dsp_flag_z; - ctrl1[12] = dsp_flag_n; - ctrl1[13] = dsp_flag_c; - } - } - - if (instr1 != lastExec) - { - WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count); - - WriteLog("Instruction for non-pipelined core: %04X\n", instr1); - WriteLog("Instruction for pipelined core: %04X\n", lastExec); - - log_done(); - exit(1); - } - - count++; - } -} -#endif - - // // DSP execution core // -//static bool R20Set = false, tripwire = false; -//static uint32_t pcQueue[32], ptrPCQ = 0; void DSPExec(int32_t cycles) { -#ifdef DSP_SINGLE_STEPPING - if (dsp_control & 0x18) - { - cycles = 1; - dsp_control &= ~0x10; - } -#endif -//There is *no* good reason to do this here! -// DSPHandleIRQs(); dsp_releaseTimeSlice_flag = 0; dsp_in_exec++; while (cycles > 0 && DSP_RUNNING) { -/*extern uint32_t totalFrames; -//F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E) -//-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38 -//C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C) -//F1B140: -if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140) -{ - doDSPDis = true; - WriteLog("Starting disassembly at frame #%u...\n", totalFrames); -} -if (dsp_pc == 0xF1B092) - doDSPDis = false;//*/ -/*if (dsp_pc == 0xF1B140) - doDSPDis = true;//*/ - - if (IMASKCleared) // If IMASK was cleared, + if (IMASKCleared) { -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc); -#endif - DSPHandleIRQsNP(); // See if any other interrupts are pending! + DSPHandleIRQsNP(); IMASKCleared = false; } -/*if (badWrite) -{ - WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]); - for(int i=0; i<80; i+=4) - WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i)); - WriteLog("\n"); -}//*/ -/*if (dsp_pc == 0xF1B55E) -{ - WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : "")); -}//*/ -/*if (dsp_pc == 0xF1B7D2) // Start here??? - doDSPDis = true; -pcQueue[ptrPCQ++] = dsp_pc; -ptrPCQ %= 32;*/ uint16_t opcode = DSPReadWord(dsp_pc, DSP); uint32_t index = opcode >> 10; dsp_opcode_first_parameter = (opcode >> 5) & 0x1F; dsp_opcode_second_parameter = opcode & 0x1F; dsp_pc += 2; dsp_opcode[index](); - dsp_opcode_use[index]++; cycles -= dsp_opcode_cycles[index]; -/*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set) -{ - WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : "")); - R20Set = true; -} -if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set) -{ - WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : "")); - DSPDumpRegisters(); - DSPDumpDisassembly(); - exit(1); -} -if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire) -{ - char buffer[512]; - WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks()); - DSPDumpRegisters(); - tripwire = true; - WriteLog("\nBacktrace:\n"); - for(int i=0; i<32; i++) - { - dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]); - WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer); - } - WriteLog("\n"); -}*/ } dsp_in_exec--; } - // // DSP opcode handlers // -// There is a problem here with interrupt handlers the JUMP and JR instructions that -// can cause trouble because an interrupt can occur *before* the instruction following the -// jump can execute... !!! FIX !!! static void dsp_opcode_jump(void) { -#ifdef DSP_DIS_JUMP -const char * condition[32] = -{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz", - "c z", "???", "???", "???", "???", "???", "???", "???", "???", - "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???", - "???", "???", "???", "F" }; - if (doDSPDis) - WriteLog("%06X: JUMP %s, (R%02u) [NCZ:%u%u%u, R%02u=%08X] ", dsp_pc-2, condition[IMM_2], IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM); -#endif - // normalize flags -/* dsp_flag_c=dsp_flag_c?1:0; - dsp_flag_z=dsp_flag_z?1:0; - dsp_flag_n=dsp_flag_n?1:0;*/ - // KLUDGE: Used by BRANCH_CONDITION uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z; if (BRANCH_CONDITION(IMM_2)) { -#ifdef DSP_DIS_JUMP - if (doDSPDis) - WriteLog("Branched!\n"); -#endif uint32_t delayed_pc = RM; DSPExec(1); dsp_pc = delayed_pc; } -#ifdef DSP_DIS_JUMP - else - if (doDSPDis) - WriteLog("Branch NOT taken.\n"); -#endif } - static void dsp_opcode_jr(void) { -#ifdef DSP_DIS_JR -const char * condition[32] = -{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz", - "c z", "???", "???", "???", "???", "???", "???", "???", "???", - "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???", - "???", "???", "???", "F" }; - if (doDSPDis) - WriteLog("%06X: JR %s, %06X [NCZ:%u%u%u] ", dsp_pc-2, condition[IMM_2], dsp_pc+((IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1) * 2), dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif - // normalize flags -/* dsp_flag_c=dsp_flag_c?1:0; - dsp_flag_z=dsp_flag_z?1:0; - dsp_flag_n=dsp_flag_n?1:0;*/ - // KLUDGE: Used by BRANCH_CONDITION uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z; if (BRANCH_CONDITION(IMM_2)) { -#ifdef DSP_DIS_JR - if (doDSPDis) - WriteLog("Branched!\n"); -#endif - int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1 + int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); int32_t delayed_pc = dsp_pc + (offset * 2); DSPExec(1); dsp_pc = delayed_pc; } -#ifdef DSP_DIS_JR - else - if (doDSPDis) - WriteLog("Branch NOT taken.\n"); -#endif } static void dsp_opcode_add(void) { -#ifdef DSP_DIS_ADD - if (doDSPDis) - WriteLog("%06X: ADD R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res = RN + RM; SET_ZNC_ADD(RN, RM, res); RN = res; -#ifdef DSP_DIS_ADD - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } static void dsp_opcode_addc(void) { -#ifdef DSP_DIS_ADDC - if (doDSPDis) - WriteLog("%06X: ADDC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res = RN + RM + dsp_flag_c; uint32_t carry = dsp_flag_c; -// SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes! SET_ZNC_ADD(RN + carry, RM, res); -// SET_ZNC_ADD(RN, RM + carry, res); RN = res; -#ifdef DSP_DIS_ADDC - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_addq(void) { -#ifdef DSP_DIS_ADDQ - if (doDSPDis) - WriteLog("%06X: ADDQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t r1 = dsp_convert_zero[IMM_1]; uint32_t res = RN + r1; CLR_ZNC; SET_ZNC_ADD(RN, r1, res); RN = res; -#ifdef DSP_DIS_ADDQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_sub(void) { -#ifdef DSP_DIS_SUB - if (doDSPDis) - WriteLog("%06X: SUB R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res = RN - RM; SET_ZNC_SUB(RN, RM, res); RN = res; -#ifdef DSP_DIS_SUB - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_subc(void) { -#ifdef DSP_DIS_SUBC - if (doDSPDis) - WriteLog("%06X: SUBC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif - // This is how the DSP ALU does it--Two's complement with inverted carry uint64_t res = (uint64_t)RN + (uint64_t)(RM ^ 0xFFFFFFFF) + (dsp_flag_c ^ 1); - // Carry out of the result is inverted too dsp_flag_c = ((res >> 32) & 0x01) ^ 1; RN = (res & 0xFFFFFFFF); SET_ZN(RN); -#ifdef DSP_DIS_SUBC - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } static void dsp_opcode_subq(void) { -#ifdef DSP_DIS_SUBQ - if (doDSPDis) - WriteLog("%06X: SUBQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t r1 = dsp_convert_zero[IMM_1]; uint32_t res = RN - r1; SET_ZNC_SUB(RN, r1, res); RN = res; -#ifdef DSP_DIS_SUBQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_cmp(void) { -#ifdef DSP_DIS_CMP - if (doDSPDis) - WriteLog("%06X: CMP R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res = RN - RM; SET_ZNC_SUB(RN, RM, res); -#ifdef DSP_DIS_CMP - if (doDSPDis) - WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif } - static void dsp_opcode_cmpq(void) { static int32_t sqtable[32] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1 }; -#ifdef DSP_DIS_CMPQ - if (doDSPDis) - WriteLog("%06X: CMPQ #%d, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, sqtable[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif - uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3; + + uint32_t r1 = sqtable[IMM_1 & 0x1F]; uint32_t res = RN - r1; SET_ZNC_SUB(RN, r1, res); -#ifdef DSP_DIS_CMPQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif } - static void dsp_opcode_and(void) { -#ifdef DSP_DIS_AND - if (doDSPDis) - WriteLog("%06X: AND R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RN & RM; SET_ZN(RN); -#ifdef DSP_DIS_AND - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_or(void) { -#ifdef DSP_DIS_OR - if (doDSPDis) - WriteLog("%06X: OR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RN | RM; SET_ZN(RN); -#ifdef DSP_DIS_OR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_xor(void) { -#ifdef DSP_DIS_XOR - if (doDSPDis) - WriteLog("%06X: XOR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RN ^ RM; SET_ZN(RN); -#ifdef DSP_DIS_XOR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_not(void) { -#ifdef DSP_DIS_NOT - if (doDSPDis) - WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif RN = ~RN; SET_ZN(RN); -#ifdef DSP_DIS_NOT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_move_pc(void) { RN = dsp_pc - 2; } - static void dsp_opcode_store_r14_indexed(void) { -#ifdef DSP_DIS_STORE14I - if (doDSPDis) - WriteLog("%06X: STORE R%02u, (R14+$%02X) [NCZ:%u%u%u, R%02u=%08X, R14+$%02X=%08X]\n", dsp_pc-2, IMM_2, dsp_convert_zero[IMM_1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_convert_zero[IMM_1] << 2, dsp_reg[14]+(dsp_convert_zero[IMM_1] << 2)); -#endif -#ifdef DSP_CORRECT_ALIGNMENT_STORE - DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP); -#else DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP); -#endif } - static void dsp_opcode_store_r15_indexed(void) { -#ifdef DSP_DIS_STORE15I - if (doDSPDis) - WriteLog("%06X: STORE R%02u, (R15+$%02X) [NCZ:%u%u%u, R%02u=%08X, R15+$%02X=%08X]\n", dsp_pc-2, IMM_2, dsp_convert_zero[IMM_1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_convert_zero[IMM_1] << 2, dsp_reg[15]+(dsp_convert_zero[IMM_1] << 2)); -#endif -#ifdef DSP_CORRECT_ALIGNMENT_STORE - DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP); -#else DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP); -#endif } - static void dsp_opcode_load_r14_ri(void) { -#ifdef DSP_DIS_LOAD14R - if (doDSPDis) - WriteLog("%06X: LOAD (R14+R%02u), R%02u [NCZ:%u%u%u, R14+R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM+dsp_reg[14], IMM_2, RN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP); -#else - RN = DSPReadLong(dsp_reg[14] + RM, DSP); -#endif -#ifdef DSP_DIS_LOAD14R - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_load_r15_ri(void) { -#ifdef DSP_DIS_LOAD15R - if (doDSPDis) - WriteLog("%06X: LOAD (R15+R%02u), R%02u [NCZ:%u%u%u, R15+R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM+dsp_reg[15], IMM_2, RN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP); -#else - RN = DSPReadLong(dsp_reg[15] + RM, DSP); -#endif -#ifdef DSP_DIS_LOAD15R - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_store_r14_ri(void) { DSPWriteLong(dsp_reg[14] + RM, RN, DSP); } - static void dsp_opcode_store_r15_ri(void) { DSPWriteLong(dsp_reg[15] + RM, RN, DSP); } - static void dsp_opcode_nop(void) { -#ifdef DSP_DIS_NOP - if (doDSPDis) - WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif } - static void dsp_opcode_storeb(void) { -#ifdef DSP_DIS_STOREB - if (doDSPDis) - WriteLog("%06X: STOREB R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM); -#endif if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF)) DSPWriteLong(RM, RN & 0xFF, DSP); else JaguarWriteByte(RM, RN, DSP); } - static void dsp_opcode_storew(void) { -#ifdef DSP_DIS_STOREW - if (doDSPDis) - WriteLog("%06X: STOREW R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM); -#endif -#ifdef DSP_CORRECT_ALIGNMENT_STORE - if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF)) - DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP); - else - JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP); -#else if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF)) DSPWriteLong(RM, RN & 0xFFFF, DSP); else JaguarWriteWord(RM, RN, DSP); -#endif } - static void dsp_opcode_store(void) { -#ifdef DSP_DIS_STORE - if (doDSPDis) - WriteLog("%06X: STORE R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM); -#endif -#ifdef DSP_CORRECT_ALIGNMENT_STORE - DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP); -#else DSPWriteLong(RM, RN, DSP); -#endif } - static void dsp_opcode_loadb(void) { -#ifdef DSP_DIS_LOADB - if (doDSPDis) - WriteLog("%06X: LOADB (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF)) RN = DSPReadLong(RM, DSP) & 0xFF; else RN = JaguarReadByte(RM, DSP); -#ifdef DSP_DIS_LOADB - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_loadw(void) { -#ifdef DSP_DIS_LOADW - if (doDSPDis) - WriteLog("%06X: LOADW (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF)) RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF; else RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP); -#else - if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF)) - RN = DSPReadLong(RM, DSP) & 0xFFFF; - else - RN = JaguarReadWord(RM, DSP); -#endif -#ifdef DSP_DIS_LOADW - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_load(void) { -#ifdef DSP_DIS_LOAD - if (doDSPDis) - WriteLog("%06X: LOAD (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT RN = DSPReadLong(RM & 0xFFFFFFFC, DSP); -#else - RN = DSPReadLong(RM, DSP); -#endif -#ifdef DSP_DIS_LOAD - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_load_r14_indexed(void) { -#ifdef DSP_DIS_LOAD14I - if (doDSPDis) - WriteLog("%06X: LOAD (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1] << 2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[IMM_1] << 2, dsp_reg[14]+(dsp_convert_zero[IMM_1] << 2), IMM_2, RN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP); -#else - RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP); -#endif -#ifdef DSP_DIS_LOAD14I - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_load_r15_indexed(void) { -#ifdef DSP_DIS_LOAD15I - if (doDSPDis) - WriteLog("%06X: LOAD (R15+$%02X), R%02u [NCZ:%u%u%u, R15+$%02X=%08X, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1] << 2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[IMM_1] << 2, dsp_reg[15]+(dsp_convert_zero[IMM_1] << 2), IMM_2, RN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP); -#else - RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP); -#endif -#ifdef DSP_DIS_LOAD15I - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_movei(void) { -#ifdef DSP_DIS_MOVEI - if (doDSPDis) - WriteLog("%06X: MOVEI #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, (uint32_t)DSPReadWord(dsp_pc) | ((uint32_t)DSPReadWord(dsp_pc + 2) << 16), IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif - // This instruction is followed by 32-bit value in LSW / MSW format... RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16); dsp_pc += 4; -#ifdef DSP_DIS_MOVEI - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_moveta(void) { -#ifdef DSP_DIS_MOVETA - if (doDSPDis) - WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN); -#endif ALTERNATE_RN = RM; -#ifdef DSP_DIS_MOVETA - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN); -#endif } - static void dsp_opcode_movefa(void) { -#ifdef DSP_DIS_MOVEFA - if (doDSPDis) - WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN); -#endif RN = ALTERNATE_RM; -#ifdef DSP_DIS_MOVEFA - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN); -#endif } - static void dsp_opcode_move(void) { -#ifdef DSP_DIS_MOVE - if (doDSPDis) - WriteLog("%06X: MOVE R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RM; -#ifdef DSP_DIS_MOVE - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_moveq(void) { -#ifdef DSP_DIS_MOVEQ - if (doDSPDis) - WriteLog("%06X: MOVEQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif RN = IMM_1; -#ifdef DSP_DIS_MOVEQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_resmac(void) { -#ifdef DSP_DIS_RESMAC - if (doDSPDis) - WriteLog("%06X: RESMAC R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_ACC=%02X%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF)); -#endif RN = (uint32_t)dsp_acc; -#ifdef DSP_DIS_RESMAC - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_imult(void) { -#ifdef DSP_DIS_IMULT - if (doDSPDis) - WriteLog("%06X: IMULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = (int16_t)RN * (int16_t)RM; SET_ZN(RN); -#ifdef DSP_DIS_IMULT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_mult(void) { -#ifdef DSP_DIS_MULT - if (doDSPDis) - WriteLog("%06X: MULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = (uint16_t)RM * (uint16_t)RN; SET_ZN(RN); -#ifdef DSP_DIS_MULT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_bclr(void) { -#ifdef DSP_DIS_BCLR - if (doDSPDis) - WriteLog("%06X: BCLR #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t res = RN & ~(1 << IMM_1); RN = res; SET_ZN(res); -#ifdef DSP_DIS_BCLR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_btst(void) { -#ifdef DSP_DIS_BTST - if (doDSPDis) - WriteLog("%06X: BTST #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif dsp_flag_z = (~RN >> IMM_1) & 1; -#ifdef DSP_DIS_BTST - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_bset(void) { -#ifdef DSP_DIS_BSET - if (doDSPDis) - WriteLog("%06X: BSET #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t res = RN | (1 << IMM_1); RN = res; SET_ZN(res); -#ifdef DSP_DIS_BSET - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_subqt(void) { -#ifdef DSP_DIS_SUBQT - if (doDSPDis) - WriteLog("%06X: SUBQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif RN -= dsp_convert_zero[IMM_1]; -#ifdef DSP_DIS_SUBQT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_addqt(void) { -#ifdef DSP_DIS_ADDQT - if (doDSPDis) - WriteLog("%06X: ADDQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif RN += dsp_convert_zero[IMM_1]; -#ifdef DSP_DIS_ADDQT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_imacn(void) { -#ifdef DSP_DIS_IMACN - if (doDSPDis) - WriteLog("%06X: IMACN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif int32_t res = (int16_t)RM * (int16_t)RN; dsp_acc += (int64_t)res; -//Should we AND the result to fit into 40 bits here??? -#ifdef DSP_DIS_IMACN - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF)); -#endif } - static void dsp_opcode_mtoi(void) { RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF); SET_ZN(RN); } - static void dsp_opcode_normi(void) { uint32_t _Rm = RM; @@ -2389,11 +951,11 @@ static void dsp_opcode_normi(void) res++; } } + RN = res; SET_ZN(RN); } - static void dsp_opcode_mmult(void) { int count = dsp_matrix_control&0x0f; @@ -2429,19 +991,13 @@ static void dsp_opcode_mmult(void) addr += 4 * count; } } + RN = res = (int32_t)accum; - // carry flag to do -//NOTE: The flags are set based upon the last add/multiply done... SET_ZN(RN); } - static void dsp_opcode_abs(void) { -#ifdef DSP_DIS_ABS - if (doDSPDis) - WriteLog("%06X: ABS R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t _Rn = RN; uint32_t res; @@ -2453,51 +1009,18 @@ static void dsp_opcode_abs(void) res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn); CLR_ZN; SET_Z(res); } -#ifdef DSP_DIS_ABS - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_div(void) { -#if 0 - if (RM) - { - if (dsp_div_control & 0x01) // 16.16 division - { - dsp_remain = ((uint64_t)RN << 16) % RM; - RN = ((uint64_t)RN << 16) / RM; - } - else - { - // We calculate the remainder first because we destroy RN after - // this by assigning it to itself. - dsp_remain = RN % RM; - RN = RN / RM; - } - - } - else - { - // This is what happens according to SCPCD. NYAN! - RN = 0xFFFFFFFF; - dsp_remain = 0; - } -#else - // Real algorithm, courtesy of SCPCD: NYAN! uint32_t q = RN; uint32_t r = 0; - // If 16.16 division, stuff top 16 bits of RN into remainder and put the - // bottom 16 of RN in top 16 of quotient if (dsp_div_control & 0x01) q <<= 16, r = RN >> 16; for(int i=0; i<32; i++) { -// uint32_t sign = (r >> 31) & 0x01; uint32_t sign = r & 0x80000000; r = (r << 1) | ((q >> 31) & 0x01); r += (sign ? RM : -RM); @@ -2506,113 +1029,55 @@ static void dsp_opcode_div(void) RN = q; dsp_remain = r; -#endif } - static void dsp_opcode_imultn(void) { -#ifdef DSP_DIS_IMULTN - if (doDSPDis) - WriteLog("%06X: IMULTN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif - // This is OK, since this multiply won't overflow 32 bits... int32_t res = (int32_t)((int16_t)RN * (int16_t)RM); dsp_acc = (int64_t)res; SET_ZN(res); -#ifdef DSP_DIS_IMULTN - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF)); -#endif } - static void dsp_opcode_neg(void) { -#ifdef DSP_DIS_NEG - if (doDSPDis) - WriteLog("%06X: NEG R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t res = -RN; SET_ZNC_SUB(0, RN, res); RN = res; -#ifdef DSP_DIS_NEG - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_shlq(void) { -#ifdef DSP_DIS_SHLQ - if (doDSPDis) - WriteLog("%06X: SHLQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, 32 - IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif - // NB: This instruction is the *only* one that does (32 - immediate data). int32_t r1 = 32 - IMM_1; uint32_t res = RN << r1; SET_ZN(res); dsp_flag_c = (RN >> 31) & 1; RN = res; -#ifdef DSP_DIS_SHLQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_shrq(void) { -#ifdef DSP_DIS_SHRQ - if (doDSPDis) - WriteLog("%06X: SHRQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif int32_t r1 = dsp_convert_zero[IMM_1]; uint32_t res = RN >> r1; SET_ZN(res); dsp_flag_c = RN & 1; RN = res; -#ifdef DSP_DIS_SHRQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_ror(void) { -#ifdef DSP_DIS_ROR - if (doDSPDis) - WriteLog("%06X: ROR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t r1 = RM & 0x1F; uint32_t res = (RN >> r1) | (RN << (32 - r1)); SET_ZN(res); dsp_flag_c = (RN >> 31) & 1; RN = res; -#ifdef DSP_DIS_ROR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void dsp_opcode_rorq(void) { -#ifdef DSP_DIS_RORQ - if (doDSPDis) - WriteLog("%06X: RORQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F]; uint32_t r2 = RN; uint32_t res = (r2 >> r1) | (r2 << (32 - r1)); RN = res; SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01; -#ifdef DSP_DIS_RORQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_sha(void) { int32_t sRm=(int32_t)RM; @@ -2640,27 +1105,18 @@ static void dsp_opcode_sha(void) shift--; } } + RN = _Rn; SET_ZN(RN); } - static void dsp_opcode_sharq(void) { -#ifdef DSP_DIS_SHARQ - if (doDSPDis) - WriteLog("%06X: SHARQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1]; SET_ZN(res); dsp_flag_c = RN & 0x01; RN = res; -#ifdef DSP_DIS_SHARQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } - static void dsp_opcode_sh(void) { int32_t sRm=(int32_t)RM; @@ -2688,26 +1144,19 @@ static void dsp_opcode_sh(void) shift--; } } + RN = _Rn; SET_ZN(RN); } void dsp_opcode_addqmod(void) { -#ifdef DSP_DIS_ADDQMOD - if (doDSPDis) - WriteLog("%06X: ADDQMOD #%u, R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_MOD=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_modulo); -#endif uint32_t r1 = dsp_convert_zero[IMM_1]; uint32_t r2 = RN; uint32_t res = r2 + r1; res = (res & (~dsp_modulo)) | (r2 & dsp_modulo); RN = res; SET_ZNC_ADD(r2, r1, res); -#ifdef DSP_DIS_ADDQMOD - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); -#endif } void dsp_opcode_subqmod(void) @@ -2747,2053 +1196,4 @@ void dsp_opcode_sat16s(void) void dsp_opcode_illegal(void) { - // Don't know what it does, but it does *something*... - WriteLog("%06X: illegal %u, %u [NCZ:%u%u%u]\n", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z); -} - -// -// New pipelined DSP core -// - -static void DSP_abs(void); -static void DSP_add(void); -static void DSP_addc(void); -static void DSP_addq(void); -static void DSP_addqmod(void); -static void DSP_addqt(void); -static void DSP_and(void); -static void DSP_bclr(void); -static void DSP_bset(void); -static void DSP_btst(void); -static void DSP_cmp(void); -static void DSP_cmpq(void); -static void DSP_div(void); -static void DSP_imacn(void); -static void DSP_imult(void); -static void DSP_imultn(void); -static void DSP_illegal(void); -static void DSP_jr(void); -static void DSP_jump(void); -static void DSP_load(void); -static void DSP_loadb(void); -static void DSP_loadw(void); -static void DSP_load_r14_i(void); -static void DSP_load_r14_r(void); -static void DSP_load_r15_i(void); -static void DSP_load_r15_r(void); -static void DSP_mirror(void); -static void DSP_mmult(void); -static void DSP_move(void); -static void DSP_movefa(void); -static void DSP_movei(void); -static void DSP_movepc(void); -static void DSP_moveq(void); -static void DSP_moveta(void); -static void DSP_mtoi(void); -static void DSP_mult(void); -static void DSP_neg(void); -static void DSP_nop(void); -static void DSP_normi(void); -static void DSP_not(void); -static void DSP_or(void); -static void DSP_resmac(void); -static void DSP_ror(void); -static void DSP_rorq(void); -static void DSP_sat16s(void); -static void DSP_sat32s(void); -static void DSP_sh(void); -static void DSP_sha(void); -static void DSP_sharq(void); -static void DSP_shlq(void); -static void DSP_shrq(void); -static void DSP_store(void); -static void DSP_storeb(void); -static void DSP_storew(void); -static void DSP_store_r14_i(void); -static void DSP_store_r14_r(void); -static void DSP_store_r15_i(void); -static void DSP_store_r15_r(void); -static void DSP_sub(void); -static void DSP_subc(void); -static void DSP_subq(void); -static void DSP_subqmod(void); -static void DSP_subqt(void); -static void DSP_xor(void); - -void (* DSPOpcode[64])() = -{ - DSP_add, DSP_addc, DSP_addq, DSP_addqt, - DSP_sub, DSP_subc, DSP_subq, DSP_subqt, - DSP_neg, DSP_and, DSP_or, DSP_xor, - DSP_not, DSP_btst, DSP_bset, DSP_bclr, - - DSP_mult, DSP_imult, DSP_imultn, DSP_resmac, - DSP_imacn, DSP_div, DSP_abs, DSP_sh, - DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq, - DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq, - - DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq, - DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb, - DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i, - DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store, - - DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc, - DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi, - DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r, - DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod -}; - -bool readAffected[64][2] = -{ - { true, true}, { true, true}, {false, true}, {false, true}, - { true, true}, { true, true}, {false, true}, {false, true}, - {false, true}, { true, true}, { true, true}, { true, true}, - {false, true}, {false, true}, {false, true}, {false, true}, - - { true, true}, { true, true}, { true, true}, {false, true}, - { true, true}, { true, true}, {false, true}, { true, true}, - {false, true}, {false, true}, { true, true}, {false, true}, - { true, true}, {false, true}, { true, true}, {false, true}, - - {false, true}, {false, true}, { true, false}, {false, false}, - { true, false}, {false, false}, {false, false}, { true, false}, - { true, false}, { true, false}, {false, true}, { true, false}, - { true, false}, { true, true}, { true, true}, { true, true}, - - {false, true}, { true, true}, { true, true}, {false, true}, - { true, false}, { true, false}, { true, true}, { true, false}, - { true, false}, {false, false}, { true, false}, { true, false}, - { true, true}, { true, true}, {false, false}, {false, true} -}; - -bool isLoadStore[65] = -{ - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, true, - true, true, false, true, true, true, true, true, - - false, true, true, false, false, false, false, false, - false, false, true, true, true, true, false, false, false -}; - -void FlushDSPPipeline(void) -{ - plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0; - - for(int i=0; i<4; i++) - pipeline[i].opcode = PIPELINE_STALL; - - for(int i=0; i<32; i++) - scoreboard[i] = 0; -} - -// -// New pipelined DSP execution core -// -/*void DSPExecP(int32_t cycles) -{ -// bool inhibitFetch = false; - - dsp_releaseTimeSlice_flag = 0; - dsp_in_exec++; - - while (cycles > 0 && DSP_RUNNING) - { -WriteLog("DSPExecP: Pipeline status...\n"); -WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister); -WriteLog(" --> Scoreboard: "); -for(int i=0; i<32; i++) - WriteLog("%s ", scoreboard[i] ? "T" : "F"); -WriteLog("\n"); - // Stage 1: Instruction fetch -// if (!inhibitFetch) -// { - pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP); - pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10; - pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F; - pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F; - if (pipeline[plPtrFetch].opcode == 38) - pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP) - | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16); -// } -// else -// inhibitFetch = false; -WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc); - -WriteLog("DSPExecP: Pipeline status (after stage 1)...\n"); -WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister); - // Stage 2: Read registers -//Ok, stalls here depend on whether or not the instruction reads two registers or not -//and *which* register (1 or 2) is the one being read... !!! FIX !!! - if (scoreboard[pipeline[plPtrRead].operand2]) - && pipeline[plPtrRead].opcode != PIPELINE_STALL) - // We have a hit in the scoreboard, so we have to stall the pipeline... -{ -//This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!! -// dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2); -WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false"); - pipeline[plPtrFetch] = pipeline[plPtrRead]; - pipeline[plPtrRead].opcode = PIPELINE_STALL; -} - else - { - pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1]; - pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2]; - pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN - - if (pipeline[plPtrRead].opcode != PIPELINE_STALL) - // Shouldn't we be more selective with the register scoreboarding? - // Yes, we should. !!! FIX !!! - scoreboard[pipeline[plPtrRead].operand2] = true; -//Advance PC here??? Yes. -// dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2); -//This is a mangling of the pipeline stages, but what else to do??? - dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2); - } - -WriteLog("DSPExecP: Pipeline status (after stage 2)...\n"); -WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister); - // Stage 3: Execute - if (pipeline[plPtrExec].opcode != PIPELINE_STALL) - { -WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]); - DSPOpcode[pipeline[plPtrExec].opcode](); - dsp_opcode_use[pipeline[plPtrExec].opcode]++; - cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode]; - } - else - cycles--; - -WriteLog("DSPExecP: Pipeline status (after stage 3)...\n"); -WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister); - // Stage 4: Write back register - if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - - scoreboard[pipeline[plPtrWrite].operand1] - = scoreboard[pipeline[plPtrWrite].operand2] = false; - } - - // Push instructions through the pipeline... - plPtrFetch = (++plPtrFetch) & 0x03; - plPtrRead = (++plPtrRead) & 0x03; - plPtrExec = (++plPtrExec) & 0x03; - plPtrWrite = (++plPtrWrite) & 0x03; - } - - dsp_in_exec--; -}*/ - - -//Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values! -//!!! FIX !!! -// Should be fixed now. Another problem is figuring how to do the sequence following -// a branch followed with the JR & JUMP instructions... -// -// There are two conflicting problems: - -/* -F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084] -F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031] -F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086] -F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F] -F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0] -F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken. -F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431] -F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100] -F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100] -DSP: Writing 00004431 to DSP_FLAGS by DSP... -DSP: Finished interrupt. -; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of -; bank 0 (where is was prepared)! -F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched! -F1B252: NOP [NCZ:001] -*/ - -// The other is when you see this at the end of an IRQ: - -/* -JUMP T, (R29) ; R29 = Previous stack + 2 -STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100 - -; Actually, this is OK if we do the atomic JUMP/JR operation correctly: -; 1) The STORE goes through the pipeline and is executed/written back -; 2) The pipeline is flushed -; 3) The DSP_PC is set to the new address -; 4) Execution resumes - -JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from - ; bank 0 instead of the current bank 1 and so goes astray! -*/ - -//One other thing: Since these stages are supposed to happen simulaneously, try executing -//them in reverse order to see if that reduces pipeline stalls from late writebacks... - - -/* -Small problem here: The return address when INT0 comes up is $F1B088, but when INT1 -follows it, the JUMP out of the previous interrupt is bypassed immediately--this is -because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3... -If it were done properly, the STORE write back would occur *after* (well, technically, -during) the execution of the the JUMP that follows it. - -!!! FIX !!! [DONE] - -F1B08A: JR z, F1B082 [NCZ:001] Branched! -F1B08A: NOP [NCZ:001] -[STALL...] -F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178] -[STALL...] -[STALL...] -F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000] -[STALL...] -[STALL...] -F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000] -F1B08A: JR z, F1B082 [NCZ:001] Branched! -F1B08A: NOP [NCZ:001] -[STALL...] -F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178] -[STALL...] -[STALL...] -Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K... -DSP: CPU -> DSP interrupt -DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0] -Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K... -[STALL...] -F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4] -[STALL...] -[STALL...] -F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched! -F1B006: NOP [NCZ:001] -[STALL...] -F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100] -[STALL...] -[STALL...] -F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039] -F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8] -[STALL...] -[STALL...] -F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001] -F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC] -[STALL...] -[STALL...] -F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064] -F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0] -[STALL...] -[STALL...] -F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008] -F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC] -[STALL...] -[STALL...] -F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4] -[STALL...] -[STALL...] -F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E] -[STALL...] -[STALL...] -F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched! -F1B0FE: NOP [NCZ:000] -[STALL...] -F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001] -[STALL...] -[STALL...] -F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102] -[STALL...] -[STALL...] -F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched! -F1B138: NOP [NCZ:000] -[STALL...] -F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8] -[STALL...] -[STALL...] -F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8] -F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0] -F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000] -[STALL...] -[STALL...] -F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0] -F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031] -[STALL...] -[STALL...] -F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231] -F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086] -F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0] -[STALL...] -F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088] -F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100] -[STALL...] -[STALL...] -F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100] -DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)... -DSP: Finished interrupt. -DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0] -[STALL...] -F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC] -[STALL...] -[STALL...] -F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched! -F1B016: NOP [NCZ:001] -[STALL...] -F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100] -*/ - -uint32_t pcQueue1[0x400]; -uint32_t pcQPtr1 = 0; -static uint32_t prevR1; -//Let's try a 3 stage pipeline.... -//Looks like 3 stage is correct, otherwise bad things happen... -void DSPExecP2(int32_t cycles) -{ - dsp_releaseTimeSlice_flag = 0; - dsp_in_exec++; - - while (cycles > 0 && DSP_RUNNING) - { -/*extern uint32_t totalFrames; -//F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E) -//-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38 -//C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C) -//F1B140: -if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140) -{ - doDSPDis = true; - WriteLog("Starting disassembly at frame #%u...\n", totalFrames); -} -if (dsp_pc == 0xF1B092) - doDSPDis = false;//*/ -/*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38) - doDSPDis = true;//*/ -/*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0) - doDSPDis = true;//*/ -/*if (dsp_pc == 0xF1B0A0) - doDSPDis = true;//*/ -/*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C) - doDSPDis = true;//*/ -//Two parter... (not sure how to write this) -//if (dsp_pc == 0xF1B0D2) -// prevR1 = dsp_reg[1]; - -//F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414] -//F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414] - - -pcQueue1[pcQPtr1++] = dsp_pc; -pcQPtr1 &= 0x3FF; - -#ifdef DSP_DEBUG_PL2 -if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis) -{ - WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n"); - doDSPDis = true; - - char buffer[512]; - - for(int i=0; i<0x400; i++) - { - dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]); - WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer); - } - WriteLog("\n"); -}//*/ -#endif - - if (IMASKCleared) // If IMASK was cleared, - { -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Finished interrupt.\n"); -#endif - DSPHandleIRQs(); // See if any other interrupts are pending! - IMASKCleared = false; - } - -//if (dsp_flags & REGPAGE) -// WriteLog(" --> REGPAGE has just been set!\n"); -#ifdef DSP_DEBUG_PL2 -if (doDSPDis) -{ -WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]); -WriteLog(" --> Scoreboard: "); -for(int i=0; i<32; i++) - WriteLog("%s ", scoreboard[i] ? "T" : "F"); -WriteLog("\n"); -} -#endif - // Stage 1a: Instruction fetch - pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP); - pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10; - pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F; - pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F; - if (pipeline[plPtrRead].opcode == 38) - pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP) - | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16); -#ifdef DSP_DEBUG_PL2 -if (doDSPDis) -{ -WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc); -WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]); -} -#endif - // Stage 1b: Read registers -//Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that -//modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!! -//Ugly, but [DONE] -//Another problem: Any sequential combination of LOAD and STORE operations will cause the -//pipeline to stall, and we don't take care of that here. !!! FIX !!! - if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0]) - || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]) - || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14]) - || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15]) -//Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to -//work--somewhat... - || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode])) - // We have a hit in the scoreboard, so we have to stall the pipeline... -#ifdef DSP_DEBUG_PL2 -{ -if (doDSPDis) -{ -WriteLog(" --> Stalling pipeline: "); -if (readAffected[pipeline[plPtrRead].opcode][0]) - WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false"); -if (readAffected[pipeline[plPtrRead].opcode][1]) - WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false"); -WriteLog("\n"); -} -#endif - pipeline[plPtrRead].opcode = PIPELINE_STALL; -#ifdef DSP_DEBUG_PL2 -} -#endif - else - { - pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1]; - pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2]; - pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN - - // Shouldn't we be more selective with the register scoreboarding? - // Yes, we should. !!! FIX !!! Kinda [DONE] -#ifndef NEW_SCOREBOARD - scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode]; -#else -//Hopefully this will fix the dual MOVEQ # problem... - scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0); -#endif - -//Advance PC here??? Yes. - dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2); - } - -#ifdef DSP_DEBUG_PL2 -if (doDSPDis) -{ -WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]); -} -#endif - // Stage 2: Execute - if (pipeline[plPtrExec].opcode != PIPELINE_STALL) - { -#ifdef DSP_DEBUG_PL2 -if (doDSPDis) - WriteLog("\t[inst=%02u][R28=%08X, alt R28=%08X, REGPAGE=%s]\n", pipeline[plPtrExec].opcode, dsp_reg[28], dsp_alternate_reg[28], (dsp_flags & REGPAGE ? "set" : "not set")); - -if (doDSPDis) -{ -WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]); -} -#endif -//CC only! -#ifdef DSP_DEBUG_CC -lastExec = pipeline[plPtrExec].instruction; -//WriteLog("[lastExec = %04X]\n", lastExec); -#endif - cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode]; - dsp_opcode_use[pipeline[plPtrExec].opcode]++; - DSPOpcode[pipeline[plPtrExec].opcode](); -//WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc); - } - else -{ -//Let's not, until we do the stalling correctly... -//But, we gotta while we're doing the comparison core...! -//Or do we? cycles--; -//Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions -//will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is -//to model this clock cycle behavior correctly... -//Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3 -//don't affect the reads at stage 1... -#ifdef DSP_DEBUG_STALL -if (doDSPDis) - WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc); -#endif -} - -#ifdef DSP_DEBUG_PL2 -if (doDSPDis) -{ -WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc); -WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]); -WriteLog("\n"); -} -#endif - // Stage 3: Write back register/memory address - if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { -/*if (pipeline[plPtrWrite].writebackRegister == 3 - && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF) - && !doDSPDis) -{ - WriteLog("DSP: Register R03 has stepped out of bounds...\n\n"); - doDSPDis = true; -}//*/ - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFE) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - else - { - if (pipeline[plPtrWrite].type == TYPE_BYTE) - JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else if (pipeline[plPtrWrite].type == TYPE_WORD) - JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else - JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - } - } - -#ifndef NEW_SCOREBOARD - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - scoreboard[pipeline[plPtrWrite].operand2] = false; -#else -//Yup, sequential MOVEQ # problem fixing (I hope!)... - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - if (scoreboard[pipeline[plPtrWrite].operand2]) - scoreboard[pipeline[plPtrWrite].operand2]--; -#endif - } - - // Push instructions through the pipeline... - plPtrRead = (plPtrRead + 1) & 0x03; - plPtrExec = (plPtrExec + 1) & 0x03; - plPtrWrite = (plPtrWrite + 1) & 0x03; - } - - dsp_in_exec--; -} - - - -/* -//#define DSP_DEBUG_PL3 -//Let's try a 2 stage pipeline.... -void DSPExecP3(int32_t cycles) -{ - dsp_releaseTimeSlice_flag = 0; - dsp_in_exec++; - - while (cycles > 0 && DSP_RUNNING) - { -//if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) -// doDSPDis = true; -#ifdef DSP_DEBUG_PL3 -WriteLog("DSPExecP: Pipeline status...\n"); -WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -WriteLog(" --> Scoreboard: "); -for(int i=0; i<32; i++) - WriteLog("%s ", scoreboard[i] ? "T" : "F"); -WriteLog("\n"); -#endif - // Stage 1a: Instruction fetch - pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP); - pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10; - pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F; - pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F; - if (pipeline[plPtrRead].opcode == 38) - pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP) - | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16); -#ifdef DSP_DEBUG_PL3 -WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc); -WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n"); -WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -#endif - // Stage 1b: Read registers - if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0]) - || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])) - // We have a hit in the scoreboard, so we have to stall the pipeline... -#ifdef DSP_DEBUG_PL3 -{ -WriteLog(" --> Stalling pipeline: "); -if (readAffected[pipeline[plPtrRead].opcode][0]) - WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false"); -if (readAffected[pipeline[plPtrRead].opcode][1]) - WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false"); -WriteLog("\n"); -#endif - pipeline[plPtrRead].opcode = PIPELINE_STALL; -#ifdef DSP_DEBUG_PL3 -} -#endif - else - { - pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1]; - pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2]; - pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN - - // Shouldn't we be more selective with the register scoreboarding? - // Yes, we should. !!! FIX !!! [Kinda DONE] - scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode]; - -//Advance PC here??? Yes. - dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2); - } - -#ifdef DSP_DEBUG_PL3 -WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n"); -WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -#endif - // Stage 2a: Execute - if (pipeline[plPtrExec].opcode != PIPELINE_STALL) - { -#ifdef DSP_DEBUG_PL3 -WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]); -#endif - DSPOpcode[pipeline[plPtrExec].opcode](); - dsp_opcode_use[pipeline[plPtrExec].opcode]++; - cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode]; - } - else - cycles--; - -#ifdef DSP_DEBUG_PL3 -WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n"); -WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]); -WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]); -WriteLog("\n"); -#endif - // Stage 2b: Write back register - if (pipeline[plPtrExec].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrExec].writebackRegister != 0xFF) - dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result; - - if (affectsScoreboard[pipeline[plPtrExec].opcode]) - scoreboard[pipeline[plPtrExec].operand2] = false; - } - - // Push instructions through the pipeline... - plPtrRead = (++plPtrRead) & 0x03; - plPtrExec = (++plPtrExec) & 0x03; - } - - dsp_in_exec--; -}*/ - -// -// DSP pipelined opcode handlers -// - -#define PRM pipeline[plPtrExec].reg1 -#define PRN pipeline[plPtrExec].reg2 -#define PIMM1 pipeline[plPtrExec].operand1 -#define PIMM2 pipeline[plPtrExec].operand2 -#define PRES pipeline[plPtrExec].result -#define PWBR pipeline[plPtrExec].writebackRegister -#define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF -//#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2) -#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2)) - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)) -#define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE - -static void DSP_abs(void) -{ -#ifdef DSP_DIS_ABS - if (doDSPDis) - WriteLog("%06X: ABS R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - uint32_t _Rn = PRN; - - if (_Rn == 0x80000000) - dsp_flag_n = 1; - else - { - dsp_flag_c = ((_Rn & 0x80000000) >> 31); - PRES = (_Rn & 0x80000000 ? -_Rn : _Rn); - CLR_ZN; SET_Z(PRES); - } -#ifdef DSP_DIS_ABS - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_add(void) -{ -#ifdef DSP_DIS_ADD - if (doDSPDis) - WriteLog("%06X: ADD R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - uint32_t res = PRN + PRM; - SET_ZNC_ADD(PRN, PRM, res); - PRES = res; -#ifdef DSP_DIS_ADD - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_addc(void) -{ -#ifdef DSP_DIS_ADDC - if (doDSPDis) - WriteLog("%06X: ADDC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - uint32_t res = PRN + PRM + dsp_flag_c; - uint32_t carry = dsp_flag_c; -// SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes! - SET_ZNC_ADD(PRN + carry, PRM, res); -// SET_ZNC_ADD(PRN, PRM + carry, res); - PRES = res; -#ifdef DSP_DIS_ADDC - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_addq(void) -{ -#ifdef DSP_DIS_ADDQ - if (doDSPDis) - WriteLog("%06X: ADDQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - uint32_t r1 = dsp_convert_zero[PIMM1]; - uint32_t res = PRN + r1; - CLR_ZNC; SET_ZNC_ADD(PRN, r1, res); - PRES = res; -#ifdef DSP_DIS_ADDQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_addqmod(void) -{ -#ifdef DSP_DIS_ADDQMOD - if (doDSPDis) - WriteLog("%06X: ADDQMOD #%u, R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_MOD=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, dsp_modulo); -#endif - uint32_t r1 = dsp_convert_zero[PIMM1]; - uint32_t r2 = PRN; - uint32_t res = r2 + r1; - res = (res & (~dsp_modulo)) | (r2 & dsp_modulo); - PRES = res; - SET_ZNC_ADD(r2, r1, res); -#ifdef DSP_DIS_ADDQMOD - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_addqt(void) -{ -#ifdef DSP_DIS_ADDQT - if (doDSPDis) - WriteLog("%06X: ADDQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - PRES = PRN + dsp_convert_zero[PIMM1]; -#ifdef DSP_DIS_ADDQT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_and(void) -{ -#ifdef DSP_DIS_AND - if (doDSPDis) - WriteLog("%06X: AND R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - PRES = PRN & PRM; - SET_ZN(PRES); -#ifdef DSP_DIS_AND - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_bclr(void) -{ -#ifdef DSP_DIS_BCLR - if (doDSPDis) - WriteLog("%06X: BCLR #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - PRES = PRN & ~(1 << PIMM1); - SET_ZN(PRES); -#ifdef DSP_DIS_BCLR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_bset(void) -{ -#ifdef DSP_DIS_BSET - if (doDSPDis) - WriteLog("%06X: BSET #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - PRES = PRN | (1 << PIMM1); - SET_ZN(PRES); -#ifdef DSP_DIS_BSET - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_btst(void) -{ -#ifdef DSP_DIS_BTST - if (doDSPDis) - WriteLog("%06X: BTST #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - dsp_flag_z = (~PRN >> PIMM1) & 1; - NO_WRITEBACK; -#ifdef DSP_DIS_BTST - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif -} - -static void DSP_cmp(void) -{ -#ifdef DSP_DIS_CMP - if (doDSPDis) - WriteLog("%06X: CMP R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - uint32_t res = PRN - PRM; - SET_ZNC_SUB(PRN, PRM, res); - NO_WRITEBACK; -#ifdef DSP_DIS_CMP - if (doDSPDis) - WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif -} - -static void DSP_cmpq(void) -{ - static int32_t sqtable[32] = - { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1 }; -#ifdef DSP_DIS_CMPQ - if (doDSPDis) - WriteLog("%06X: CMPQ #%d, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, sqtable[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3; - uint32_t res = PRN - r1; - SET_ZNC_SUB(PRN, r1, res); - NO_WRITEBACK; -#ifdef DSP_DIS_CMPQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif -} - -static void DSP_div(void) -{ - uint32_t _Rm = PRM, _Rn = PRN; - - if (_Rm) - { - if (dsp_div_control & 1) - { - dsp_remain = (((uint64_t)_Rn) << 16) % _Rm; - if (dsp_remain & 0x80000000) - dsp_remain -= _Rm; - PRES = (((uint64_t)_Rn) << 16) / _Rm; - } - else - { - dsp_remain = _Rn % _Rm; - if (dsp_remain & 0x80000000) - dsp_remain -= _Rm; - PRES = PRN / _Rm; - } - } - else - PRES = 0xFFFFFFFF; -} - -static void DSP_imacn(void) -{ -#ifdef DSP_DIS_IMACN - if (doDSPDis) - WriteLog("%06X: IMACN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - int32_t res = (int16_t)PRM * (int16_t)PRN; - dsp_acc += (int64_t)res; -//Should we AND the result to fit into 40 bits here??? - NO_WRITEBACK; -#ifdef DSP_DIS_IMACN - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF)); -#endif -} - -static void DSP_imult(void) -{ -#ifdef DSP_DIS_IMULT - if (doDSPDis) - WriteLog("%06X: IMULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - PRES = (int16_t)PRN * (int16_t)PRM; - SET_ZN(PRES); -#ifdef DSP_DIS_IMULT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_imultn(void) -{ -#ifdef DSP_DIS_IMULTN - if (doDSPDis) - WriteLog("%06X: IMULTN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - // This is OK, since this multiply won't overflow 32 bits... - int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM); - dsp_acc = (int64_t)res; - SET_ZN(res); - NO_WRITEBACK; -#ifdef DSP_DIS_IMULTN - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF)); -#endif -} - -static void DSP_illegal(void) -{ -#ifdef DSP_DIS_ILLEGAL - if (doDSPDis) - WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif - NO_WRITEBACK; -} - -// There is a problem here with interrupt handlers the JUMP and JR instructions that -// can cause trouble because an interrupt can occur *before* the instruction following the -// jump can execute... !!! FIX !!! -// This can probably be solved by judicious coding in the pipeline execution core... -// And should be fixed now... -static void DSP_jr(void) -{ -#ifdef DSP_DIS_JR -const char * condition[32] = -{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz", - "c z", "???", "???", "???", "???", "???", "???", "???", "???", - "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???", - "???", "???", "???", "F" }; - if (doDSPDis) -//How come this is always off by 2??? - WriteLog("%06X: JR %s, %06X [NCZ:%u%u%u] ", DSP_PPC, condition[PIMM2], DSP_PPC+((PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1) * 2)+2, dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif - // KLUDGE: Used by BRANCH_CONDITION macro - uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z; - - if (BRANCH_CONDITION(PIMM2)) - { -#ifdef DSP_DIS_JR - if (doDSPDis) - WriteLog("Branched!\n"); -#endif - int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1 -//Account for pipeline effects... - uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2)); -//WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC); - - // Now that we've branched, we have to make sure that the following instruction - // is executed atomically with this one and then flush the pipeline before setting - // the new PC. - - // Step 1: Handle writebacks at stage 3 of pipeline -/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - scoreboard[pipeline[plPtrWrite].operand2] = false; - }//*/ - if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFE) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - else - { - if (pipeline[plPtrWrite].type == TYPE_BYTE) - JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else if (pipeline[plPtrWrite].type == TYPE_WORD) - JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else - JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - } - } - -#ifndef NEW_SCOREBOARD - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - scoreboard[pipeline[plPtrWrite].operand2] = false; -#else -//Yup, sequential MOVEQ # problem fixing (I hope!)... - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - if (scoreboard[pipeline[plPtrWrite].operand2]) - scoreboard[pipeline[plPtrWrite].operand2]--; -#endif - } - - // Step 2: Push instruction through pipeline & execute following instruction - // NOTE: By putting our following instruction at stage 3 of the pipeline, - // we effectively handle the final push of the instruction through the - // pipeline when the new PC takes effect (since when we return, the - // pipeline code will be executing the writeback stage. If we reverse - // the execution order of the pipeline stages, this will no longer be - // the case!)... - pipeline[plPtrExec] = pipeline[plPtrRead]; -//This is BAD. We need to get that next opcode and execute it! -//NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably -// remove this crap. - if (pipeline[plPtrExec].opcode == PIPELINE_STALL) - { - uint16_t instruction = DSPReadWord(dsp_pc, DSP); - pipeline[plPtrExec].opcode = instruction >> 10; - pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F; - pipeline[plPtrExec].operand2 = instruction & 0x1F; - pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1]; - pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2]; - pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN - }//*/ - dsp_pc += 2; // For DSP_DIS_* accuracy - DSPOpcode[pipeline[plPtrExec].opcode](); - dsp_opcode_use[pipeline[plPtrExec].opcode]++; - pipeline[plPtrWrite] = pipeline[plPtrExec]; - - // Step 3: Flush pipeline & set new PC - pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL; - dsp_pc = newPC; - } - else -#ifdef DSP_DIS_JR - { - if (doDSPDis) - WriteLog("Branch NOT taken.\n"); -#endif - NO_WRITEBACK; -#ifdef DSP_DIS_JR - } -#endif -// WriteLog(" --> DSP_PC: %08X\n", dsp_pc); -} - -static void DSP_jump(void) -{ -#ifdef DSP_DIS_JUMP -const char * condition[32] = -{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz", - "c z", "???", "???", "???", "???", "???", "???", "???", "???", - "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???", - "???", "???", "???", "F" }; - if (doDSPDis) - WriteLog("%06X: JUMP %s, (R%02u) [NCZ:%u%u%u, R%02u=%08X] ", DSP_PPC, condition[PIMM2], PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM); -#endif - // KLUDGE: Used by BRANCH_CONDITION macro - uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z; - - if (BRANCH_CONDITION(PIMM2)) - { -#ifdef DSP_DIS_JUMP - if (doDSPDis) - WriteLog("Branched!\n"); -#endif - uint32_t PCSave = PRM; - // Now that we've branched, we have to make sure that the following instruction - // is executed atomically with this one and then flush the pipeline before setting - // the new PC. - - // Step 1: Handle writebacks at stage 3 of pipeline -/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - scoreboard[pipeline[plPtrWrite].operand2] = false; - }//*/ - if (pipeline[plPtrWrite].opcode != PIPELINE_STALL) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFF) - { - if (pipeline[plPtrWrite].writebackRegister != 0xFE) - dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result; - else - { - if (pipeline[plPtrWrite].type == TYPE_BYTE) - JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else if (pipeline[plPtrWrite].type == TYPE_WORD) - JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - else - JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value); - } - } - -#ifndef NEW_SCOREBOARD - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - scoreboard[pipeline[plPtrWrite].operand2] = false; -#else -//Yup, sequential MOVEQ # problem fixing (I hope!)... - if (affectsScoreboard[pipeline[plPtrWrite].opcode]) - if (scoreboard[pipeline[plPtrWrite].operand2]) - scoreboard[pipeline[plPtrWrite].operand2]--; -#endif - } - - // Step 2: Push instruction through pipeline & execute following instruction - // NOTE: By putting our following instruction at stage 3 of the pipeline, - // we effectively handle the final push of the instruction through the - // pipeline when the new PC takes effect (since when we return, the - // pipeline code will be executing the writeback stage. If we reverse - // the execution order of the pipeline stages, this will no longer be - // the case!)... - pipeline[plPtrExec] = pipeline[plPtrRead]; -//This is BAD. We need to get that next opcode and execute it! -//Also, same problem in JR! -//NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably -// remove this crap. - if (pipeline[plPtrExec].opcode == PIPELINE_STALL) - { - uint16_t instruction = DSPReadWord(dsp_pc, DSP); - pipeline[plPtrExec].opcode = instruction >> 10; - pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F; - pipeline[plPtrExec].operand2 = instruction & 0x1F; - pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1]; - pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2]; - pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN - }//*/ - dsp_pc += 2; // For DSP_DIS_* accuracy - DSPOpcode[pipeline[plPtrExec].opcode](); - dsp_opcode_use[pipeline[plPtrExec].opcode]++; - pipeline[plPtrWrite] = pipeline[plPtrExec]; - - // Step 3: Flush pipeline & set new PC - pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL; - dsp_pc = PCSave; - } - else -#ifdef DSP_DIS_JUMP - { - if (doDSPDis) - WriteLog("Branch NOT taken.\n"); -#endif - NO_WRITEBACK; -#ifdef DSP_DIS_JUMP - } -#endif -} - -static void DSP_load(void) -{ -#ifdef DSP_DIS_LOAD - if (doDSPDis) - WriteLog("%06X: LOAD (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT - PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP); -#else - PRES = DSPReadLong(PRM, DSP); -#endif -#ifdef DSP_DIS_LOAD - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_loadb(void) -{ -#ifdef DSP_DIS_LOADB - if (doDSPDis) - WriteLog("%06X: LOADB (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF)) - PRES = DSPReadLong(PRM, DSP) & 0xFF; - else - PRES = JaguarReadByte(PRM, DSP); -#ifdef DSP_DIS_LOADB - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_loadw(void) -{ -#ifdef DSP_DIS_LOADW - if (doDSPDis) - WriteLog("%06X: LOADW (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT - if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF)) - PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF; - else - PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP); -#else - if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF)) - PRES = DSPReadLong(PRM, DSP) & 0xFFFF; - else - PRES = JaguarReadWord(PRM, DSP); -#endif -#ifdef DSP_DIS_LOADW - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_load_r14_i(void) -{ -#ifdef DSP_DIS_LOAD14I - if (doDSPDis) - WriteLog("%06X: LOAD (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1] << 2, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[PIMM1] << 2, dsp_reg[14]+(dsp_convert_zero[PIMM1] << 2), PIMM2, PRN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT - PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP); -#else - PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP); -#endif -#ifdef DSP_DIS_LOAD14I - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_load_r14_r(void) -{ -#ifdef DSP_DIS_LOAD14R - if (doDSPDis) - WriteLog("%06X: LOAD (R14+R%02u), R%02u [NCZ:%u%u%u, R14+R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM+dsp_reg[14], PIMM2, PRES); -#endif -#ifdef DSP_CORRECT_ALIGNMENT - PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP); -#else - PRES = DSPReadLong(dsp_reg[14] + PRM, DSP); -#endif -#ifdef DSP_DIS_LOAD14R - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_load_r15_i(void) -{ -#ifdef DSP_DIS_LOAD15I - if (doDSPDis) - WriteLog("%06X: LOAD (R15+$%02X), R%02u [NCZ:%u%u%u, R15+$%02X=%08X, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1] << 2, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[PIMM1] << 2, dsp_reg[15]+(dsp_convert_zero[PIMM1] << 2), PIMM2, PRN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT - PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP); -#else - PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP); -#endif -#ifdef DSP_DIS_LOAD15I - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_load_r15_r(void) -{ -#ifdef DSP_DIS_LOAD15R - if (doDSPDis) - WriteLog("%06X: LOAD (R15+R%02u), R%02u [NCZ:%u%u%u, R15+R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM+dsp_reg[15], PIMM2, PRN); -#endif -#ifdef DSP_CORRECT_ALIGNMENT - PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP); -#else - PRES = DSPReadLong(dsp_reg[15] + PRM, DSP); -#endif -#ifdef DSP_DIS_LOAD15R - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_mirror(void) -{ - uint32_t r1 = PRN; - PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16]; - SET_ZN(PRES); -} - -static void DSP_mmult(void) -{ - int count = dsp_matrix_control&0x0f; - uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram - int64_t accum = 0; - uint32_t res; - - if (!(dsp_matrix_control & 0x10)) - { - for (int i = 0; i < count; i++) - { - int16_t a; - if (i&0x01) - a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff); - else - a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff); - int16_t b=((int16_t)DSPReadWord(addr + 2, DSP)); - accum += a*b; - addr += 4; - } - } - else - { - for (int i = 0; i < count; i++) - { - int16_t a; - if (i&0x01) - a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff); - else - a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff); - int16_t b=((int16_t)DSPReadWord(addr + 2, DSP)); - accum += a*b; - addr += 4 * count; - } - } - - PRES = res = (int32_t)accum; - // carry flag to do -//NOTE: The flags are set based upon the last add/multiply done... - SET_ZN(PRES); -} - -static void DSP_move(void) -{ -#ifdef DSP_DIS_MOVE - if (doDSPDis) - WriteLog("%06X: MOVE R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - PRES = PRM; -#ifdef DSP_DIS_MOVE - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_movefa(void) -{ -#ifdef DSP_DIS_MOVEFA - if (doDSPDis) -// WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, ALTERNATE_RM, PIMM2, PRN); - WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, dsp_alternate_reg[PIMM1], PIMM2, PRN); -#endif -// PRES = ALTERNATE_RM; - PRES = dsp_alternate_reg[PIMM1]; -#ifdef DSP_DIS_MOVEFA - if (doDSPDis) -// WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, ALTERNATE_RM, PIMM2, PRN); - WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, dsp_alternate_reg[PIMM1], PIMM2, PRES); -#endif -} - -static void DSP_movei(void) -{ -#ifdef DSP_DIS_MOVEI - if (doDSPDis) - WriteLog("%06X: MOVEI #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PRES, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif -// // This instruction is followed by 32-bit value in LSW / MSW format... -// PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16); -// dsp_pc += 4; -#ifdef DSP_DIS_MOVEI - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_movepc(void) -{ -#ifdef DSP_DIS_MOVEPC - if (doDSPDis) - WriteLog("%06X: MOVE PC, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif -//Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE] -// PRES = dsp_pc - 2; -//Account for pipeline effects... - PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2)); -#ifdef DSP_DIS_MOVEPC - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_moveq(void) -{ -#ifdef DSP_DIS_MOVEQ - if (doDSPDis) - WriteLog("%06X: MOVEQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - PRES = PIMM1; -#ifdef DSP_DIS_MOVEQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_moveta(void) -{ -#ifdef DSP_DIS_MOVETA - if (doDSPDis) -// WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, ALTERNATE_RN); - WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, dsp_alternate_reg[PIMM2]); -#endif -// ALTERNATE_RN = PRM; - dsp_alternate_reg[PIMM2] = PRM; - NO_WRITEBACK; -#ifdef DSP_DIS_MOVETA - if (doDSPDis) -// WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, ALTERNATE_RN); - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, dsp_alternate_reg[PIMM2]); -#endif -} - -static void DSP_mtoi(void) -{ - PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF); - SET_ZN(PRES); -} - -static void DSP_mult(void) -{ -#ifdef DSP_DIS_MULT - if (doDSPDis) - WriteLog("%06X: MULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - PRES = (uint16_t)PRM * (uint16_t)PRN; - SET_ZN(PRES); -#ifdef DSP_DIS_MULT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_neg(void) -{ -#ifdef DSP_DIS_NEG - if (doDSPDis) - WriteLog("%06X: NEG R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - uint32_t res = -PRN; - SET_ZNC_SUB(0, PRN, res); - PRES = res; -#ifdef DSP_DIS_NEG - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_nop(void) -{ -#ifdef DSP_DIS_NOP - if (doDSPDis) - WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z); -#endif - NO_WRITEBACK; -} - -static void DSP_normi(void) -{ - uint32_t _Rm = PRM; - uint32_t res = 0; - - if (_Rm) - { - while ((_Rm & 0xffc00000) == 0) - { - _Rm <<= 1; - res--; - } - while ((_Rm & 0xff800000) != 0) - { - _Rm >>= 1; - res++; - } - } - PRES = res; - SET_ZN(PRES); -} - -static void DSP_not(void) -{ -#ifdef DSP_DIS_NOT - if (doDSPDis) - WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - PRES = ~PRN; - SET_ZN(PRES); -#ifdef DSP_DIS_NOT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_or(void) -{ -#ifdef DSP_DIS_OR - if (doDSPDis) - WriteLog("%06X: OR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - PRES = PRN | PRM; - SET_ZN(PRES); -#ifdef DSP_DIS_OR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_resmac(void) -{ -#ifdef DSP_DIS_RESMAC - if (doDSPDis) - WriteLog("%06X: RESMAC R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_ACC=%02X%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF)); -#endif - PRES = (uint32_t)dsp_acc; -#ifdef DSP_DIS_RESMAC - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif -} - -static void DSP_ror(void) -{ -#ifdef DSP_DIS_ROR - if (doDSPDis) - WriteLog("%06X: ROR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - uint32_t r1 = PRM & 0x1F; - uint32_t res = (PRN >> r1) | (PRN << (32 - r1)); - SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1; - PRES = res; -#ifdef DSP_DIS_ROR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_rorq(void) -{ -#ifdef DSP_DIS_RORQ - if (doDSPDis) - WriteLog("%06X: RORQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F]; - uint32_t r2 = PRN; - uint32_t res = (r2 >> r1) | (r2 << (32 - r1)); - PRES = res; - SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01; -#ifdef DSP_DIS_RORQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_sat16s(void) -{ - int32_t r2 = PRN; - uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2; - PRES = res; - SET_ZN(res); -} - -static void DSP_sat32s(void) -{ - int32_t r2 = (uint32_t)PRN; - int32_t temp = dsp_acc >> 32; - uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2; - PRES = res; - SET_ZN(res); -} - -static void DSP_sh(void) -{ - int32_t sRm = (int32_t)PRM; - uint32_t _Rn = PRN; - - if (sRm < 0) - { - uint32_t shift = -sRm; - - if (shift >= 32) - shift = 32; - - dsp_flag_c = (_Rn & 0x80000000) >> 31; - - while (shift) - { - _Rn <<= 1; - shift--; - } - } - else - { - uint32_t shift = sRm; - - if (shift >= 32) - shift = 32; - - dsp_flag_c = _Rn & 0x1; - - while (shift) - { - _Rn >>= 1; - shift--; - } - } - - PRES = _Rn; - SET_ZN(PRES); -} - -static void DSP_sha(void) -{ - int32_t sRm = (int32_t)PRM; - uint32_t _Rn = PRN; - - if (sRm < 0) - { - uint32_t shift = -sRm; - - if (shift >= 32) - shift = 32; - - dsp_flag_c = (_Rn & 0x80000000) >> 31; - - while (shift) - { - _Rn <<= 1; - shift--; - } - } - else - { - uint32_t shift = sRm; - - if (shift >= 32) - shift = 32; - - dsp_flag_c = _Rn & 0x1; - - while (shift) - { - _Rn = ((int32_t)_Rn) >> 1; - shift--; - } - } - - PRES = _Rn; - SET_ZN(PRES); -} - -static void DSP_sharq(void) -{ -#ifdef DSP_DIS_SHARQ - if (doDSPDis) - WriteLog("%06X: SHARQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1]; - SET_ZN(res); dsp_flag_c = PRN & 0x01; - PRES = res; -#ifdef DSP_DIS_SHARQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_shlq(void) -{ -#ifdef DSP_DIS_SHLQ - if (doDSPDis) - WriteLog("%06X: SHLQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, 32 - PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - int32_t r1 = 32 - PIMM1; - uint32_t res = PRN << r1; - SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1; - PRES = res; -#ifdef DSP_DIS_SHLQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_shrq(void) -{ -#ifdef DSP_DIS_SHRQ - if (doDSPDis) - WriteLog("%06X: SHRQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - int32_t r1 = dsp_convert_zero[PIMM1]; - uint32_t res = PRN >> r1; - SET_ZN(res); dsp_flag_c = PRN & 1; - PRES = res; -#ifdef DSP_DIS_SHRQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_store(void) -{ -#ifdef DSP_DIS_STORE - if (doDSPDis) - WriteLog("%06X: STORE R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", DSP_PPC, PIMM2, PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, PIMM1, PRM); -#endif -// DSPWriteLong(PRM, PRN, DSP); -// NO_WRITEBACK; -#ifdef DSP_CORRECT_ALIGNMENT_STORE - pipeline[plPtrExec].address = PRM & 0xFFFFFFFC; -#else - pipeline[plPtrExec].address = PRM; -#endif - pipeline[plPtrExec].value = PRN; - pipeline[plPtrExec].type = TYPE_DWORD; - WRITEBACK_ADDR; -} - -static void DSP_storeb(void) -{ -#ifdef DSP_DIS_STOREB - if (doDSPDis) - WriteLog("%06X: STOREB R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", DSP_PPC, PIMM2, PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, PIMM1, PRM); -#endif -// if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF)) -// DSPWriteLong(PRM, PRN & 0xFF, DSP); -// else -// JaguarWriteByte(PRM, PRN, DSP); -// -// NO_WRITEBACK; - pipeline[plPtrExec].address = PRM; - - if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF)) - { - pipeline[plPtrExec].value = PRN & 0xFF; - pipeline[plPtrExec].type = TYPE_DWORD; - } - else - { - pipeline[plPtrExec].value = PRN; - pipeline[plPtrExec].type = TYPE_BYTE; - } - - WRITEBACK_ADDR; -} - -static void DSP_storew(void) -{ -#ifdef DSP_DIS_STOREW - if (doDSPDis) - WriteLog("%06X: STOREW R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", DSP_PPC, PIMM2, PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, PIMM1, PRM); -#endif -// if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF)) -// DSPWriteLong(PRM, PRN & 0xFFFF, DSP); -// else -// JaguarWriteWord(PRM, PRN, DSP); -// -// NO_WRITEBACK; -#ifdef DSP_CORRECT_ALIGNMENT_STORE - pipeline[plPtrExec].address = PRM & 0xFFFFFFFE; -#else - pipeline[plPtrExec].address = PRM; -#endif - - if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF)) - { - pipeline[plPtrExec].value = PRN & 0xFFFF; - pipeline[plPtrExec].type = TYPE_DWORD; - } - else - { - pipeline[plPtrExec].value = PRN; - pipeline[plPtrExec].type = TYPE_WORD; - } - WRITEBACK_ADDR; -} - -static void DSP_store_r14_i(void) -{ -#ifdef DSP_DIS_STORE14I - if (doDSPDis) - WriteLog("%06X: STORE R%02u, (R14+$%02X) [NCZ:%u%u%u, R%02u=%08X, R14+$%02X=%08X]\n", DSP_PPC, PIMM2, dsp_convert_zero[PIMM1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, dsp_convert_zero[PIMM1] << 2, dsp_reg[14]+(dsp_convert_zero[PIMM1] << 2)); -#endif -// DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP); -// NO_WRITEBACK; -#ifdef DSP_CORRECT_ALIGNMENT_STORE - pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2); -#else - pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2); -#endif - pipeline[plPtrExec].value = PRN; - pipeline[plPtrExec].type = TYPE_DWORD; - WRITEBACK_ADDR; -} - -static void DSP_store_r14_r(void) -{ -// DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP); -// NO_WRITEBACK; -#ifdef DSP_CORRECT_ALIGNMENT_STORE - pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC; -#else - pipeline[plPtrExec].address = dsp_reg[14] + PRM; -#endif - pipeline[plPtrExec].value = PRN; - pipeline[plPtrExec].type = TYPE_DWORD; - WRITEBACK_ADDR; -} - -static void DSP_store_r15_i(void) -{ -#ifdef DSP_DIS_STORE15I - if (doDSPDis) - WriteLog("%06X: STORE R%02u, (R15+$%02X) [NCZ:%u%u%u, R%02u=%08X, R15+$%02X=%08X]\n", DSP_PPC, PIMM2, dsp_convert_zero[PIMM1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, dsp_convert_zero[PIMM1] << 2, dsp_reg[15]+(dsp_convert_zero[PIMM1] << 2)); -#endif -// DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP); -// NO_WRITEBACK; -#ifdef DSP_CORRECT_ALIGNMENT_STORE - pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2); -#else - pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2); -#endif - pipeline[plPtrExec].value = PRN; - pipeline[plPtrExec].type = TYPE_DWORD; - WRITEBACK_ADDR; -} - -static void DSP_store_r15_r(void) -{ -// DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP); -// NO_WRITEBACK; -#ifdef DSP_CORRECT_ALIGNMENT_STORE - pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC; -#else - pipeline[plPtrExec].address = dsp_reg[15] + PRM; -#endif - pipeline[plPtrExec].value = PRN; - pipeline[plPtrExec].type = TYPE_DWORD; - WRITEBACK_ADDR; -} - -static void DSP_sub(void) -{ -#ifdef DSP_DIS_SUB - if (doDSPDis) - WriteLog("%06X: SUB R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - uint32_t res = PRN - PRM; - SET_ZNC_SUB(PRN, PRM, res); - PRES = res; -#ifdef DSP_DIS_SUB - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_subc(void) -{ -#ifdef DSP_DIS_SUBC - if (doDSPDis) - WriteLog("%06X: SUBC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - uint32_t res = PRN - PRM - dsp_flag_c; - uint32_t borrow = dsp_flag_c; - SET_ZNC_SUB(PRN - borrow, PRM, res); - PRES = res; -#ifdef DSP_DIS_SUBC - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif -} - -static void DSP_subq(void) -{ -#ifdef DSP_DIS_SUBQ - if (doDSPDis) - WriteLog("%06X: SUBQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - uint32_t r1 = dsp_convert_zero[PIMM1]; - uint32_t res = PRN - r1; - SET_ZNC_SUB(PRN, r1, res); - PRES = res; -#ifdef DSP_DIS_SUBQ - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_subqmod(void) -{ - uint32_t r1 = dsp_convert_zero[PIMM1]; - uint32_t r2 = PRN; - uint32_t res = r2 - r1; - res = (res & (~dsp_modulo)) | (r2 & dsp_modulo); - PRES = res; - SET_ZNC_SUB(r2, r1, res); -} - -static void DSP_subqt(void) -{ -#ifdef DSP_DIS_SUBQT - if (doDSPDis) - WriteLog("%06X: SUBQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN); -#endif - PRES = PRN - dsp_convert_zero[PIMM1]; -#ifdef DSP_DIS_SUBQT - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES); -#endif -} - -static void DSP_xor(void) -{ -#ifdef DSP_DIS_XOR - if (doDSPDis) - WriteLog("%06X: XOR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN); -#endif - PRES = PRN ^ PRM; - SET_ZN(PRES); -#ifdef DSP_DIS_XOR - if (doDSPDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES); -#endif } diff --git a/waterbox/virtualjaguar/src/dsp.h b/waterbox/virtualjaguar/src/dsp.h index e1d77dd704..7f471b919c 100644 --- a/waterbox/virtualjaguar/src/dsp.h +++ b/waterbox/virtualjaguar/src/dsp.h @@ -15,7 +15,6 @@ void DSPReset(void); void DSPExec(int32_t); void DSPDone(void); void DSPUpdateRegisterBanks(void); -void DSPHandleIRQs(void); void DSPSetIRQLine(int irqline, int state); uint8_t DSPReadByte(uint32_t offset, uint32_t who = UNKNOWN); uint16_t DSPReadWord(uint32_t offset, uint32_t who = UNKNOWN); @@ -26,14 +25,8 @@ void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who = UNKNOWN); void DSPReleaseTimeslice(void); bool DSPIsRunning(void); -void DSPExecP(int32_t cycles); -void DSPExecP2(int32_t cycles); -//void DSPExecP3(int32_t cycles); -void DSPExecComp(int32_t cycles); - // Exported vars -extern bool doDSPDis; extern uint32_t dsp_reg_bank_0[], dsp_reg_bank_1[]; // DSP interrupt numbers (in $F1A100, bits 4-8 & 16) diff --git a/waterbox/virtualjaguar/src/eeprom.cpp b/waterbox/virtualjaguar/src/eeprom.cpp index 0c9dcadfae..2854f5a4ec 100644 --- a/waterbox/virtualjaguar/src/eeprom.cpp +++ b/waterbox/virtualjaguar/src/eeprom.cpp @@ -16,34 +16,22 @@ #include "eeprom.h" #include -#include // For memset +#include #include "jaguar.h" -#include "log.h" -#include "settings.h" - -//#define eeprom_LOG uint16_t eeprom_ram[64]; -uint16_t cdromEEPROM[64]; bool eeprom_dirty; -// -// Private function prototypes -// - static void EEPROMSave(void); static void eeprom_set_di(uint32_t state); static void eeprom_set_cs(uint32_t state); static uint32_t eeprom_get_do(void); - enum { EE_STATE_START = 1, EE_STATE_OP_A, EE_STATE_OP_B, EE_STATE_0, EE_STATE_1, EE_STATE_2, EE_STATE_3, EE_STATE_0_0, EE_READ_ADDRESS, EE_STATE_0_0_0, EE_STATE_0_0_1, EE_STATE_0_0_2, EE_STATE_0_0_3, EE_STATE_0_0_1_0, EE_READ_DATA, EE_STATE_BUSY, EE_STATE_1_0, EE_STATE_1_1, EE_STATE_2_0, EE_STATE_3_0 }; -// Local global variables - static uint16_t jerry_ee_state = EE_STATE_START; static uint16_t jerry_ee_op = 0; static uint16_t jerry_ee_rstate = 0; @@ -54,47 +42,36 @@ static uint16_t jerry_ee_data_cnt = 16; static uint16_t jerry_writes_enabled = 0; static uint16_t jerry_ee_direct_jump = 0; -static char eeprom_filename[MAX_PATH]; -static char cdromEEPROMFilename[MAX_PATH]; - - void EepromInit(void) { memset(eeprom_ram, 0xFF, 64 * sizeof(uint16_t)); - memset(cdromEEPROM, 0xFF, 64 * sizeof(uint16_t)); eeprom_dirty = false; } - void EepromReset(void) { } - void EepromDone(void) { - WriteLog("EEPROM: Done.\n"); } - static void EEPROMSave(void) { eeprom_dirty = true; } - uint8_t EepromReadByte(uint32_t offset) { switch (offset) { - case 0xF14001: - return eeprom_get_do(); - case 0xF14801: - break; - case 0xF15001: - eeprom_set_cs(1); - break; -// default: WriteLog("EEPROM: unmapped 0x%.8x\n", offset); break; + case 0xF14001: + return eeprom_get_do(); + case 0xF14801: + break; + case 0xF15001: + eeprom_set_cs(1); + break; } return 0x00; @@ -106,231 +83,182 @@ uint16_t EepromReadWord(uint32_t offset) return ((uint16_t)EepromReadByte(offset + 0) << 8) | EepromReadByte(offset + 1); } - void EepromWriteByte(uint32_t offset, uint8_t data) { switch (offset) { - case 0xF14001: - break; - case 0xF14801: - eeprom_set_di(data & 0x01); - break; - case 0xF15001: - eeprom_set_cs(1); - break; -// default: WriteLog("eeprom: unmapped 0x%.8x\n",offset); break; + case 0xF14001: + break; + case 0xF14801: + eeprom_set_di(data & 0x01); + break; + case 0xF15001: + eeprom_set_cs(1); + break; } } - void EepromWriteWord(uint32_t offset, uint16_t data) { EepromWriteByte(offset + 0, (data >> 8) & 0xFF); EepromWriteByte(offset + 1, data & 0xFF); } - -/* -; -; Commands specific to the National Semiconductor NM93C14 -; -; -; 9-bit commands.. -; 876543210 -eEWDS equ %100000000 ;Erase/Write disable (default) -eWRAL equ %100010000 ;Writes all registers -eERAL equ %100100000 ;Erase all registers -eEWEN equ %100110000 ;Erase/write Enable -eWRITE equ %101000000 ;Write selected register -eREAD equ %110000000 ;read from EEPROM -eERASE equ %111000000 ;Erase selected register -*/ - - static void eeprom_set_di(uint32_t data) { -// WriteLog("eeprom: di=%i\n",data); -// WriteLog("eeprom: state %i\n",jerry_ee_state); switch (jerry_ee_state) { - case EE_STATE_START: - jerry_ee_state = EE_STATE_OP_A; - break; - case EE_STATE_OP_A: - jerry_ee_op = (data << 1); - jerry_ee_state = EE_STATE_OP_B; - break; - case EE_STATE_OP_B: - jerry_ee_op |= data; - jerry_ee_direct_jump = 0; -// WriteLog("eeprom: opcode %i\n",jerry_ee_op); + case EE_STATE_START: + jerry_ee_state = EE_STATE_OP_A; + break; + case EE_STATE_OP_A: + jerry_ee_op = (data << 1); + jerry_ee_state = EE_STATE_OP_B; + break; + case EE_STATE_OP_B: + jerry_ee_op |= data; + jerry_ee_direct_jump = 0; - switch (jerry_ee_op) - { - // Opcode 00: eEWEN, eERAL, eWRAL, eEWNDS - case 0: jerry_ee_state = EE_STATE_0; break; - // Opcode 01: eWRITE (Write selected register) - case 1: jerry_ee_state = EE_STATE_1; break; - // Opcode 10: eREAD (Read from EEPROM) - case 2: jerry_ee_state = EE_STATE_2; break; - // Opcode 11: eERASE (Erase selected register) - case 3: jerry_ee_state = EE_STATE_3; break; - } + switch (jerry_ee_op) + { + case 0: jerry_ee_state = EE_STATE_0; break; + case 1: jerry_ee_state = EE_STATE_1; break; + case 2: jerry_ee_state = EE_STATE_2; break; + case 3: jerry_ee_state = EE_STATE_3; break; + } - eeprom_set_di(data); - break; - case EE_STATE_0: - jerry_ee_rstate = EE_STATE_0_0; - jerry_ee_state = EE_READ_ADDRESS; - jerry_ee_direct_jump = 1; - jerry_ee_address_cnt = 6; - jerry_ee_address_data = 0; - break; - case EE_STATE_0_0: - switch ((jerry_ee_address_data >> 4) & 0x03) - { - // Opcode 00 00: eEWDS (Erase/Write disable) - case 0: jerry_ee_state=EE_STATE_0_0_0; break; - // Opcode 00 01: eWRAL (Write all registers) - case 1: jerry_ee_state=EE_STATE_0_0_1; break; - // Opcode 00 10: eERAL (Erase all registers) - case 2: jerry_ee_state=EE_STATE_0_0_2; break; - // Opcode 00 11: eEWEN (Erase/Write enable) - case 3: jerry_ee_state=EE_STATE_0_0_3; break; - } + eeprom_set_di(data); + break; + case EE_STATE_0: + jerry_ee_rstate = EE_STATE_0_0; + jerry_ee_state = EE_READ_ADDRESS; + jerry_ee_direct_jump = 1; + jerry_ee_address_cnt = 6; + jerry_ee_address_data = 0; + break; + case EE_STATE_0_0: + switch ((jerry_ee_address_data >> 4) & 0x03) + { + case 0: jerry_ee_state=EE_STATE_0_0_0; break; + case 1: jerry_ee_state=EE_STATE_0_0_1; break; + case 2: jerry_ee_state=EE_STATE_0_0_2; break; + case 3: jerry_ee_state=EE_STATE_0_0_3; break; + } - eeprom_set_di(data); - break; - case EE_STATE_0_0_0: - // writes disable - // WriteLog("eeprom: read only\n"); - jerry_writes_enabled = 0; - jerry_ee_state = EE_STATE_START; - break; - case EE_STATE_0_0_1: - // writes all - jerry_ee_rstate = EE_STATE_0_0_1_0; - jerry_ee_state = EE_READ_DATA; - jerry_ee_data_cnt = 16; - jerry_ee_data = 0; - jerry_ee_direct_jump = 1; - break; - case EE_STATE_0_0_1_0: - // WriteLog("eeprom: filling eeprom with 0x%.4x\n",data); - if (jerry_writes_enabled) - { - for(int i=0; i<64; i++) - eeprom_ram[i] = jerry_ee_data; + eeprom_set_di(data); + break; + case EE_STATE_0_0_0: + jerry_writes_enabled = 0; + jerry_ee_state = EE_STATE_START; + break; + case EE_STATE_0_0_1: + jerry_ee_rstate = EE_STATE_0_0_1_0; + jerry_ee_state = EE_READ_DATA; + jerry_ee_data_cnt = 16; + jerry_ee_data = 0; + jerry_ee_direct_jump = 1; + break; + case EE_STATE_0_0_1_0: + if (jerry_writes_enabled) + { + for(int i=0; i<64; i++) + eeprom_ram[i] = jerry_ee_data; - EEPROMSave(); // Save it NOW! - } + EEPROMSave(); + } - //else - // WriteLog("eeprom: not writing because read only\n"); - jerry_ee_state = EE_STATE_BUSY; - break; - case EE_STATE_0_0_2: - // erase all - //WriteLog("eeprom: erasing eeprom\n"); - if (jerry_writes_enabled) - for(int i=0; i<64; i++) - eeprom_ram[i] = 0xFFFF; + jerry_ee_state = EE_STATE_BUSY; + break; + case EE_STATE_0_0_2: + if (jerry_writes_enabled) + for(int i=0; i<64; i++) + eeprom_ram[i] = 0xFFFF; - jerry_ee_state = EE_STATE_BUSY; - break; - case EE_STATE_0_0_3: - // writes enable - //WriteLog("eeprom: read/write\n"); - jerry_writes_enabled = 1; - jerry_ee_state = EE_STATE_START; - break; - case EE_STATE_1: - jerry_ee_rstate = EE_STATE_1_0; - jerry_ee_state = EE_READ_ADDRESS; - jerry_ee_address_cnt = 6; - jerry_ee_address_data = 0; - jerry_ee_direct_jump = 1; - break; - case EE_STATE_1_0: - jerry_ee_rstate = EE_STATE_1_1; - jerry_ee_state = EE_READ_DATA; - jerry_ee_data_cnt = 16; - jerry_ee_data = 0; - jerry_ee_direct_jump = 1; - break; - case EE_STATE_1_1: - //WriteLog("eeprom: writing 0x%.4x at 0x%.2x\n",jerry_ee_data,jerry_ee_address_data); - if (jerry_writes_enabled) - { - eeprom_ram[jerry_ee_address_data] = jerry_ee_data; - EEPROMSave(); // Save it NOW! - } + jerry_ee_state = EE_STATE_BUSY; + break; + case EE_STATE_0_0_3: + jerry_writes_enabled = 1; + jerry_ee_state = EE_STATE_START; + break; + case EE_STATE_1: + jerry_ee_rstate = EE_STATE_1_0; + jerry_ee_state = EE_READ_ADDRESS; + jerry_ee_address_cnt = 6; + jerry_ee_address_data = 0; + jerry_ee_direct_jump = 1; + break; + case EE_STATE_1_0: + jerry_ee_rstate = EE_STATE_1_1; + jerry_ee_state = EE_READ_DATA; + jerry_ee_data_cnt = 16; + jerry_ee_data = 0; + jerry_ee_direct_jump = 1; + break; + case EE_STATE_1_1: + if (jerry_writes_enabled) + { + eeprom_ram[jerry_ee_address_data] = jerry_ee_data; + EEPROMSave(); + } - jerry_ee_state = EE_STATE_BUSY; - break; - case EE_STATE_2: - jerry_ee_rstate = EE_STATE_2_0; - jerry_ee_state = EE_READ_ADDRESS; - jerry_ee_address_cnt = 6; - jerry_ee_address_data = 0; - jerry_ee_data_cnt = 16; - jerry_ee_data = 0; - break; - case EE_STATE_3: - jerry_ee_rstate = EE_STATE_3_0; - jerry_ee_state = EE_READ_ADDRESS; - jerry_ee_address_cnt = 6; - jerry_ee_address_data = 0; - jerry_ee_direct_jump = 1; - break; - case EE_STATE_3_0: - //WriteLog("eeprom: erasing 0x%.2x\n",jerry_ee_address_data); - if (jerry_writes_enabled) - eeprom_ram[jerry_ee_address_data] = 0xFFFF; + jerry_ee_state = EE_STATE_BUSY; + break; + case EE_STATE_2: + jerry_ee_rstate = EE_STATE_2_0; + jerry_ee_state = EE_READ_ADDRESS; + jerry_ee_address_cnt = 6; + jerry_ee_address_data = 0; + jerry_ee_data_cnt = 16; + jerry_ee_data = 0; + break; + case EE_STATE_3: + jerry_ee_rstate = EE_STATE_3_0; + jerry_ee_state = EE_READ_ADDRESS; + jerry_ee_address_cnt = 6; + jerry_ee_address_data = 0; + jerry_ee_direct_jump = 1; + break; + case EE_STATE_3_0: + if (jerry_writes_enabled) + eeprom_ram[jerry_ee_address_data] = 0xFFFF; - jerry_ee_state = EE_STATE_BUSY; - break; - case EE_READ_DATA: - //WriteLog("eeprom:\t\t\t%i bit %i\n",data,jerry_ee_data_cnt-1); - jerry_ee_data <<= 1; - jerry_ee_data |= data; - jerry_ee_data_cnt--; + jerry_ee_state = EE_STATE_BUSY; + break; + case EE_READ_DATA: + jerry_ee_data <<= 1; + jerry_ee_data |= data; + jerry_ee_data_cnt--; - if (!jerry_ee_data_cnt) - { - jerry_ee_state = jerry_ee_rstate; + if (!jerry_ee_data_cnt) + { + jerry_ee_state = jerry_ee_rstate; - if (jerry_ee_direct_jump) - eeprom_set_di(data); - } + if (jerry_ee_direct_jump) + eeprom_set_di(data); + } - break; - case EE_READ_ADDRESS: - jerry_ee_address_data <<= 1; - jerry_ee_address_data |= data; - jerry_ee_address_cnt--; -// WriteLog("eeprom:\t%i bits remaining\n",jerry_ee_address_cnt); + break; + case EE_READ_ADDRESS: + jerry_ee_address_data <<= 1; + jerry_ee_address_data |= data; + jerry_ee_address_cnt--; - if (!jerry_ee_address_cnt) - { - jerry_ee_state = jerry_ee_rstate; - //WriteLog("eeprom:\t\tread address 0x%.2x\n",jerry_ee_address_data); + if (!jerry_ee_address_cnt) + { + jerry_ee_state = jerry_ee_rstate; - if (jerry_ee_direct_jump) - eeprom_set_di(data); - } + if (jerry_ee_direct_jump) + eeprom_set_di(data); + } - break; - default: - jerry_ee_state = EE_STATE_OP_A; + break; + default: + jerry_ee_state = EE_STATE_OP_A; } } - -static void eeprom_set_cs(uint32_t /*state*/) +static void eeprom_set_cs(uint32_t) { -// WriteLog("eeprom: cs=%i\n",state); jerry_ee_state = EE_STATE_START; jerry_ee_op = 0; jerry_ee_rstate = 0; @@ -348,26 +276,24 @@ static uint32_t eeprom_get_do(void) switch (jerry_ee_state) { - case EE_STATE_START: - data = 1; - break; - case EE_STATE_BUSY: - jerry_ee_state = EE_STATE_START; - data = 0; - break; - case EE_STATE_2_0: - jerry_ee_data_cnt--; - data = (eeprom_ram[jerry_ee_address_data] >> jerry_ee_data_cnt) & 0x01; - - if (!jerry_ee_data_cnt) - { - //WriteLog("eeprom: read 0x%.4x at 0x%.2x cpu %i pc=0x%.8x\n",eeprom_ram[jerry_ee_address_data],jerry_ee_address_data,jaguar_cpu_in_exec,s68000readPC()); + case EE_STATE_START: + data = 1; + break; + case EE_STATE_BUSY: jerry_ee_state = EE_STATE_START; - } - break; + data = 0; + break; + case EE_STATE_2_0: + jerry_ee_data_cnt--; + data = (eeprom_ram[jerry_ee_address_data] >> jerry_ee_data_cnt) & 0x01; + + if (!jerry_ee_data_cnt) + { + jerry_ee_state = EE_STATE_START; + } + break; } -// WriteLog("eeprom: do=%i\n",data); return data; } diff --git a/waterbox/virtualjaguar/src/event.cpp b/waterbox/virtualjaguar/src/event.cpp index 56e960d155..df08603687 100644 --- a/waterbox/virtualjaguar/src/event.cpp +++ b/waterbox/virtualjaguar/src/event.cpp @@ -20,13 +20,9 @@ #include "event.h" #include -#include "log.h" - -//#define EVENT_LIST_SIZE 512 #define EVENT_LIST_SIZE 32 - // Now, a bit of weirdness: It seems that the number of lines displayed on the screen // makes the effective refresh rate either 30 or 25 Hz! @@ -47,14 +43,12 @@ struct Event void (* timerCallback)(void); }; - static Event eventList[EVENT_LIST_SIZE]; static Event eventListJERRY[EVENT_LIST_SIZE]; static uint32_t nextEvent; static uint32_t nextEventJERRY; static uint32_t numberOfEvents; - void InitializeEventList(void) { for(uint32_t i=0; i #include #include "crc32.h" -#include "filedb.h" #include "eeprom.h" #include "jaguar.h" -#include "log.h" #include "memory.h" -#include "universalhdr.h" -// Private function prototypes -//static int ParseFileType(uint8_t header1, uint8_t header2, uint32_t size); - -// Private variables/enums - - -// -// Jaguar file loading -// We do a more intelligent file analysis here instead of relying on (possible -// false) file extensions which people don't seem to give two shits about -// anyway. :-( -// bool JaguarLoadFile(uint8_t * buffer, uint32_t size) { jaguarROMSize = size; jaguarMainROMCRC32 = crc32_calcCheckSum(buffer, jaguarROMSize); - WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32); -// TODO: Check for EEPROM file in ZIP file. If there is no EEPROM in the user's EEPROM -// directory, copy the one from the ZIP file, if it exists. + EepromInit(); - jaguarRunAddress = 0x802000; // For non-BIOS runs, this is true + jaguarRunAddress = 0x802000; int fileType = ParseFileType(buffer, jaguarROMSize); jaguarCartInserted = false; @@ -56,31 +39,23 @@ bool JaguarLoadFile(uint8_t * buffer, uint32_t size) { jaguarCartInserted = true; memcpy(jagMemSpace + 0x800000, buffer, jaguarROMSize); -// Checking something... -jaguarRunAddress = GET32(jagMemSpace, 0x800404); -WriteLog("FILE: Cartridge run address is reported as $%X...\n", jaguarRunAddress); + jaguarRunAddress = GET32(jagMemSpace, 0x800404); return true; } else if (fileType == JST_ALPINE) { - // File extension ".ROM": Alpine image that loads/runs at $802000 - WriteLog("FILE: Setting up Alpine ROM... Run address: 00802000, length: %08X\n", jaguarROMSize); memset(jagMemSpace + 0x800000, 0xFF, 0x2000); memcpy(jagMemSpace + 0x802000, buffer, jaguarROMSize); -// Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought... - // Try setting the vector to say, $1000 and putting an instruction there that loops forever: - // This kludge works! Yeah! SET32(jaguarMainRAM, 0x10, 0x00001000); - SET16(jaguarMainRAM, 0x1000, 0x60FE); // Here: bra Here + SET16(jaguarMainRAM, 0x1000, 0x60FE); return true; } else if (fileType == JST_ABS_TYPE1) { - // For ABS type 1, run address == load address uint32_t loadAddress = GET32(buffer, 0x16), codeSize = GET32(buffer, 0x02) + GET32(buffer, 0x06); - WriteLog("FILE: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize); + memcpy(jagMemSpace + loadAddress, buffer + 0x24, codeSize); jaguarRunAddress = loadAddress; return true; @@ -89,134 +64,60 @@ WriteLog("FILE: Cartridge run address is reported as $%X...\n", jaguarRunAddress { uint32_t loadAddress = GET32(buffer, 0x28), runAddress = GET32(buffer, 0x24), codeSize = GET32(buffer, 0x18) + GET32(buffer, 0x1C); - WriteLog("FILE: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize); + memcpy(jagMemSpace + loadAddress, buffer + 0xA8, codeSize); jaguarRunAddress = runAddress; return true; } - // NB: This is *wrong* - /* - Basically, if there is no "JAG" at position $1C, then the long there is the load/start - address in LITTLE ENDIAN. - If "JAG" is present, the the next character ("R" or "L") determines the size of the - JagServer command (2 bytes vs. 4). Following that are the commands themselves; - typically it will either be 2 (load) or 3 (load & run). Command headers go like so: - 2: - Load address (long) - Length (long) - payload - 3: - Load address (long) - Length (long) - Run address (long) - payload - 5: (Reset) - [command only] - 7: (Run at address) - Run address (long) - [no payload] - 9: (Clear memory) - Start address (long) - End address (long) - [no payload] - 10: (Poll for commands) - [command only] - 12: (Load & run user program) - filname, terminated with NULL - [no payload] - $FFFF: (Halt) - [no payload] - */ else if (fileType == JST_JAGSERVER) { - // This kind of shiaut should be in the detection code below... - // (and now it is! :-) -// if (buffer[0x1C] == 'J' && buffer[0x1D] == 'A' && buffer[0x1E] == 'G') -// { - // Still need to do some checking here for type 2 vs. type 3. This assumes 3 - // Also, JAGR vs. JAGL (word command size vs. long command size) - uint32_t loadAddress = GET32(buffer, 0x22), runAddress = GET32(buffer, 0x2A); - WriteLog("FILE: Setting up homebrew (Jag Server)... Run address: $%X, length: $%X\n", runAddress, jaguarROMSize - 0x2E); - memcpy(jagMemSpace + loadAddress, buffer + 0x2E, jaguarROMSize - 0x2E); - jaguarRunAddress = runAddress; + uint32_t loadAddress = GET32(buffer, 0x22), runAddress = GET32(buffer, 0x2A); + memcpy(jagMemSpace + loadAddress, buffer + 0x2E, jaguarROMSize - 0x2E); + jaguarRunAddress = runAddress; -// Hmm. Is this kludge necessary? -SET32(jaguarMainRAM, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction) -SET16(jaguarMainRAM, 0x1000, 0x60FE); // Here: bra Here + SET32(jaguarMainRAM, 0x10, 0x00001000); + SET16(jaguarMainRAM, 0x1000, 0x60FE); - return true; -// } -// else // Special WTFOMGBBQ type here... -// { -// uint32_t loadAddress = (buffer[0x1F] << 24) | (buffer[0x1E] << 16) | (buffer[0x1D] << 8) | buffer[0x1C]; -// WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress, jaguarROMSize - 0x20); -// memcpy(jagMemSpace + loadAddress, buffer + 0x20, jaguarROMSize - 0x20); -// jaguarRunAddress = loadAddress; -// return true; -// } + return true; } else if (fileType == JST_WTFOMGBBQ) { uint32_t loadAddress = (buffer[0x1F] << 24) | (buffer[0x1E] << 16) | (buffer[0x1D] << 8) | buffer[0x1C]; - WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress, jaguarROMSize - 0x20); memcpy(jagMemSpace + loadAddress, buffer + 0x20, jaguarROMSize - 0x20); jaguarRunAddress = loadAddress; return true; } // We can assume we have JST_NONE at this point. :-P - WriteLog("FILE: Failed to load headerless file.\n"); return false; } - -// -// "Alpine" file loading -// Since the developers were coming after us with torches and pitchforks, we -// decided to allow this kind of thing. ;-) But ONLY FOR THE DEVS, DAMMIT! >:-U -// O_O -// bool AlpineLoadFile(uint8_t * buffer, uint32_t size) { jaguarROMSize = size; jaguarMainROMCRC32 = crc32_calcCheckSum(buffer, jaguarROMSize); - WriteLog("FILE: CRC is %08X\n", (unsigned int)jaguarMainROMCRC32); EepromInit(); jaguarRunAddress = 0x802000; - WriteLog("FILE: Setting up Alpine ROM with non-standard length... Run address: 00802000, length: %08X\n", jaguarROMSize); - memset(jagMemSpace + 0x800000, 0xFF, 0x2000); memcpy(jagMemSpace + 0x802000, buffer, jaguarROMSize); -// Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought... - // Try setting the vector to say, $1000 and putting an instruction there - // that loops forever: - // This kludge works! Yeah! - SET32(jaguarMainRAM, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction) - SET16(jaguarMainRAM, 0x1000, 0x60FE); // Here: bra Here + SET32(jaguarMainRAM, 0x10, 0x00001000); + SET16(jaguarMainRAM, 0x1000, 0x60FE); return true; } -// -// Parse the file type based upon file size and/or headers. -// uint32_t ParseFileType(uint8_t * buffer, uint32_t size) { - // Check headers first... - - // ABS/COFF type 1 if (buffer[0] == 0x60 && buffer[1] == 0x1B) return JST_ABS_TYPE1; - // ABS/COFF type 2 if (buffer[0] == 0x01 && buffer[1] == 0x50) return JST_ABS_TYPE2; - // Jag Server & other old shite if (buffer[0] == 0x60 && buffer[1] == 0x1A) { if (buffer[0x1C] == 'J' && buffer[0x1D] == 'A' && buffer[0x1E] == 'G') @@ -225,128 +126,11 @@ uint32_t ParseFileType(uint8_t * buffer, uint32_t size) return JST_WTFOMGBBQ; } - // And if that fails, try file sizes... - - // If the file size is divisible by 1M, we probably have an regular ROM. - // We can also check our CRC32 against the internal ROM database to be sure. - // (We also check for the Memory Track cartridge size here as well...) if ((size % 1048576) == 0 || size == 131072) return JST_ROM; - // If the file size + 8192 bytes is divisible by 1M, we probably have an - // Alpine format ROM. if (((size + 8192) % 1048576) == 0) return JST_ALPINE; - // Headerless crap return JST_NONE; } - -// -// Check for universal header -// -bool HasUniversalHeader(uint8_t * rom, uint32_t romSize) -{ - // Sanity check - if (romSize < 8192) - return false; - - for(int i=0; i<8192; i++) - if (rom[i] != universalCartHeader[i]) - return false; - - return true; -} - -#if 0 -// Misc. doco - -/* -Stubulator ROM vectors... -handler 001 at $00E00008 -handler 002 at $00E008DE -handler 003 at $00E008E2 -handler 004 at $00E008E6 -handler 005 at $00E008EA -handler 006 at $00E008EE -handler 007 at $00E008F2 -handler 008 at $00E0054A -handler 009 at $00E008FA -handler 010 at $00000000 -handler 011 at $00000000 -handler 012 at $00E008FE -handler 013 at $00E00902 -handler 014 at $00E00906 -handler 015 at $00E0090A -handler 016 at $00E0090E -handler 017 at $00E00912 -handler 018 at $00E00916 -handler 019 at $00E0091A -handler 020 at $00E0091E -handler 021 at $00E00922 -handler 022 at $00E00926 -handler 023 at $00E0092A -handler 024 at $00E0092E -handler 025 at $00E0107A -handler 026 at $00E0107A -handler 027 at $00E0107A -handler 028 at $00E008DA -handler 029 at $00E0107A -handler 030 at $00E0107A -handler 031 at $00E0107A -handler 032 at $00000000 - -Let's try setting up the illegal instruction vector for a stubulated jaguar... - - SET32(jaguar_mainRam, 0x08, 0x00E008DE); - SET32(jaguar_mainRam, 0x0C, 0x00E008E2); - SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)... - SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/ - -/* -ABS Format sleuthing (LBUGDEMO.ABS): - -000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00 -000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C -000020 00 00 40 00 - -DRI-format file detected... -Text segment size = 0x0000050c bytes -Data segment size = 0x000462c0 bytes -BSS Segment size = 0x00000428 bytes -Symbol Table size = 0x000012a6 bytes -Absolute Address for text segment = 0x00802000 -Absolute Address for data segment = 0x0080250c -Absolute Address for BSS segment = 0x00004000 - -(CRZDEMO.ABS): -000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b -000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98 -000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0 - -000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes) -000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00 -000050 00 00 00 00 00 00 00 20 -000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes) -000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00 -000078 00 00 00 00 00 00 00 40 -000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes) -000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00 -0000a0 00 00 00 00 00 00 00 80 - -Header size is $A8 bytes... - -BSD/COFF format file detected... -3 sections specified -Symbol Table offset = 230160 ($00038310) -Symbol Table contains 1339 symbol entries ($0000053B) -The additional header size is 28 bytes ($001C) -Magic Number for RUN_HDR = 0x00000107 -Text Segment Size = 7632 ($00001DD0) -Data Segment Size = 222360 ($00036498) -BSS Segment Size = 428928 ($00068B80) -Starting Address for executable = 0x00802000 -Start of Text Segment = 0x00802000 -Start of Data Segment = 0x00803dd0 -*/ -#endif diff --git a/waterbox/virtualjaguar/src/file.h b/waterbox/virtualjaguar/src/file.h index 7f6413b6ee..872a37c8a4 100644 --- a/waterbox/virtualjaguar/src/file.h +++ b/waterbox/virtualjaguar/src/file.h @@ -9,10 +9,6 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - enum FileType { FT_SOFTWARE=0, FT_EEPROM, FT_LABEL, FT_BOXART, FT_OVERLAY }; // JST = Jaguar Software Type enum { JST_NONE = 0, JST_ROM, JST_ALPINE, JST_ABS_TYPE1, JST_ABS_TYPE2, JST_JAGSERVER, JST_WTFOMGBBQ }; @@ -20,10 +16,5 @@ enum { JST_NONE = 0, JST_ROM, JST_ALPINE, JST_ABS_TYPE1, JST_ABS_TYPE2, JST_JAGS bool JaguarLoadFile(uint8_t * buffer, uint32_t size); bool AlpineLoadFile(uint8_t * buffer, uint32_t size); uint32_t ParseFileType(uint8_t * buffer, uint32_t size); -bool HasUniversalHeader(uint8_t * rom, uint32_t romSize); - -#ifdef __cplusplus -} -#endif #endif // __FILE_H__ diff --git a/waterbox/virtualjaguar/src/filedb.cpp b/waterbox/virtualjaguar/src/filedb.cpp deleted file mode 100644 index dd64da5bcf..0000000000 --- a/waterbox/virtualjaguar/src/filedb.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// -// filedb.cpp - File database -// -// by James Hammons -// (C) 2010 Underground Software -// -// JLH = James Hammons -// -// Who When What -// --- ---------- ------------------------------------------------------------ -// JLH 02/15/2010 Created this file -// - -#include "filedb.h" - - -#if 0 -struct RomIdentifier -{ - const uint32_t crc32; - const char name[128]; -// const uint8_t compatibility; - const uint32_t flags; -}; - -enum FileFlags { FF_ROM=1, FF_ALPINE=2, FF_BIOS=4, FF_REQ_DSP=8, FF_REQ_BIOS=16, FF_NON_WORKING=32, FF_BAD_DUMP=64, FF_VERIFIED=128 }; -#endif - -// Should have another flag for whether or not it requires DSP, BIOS, -// whether it's a .rom, it's a BIOS, etc... -// ... And now we do! :-D - -// How the CRCs work: -// If the cart has an RSA signature, we do a CRC on the whole file. -// If the cart has a universal header, we do a CRC on the file minus the UH. -// This is to ensure that we can detect something properly (like an Alpine ROM) -// that somebody slapped a universal header on. - -RomIdentifier romList[] = { - { 0x0509C85E, "Raiden (World) (alt)", FF_ROM | FF_REQ_BIOS }, - { 0x08849D0F, "Hyper Force (World)", FF_ALPINE | FF_VERIFIED }, - { 0x08F15576, "Iron Soldier (World) (v1.04)", FF_ROM | FF_VERIFIED }, - { 0x0957A072, "Kasumi Ninja (World)", FF_ROM | FF_VERIFIED }, - { 0x0AC83D77, "NBA Jam T.E. (World)", FF_ROM | FF_VERIFIED }, - { 0x0EC5369D, "Evolution - Dino Dudes (World)", FF_ROM | FF_VERIFIED }, - { 0x0F6A1C2C, "Ultra Vortek (World)", FF_ROM | FF_VERIFIED }, - { 0x0FDCEB66, "Brutal Sports Football (World)", FF_ROM | FF_BAD_DUMP }, - { 0x14915F20, "White Men Can't Jump (World)", FF_ROM | FF_VERIFIED }, - { 0x1660F070, "Power Drive Rally (World)", FF_ROM | FF_VERIFIED }, - { 0x1A20C5C4, "Protector (World)", FF_ROM | FF_VERIFIED | FF_REQ_DSP }, - { 0x1E451446, "Trevor McFur in the Crescent Galaxy (World)", FF_ROM | FF_VERIFIED }, - { 0x20936557, "Space War 2000", FF_ALPINE | FF_VERIFIED }, - { 0x27594C6A, "Defender 2000 (World)", FF_ROM | FF_VERIFIED }, - { 0x2BAA92A1, "Space War 2000 (World) (OVERDUMP)", FF_ALPINE }, - { 0x2E17D5DA, "Bubsy in Fractured Furry Tales (World)", FF_ROM | FF_VERIFIED }, - { 0x31812799, "Raiden (World)", FF_ROM | FF_VERIFIED }, - { 0x3241AB6A, "Towers II", FF_ALPINE }, - { 0x348E6449, "Double Dragon V - The Shadow Falls (World)", FF_ROM | FF_VERIFIED }, - { 0x3615AF6A, "Fever Pitch Soccer (World) (En,Fr,De,Es,It)", FF_ROM | FF_VERIFIED }, - { 0x38A130ED, "Troy Aikman NFL Football (World)", FF_ROM | FF_VERIFIED }, - { 0x40E1A1D0, "Air Cars (World)", FF_ROM | FF_VERIFIED }, - { 0x4471BFA0, "Skyhammer (World)", FF_ALPINE | FF_VERIFIED }, - { 0x47EBC158, "Theme Park (World)", FF_ROM | FF_VERIFIED }, - { 0x4899628F, "Hover Strike (World)", FF_ROM | FF_VERIFIED }, - { 0x4A08A2BD, "SuperCross 3D (World)", FF_ROM | FF_BAD_DUMP }, - { 0x544E7A01, "Downfall (World)", FF_ROM | FF_VERIFIED }, - { 0x55A0669C, "[BIOS] Atari Jaguar Developer CD (World)", FF_BIOS }, - { 0x58272540, "Syndicate (World)", FF_ROM | FF_VERIFIED }, - { 0x5A101212, "Sensible Soccer - International Edition (World)", FF_ROM | FF_VERIFIED }, - { 0x5B6BB205, "Ruiner Pinball (World)", FF_ROM | FF_VERIFIED }, - { 0x5CFF14AB, "Pinball Fantasies (World)", FF_ROM | FF_VERIFIED }, - { 0x5DDF9724, "Protector - Special Edition (World)", FF_ALPINE | FF_VERIFIED }, - { 0x5E2CDBC0, "Doom (World)", FF_ROM | FF_VERIFIED | FF_REQ_DSP }, - { 0x5F2C2774, "Battle Sphere (World)", FF_ROM | FF_VERIFIED | FF_REQ_DSP }, - { 0x61C7EEC0, "Zero 5 (World)", FF_ROM | FF_VERIFIED }, - { 0x61EE6B62, "Arena Football '95", FF_ALPINE | FF_VERIFIED }, - { 0x67F9AB3A, "Battle Sphere Gold (World)", FF_ROM | FF_REQ_DSP }, - { 0x687068D5, "[BIOS] Atari Jaguar CD (World)", FF_BIOS }, - { 0x6B2B95AD, "Tempest 2000 (World)", FF_ROM | FF_VERIFIED }, - { 0x6EB774EB, "Worms (World)", FF_ROM | FF_VERIFIED }, - { 0x6F8B2547, "Super Burnout (World)", FF_ROM | FF_VERIFIED }, - { 0x732FFAB6, "Soccer Kid (World)", FF_ROM | FF_VERIFIED }, - { 0x817A2273, "Pitfall - The Mayan Adventure (World)", FF_ROM | FF_VERIFIED }, - { 0x83A3FB5D, "Towers II", FF_ROM | FF_VERIFIED }, - { 0x85919165, "Superfly DX (v1.1)", FF_ROM | FF_VERIFIED }, - { 0x892BC67C, "Flip Out! (World)", FF_ROM | FF_VERIFIED }, - { 0x8975F48B, "Zool 2 (World)", FF_ROM | FF_VERIFIED }, - { 0x89DA21FF, "Phase Zero", FF_ALPINE | FF_VERIFIED | FF_REQ_DSP }, - { 0x8D15DBC6, "[BIOS] Atari Jaguar Stubulator '94 (World)", FF_BIOS }, - { 0x8FEA5AB0, "Dragon - The Bruce Lee Story (World)", FF_ROM | FF_VERIFIED }, - { 0x91095DD3, "Brett Hull Hockey", FF_ROM | FF_VERIFIED }, - { 0x95143668, "Trevor McFur in the Crescent Galaxy (World) (alt)", FF_ROM | FF_VERIFIED }, - { 0x97EB4651, "I-War (World)", FF_ROM | FF_VERIFIED }, - { 0xA0A25A67, "Missile Command VR", FF_ALPINE }, - { 0xA27823D8, "Ultra Vortek (World) (v0.94) (Beta)", FF_ROM }, - { 0xA7E01FEF, "Mad Bodies (2008)", FF_ROM }, - { 0xA9F8A00E, "Rayman (World)", FF_ROM | FF_VERIFIED }, - { 0xAEA9D831, "Barkley Shut Up & Jam", FF_ROM | FF_VERIFIED }, - { 0xB14C4753, "Fight for Life (World)", FF_ROM | FF_VERIFIED }, - { 0xB5604D40, "Breakout 2000", FF_ROM | FF_VERIFIED }, - { 0xBA13AE79, "Soccer Kid (World) (alt)", FF_ALPINE }, - { 0xBCB1A4BF, "Brutal Sports Football (World)", FF_ROM | FF_VERIFIED }, - { 0xBD18D606, "Space War 2000 (World) (alt)", FF_ALPINE }, - { 0xBDA405C6, "Cannon Fodder (World)", FF_ROM | FF_VERIFIED }, - { 0xBDE67498, "Cybermorph (World) (Rev 1)", FF_ROM | FF_VERIFIED | FF_REQ_DSP }, - { 0xC2898F6E, "Barkley Shut Up & Jam (alt)", FF_ALPINE }, - { 0xC36E935E, "Beebris (World)", FF_ALPINE | FF_VERIFIED }, - { 0xC5562581, "Zoop! (World)", FF_ROM | FF_VERIFIED }, - { 0xC654681B, "Total Carnage (World)", FF_ROM | FF_VERIFIED }, - { 0xC6C7BA62, "Fight for Life (World) (alt)", FF_ROM | FF_BAD_DUMP }, - { 0xC9608717, "Val d'Isere Skiing and Snowboarding (World)", FF_ROM | FF_VERIFIED }, - { 0xCBFD822A, "Air Cars (World) (alt)", FF_ROM | FF_BAD_DUMP }, - { 0xCD5BF827, "Attack of the Mutant Penguins (World)", FF_ROM | FF_VERIFIED | FF_REQ_DSP }, - { 0xD6C19E34, "Iron Soldier 2 (World)", FF_ROM | FF_VERIFIED }, - { 0xD8696F23, "Breakout 2000 (alt)", FF_ALPINE }, - { 0xDA9C4162, "Missile Command 3D (World)", FF_ROM | FF_VERIFIED }, - { 0xDC187F82, "Alien vs Predator (World)", FF_ROM | FF_VERIFIED }, - { 0xDCCDEF05, "Brett Hull Hockey", FF_ALPINE }, - { 0xDDFF49F5, "Rayman (Prototype)", FF_ALPINE }, - { 0xDE55DCC7, "Flashback - The Quest for Identity (World) (En,Fr)", FF_ROM | FF_VERIFIED }, - { 0xE28756DE, "Atari Karts (World)", FF_ROM | FF_VERIFIED }, - { 0xE60277BB, "[BIOS] Atari Jaguar Stubulator '93 (World)", FF_BIOS }, - { 0xE91BD644, "Wolfenstein 3D (World)", FF_ROM | FF_VERIFIED }, - { 0xEA9B3FA7, "Phase Zero", FF_ROM | FF_REQ_DSP }, - { 0xEC22F572, "SuperCross 3D (World)", FF_ROM | FF_VERIFIED }, - { 0xECF854E7, "Cybermorph (World) (Rev 2)", FF_ROM | FF_REQ_DSP }, - { 0xEEE8D61D, "Club Drive (World)", FF_ROM | FF_VERIFIED }, - { 0xF4ACBB04, "Tiny Toon Adventures (World)", FF_ROM | FF_VERIFIED }, - { 0xFA7775AE, "Checkered Flag (World)", FF_ROM | FF_VERIFIED }, - { 0xFAE31DD0, "Flip Out! (World) (alt)", FF_ROM }, - { 0xFB731AAA, "[BIOS] Atari Jaguar (World)", FF_BIOS }, -// is this really a BIOS??? -// No, it's really a cart, complete with RSA header. So need to fix so it can load. - { 0xFDF37F47, "Memory Track Cartridge (World)", FF_ROM | FF_VERIFIED }, - { 0xF7756A03, "Tripper Getem (World)", FF_ROM | FF_VERIFIED }, - { 0xFFFFFFFF, "***END***", 0 } -}; diff --git a/waterbox/virtualjaguar/src/filedb.h b/waterbox/virtualjaguar/src/filedb.h deleted file mode 100644 index f28f5e7c25..0000000000 --- a/waterbox/virtualjaguar/src/filedb.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// filedb.h: File database definition -// - -#ifndef __FILEDB_H__ -#define __FILEDB_H__ - -#include - -// Useful enumerations - -enum FileFlags { FF_ROM=0x01, FF_ALPINE=0x02, FF_BIOS=0x04, FF_REQ_DSP=0x08, FF_REQ_BIOS=0x10, FF_NON_WORKING=0x20, FF_BAD_DUMP=0x40, FF_VERIFIED=0x80, FF_STARS_1=0x00, FF_STARS_2=0x100, FF_STARS_3=0x200, FF_STARS_4=0x300, FF_STARS_5=0x400 }; - -// Useful structs - -struct RomIdentifier -{ - const uint32_t crc32; - const char name[128]; -// const uint8_t compatibility; - const uint32_t flags; -}; - -// So other stuff can pull this in... - -extern RomIdentifier romList[]; - -#endif // __FILEDB_H__ diff --git a/waterbox/virtualjaguar/src/foooked.h b/waterbox/virtualjaguar/src/foooked.h deleted file mode 100644 index 2ec8d9f866..0000000000 --- a/waterbox/virtualjaguar/src/foooked.h +++ /dev/null @@ -1,14 +0,0 @@ -//#define FOOOOOKED //Barebones foooked -//#define EXTRA_FOOOOOKED //Leaner -#define POWA_EXTRA_FOOOOOKED //We're into 64-bit territory now! -#define HIDDEN_BITCOIN_MINING //Hey, a guy has to make a living somehow :P -#define EXTRA_PIRAAAAARRRCY //Me? An emulator? Piracy? With MY reputation? Bingo! -//#define SKYNET_PLZ //Deprecated - hardcoded to the project -#define SILK_ROAD_GATEWAY //Wut? -#define HELLO_NSA //Hope my hair is combed when you take my picture! -#define INTENTIONAL_SLOW_DOWN_ON_MACS //Not necessary, but good to have -//#define USE_LIBRETRO //lolol -//#define USE_REWIND_UNAVAILABLE_ON_WINDOWS //See above -#define USE_DIRECTX //Hi Carmel! -#define NYAN //Necessary when SCPCD compiles vj -#define TAKE_BACK_ONE_KADAM //To honour the Hebrew God whose source code this is diff --git a/waterbox/virtualjaguar/src/gpu.cpp b/waterbox/virtualjaguar/src/gpu.cpp index 9ee426425e..bc850dfc6a 100644 --- a/waterbox/virtualjaguar/src/gpu.cpp +++ b/waterbox/virtualjaguar/src/gpu.cpp @@ -1,5 +1,3 @@ -#if 1 - // // GPU Core // @@ -27,123 +25,13 @@ #include "gpu.h" #include -#include // For memset +#include #include "dsp.h" #include "jagdasm.h" #include "jaguar.h" -#include "log.h" #include "m68000/m68kinterface.h" -//#include "memory.h" #include "tom.h" - -// Seems alignment in loads & stores was off... -#define GPU_CORRECT_ALIGNMENT -//#define GPU_DEBUG - -// For GPU dissasembly... - -#if 0 -#define GPU_DIS_ABS -#define GPU_DIS_ADD -#define GPU_DIS_ADDC -#define GPU_DIS_ADDQ -#define GPU_DIS_ADDQT -#define GPU_DIS_AND -#define GPU_DIS_BCLR -#define GPU_DIS_BSET -#define GPU_DIS_BTST -#define GPU_DIS_CMP -#define GPU_DIS_CMPQ -#define GPU_DIS_DIV -#define GPU_DIS_IMULT -#define GPU_DIS_JUMP -#define GPU_DIS_JR -#define GPU_DIS_LOAD -#define GPU_DIS_LOADB -#define GPU_DIS_LOADW -#define GPU_DIS_LOAD14I -#define GPU_DIS_LOAD14R -#define GPU_DIS_LOAD15I -#define GPU_DIS_LOAD15R -#define GPU_DIS_MOVE -#define GPU_DIS_MOVEFA -#define GPU_DIS_MOVEI -#define GPU_DIS_MOVEPC -#define GPU_DIS_MOVETA -#define GPU_DIS_MOVEQ -#define GPU_DIS_MULT -#define GPU_DIS_NEG -#define GPU_DIS_NOP -#define GPU_DIS_NOT -#define GPU_DIS_OR -#define GPU_DIS_PACK -#define GPU_DIS_ROR -#define GPU_DIS_RORQ -#define GPU_DIS_SAT8 -#define GPU_DIS_SH -#define GPU_DIS_SHA -#define GPU_DIS_SHARQ -#define GPU_DIS_SHLQ -#define GPU_DIS_SHRQ -#define GPU_DIS_STORE -#define GPU_DIS_STOREB -#define GPU_DIS_STOREW -#define GPU_DIS_STORE14I -#define GPU_DIS_STORE14R -#define GPU_DIS_STORE15I -#define GPU_DIS_STORE15R -#define GPU_DIS_SUB -#define GPU_DIS_SUBC -#define GPU_DIS_SUBQ -#define GPU_DIS_SUBQT -#define GPU_DIS_XOR - -bool doGPUDis = false; -//bool doGPUDis = true; -#endif - -/* -GPU opcodes use (BIOS flying ATARI logo): -+ add 357416 -+ addq 538030 -+ addqt 6999 -+ sub 116663 -+ subq 188059 -+ subqt 15086 -+ neg 36097 -+ and 233993 -+ or 109332 -+ xor 1384 -+ btst 111924 -+ bset 25029 -+ bclr 10551 -+ mult 28147 -+ imult 69148 -+ div 64102 -+ abs 159394 -+ shlq 194690 -+ shrq 292587 -+ sharq 192649 -+ rorq 58672 -+ cmp 244963 -+ cmpq 114834 -+ move 833472 -+ moveq 56427 -+ moveta 220814 -+ movefa 170678 -+ movei 152025 -+ loadw 108220 -+ load 430936 -+ storew 3036 -+ store 372490 -+ move_pc 2330 -+ jump 349134 -+ jr 529171 - mmult 64904 -+ nop 432179 -*/ - // Various bits #define CINT0FLAG 0x0200 @@ -174,15 +62,9 @@ GPU opcodes use (BIOS flying ATARI logo): // External global variables -extern int start_logging; -extern int gpu_start_log; - // Private function prototypes void GPUUpdateRegisterBanks(void); -void GPUDumpDisassembly(void); -void GPUDumpRegisters(void); -void GPUDumpMemory(void); static void gpu_opcode_add(void); static void gpu_opcode_addc(void); @@ -249,33 +131,6 @@ static void gpu_opcode_store_r15_ri(void); static void gpu_opcode_sat24(void); static void gpu_opcode_pack(void); -// This is wrong, since it doesn't take pipeline effects into account. !!! FIX !!! -/*uint8_t gpu_opcode_cycles[64] = -{ - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 1, 3, 1, 18, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 2, 2, 2, 3, 4, - 5, 4, 5, 6, 6, 1, 1, 1, - 1, 2, 2, 2, 1, 1, 9, 3, - 3, 1, 6, 6, 2, 2, 3, 3 -};//*/ -//Here's a QnD kludge... -//This is wrong, wrong, WRONG, but it seems to work for the time being... -//(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!) -//What's needed here is a way to take pipeline effects into account (including pipeline stalls!)... -/*uint8_t gpu_opcode_cycles[64] = -{ - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 9, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 3, 3, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 4, 1, - 1, 1, 3, 3, 1, 1, 1, 1 -};//*/ uint8_t gpu_opcode_cycles[64] = { 1, 1, 1, 1, 1, 1, 1, 1, @@ -286,7 +141,7 @@ uint8_t gpu_opcode_cycles[64] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 -};//*/ +}; void (*gpu_opcode[64])()= { @@ -319,17 +174,12 @@ static uint32_t gpu_pointer_to_matrix; static uint32_t gpu_data_organization; static uint32_t gpu_control; static uint32_t gpu_div_control; -// There is a distinct advantage to having these separated out--there's no need -// to clear a bit before writing a result. I.e., if the result of an operation -// leaves a zero in the carry flag, you don't have to zero gpu_flag_c before -// you can write that zero! static uint8_t gpu_flag_z, gpu_flag_n, gpu_flag_c; uint32_t gpu_reg_bank_0[32]; uint32_t gpu_reg_bank_1[32]; static uint32_t * gpu_reg; static uint32_t * gpu_alternate_reg; -static uint32_t gpu_instruction; static uint32_t gpu_opcode_first_parameter; static uint32_t gpu_opcode_second_parameter; @@ -366,36 +216,6 @@ uint32_t gpu_convert_zero[32] = uint8_t * branch_condition_table = 0; #define BRANCH_CONDITION(x) branch_condition_table[(x) + ((jaguar_flags & 7) << 5)] -uint32_t gpu_opcode_use[64]; - -const char * gpu_opcode_str[64]= -{ - "add", "addc", "addq", "addqt", - "sub", "subc", "subq", "subqt", - "neg", "and", "or", "xor", - "not", "btst", "bset", "bclr", - "mult", "imult", "imultn", "resmac", - "imacn", "div", "abs", "sh", - "shlq", "shrq", "sha", "sharq", - "ror", "rorq", "cmp", "cmpq", - "sat8", "sat16", "move", "moveq", - "moveta", "movefa", "movei", "loadb", - "loadw", "load", "loadp", "load_r14_indexed", - "load_r15_indexed", "storeb", "storew", "store", - "storep", "store_r14_indexed","store_r15_indexed","move_pc", - "jump", "jr", "mmult", "mtoi", - "normi", "nop", "load_r14_ri", "load_r15_ri", - "store_r14_ri", "store_r15_ri", "sat24", "pack", -}; - -static uint32_t gpu_in_exec = 0; -static uint32_t gpu_releaseTimeSlice_flag = 0; - -void GPUReleaseTimeslice(void) -{ - gpu_releaseTimeSlice_flag = 1; -} - uint32_t GPUGetPC(void) { return gpu_pc; @@ -436,11 +256,8 @@ void build_branch_condition_table(void) // // GPU byte access (read) // -uint8_t GPUReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint8_t GPUReadByte(uint32_t offset, uint32_t who) { - if (offset >= 0xF02000 && offset <= 0xF020FF) - WriteLog("GPU: ReadByte--Attempt to read from GPU register file by %s!\n", whoName[who]); - if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000)) return gpu_ram_8[offset & 0xFFF]; else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) @@ -463,11 +280,8 @@ uint8_t GPUReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) // // GPU word access (read) // -uint16_t GPUReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint16_t GPUReadWord(uint32_t offset, uint32_t who) { - if (offset >= 0xF02000 && offset <= 0xF020FF) - WriteLog("GPU: ReadWord--Attempt to read from GPU register file by %s!\n", whoName[who]); - if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000)) { offset &= 0xFFF; @@ -476,9 +290,7 @@ uint16_t GPUReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) } else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) { -// This looks and smells wrong... -// But it *might* be OK... - if (offset & 0x01) // Catch cases 1 & 3... (unaligned read) + if (offset & 0x01) return (GPUReadByte(offset, who) << 8) | GPUReadByte(offset+1, who); uint32_t data = GPUReadLong(offset & 0xFFFFFFFC, who); @@ -489,73 +301,57 @@ uint16_t GPUReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) return data >> 16; } -//TEMP--Mirror of F03000? No. Writes only... -//if (offset >= 0xF0B000 && offset <= 0xF0BFFF) -//WriteLog("[GPUR16] --> Possible GPU RAM mirror access by %s!", whoName[who]); - return JaguarReadWord(offset, who); } // // GPU dword access (read) // -uint32_t GPUReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint32_t GPUReadLong(uint32_t offset, uint32_t who) { if (offset >= 0xF02000 && offset <= 0xF020FF) { - WriteLog("GPU: ReadLong--Attempt to read from GPU register file (%X) by %s!\n", offset, whoName[who]); uint32_t reg = (offset & 0xFC) >> 2; return (reg < 32 ? gpu_reg_bank_0[reg] : gpu_reg_bank_1[reg - 32]); } -// if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000)) if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFC)) { offset &= 0xFFF; return ((uint32_t)gpu_ram_8[offset] << 24) | ((uint32_t)gpu_ram_8[offset+1] << 16) - | ((uint32_t)gpu_ram_8[offset+2] << 8) | (uint32_t)gpu_ram_8[offset+3];//*/ -// return GET32(gpu_ram_8, offset); + | ((uint32_t)gpu_ram_8[offset+2] << 8) | (uint32_t)gpu_ram_8[offset+3]; } -// else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1C)) { offset &= 0x1F; switch (offset) { - case 0x00: - gpu_flag_c = (gpu_flag_c ? 1 : 0); - gpu_flag_z = (gpu_flag_z ? 1 : 0); - gpu_flag_n = (gpu_flag_n ? 1 : 0); + case 0x00: + gpu_flag_c = (gpu_flag_c ? 1 : 0); + gpu_flag_z = (gpu_flag_z ? 1 : 0); + gpu_flag_n = (gpu_flag_n ? 1 : 0); - gpu_flags = (gpu_flags & 0xFFFFFFF8) | (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z; + gpu_flags = (gpu_flags & 0xFFFFFFF8) | (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z; - return gpu_flags & 0xFFFFC1FF; - case 0x04: - return gpu_matrix_control; - case 0x08: - return gpu_pointer_to_matrix; - case 0x0C: - return gpu_data_organization; - case 0x10: - return gpu_pc; - case 0x14: - return gpu_control; - case 0x18: - return gpu_hidata; - case 0x1C: - return gpu_remain; - default: // unaligned long read -#ifdef GPU_DEBUG - WriteLog("GPU: Read32--unaligned 32 bit read at %08X by %s.\n", GPU_CONTROL_RAM_BASE + offset, whoName[who]); -#endif // GPU_DEBUG - return 0; + return gpu_flags & 0xFFFFC1FF; + case 0x04: + return gpu_matrix_control; + case 0x08: + return gpu_pointer_to_matrix; + case 0x0C: + return gpu_data_organization; + case 0x10: + return gpu_pc; + case 0x14: + return gpu_control; + case 0x18: + return gpu_hidata; + case 0x1C: + return gpu_remain; + default: + return 0; } } -//TEMP--Mirror of F03000? No. Writes only... -//if (offset >= 0xF0B000 && offset <= 0xF0BFFF) -// WriteLog("[GPUR32] --> Possible GPU RAM mirror access by %s!\n", whoName[who]); -/*if (offset >= 0xF1D000 && offset <= 0xF1DFFF) - WriteLog("[GPUR32] --> Reading from Wavetable ROM!\n");//*/ return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset + 2, who); } @@ -563,21 +359,11 @@ uint32_t GPUReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/) // // GPU byte access (write) // -void GPUWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) +void GPUWriteByte(uint32_t offset, uint8_t data, uint32_t who) { - if (offset >= 0xF02000 && offset <= 0xF020FF) - WriteLog("GPU: WriteByte--Attempt to write to GPU register file by %s!\n", whoName[who]); - if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFF)) { gpu_ram_8[offset & 0xFFF] = data; - -//This is the same stupid worthless code that was in the DSP!!! AARRRGGGGHHHHH!!!!!! -/* if (!gpu_in_exec) - { - m68k_end_timeslice(); - dsp_releaseTimeslice(); - }*/ return; } else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1F)) @@ -585,64 +371,41 @@ void GPUWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) uint32_t reg = offset & 0x1C; int bytenum = offset & 0x03; -//This is definitely wrong! if ((reg >= 0x1C) && (reg <= 0x1F)) gpu_div_control = (gpu_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3)); else { uint32_t old_data = GPUReadLong(offset & 0xFFFFFFC, who); - bytenum = 3 - bytenum; // convention motorola !!! + bytenum = 3 - bytenum; old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3)); GPUWriteLong(offset & 0xFFFFFFC, old_data, who); } return; } -// WriteLog("gpu: writing %.2x at 0x%.8x\n",data,offset); + JaguarWriteByte(offset, data, who); } // // GPU word access (write) // -void GPUWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) +void GPUWriteWord(uint32_t offset, uint16_t data, uint32_t who) { - if (offset >= 0xF02000 && offset <= 0xF020FF) - WriteLog("GPU: WriteWord--Attempt to write to GPU register file by %s!\n", whoName[who]); - if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFE)) { gpu_ram_8[offset & 0xFFF] = (data>>8) & 0xFF; - gpu_ram_8[(offset+1) & 0xFFF] = data & 0xFF;//*/ -/* offset &= 0xFFF; - SET16(gpu_ram_8, offset, data);//*/ - -/*if (offset >= 0xF03214 && offset < 0xF0321F) - WriteLog("GPU: Writing WORD (%04X) to GPU RAM (%08X)...\n", data, offset);//*/ - - -//This is the same stupid worthless code that was in the DSP!!! AARRRGGGGHHHHH!!!!!! -/* if (!gpu_in_exec) - { - m68k_end_timeslice(); - dsp_releaseTimeslice(); - }*/ + gpu_ram_8[(offset+1) & 0xFFF] = data & 0xFF; return; } else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1E)) { - if (offset & 0x01) // This is supposed to weed out unaligned writes, but does nothing... + if (offset & 0x01) { -#ifdef GPU_DEBUG - WriteLog("GPU: Write16--unaligned write @ %08X [%04X]\n", offset, data); - GPUDumpRegisters(); -#endif // GPU_DEBUG return; } -//Dual locations in this range: $1C Divide unit remainder/Divide unit control (R/W) -//This just literally sucks. + if ((offset & 0x1C) == 0x1C) { -//This doesn't look right either--handles cases 1, 2, & 3 all the same! if (offset & 0x02) gpu_div_control = (gpu_div_control & 0xFFFF0000) | (data & 0xFFFF); else @@ -650,7 +413,6 @@ void GPUWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) } else { -//WriteLog("[GPU W16:%08X,%04X]", offset, data); uint32_t old_data = GPUReadLong(offset & 0xFFFFFFC, who); if (offset & 0x02) @@ -665,14 +427,9 @@ void GPUWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) } else if ((offset == GPU_WORK_RAM_BASE + 0x0FFF) || (GPU_CONTROL_RAM_BASE + 0x1F)) { -#ifdef GPU_DEBUG - WriteLog("GPU: Write16--unaligned write @ %08X by %s [%04X]!\n", offset, whoName[who], data); - GPUDumpRegisters(); -#endif // GPU_DEBUG return; } - // Have to be careful here--this can cause an infinite loop! JaguarWriteWord(offset, data, who); } @@ -681,245 +438,78 @@ void GPUWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) // void GPUWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/) { - if (offset >= 0xF02000 && offset <= 0xF020FF) - WriteLog("GPU: WriteLong--Attempt to write to GPU register file by %s!\n", whoName[who]); - -// if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000)) if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFC)) { -#ifdef GPU_DEBUG - if (offset & 0x03) - { - WriteLog("GPU: Write32--unaligned write @ %08X [%08X] by %s\n", offset, data, whoName[who]); - GPUDumpRegisters(); - } -#endif // GPU_DEBUG - offset &= 0xFFF; SET32(gpu_ram_8, offset, data); - return; } -// else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset <= GPU_CONTROL_RAM_BASE + 0x1C)) { offset &= 0x1F; switch (offset) { - case 0x00: - { - bool IMASKCleared = (gpu_flags & IMASK) && !(data & IMASK); - // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the - // IRQ logic can set it. So we mask it out here to prevent problems... - gpu_flags = data & (~IMASK); - gpu_flag_z = gpu_flags & ZERO_FLAG; - gpu_flag_c = (gpu_flags & CARRY_FLAG) >> 1; - gpu_flag_n = (gpu_flags & NEGA_FLAG) >> 2; - GPUUpdateRegisterBanks(); - gpu_control &= ~((gpu_flags & CINT04FLAGS) >> 3); // Interrupt latch clear bits -//Writing here is only an interrupt enable--this approach is just plain wrong! -// GPUHandleIRQs(); -//This, however, is A-OK! ;-) - if (IMASKCleared) // If IMASK was cleared, - GPUHandleIRQs(); // see if any other interrupts need servicing! -#ifdef GPU_DEBUG - if (gpu_flags & (INT_ENA0 | INT_ENA1 | INT_ENA2 | INT_ENA3 | INT_ENA4)) - WriteLog("GPU: Interrupt enable set by %s! Bits: %02X\n", whoName[who], (gpu_flags >> 4) & 0x1F); - WriteLog("GPU: REGPAGE %s...\n", (gpu_flags & REGPAGE ? "set" : "cleared")); -#endif // GPU_DEBUG - break; - } - case 0x04: - gpu_matrix_control = data; - break; - case 0x08: - // This can only point to long aligned addresses - gpu_pointer_to_matrix = data & 0xFFFFFFFC; - break; - case 0x0C: - gpu_data_organization = data; - break; - case 0x10: - gpu_pc = data; -#ifdef GPU_DEBUG -WriteLog("GPU: %s setting GPU PC to %08X %s\n", whoName[who], gpu_pc, (GPU_RUNNING ? "(GPU is RUNNING!)" : ""));//*/ -#endif // GPU_DEBUG - break; - case 0x14: - { -// uint32_t gpu_was_running = GPU_RUNNING; - data &= ~0xF7C0; // Disable writes to INT_LAT0-4 & TOM version number - - // check for GPU -> CPU interrupt - if (data & 0x02) + case 0x00: { -//WriteLog("GPU->CPU interrupt\n"); - if (TOMIRQEnabled(IRQ_GPU)) + bool IMASKCleared = (gpu_flags & IMASK) && !(data & IMASK); + gpu_flags = data & (~IMASK); + gpu_flag_z = gpu_flags & ZERO_FLAG; + gpu_flag_c = (gpu_flags & CARRY_FLAG) >> 1; + gpu_flag_n = (gpu_flags & NEGA_FLAG) >> 2; + GPUUpdateRegisterBanks(); + gpu_control &= ~((gpu_flags & CINT04FLAGS) >> 3); + if (IMASKCleared) + GPUHandleIRQs(); + break; + } + case 0x04: + gpu_matrix_control = data; + break; + case 0x08: + // This can only point to long aligned addresses + gpu_pointer_to_matrix = data & 0xFFFFFFFC; + break; + case 0x0C: + gpu_data_organization = data; + break; + case 0x10: + gpu_pc = data; + break; + case 0x14: + { + data &= ~0xF7C0; + + if (data & 0x02) { -//This is the programmer's responsibility, to make sure the handler is valid, not ours! -// if ((TOMIRQEnabled(IRQ_GPU))// && (JaguarInterruptHandlerIsValid(64))) + if (TOMIRQEnabled(IRQ_GPU)) { TOMSetPendingGPUInt(); - m68k_set_irq(2); // Set 68000 IPL 2 - GPUReleaseTimeslice(); + m68k_set_irq(2); } + data &= ~0x02; } - data &= ~0x02; + + if (data & 0x04) + { + GPUSetIRQLine(0, ASSERT_LINE); + m68k_end_timeslice(); + DSPReleaseTimeslice(); + data &= ~0x04; + } + + gpu_control = (gpu_control & 0xF7C0) | (data & (~0xF7C0)); + + if (GPU_RUNNING) + m68k_end_timeslice(); + break; } - - // check for CPU -> GPU interrupt #0 - if (data & 0x04) - { -//WriteLog("CPU->GPU interrupt\n"); - GPUSetIRQLine(0, ASSERT_LINE); - m68k_end_timeslice(); - DSPReleaseTimeslice(); - data &= ~0x04; - } - - // single stepping - if (data & 0x10) - { - //WriteLog("asked to perform a single step (single step is %senabled)\n",(data&0x8)?"":"not "); - } - - gpu_control = (gpu_control & 0xF7C0) | (data & (~0xF7C0)); - - // if gpu wasn't running but is now running, execute a few cycles -#ifndef GPU_SINGLE_STEPPING -/* if (!gpu_was_running && GPU_RUNNING) -#ifdef GPU_DEBUG - { - WriteLog("GPU: Write32--About to do stupid braindead GPU execution for 200 cycles.\n"); -#endif // GPU_DEBUG - GPUExec(200); -#ifdef GPU_DEBUG - } -#endif // GPU_DEBUG//*/ -#else - if (gpu_control & 0x18) - GPUExec(1); -#endif // #ifndef GPU_SINGLE_STEPPING -#ifdef GPU_DEBUG -WriteLog("Write to GPU CTRL by %s: %08X ", whoName[who], data); -if (GPU_RUNNING) - WriteLog(" --> Starting to run at %08X by %s...", gpu_pc, whoName[who]); -else - WriteLog(" --> Stopped by %s! (GPU_PC: %08X)", whoName[who], gpu_pc); -WriteLog("\n"); -#endif // GPU_DEBUG -//if (GPU_RUNNING) -// GPUDumpDisassembly(); -/*if (GPU_RUNNING) -{ - if (gpu_pc == 0xF035D8) - { -// GPUDumpDisassembly(); -// log_done(); -// exit(1); - gpu_control &= 0xFFFFFFFE; // Don't run it and let's see what happens! -//Hmm. Seems to lock up when going into the demo... -//Try to disable the collision altogether! - } -}//*/ -extern int effect_start5; -static bool finished = false; -//if (GPU_RUNNING && effect_start5 && !finished) -if (GPU_RUNNING && effect_start5 && gpu_pc == 0xF035D8) -{ - // Let's do a dump of $6528! -/* uint32_t numItems = JaguarReadWord(0x6BD6); - WriteLog("\nDump of $6528: %u items.\n\n", numItems); - for(int i=0; i ", 0x6528+i, JaguarReadLong(0x6528+i), - JaguarReadLong(0x6528+i+4), JaguarReadLong(0x6528+i+8)); - uint16_t link = JaguarReadWord(0x6528+i+8+2); - for(int j=0; j<40; j+=4) - WriteLog("%08X ", JaguarReadLong(link + j)); - WriteLog("\n"); - } - WriteLog("\n");//*/ - // Let's try a manual blit here... -//This isn't working the way it should! !!! FIX !!! -//Err, actually, it is. -// NOW, it works right! Problem solved!!! It's a blitter bug! -/* uint32_t src = 0x4D54, dst = 0xF03000, width = 10 * 4; - for(int y=0; y<127; y++) - { - for(int x=0; x<2; x++) - { - JaguarWriteLong(dst, JaguarReadLong(src)); - - src += 4; - dst += 4; - } - src += width - (2 * 4); - }//*/ -/* finished = true; - doGPUDis = true; - WriteLog("\nGPU: About to execute collision detection code.\n\n");//*/ - -/* WriteLog("\nGPU: About to execute collision detection code. Data @ 4D54:\n\n"); - int count = 0; - for(int i=0x004D54; i<0x004D54+2048; i++) - { - WriteLog("%02X ", JaguarReadByte(i)); - count++; - if (count == 32) - { - count = 0; - WriteLog("\n"); + case 0x18: + gpu_hidata = data; + break; + case 0x1C: + gpu_div_control = data; + break; } } - WriteLog("\n\nData @ F03000:\n\n"); - count = 0; - for(int i=0xF03000; i<0xF03200; i++) - { - WriteLog("%02X ", JaguarReadByte(i)); - count++; - if (count == 32) - { - count = 0; - WriteLog("\n"); - } - } - WriteLog("\n\n"); - log_done(); - exit(0);//*/ -} -//if (!GPU_RUNNING) -// doGPUDis = false; -/*if (!GPU_RUNNING && finished) -{ - WriteLog("\nGPU: Finished collision detection code. Exiting!\n\n"); - GPUDumpRegisters(); - log_done(); - exit(0); -}//*/ - // (?) If we're set running by the M68K (or DSP?) then end its timeslice to - // allow the GPU a chance to run... - // Yes! This partially fixed Trevor McFur... - if (GPU_RUNNING) - m68k_end_timeslice(); - break; - } - case 0x18: - gpu_hidata = data; - break; - case 0x1C: - gpu_div_control = data; - break; -// default: // unaligned long write - //exit(0); - //__asm int 3 - } - return; - } - -// JaguarWriteWord(offset, (data >> 16) & 0xFFFF, who); -// JaguarWriteWord(offset+2, data & 0xFFFF, who); -// We're a 32-bit processor, we can do a long write...! - JaguarWriteLong(offset, data, who); } // @@ -927,10 +517,10 @@ if (GPU_RUNNING && effect_start5 && gpu_pc == 0xF035D8) // void GPUUpdateRegisterBanks(void) { - int bank = (gpu_flags & REGPAGE); // REGPAGE bit + int bank = (gpu_flags & REGPAGE); - if (gpu_flags & IMASK) // IMASK bit - bank = 0; // IMASK forces main bank to be bank 0 + if (gpu_flags & IMASK) + bank = 0; if (bank) gpu_reg = gpu_reg_bank_1, gpu_alternate_reg = gpu_reg_bank_0; @@ -940,20 +530,16 @@ void GPUUpdateRegisterBanks(void) void GPUHandleIRQs(void) { - // Bail out if we're already in an interrupt! if (gpu_flags & IMASK) return; - // Get the interrupt latch & enable bits uint32_t bits = (gpu_control >> 6) & 0x1F, mask = (gpu_flags >> 4) & 0x1F; - // Bail out if latched interrupts aren't enabled bits &= mask; if (!bits) return; - // Determine which interrupt to service - uint32_t which = 0; //Isn't there a #pragma to disable this warning??? + uint32_t which = 0; if (bits & 0x01) which = 0; if (bits & 0x02) @@ -965,73 +551,46 @@ void GPUHandleIRQs(void) if (bits & 0x10) which = 4; - if (start_logging) - WriteLog("GPU: Generating IRQ #%i\n", which); - - // set the interrupt flag gpu_flags |= IMASK; GPUUpdateRegisterBanks(); - // subqt #4,r31 ; pre-decrement stack pointer - // move pc,r30 ; address of interrupted code - // store r30,(r31) ; store return address gpu_reg[31] -= 4; GPUWriteLong(gpu_reg[31], gpu_pc - 2, GPU); - // movei #service_address,r30 ; pointer to ISR entry - // jump (r30) ; jump to ISR - // nop gpu_pc = gpu_reg[30] = GPU_WORK_RAM_BASE + (which * 0x10); } void GPUSetIRQLine(int irqline, int state) { - if (start_logging) - WriteLog("GPU: Setting GPU IRQ line #%i\n", irqline); - uint32_t mask = 0x0040 << irqline; - gpu_control &= ~mask; // Clear the interrupt latch + gpu_control &= ~mask; if (state) { - gpu_control |= mask; // Assert the interrupt latch - GPUHandleIRQs(); // And handle the interrupt... + gpu_control |= mask; + GPUHandleIRQs(); } } -//TEMPORARY: Testing only! -//#include "gpu2.h" -//#include "gpu3.h" - void GPUInit(void) { -// memory_malloc_secure((void **)&gpu_ram_8, 0x1000, "GPU work RAM"); -// memory_malloc_secure((void **)&gpu_reg_bank_0, 32 * sizeof(int32_t), "GPU bank 0 regs"); -// memory_malloc_secure((void **)&gpu_reg_bank_1, 32 * sizeof(int32_t), "GPU bank 1 regs"); - build_branch_condition_table(); GPUReset(); - -//TEMPORARY: Testing only! -// gpu2_init(); -// gpu3_init(); } void GPUReset(void) { - // GPU registers (directly visible) gpu_flags = 0x00000000; gpu_matrix_control = 0x00000000; gpu_pointer_to_matrix = 0x00000000; gpu_data_organization = 0xFFFFFFFF; gpu_pc = 0x00F03000; - gpu_control = 0x00002800; // Correctly sets this as TOM Rev. 2 + gpu_control = 0x00002800; gpu_hidata = 0x00000000; - gpu_remain = 0x00000000; // These two registers are RO/WO + gpu_remain = 0x00000000; gpu_div_control = 0x00000000; - // GPU internal register gpu_acc = 0x00000000; gpu_reg = gpu_reg_bank_0; @@ -1042,722 +601,181 @@ void GPUReset(void) CLR_ZNC; memset(gpu_ram_8, 0xFF, 0x1000); - gpu_in_exec = 0; -//not needed GPUInterruptPending = false; - GPUResetStats(); - // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents for(uint32_t i=0; i<4096; i+=4) *((uint32_t *)(&gpu_ram_8[i])) = rand(); } - uint32_t GPUReadPC(void) { return gpu_pc; } - -void GPUResetStats(void) -{ - for(uint32_t i=0; i<64; i++) - gpu_opcode_use[i] = 0; - WriteLog("--> GPU stats were reset!\n"); -} - - -void GPUDumpDisassembly(void) -{ - char buffer[512]; - - WriteLog("\n---[GPU code at 00F03000]---------------------------\n"); - uint32_t j = 0xF03000; - while (j <= 0xF03FFF) - { - uint32_t oldj = j; - j += dasmjag(JAGUAR_GPU, buffer, j); - WriteLog("\t%08X: %s\n", oldj, buffer); - } -} - - -void GPUDumpRegisters(void) -{ - WriteLog("\n---[GPU flags: NCZ %d%d%d]-----------------------\n", gpu_flag_n, gpu_flag_c, gpu_flag_z); - WriteLog("\nRegisters bank 0\n"); - for(int j=0; j<8; j++) - { - WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", - (j << 2) + 0, gpu_reg_bank_0[(j << 2) + 0], - (j << 2) + 1, gpu_reg_bank_0[(j << 2) + 1], - (j << 2) + 2, gpu_reg_bank_0[(j << 2) + 2], - (j << 2) + 3, gpu_reg_bank_0[(j << 2) + 3]); - } - WriteLog("Registers bank 1\n"); - for(int j=0; j<8; j++) - { - WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", - (j << 2) + 0, gpu_reg_bank_1[(j << 2) + 0], - (j << 2) + 1, gpu_reg_bank_1[(j << 2) + 1], - (j << 2) + 2, gpu_reg_bank_1[(j << 2) + 2], - (j << 2) + 3, gpu_reg_bank_1[(j << 2) + 3]); - } -} - - -void GPUDumpMemory(void) -{ - WriteLog("\n---[GPU data at 00F03000]---------------------------\n"); - for(int i=0; i<0xFFF; i+=4) - WriteLog("\t%08X: %02X %02X %02X %02X\n", 0xF03000+i, gpu_ram_8[i], - gpu_ram_8[i+1], gpu_ram_8[i+2], gpu_ram_8[i+3]); -} - - void GPUDone(void) { - WriteLog("\n\n---------------------------------------------------------------------\n"); - WriteLog("GPU I/O Registers\n"); - WriteLog("---------------------------------------------------------------------\n"); - WriteLog("F0%04X (G_FLAGS): $%06X\n", 0x2100, (gpu_flags & 0xFFFFFFF8) | (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z); - WriteLog("F0%04X (G_MTXC): $%04X\n", 0x2104, gpu_matrix_control); - WriteLog("F0%04X (G_MTXA): $%04X\n", 0x2108, gpu_pointer_to_matrix); - WriteLog("F0%04X (G_END): $%02X\n", 0x210C, gpu_data_organization); - WriteLog("F0%04X (G_PC): $%06X\n", 0x2110, gpu_pc); - WriteLog("F0%04X (G_CTRL): $%06X\n", 0x2114, gpu_control); - WriteLog("F0%04X (G_HIDATA): $%08X\n", 0x2118, gpu_hidata); - WriteLog("F0%04X (G_REMAIN): $%08X\n", 0x211C, gpu_remain); - WriteLog("F0%04X (G_DIVCTRL): $%02X\n", 0x211C, gpu_div_control); - WriteLog("---------------------------------------------------------------------\n\n\n"); - - WriteLog("GPU: Stopped at PC=%08X (GPU %s running)\n", (unsigned int)gpu_pc, GPU_RUNNING ? "was" : "wasn't"); - - // Get the interrupt latch & enable bits - uint8_t bits = (gpu_control >> 6) & 0x1F, mask = (gpu_flags >> 4) & 0x1F; - WriteLog("GPU: Latch bits = %02X, enable bits = %02X\n", bits, mask); - - GPUDumpRegisters(); - GPUDumpDisassembly(); - - WriteLog("\nGPU opcodes use:\n"); - for(int i=0; i<64; i++) - { - if (gpu_opcode_use[i]) - WriteLog("\t%17s %lu\n", gpu_opcode_str[i], gpu_opcode_use[i]); - } - WriteLog("\n"); } - // // Main GPU execution core // -static int testCount = 1; -static int len = 0; -static bool tripwire = false; + void GPUExec(int32_t cycles) { if (!GPU_RUNNING) return; -#ifdef GPU_SINGLE_STEPPING - if (gpu_control & 0x18) - { - cycles = 1; - gpu_control &= ~0x10; - } -#endif GPUHandleIRQs(); - gpu_releaseTimeSlice_flag = 0; - gpu_in_exec++; while (cycles > 0 && GPU_RUNNING) { -if (gpu_ram_8[0x054] == 0x98 && gpu_ram_8[0x055] == 0x0A && gpu_ram_8[0x056] == 0x03 - && gpu_ram_8[0x057] == 0x00 && gpu_ram_8[0x058] == 0x00 && gpu_ram_8[0x059] == 0x00) -{ - if (gpu_pc == 0xF03000) - { - extern uint32_t starCount; - starCount = 0; -/* WriteLog("GPU: Starting starfield generator... Dump of [R03=%08X]:\n", gpu_reg_bank_0[03]); - uint32_t base = gpu_reg_bank_0[3]; - for(uint32_t i=0; i<0x100; i+=16) - { - WriteLog("%02X: ", i); - for(uint32_t j=0; j<16; j++) - { - WriteLog("%02X ", JaguarReadByte(base + i + j)); - } - WriteLog("\n"); - }*/ - } -// if (gpu_pc == 0xF03) - { - } -}//*/ -/*if (gpu_pc == 0xF03B9E && gpu_reg_bank_0[01] == 0) -{ - GPUDumpRegisters(); - WriteLog("GPU: Starting disassembly log...\n"); - doGPUDis = true; -}//*/ -/*if (gpu_pc == 0xF0359A) -{ - doGPUDis = true; - GPUDumpRegisters(); -}*/ -/* gpu_flag_c = (gpu_flag_c ? 1 : 0); - gpu_flag_z = (gpu_flag_z ? 1 : 0); - gpu_flag_n = (gpu_flag_n ? 1 : 0);*/ -#if 0 -if (gpu_pc == 0xF03200) - doGPUDis = true; -#endif - uint16_t opcode = GPUReadWord(gpu_pc, GPU); uint32_t index = opcode >> 10; - gpu_instruction = opcode; // Added for GPU #3... gpu_opcode_first_parameter = (opcode >> 5) & 0x1F; gpu_opcode_second_parameter = opcode & 0x1F; -/*if (gpu_pc == 0xF03BE8) -WriteLog("Start of OP frame write...\n"); -if (gpu_pc == 0xF03EEE) -WriteLog("--> Writing BRANCH object ---\n"); -if (gpu_pc == 0xF03F62) -WriteLog("--> Writing BITMAP object ***\n");//*/ -/*if (gpu_pc == 0xF03546) -{ - WriteLog("\n--> GPU PC: F03546\n"); - GPUDumpRegisters(); - GPUDumpDisassembly(); -}//*/ -/*if (gpu_pc == 0xF033F6) -{ - WriteLog("\n--> GPU PC: F033F6\n"); - GPUDumpRegisters(); - GPUDumpDisassembly(); -}//*/ -/*if (gpu_pc == 0xF033CC) -{ - WriteLog("\n--> GPU PC: F033CC\n"); - GPUDumpRegisters(); - GPUDumpDisassembly(); -}//*/ -/*if (gpu_pc == 0xF033D6) -{ - WriteLog("\n--> GPU PC: F033D6 (#%d)\n", testCount++); - GPUDumpRegisters(); - GPUDumpMemory(); -}//*/ -/*if (gpu_pc == 0xF033D8) -{ - WriteLog("\n--> GPU PC: F033D8 (#%d)\n", testCount++); - GPUDumpRegisters(); - GPUDumpMemory(); -}//*/ -/*if (gpu_pc == 0xF0358E) -{ - WriteLog("\n--> GPU PC: F0358E (#%d)\n", testCount++); - GPUDumpRegisters(); - GPUDumpMemory(); -}//*/ -/*if (gpu_pc == 0xF034CA) -{ - WriteLog("\n--> GPU PC: F034CA (#%d)\n", testCount++); - GPUDumpRegisters(); -}//*/ -/*if (gpu_pc == 0xF034CA) -{ - len = gpu_reg[1] + 4;//, r9save = gpu_reg[9]; - WriteLog("\nAbout to subtract [#%d] (R14=%08X, R15=%08X, R9=%08X):\n ", testCount++, gpu_reg[14], gpu_reg[15], gpu_reg[9]); - for(int i=0; i GPU PC: F035C8 (#%d)\n", testCount++); - GPUDumpRegisters(); - GPUDumpDisassembly(); -}//*/ -if (gpu_start_log) -{ -// gpu_reset_stats(); -static char buffer[512]; -dasmjag(JAGUAR_GPU, buffer, gpu_pc); -WriteLog("GPU: [%08X] %s (RM=%08X, RN=%08X) -> ", gpu_pc, buffer, RM, RN); -}//*/ -//$E400 -> 1110 01 -> $39 -> 57 -//GPU #1 gpu_pc += 2; gpu_opcode[index](); -//GPU #2 -// gpu2_opcode[index](); -// gpu_pc += 2; -//GPU #3 (Doesn't show ATARI logo! #1 & #2 do...) -// gpu_pc += 2; -// gpu3_opcode[index](); - -// BIOS hacking -//GPU: [00F03548] jr nz,00F03560 (0xd561) (RM=00F03114, RN=00000004) -> --> JR: Branch taken. -/*static bool firstTime = true; -if (gpu_pc == 0xF03548 && firstTime) -{ - gpu_flag_z = 1; -// firstTime = false; - -//static char buffer[512]; -//int k=0xF03548; -//while (k<0xF0356C) -//{ -//int oldk = k; -//k += dasmjag(JAGUAR_GPU, buffer, k); -//WriteLog("GPU: [%08X] %s\n", oldk, buffer); -//} -// gpu_start_log = 1; -}//*/ -//GPU: [00F0354C] jump nz,(r29) (0xd3a1) (RM=00F03314, RN=00000004) -> (RM=00F03314, RN=00000004) -/*if (gpu_pc == 0xF0354C) - gpu_flag_z = 0;//, gpu_start_log = 1;//*/ cycles -= gpu_opcode_cycles[index]; - gpu_opcode_use[index]++; -if (gpu_start_log) - WriteLog("(RM=%08X, RN=%08X)\n", RM, RN);//*/ -if ((gpu_pc < 0xF03000 || gpu_pc > 0xF03FFF) && !tripwire) -{ - WriteLog("GPU: Executing outside local RAM! GPU_PC: %08X\n", gpu_pc); - tripwire = true; -} } - - gpu_in_exec--; } // // GPU opcodes // -/* -GPU opcodes use (offset punch--vertically below bad guy): - add 18686 - addq 32621 - sub 7483 - subq 10252 - and 21229 - or 15003 - btst 1822 - bset 2072 - mult 141 - div 2392 - shlq 13449 - shrq 10297 - sharq 11104 - cmp 6775 - cmpq 5944 - move 31259 - moveq 4473 - movei 23277 - loadb 46 - loadw 4201 - load 28580 - load_r14_indexed 1183 - load_r15_indexed 1125 - storew 178 - store 10144 - store_r14_indexed 320 - store_r15_indexed 1 - move_pc 1742 - jump 24467 - jr 18090 - nop 41362 -*/ - - static void gpu_opcode_jump(void) { -#ifdef GPU_DIS_JUMP -const char * condition[32] = -{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz", - "c z", "???", "???", "???", "???", "???", "???", "???", "???", - "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???", - "???", "???", "???", "F" }; - if (doGPUDis) - WriteLog("%06X: JUMP %s, (R%02u) [NCZ:%u%u%u, R%02u=%08X] ", gpu_pc-2, condition[IMM_2], IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM); -#endif - // normalize flags -/* gpu_flag_c = (gpu_flag_c ? 1 : 0); - gpu_flag_z = (gpu_flag_z ? 1 : 0); - gpu_flag_n = (gpu_flag_n ? 1 : 0);*/ - // KLUDGE: Used by BRANCH_CONDITION uint32_t jaguar_flags = (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z; if (BRANCH_CONDITION(IMM_2)) { -#ifdef GPU_DIS_JUMP - if (doGPUDis) - WriteLog("Branched!\n"); -#endif -if (gpu_start_log) - WriteLog(" --> JUMP: Branch taken.\n"); uint32_t delayed_pc = RM; GPUExec(1); gpu_pc = delayed_pc; -/* uint16_t opcode = GPUReadWord(gpu_pc, GPU); - gpu_opcode_first_parameter = (opcode >> 5) & 0x1F; - gpu_opcode_second_parameter = opcode & 0x1F; - - gpu_pc = delayed_pc; - gpu_opcode[opcode>>10]();//*/ } -#ifdef GPU_DIS_JUMP - else - if (doGPUDis) - WriteLog("Branch NOT taken.\n"); -#endif } - static void gpu_opcode_jr(void) { -#ifdef GPU_DIS_JR -const char * condition[32] = -{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz", - "c z", "???", "???", "???", "???", "???", "???", "???", "???", - "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???", - "???", "???", "???", "F" }; - if (doGPUDis) - WriteLog("%06X: JR %s, %06X [NCZ:%u%u%u] ", gpu_pc-2, condition[IMM_2], gpu_pc+((IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1) * 2), gpu_flag_n, gpu_flag_c, gpu_flag_z); -#endif -/* if (CONDITION(jaguar.op & 31)) - { - int32_t r1 = (INT8)((jaguar.op >> 2) & 0xF8) >> 2; - uint32_t newpc = jaguar.PC + r1; - CALL_MAME_DEBUG; - jaguar.op = ROPCODE(jaguar.PC); - jaguar.PC = newpc; - (*jaguar.table[jaguar.op >> 10])(); - - jaguar_icount -= 3; // 3 wait states guaranteed - }*/ - // normalize flags -/* gpu_flag_n = (gpu_flag_n ? 1 : 0); - gpu_flag_c = (gpu_flag_c ? 1 : 0); - gpu_flag_z = (gpu_flag_z ? 1 : 0);*/ - // KLUDGE: Used by BRANCH_CONDITION uint32_t jaguar_flags = (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z; if (BRANCH_CONDITION(IMM_2)) { -#ifdef GPU_DIS_JR - if (doGPUDis) - WriteLog("Branched!\n"); -#endif -if (gpu_start_log) - WriteLog(" --> JR: Branch taken.\n"); - int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1 + int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); int32_t delayed_pc = gpu_pc + (offset * 2); GPUExec(1); gpu_pc = delayed_pc; -/* uint16_t opcode = GPUReadWord(gpu_pc, GPU); - gpu_opcode_first_parameter = (opcode >> 5) & 0x1F; - gpu_opcode_second_parameter = opcode & 0x1F; - - gpu_pc = delayed_pc; - gpu_opcode[opcode>>10]();//*/ } -#ifdef GPU_DIS_JR - else - if (doGPUDis) - WriteLog("Branch NOT taken.\n"); -#endif } - static void gpu_opcode_add(void) { -#ifdef GPU_DIS_ADD - if (doGPUDis) - WriteLog("%06X: ADD R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res = RN + RM; CLR_ZNC; SET_ZNC_ADD(RN, RM, res); RN = res; -#ifdef GPU_DIS_ADD - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_addc(void) { -#ifdef GPU_DIS_ADDC - if (doGPUDis) - WriteLog("%06X: ADDC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif -/* int dreg = jaguar.op & 31; - uint32_t r1 = jaguar.r[(jaguar.op >> 5) & 31]; - uint32_t r2 = jaguar.r[dreg]; - uint32_t res = r2 + r1 + ((jaguar.FLAGS >> 1) & 1); - jaguar.r[dreg] = res; - CLR_ZNC; SET_ZNC_ADD(r2,r1,res);*/ - uint32_t res = RN + RM + gpu_flag_c; uint32_t carry = gpu_flag_c; -// SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes! SET_ZNC_ADD(RN + carry, RM, res); -// SET_ZNC_ADD(RN, RM + carry, res); RN = res; -#ifdef GPU_DIS_ADDC - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_addq(void) { -#ifdef GPU_DIS_ADDQ - if (doGPUDis) - WriteLog("%06X: ADDQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t r1 = gpu_convert_zero[IMM_1]; uint32_t res = RN + r1; CLR_ZNC; SET_ZNC_ADD(RN, r1, res); RN = res; -#ifdef GPU_DIS_ADDQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_addqt(void) { -#ifdef GPU_DIS_ADDQT - if (doGPUDis) - WriteLog("%06X: ADDQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif RN += gpu_convert_zero[IMM_1]; -#ifdef GPU_DIS_ADDQT - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_sub(void) { -#ifdef GPU_DIS_SUB - if (doGPUDis) - WriteLog("%06X: SUB R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res = RN - RM; SET_ZNC_SUB(RN, RM, res); RN = res; -#ifdef GPU_DIS_SUB - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_subc(void) { -#ifdef GPU_DIS_SUBC - if (doGPUDis) - WriteLog("%06X: SUBC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif - // This is how the GPU ALU does it--Two's complement with inverted carry uint64_t res = (uint64_t)RN + (uint64_t)(RM ^ 0xFFFFFFFF) + (gpu_flag_c ^ 1); - // Carry out of the result is inverted too gpu_flag_c = ((res >> 32) & 0x01) ^ 1; RN = (res & 0xFFFFFFFF); SET_ZN(RN); -#ifdef GPU_DIS_SUBC - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_subq(void) { -#ifdef GPU_DIS_SUBQ - if (doGPUDis) - WriteLog("%06X: SUBQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t r1 = gpu_convert_zero[IMM_1]; uint32_t res = RN - r1; SET_ZNC_SUB(RN, r1, res); RN = res; -#ifdef GPU_DIS_SUBQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_subqt(void) { -#ifdef GPU_DIS_SUBQT - if (doGPUDis) - WriteLog("%06X: SUBQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif RN -= gpu_convert_zero[IMM_1]; -#ifdef GPU_DIS_SUBQT - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_cmp(void) { -#ifdef GPU_DIS_CMP - if (doGPUDis) - WriteLog("%06X: CMP R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res = RN - RM; SET_ZNC_SUB(RN, RM, res); -#ifdef GPU_DIS_CMP - if (doGPUDis) - WriteLog("[NCZ:%u%u%u]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z); -#endif } - static void gpu_opcode_cmpq(void) { static int32_t sqtable[32] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1 }; -#ifdef GPU_DIS_CMPQ - if (doGPUDis) - WriteLog("%06X: CMPQ #%d, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, sqtable[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif - uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3; + + uint32_t r1 = sqtable[IMM_1 & 0x1F]; uint32_t res = RN - r1; SET_ZNC_SUB(RN, r1, res); -#ifdef GPU_DIS_CMPQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z); -#endif } - static void gpu_opcode_and(void) { -#ifdef GPU_DIS_AND - if (doGPUDis) - WriteLog("%06X: AND R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RN & RM; SET_ZN(RN); -#ifdef GPU_DIS_AND - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_or(void) { -#ifdef GPU_DIS_OR - if (doGPUDis) - WriteLog("%06X: OR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RN | RM; SET_ZN(RN); -#ifdef GPU_DIS_OR - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_xor(void) { -#ifdef GPU_DIS_XOR - if (doGPUDis) - WriteLog("%06X: XOR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RN ^ RM; SET_ZN(RN); -#ifdef GPU_DIS_XOR - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_not(void) { -#ifdef GPU_DIS_NOT - if (doGPUDis) - WriteLog("%06X: NOT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = ~RN; SET_ZN(RN); -#ifdef GPU_DIS_NOT - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_move_pc(void) { -#ifdef GPU_DIS_MOVEPC - if (doGPUDis) - WriteLog("%06X: MOVE PC, R%02u [NCZ:%u%u%u, PC=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_pc-2, IMM_2, RN); -#endif - // Should be previous PC--this might not always be previous instruction! - // Then again, this will point right at the *current* instruction, i.e., MOVE PC,R! RN = gpu_pc - 2; -#ifdef GPU_DIS_MOVEPC - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_sat8(void) { -#ifdef GPU_DIS_SAT8 - if (doGPUDis) - WriteLog("%06X: SAT8 R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif RN = ((int32_t)RN < 0 ? 0 : (RN > 0xFF ? 0xFF : RN)); SET_ZN(RN); -#ifdef GPU_DIS_SAT8 - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_sat16(void) { RN = ((int32_t)RN < 0 ? 0 : (RN > 0xFFFF ? 0xFFFF : RN)); @@ -1770,213 +788,101 @@ static void gpu_opcode_sat24(void) SET_ZN(RN); } - static void gpu_opcode_store_r14_indexed(void) { -#ifdef GPU_DIS_STORE14I - if (doGPUDis) - WriteLog("%06X: STORE R%02u, (R14+$%02X) [NCZ:%u%u%u, R%02u=%08X, R14+$%02X=%08X]\n", gpu_pc-2, IMM_2, gpu_convert_zero[IMM_1] << 2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, gpu_convert_zero[IMM_1] << 2, gpu_reg[14]+(gpu_convert_zero[IMM_1] << 2)); -#endif -#ifdef GPU_CORRECT_ALIGNMENT uint32_t address = gpu_reg[14] + (gpu_convert_zero[IMM_1] << 2); if (address >= 0xF03000 && address <= 0xF03FFF) GPUWriteLong(address & 0xFFFFFFFC, RN, GPU); else GPUWriteLong(address, RN, GPU); -#else - GPUWriteLong(gpu_reg[14] + (gpu_convert_zero[IMM_1] << 2), RN, GPU); -#endif } - static void gpu_opcode_store_r15_indexed(void) { -#ifdef GPU_DIS_STORE15I - if (doGPUDis) - WriteLog("%06X: STORE R%02u, (R15+$%02X) [NCZ:%u%u%u, R%02u=%08X, R15+$%02X=%08X]\n", gpu_pc-2, IMM_2, gpu_convert_zero[IMM_1] << 2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, gpu_convert_zero[IMM_1] << 2, gpu_reg[15]+(gpu_convert_zero[IMM_1] << 2)); -#endif -#ifdef GPU_CORRECT_ALIGNMENT uint32_t address = gpu_reg[15] + (gpu_convert_zero[IMM_1] << 2); if (address >= 0xF03000 && address <= 0xF03FFF) GPUWriteLong(address & 0xFFFFFFFC, RN, GPU); else GPUWriteLong(address, RN, GPU); -#else - GPUWriteLong(gpu_reg[15] + (gpu_convert_zero[IMM_1] << 2), RN, GPU); -#endif } - static void gpu_opcode_load_r14_ri(void) { -#ifdef GPU_DIS_LOAD14R - if (doGPUDis) - WriteLog("%06X: LOAD (R14+R%02u), R%02u [NCZ:%u%u%u, R14+R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM+gpu_reg[14], IMM_2, RN); -#endif -#ifdef GPU_CORRECT_ALIGNMENT uint32_t address = gpu_reg[14] + RM; if (address >= 0xF03000 && address <= 0xF03FFF) RN = GPUReadLong(address & 0xFFFFFFFC, GPU); else RN = GPUReadLong(address, GPU); -#else - RN = GPUReadLong(gpu_reg[14] + RM, GPU); -#endif -#ifdef GPU_DIS_LOAD14R - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_load_r15_ri(void) { -#ifdef GPU_DIS_LOAD15R - if (doGPUDis) - WriteLog("%06X: LOAD (R15+R%02u), R%02u [NCZ:%u%u%u, R15+R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM+gpu_reg[15], IMM_2, RN); -#endif -#ifdef GPU_CORRECT_ALIGNMENT uint32_t address = gpu_reg[15] + RM; if (address >= 0xF03000 && address <= 0xF03FFF) RN = GPUReadLong(address & 0xFFFFFFFC, GPU); else RN = GPUReadLong(address, GPU); -#else - RN = GPUReadLong(gpu_reg[15] + RM, GPU); -#endif -#ifdef GPU_DIS_LOAD15R - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_store_r14_ri(void) { -#ifdef GPU_DIS_STORE14R - if (doGPUDis) - WriteLog("%06X: STORE R%02u, (R14+R%02u) [NCZ:%u%u%u, R%02u=%08X, R14+R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM+gpu_reg[14]); -#endif -#ifdef GPU_CORRECT_ALIGNMENT uint32_t address = gpu_reg[14] + RM; if (address >= 0xF03000 && address <= 0xF03FFF) GPUWriteLong(address & 0xFFFFFFFC, RN, GPU); else GPUWriteLong(address, RN, GPU); -#else - GPUWriteLong(gpu_reg[14] + RM, RN, GPU); -#endif } - static void gpu_opcode_store_r15_ri(void) { -#ifdef GPU_DIS_STORE15R - if (doGPUDis) - WriteLog("%06X: STORE R%02u, (R15+R%02u) [NCZ:%u%u%u, R%02u=%08X, R15+R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM+gpu_reg[15]); -#endif -#ifdef GPU_CORRECT_ALIGNMENT_STORE - uint32_t address = gpu_reg[15] + RM; - - if (address >= 0xF03000 && address <= 0xF03FFF) - GPUWriteLong(address & 0xFFFFFFFC, RN, GPU); - else - GPUWriteLong(address, RN, GPU); -#else GPUWriteLong(gpu_reg[15] + RM, RN, GPU); -#endif } - static void gpu_opcode_nop(void) { -#ifdef GPU_DIS_NOP - if (doGPUDis) - WriteLog("%06X: NOP [NCZ:%u%u%u]\n", gpu_pc-2, gpu_flag_n, gpu_flag_c, gpu_flag_z); -#endif } - static void gpu_opcode_pack(void) { -#ifdef GPU_DIS_PACK - if (doGPUDis) - WriteLog("%06X: %s R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, (!IMM_1 ? "PACK " : "UNPACK"), IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t val = RN; -//BUG! if (RM == 0) // Pack if (IMM_1 == 0) // Pack RN = ((val >> 10) & 0x0000F000) | ((val >> 5) & 0x00000F00) | (val & 0x000000FF); else // Unpack RN = ((val & 0x0000F000) << 10) | ((val & 0x00000F00) << 5) | (val & 0x000000FF); -#ifdef GPU_DIS_PACK - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_storeb(void) { -#ifdef GPU_DIS_STOREB - if (doGPUDis) - WriteLog("%06X: STOREB R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM); -#endif -//Is this right??? -// Would appear to be so...! if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) GPUWriteLong(RM, RN & 0xFF, GPU); else JaguarWriteByte(RM, RN, GPU); } - static void gpu_opcode_storew(void) { -#ifdef GPU_DIS_STOREW - if (doGPUDis) - WriteLog("%06X: STOREW R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM); -#endif -#ifdef GPU_CORRECT_ALIGNMENT if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) GPUWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, GPU); else JaguarWriteWord(RM, RN, GPU); -#else - if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) - GPUWriteLong(RM, RN & 0xFFFF, GPU); - else - JaguarWriteWord(RM, RN, GPU); -#endif } - static void gpu_opcode_store(void) { -#ifdef GPU_DIS_STORE - if (doGPUDis) - WriteLog("%06X: STORE R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_pc-2, IMM_2, IMM_1, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN, IMM_1, RM); -#endif -#ifdef GPU_CORRECT_ALIGNMENT if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) GPUWriteLong(RM & 0xFFFFFFFC, RN, GPU); else GPUWriteLong(RM, RN, GPU); -#else - GPUWriteLong(RM, RN, GPU); -#endif } - static void gpu_opcode_storep(void) { -#ifdef GPU_CORRECT_ALIGNMENT if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) { GPUWriteLong((RM & 0xFFFFFFF8) + 0, gpu_hidata, GPU); @@ -1987,100 +893,31 @@ static void gpu_opcode_storep(void) GPUWriteLong(RM + 0, gpu_hidata, GPU); GPUWriteLong(RM + 4, RN, GPU); } -#else - GPUWriteLong(RM + 0, gpu_hidata, GPU); - GPUWriteLong(RM + 4, RN, GPU); -#endif } static void gpu_opcode_loadb(void) { -#ifdef GPU_DIS_LOADB - if (doGPUDis) - WriteLog("%06X: LOADB (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) RN = GPUReadLong(RM, GPU) & 0xFF; else RN = JaguarReadByte(RM, GPU); -#ifdef GPU_DIS_LOADB - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_loadw(void) { -#ifdef GPU_DIS_LOADW - if (doGPUDis) - WriteLog("%06X: LOADW (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif -#ifdef GPU_CORRECT_ALIGNMENT if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) RN = GPUReadLong(RM & 0xFFFFFFFE, GPU) & 0xFFFF; else RN = JaguarReadWord(RM, GPU); -#else - if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) - RN = GPUReadLong(RM, GPU) & 0xFFFF; - else - RN = JaguarReadWord(RM, GPU); -#endif -#ifdef GPU_DIS_LOADW - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - -// According to the docs, & "Do The Same", this address is long aligned... -// So let's try it: -// And it works!!! Need to fix all instances... -// Also, Power Drive Rally seems to contradict the idea that only LOADs in -// the $F03000-$F03FFF range are aligned... -#warning "!!! Alignment issues, need to find definitive final word on this !!!" -/* -Preliminary testing on real hardware seems to confirm that something strange goes on -with unaligned reads in main memory. When the address is off by 1, the result is the -same as the long address with the top byte replaced by something. So if the read is -from $401, and $400 has 12 34 56 78, the value read will be $nn345678, where nn is a currently unknown vlaue. -When the address is off by 2, the result would be $nnnn5678, where nnnn is unknown. -When the address is off by 3, the result would be $nnnnnn78, where nnnnnn is unknown. -It may be that the "unknown" values come from the prefetch queue, but not sure how -to test that. They seem to be stable, though, which would indicate such a mechanism. -Sometimes, however, the off by 2 case returns $12345678! -*/ static void gpu_opcode_load(void) { -#ifdef GPU_DIS_LOAD - if (doGPUDis) - WriteLog("%06X: LOAD (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif -#ifdef GPU_CORRECT_ALIGNMENT - uint32_t mask[4] = { 0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00 }; -// if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) - RN = GPUReadLong(RM & 0xFFFFFFFC, GPU); -// RN = GPUReadLong(RM & 0x00FFFFFC, GPU); -// else -// RN = GPUReadLong(RM, GPU); - // Simulate garbage in unaligned reads... -//seems that this behavior is different in GPU mem vs. main mem... -// if ((RM < 0xF03000) || (RM > 0xF0BFFF)) -// RN |= mask[RM & 0x03]; -#else - RN = GPUReadLong(RM, GPU); -#endif -#ifdef GPU_DIS_LOAD - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif + RN = GPUReadLong(RM & 0xFFFFFFFC, GPU); } - static void gpu_opcode_loadp(void) { -#ifdef GPU_CORRECT_ALIGNMENT if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) { gpu_hidata = GPUReadLong((RM & 0xFFFFFFF8) + 0, GPU); @@ -2091,221 +928,96 @@ static void gpu_opcode_loadp(void) gpu_hidata = GPUReadLong(RM + 0, GPU); RN = GPUReadLong(RM + 4, GPU); } -#else - gpu_hidata = GPUReadLong(RM + 0, GPU); - RN = GPUReadLong(RM + 4, GPU); -#endif } - static void gpu_opcode_load_r14_indexed(void) { -#ifdef GPU_DIS_LOAD14I - if (doGPUDis) - WriteLog("%06X: LOAD (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1] << 2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_convert_zero[IMM_1] << 2, gpu_reg[14]+(gpu_convert_zero[IMM_1] << 2), IMM_2, RN); -#endif -#ifdef GPU_CORRECT_ALIGNMENT uint32_t address = gpu_reg[14] + (gpu_convert_zero[IMM_1] << 2); if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) RN = GPUReadLong(address & 0xFFFFFFFC, GPU); else RN = GPUReadLong(address, GPU); -#else - RN = GPUReadLong(gpu_reg[14] + (gpu_convert_zero[IMM_1] << 2), GPU); -#endif -#ifdef GPU_DIS_LOAD14I - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_load_r15_indexed(void) { -#ifdef GPU_DIS_LOAD15I - if (doGPUDis) - WriteLog("%06X: LOAD (R15+$%02X), R%02u [NCZ:%u%u%u, R15+$%02X=%08X, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1] << 2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_convert_zero[IMM_1] << 2, gpu_reg[15]+(gpu_convert_zero[IMM_1] << 2), IMM_2, RN); -#endif -#ifdef GPU_CORRECT_ALIGNMENT uint32_t address = gpu_reg[15] + (gpu_convert_zero[IMM_1] << 2); if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) RN = GPUReadLong(address & 0xFFFFFFFC, GPU); else RN = GPUReadLong(address, GPU); -#else - RN = GPUReadLong(gpu_reg[15] + (gpu_convert_zero[IMM_1] << 2), GPU); -#endif -#ifdef GPU_DIS_LOAD15I - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_movei(void) { -#ifdef GPU_DIS_MOVEI - if (doGPUDis) - WriteLog("%06X: MOVEI #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, (uint32_t)GPUReadWord(gpu_pc) | ((uint32_t)GPUReadWord(gpu_pc + 2) << 16), IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif - // This instruction is followed by 32-bit value in LSW / MSW format... RN = (uint32_t)GPUReadWord(gpu_pc, GPU) | ((uint32_t)GPUReadWord(gpu_pc + 2, GPU) << 16); gpu_pc += 4; -#ifdef GPU_DIS_MOVEI - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_moveta(void) { -#ifdef GPU_DIS_MOVETA - if (doGPUDis) - WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN); -#endif ALTERNATE_RN = RM; -#ifdef GPU_DIS_MOVETA - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN); -#endif } - static void gpu_opcode_movefa(void) { -#ifdef GPU_DIS_MOVEFA - if (doGPUDis) - WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN); -#endif RN = ALTERNATE_RM; -#ifdef GPU_DIS_MOVEFA - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN); -#endif } - static void gpu_opcode_move(void) { -#ifdef GPU_DIS_MOVE - if (doGPUDis) - WriteLog("%06X: MOVE R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = RM; -#ifdef GPU_DIS_MOVE - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_moveq(void) { -#ifdef GPU_DIS_MOVEQ - if (doGPUDis) - WriteLog("%06X: MOVEQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif RN = IMM_1; -#ifdef GPU_DIS_MOVEQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_resmac(void) { RN = gpu_acc; } - static void gpu_opcode_imult(void) { -#ifdef GPU_DIS_IMULT - if (doGPUDis) - WriteLog("%06X: IMULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = (int16_t)RN * (int16_t)RM; SET_ZN(RN); -#ifdef GPU_DIS_IMULT - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_mult(void) { -#ifdef GPU_DIS_MULT - if (doGPUDis) - WriteLog("%06X: MULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif RN = (uint16_t)RM * (uint16_t)RN; -// RN = (RM & 0xFFFF) * (RN & 0xFFFF); SET_ZN(RN); -#ifdef GPU_DIS_MULT - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_bclr(void) { -#ifdef GPU_DIS_BCLR - if (doGPUDis) - WriteLog("%06X: BCLR #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t res = RN & ~(1 << IMM_1); RN = res; SET_ZN(res); -#ifdef GPU_DIS_BCLR - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_btst(void) { -#ifdef GPU_DIS_BTST - if (doGPUDis) - WriteLog("%06X: BTST #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif gpu_flag_z = (~RN >> IMM_1) & 1; -#ifdef GPU_DIS_BTST - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_bset(void) { -#ifdef GPU_DIS_BSET - if (doGPUDis) - WriteLog("%06X: BSET #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t res = RN | (1 << IMM_1); RN = res; SET_ZN(res); -#ifdef GPU_DIS_BSET - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_imacn(void) { uint32_t res = (int16_t)RM * (int16_t)(RN); gpu_acc += res; } - static void gpu_opcode_mtoi(void) { uint32_t _RM = RM; @@ -2313,7 +1025,6 @@ static void gpu_opcode_mtoi(void) SET_ZN(res); } - static void gpu_opcode_normi(void) { uint32_t _RM = RM; @@ -2338,12 +1049,12 @@ static void gpu_opcode_normi(void) static void gpu_opcode_mmult(void) { - int count = gpu_matrix_control & 0x0F; // Matrix width - uint32_t addr = gpu_pointer_to_matrix; // In the GPU's RAM + int count = gpu_matrix_control & 0x0F; + uint32_t addr = gpu_pointer_to_matrix; int64_t accum = 0; uint32_t res; - if (gpu_matrix_control & 0x10) // Column stepping + if (gpu_matrix_control & 0x10) { for(int i=0; i ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif gpu_flag_c = RN >> 31; if (RN == 0x80000000) - //Is 0x80000000 a positive number? If so, then we need to set C to 0 as well! gpu_flag_n = 1, gpu_flag_z = 0; else { @@ -2395,54 +1099,18 @@ static void gpu_opcode_abs(void) RN = -RN; gpu_flag_n = 0; SET_FLAG_Z(RN); } -#ifdef GPU_DIS_ABS - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - -static void gpu_opcode_div(void) // RN / RM +static void gpu_opcode_div(void) { -#ifdef GPU_DIS_DIV - if (doGPUDis) - WriteLog("%06X: DIV R%02u, R%02u (%s) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, (gpu_div_control & 0x01 ? "16.16" : "32"), gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif -#if 0 - if (RM) - { - if (gpu_div_control & 0x01) // 16.16 division - { - gpu_remain = ((uint64_t)RN << 16) % RM; - RN = ((uint64_t)RN << 16) / RM; - } - else - { - // We calculate the remainder first because we destroy RN after - // this by assigning it to itself. - gpu_remain = RN % RM; - RN = RN / RM; - } - } - else - { - // This is what happens according to SCPCD. NYAN! - RN = 0xFFFFFFFF; - gpu_remain = 0; - } -#else - // Real algorithm, courtesy of SCPCD: NYAN! uint32_t q = RN; uint32_t r = 0; - // If 16.16 division, stuff top 16 bits of RN into remainder and put the - // bottom 16 of RN in top 16 of quotient if (gpu_div_control & 0x01) q <<= 16, r = RN >> 16; for(int i=0; i<32; i++) { -// uint32_t sign = (r >> 31) & 0x01; uint32_t sign = r & 0x80000000; r = (r << 1) | ((q >> 31) & 0x01); r += (sign ? RM : -RM); @@ -2451,15 +1119,8 @@ static void gpu_opcode_div(void) // RN / RM RN = q; gpu_remain = r; -#endif - -#ifdef GPU_DIS_DIV - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] Remainder: %08X\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN, gpu_remain); -#endif } - static void gpu_opcode_imultn(void) { uint32_t res = (int32_t)((int16_t)RN * (int16_t)RM); @@ -2468,119 +1129,48 @@ static void gpu_opcode_imultn(void) SET_FLAG_N(res); } - static void gpu_opcode_neg(void) { -#ifdef GPU_DIS_NEG - if (doGPUDis) - WriteLog("%06X: NEG R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t res = -RN; SET_ZNC_SUB(0, RN, res); RN = res; -#ifdef GPU_DIS_NEG - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_shlq(void) { -#ifdef GPU_DIS_SHLQ - if (doGPUDis) - WriteLog("%06X: SHLQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, 32 - IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif -// Was a bug here... -// (Look at Aaron's code: If r1 = 32, then 32 - 32 = 0 which is wrong!) int32_t r1 = 32 - IMM_1; uint32_t res = RN << r1; SET_ZN(res); gpu_flag_c = (RN >> 31) & 1; RN = res; -#ifdef GPU_DIS_SHLQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_shrq(void) { -#ifdef GPU_DIS_SHRQ - if (doGPUDis) - WriteLog("%06X: SHRQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif int32_t r1 = gpu_convert_zero[IMM_1]; uint32_t res = RN >> r1; SET_ZN(res); gpu_flag_c = RN & 1; RN = res; -#ifdef GPU_DIS_SHRQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_ror(void) { -#ifdef GPU_DIS_ROR - if (doGPUDis) - WriteLog("%06X: ROR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t r1 = RM & 0x1F; uint32_t res = (RN >> r1) | (RN << (32 - r1)); SET_ZN(res); gpu_flag_c = (RN >> 31) & 1; RN = res; -#ifdef GPU_DIS_ROR - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - static void gpu_opcode_rorq(void) { -#ifdef GPU_DIS_RORQ - if (doGPUDis) - WriteLog("%06X: RORQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t r1 = gpu_convert_zero[IMM_1 & 0x1F]; uint32_t r2 = RN; uint32_t res = (r2 >> r1) | (r2 << (32 - r1)); RN = res; SET_ZN(res); gpu_flag_c = (r2 >> 31) & 0x01; -#ifdef GPU_DIS_RORQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_sha(void) { -/* int dreg = jaguar.op & 31; - int32_t r1 = (int32_t)jaguar.r[(jaguar.op >> 5) & 31]; - uint32_t r2 = jaguar.r[dreg]; - uint32_t res; - - CLR_ZNC; - if (r1 < 0) - { - res = (r1 <= -32) ? 0 : (r2 << -r1); - jaguar.FLAGS |= (r2 >> 30) & 2; - } - else - { - res = (r1 >= 32) ? ((int32_t)r2 >> 31) : ((int32_t)r2 >> r1); - jaguar.FLAGS |= (r2 << 1) & 2; - } - jaguar.r[dreg] = res; - SET_ZN(res);*/ - -#ifdef GPU_DIS_SHA - if (doGPUDis) - WriteLog("%06X: SHA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif uint32_t res; if ((int32_t)RM < 0) @@ -2595,94 +1185,26 @@ static void gpu_opcode_sha(void) } RN = res; SET_ZN(res); -#ifdef GPU_DIS_SHA - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif - -/* int32_t sRM=(int32_t)RM; - uint32_t _RN=RN; - - if (sRM<0) - { - uint32_t shift=-sRM; - if (shift>=32) shift=32; - gpu_flag_c=(_RN&0x80000000)>>31; - while (shift) - { - _RN<<=1; - shift--; - } - } - else - { - uint32_t shift=sRM; - if (shift>=32) shift=32; - gpu_flag_c=_RN&0x1; - while (shift) - { - _RN=((int32_t)_RN)>>1; - shift--; - } - } - RN=_RN; - SET_FLAG_Z(_RN); - SET_FLAG_N(_RN);*/ } - static void gpu_opcode_sharq(void) { -#ifdef GPU_DIS_SHARQ - if (doGPUDis) - WriteLog("%06X: SHARQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", gpu_pc-2, gpu_convert_zero[IMM_1], IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif uint32_t res = (int32_t)RN >> gpu_convert_zero[IMM_1]; SET_ZN(res); gpu_flag_c = RN & 0x01; RN = res; -#ifdef GPU_DIS_SHARQ - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_2, RN); -#endif } - static void gpu_opcode_sh(void) { -#ifdef GPU_DIS_SH - if (doGPUDis) - WriteLog("%06X: SH R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif - if (RM & 0x80000000) // Shift left + if (RM & 0x80000000) { gpu_flag_c = RN >> 31; RN = ((int32_t)RM <= -32 ? 0 : RN << -(int32_t)RM); } - else // Shift right + else { gpu_flag_c = RN & 0x01; RN = (RM >= 32 ? 0 : RN >> RM); } SET_ZN(RN); -#ifdef GPU_DIS_SH - if (doGPUDis) - WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); -#endif } - - -//Temporary: Testing only! -//#include "gpu2.cpp" -//#include "gpu3.cpp" - -#else - - -// New thread-safe GPU core - -int GPUCore(void * data) -{ -} - -#endif - diff --git a/waterbox/virtualjaguar/src/gpu.h b/waterbox/virtualjaguar/src/gpu.h index 47ec01252a..2d24715ffb 100644 --- a/waterbox/virtualjaguar/src/gpu.h +++ b/waterbox/virtualjaguar/src/gpu.h @@ -5,7 +5,6 @@ #ifndef __GPU_H__ #define __GPU_H__ -//#include "types.h" #include "memory.h" #define GPU_CONTROL_RAM_BASE 0x00F02100 @@ -27,8 +26,6 @@ void GPUWriteWord(uint32_t offset, uint16_t data, uint32_t who = UNKNOWN); void GPUWriteLong(uint32_t offset, uint32_t data, uint32_t who = UNKNOWN); uint32_t GPUGetPC(void); -void GPUReleaseTimeslice(void); -void GPUResetStats(void); uint32_t GPUReadPC(void); // GPU interrupt numbers (from $F00100, bits 4-8) diff --git a/waterbox/virtualjaguar/src/jagdasm.cpp b/waterbox/virtualjaguar/src/jagdasm.cpp index 885e46a664..4ce77e5b6c 100644 --- a/waterbox/virtualjaguar/src/jagdasm.cpp +++ b/waterbox/virtualjaguar/src/jagdasm.cpp @@ -64,8 +64,6 @@ const char * condition[32] = "never," }; - - char * signed_16bit(int16_t val) { static char temp[10]; @@ -78,7 +76,6 @@ char * signed_16bit(int16_t val) return temp; } - unsigned dasmjag(int dsp_type, char * bufferOut, unsigned pc) { char buffer[64]; @@ -180,9 +177,6 @@ unsigned dasmjag(int dsp_type, char * bufferOut, unsigned pc) break; } -#if 0 - sprintf(bufferOut,"%-24s (%04X)", buffer, op); -#else if (size == 2) sprintf(bufferOut, "%04X %-24s", op, buffer); else @@ -190,7 +184,6 @@ unsigned dasmjag(int dsp_type, char * bufferOut, unsigned pc) uint16_t word1 = ROPCODE(pc), word2 = ROPCODE(pc + 2); sprintf(bufferOut, "%04X %04X %04X %-24s", op, word1, word2, buffer); } -#endif return size; } diff --git a/waterbox/virtualjaguar/src/jaguar.cpp b/waterbox/virtualjaguar/src/jaguar.cpp index bbbf0eb406..a34fe0bf2e 100644 --- a/waterbox/virtualjaguar/src/jaguar.cpp +++ b/waterbox/virtualjaguar/src/jaguar.cpp @@ -16,6 +16,7 @@ #include "jaguar.h" +#include #include #include #include "blitter.h" @@ -24,1042 +25,63 @@ #include "dsp.h" #include "eeprom.h" #include "event.h" -#include "foooked.h" #include "gpu.h" #include "jerry.h" #include "joystick.h" -#include "log.h" #include "m68000/m68kinterface.h" -//#include "memory.h" #include "memtrack.h" -#include "mmu.h" #include "settings.h" #include "tom.h" -#define CPU_DEBUG -//Do this in makefile??? Yes! Could, but it's easier to define here... -//#define LOG_UNMAPPED_MEMORY_ACCESSES -//#define ABORT_ON_UNMAPPED_MEMORY_ACCESS -//#define ABORT_ON_ILLEGAL_INSTRUCTIONS -//#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION -//#define CPU_DEBUG_MEMORY -//#define LOG_CD_BIOS_CALLS -//#define CPU_DEBUG_TRACING -#define ALPINE_FUNCTIONS - // Private function prototypes unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who = UNKNOWN); unsigned jaguar_unknown_readword(unsigned address, uint32_t who = UNKNOWN); void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who = UNKNOWN); void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who = UNKNOWN); -void M68K_show_context(void); // External variables -#ifdef CPU_DEBUG_MEMORY -extern bool startMemLog; // Set by "e" key -extern int effect_start; -extern int effect_start2, effect_start3, effect_start4, effect_start5, effect_start6; -#endif - // Really, need to include memory.h for this, but it might interfere with some stuff... extern uint8_t jagMemSpace[]; // Internal variables -uint32_t jaguar_active_memory_dumps = 0; - uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress; bool jaguarCartInserted = false; bool lowerField = false; -#ifdef CPU_DEBUG_MEMORY -uint8_t writeMemMax[0x400000], writeMemMin[0x400000]; -uint8_t readMem[0x400000]; -uint32_t returnAddr[4000], raPtr = 0xFFFFFFFF; -#endif - -uint32_t pcQueue[0x400]; -uint32_t a0Queue[0x400]; -uint32_t a1Queue[0x400]; -uint32_t a2Queue[0x400]; -uint32_t a3Queue[0x400]; -uint32_t a4Queue[0x400]; -uint32_t a5Queue[0x400]; -uint32_t a6Queue[0x400]; -uint32_t a7Queue[0x400]; -uint32_t d0Queue[0x400]; -uint32_t d1Queue[0x400]; -uint32_t d2Queue[0x400]; -uint32_t d3Queue[0x400]; -uint32_t d4Queue[0x400]; -uint32_t d5Queue[0x400]; -uint32_t d6Queue[0x400]; -uint32_t d7Queue[0x400]; -uint32_t srQueue[0x400]; -uint32_t pcQPtr = 0; -bool startM68KTracing = false; - -// Breakpoint on memory access vars (exported) -bool bpmActive = false; -uint32_t bpmAddress1; - - -// -// Callback function to detect illegal instructions -// -void GPUDumpDisassembly(void); -void GPUDumpRegisters(void); -static bool start = false; - void M68KInstructionHook(void) { - uint32_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC); -// Temp, for comparing... -{ -/* static char buffer[2048];//, mem[64]; - m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000); - printf("%08X: %s\n", m68kPC, buffer);//*/ + // TODO: Trace/Exec callback } -//JaguarDasm(m68kPC, 1); -//Testing Hover Strike... -#if 0 -//Dasm(regs.pc, 1); -static int hitCount = 0; -static int inRoutine = 0; -static int instSeen; - -//if (regs.pc == 0x80340A) -if (m68kPC == 0x803416) -{ - hitCount++; - inRoutine = 1; - instSeen = 0; - printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1)); -} -else if (m68kPC == 0x803422) -{ - inRoutine = 0; - printf("(%i instructions)\n", instSeen); -} - -if (inRoutine) - instSeen++; -#endif - -// For code tracing... -#ifdef CPU_DEBUG_TRACING - if (startM68KTracing) - { - static char buffer[2048]; - - m68k_disassemble(buffer, m68kPC, 0); - WriteLog("%06X: %s\n", m68kPC, buffer); - } -#endif - -// For tracebacks... -// Ideally, we'd save all the registers as well... - pcQueue[pcQPtr] = m68kPC; - a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0); - a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1); - a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2); - a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3); - a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4); - a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5); - a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6); - a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7); - d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0); - d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1); - d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2); - d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3); - d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4); - d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5); - d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6); - d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7); - srQueue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_SR); - pcQPtr++; - pcQPtr &= 0x3FF; - - if (m68kPC & 0x01) // Oops! We're fetching an odd address! - { - /*WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n"); - - static char buffer[2048]; - for(int i=0; i<0x400; i++) - { -// WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]); - WriteLog("[A0=%08X, A1=%08X, A2=%08X, A3=%08X, A4=%08X, A5=%08X, A6=%08X, A7=%08X, D0=%08X, D1=%08X, D2=%08X, D3=%08X, D4=%08X, D5=%08X, D6=%08X, D7=%08X, SR=%04X]\n", a0Queue[(pcQPtr + i) & 0x3FF], a1Queue[(pcQPtr + i) & 0x3FF], a2Queue[(pcQPtr + i) & 0x3FF], a3Queue[(pcQPtr + i) & 0x3FF], a4Queue[(pcQPtr + i) & 0x3FF], a5Queue[(pcQPtr + i) & 0x3FF], a6Queue[(pcQPtr + i) & 0x3FF], a7Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF], d1Queue[(pcQPtr + i) & 0x3FF], d2Queue[(pcQPtr + i) & 0x3FF], d3Queue[(pcQPtr + i) & 0x3FF], d4Queue[(pcQPtr + i) & 0x3FF], d5Queue[(pcQPtr + i) & 0x3FF], d6Queue[(pcQPtr + i) & 0x3FF], d7Queue[(pcQPtr + i) & 0x3FF], srQueue[(pcQPtr + i) & 0x3FF]); - m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000); - WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer); - } - WriteLog("\n"); - - uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7); - WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack)); - for(int i=0; i<10; i++) - WriteLog("%06X: %08X\n", topOfStack - (i * 4), JaguarReadLong(topOfStack - (i * 4))); - WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled"); - M68K_show_context(); - LogDone(); - exit(0);*/ - } - - // Disassemble everything -/* { - static char buffer[2048]; - m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000); - WriteLog("%08X: %s", m68kPC, buffer); - WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n", - m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), - m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1)); - }//*/ -/* if (m68kPC >= 0x807EC4 && m68kPC <= 0x807EDB) - { - static char buffer[2048]; - m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000); - WriteLog("%08X: %s", m68kPC, buffer); - WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n", - m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), - m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1)); - }//*/ -/* if (m68kPC == 0x8D0E48 && effect_start5) - { - WriteLog("\nM68K: At collision detection code. Exiting!\n\n"); - GPUDumpRegisters(); - GPUDumpDisassembly(); - log_done(); - exit(0); - }//*/ -/* uint16_t opcode = JaguarReadWord(m68kPC); - if (opcode == 0x4E75) // RTS - { - if (startMemLog) -// WriteLog("Jaguar: Returning from subroutine to %08X\n", JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7))); - { - uint32_t addr = JaguarReadLong(m68k_get_reg(NULL, M68K_REG_A7)); - bool found = false; - if (raPtr != 0xFFFFFFFF) - { - for(uint32_t i=0; i<=raPtr; i++) - { - if (returnAddr[i] == addr) - { - found = true; - break; - } - } - } - - if (!found) - returnAddr[++raPtr] = addr; - } - }//*/ - -//Flip Out! debugging... -//805F46, 806486 -/* -00805FDC: movea.l #$9c6f8, A0 D0=00100010, A0=00100000 -00805FE2: move.w #$10, (A0)+ D0=00100010, A0=0009C6F8 -00805FE6: cmpa.l #$c96f8, A0 D0=00100010, A0=0009C6FA -00805FEC: bne 805fe2 D0=00100010, A0=0009C6FA - -0080603A: move.l #$11ed7c, $100.w D0=61700080, A0=000C96F8, D1=00000000, A1=000040D8 - -0012314C: move.l (A0)+, (A1)+ D0=61700080, A0=00124174, D1=00000000, A1=00F03FFC -0012314E: cmpa.l #$f04000, A1 D0=61700080, A0=00124178, D1=00000000, A1=00F04000 -00123154: blt 12314c D0=61700080, A0=00124178, D1=00000000, A1=00F04000 -00123156: move.l #$0, $f035d0.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000 -00123160: move.l #$f03000, $f02110.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000 -0012316A: move.l #$1, $f02114.l D0=61700080, A0=00124178, D1=00000000, A1=00F04000 -00123174: rts D0=61700080, A0=00124178, D1=00000000, A1=00F04000 -*/ -/* static char buffer[2048]; -//if (m68kPC > 0x805F48) start = true; -//if (m68kPC > 0x806486) start = true; -//if (m68kPC == 0x805FEE) start = true; -//if (m68kPC == 0x80600C)// start = true; -if (m68kPC == 0x802058) start = true; -//{ -// GPUDumpRegisters(); -// GPUDumpDisassembly(); -// -// M68K_show_context(); -// log_done(); -// exit(0); -//} - if (start) - { - m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000); - WriteLog("%08X: %s \t\tD0=%08X, A0=%08X, D1=%08X, A1=%08X\n", m68kPC, buffer, m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_A1)); - }//*/ - -/* if (m68kPC == 0x803F16) - { - WriteLog("M68K: Registers found at $803F16:\n"); - WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC)); - for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++) - WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i)); - WriteLog("\n"); - for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++) - WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i)); - }*/ -//Looks like the DSP is supposed to return $12345678 when it finishes its validation routine... -// !!! Investigate !!! -/*extern bool doDSPDis; - static bool disgo = false; - if (m68kPC == 0x50222) - { - // CD BIOS hacking -// WriteLog("M68K: About to stuff $12345678 into $F1B000 (=%08X)...\n", DSPReadLong(0xF1B000, M68K)); -// DSPWriteLong(0xF1B000, 0x12345678, M68K); -// disgo = true; - } - if (m68kPC == 0x5000) -// doDSPDis = true; - disgo = true; - if (disgo) - { - static char buffer[2048]; - m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000); - WriteLog("%08X: %s", m68kPC, buffer); - WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n", - m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), - m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2)); - }//*/ -/* if (m68kPC == 0x82E1A) - { - static char buffer[2048]; - m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000); - WriteLog("--> [Routine start] %08X: %s", m68kPC, buffer); - WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n", - m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), - m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2)); - }//*/ -/* if (m68kPC == 0x82E58) - WriteLog("--> [Routine end]\n"); - if (m68kPC == 0x80004) - { - WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2)); -// m68k_set_reg(M68K_REG_D2, 0x12345678); - }//*/ - -#ifdef LOG_CD_BIOS_CALLS -/* -CD_init:: -> $3000 -BIOS_VER:: -> $3004 -CD_mode:: -> $3006 -CD_ack:: -> $300C -CD_jeri:: -> $3012 -CD_spin:: -> $3018 -CD_stop:: -> $301E -CD_mute:: -> $3024 -CD_umute:: -> $302A -CD_paus:: -> $3030 -CD_upaus:: -> $3036 -CD_read:: -> $303C -CD_uread:: -> $3042 -CD_setup:: -> $3048 -CD_ptr:: -> $304E -CD_osamp:: -> $3054 -CD_getoc:: -> $305A -CD_initm:: -> $3060 -CD_initf:: -> $3066 -CD_switch:: -> $306C -*/ - if (m68kPC == 0x3000) - WriteLog("M68K: CD_init\n"); - else if (m68kPC == 0x3006 + (6 * 0)) - WriteLog("M68K: CD_mode\n"); - else if (m68kPC == 0x3006 + (6 * 1)) - WriteLog("M68K: CD_ack\n"); - else if (m68kPC == 0x3006 + (6 * 2)) - WriteLog("M68K: CD_jeri\n"); - else if (m68kPC == 0x3006 + (6 * 3)) - WriteLog("M68K: CD_spin\n"); - else if (m68kPC == 0x3006 + (6 * 4)) - WriteLog("M68K: CD_stop\n"); - else if (m68kPC == 0x3006 + (6 * 5)) - WriteLog("M68K: CD_mute\n"); - else if (m68kPC == 0x3006 + (6 * 6)) - WriteLog("M68K: CD_umute\n"); - else if (m68kPC == 0x3006 + (6 * 7)) - WriteLog("M68K: CD_paus\n"); - else if (m68kPC == 0x3006 + (6 * 8)) - WriteLog("M68K: CD_upaus\n"); - else if (m68kPC == 0x3006 + (6 * 9)) - WriteLog("M68K: CD_read\n"); - else if (m68kPC == 0x3006 + (6 * 10)) - WriteLog("M68K: CD_uread\n"); - else if (m68kPC == 0x3006 + (6 * 11)) - WriteLog("M68K: CD_setup\n"); - else if (m68kPC == 0x3006 + (6 * 12)) - WriteLog("M68K: CD_ptr\n"); - else if (m68kPC == 0x3006 + (6 * 13)) - WriteLog("M68K: CD_osamp\n"); - else if (m68kPC == 0x3006 + (6 * 14)) - WriteLog("M68K: CD_getoc\n"); - else if (m68kPC == 0x3006 + (6 * 15)) - WriteLog("M68K: CD_initm\n"); - else if (m68kPC == 0x3006 + (6 * 16)) - WriteLog("M68K: CD_initf\n"); - else if (m68kPC == 0x3006 + (6 * 17)) - WriteLog("M68K: CD_switch\n"); - - if (m68kPC >= 0x3000 && m68kPC <= 0x306C) - WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n", - m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), - m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2)); -#endif - -#ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS - if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), 0))//M68K_CPU_TYPE_68000)) - { -#ifndef ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION - if (m68k_read_memory_16(m68kPC) == 0x4AFC) - { - // This is a kludge to let homebrew programs work properly (i.e., let the other processors - // keep going even when the 68K dumped back to the debugger or what have you). -//dis no wok right! -// m68k_set_reg(M68K_REG_PC, m68kPC - 2); -// Try setting the vector to the illegal instruction... -//This doesn't work right either! Do something else! Quick! -// SET32(jaguar_mainRam, 0x10, m68kPC); - - return; - } -#endif - - WriteLog("\nM68K encountered an illegal instruction at %08X!!!\n\nAborting!\n", m68kPC); - uint32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7); - WriteLog("M68K: Top of stack: %08X. Stack trace:\n", JaguarReadLong(topOfStack)); - uint32_t address = topOfStack - (4 * 4 * 3); - - for(int i=0; i<10; i++) - { - WriteLog("%06X:", address); - - for(int j=0; j<4; j++) - { - WriteLog(" %08X", JaguarReadLong(address)); - address += 4; - } - - WriteLog("\n"); - } - - WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VIDEO)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled"); - M68K_show_context(); - -//temp -// WriteLog("\n\n68K disasm\n\n"); -// jaguar_dasm(0x802000, 0x50C); -// WriteLog("\n\n"); -//endoftemp - - LogDone(); - exit(0); - }//*/ -#endif -} - -#if 0 -Now here be dragons... -Here is how memory ranges are defined in the CoJag driver. -Note that we only have to be concerned with 3 entities read/writing anything: -The main CPU, the GPU, and the DSP. Everything else is unnecessary. So we can keep our main memory -checking in jaguar.cpp, gpu.cpp and dsp.cpp. There should be NO checking in TOM, JERRY, etc. other than -things that are entirely internal to those modules. This way we should be able to get a handle on all -this crap which is currently scattered over Hells Half Acre(tm). - -Also: We need to distinguish whether or not we need .b, .w, and .dw versions of everything, or if there -is a good way to collapse that shit (look below for inspiration). Current method works, but is error prone. - -/************************************* - * - * Main CPU memory handlers - * - *************************************/ - -static ADDRESS_MAP_START( m68020_map, ADDRESS_SPACE_PROGRAM, 32 ) - AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_BASE(&jaguar_shared_ram) AM_SHARE(1) - AM_RANGE(0x800000, 0x9fffff) AM_ROM AM_REGION(REGION_USER1, 0) AM_BASE(&rom_base) - AM_RANGE(0xa00000, 0xa1ffff) AM_RAM - AM_RANGE(0xa20000, 0xa21fff) AM_READWRITE(eeprom_data_r, eeprom_data_w) AM_BASE(&generic_nvram32) AM_SIZE(&generic_nvram_size) - AM_RANGE(0xa30000, 0xa30003) AM_WRITE(watchdog_reset32_w) - AM_RANGE(0xa40000, 0xa40003) AM_WRITE(eeprom_enable_w) - AM_RANGE(0xb70000, 0xb70003) AM_READWRITE(misc_control_r, misc_control_w) - AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(2) - AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w) - AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w) - AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_BASE(&jaguar_gpu_clut) AM_SHARE(2) - AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w) - AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w) - AM_RANGE(0xf03000, 0xf03fff) AM_MIRROR(0x008000) AM_RAM AM_BASE(&jaguar_gpu_ram) AM_SHARE(3) - AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w) - AM_RANGE(0xf16000, 0xf1600b) AM_READ(cojag_gun_input_r) // GPI02 - AM_RANGE(0xf17000, 0xf17003) AM_READ(status_r) // GPI03 -// AM_RANGE(0xf17800, 0xf17803) AM_WRITE(latch_w) // GPI04 - AM_RANGE(0xf17c00, 0xf17c03) AM_READ(jamma_r) // GPI05 - AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w) - AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w) - AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_BASE(&jaguar_dsp_ram) AM_SHARE(4) -ADDRESS_MAP_END - -/************************************* - * - * GPU memory handlers - * - *************************************/ - -static ADDRESS_MAP_START( gpu_map, ADDRESS_SPACE_PROGRAM, 32 ) - AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1) - AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8) - AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9) - AM_RANGE(0xe00000, 0xe003ff) AM_DEVREADWRITE(IDE_CONTROLLER, "ide", ide_controller32_r, ide_controller32_w) - AM_RANGE(0xf00000, 0xf003ff) AM_READWRITE(jaguar_tom_regs32_r, jaguar_tom_regs32_w) - AM_RANGE(0xf00400, 0xf007ff) AM_RAM AM_SHARE(2) - AM_RANGE(0xf02100, 0xf021ff) AM_READWRITE(gpuctrl_r, gpuctrl_w) - AM_RANGE(0xf02200, 0xf022ff) AM_READWRITE(jaguar_blitter_r, jaguar_blitter_w) - AM_RANGE(0xf03000, 0xf03fff) AM_RAM AM_SHARE(3) - AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w) -ADDRESS_MAP_END - -/************************************* - * - * DSP memory handlers - * - *************************************/ - -static ADDRESS_MAP_START( dsp_map, ADDRESS_SPACE_PROGRAM, 32 ) - AM_RANGE(0x000000, 0x7fffff) AM_RAM AM_SHARE(1) - AM_RANGE(0x800000, 0xbfffff) AM_ROMBANK(8) - AM_RANGE(0xc00000, 0xdfffff) AM_ROMBANK(9) - AM_RANGE(0xf10000, 0xf103ff) AM_READWRITE(jaguar_jerry_regs32_r, jaguar_jerry_regs32_w) - AM_RANGE(0xf1a100, 0xf1a13f) AM_READWRITE(dspctrl_r, dspctrl_w) - AM_RANGE(0xf1a140, 0xf1a17f) AM_READWRITE(jaguar_serial_r, jaguar_serial_w) - AM_RANGE(0xf1b000, 0xf1cfff) AM_RAM AM_SHARE(4) - AM_RANGE(0xf1d000, 0xf1dfff) AM_READ(jaguar_wave_rom_r) AM_BASE(&jaguar_wave_rom) -ADDRESS_MAP_END -*/ -#endif - -//#define EXPERIMENTAL_MEMORY_HANDLING -// Experimental memory mappage... -// Dunno if this is a good approach or not, but it seems to make better -// sense to have all this crap in one spot intstead of scattered all over -// the place the way it is now. -#ifdef EXPERIMENTAL_MEMORY_HANDLING -// Needed defines... -#define NEW_TIMER_SYSTEM - -/* -uint8_t jaguarMainRAM[0x400000]; // 68K CPU RAM -uint8_t jaguarMainROM[0x600000]; // 68K CPU ROM -uint8_t jaguarBootROM[0x040000]; // 68K CPU BIOS ROM--uses only half of this! -uint8_t jaguarCDBootROM[0x040000]; // 68K CPU CD BIOS ROM -bool BIOSLoaded = false; -bool CDBIOSLoaded = false; - -uint8_t cdRAM[0x100]; -uint8_t tomRAM[0x4000]; -uint8_t jerryRAM[0x10000]; -static uint16_t eeprom_ram[64]; - -// NOTE: CD BIOS ROM is read from cartridge space @ $802000 (it's a cartridge, after all) -*/ - -enum MemType { MM_NOP = 0, MM_RAM, MM_ROM, MM_IO }; - -// M68K Memory map/handlers -uint32_t { - { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM }, - { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM }, -// Note that this is really memory mapped I/O region... -// { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM }, - { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W - { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W - { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W - { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W - { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W - { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A - { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B - { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24) - { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data - { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old) - { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface - - { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM }, - -// { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW }, - { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler }, - { 0xF00052, 0xF00053, MM_IO, tomTimerDivider }, - { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other... - { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well - //What about LBUF writes??? - { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL - { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER - { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM - - { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW }, - -/* - EEPROM: - { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO } - { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR } - { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ } - - JOYSTICK: - { 0xF14000, 0xF14003, MM_IO, joystickFoo } - 0 = pad0/1 button values (4 bits each), RO(?) - 1 = pad0/1 index value (4 bits each), WO - 2 = unused, RO - 3 = NTSC/PAL, certain button states, RO - -JOYSTICK $F14000 Read/Write - 15.....8 7......0 -Read fedcba98 7654321q f-1 Signals J15 to J1 - q Cartridge EEPROM output data -Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs - 0 = disable J7-J0 outputs - x don't care - m Audio mute - 0 = Audio muted (reset state) - 1 = Audio enabled - 7-4 J7-J4 outputs (port 2) - 3-0 J3-J0 outputs (port 1) -JOYBUTS $F14002 Read Only - 15.....8 7......0 -Read xxxxxxxx rrdv3210 x don't care - r Reserved - d Reserved - v 1 = NTSC Video hardware - 0 = PAL Video hardware - 3-2 Button inputs B3 & B2 (port 2) - 1-0 Button inputs B1 & B0 (port 1) - -J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15 -J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11 - 0 0 0 0 - 0 0 0 1 - 0 0 1 0 - 0 0 1 1 - 0 1 0 0 - 0 1 0 1 - 0 1 1 0 - 0 1 1 1 Row 3 C3 Option # 9 6 3 - 1 0 0 0 - 1 0 0 1 - 1 0 1 0 - 1 0 1 1 Row 2 C2 C 0 8 5 2 - 1 1 0 0 - 1 1 0 1 Row 1 C1 B * 7 4 1 - 1 1 1 0 Row 0 Pause A Up Down Left Right - 1 1 1 1 - -0 bit read in any position means that button is pressed. -C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached. -*/ -}; - -void WriteByte(uint32_t address, uint8_t byte, uint32_t who/*=UNKNOWN*/) -{ - // Not sure, but I think the system only has 24 address bits... - address &= 0x00FFFFFF; - - // RAM ($000000 - $3FFFFF) 4M - if (address <= 0x3FFFFF) - jaguarMainRAM[address] = byte; - // hole ($400000 - $7FFFFF) 4M - else if (address <= 0x7FFFFF) - ; // Do nothing - // GAME ROM ($800000 - $DFFEFF) 6M - 256 bytes - else if (address <= 0xDFFEFF) - ; // Do nothing - // CDROM ($DFFF00 - $DFFFFF) 256 bytes - else if (address <= 0xDFFFFF) - { - cdRAM[address & 0xFF] = byte; -#ifdef CDROM_LOG - if ((address & 0xFF) < 12 * 4) - WriteLog("[%s] ", BReg[(address & 0xFF) / 4]); - WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC)); -#endif - } - // BIOS ROM ($E00000 - $E3FFFF) 256K - else if (address <= 0xE3FFFF) - ; // Do nothing - // hole ($E40000 - $EFFFFF) 768K - else if (address <= 0xEFFFFF) - ; // Do nothing - // TOM ($F00000 - $F0FFFF) 64K - else if (address <= 0xF0FFFF) -// ; // Do nothing - { - if (address == 0xF00050) - { - tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | ((uint16_t)byte << 8); - TOMResetPIT(); - return; - } - else if (address == 0xF00051) - { - tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | byte; - TOMResetPIT(); - return; - } - else if (address == 0xF00052) - { - tomTimerDivider = (tomTimerDivider & 0x00FF) | ((uint16_t)byte << 8); - TOMResetPIT(); - return; - } - else if (address == 0xF00053) - { - tomTimerDivider = (tomTimerDivider & 0xFF00) | byte; - TOMResetPIT(); - return; - } - else if (address >= 0xF00400 && address <= 0xF007FF) // CLUT (A & B) - { - // Writing to one CLUT writes to the other - address &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF) - tomRAM[address] = tomRAM[address + 0x200] = byte; - return; - } - //What about LBUF writes??? - else if ((address >= 0xF02100) && (address <= 0xF0211F)) // GPU CONTROL - { - GPUWriteByte(address, byte, who); - return; - } - else if ((address >= 0xF02200) && (address <= 0xF0229F)) // BLITTER - { - BlitterWriteByte(address, byte, who); - return; - } - else if ((address >= 0xF03000) && (address <= 0xF03FFF)) // GPU RAM - { - GPUWriteByte(address, byte, who); - return; - } - - tomRAM[address & 0x3FFF] = byte; - } - // JERRY ($F10000 - $F1FFFF) 64K - else if (address <= 0xF1FFFF) -// ; // Do nothing - { -#ifdef JERRY_DEBUG - WriteLog("jerry: writing byte %.2x at 0x%.6x\n", byte, address); -#endif - if ((address >= DSP_CONTROL_RAM_BASE) && (address < DSP_CONTROL_RAM_BASE+0x20)) - { - DSPWriteByte(address, byte, who); - return; - } - else if ((address >= DSP_WORK_RAM_BASE) && (address < DSP_WORK_RAM_BASE+0x2000)) - { - DSPWriteByte(address, byte, who); - return; - } - // SCLK ($F1A150--8 bits wide) -//NOTE: This should be taken care of in DAC... - else if ((address >= 0xF1A152) && (address <= 0xF1A153)) - { -// WriteLog("JERRY: Writing %02X to SCLK...\n", data); - if ((address & 0x03) == 2) - JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0x00FF) | ((uint32_t)byte << 8); - else - JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32_t)byte; - - JERRYI2SInterruptTimer = -1; -#ifndef NEW_TIMER_SYSTEM - jerry_i2s_exec(0); -#else - RemoveCallback(JERRYI2SCallback); - JERRYI2SCallback(); -#endif -// return; - } - // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...) - else if (address >= 0xF1A148 && address <= 0xF1A157) - { - DACWriteByte(address, byte, who); - return; - } - else if (address >= 0xF10000 && address <= 0xF10007) - { -#ifndef NEW_TIMER_SYSTEM - switch (address & 0x07) - { - case 0: - JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (byte << 8); - JERRYResetPIT1(); - break; - case 1: - JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | byte; - JERRYResetPIT1(); - break; - case 2: - JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (byte << 8); - JERRYResetPIT1(); - break; - case 3: - JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | byte; - JERRYResetPIT1(); - break; - case 4: - JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (byte << 8); - JERRYResetPIT2(); - break; - case 5: - JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | byte; - JERRYResetPIT2(); - break; - case 6: - JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (byte << 8); - JERRYResetPIT2(); - break; - case 7: - JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | byte; - JERRYResetPIT2(); - } -#else -WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", address); -#endif - return; - } -/* else if ((offset >= 0xF10010) && (offset <= 0xF10015)) - { - clock_byte_write(offset, byte); - return; - }//*/ - // JERRY -> 68K interrupt enables/latches (need to be handled!) - else if (address >= 0xF10020 && address <= 0xF10023) - { -WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", byte, address); - } -/* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01)) - { - anajoy_byte_write(offset, byte); - return; - }*/ - else if ((address >= 0xF14000) && (address <= 0xF14003)) - { - JoystickWriteByte(address, byte); - EepromWriteByte(address, byte); - return; - } - else if ((address >= 0xF14004) && (address <= 0xF1A0FF)) - { - EepromWriteByte(address, byte); - return; - } -//Need to protect write attempts to Wavetable ROM (F1D000-FFF) - else if (address >= 0xF1D000 && address <= 0xF1DFFF) - return; - - jerryRAM[address & 0xFFFF] = byte; - } - // hole ($F20000 - $FFFFFF) 1M - 128K - else - ; // Do nothing -} - - -void WriteWord(uint32_t adddress, uint16_t word) -{ -} - - -void WriteDWord(uint32_t adddress, uint32_t dword) -{ -} - - -uint8_t ReadByte(uint32_t adddress) -{ -} - - -uint16_t ReadWord(uint32_t adddress) -{ -} - - -uint32_t ReadDWord(uint32_t adddress) -{ -} -#endif - - -void ShowM68KContext(void) -{ - printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC)); - - for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++) - { - printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i)); - - if (i == M68K_REG_D3 || i == M68K_REG_D7) - printf("\n"); - } - - for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++) - { - printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i)); - - if (i == M68K_REG_A3 || i == M68K_REG_A7) - printf("\n"); - } - - uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC); - uint32_t disPC = currpc - 30; - char buffer[128]; - - do - { - uint32_t oldpc = disPC; - disPC += m68k_disassemble(buffer, disPC, 0); - printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer); - } - while (disPC < (currpc + 10)); -} - // // Custom UAE 68000 read/write/IRQ functions // -#if 0 -IRQs: -=-=-= - - IPL Name Vector Control - ---------+---------------+---------------+--------------- - 2 VBLANK IRQ $100 INT1 bit #0 - 2 GPU IRQ $100 INT1 bit #1 - 2 HBLANK IRQ $100 INT1 bit #2 - 2 Timer IRQ $100 INT1 bit #3 - - Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit. - and are therefore indistinguishable. - - A typical way to install a LEVEL2 handler for the 68000 would be - something like this, you gotta supply "last_line" and "handler". - Note that the interrupt is auto vectored thru $100 (not $68) - - - V_AUTO = $100 - VI = $F004E - INT1 = $F00E0 - INT2 = $F00E2 - - IRQS_HANDLED=$909 ;; VBLANK and TIMER - - move.w #$2700,sr ;; no IRQs please - move.l #handler,V_AUTO ;; install our routine - - move.w #last_line,VI ;; scanline where IRQ should occur - ;; should be 'odd' BTW - move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER - move.w #$2100,sr ;; enable IRQs on the 68K - ... - -handler: - move.w d0,-(a7) - move.w INT1,d0 - btst.b #0,d0 - bne.b .no_blank - - ... - -.no_blank: - btst.b #3,d0 - beq.b .no_timer - - ... - -.no_timer: - move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive - move.w #0,INT2 ; let GPU run again - move.w (a7)+,d0 - rte - - As you can see, if you have multiple INT1 interrupts coming in, - you need to check the lower byte of INT1, to see which interrupt - happened. -#endif int irq_ack_handler(int level) { -#ifdef CPU_DEBUG_TRACING - if (startM68KTracing) - { - WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC)); - } -#endif - - // Tracing the IPL lines on the Jaguar schematic yields the following: - // IPL1 is connected to INTL on TOM (OUT to 68K) - // IPL0-2 are also tied to Vcc via 4.7K resistors! - // (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry)) - // There doesn't seem to be any other path to IPL0 or 2 on the schematic, - // which means that *all* IRQs to the 68K are routed thru TOM at level 2. - // Which means they're all maskable. - - // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work - // OK... - // They aren't, and this causes problems with a, err, specific ROM. :-D - if (level == 2) { - m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)... - return 64; // Set user interrupt #0 + m68k_set_irq(0); + return 64; } return M68K_INT_ACK_AUTOVECTOR; } - -//#define USE_NEW_MMU - unsigned int m68k_read_memory_8(unsigned int address) { -#ifdef ALPINE_FUNCTIONS - // Check if breakpoint on memory is active, and deal with it - if (bpmActive && address == bpmAddress1) - M68KDebugHalt(); -#endif - - // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; -#ifdef CPU_DEBUG_MEMORY - // Note that the Jaguar only has 2M of RAM, not 4! - if ((address >= 0x000000) && (address <= 0x1FFFFF)) - { - if (startMemLog) - readMem[address] = 1; - } -#endif -//WriteLog("[RM8] Addr: %08X\n", address); -//; So, it seems that it stores the returned DWORD at $51136 and $FB074. -/* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076 - || address == 0x1AF05E) - WriteLog("[RM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, jaguar_mainRam[address]);//*/ -#ifndef USE_NEW_MMU + unsigned int retVal = 0; - // Note that the Jaguar only has 2M of RAM, not 4! if ((address >= 0x000000) && (address <= 0x1FFFFF)) retVal = jaguarMainRAM[address]; -// else if ((address >= 0x800000) && (address <= 0xDFFFFF)) else if ((address >= 0x800000) && (address <= 0xDFFEFF)) retVal = jaguarMainROM[address - 0x800000]; else if ((address >= 0xE00000) && (address <= 0xE3FFFF)) -// retVal = jaguarBootROM[address - 0xE00000]; -// retVal = jaguarDevBootROM1[address - 0xE00000]; retVal = jagMemSpace[address]; else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF)) retVal = CDROMReadByte(address); @@ -1070,101 +92,19 @@ unsigned int m68k_read_memory_8(unsigned int address) else retVal = jaguar_unknown_readbyte(address, M68K); -//if (address >= 0x2800 && address <= 0x281F) -// WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC)); -//if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16) -// WriteLog("M68K: Read byte $%02X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC)); return retVal; -#else - return MMURead8(address, M68K); -#endif } - -void gpu_dump_disassembly(void); -void gpu_dump_registers(void); - unsigned int m68k_read_memory_16(unsigned int address) { -#ifdef ALPINE_FUNCTIONS - // Check if breakpoint on memory is active, and deal with it - if (bpmActive && address == bpmAddress1) - M68KDebugHalt(); -#endif - - // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; -#ifdef CPU_DEBUG_MEMORY -/* if ((address >= 0x000000) && (address <= 0x3FFFFE)) - { - if (startMemLog) - readMem[address] = 1, readMem[address + 1] = 1; - }//*/ -/* if (effect_start && (address >= 0x8064FC && address <= 0x806501)) - { - return 0x4E71; // NOP - } - if (effect_start2 && (address >= 0x806502 && address <= 0x806507)) - { - return 0x4E71; // NOP - } - if (effect_start3 && (address >= 0x806512 && address <= 0x806517)) - { - return 0x4E71; // NOP - } - if (effect_start4 && (address >= 0x806524 && address <= 0x806527)) - { - return 0x4E71; // NOP - } - if (effect_start5 && (address >= 0x80653E && address <= 0x806543)) //Collision detection! - { - return 0x4E71; // NOP - } - if (effect_start6 && (address >= 0x806544 && address <= 0x806547)) - { - return 0x4E71; // NOP - }//*/ -#endif -//WriteLog("[RM16] Addr: %08X\n", address); -/*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005FBA) -// for(int i=0; i<10000; i++) - WriteLog("[M68K] In routine #6!\n");//*/ -//if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00006696) // GPU Program #4 -//if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005B3C) // GPU Program #2 -/*if (m68k_get_reg(NULL, M68K_REG_PC) == 0x00005BA8) // GPU Program #3 -{ - WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address)); - gpu_dump_registers(); - gpu_dump_disassembly(); -// for(int i=0; i<10000; i++) -// WriteLog("[M68K] About to run GPU!\n"); -}//*/ -//WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value); -/*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x00006696 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x000066A8) -{ - if (address == 0x000066A0) - { - gpu_dump_registers(); - gpu_dump_disassembly(); - } - for(int i=0; i<10000; i++) - WriteLog("[M68K] About to run GPU! (Addr:%08X, data:%04X)\n", address, TOMReadWord(address)); -}//*/ -//; So, it seems that it stores the returned DWORD at $51136 and $FB074. -/* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076 - || address == 0x1AF05E) - WriteLog("[RM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, GET16(jaguar_mainRam, address));//*/ -#ifndef USE_NEW_MMU + unsigned int retVal = 0; - // Note that the Jaguar only has 2M of RAM, not 4! if ((address >= 0x000000) && (address <= 0x1FFFFE)) -// retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1]; retVal = GET16(jaguarMainRAM, address); -// else if ((address >= 0x800000) && (address <= 0xDFFFFE)) else if ((address >= 0x800000) && (address <= 0xDFFEFE)) { - // Memory Track reading... if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47)) { retVal = MTReadWord(address); @@ -1174,8 +114,6 @@ unsigned int m68k_read_memory_16(unsigned int address) | jaguarMainROM[address - 0x800000 + 1]; } else if ((address >= 0xE00000) && (address <= 0xE3FFFE)) -// retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1]; -// retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1]; retVal = (jagMemSpace[address] << 8) | jagMemSpace[address + 1]; else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE)) retVal = CDROMReadWord(address, M68K); @@ -1186,42 +124,17 @@ unsigned int m68k_read_memory_16(unsigned int address) else retVal = jaguar_unknown_readword(address, M68K); -//if (address >= 0xF1B000 && address <= 0xF1CFFF) -// WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC)); -//if (address >= 0x2800 && address <= 0x281F) -// WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC)); -//$8B3AE -> Transferred from $F1C010 -//$8B5E4 -> Only +1 read at $808AA -//if (address >= 0x8B5E4 && address <= 0x8B5E4 + 16) -// WriteLog("M68K: Read word $%04X at $%08X [PC=%08X]\n", retVal, address, m68k_get_reg(NULL, M68K_REG_PC)); return retVal; -#else - return MMURead16(address, M68K); -#endif } - unsigned int m68k_read_memory_32(unsigned int address) { -#ifdef ALPINE_FUNCTIONS - // Check if breakpoint on memory is active, and deal with it - if (bpmActive && address == bpmAddress1) - M68KDebugHalt(); -#endif - - // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; -//; So, it seems that it stores the returned DWORD at $51136 and $FB074. -/* if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E) - WriteLog("[RM32 PC=%08X] Addr: %08X, val: %08X\n", m68k_get_reg(NULL, M68K_REG_PC), address, (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2));//*/ -//WriteLog("--> [RM32]\n"); -#ifndef USE_NEW_MMU uint32_t retVal = 0; if ((address >= 0x800000) && (address <= 0xDFFEFE)) { - // Memory Track reading... if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47)) retVal = MTReadLong(address); else @@ -1231,53 +144,12 @@ unsigned int m68k_read_memory_32(unsigned int address) } return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2); -#else - return MMURead32(address, M68K); -#endif } - void m68k_write_memory_8(unsigned int address, unsigned int value) { -#ifdef ALPINE_FUNCTIONS - // Check if breakpoint on memory is active, and deal with it - if (bpmActive && address == bpmAddress1) - M68KDebugHalt(); -#endif - - // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; -#ifdef CPU_DEBUG_MEMORY - // Note that the Jaguar only has 2M of RAM, not 4! - if ((address >= 0x000000) && (address <= 0x1FFFFF)) - { - if (startMemLog) - { - if (value > writeMemMax[address]) - writeMemMax[address] = value; - if (value < writeMemMin[address]) - writeMemMin[address] = value; - } - } -#endif -/*if (address == 0x4E00) - WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/ -//if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F)) -// WriteLog("M68K: Writing %02X at %08X\n", value, address); -//WriteLog("[WM8 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value); -/*if (effect_start) - if (address >= 0x18FA70 && address < (0x18FA70 + 8000)) - WriteLog("M68K: Byte %02X written at %08X by 68K\n", value, address);//*/ -//$53D0 -/*if (address >= 0x53D0 && address <= 0x53FF) - printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/ -//Testing AvP on UAE core... -//000075A0: FFFFF80E B6320220 (BITMAP) -/*if (address == 0x75A0 && value == 0xFF) - printf("M68K: (8) Tripwire hit...\n");//*/ -#ifndef USE_NEW_MMU - // Note that the Jaguar only has 2M of RAM, not 4! if ((address >= 0x000000) && (address <= 0x1FFFFF)) jaguarMainRAM[address] = value; else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF)) @@ -1288,87 +160,16 @@ void m68k_write_memory_8(unsigned int address, unsigned int value) JERRYWriteByte(address, value, M68K); else jaguar_unknown_writebyte(address, value, M68K); -#else - MMUWrite8(address, value, M68K); -#endif } - void m68k_write_memory_16(unsigned int address, unsigned int value) { -#ifdef ALPINE_FUNCTIONS - // Check if breakpoint on memory is active, and deal with it - if (bpmActive && address == bpmAddress1) - M68KDebugHalt(); -#endif - - // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; -#ifdef CPU_DEBUG_MEMORY - // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFE)) { - if (startMemLog) - { - uint8_t hi = value >> 8, lo = value & 0xFF; - - if (hi > writeMemMax[address]) - writeMemMax[address] = hi; - if (hi < writeMemMin[address]) - writeMemMin[address] = hi; - - if (lo > writeMemMax[address+1]) - writeMemMax[address+1] = lo; - if (lo < writeMemMin[address+1]) - writeMemMin[address+1] = lo; - } - } -#endif -/*if (address == 0x4E00) - WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/ -//if ((address >= 0x1FF020 && address <= 0x1FF03F) || (address >= 0x1FF820 && address <= 0x1FF83F)) -// WriteLog("M68K: Writing %04X at %08X\n", value, address); -//WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value); -//if (address >= 0xF02200 && address <= 0xF0229F) -// WriteLog("M68K: Writing to blitter --> %04X at %08X\n", value, address); -//if (address >= 0x0E75D0 && address <= 0x0E75E7) -// WriteLog("M68K: Writing %04X at %08X, M68K PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC)); -/*extern uint32_t totalFrames; -if (address == 0xF02114) - WriteLog("M68K: Writing to GPU_CTRL (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC)); -if (address == 0xF02110) - WriteLog("M68K: Writing to GPU_PC (frame:%u)... [M68K PC:%08X]\n", totalFrames, m68k_get_reg(NULL, M68K_REG_PC));//*/ -//if (address >= 0xF03B00 && address <= 0xF03DFF) -// WriteLog("M68K: Writing %04X to %08X...\n", value, address); - -/*if (address == 0x0100)//64*4) - WriteLog("M68K: Wrote word to VI vector value %04X...\n", value);//*/ -/*if (effect_start) - if (address >= 0x18FA70 && address < (0x18FA70 + 8000)) - WriteLog("M68K: Word %04X written at %08X by 68K\n", value, address);//*/ -/* if (address == 0x51136 || address == 0x51138 || address == 0xFB074 || address == 0xFB076 - || address == 0x1AF05E) - WriteLog("[WM16 PC=%08X] Addr: %08X, val: %04X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/ -//$53D0 -/*if (address >= 0x53D0 && address <= 0x53FF) - printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/ -//Testing AvP on UAE core... -//000075A0: FFFFF80E B6320220 (BITMAP) -/*if (address == 0x75A0 && value == 0xFFFF) -{ - printf("\nM68K: (16) Tripwire hit...\n"); - ShowM68KContext(); -}//*/ - -#ifndef USE_NEW_MMU - // Note that the Jaguar only has 2M of RAM, not 4! - if ((address >= 0x000000) && (address <= 0x1FFFFE)) - { -/* jaguar_mainRam[address] = value >> 8; - jaguar_mainRam[address + 1] = value & 0xFF;*/ SET16(jaguarMainRAM, address, value); } - // Memory Track device writes.... else if ((address >= 0x800000) && (address <= 0x87FFFE)) { if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47)) @@ -1383,209 +184,44 @@ if (address == 0xF02110) else { jaguar_unknown_writeword(address, value, M68K); -#ifdef LOG_UNMAPPED_MEMORY_ACCESSES - WriteLog("\tA0=%08X, A1=%08X, D0=%08X, D1=%08X\n", - m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), - m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1)); -#endif } -#else - MMUWrite16(address, value, M68K); -#endif } - void m68k_write_memory_32(unsigned int address, unsigned int value) { -#ifdef ALPINE_FUNCTIONS - // Check if breakpoint on memory is active, and deal with it - if (bpmActive && address == bpmAddress1) - M68KDebugHalt(); -#endif - - // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; -/*if (address == 0x4E00) - WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/ -//WriteLog("--> [WM32]\n"); -/*if (address == 0x0100)//64*4) - WriteLog("M68K: Wrote dword to VI vector value %08X...\n", value);//*/ -/*if (address >= 0xF03214 && address < 0xF0321F) - WriteLog("M68K: Writing DWORD (%08X) to GPU RAM (%08X)...\n", value, address);//*/ -//M68K: Writing DWORD (88E30047) to GPU RAM (00F03214)... -/*extern bool doGPUDis; -if (address == 0xF03214 && value == 0x88E30047) -// start = true; - doGPUDis = true;//*/ -/* if (address == 0x51136 || address == 0xFB074) - WriteLog("[WM32 PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/ -//Testing AvP on UAE core... -//000075A0: FFFFF80E B6320220 (BITMAP) -/*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000) -{ - printf("\nM68K: (32) Tripwire hit...\n"); - ShowM68KContext(); -}//*/ -#ifndef USE_NEW_MMU m68k_write_memory_16(address, value >> 16); m68k_write_memory_16(address + 2, value & 0xFFFF); -#else - MMUWrite32(address, value, M68K); -#endif } - uint32_t JaguarGetHandler(uint32_t i) { return JaguarReadLong(i * 4); } - -bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only... -{ - uint32_t handler = JaguarGetHandler(i); - return (handler && (handler != 0xFFFFFFFF) ? true : false); -} - - -void M68K_show_context(void) -{ - WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC)); - - for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++) - { - WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i)); - - if (i == M68K_REG_D3 || i == M68K_REG_D7) - WriteLog("\n"); - } - - for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++) - { - WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i)); - - if (i == M68K_REG_A3 || i == M68K_REG_A7) - WriteLog("\n"); - } - - WriteLog("68K disasm\n"); -// jaguar_dasm(s68000readPC()-0x1000,0x20000); - JaguarDasm(m68k_get_reg(NULL, M68K_REG_PC) - 0x80, 0x200); -// jaguar_dasm(0x5000, 0x14414); - -// WriteLog("\n.......[Cart start]...........\n\n"); -// jaguar_dasm(0x192000, 0x1000);//0x200); - - WriteLog("..................\n"); - - if (TOMIRQEnabled(IRQ_VIDEO)) - { - WriteLog("video int: enabled\n"); - JaguarDasm(JaguarGetHandler(64), 0x200); - } - else - WriteLog("video int: disabled\n"); - - WriteLog("..................\n"); - - for(int i=0; i<256; i++) - { - WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i)); - uint32_t address = (uint32_t)JaguarGetHandler(i); - - if (address == 0) - WriteLog(".........\n"); - else - WriteLog("$%08X\n", address); - } -} - - // // Unknown read/write byte/word routines // -// It's hard to believe that developers would be sloppy with their memory -// writes, yet in some cases the developers screwed up royal. E.g., Club Drive -// has the following code: -// -// 807EC4: movea.l #$f1b000, A1 -// 807ECA: movea.l #$8129e0, A0 -// 807ED0: move.l A0, D0 -// 807ED2: move.l #$f1bb94, D1 -// 807ED8: sub.l D0, D1 -// 807EDA: lsr.l #2, D1 -// 807EDC: move.l (A0)+, (A1)+ -// 807EDE: dbra D1, 807edc -// -// The problem is at $807ED0--instead of putting A0 into D0, they really meant -// to put A1 in. This mistake causes it to try and overwrite approximately -// $700000 worth of address space! (That is, unless the 68K causes a bus -// error...) - -void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/) +void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who) { -#ifdef LOG_UNMAPPED_MEMORY_ACCESSES - WriteLog("Jaguar: Unknown byte %02X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC)); -#endif -#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS -// extern bool finished; - finished = true; -// extern bool doDSPDis; - if (who == DSP) - doDSPDis = true; -#endif } - -void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/) +void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who) { -#ifdef LOG_UNMAPPED_MEMORY_ACCESSES - WriteLog("Jaguar: Unknown word %04X written at %08X by %s (M68K PC=%06X)\n", data, address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC)); -#endif -#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS -// extern bool finished; - finished = true; -// extern bool doDSPDis; - if (who == DSP) - doDSPDis = true; -#endif } - -unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/) +unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who) { -#ifdef LOG_UNMAPPED_MEMORY_ACCESSES - WriteLog("Jaguar: Unknown byte read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC)); -#endif -#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS -// extern bool finished; - finished = true; -// extern bool doDSPDis; - if (who == DSP) - doDSPDis = true; -#endif return 0xFF; } - -unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/) +unsigned jaguar_unknown_readword(unsigned address, uint32_t who) { -#ifdef LOG_UNMAPPED_MEMORY_ACCESSES - WriteLog("Jaguar: Unknown word read at %08X by %s (M68K PC=%06X)\n", address, whoName[who], m68k_get_reg(NULL, M68K_REG_PC)); -#endif -#ifdef ABORT_ON_UNMAPPED_MEMORY_ACCESS -// extern bool finished; - finished = true; -// extern bool doDSPDis; - if (who == DSP) - doDSPDis = true; -#endif return 0xFFFF; } - // // Disassemble M68K instructions at the given offset // @@ -1595,47 +231,21 @@ unsigned int m68k_read_disassembler_8(unsigned int address) return m68k_read_memory_8(address); } - unsigned int m68k_read_disassembler_16(unsigned int address) { return m68k_read_memory_16(address); } - unsigned int m68k_read_disassembler_32(unsigned int address) { return m68k_read_memory_32(address); } - -void JaguarDasm(uint32_t offset, uint32_t qt) -{ -#ifdef CPU_DEBUG - static char buffer[2048];//, mem[64]; - int pc = offset, oldpc; - - for(uint32_t i=0; i= 0x800000) && (offset < 0xDFFF00)) @@ -1643,8 +253,6 @@ uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF)) data = CDROMReadByte(offset, who); else if ((offset >= 0xE00000) && (offset < 0xE40000)) -// data = jaguarBootROM[offset & 0x3FFFF]; -// data = jaguarDevBootROM1[offset & 0x3FFFF]; data = jagMemSpace[offset]; else if ((offset >= 0xF00000) && (offset < 0xF10000)) data = TOMReadByte(offset, who); @@ -1656,12 +264,10 @@ uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) return data; } - -uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint16_t JaguarReadWord(uint32_t offset, uint32_t who) { offset &= 0xFFFFFF; - // First 2M is mirrored in the $0 - $7FFFFF range if (offset < 0x800000) { return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF]; @@ -1671,12 +277,9 @@ uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) offset -= 0x800000; return (jaguarMainROM[offset+0] << 8) | jaguarMainROM[offset+1]; } -// else if ((offset >= 0xDFFF00) && (offset < 0xDFFF00)) else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFE)) return CDROMReadWord(offset, who); else if ((offset >= 0xE00000) && (offset <= 0xE3FFFE)) -// return (jaguarBootROM[(offset+0) & 0x3FFFF] << 8) | jaguarBootROM[(offset+1) & 0x3FFFF]; -// return (jaguarDevBootROM1[(offset+0) & 0x3FFFF] << 8) | jaguarDevBootROM1[(offset+1) & 0x3FFFF]; return (jagMemSpace[offset + 0] << 8) | jagMemSpace[offset + 1]; else if ((offset >= 0xF00000) && (offset <= 0xF0FFFE)) return TOMReadWord(offset, who); @@ -1686,23 +289,10 @@ uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) return jaguar_unknown_readword(offset, who); } - -void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) +void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who) { -/* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18) - { - WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]); - }//*/ -/* if (offset >= 0x4E00 && offset < 0x4E04) - WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/ -//Need to check for writes in the range of $18FA70 + 8000... -/*if (effect_start) - if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000)) - WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/ - offset &= 0xFFFFFF; - // First 2M is mirrored in the $0 - $7FFFFF range if (offset < 0x800000) { jaguarMainRAM[offset & 0x1FFFFF] = data; @@ -1727,121 +317,12 @@ void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) jaguar_unknown_writebyte(offset, data, who); } - -uint32_t starCount; -void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) +void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who) { -/* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18) - { - WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]); - WriteLog(" GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG)); - }//*/ -/* if (offset >= 0x4E00 && offset < 0x4E04) - WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/ -/*if (offset == 0x0100)//64*4) - WriteLog("M68K: %s wrote word to VI vector value %04X...\n", whoName[who], data); -if (offset == 0x0102)//64*4) - WriteLog("M68K: %s wrote word to VI vector+2 value %04X...\n", whoName[who], data);//*/ -//TEMP--Mirror of F03000? Yes, but only 32-bit CPUs can do it (i.e., NOT the 68K!) -// PLUS, you would handle this in the GPU/DSP WriteLong code! Not here! -//Need to check for writes in the range of $18FA70 + 8000... -/*if (effect_start) - if (offset >= 0x18FA70 && offset < (0x18FA70 + 8000)) - WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/ -/*if (offset >= 0x2C00 && offset <= 0x2CFF) - WriteLog("Jaguar: Word %04X written to TOC+%02X by %s\n", data, offset-0x2C00, whoName[who]);//*/ - offset &= 0xFFFFFF; - // First 2M is mirrored in the $0 - $7FFFFF range if (offset <= 0x7FFFFE) { -/* -GPU Table (CD BIOS) - -1A 69 F0 ($0000) -> Starfield -1A 73 C8 ($0001) -> Final clearing blit & bitmap blit? -1A 79 F0 ($0002) -1A 88 C0 ($0003) -1A 8F E8 ($0004) -> "Jaguar" small color logo? -1A 95 20 ($0005) -1A 9F 08 ($0006) -1A A1 38 ($0007) -1A AB 38 ($0008) -1A B3 C8 ($0009) -1A B9 C0 ($000A) -*/ - -//This MUST be done by the 68K! -/*if (offset == 0x670C) - WriteLog("Jaguar: %s writing to location $670C...\n", whoName[who]);*/ - -/*extern bool doGPUDis; -//if ((offset == 0x100000 + 75522) && who == GPU) // 76,226 -> 75522 -if ((offset == 0x100000 + 128470) && who == GPU) // 107,167 -> 128470 (384 x 250 screen size 16BPP) -//if ((offset >= 0x100000 && offset <= 0x12C087) && who == GPU) - doGPUDis = true;//*/ -/*if (offset == 0x100000 + 128470) // 107,167 -> 128470 (384 x 250 screen size 16BPP) - WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]); -if ((data & 0xFF00) != 0x7700) - WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/ -/*if ((offset >= 0x100000 && offset <= 0x147FFF) && who == GPU) - return;//*/ -/*if ((data & 0xFF00) != 0x7700 && who == GPU) - WriteLog("JWW: Writing value %04X at %08X by %s...\n", data, offset, whoName[who]);//*/ -/*if ((offset >= 0x100000 + 0x48000 && offset <= 0x12C087 + 0x48000) && who == GPU) - return;//*/ -/*extern bool doGPUDis; -if (offset == 0x120216 && who == GPU) - doGPUDis = true;//*/ -/*extern uint32_t gpu_pc; -if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638)) -{ - uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000); - uint32_t y = base / 0x300; - uint32_t x = (base - (y * 0x300)) / 2; - WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L")); -}//*/ -/* -JWW: Writing starfield star 775E at 0011F650 (555984/1447) -*/ -//if (offset == (0x001E17F8 + 0x34)) -/*if (who == GPU && offset == (0x001E17F8 + 0x34)) - data = 0xFE3C;//*/ -// WriteLog("JWW: Write at %08X written to by %s.\n", 0x001E17F8 + 0x34, whoName[who]);//*/ -/*extern uint32_t gpu_pc; -if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638)) -{ - extern int objectPtr; -// if (offset > 0x148000) -// return; - starCount++; - if (starCount > objectPtr) - return; - -// if (starCount == 1) -// WriteLog("--> Drawing 1st star...\n"); -// -// uint32_t base = offset - (offset > 0x148000 ? 0x148000 : 0x100000); -// uint32_t y = base / 0x300; -// uint32_t x = (base - (y * 0x300)) / 2; -// WriteLog("JWW: Writing starfield star %04X at %08X (%u/%u) [%s]\n", data, offset, x, y, (gpu_pc == 0xF03604 ? "s" : "L")); - -//A star of interest... -//-->JWW: Writing starfield star 77C9 at 0011D31A (269/155) [s] -//1st trail +3(x), -1(y) -> 272, 154 -> 0011D020 -//JWW: Blitter writing echo 77B3 at 0011D022... -}//*/ -//extern bool doGPUDis; -/*if (offset == 0x11D022 + 0x48000 || offset == 0x11D022)// && who == GPU) -{ -// doGPUDis = true; - WriteLog("JWW: %s writing echo %04X at %08X...\n", whoName[who], data, offset); -// LogBlit(); -} -if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A) - WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/ - jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8; jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF; return; @@ -1861,82 +342,47 @@ if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A) JERRYWriteWord(offset, data, who); return; } - // Don't bomb on attempts to write to ROM else if (offset >= 0x800000 && offset <= 0xEFFFFF) return; jaguar_unknown_writeword(offset, data, who); } - -// We really should re-do this so that it does *real* 32-bit access... !!! FIX !!! -uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint32_t JaguarReadLong(uint32_t offset, uint32_t who) { return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who); } - -// We really should re-do this so that it does *real* 32-bit access... !!! FIX !!! -void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/) +void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who) { -/* extern bool doDSPDis; - if (offset < 0x400 && !doDSPDis) - { - WriteLog("JLW: Write to %08X by %s... Starting DSP log!\n\n", offset, whoName[who]); - doDSPDis = true; - }//*/ -/*if (offset == 0x0100)//64*4) - WriteLog("M68K: %s wrote dword to VI vector value %08X...\n", whoName[who], data);//*/ - JaguarWriteWord(offset, data >> 16, who); JaguarWriteWord(offset+2, data & 0xFFFF, who); } - void JaguarSetScreenBuffer(uint32_t * buffer) { - // This is in TOM, but we set it here... screenBuffer = buffer; } - void JaguarSetScreenPitch(uint32_t pitch) { - // This is in TOM, but we set it here... screenPitch = pitch; } - // // Jaguar console initialization // void JaguarInit(void) { - // For randomizing RAM srand(time(NULL)); - // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents for(uint32_t i=0; i<0x200000; i+=4) *((uint32_t *)(&jaguarMainRAM[i])) = rand(); -#ifdef CPU_DEBUG_MEMORY - memset(readMem, 0x00, 0x400000); - memset(writeMemMin, 0xFF, 0x400000); - memset(writeMemMax, 0x00, 0x400000); -#endif -// memset(jaguarMainRAM, 0x00, 0x200000); -// memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs... -// memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s... -//NOTE: This *doesn't* fix FlipOut... -//Or does it? Hmm... -//Seems to want $01010101... Dunno why. Investigate! -// memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s... -// memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs... - lowerField = false; // Reset the lower field flag -//temp, for crappy crap that sux -memset(jaguarMainRAM + 0x804, 0xFF, 4); + lowerField = false; + memset(jaguarMainRAM + 0x804, 0xFF, 4); - m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit + m68k_pulse_reset(); GPUInit(); DSPInit(); TOMInit(); @@ -1944,211 +390,41 @@ memset(jaguarMainRAM + 0x804, 0xFF, 4); CDROMInit(); } - -//New timer based code stuffola... void HalflineCallback(void); void RenderCallback(void); + void JaguarReset(void) { - // Only problem with this approach: It wipes out RAM loaded files...! - // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents for(uint32_t i=8; i<0x200000; i+=4) *((uint32_t *)(&jaguarMainRAM[i])) = rand(); - // New timer base code stuffola... InitializeEventList(); -//Need to change this so it uses the single RAM space and load the BIOS -//into it somewhere... -//Also, have to change this here and in JaguarReadXX() currently - // Only use the system BIOS if it's available...! (it's always available now!) - // AND only if a jaguar cartridge has been inserted. + if (vjs.useJaguarBIOS && jaguarCartInserted && !vjs.hardwareTypeAlpine) memcpy(jaguarMainRAM, jagMemSpace + 0xE00000, 8); else SET32(jaguarMainRAM, 4, jaguarRunAddress); -// WriteLog("jaguar_reset():\n"); TOMReset(); JERRYReset(); GPUReset(); DSPReset(); CDROMReset(); - m68k_pulse_reset(); // Reset the 68000 - WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7)); + m68k_pulse_reset(); - lowerField = false; // Reset the lower field flag -// SetCallbackTime(ScanlineCallback, 63.5555); -// SetCallbackTime(ScanlineCallback, 31.77775); + lowerField = false; SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0)); } - void JaguarDone(void) { -#ifdef CPU_DEBUG_MEMORY -/* WriteLog("\nJaguar: Memory Usage Stats (return addresses)\n\n"); - - for(uint32_t i=0; i<=raPtr; i++) - { - WriteLog("\t%08X\n", returnAddr[i]); - WriteLog("M68000 disassembly at $%08X...\n", returnAddr[i] - 16); - jaguar_dasm(returnAddr[i] - 16, 16); - WriteLog("\n"); - } - WriteLog("\n");//*/ - -/* int start = 0, end = 0; - bool endTriggered = false, startTriggered = false; - for(int i=0; i<0x400000; i++) - { - if (readMem[i] && writeMemMin[i] != 0xFF && writeMemMax != 0x00) - { - if (!startTriggered) - startTriggered = true, endTriggered = false, start = i; - - WriteLog("\t\tMin/Max @ %06X: %u/%u\n", i, writeMemMin[i], writeMemMax[i]); - } - else - { - if (!endTriggered) - { - end = i - 1, endTriggered = true, startTriggered = false; - WriteLog("\tMemory range accessed: %06X - %06X\n", start, end); - } - } - } - WriteLog("\n");//*/ -#endif -//#ifdef CPU_DEBUG -// for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++) -// WriteLog("\tA%i = 0x%.8x\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i)); - int32_t topOfStack = m68k_get_reg(NULL, M68K_REG_A7); - WriteLog("M68K: Top of stack: %08X -> (%08X). Stack trace:\n", topOfStack, JaguarReadLong(topOfStack)); -#if 0 - for(int i=-2; i<9; i++) - WriteLog("%06X: %08X\n", topOfStack + (i * 4), JaguarReadLong(topOfStack + (i * 4))); -#else - uint32_t address = topOfStack - (4 * 4 * 3); - - for(int i=0; i<10; i++) - { - WriteLog("%06X:", address); - - for(int j=0; j<4; j++) - { - WriteLog(" %08X", JaguarReadLong(address)); - address += 4; - } - - WriteLog("\n"); - } -#endif - -/* WriteLog("\nM68000 disassembly at $802288...\n"); - jaguar_dasm(0x802288, 3); - WriteLog("\nM68000 disassembly at $802200...\n"); - jaguar_dasm(0x802200, 500); - WriteLog("\nM68000 disassembly at $802518...\n"); - jaguar_dasm(0x802518, 100);//*/ - -/* WriteLog("\n\nM68000 disassembly at $803F00 (look @ $803F2A)...\n"); - jaguar_dasm(0x803F00, 500); - WriteLog("\n");//*/ - -/* WriteLog("\n\nM68000 disassembly at $802B00 (look @ $802B5E)...\n"); - jaguar_dasm(0x802B00, 500); - WriteLog("\n");//*/ - -/* WriteLog("\n\nM68000 disassembly at $809900 (look @ $8099F8)...\n"); - jaguar_dasm(0x809900, 500); - WriteLog("\n");//*/ -//8099F8 -/* WriteLog("\n\nDump of $8093C8:\n\n"); - for(int i=0x8093C8; i<0x809900; i+=4) - WriteLog("%06X: %08X\n", i, JaguarReadLong(i));//*/ -/* WriteLog("\n\nM68000 disassembly at $90006C...\n"); - jaguar_dasm(0x90006C, 500); - WriteLog("\n");//*/ -/* WriteLog("\n\nM68000 disassembly at $1AC000...\n"); - jaguar_dasm(0x1AC000, 6000); - WriteLog("\n");//*/ - -// WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004)); - WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F); - WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VIDEO)) - && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR)); - M68K_show_context(); -//#endif - CDROMDone(); GPUDone(); DSPDone(); TOMDone(); JERRYDone(); - - // temp, until debugger is in place -//00802016: jsr $836F1A.l -//0080201C: jsr $836B30.l -//00802022: jsr $836B18.l -//00802028: jsr $8135F0.l -//00813C1E: jsr $813F76.l -//00802038: jsr $836D00.l -//00802098: jsr $8373A4.l -//008020A2: jsr $83E24A.l -//008020BA: jsr $83E156.l -//008020C6: jsr $83E19C.l -//008020E6: jsr $8445E8.l -//008020EC: jsr $838C20.l -//0080211A: jsr $838ED6.l -//00802124: jsr $89CA56.l -//0080212A: jsr $802B48.l -#if 0 - WriteLog("-------------------------------------------\n"); - JaguarDasm(0x8445E8, 0x200); - WriteLog("-------------------------------------------\n"); - JaguarDasm(0x838C20, 0x200); - WriteLog("-------------------------------------------\n"); - JaguarDasm(0x838ED6, 0x200); - WriteLog("-------------------------------------------\n"); - JaguarDasm(0x89CA56, 0x200); - WriteLog("-------------------------------------------\n"); - JaguarDasm(0x802B48, 0x200); - WriteLog("\n\nM68000 disassembly at $802000...\n"); - JaguarDasm(0x802000, 6000); - WriteLog("\n");//*/ -#endif -/* WriteLog("\n\nM68000 disassembly at $6004...\n"); - JaguarDasm(0x6004, 10000); - WriteLog("\n");//*/ -// WriteLog("\n\nM68000 disassembly at $802000...\n"); -// JaguarDasm(0x802000, 0x1000); -// WriteLog("\n\nM68000 disassembly at $4100...\n"); -// JaguarDasm(0x4100, 200); -// WriteLog("\n\nM68000 disassembly at $800800...\n"); -// JaguarDasm(0x800800, 0x1000); } - -// Temp debugging stuff - -void DumpMainMemory(void) -{ - FILE * fp = fopen("./memdump.bin", "wb"); - - if (fp == NULL) - return; - - fwrite(jaguarMainRAM, 1, 0x200000, fp); - fclose(fp); -} - - -uint8_t * GetRamPtr(void) -{ - return jaguarMainRAM; -} - - // // New Jaguar execution stack // This executes 1 frame's worth of code. @@ -2161,19 +437,16 @@ void JaguarExecuteNew(void) do { double timeToNextEvent = GetTimeToNextEvent(); -//WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent)); m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent)); - if (vjs.GPUEnabled) - GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); + GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); HandleNextEvent(); } while (!frameDone); } - // // The thing to keep in mind is that the VC is advanced every HALF line, // regardless of whether the display is interlaced or not. The only difference @@ -2202,44 +475,31 @@ void HalflineCallback(void) uint16_t vc = TOMReadWord(0xF00006, JAGUAR); uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1; uint16_t vi = TOMReadWord(0xF0004E, JAGUAR); -// uint16_t vbb = TOMReadWord(0xF00040, JAGUAR); vc++; - // Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL). - // So we cut the number of half-lines in a frame in half. :-P uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2; if ((vc & 0x7FF) >= numHalfLines) { lowerField = !lowerField; - // If we're rendering the lower field, set the high bit (#11, counting - // from 0) of VC vc = (lowerField ? 0x0800 : 0x0000); } -//WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp); TOMWriteWord(0xF00006, vc, JAGUAR); - // Time for Vertical Interrupt? if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO)) { - // We don't have to worry about autovectors & whatnot because the Jaguar - // tells you through its HW registers who sent the interrupt... TOMSetPendingVideoInt(); m68k_set_irq(2); } TOMExecHalfline(vc, true); -//Change this to VBB??? -//Doesn't seem to matter (at least for Flip Out & I-War) if ((vc & 0x7FF) == 0) -// if (vc == vbb) { JoystickExec(); frameDone = true; - }//*/ + } SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0)); } - diff --git a/waterbox/virtualjaguar/src/jaguar.h b/waterbox/virtualjaguar/src/jaguar.h index 63e6de6238..1c38fa0f5d 100644 --- a/waterbox/virtualjaguar/src/jaguar.h +++ b/waterbox/virtualjaguar/src/jaguar.h @@ -17,19 +17,12 @@ void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who = UNKNOWN); void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who = UNKNOWN); void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who = UNKNOWN); -bool JaguarInterruptHandlerIsValid(uint32_t i); -void JaguarDasm(uint32_t offset, uint32_t qt); - void JaguarExecuteNew(void); // Exports from JAGUAR.CPP -extern int32_t jaguarCPUInExec; extern uint32_t jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress; -extern char * jaguarEepromsPath; extern bool jaguarCartInserted; -extern bool bpmActive; -extern uint32_t bpmAddress1; // Various clock rates @@ -43,9 +36,4 @@ extern uint32_t bpmAddress1; #define ASSERT_LINE 1 #define CLEAR_LINE 0 -//Temp debug stuff (will go away soon, so don't depend on these) - -void DumpMainMemory(void); -uint8_t * GetRamPtr(void); - #endif // __JAGUAR_H__ diff --git a/waterbox/virtualjaguar/src/jerry.cpp b/waterbox/virtualjaguar/src/jerry.cpp index 1e2478fbbd..7d2728f4da 100644 --- a/waterbox/virtualjaguar/src/jerry.cpp +++ b/waterbox/virtualjaguar/src/jerry.cpp @@ -12,149 +12,9 @@ // JLH 11/25/2009 Major rewrite of memory subsystem and handlers // -// ------------------------------------------------------------ -// JERRY REGISTERS (Mapped by Aaron Giles) -// ------------------------------------------------------------ -// F10000-F13FFF R/W xxxxxxxx xxxxxxxx Jerry -// F10000 W xxxxxxxx xxxxxxxx JPIT1 - timer 1 pre-scaler -// F10002 W xxxxxxxx xxxxxxxx JPIT2 - timer 1 divider -// F10004 W xxxxxxxx xxxxxxxx JPIT3 - timer 2 pre-scaler -// F10008 W xxxxxxxx xxxxxxxx JPIT4 - timer 2 divider -// F10010 W ------xx xxxxxxxx CLK1 - processor clock divider -// F10012 W ------xx xxxxxxxx CLK2 - video clock divider -// F10014 W -------- --xxxxxx CLK3 - chroma clock divider -// F10020 R/W ---xxxxx ---xxxxx JINTCTRL - interrupt control register -// W ---x---- -------- (J_SYNCLR - clear synchronous serial intf ints) -// W ----x--- -------- (J_ASYNCLR - clear asynchronous serial intf ints) -// W -----x-- -------- (J_TIM2CLR - clear timer 2 [tempo] interrupts) -// W ------x- -------- (J_TIM1CLR - clear timer 1 [sample] interrupts) -// W -------x -------- (J_EXTCLR - clear external interrupts) -// R/W -------- ---x---- (J_SYNENA - enable synchronous serial intf ints) -// R/W -------- ----x--- (J_ASYNENA - enable asynchronous serial intf ints) -// R/W -------- -----x-- (J_TIM2ENA - enable timer 2 [tempo] interrupts) -// R/W -------- ------x- (J_TIM1ENA - enable timer 1 [sample] interrupts) -// R/W -------- -------x (J_EXTENA - enable external interrupts) -// F10030 R/W -------- xxxxxxxx ASIDATA - asynchronous serial data -// F10032 W -x------ -xxxxxxx ASICTRL - asynchronous serial control -// W -x------ -------- (TXBRK - transmit break) -// W -------- -x------ (CLRERR - clear error) -// W -------- --x----- (RINTEN - enable receiver interrupts) -// W -------- ---x---- (TINTEN - enable transmitter interrupts) -// W -------- ----x--- (RXIPOL - receiver input polarity) -// W -------- -----x-- (TXOPOL - transmitter output polarity) -// W -------- ------x- (PAREN - parity enable) -// W -------- -------x (ODD - odd parity select) -// F10032 R xxx-xxxx x-xxxxxx ASISTAT - asynchronous serial status -// R x------- -------- (ERROR - OR of PE,FE,OE) -// R -x------ -------- (TXBRK - transmit break) -// R --x----- -------- (SERIN - serial input) -// R ----x--- -------- (OE - overrun error) -// R -----x-- -------- (FE - framing error) -// R ------x- -------- (PE - parity error) -// R -------x -------- (TBE - transmit buffer empty) -// R -------- x------- (RBF - receive buffer full) -// R -------- ---x---- (TINTEN - enable transmitter interrupts) -// R -------- ----x--- (RXIPOL - receiver input polarity) -// R -------- -----x-- (TXOPOL - transmitter output polarity) -// R -------- ------x- (PAREN - parity enable) -// R -------- -------x (ODD - odd parity) -// F10034 R/W xxxxxxxx xxxxxxxx ASICLK - asynchronous serial interface clock -// F10036 R xxxxxxxx xxxxxxxx JPIT1 - timer 1 pre-scaler -// F10038 R xxxxxxxx xxxxxxxx JPIT2 - timer 1 divider -// F1003A R xxxxxxxx xxxxxxxx JPIT3 - timer 2 pre-scaler -// F1003C R xxxxxxxx xxxxxxxx JPIT4 - timer 2 divider -// ------------------------------------------------------------ -// F14000-F17FFF R/W xxxxxxxx xxxxxxxx Joysticks and GPIO0-5 -// F14000 R xxxxxxxx xxxxxxxx JOYSTICK - read joystick state -// F14000 W x------- xxxxxxxx JOYSTICK - latch joystick output -// W x------- -------- (enable joystick outputs) -// W -------- xxxxxxxx (joystick output data) -// F14002 R xxxxxxxx xxxxxxxx JOYBUTS - button register -// F14800-F14FFF R/W xxxxxxxx xxxxxxxx GPI00 - reserved (CD-ROM? no.) -// F15000-F15FFF R/W xxxxxxxx xxxxxxxx GPI01 - reserved -// F16000-F16FFF R/W xxxxxxxx xxxxxxxx GPI02 - reserved -// F17000-F177FF R/W xxxxxxxx xxxxxxxx GPI03 - reserved -// F17800-F17BFF R/W xxxxxxxx xxxxxxxx GPI04 - reserved -// F17C00-F17FFF R/W xxxxxxxx xxxxxxxx GPI05 - reserved -// ------------------------------------------------------------ -// F18000-F1FFFF R/W xxxxxxxx xxxxxxxx Jerry DSP -// F1A100 R/W xxxxxxxx xxxxxxxx D_FLAGS - DSP flags register -// R/W x------- -------- (DMAEN - DMA enable) -// R/W -x------ -------- (REGPAGE - register page) -// W --x----- -------- (D_EXT0CLR - clear external interrupt 0) -// W ---x---- -------- (D_TIM2CLR - clear timer 2 interrupt) -// W ----x--- -------- (D_TIM1CLR - clear timer 1 interrupt) -// W -----x-- -------- (D_I2SCLR - clear I2S interrupt) -// W ------x- -------- (D_CPUCLR - clear CPU interrupt) -// R/W -------x -------- (D_EXT0ENA - enable external interrupt 0) -// R/W -------- x------- (D_TIM2ENA - enable timer 2 interrupt) -// R/W -------- -x------ (D_TIM1ENA - enable timer 1 interrupt) -// R/W -------- --x----- (D_I2SENA - enable I2S interrupt) -// R/W -------- ---x---- (D_CPUENA - enable CPU interrupt) -// R/W -------- ----x--- (IMASK - interrupt mask) -// R/W -------- -----x-- (NEGA_FLAG - ALU negative) -// R/W -------- ------x- (CARRY_FLAG - ALU carry) -// R/W -------- -------x (ZERO_FLAG - ALU zero) -// F1A102 R/W -------- ------xx D_FLAGS - upper DSP flags -// R/W -------- ------x- (D_EXT1ENA - enable external interrupt 1) -// R/W -------- -------x (D_EXT1CLR - clear external interrupt 1) -// F1A104 W -------- ----xxxx D_MTXC - matrix control register -// W -------- ----x--- (MATCOL - column/row major) -// W -------- -----xxx (MATRIX3-15 - matrix width) -// F1A108 W ----xxxx xxxxxx-- D_MTXA - matrix address register -// F1A10C W -------- -----x-x D_END - data organization register -// W -------- -----x-- (BIG_INST - big endian instruction fetch) -// W -------- -------x (BIG_IO - big endian I/O) -// F1A110 R/W xxxxxxxx xxxxxxxx D_PC - DSP program counter -// F1A114 R/W xxxxxxxx xx-xxxxx D_CTRL - DSP control/status register -// R xxxx---- -------- (VERSION - DSP version code) -// R/W ----x--- -------- (BUS_HOG - hog the bus!) -// R/W -----x-- -------- (D_EXT0LAT - external interrupt 0 latch) -// R/W ------x- -------- (D_TIM2LAT - timer 2 interrupt latch) -// R/W -------x -------- (D_TIM1LAT - timer 1 interrupt latch) -// R/W -------- x------- (D_I2SLAT - I2S interrupt latch) -// R/W -------- -x------ (D_CPULAT - CPU interrupt latch) -// R/W -------- ---x---- (SINGLE_GO - single step one instruction) -// R/W -------- ----x--- (SINGLE_STEP - single step mode) -// R/W -------- -----x-- (FORCEINT0 - cause interrupt 0 on GPU) -// R/W -------- ------x- (CPUINT - send GPU interrupt to CPU) -// R/W -------- -------x (DSPGO - enable DSP execution) -// F1A116 R/W -------- -------x D_CTRL - upper DSP control/status register -// R/W -------- -------x (D_EXT1LAT - external interrupt 1 latch) -// F1A118-F1A11B W xxxxxxxx xxxxxxxx D_MOD - modulo instruction mask -// F1A11C-F1A11F R xxxxxxxx xxxxxxxx D_REMAIN - divide unit remainder -// F1A11C W -------- -------x D_DIVCTRL - divide unit control -// W -------- -------x (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide) -// F1A120-F1A123 R xxxxxxxx xxxxxxxx D_MACHI - multiply & accumulate high bits -// F1A148 W xxxxxxxx xxxxxxxx R_DAC - right transmit data -// F1A14C W xxxxxxxx xxxxxxxx L_DAC - left transmit data -// F1A150 W -------- xxxxxxxx SCLK - serial clock frequency -// F1A150 R -------- ------xx SSTAT -// R -------- ------x- (left - no description) -// R -------- -------x (WS - word strobe status) -// F1A154 W -------- --xxxx-x SMODE - serial mode -// W -------- --x----- (EVERYWORD - interrupt on MSB of every word) -// W -------- ---x---- (FALLING - interrupt on falling edge) -// W -------- ----x--- (RISING - interrupt of rising edge) -// W -------- -----x-- (WSEN - enable word strobes) -// W -------- -------x (INTERNAL - enables serial clock) -// ------------------------------------------------------------ -// F1B000-F1CFFF R/W xxxxxxxx xxxxxxxx Local DSP RAM -// ------------------------------------------------------------ -// F1D000 R xxxxxxxx xxxxxxxx ROM_TRI - triangle wave -// F1D200 R xxxxxxxx xxxxxxxx ROM_SINE - full sine wave -// F1D400 R xxxxxxxx xxxxxxxx ROM_AMSINE - amplitude modulated sine wave -// F1D600 R xxxxxxxx xxxxxxxx ROM_12W - sine wave and second order harmonic -// F1D800 R xxxxxxxx xxxxxxxx ROM_CHIRP16 - chirp -// F1DA00 R xxxxxxxx xxxxxxxx ROM_NTRI - traingle wave with noise -// F1DC00 R xxxxxxxx xxxxxxxx ROM_DELTA - spike -// F1DE00 R xxxxxxxx xxxxxxxx ROM_NOISE - white noise -// ------------------------------------------------------------ - #include "jerry.h" -#include // For memcpy -//#include +#include #include "cdrom.h" #include "dac.h" #include "dsp.h" @@ -162,21 +22,14 @@ #include "event.h" #include "jaguar.h" #include "joystick.h" -#include "log.h" #include "m68000/m68kinterface.h" #include "memtrack.h" #include "settings.h" #include "tom.h" -//#include "memory.h" #include "wavetable.h" -//Note that 44100 Hz requires samples every 22.675737 usec. -//#define JERRY_DEBUG - /*static*/ uint8_t jerry_ram_8[0x10000]; -//#define JERRY_CONFIG 0x4002 // ??? What's this ??? - // JERRY Registers (write, offset from $F10000) #define JPIT1 0x00 #define JPIT2 0x02 @@ -192,7 +45,6 @@ #define SCLK 0xA150 #define SMODE 0xA154 - uint8_t analog_x, analog_y; static uint32_t JERRYPIT1Prescaler; @@ -202,7 +54,6 @@ static uint32_t JERRYPIT2Divider; static int32_t jerry_timer_1_counter; static int32_t jerry_timer_2_counter; -//uint32_t JERRYI2SInterruptDivide = 8; int32_t JERRYI2SInterruptTimer = -1; uint32_t jerryI2SCycles; uint32_t jerryIntPending; @@ -223,13 +74,10 @@ void JERRYI2SCallback(void); void JERRYResetI2S(void) { - //WriteLog("i2s: reseting\n"); -//This is really SCLK... !!! FIX !!! sclk = 8; JERRYI2SInterruptTimer = -1; } - void JERRYResetPIT1(void) { RemoveCallback(JERRYPIT1Callback); @@ -241,7 +89,6 @@ void JERRYResetPIT1(void) } } - void JERRYResetPIT2(void) { RemoveCallback(JERRYPIT2Callback); @@ -253,100 +100,50 @@ void JERRYResetPIT2(void) } } - -// This is the cause of the regressions in Cybermorph and Missile Command 3D... -// Solution: Probably have to check the DSP enable bit before sending these thru. -//#define JERRY_NO_IRQS void JERRYPIT1Callback(void) { -#ifndef JERRY_NO_IRQS -//WriteLog("JERRY: In PIT1 callback, IRQM=$%04X\n", jerryInterruptMask); if (TOMIRQEnabled(IRQ_DSP)) { - if (jerryInterruptMask & IRQ2_TIMER1) // CPU Timer 1 IRQ + if (jerryInterruptMask & IRQ2_TIMER1) { -// Not sure, but I think we don't generate another IRQ if one's already going... -// But this seems to work... :-/ jerryPendingInterrupt |= IRQ2_TIMER1; - m68k_set_irq(2); // Generate 68K IPL 2 + m68k_set_irq(2); } } -#endif - DSPSetIRQLine(DSPIRQ_TIMER0, ASSERT_LINE); // This does the 'IRQ enabled' checking... + DSPSetIRQLine(DSPIRQ_TIMER0, ASSERT_LINE); JERRYResetPIT1(); } - void JERRYPIT2Callback(void) { -#ifndef JERRY_NO_IRQS if (TOMIRQEnabled(IRQ_DSP)) { -//WriteLog("JERRY: In PIT2 callback, IRQM=$%04X\n", jerryInterruptMask); - if (jerryInterruptMask & IRQ2_TIMER2) // CPU Timer 2 IRQ + if (jerryInterruptMask & IRQ2_TIMER2) { jerryPendingInterrupt |= IRQ2_TIMER2; - m68k_set_irq(2); // Generate 68K IPL 2 + m68k_set_irq(2); } } -#endif - DSPSetIRQLine(DSPIRQ_TIMER1, ASSERT_LINE); // This does the 'IRQ enabled' checking... + DSPSetIRQLine(DSPIRQ_TIMER1, ASSERT_LINE); JERRYResetPIT2(); } - void JERRYI2SCallback(void) { - // We don't have to divide the RISC clock rate by this--the reason is a bit - // convoluted. Will put explanation here later... -// What's needed here is to find the ratio of the frequency to the number of clock cycles -// in one second. For example, if the sample rate is 44100, we divide the clock rate by -// this: 26590906 / 44100 = 602 cycles. -// Which means, every 602 cycles that go by we have to generate an interrupt. jerryI2SCycles = 32 * (2 * (sclk + 1)); -//This makes audio faster, but not enough and the pitch is wrong besides -// jerryI2SCycles = 32 * (2 * (sclk - 1)); - // If INTERNAL flag is set, then JERRY's SCLK is master if (smode & SMODE_INTERNAL) { - // This does the 'IRQ enabled' checking... DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE); -// double usecs = (float)jerryI2SCycles * RISC_CYCLE_IN_USEC; -//this fix is almost enough to fix timings in tripper, but not quite enough... double usecs = (float)jerryI2SCycles * (vjs.hardwareTypeNTSC ? RISC_CYCLE_IN_USEC : RISC_CYCLE_PAL_IN_USEC); SetCallbackTime(JERRYI2SCallback, usecs, EVENT_JERRY); } else { - // JERRY is slave to external word clock - -//Note that 44100 Hz requires samples every 22.675737 usec. -//When JERRY is slave to the word clock, we need to do interrupts either at 44.1K -//sample rate or at a 88.2K sample rate (11.332... usec). -/* // This is just a temporary kludge to see if the CD bus mastering works - // I.e., this is totally faked...! -// The whole interrupt system is pretty much borked and is need of an overhaul. -// What we need is a way of handling these interrupts when they happen instead of -// scanline boundaries the way it is now. - jerry_i2s_interrupt_timer -= cycles; - if (jerry_i2s_interrupt_timer <= 0) + if (ButchIsReadyToSend()) { -//This is probably wrong as well (i.e., need to check enable lines)... !!! FIX !!! [DONE] - if (ButchIsReadyToSend())//Not sure this is right spot to check... - { -// return GetWordFromButchSSI(offset, who); - SetSSIWordsXmittedFromButch(); - DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE); - } - jerry_i2s_interrupt_timer += 602; - }*/ - - if (ButchIsReadyToSend())//Not sure this is right spot to check... - { -// return GetWordFromButchSSI(offset, who); SetSSIWordsXmittedFromButch(); DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE); } @@ -355,7 +152,6 @@ void JERRYI2SCallback(void) } } - void JERRYInit(void) { JoystickInit(); @@ -372,7 +168,6 @@ void JERRYInit(void) DACInit(); } - void JERRYReset(void) { JoystickReset(); @@ -380,7 +175,7 @@ void JERRYReset(void) MTReset(); JERRYResetI2S(); - memset(jerry_ram_8, 0x00, 0xD000); // Don't clear out the Wavetable ROM...! + memset(jerry_ram_8, 0x00, 0xD000); JERRYPIT1Prescaler = 0xFFFF; JERRYPIT2Prescaler = 0xFFFF; JERRYPIT1Divider = 0xFFFF; @@ -393,94 +188,36 @@ void JERRYReset(void) DACReset(); } - void JERRYDone(void) { - JERRYDumpIORegistersToLog(); - WriteLog("JERRY: M68K Interrupt control ($F10020) = %04X\n", GET16(jerry_ram_8, 0x20)); JoystickDone(); DACDone(); EepromDone(); MTDone(); } - bool JERRYIRQEnabled(int irq) { - // Read the word @ $F10020 -// return jerry_ram_8[0x21] & (1 << irq); return jerryInterruptMask & irq; } - void JERRYSetPendingIRQ(int irq) { - // This is the shadow of INT (it's a split RO/WO register) -// jerryIntPending |= (1 << irq); jerryPendingInterrupt |= irq; } -// -// Dump all JERRY register values to the log -// -void JERRYDumpIORegistersToLog(void) -{ - WriteLog("\n\n---------------------------------------------------------------------\n"); - WriteLog("JERRY I/O Registers\n"); - WriteLog("---------------------------------------------------------------------\n"); - WriteLog("F1%04X (JPIT1): $%04X\n", JPIT1, GET16(jerry_ram_8, JPIT1)); - WriteLog("F1%04X (JPIT2): $%04X\n", JPIT2, GET16(jerry_ram_8, JPIT2)); - WriteLog("F1%04X (JPIT3): $%04X\n", JPIT3, GET16(jerry_ram_8, JPIT3)); - WriteLog("F1%04X (JPIT4): $%04X\n", JPIT4, GET16(jerry_ram_8, JPIT4)); - WriteLog("F1%04X (CLK1): $%04X\n", CLK1, GET16(jerry_ram_8, CLK1)); - WriteLog("F1%04X (CLK2): $%04X\n", CLK2, GET16(jerry_ram_8, CLK2)); - WriteLog("F1%04X (CLK3): $%04X\n", CLK3, GET16(jerry_ram_8, CLK3)); - WriteLog("F1%04X (JINTCTRL): $%04X\n", JINTCTRL, GET16(jerry_ram_8, JINTCTRL)); - WriteLog("F1%04X (ASIDATA): $%04X\n", ASIDATA, GET16(jerry_ram_8, ASIDATA)); - WriteLog("F1%04X (ASICTRL): $%04X\n", ASICTRL, GET16(jerry_ram_8, ASICTRL)); - WriteLog("F1%04X (ASICLK): $%04X\n", ASICLK, GET16(jerry_ram_8, ASICLK)); - WriteLog("F1%04X (SCLK): $%04X\n", SCLK, GET16(jerry_ram_8, SCLK)); - WriteLog("F1%04X (SMODE): $%04X\n", SMODE, GET16(jerry_ram_8, SMODE)); - WriteLog("---------------------------------------------------------------------\n\n\n"); -} - - // // JERRY byte access (read) // -uint8_t JERRYReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint8_t JERRYReadByte(uint32_t offset, uint32_t who) { -#ifdef JERRY_DEBUG - WriteLog("JERRY: Reading byte at %06X\n", offset); -#endif if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20)) return DSPReadByte(offset, who); else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000)) return DSPReadByte(offset, who); - // LRXD/RRXD/SSTAT $F1A148/4C/50 (really 16-bit registers...) else if (offset >= 0xF1A148 && offset <= 0xF1A153) return DACReadByte(offset, who); -// F10036 R xxxxxxxx xxxxxxxx JPIT1 - timer 1 pre-scaler -// F10038 R xxxxxxxx xxxxxxxx JPIT2 - timer 1 divider -// F1003A R xxxxxxxx xxxxxxxx JPIT3 - timer 2 pre-scaler -// F1003C R xxxxxxxx xxxxxxxx JPIT4 - timer 2 divider -//This is WRONG! -// else if (offset >= 0xF10000 && offset <= 0xF10007) -//This is still wrong. What needs to be returned here are the values being counted down -//in the jerry_timer_n_counter variables... !!! FIX !!! [DONE] - -//This is probably the problem with the new timer code... This is invalid -//under the new system... !!! FIX !!! - else if ((offset >= 0xF10036) && (offset <= 0xF1003D)) - { -WriteLog("JERRY: Unhandled timer read (BYTE) at %08X...\n", offset); - } -// else if (offset >= 0xF10010 && offset <= 0xF10015) -// return clock_byte_read(offset); -// else if (offset >= 0xF17C00 && offset <= 0xF17C01) -// return anajoy_byte_read(offset); else if (offset >= 0xF14000 && offset <= 0xF14003) -// return JoystickReadByte(offset) | EepromReadByte(offset); { uint16_t value = JoystickReadWord(offset & 0xFE); @@ -489,7 +226,6 @@ WriteLog("JERRY: Unhandled timer read (BYTE) at %08X...\n", offset); else value >>= 8; - // This is wrong, should only have the lowest bit from $F14001 return value | EepromReadByte(offset); } else if (offset >= 0xF14000 && offset <= 0xF1A0FF) @@ -498,42 +234,19 @@ WriteLog("JERRY: Unhandled timer read (BYTE) at %08X...\n", offset); return jerry_ram_8[offset & 0xFFFF]; } - // // JERRY word access (read) // -uint16_t JERRYReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint16_t JERRYReadWord(uint32_t offset, uint32_t who) { -#ifdef JERRY_DEBUG - WriteLog("JERRY: Reading word at %06X\n", offset); -#endif - if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20)) return DSPReadWord(offset, who); else if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF) return DSPReadWord(offset, who); - // LRXD/RRXD/SSTAT $F1A148/4C/50 (really 16-bit registers...) else if (offset >= 0xF1A148 && offset <= 0xF1A153) return DACReadWord(offset, who); -// F10036 R xxxxxxxx xxxxxxxx JPIT1 - timer 1 pre-scaler -// F10038 R xxxxxxxx xxxxxxxx JPIT2 - timer 1 divider -// F1003A R xxxxxxxx xxxxxxxx JPIT3 - timer 2 pre-scaler -// F1003C R xxxxxxxx xxxxxxxx JPIT4 - timer 2 divider -//This is WRONG! -// else if ((offset >= 0xF10000) && (offset <= 0xF10007)) -//This is still wrong. What needs to be returned here are the values being counted down -//in the jerry_timer_n_counter variables... !!! FIX !!! [DONE] - else if ((offset >= 0xF10036) && (offset <= 0xF1003D)) - { -WriteLog("JERRY: Unhandled timer read (WORD) at %08X...\n", offset); - } -// else if ((offset >= 0xF10010) && (offset <= 0xF10015)) -// return clock_word_read(offset); else if (offset == 0xF10020) -// return jerryIntPending; return jerryPendingInterrupt; -// else if ((offset >= 0xF17C00) && (offset <= 0xF17C01)) -// return anajoy_word_read(offset); else if (offset == 0xF14000) return (JoystickReadWord(offset) & 0xFFFE) | EepromReadWord(offset); else if ((offset >= 0xF14002) && (offset < 0xF14003)) @@ -541,251 +254,114 @@ WriteLog("JERRY: Unhandled timer read (WORD) at %08X...\n", offset); else if ((offset >= 0xF14000) && (offset <= 0xF1A0FF)) return EepromReadWord(offset); -/*if (offset >= 0xF1D000) - WriteLog("JERRY: Reading word at %08X [%04X]...\n", offset, ((uint16_t)jerry_ram_8[(offset+0)&0xFFFF] << 8) | jerry_ram_8[(offset+1)&0xFFFF]);//*/ - - offset &= 0xFFFF; // Prevent crashing...! + offset &= 0xFFFF; return ((uint16_t)jerry_ram_8[offset+0] << 8) | jerry_ram_8[offset+1]; } - // // JERRY byte access (write) // -void JERRYWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) +void JERRYWriteByte(uint32_t offset, uint8_t data, uint32_t who) { - // Moved here tentatively, so we can see everything written to JERRY. jerry_ram_8[offset & 0xFFFF] = data; -#ifdef JERRY_DEBUG - WriteLog("jerry: writing byte %.2x at 0x%.6x\n",data,offset); -#endif if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20)) { DSPWriteByte(offset, data, who); - return; } else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000)) { DSPWriteByte(offset, data, who); - return; } - // SCLK ($F1A150--8 bits wide) -//NOTE: This should be taken care of in DAC... -#if 0 - else if ((offset >= 0xF1A152) && (offset <= 0xF1A153)) - { -#if 0 -// WriteLog("JERRY: Writing %02X to SCLK...\n", data); - if ((offset & 0x03) == 2) - sclk = (sclk & 0x00FF) | ((uint32_t)data << 8); - else - sclk = (sclk & 0xFF00) | (uint32_t)data; -#else - sclk = data; -#endif -#warning "!!! SCLK should be handled in dac.cpp !!!" - JERRYI2SInterruptTimer = -1; - RemoveCallback(JERRYI2SCallback); - JERRYI2SCallback(); -// return; - } -#endif - // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...) else if (offset >= 0xF1A148 && offset <= 0xF1A157) { DACWriteByte(offset, data, who); - return; } - else if (offset >= 0xF10000 && offset <= 0xF10007) - { -WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", offset); - return; - } -/* else if ((offset >= 0xF10010) && (offset <= 0xF10015)) - { - clock_byte_write(offset, data); - return; - }//*/ - // JERRY -> 68K interrupt enables/latches (need to be handled!) - else if (offset >= 0xF10020 && offset <= 0xF10021)//WAS:23) + else if (offset >= 0xF10020 && offset <= 0xF10021) { if (offset == 0xF10020) { - // Clear pending interrupts... jerryPendingInterrupt &= ~data; } else if (offset == 0xF10021) jerryInterruptMask = data; -//WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", data, offset); -//WriteLog("JERRY: (Previous is partially handled... IRQMask=$%04X)\n", jerryInterruptMask); } -/* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01)) - { - anajoy_byte_write(offset, data); - return; - }*/ else if ((offset >= 0xF14000) && (offset <= 0xF14003)) { -WriteLog("JERRYWriteByte: Unhandled byte write to JOYSTICK by %s.\n", whoName[who]); -// JoystickWriteByte(offset, data); JoystickWriteWord(offset & 0xFE, (uint16_t)data); -// This is wrong, EEPROM is never written here EepromWriteByte(offset, data); - return; } else if ((offset >= 0xF14000) && (offset <= 0xF1A0FF)) { EepromWriteByte(offset, data); - return; } - -//Need to protect write attempts to Wavetable ROM (F1D000-FFF) - if (offset >= 0xF1D000 && offset <= 0xF1DFFF) - return; - -// jerry_ram_8[offset & 0xFFFF] = data; } - // // JERRY word access (write) // -void JERRYWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) +void JERRYWriteWord(uint32_t offset, uint16_t data, uint32_t who) { - // Moved here tentatively, so we can see everything written to JERRY. jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF; jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF; -#ifdef JERRY_DEBUG - WriteLog( "JERRY: Writing word %04X at %06X\n", data, offset); -#endif -#if 1 -if (offset == 0xF10000) - WriteLog("JERRY: JPIT1 word written by %s: %u\n", whoName[who], data); -else if (offset == 0xF10002) - WriteLog("JERRY: JPIT2 word written by %s: %u\n", whoName[who], data); -else if (offset == 0xF10004) - WriteLog("JERRY: JPIT3 word written by %s: %u\n", whoName[who], data); -else if (offset == 0xF10006) - WriteLog("JERRY: JPIT4 word written by %s: %u\n", whoName[who], data); -else if (offset == 0xF10010) - WriteLog("JERRY: CLK1 word written by %s: %u\n", whoName[who], data); -else if (offset == 0xF10012) - WriteLog("JERRY: CLK2 word written by %s: %u\n", whoName[who], data); -else if (offset == 0xF10014) - WriteLog("JERRY: CLK3 word written by %s: %u\n", whoName[who], data); -//else if (offset == 0xF1A100) -// WriteLog("JERRY: D_FLAGS word written by %s: %u\n", whoName[who], data); -//else if (offset == 0xF1A102) -// WriteLog("JERRY: D_FLAGS+2 word written by %s: %u\n", whoName[who], data); -else if (offset == 0xF10020) - WriteLog("JERRY: JINTCTRL word written by %s: $%04X (%s%s%s%s%s%s)\n", whoName[who], data, - (data & 0x01 ? "Extrnl " : ""), (data & 0x02 ? "DSP " : ""), - (data & 0x04 ? "Timer0 " : ""), (data & 0x08 ? "Timer1 " : ""), - (data & 0x10 ? "ASI " : ""), (data & 0x20 ? "I2S " : "")); -#endif - if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20)) { DSPWriteWord(offset, data, who); - return; } else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000)) { DSPWriteWord(offset, data, who); - return; } -//NOTE: This should be taken care of in DAC... -#if 0 - else if (offset == 0xF1A152) // Bottom half of SCLK ($F1A150) - { -#warning "!!! SCLK should be handled in dac.cpp !!!" - WriteLog("JERRY: Writing $%X to SCLK (by %s)...\n", data, whoName[who]); -//This should *only* be enabled when SMODE has its INTERNAL bit set! !!! FIX !!! -#if 0 - sclk = (uint8_t)data; -#else - sclk = data & 0xFF; -#endif - JERRYI2SInterruptTimer = -1; - RemoveCallback(JERRYI2SCallback); - JERRYI2SCallback(); - - DACWriteWord(offset, data, who); - return; - } -#endif - // LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...) else if (offset >= 0xF1A148 && offset <= 0xF1A156) { DACWriteWord(offset, data, who); - return; } else if (offset >= 0xF10000 && offset <= 0xF10007) { switch(offset & 0x07) { - case 0: - JERRYPIT1Prescaler = data; - JERRYResetPIT1(); - break; - case 2: - JERRYPIT1Divider = data; - JERRYResetPIT1(); - break; - case 4: - JERRYPIT2Prescaler = data; - JERRYResetPIT2(); - break; - case 6: - JERRYPIT2Divider = data; - JERRYResetPIT2(); + case 0: + JERRYPIT1Prescaler = data; + JERRYResetPIT1(); + break; + case 2: + JERRYPIT1Divider = data; + JERRYResetPIT1(); + break; + case 4: + JERRYPIT2Prescaler = data; + JERRYResetPIT2(); + break; + case 6: + JERRYPIT2Divider = data; + JERRYResetPIT2(); } - // Need to handle (unaligned) cases??? - - return; } - // JERRY -> 68K interrupt enables/latches (need to be handled!) else if (offset >= 0xF10020 && offset <= 0xF10022) { jerryInterruptMask = data & 0xFF; jerryPendingInterrupt &= ~(data >> 8); -//WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%04X to $%08X!\n", data, offset); -//WriteLog("JERRY: (Previous is partially handled... IRQMask=$%04X)\n", jerryInterruptMask); - return; } else if (offset >= 0xF14000 && offset < 0xF14003) { JoystickWriteWord(offset, data); EepromWriteWord(offset, data); - return; } else if (offset >= 0xF14000 && offset <= 0xF1A0FF) { EepromWriteWord(offset, data); - return; } - -//Need to protect write attempts to Wavetable ROM (F1D000-FFF) - if (offset >= 0xF1D000 && offset <= 0xF1DFFF) - return; - -// jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF; -// jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF; } - int JERRYGetPIT1Frequency(void) { int systemClockFrequency = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL); return systemClockFrequency / ((JERRYPIT1Prescaler + 1) * (JERRYPIT1Divider + 1)); } - int JERRYGetPIT2Frequency(void) { int systemClockFrequency = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL); return systemClockFrequency / ((JERRYPIT2Prescaler + 1) * (JERRYPIT2Divider + 1)); } - diff --git a/waterbox/virtualjaguar/src/jerry.h b/waterbox/virtualjaguar/src/jerry.h index 868c5a0efc..2d9da9bf69 100644 --- a/waterbox/virtualjaguar/src/jerry.h +++ b/waterbox/virtualjaguar/src/jerry.h @@ -5,13 +5,11 @@ #ifndef __JERRY_H__ #define __JERRY_H__ -//#include "types.h" #include "memory.h" void JERRYInit(void); void JERRYReset(void); void JERRYDone(void); -void JERRYDumpIORegistersToLog(void); uint8_t JERRYReadByte(uint32_t offset, uint32_t who = UNKNOWN); uint16_t JERRYReadWord(uint32_t offset, uint32_t who = UNKNOWN); @@ -26,7 +24,6 @@ int JERRYGetPIT2Frequency(void); // 68000 Interrupt bit positions (enabled at $F10020) -//enum { IRQ2_EXTERNAL = 0, IRQ2_DSP, IRQ2_TIMER1, IRQ2_TIMER2, IRQ2_ASI, IRQ2_SSI }; enum { IRQ2_EXTERNAL=0x01, IRQ2_DSP=0x02, IRQ2_TIMER1=0x04, IRQ2_TIMER2=0x08, IRQ2_ASI=0x10, IRQ2_SSI=0x20 }; bool JERRYIRQEnabled(int irq); @@ -38,7 +35,6 @@ void JERRYI2SCallback(void); // External variables -//extern uint32_t JERRYI2SInterruptDivide; extern int32_t JERRYI2SInterruptTimer; #endif diff --git a/waterbox/virtualjaguar/src/joystick.cpp b/waterbox/virtualjaguar/src/joystick.cpp index 69d75771cd..46d33d2950 100644 --- a/waterbox/virtualjaguar/src/joystick.cpp +++ b/waterbox/virtualjaguar/src/joystick.cpp @@ -14,10 +14,9 @@ // #include "joystick.h" -#include // For memset() +#include #include "gpu.h" #include "jaguar.h" -#include "log.h" #include "settings.h" // Global vars @@ -25,68 +24,38 @@ static uint8_t joystick_ram[4]; uint8_t joypad0Buttons[21]; uint8_t joypad1Buttons[21]; -bool audioEnabled = false; -bool joysticksEnabled = false; - - -bool GUIKeyHeld = false; -extern int start_logging; -int gpu_start_log = 0; -int op_start_log = 0; -int blit_start_log = 0; -int effect_start = 0; -int effect_start2 = 0, effect_start3 = 0, effect_start4 = 0, effect_start5 = 0, effect_start6 = 0; -bool interactiveMode = false; -bool iLeft, iRight, iToggle = false; -bool keyHeld1 = false, keyHeld2 = false, keyHeld3 = false; -int objectPtr = 0; -bool startMemLog = false; -extern bool doDSPDis, doGPUDis; - -bool blitterSingleStep = false; -bool bssGo = false; -bool bssHeld = false; +static bool joysticksEnabled; extern bool lagged; extern void (*inputcb)(); - void JoystickInit(void) { JoystickReset(); } - void JoystickExec(void) { - gpu_start_log = 0; // Only log while key down! - effect_start = 0; - effect_start2 = effect_start3 = effect_start4 = effect_start5 = effect_start6 = 0; - blit_start_log = 0; - iLeft = iRight = false; } - void JoystickReset(void) { memset(joystick_ram, 0x00, 4); memset(joypad0Buttons, 0, 21); memset(joypad1Buttons, 0, 21); + joysticksEnabled = false; } - void JoystickDone(void) { } - uint16_t JoystickReadWord(uint32_t offset) { lagged = false; if (__builtin_expect(!!inputcb, false)) inputcb(); - // E, D, B, 7 uint8_t joypad0Offset[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0xFF, 0xFF, 0xFF, 0x08, 0xFF, 0x04, 0x00, 0xFF }; @@ -94,7 +63,6 @@ uint16_t JoystickReadWord(uint32_t offset) 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x04, 0xFF, 0x08, 0x0C, 0xFF }; -#warning "No bounds checking done in JoystickReadByte!" offset &= 0x03; if (offset == 0) @@ -102,8 +70,6 @@ uint16_t JoystickReadWord(uint32_t offset) if (!joysticksEnabled) return 0xFFFF; - // Joystick data returns active low for buttons pressed, high for non- - // pressed. uint16_t data = 0xFFFF; uint8_t offset0 = joypad0Offset[joystick_ram[1] & 0x0F]; uint8_t offset1 = joypad1Offset[(joystick_ram[1] >> 4) & 0x0F]; @@ -134,21 +100,17 @@ uint16_t JoystickReadWord(uint32_t offset) } else if (offset == 2) { - // Hardware ID returns NTSC/PAL identification bit here - // N.B.: On real H/W, bit 7 is *always* zero...! uint16_t data = 0xFF6F | (vjs.hardwareTypeNTSC ? 0x10 : 0x00); if (!joysticksEnabled) return data; - // Joystick data returns active low for buttons pressed, high for non- - // pressed. uint8_t offset0 = joypad0Offset[joystick_ram[1] & 0x0F]; uint8_t offset1 = joypad1Offset[(joystick_ram[1] >> 4) & 0x0F]; if (offset0 != 0xFF) { - offset0 /= 4; // Make index 0, 1, 2, 3 instead of 0, 4, 8, 12 + offset0 /= 4; uint8_t mask[4][2] = { { BUTTON_A, BUTTON_PAUSE }, { BUTTON_B, 0xFF }, { BUTTON_C, 0xFF }, { BUTTON_OPTION, 0xFF } }; data &= (joypad0Buttons[mask[offset0][0]] ? 0xFFFD : 0xFFFF); @@ -158,7 +120,7 @@ uint16_t JoystickReadWord(uint32_t offset) if (offset1 != 0xFF) { - offset1 /= 4; // Make index 0, 1, 2, 3 instead of 0, 4, 8, 12 + offset1 /= 4; uint8_t mask[4][2] = { { BUTTON_A, BUTTON_PAUSE }, { BUTTON_B, 0xFF }, { BUTTON_C, 0xFF }, { BUTTON_OPTION, 0xFF } }; data &= (joypad1Buttons[mask[offset1][0]] ? 0xFFF7 : 0xFFFF); @@ -172,18 +134,14 @@ uint16_t JoystickReadWord(uint32_t offset) return 0xFFFF; } - void JoystickWriteWord(uint32_t offset, uint16_t data) { -#warning "No bounds checking done for JoystickWriteWord!" offset &= 0x03; joystick_ram[offset + 0] = (data >> 8) & 0xFF; joystick_ram[offset + 1] = data & 0xFF; if (offset == 0) { - audioEnabled = (data & 0x0100 ? true : false); joysticksEnabled = (data & 0x8000 ? true : false); } } - diff --git a/waterbox/virtualjaguar/src/joystick.h b/waterbox/virtualjaguar/src/joystick.h index 09e2378ce5..de4fa62990 100644 --- a/waterbox/virtualjaguar/src/joystick.h +++ b/waterbox/virtualjaguar/src/joystick.h @@ -34,16 +34,11 @@ BUTTON_PAUSE = 20, BUTTON_LAST = 20 }; void JoystickInit(void); void JoystickReset(void); void JoystickDone(void); -//void JoystickWriteByte(uint32_t, uint8_t); void JoystickWriteWord(uint32_t, uint16_t); -//uint8_t JoystickReadByte(uint32_t); uint16_t JoystickReadWord(uint32_t); void JoystickExec(void); extern uint8_t joypad0Buttons[]; extern uint8_t joypad1Buttons[]; -extern bool audioEnabled; -extern bool joysticksEnabled; #endif // __JOYSTICK_H__ - diff --git a/waterbox/virtualjaguar/src/log.cpp b/waterbox/virtualjaguar/src/log.cpp deleted file mode 100644 index 23fc806fa3..0000000000 --- a/waterbox/virtualjaguar/src/log.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// -// Log handler -// -// Originally by David Raingeard (Cal2) -// GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS) -// Cleanups/new stuff by James Hammons -// (C) 2010 Underground Software -// -// JLH = James Hammons -// -// Who When What -// --- ---------- ------------------------------------------------------------- -// JLH 01/16/2010 Created this log ;-) -// JLH 07/11/2011 Instead of dumping out on max log file size being reached, we -// now just silently ignore any more output. 10 megs ought to be -// enough for anybody. ;-) Except when it isn't. :-P -// - -#include "log.h" - -#include -#include -#include - - -//#define MAX_LOG_SIZE 10000000 // Maximum size of log file (10 MB) -#define MAX_LOG_SIZE 100000000 // Maximum size of log file (100 MB) - -static FILE * log_stream = NULL; -static uint32_t logSize = 0; - -int LogInit(const char * path) -{ - log_stream = fopen(path, "w"); - - if (log_stream == NULL) - return 0; - - return 1; -} - -FILE * LogGet(void) -{ - return log_stream; -} - -void LogDone(void) -{ - if (log_stream != NULL) - fclose(log_stream); -} - -// -// This logger is used mainly to ensure that text gets written to the log file -// even if the program crashes. The performance hit is acceptable in this case! -// -void WriteLog(const char * text, ...) -{ - va_list arg; - va_start(arg, text); - - if (log_stream == NULL) - { - va_end(arg); - return; - } - - logSize += vfprintf(log_stream, text, arg); - - if (logSize > MAX_LOG_SIZE) - { - // Instead of dumping out, we just close the file and ignore any more output. - fflush(log_stream); - fclose(log_stream); - log_stream = NULL; - } - - va_end(arg); - fflush(log_stream); // Make sure that text is written! -} diff --git a/waterbox/virtualjaguar/src/log.h b/waterbox/virtualjaguar/src/log.h deleted file mode 100644 index c406bf8154..0000000000 --- a/waterbox/virtualjaguar/src/log.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// log.h: Logfile support -// - -#ifndef __LOG_H__ -#define __LOG_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int LogInit(const char *); -FILE * LogGet(void); -void LogDone(void); -void WriteLog(const char * text, ...); - -#ifdef __cplusplus -} -#endif - -// Some useful defines... :-) -//#define GPU_DEBUG -//#define LOG_BLITS - -#endif // __LOG_H__ diff --git a/waterbox/virtualjaguar/src/memory.cpp b/waterbox/virtualjaguar/src/memory.cpp index f067c916ff..129d177c85 100644 --- a/waterbox/virtualjaguar/src/memory.cpp +++ b/waterbox/virtualjaguar/src/memory.cpp @@ -10,26 +10,9 @@ // JLH 12/10/2009 Repurposed this file. :-) // -/* -$FFFFFF => 16,777,215 -$A00000 => 10,485,760 - -Really, just six megabytes short of using the entire address space... -Why not? We could just allocate the entire space and then use the MMU code to do -things like call functions and whatnot... -In other words, read/write would just tuck the value into the host RAM space and -the I/O function would take care of any weird stuff... - -Actually: writes would tuck in the value, but reads would have to be handled -correctly since some registers do not fall on the same address as far as reading -goes... Still completely doable though. :-) - -N.B.: Jaguar RAM is only 2 megs. ROM is 6 megs max, IO is 128K -*/ - #include "memory.h" -uint8_t jagMemSpace[0xF20000]; // The entire memory space of the Jaguar...! +uint8_t jagMemSpace[0xF20000]; uint8_t * jaguarMainRAM = &jagMemSpace[0x000000]; uint8_t * jaguarMainROM = &jagMemSpace[0x800000]; @@ -37,85 +20,6 @@ uint8_t * cdRAM = &jagMemSpace[0xDFFF00]; uint8_t * gpuRAM = &jagMemSpace[0xF03000]; uint8_t * dspRAM = &jagMemSpace[0xF1B000]; -#if 0 -union Word -{ - uint16_t word; - struct { - // This changes depending on endianness... -#ifdef __BIG_ENDIAN__ - uint8_t hi, lo; // Big endian -#else - uint8_t lo, hi; // Little endian -#endif - }; -}; -#endif - -#if 0 -union DWord -{ - uint32_t dword; - struct - { -#ifdef __BIG_ENDIAN__ - uint16_t hiw, low; -#else - uint16_t low, hiw; -#endif - }; -}; -#endif - -#if 0 -static void test(void) -{ - Word reg; - reg.word = 0x1234; - reg.lo = 0xFF; - reg.hi = 0xEE; - - DWord reg2; - reg2.hiw = 0xFFFE; - reg2.low = 0x3322; - reg2.low.lo = 0x11; -} -#endif - -// OR, we could do like so: -#if 0 -#ifdef __BIG_ENDIAN__ -#define DWORD_BYTE_HWORD_H 1 -#define DWORD_BYTE_HWORD_L 2 -#define DWORD_BYTE_LWORD_H 3 -#define DWORD_BYTE_LWORD_L 4 -#else -#define DWORD_BYTE_HWORD_H 4 -#define DWORD_BYTE_HWORD_L 3 -#define DWORD_BYTE_LWORD_H 2 -#define DWORD_BYTE_LWORD_L 1 -#endif -// But this starts to get cumbersome after a while... Is union really better? - -//More union stuff... -unsigned long ByteSwap1 (unsigned long nLongNumber) -{ - union u {unsigned long vi; unsigned char c[sizeof(unsigned long)];}; - union v {unsigned long ni; unsigned char d[sizeof(unsigned long)];}; - union u un; - union v vn; - un.vi = nLongNumber; - vn.d[0]=un.c[3]; - vn.d[1]=un.c[2]; - vn.d[2]=un.c[1]; - vn.d[3]=un.c[0]; - return (vn.ni); -} -#endif - -//Not sure if this is a good approach yet... -//should be if we use proper aliasing, and htonl and friends... -#if 1 uint32_t & butch = *((uint32_t *)&jagMemSpace[0xDFFF00]); // base of Butch == interrupt control register, R/W uint32_t & dscntrl = *((uint32_t *)&jagMemSpace[0xDFFF04]); // DSA control register, R/W uint16_t & ds_data = *((uint16_t *)&jagMemSpace[0xDFFF0A]); // DSA TX/RX data, R/W @@ -127,29 +31,6 @@ uint32_t & sb_time = *((uint32_t *)&jagMemSpace[0xDFFF20]); // Subcode time an uint32_t & fifo_data = *((uint32_t *)&jagMemSpace[0xDFFF24]); // i2s FIFO data uint32_t & i2sdat2 = *((uint32_t *)&jagMemSpace[0xDFFF28]); // i2s FIFO data (old) uint32_t & unknown = *((uint32_t *)&jagMemSpace[0xDFFF2C]); // Seems to be some sort of I2S interface -#else -uint32_t butch, dscntrl, ds_data, i2cntrl, sbcntrl, subdata, subdatb, sb_time, fifo_data, i2sdat2, unknown; -#endif - -//#warning "Need to separate out this stuff (or do we???)" -//if we use a contiguous memory space, we don't need this shit... -//err, maybe we do, let's not be so hasty now... :-) - -//#define ENDIANSAFE(x) htonl(x) - -// The nice thing about doing it this way is that on big endian machines, htons/l -// compile to nothing and on Intel machines, it compiles down to a single bswap instruction. -// So endianness issues go away nicely without a lot of drama. :-D - -#define BSWAP16(x) (htons(x)) -#define BSWAP32(x) (htonl(x)) -//this isn't endian safe... -#define BSWAP64(x) ((htonl(x & 0xFFFFFFFF) << 32) | htonl(x >> 32)) -// Actually, we use ESAFExx() macros instead of this, and we use GCC to check the endianness... -// Actually, considering that "byteswap.h" doesn't exist elsewhere, the above -// is probably our best bet here. Just need to rename them to ESAFExx(). - -// Look at and see if that header is portable or not. uint16_t & memcon1 = *((uint16_t *)&jagMemSpace[0xF00000]); uint16_t & memcon2 = *((uint16_t *)&jagMemSpace[0xF00002]); @@ -196,7 +77,7 @@ uint32_t & g_pc = *((uint32_t *)&jagMemSpace[0xF02110]); uint32_t & g_ctrl = *((uint32_t *)&jagMemSpace[0xF02114]); uint32_t & g_hidata = *((uint32_t *)&jagMemSpace[0xF02118]); uint32_t & g_divctrl = *((uint32_t *)&jagMemSpace[0xF0211C]); -uint32_t g_remain; // Dual register with $F0211C +uint32_t g_remain; uint32_t & a1_base = *((uint32_t *)&jagMemSpace[0xF02200]); uint32_t & a1_flags = *((uint32_t *)&jagMemSpace[0xF02204]); uint32_t & a1_clip = *((uint32_t *)&jagMemSpace[0xF02208]); @@ -240,7 +121,7 @@ uint16_t & clk3 = *((uint16_t *)&jagMemSpace[0xF10014]); uint16_t & j_int = *((uint16_t *)&jagMemSpace[0xF10020]); uint16_t & asidata = *((uint16_t *)&jagMemSpace[0xF10030]); uint16_t & asictrl = *((uint16_t *)&jagMemSpace[0xF10032]); -uint16_t asistat; // Dual register with $F10032 +uint16_t asistat; uint16_t & asiclk = *((uint16_t *)&jagMemSpace[0xF10034]); uint16_t & joystick = *((uint16_t *)&jagMemSpace[0xF14000]); uint16_t & joybuts = *((uint16_t *)&jagMemSpace[0xF14002]); @@ -252,17 +133,12 @@ uint32_t & d_pc = *((uint32_t *)&jagMemSpace[0xF1A110]); uint32_t & d_ctrl = *((uint32_t *)&jagMemSpace[0xF1A114]); uint32_t & d_mod = *((uint32_t *)&jagMemSpace[0xF1A118]); uint32_t & d_divctrl = *((uint32_t *)&jagMemSpace[0xF1A11C]); -uint32_t d_remain; // Dual register with $F0211C +uint32_t d_remain; uint32_t & d_machi = *((uint32_t *)&jagMemSpace[0xF1A120]); uint16_t & ltxd = *((uint16_t *)&jagMemSpace[0xF1A148]); -uint16_t lrxd; // Dual register with $F1A148 +uint16_t lrxd; uint16_t & rtxd = *((uint16_t *)&jagMemSpace[0xF1A14C]); -uint16_t rrxd; // Dual register with $F1A14C +uint16_t rrxd; uint8_t & sclk = *((uint8_t *) &jagMemSpace[0xF1A150]); -uint8_t sstat; // Dual register with $F1A150 +uint8_t sstat; uint32_t & smode = *((uint32_t *)&jagMemSpace[0xF1A154]); - -// Memory debugging identifiers - -const char * whoName[10] = - { "Unknown", "Jaguar", "DSP", "GPU", "TOM", "JERRY", "M68K", "Blitter", "OP", "Debugger" }; diff --git a/waterbox/virtualjaguar/src/memory.h b/waterbox/virtualjaguar/src/memory.h index 0f84b7afcd..3efb27885e 100644 --- a/waterbox/virtualjaguar/src/memory.h +++ b/waterbox/virtualjaguar/src/memory.h @@ -16,13 +16,9 @@ extern uint8_t * jaguarMainROM; extern uint8_t * gpuRAM; extern uint8_t * dspRAM; -#if 1 extern uint32_t & butch, & dscntrl; extern uint16_t & ds_data; extern uint32_t & i2cntrl, & sbcntrl, & subdata, & subdatb, & sb_time, & fifo_data, & i2sdat2, & unknown; -#else -extern uint32_t butch, dscntrl, ds_data, i2cntrl, sbcntrl, subdata, subdatb, sb_time, fifo_data, i2sdat2, unknown; -#endif extern uint16_t & memcon1, & memcon2, & hc, & vc, & lph, & lpv; extern uint64_t & obData; @@ -53,156 +49,17 @@ extern uint32_t & d_machi; extern uint16_t & ltxd, lrxd, & rtxd, rrxd; extern uint8_t & sclk, sstat; extern uint32_t & smode; -/* -uint16_t & ltxd = *((uint16_t *)&jagMemSpace[0xF1A148]); -uint16_t lrxd; // Dual register with $F1A148 -uint16_t & rtxd = *((uint16_t *)&jagMemSpace[0xF1A14C]); -uint16_t rrxd; // Dual register with $F1A14C -uint8_t & sclk = *((uint8_t *) &jagMemSpace[0xF1A150]); -uint8_t sstat; // Dual register with $F1A150 -uint32_t & smode = *((uint32_t *)&jagMemSpace[0xF1A154]); -*/ - -// Read/write tracing enumeration enum { UNKNOWN, JAGUAR, DSP, GPU, TOM, JERRY, M68K, BLITTER, OP, DEBUG }; -extern const char * whoName[10]; -// BIOS identification enum - -//enum { BIOS_NORMAL=0x01, BIOS_CD=0x02, BIOS_STUB1=0x04, BIOS_STUB2=0x08, BIOS_DEV_CD=0x10 }; -//extern int biosAvailable; - -// Some handy macros to help converting native endian to big endian (jaguar native) +// Some handy macros to help converting little endian to big endian (jaguar native) // & vice versa -#define SET64(r, a, v) r[(a)] = ((v) & 0xFF00000000000000) >> 56, r[(a)+1] = ((v) & 0x00FF000000000000) >> 48, \ - r[(a)+2] = ((v) & 0x0000FF0000000000) >> 40, r[(a)+3] = ((v) & 0x000000FF00000000) >> 32, \ - r[(a)+4] = ((v) & 0xFF000000) >> 24, r[(a)+5] = ((v) & 0x00FF0000) >> 16, \ - r[(a)+6] = ((v) & 0x0000FF00) >> 8, r[(a)+7] = (v) & 0x000000FF -#define GET64(r, a) (((uint64_t)r[(a)] << 56) | ((uint64_t)r[(a)+1] << 48) | \ - ((uint64_t)r[(a)+2] << 40) | ((uint64_t)r[(a)+3] << 32) | \ - ((uint64_t)r[(a)+4] << 24) | ((uint64_t)r[(a)+5] << 16) | \ - ((uint64_t)r[(a)+6] << 8) | (uint64_t)r[(a)+7]) -#define SET32(r, a, v) r[(a)] = ((v) & 0xFF000000) >> 24, r[(a)+1] = ((v) & 0x00FF0000) >> 16, \ - r[(a)+2] = ((v) & 0x0000FF00) >> 8, r[(a)+3] = (v) & 0x000000FF -#define GET32(r, a) ((r[(a)] << 24) | (r[(a)+1] << 16) | (r[(a)+2] << 8) | r[(a)+3]) -#define SET16(r, a, v) r[(a)] = ((v) & 0xFF00) >> 8, r[(a)+1] = (v) & 0xFF -#define GET16(r, a) ((r[(a)] << 8) | r[(a)+1]) - -//This doesn't seem to work on OSX. So have to figure something else out. :-( -//byteswap.h doesn't exist on OSX. -#if 0 -// This is GCC specific, but we can fix that if we need to... -// Big plus of this approach is that these compile down to single instructions on little -// endian machines while one big endian machines we don't have any overhead. :-) - -#include -#include - -#if __BYTE_ORDER == __LITTLE_ENDIAN - #define ESAFE16(x) bswap_16(x) - #define ESAFE32(x) bswap_32(x) - #define ESAFE64(x) bswap_64(x) -#else - #define ESAFE16(x) (x) - #define ESAFE32(x) (x) - #define ESAFE64(x) (x) -#endif -#endif - -#if 0 -Stuff ripped out of Hatari, that may be useful: - -/* Can the actual CPU access unaligned memory? */ -#ifndef CPU_CAN_ACCESS_UNALIGNED -# if defined(__i386__) || defined(powerpc) || defined(__mc68020__) -# define CPU_CAN_ACCESS_UNALIGNED 1 -# else -# define CPU_CAN_ACCESS_UNALIGNED 0 -# endif -#endif - - -/* If the CPU can access unaligned memory, use these accelerated functions: */ -#if CPU_CAN_ACCESS_UNALIGNED - -#include - - -static inline uae_u32 do_get_mem_long(void *a) -{ - return SDL_SwapBE32(*(uae_u32 *)a); -} - -static inline uae_u16 do_get_mem_word(void *a) -{ - return SDL_SwapBE16(*(uae_u16 *)a); -} - - -static inline void do_put_mem_long(void *a, uae_u32 v) -{ - *(uae_u32 *)a = SDL_SwapBE32(v); -} - -static inline void do_put_mem_word(void *a, uae_u16 v) -{ - *(uae_u16 *)a = SDL_SwapBE16(v); -} - - -#else /* Cpu can not access unaligned memory: */ - - -static inline uae_u32 do_get_mem_long(void *a) -{ - uae_u8 *b = (uae_u8 *)a; - - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; -} - -static inline uae_u16 do_get_mem_word(void *a) -{ - uae_u8 *b = (uae_u8 *)a; - - return (b[0] << 8) | b[1]; -} - - -static inline void do_put_mem_long(void *a, uae_u32 v) -{ - uae_u8 *b = (uae_u8 *)a; - - b[0] = v >> 24; - b[1] = v >> 16; - b[2] = v >> 8; - b[3] = v; -} - -static inline void do_put_mem_word(void *a, uae_u16 v) -{ - uae_u8 *b = (uae_u8 *)a; - - b[0] = v >> 8; - b[1] = v; -} - - -#endif /* CPU_CAN_ACCESS_UNALIGNED */ - - -/* These are same for all architectures: */ - -static inline uae_u8 do_get_mem_byte(uae_u8 *a) -{ - return *a; -} - -static inline void do_put_mem_byte(uae_u8 *a, uae_u8 v) -{ - *a = v; -} -#endif +#define SET64(r, a, v) *(uint64_t*)&r[(a)] = __builtin_bswap64((v)) +#define GET64(r, a) (__builtin_bswap64(*(uint64_t*)&r[(a)])) +#define SET32(r, a, v) *(uint32_t*)&r[(a)] = __builtin_bswap32((v)) +#define GET32(r, a) (__builtin_bswap32(*(uint32_t*)&r[(a)])) +#define SET16(r, a, v) *(uint16_t*)&r[(a)] = __builtin_bswap16((v)) +#define GET16(r, a) (__builtin_bswap16(*(uint16_t*)&r[(a)])) #endif // __MEMORY_H__ diff --git a/waterbox/virtualjaguar/src/memtrack.cpp b/waterbox/virtualjaguar/src/memtrack.cpp index cc9daabc63..cc26f7abc2 100644 --- a/waterbox/virtualjaguar/src/memtrack.cpp +++ b/waterbox/virtualjaguar/src/memtrack.cpp @@ -25,12 +25,6 @@ #include #include -#include -#include - - -#define MEMTRACK_FILENAME "memtrack.eeprom" -//#define DEBUG_MEMTRACK enum { MT_NONE, MT_PROD_ID, MT_RESET, MT_WRITE_ENABLE }; enum { MT_IDLE, MT_PHASE1, MT_PHASE2 }; @@ -38,66 +32,22 @@ enum { MT_IDLE, MT_PHASE1, MT_PHASE2 }; uint8_t mtMem[0x20000]; uint8_t mtCommand = MT_NONE; uint8_t mtState = MT_IDLE; -bool haveMT = false; -char mtFilename[MAX_PATH]; -// Private function prototypes -void MTWriteFile(void); void MTStateMachine(uint8_t reg, uint16_t data); - void MTInit(void) { - sprintf(mtFilename, "%s%s", vjs.EEPROMPath, MEMTRACK_FILENAME); - FILE * fp = fopen(mtFilename, "rb"); - - if (fp) - { - size_t ignored = fread(mtMem, 1, 0x20000, fp); - fclose(fp); - WriteLog("MT: Loaded NVRAM from %s\n", mtFilename); - haveMT = true; - } - else - WriteLog("MT: Could not open file \"%s\"!\n", mtFilename); + memset(mtMem, 0xFF, 0x20000); } - void MTReset(void) { - if (!haveMT) - memset(mtMem, 0xFF, 0x20000); } - void MTDone(void) { - MTWriteFile(); - WriteLog("MT: Done.\n"); } - -void MTWriteFile(void) -{ - if (!haveMT) - return; - - FILE * fp = fopen(mtFilename, "wb"); - - if (fp) - { - fwrite(mtMem, 1, 0x20000, fp); - fclose(fp); - } - else - WriteLog("MT: Could not create file \"%s\"!", mtFilename); -} - - -// -// This is crappy, there doesn't seem to be a word interface to the NVRAM. But -// we'll keep this as a placeholder for now. -// uint16_t MTReadWord(uint32_t addr) { uint32_t value = MTReadLong(addr); @@ -107,14 +57,9 @@ uint16_t MTReadWord(uint32_t addr) else if ((addr & 0x03) == 2) value &= 0xFFFF; -#ifdef DEBUG_MEMTRACK -WriteLog("MT: Reading word @ $%06X: $%04X\n", addr, value); -#endif - return (uint16_t)value; } - uint32_t MTReadLong(uint32_t addr) { uint32_t value = 0; @@ -131,30 +76,17 @@ uint32_t MTReadLong(uint32_t addr) value = (uint32_t)mtMem[(addr & 0x7FFFC) >> 2]; } - // We do this because we're not sure how the real thing behaves; but it - // seems reasonable on its face to do it this way. :-P So we turn off write - // mode when reading the NVRAM. if (mtCommand == MT_WRITE_ENABLE) mtCommand = MT_NONE; -#ifdef DEBUG_MEMTRACK -WriteLog("MT: Reading long @ $%06X: $%08X\n", addr, value << 16); -#endif return value << 16; } - void MTWriteWord(uint32_t addr, uint16_t data) { - // We don't care about writes to long offsets + 2 if ((addr & 0x3) == 2) return; -#ifdef DEBUG_MEMTRACK -WriteLog("MT: Writing word @ $%06X: $%04X (Writing is %sabled)\n", addr, data, (mtCommand == MT_WRITE_ENABLE ? "en" : "dis")); -#endif - - // Write to the NVRAM if it's enabled... if (mtCommand == MT_WRITE_ENABLE) { mtMem[(addr & 0x7FFFC) >> 2] = (uint8_t)(data & 0xFF); @@ -163,63 +95,53 @@ WriteLog("MT: Writing word @ $%06X: $%04X (Writing is %sabled)\n", addr, data, ( switch (addr) { - case (0x800000 + (4 * 0x5555)): // $815554 - MTStateMachine(0, data); - break; - case (0x800000 + (4 * 0x2AAA)): // $80AAA8 - MTStateMachine(1, data); - break; + case (0x800000 + (4 * 0x5555)): + MTStateMachine(0, data); + break; + case (0x800000 + (4 * 0x2AAA)): + MTStateMachine(1, data); + break; } } - void MTWriteLong(uint32_t addr, uint32_t data) { - // Strip off lower 3 bits of the passed in address addr &= 0xFFFFFC; MTWriteWord(addr + 0, data & 0xFFFF); MTWriteWord(addr + 2, data >> 16); } - void MTStateMachine(uint8_t reg, uint16_t data) { -#ifdef DEBUG_MEMTRACK -WriteLog("MTStateMachine: reg = %u, data = $%02X, current state = %u\n", reg, data, mtState); -#endif switch (mtState) { - case MT_IDLE: - if ((reg == 0) && (data == 0xAA)) - mtState = MT_PHASE1; + case MT_IDLE: + if ((reg == 0) && (data == 0xAA)) + mtState = MT_PHASE1; - break; - case MT_PHASE1: - if ((reg == 1) && (data == 0x55)) - mtState = MT_PHASE2; - else - mtState = MT_IDLE; - - break; - case MT_PHASE2: - if (reg == 0) - { - if (data == 0x90) // Product ID - mtCommand = MT_PROD_ID; - else if (data == 0xF0) // Reset - mtCommand = MT_NONE; - else if (data == 0xA0) // Write enagle - mtCommand = MT_WRITE_ENABLE; + break; + case MT_PHASE1: + if ((reg == 1) && (data == 0x55)) + mtState = MT_PHASE2; else - mtCommand = MT_NONE; - } + mtState = MT_IDLE; - mtState = MT_IDLE; - break; + break; + case MT_PHASE2: + if (reg == 0) + { + if (data == 0x90) + mtCommand = MT_PROD_ID; + else if (data == 0xF0) + mtCommand = MT_NONE; + else if (data == 0xA0) + mtCommand = MT_WRITE_ENABLE; + else + mtCommand = MT_NONE; + } + + mtState = MT_IDLE; + break; } -#ifdef DEBUG_MEMTRACK -WriteLog(" state = %u, cmd = %u\n", mtState, mtCommand); -#endif } - diff --git a/waterbox/virtualjaguar/src/memtrack.h b/waterbox/virtualjaguar/src/memtrack.h index d6eb036cdb..e4d4ab1376 100644 --- a/waterbox/virtualjaguar/src/memtrack.h +++ b/waterbox/virtualjaguar/src/memtrack.h @@ -12,4 +12,3 @@ uint16_t MTReadWord(uint32_t addr); uint32_t MTReadLong(uint32_t addr); void MTWriteWord(uint32_t addr, uint16_t data); void MTWriteLong(uint32_t addr, uint32_t data); - diff --git a/waterbox/virtualjaguar/src/mmu.cpp b/waterbox/virtualjaguar/src/mmu.cpp deleted file mode 100644 index a33f0b225f..0000000000 --- a/waterbox/virtualjaguar/src/mmu.cpp +++ /dev/null @@ -1,608 +0,0 @@ -// -// mmu.cpp -// -// Jaguar Memory Manager Unit -// -// by James Hammons -// -// JLH = James Hammons -// -// WHO WHEN WHAT -// --- ---------- ----------------------------------------------------------- -// JLH 11/25/2009 Created this file. :-) -// - -#include "mmu.h" - -#include // For NULL definition -#include "dac.h" -//#include "jaguar.h" -//#include "memory.h" -//#include "jagbios.h" -#include "wavetable.h" - -/* -Addresses to be handled: - -SYSTEM SETUP REGISTERS - -*MEMCON1 Memory Control Register 1 F00000 RW -*MEMCON2 Memory Control Register 2 F00002 RW -HC Horizontal Count F00004 RW -VC Vertical Count F00006 RW -LPH Light Pen Horizontal F00008 RO -LPV Light Pen Vertical F0000A RO -OB[0-3] Object Data Field F00010-16 RO -OLP Object List Pointer F00020-23 WO -OBF Object Flag F00026 WO -VMODE Video Mode F00028 WO -BORD1 Border Colour (Red & Green) F0002A WO -BORD2 Border Colour (Blue) F0002C WO -*HP Horizontal Period F0002E WO -*HBB Horizontal Blank Begin F00030 WO -*HBE Horizontal Blank End F00032 WO -*HS Horizontal Sync F00034 WO -*HVS Horizontal Vertical Sync F00036 WO -HDB1 Horizontal Display Begin 1 F00038 WO -HDB2 Horizontal Display Begin 2 F0003A WO -HDE Horizontal Display End F0003C WO -*VP Vertical Period F0003E WO -*VBB Vertical Blank Begin F00040 WO -*VBE Vertical Blank End F00042 WO -*VS Vertical Sync F00044 WO -VDB Vertical Display Begin F00046 WO -VDE Vertical Display End F00048 WO -*VEB Vertical Equalization Begin F0004A WO -*VEE Vertical Equalization End F0004C WO -VI Vertical Interrupt F0004E WO -PIT[0-1] Programmable Interrupt Timer F00050-52 WO -*HEQ Horizontal Equalization End F00054 WO -BG Background Colour F00058 WO -INT1 CPU Interrupt Control Register F000E0 RW -INT2 CPU Interrupt Resume Register F000E2 WO -CLUT Colour Look-Up Table F00400-7FE RW -LBUF Line Buffer F00800-1D9E RW - -GPU REGISTERS - -G_FLAGS GPU Flags Register F02100 RW -G_MTXC Matrix Control Register F02104 WO -G_MTXA Matrix Address Register F02108 WO -G_END Data Organization Register F0210C WO -G_PC GPU Program Counter F02110 RW -G_CTRL GPU Control/Status Register F02114 RW -G_HIDATA High Data Register F02118 RW -G_REMAIN Divide Unit Remainder F0211C RO -G_DIVCTRL Divide Unit Control F0211C WO - -BLITTER REGISTERS - -A1_BASE A1 Base Register F02200 WO -A1_FLAGS Flags Register F02204 WO -A1_CLIP A1 Clipping Size F02208 WO -A1_PIXEL A1 Pixel Pointer F0220C WO - F02204 RO -A1_STEP A1 Step Value F02210 WO -A1_FSTEP A1 Step Fraction Value F02214 WO -A1_FPIXEL A1 Pixel Pointer Fraction F02218 RW -A1_INC A1 Increment F0221C WO -A1_FINC A1 Increment Fraction F02220 WO -A2_BASE A2 Base Register F02224 WO -A2_FLAGS A2 Flags Register F02228 WO -A2_MASK A2 Window Mask F0222C WO -A2_PIXEL A2 Pixel Pointer F02230 WO - F0222C RO -A2_STEP A2 Step Value F02234 WO -B_CMD Command/Status Register F02238 RW -B_COUNT Counters Register F0223C WO -B_SRCD Source Data Register F02240 WO -B_DSTD Destination Data Register F02248 WO -B_DSTZ Destination Z Register F02250 WO -B_SRCZ1 Source Z Register 1 F02258 WO -B_SRCZ2 Source Z Register 2 F02260 WO -B_PATD Pattern Data Register F02268 WO -B_IINC Intensity Increment F02270 WO -B_ZINC Z Increment F02274 WO -B_STOP Collision Control F02278 WO -B_I3 Intensity 3 F0227C WO -B_I2 Intensity 2 F02280 WO -B_I1 Intensity 1 F02284 WO -B_I0 Intensity 0 F02288 WO -B_Z3 Z 3 F0228C WO -B_Z2 Z 2 F02290 WO -B_Z1 Z 1 F02294 WO -B_Z0 Z 0 F02298 WO - -JERRY REGISTERS - -*CLK1 Processor Clock Divider F10010 WO -*CLK2 Video Clock Divider F10012 WO -*CLK3 Chroma Clock Divider F10014 WO -JPIT1 Timer 1 Pre-scaler F10000 WO -JPIT3 Timer 2 Pre-scaler F10004 WO -JPIT2 Timer 1 Divider F10002 WO -JPIT4 Timer 2 Divider F10006 WO -J_INT Interrup Control Register F10020 RW -SCLK Serial Clock Frequency F1A150 WO -SMODE Serial Mode F1A154 WO -LTXD Left Transmit Data F1A148 WO -RTXD Right Transmit Data F1A14C WO -LRXD Left Receive Data F1A148 RO -RRXD Right Receive Data F1A14C RO -L_I2S Left I2S Serial Interface F1A148 RW -R_I2S Right I2S Serial Interface F1A14C RW -SSTAT Serial Status F1A150 RO -ASICLK Asynchronous Serial Interface Clock F10034 RW -ASICTRL Asynchronous Serial Control F10032 WO -ASISTAT Asynchronous Serial Status F10032 RO -ASIDATA Asynchronous Serial Data F10030 RW - -JOYSTICK REGISTERS - -JOYSTICK Joystick Register F14000 RW -JOYBUTS Button Register F14002 RW - -DSP REGISTERS - -D_FLAGS DSP Flags Register F1A100 RW -D_MTXC DSP Matrix Control Register F1A104 WO -D_MTXA DSP Matrix Address Register F1A108 WO -D_END DSP Data Organization Register F1A10C WO -D_PC DSP Program Counter F1A110 RW -D_CTRL DSP Control/Status Register F1A114 RW -D_MOD Modulo Instruction Mask F1A118 WO -D_REMAIN Divide Unit Remainder F1A11C RO -D_DIVCTRL Divide Unit Control F1A11C WO -D_MACHI MAC High Result Bits F1A120 RO -*/ - -/* -The approach here is to have a list of addresses and who handles them. Could be -a one-to-one memory location up to a range for each function. Will look -something like this: - - { 0xF14000, 0xF14001, MM_IO, JoystickReadHandler, JoystickWriteHandler }, - -Would be nice to have a way of either calling a handler function or reading/writing -directly to/from a variable or array... -*/ - -enum MemType { MM_NOP = 0, MM_RAM = 1, MM_ROM = 2, MM_IO_R = 4, MM_IO_W = 8, MM_IO = 12 }; - -/* -Would be nice to have different structs tailored to different memory access types, -but if we don't do that, we can encode things as follows: - -MM_NOP: readFunc = writeFunc = NULL -MM_RAM: readFunc = byte array pointer, writeFunc = NULL -MM_ROM: readFunc = byte array pointer, writeFunc = NULL -MM_IO_R: readFunc = function pointer to read function, writeFunc = NULL -MM_IO_W: readFunc = NULL, writeFunc = function pointer to write function -MM_IO: readFunc = function pointer to read function, writeFunc = function pointer to write function - -There may be a need to have readFunc do both read & write functions (makes sense? perhaps) - -Should we have a read mask as well, for the purposes of reading? -*/ - -struct MemDesc { - uint32_t startAddr; - uint32_t endAddr; - MemType type; -// (void (* ioFunc)(uint32, uint32)); // <-- could also be a pointer to RAM... - void * readFunc; // This is read & write with MM_IO - void * writeFunc; - uint32_t mask; -}; - - -MemDesc memoryMap[] = { - { 0x000000, 0x1FFFFF, MM_RAM, jaguarMainRAM }, - { 0x200000, 0x3FFFFF, MM_RAM, jaguarMainRAM }, // Mirror of 1st 2 megs - { 0x400000, 0x5FFFFF, MM_RAM, jaguarMainRAM }, // " " - { 0x600000, 0x7FFFFF, MM_RAM, jaguarMainRAM }, // " " - { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM }, - - { 0xDFFF00, 0xDFFF03, MM_IO, &butch }, // base of Butch == interrupt control register, R/W - { 0xDFFF04, 0xDFFF07, MM_IO, &dscntrl }, // DSA control register, R/W - { 0xDFFF0A, 0xDFFF0B, MM_IO, &ds_data }, // DSA TX/RX data, R/W - { 0xDFFF10, 0xDFFF13, MM_IO, &i2cntrl }, // i2s bus control register, R/W - { 0xDFFF14, 0xDFFF17, MM_IO, &sbcntrl }, // CD subcode control register, R/W - { 0xDFFF18, 0xDFFF1B, MM_IO, &subdata }, // Subcode data register A - { 0xDFFF1C, 0xDFFF1F, MM_IO, &subdatb }, // Subcode data register B - { 0xDFFF20, 0xDFFF23, MM_IO, &sb_time }, // Subcode time and compare enable (D24) - { 0xDFFF24, 0xDFFF27, MM_IO, &fifo_data }, // i2s FIFO data - { 0xDFFF28, 0xDFFF2B, MM_IO, &i2sdat2 }, // i2s FIFO data (old) - { 0xDFFF2C, 0xDFFF2F, MM_IO, &unknown }, // Seems to be some sort of I2S interface - - //{ 0xE00000, 0xE1FFFF, MM_ROM, jaguarBootROM }, - - // TOM REGISTERS - - { 0xF00000, 0xF00001, MM_IO, &memcon1 }, // *MEMCON1 Memory Control Register 1 F00000 RW - { 0xF00002, 0xF00003, MM_IO, &memcon2 }, // *MEMCON2 Memory Control Register 2 F00002 RW - { 0xF00004, 0xF00005, MM_IO, &hc }, // HC Horizontal Count F00004 RW - { 0xF00006, 0xF00007, MM_IO, &vc }, // VC Vertical Count F00006 RW - { 0xF00008, 0xF00009, MM_IO_R, &lph }, // LPH Light Pen Horizontal F00008 RO - { 0xF0000A, 0xF0000B, MM_IO_R, &lpv }, // LPV Light Pen Vertical F0000A RO - { 0xF00010, 0xF00017, MM_IO_R, &obData }, // OB[0-3] Object Data Field F00010-16 RO - { 0xF00020, 0xF00023, MM_IO_W, &olp }, // OLP Object List Pointer F00020-23 WO - { 0xF00026, 0xF00027, MM_IO_W, &obf }, // OBF Object Flag F00026 WO - { 0xF00028, 0xF00029, MM_IO_W, &vmode }, // VMODE Video Mode F00028 WO - { 0xF0002A, 0xF0002B, MM_IO_W, &bord1 }, // BORD1 Border Colour (Red & Green) F0002A WO - { 0xF0002C, 0xF0002D, MM_IO_W, &bord2 }, // BORD2 Border Colour (Blue) F0002C WO - { 0xF0002E, 0xF0002F, MM_IO_W, &hp }, // *HP Horizontal Period F0002E WO - { 0xF00030, 0xF00031, MM_IO_W, &hbb }, // *HBB Horizontal Blank Begin F00030 WO - { 0xF00032, 0xF00033, MM_IO_W, &hbe }, // *HBE Horizontal Blank End F00032 WO - { 0xF00034, 0xF00035, MM_IO_W, &hs }, // *HS Horizontal Sync F00034 WO - { 0xF00036, 0xF00037, MM_IO_W, &hvs }, // *HVS Horizontal Vertical Sync F00036 WO - { 0xF00038, 0xF00039, MM_IO_W, &hdb1 }, // HDB1 Horizontal Display Begin 1 F00038 WO - { 0xF0003A, 0xF0003B, MM_IO_W, &hdb2 }, // HDB2 Horizontal Display Begin 2 F0003A WO - { 0xF0003C, 0xF0003D, MM_IO_W, &hde }, // HDE Horizontal Display End F0003C WO - { 0xF0003E, 0xF0003F, MM_IO_W, &vp }, // *VP Vertical Period F0003E WO - { 0xF00040, 0xF00041, MM_IO_W, &vbb }, // *VBB Vertical Blank Begin F00040 WO - { 0xF00042, 0xF00043, MM_IO_W, &vbe }, // *VBE Vertical Blank End F00042 WO - { 0xF00044, 0xF00045, MM_IO_W, &vs }, // *VS Vertical Sync F00044 WO - { 0xF00046, 0xF00047, MM_IO_W, &vdb }, // VDB Vertical Display Begin F00046 WO - { 0xF00048, 0xF00049, MM_IO_W, &vde }, // VDE Vertical Display End F00048 WO - { 0xF0004A, 0xF0004B, MM_IO_W, &veb }, // *VEB Vertical Equalization Begin F0004A WO - { 0xF0004C, 0xF0004D, MM_IO_W, &vee }, // *VEE Vertical Equalization End F0004C WO - { 0xF0004E, 0xF0004F, MM_IO_W, &vi }, // VI Vertical Interrupt F0004E WO - { 0xF00050, 0xF00051, MM_IO_W, &pit0 }, // PIT[0-1] Programmable Interrupt Timer F00050-52 WO - { 0xF00052, 0xF00053, MM_IO_W, &pit1 }, - { 0xF00054, 0xF00055, MM_IO_W, &heq }, // *HEQ Horizontal Equalization End F00054 WO - { 0xF00058, 0xF0005B, MM_IO_W, &bg }, // BG Background Colour F00058 WO - { 0xF000E0, 0xF000E1, MM_IO, &int1 }, // INT1 CPU Interrupt Control Register F000E0 RW - { 0xF000E2, 0xF000E3, MM_IO_W, &int2 }, // INT2 CPU Interrupt Resume Register F000E2 WO -//Some of these RAM spaces may be 16- or 32-bit only... in which case, we need -//to cast appropriately (in memory.cpp, that is)... - { 0xF00400, 0xF005FF, MM_RAM, clut }, // CLUT Colour Look-Up Table F00400-7FE RW - { 0xF00600, 0xF007FF, MM_RAM, clut }, - { 0xF00800, 0xF01D9F, MM_RAM, lbuf }, // LBUF Line Buffer F00800-1D9E RW -//Need high speed RAM interface for GPU & DSP (we have it now...) - - // GPU REGISTERS - - { 0xF02100, 0xF02103, MM_IO, &g_flags }, // G_FLAGS GPU Flags Register F02100 RW - { 0xF02104, 0xF02107, MM_IO_W, &g_mtxc }, // G_MTXC Matrix Control Register F02104 WO - { 0xF02108, 0xF0210B, MM_IO_W, &g_mtxa }, // G_MTXA Matrix Address Register F02108 WO - { 0xF0210C, 0xF0210F, MM_IO_W, &g_end }, // G_END Data Organization Register F0210C WO - { 0xF02110, 0xF02113, MM_IO, &g_pc }, // G_PC GPU Program Counter F02110 RW - { 0xF02114, 0xF02117, MM_IO, &g_ctrl }, // G_CTRL GPU Control/Status Register F02114 RW - { 0xF02118, 0xF0211B, MM_IO, &g_hidata }, // G_HIDATA High Data Register F02118 RW - { 0xF0211C, 0xF0211F, MM_IO, &g_remain, &g_divctrl }, // G_REMAIN Divide Unit Remainder F0211C RO - // G_DIVCTRL Divide Unit Control F0211C WO - { 0xF03000, 0xF03FFF, MM_RAM, gpuRAM }, - - // BLITTER REGISTERS - - { 0xF02200, 0xF02203, MM_IO_W, &a1_base }, // A1_BASE A1 Base Register F02200 WO - { 0xF02204, 0xF02207, MM_IO, &a1_pixel, &a1_flags }, // A1_FLAGS Flags Register F02204 WO - { 0xF02208, 0xF0220B, MM_IO_W, &a1_clip }, // A1_CLIP A1 Clipping Size F02208 WO - { 0xF0220C, 0xF0220F, MM_IO_W, &a1_pixel }, // A1_PIXEL A1 Pixel Pointer F0220C WO -// F02204 RO - { 0xF02210, 0xF02213, MM_IO_W, &a1_step }, // A1_STEP A1 Step Value F02210 WO - { 0xF02214, 0xF02217, MM_IO_W, &a1_fstep }, // A1_FSTEP A1 Step Fraction Value F02214 WO - { 0xF02218, 0xF0221B, MM_IO, &a1_fpixel }, // A1_FPIXEL A1 Pixel Pointer Fraction F02218 RW - { 0xF0221C, 0xF0221F, MM_IO_W, &a1_inc }, // A1_INC A1 Increment F0221C WO - { 0xF02220, 0xF02223, MM_IO_W, &a1_finc }, // A1_FINC A1 Increment Fraction F02220 WO - { 0xF02224, 0xF02227, MM_IO_W, &a2_base }, // A2_BASE A2 Base Register F02224 WO - { 0xF02228, 0xF0222B, MM_IO_W, &a2_flags }, // A2_FLAGS A2 Flags Register F02228 WO - { 0xF0222C, 0xF0222F, MM_IO, &a2_pixel, &a2_mask }, // A2_MASK A2 Window Mask F0222C WO - { 0xF02230, 0xF02233, MM_IO_W, &a2_pixel }, // A2_PIXEL A2 Pixel Pointer F02230 WO -// F0222C RO - { 0xF02234, 0xF02237, MM_IO_W, &a2_step }, // A2_STEP A2 Step Value F02234 WO - { 0xF02238, 0xF0223B, MM_IO, &b_cmd }, // B_CMD Command/Status Register F02238 RW - { 0xF0223C, 0xF0223F, MM_IO_W, &b_count }, // B_COUNT Counters Register F0223C WO - { 0xF02240, 0xF02247, MM_IO_W, &b_srcd }, // B_SRCD Source Data Register F02240 WO - { 0xF02248, 0xF0224F, MM_IO_W, &b_dstd }, // B_DSTD Destination Data Register F02248 WO - { 0xF02250, 0xF02258, MM_IO_W, &b_dstz }, // B_DSTZ Destination Z Register F02250 WO - { 0xF02258, 0xF0225F, MM_IO_W, &b_srcz1 }, // B_SRCZ1 Source Z Register 1 F02258 WO - { 0xF02260, 0xF02267, MM_IO_W, &b_srcz2 }, // B_SRCZ2 Source Z Register 2 F02260 WO - { 0xF02268, 0xF0226F, MM_IO_W, &b_patd }, // B_PATD Pattern Data Register F02268 WO - { 0xF02270, 0xF02273, MM_IO_W, &b_iinc }, // B_IINC Intensity Increment F02270 WO - { 0xF02274, 0xF02277, MM_IO_W, &b_zinc }, // B_ZINC Z Increment F02274 WO - { 0xF02278, 0xF0227B, MM_IO_W, &b_stop }, // B_STOP Collision Control F02278 WO - { 0xF0227C, 0xF0227F, MM_IO_W, &b_i3 }, // B_I3 Intensity 3 F0227C WO - { 0xF02280, 0xF02283, MM_IO_W, &b_i2 }, // B_I2 Intensity 2 F02280 WO - { 0xF02284, 0xF02287, MM_IO_W, &b_i1 }, // B_I1 Intensity 1 F02284 WO - { 0xF02288, 0xF0228B, MM_IO_W, &b_i0 }, // B_I0 Intensity 0 F02288 WO - { 0xF0228C, 0xF0228F, MM_IO_W, &b_z3 }, // B_Z3 Z 3 F0228C WO - { 0xF02290, 0xF02293, MM_IO_W, &b_z2 }, // B_Z2 Z 2 F02290 WO - { 0xF02294, 0xF02297, MM_IO_W, &b_z1 }, // B_Z1 Z 1 F02294 WO - { 0xF02298, 0xF0229B, MM_IO_W, &b_z0 }, // B_Z0 Z 0 F02298 WO - -// JTRM sez ALL GPU address space is accessible from $8000 offset as "fast" 32-bit WO access -// Dunno if anything actually USED it tho... :-P - { 0xF0A100, 0xF0A103, MM_IO_W, &g_flags }, // G_FLAGS GPU Flags Register F02100 RW - { 0xF0A104, 0xF0A107, MM_IO_W, &g_mtxc }, // G_MTXC Matrix Control Register F02104 WO - { 0xF0A108, 0xF0A10B, MM_IO_W, &g_mtxa }, // G_MTXA Matrix Address Register F02108 WO - { 0xF0A10C, 0xF0A10F, MM_IO_W, &g_end }, // G_END Data Organization Register F0210C WO - { 0xF0A110, 0xF0A113, MM_IO_W, &g_pc }, // G_PC GPU Program Counter F02110 RW - { 0xF0A114, 0xF0A117, MM_IO_W, &g_ctrl }, // G_CTRL GPU Control/Status Register F02114 RW - { 0xF0A118, 0xF0A11B, MM_IO_W, &g_hidata }, // G_HIDATA High Data Register F02118 RW - { 0xF0A11C, 0xF0A11F, MM_IO_W, &g_divctrl }, // G_REMAIN Divide Unit Remainder F0211C RO - { 0xF0B000, 0xF0BFFF, MM_IO_W, gpuRAM }, // "Fast" interface to GPU RAM - - // JERRY REGISTERS - - { 0xF10000, 0xF10001, MM_IO_W, &jpit1 }, // JPIT1 Timer 1 Pre-scaler F10000 WO - { 0xF10002, 0xF10003, MM_IO_W, &jpit2 }, // JPIT2 Timer 1 Divider F10002 WO - { 0xF10004, 0xF10005, MM_IO_W, &jpit3 }, // JPIT3 Timer 2 Pre-scaler F10004 WO - { 0xF10006, 0xF10007, MM_IO_W, &jpit4 }, // JPIT4 Timer 2 Divider F10006 WO - { 0xF10010, 0xF10011, MM_IO_W, &clk1 }, // *CLK1 Processor Clock Divider F10010 WO - { 0xF10012, 0xF10013, MM_IO_W, &clk2 }, // *CLK2 Video Clock Divider F10012 WO - { 0xF10014, 0xF10015, MM_IO_W, &clk3 }, // *CLK3 Chroma Clock Divider F10014 WO - { 0xF10020, 0xF10021, MM_IO, &j_int }, // J_INT Interrup Control Register F10020 RW - { 0xF10030, 0xF10031, MM_IO, &asidata }, // ASIDATA Asynchronous Serial Data F10030 RW - { 0xF10032, 0xF10033, MM_IO, &asistat, &asictrl }, // ASICTRL Asynchronous Serial Control F10032 WO - // ASISTAT Asynchronous Serial Status F10032 RO - { 0xF10034, 0xF10035, MM_IO, &asiclk }, // ASICLK Asynchronous Serial Interface Clock F10034 RW - { 0xF10036, 0xF10037, MM_IO_R, &jpit1 }, // JPIT1 Timer 1 Pre-scaler F10036 RO - { 0xF10038, 0xF10039, MM_IO_R, &jpit2 }, // JPIT2 Timer 1 Divider F10038 RO - { 0xF1003A, 0xF1003B, MM_IO_R, &jpit3 }, // JPIT3 Timer 2 Pre-scaler F1003A RO - { 0xF1003C, 0xF1003D, MM_IO_R, &jpit4 }, // JPIT4 Timer 2 Divider F1003C RO - - { 0xF14000, 0xF14001, MM_IO, &joystick }, // JOYSTICK Joystick Register F14000 RW - { 0xF14002, 0xF14003, MM_IO, &joybuts }, // JOYBUTS Button Register F14002 RW - - // DSP REGISTERS - - { 0xF1A100, 0xF1A103, MM_IO, &d_flags }, // D_FLAGS DSP Flags Register F1A100 RW - { 0xF1A104, 0xF1A107, MM_IO_W, &d_mtxc }, // D_MTXC DSP Matrix Control Register F1A104 WO - { 0xF1A108, 0xF1A10B, MM_IO_W, &d_mtxa }, // D_MTXA DSP Matrix Address Register F1A108 WO - { 0xF1A10C, 0xF1A10F, MM_IO_W, &d_end }, // D_END DSP Data Organization Register F1A10C WO - { 0xF1A110, 0xF1A113, MM_IO, &d_pc }, // D_PC DSP Program Counter F1A110 RW - { 0xF1A114, 0xF1A117, MM_IO, &d_ctrl }, // D_CTRL DSP Control/Status Register F1A114 RW - { 0xF1A118, 0xF1A11B, MM_IO_W, &d_mod }, // D_MOD Modulo Instruction Mask F1A118 WO - { 0xF1A11C, 0xF1A11F, MM_IO_W, &d_remain, &d_divctrl }, // D_REMAIN Divide Unit Remainder F1A11C RO - // D_DIVCTRL Divide Unit Control F1A11C WO - { 0xF1A120, 0xF1A123, MM_IO_R, &d_machi }, // D_MACHI MAC High Result Bits F1A120 RO - - - { 0xF1A148, 0xF1A149, MM_IO, &lrxd, <xd }, // LTXD Left Transmit Data F1A148 WO - // LRXD Left Receive Data F1A148 RO - // L_I2S Left I2S Serial Interface F1A148 RW - { 0xF1A14C, 0xF1A14D, MM_IO, &rrxd, &rtxd }, // RTXD Right Transmit Data F1A14C WO - // RRXD Right Receive Data F1A14C RO - // R_I2S Right I2S Serial Interface F1A14C RW - { 0xF1A150, 0xF1A150, MM_IO, &sstat, &sclk }, // SCLK Serial Clock Frequency F1A150 WO - // SSTAT Serial Status F1A150 RO - { 0xF1A154, 0xF1A157, MM_IO_W, &smode }, // SMODE Serial Mode F1A154 WO - - { 0xF1B000, 0xF1CFFF, MM_RAM, dspRAM }, // F1B000-F1CFFF R/W xxxxxxxx xxxxxxxx Local DSP RAM - { 0xF1D000, 0xF1DFFF, MM_ROM, waveTableROM }, -// hi-speed interface for DSP??? Ain't no such thang... - { 0xFFFFFF, 0xFFFFFF, MM_NOP } // End of memory address sentinel -}; - -#if 0 - -// Jaguar Memory map/handlers -uint32_t memoryMap[] = { - { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM }, - { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM }, -// Note that this is really memory mapped I/O region... -// { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM }, - { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W - { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W - { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W - { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W - { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W - { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A - { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B - { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24) - { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data - { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old) - { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface - - { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM }, - -// { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW }, - { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler }, - { 0xF00052, 0xF00053, MM_IO, tomTimerDivider }, - { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other... - { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well - //What about LBUF writes??? - { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL - { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER - { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM - - { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW }, - -/* - EEPROM: - { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO } - { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR } - { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ } - - JOYSTICK: - { 0xF14000, 0xF14003, MM_IO, joystickFoo } - 0 = pad0/1 button values (4 bits each), RO(?) - 1 = pad0/1 index value (4 bits each), WO - 2 = unused, RO - 3 = NTSC/PAL, certain button states, RO - -JOYSTICK $F14000 Read/Write - 15.....8 7......0 -Read fedcba98 7654321q f-1 Signals J15 to J1 - q Cartridge EEPROM output data -Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs - 0 = disable J7-J0 outputs - x don't care - m Audio mute - 0 = Audio muted (reset state) - 1 = Audio enabled - 7-4 J7-J4 outputs (port 2) - 3-0 J3-J0 outputs (port 1) -JOYBUTS $F14002 Read Only - 15.....8 7......0 -Read xxxxxxxx rrdv3210 x don't care - r Reserved - d Reserved - v 1 = NTSC Video hardware - 0 = PAL Video hardware - 3-2 Button inputs B3 & B2 (port 2) - 1-0 Button inputs B1 & B0 (port 1) - -J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15 -J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11 - 0 0 0 0 - 0 0 0 1 - 0 0 1 0 - 0 0 1 1 - 0 1 0 0 - 0 1 0 1 - 0 1 1 0 - 0 1 1 1 Row 3 C3 Option # 9 6 3 - 1 0 0 0 - 1 0 0 1 - 1 0 1 0 - 1 0 1 1 Row 2 C2 C 0 8 5 2 - 1 1 0 0 - 1 1 0 1 Row 1 C1 B * 7 4 1 - 1 1 1 0 Row 0 Pause A Up Down Left Right - 1 1 1 1 - -0 bit read in any position means that button is pressed. -C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached. -*/ -}; -#endif - -void MMUWrite8(uint32_t address, uint8_t data, uint32_t who/*= UNKNOWN*/) -{ -} - -void MMUWrite16(uint32_t address, uint16_t data, uint32_t who/*= UNKNOWN*/) -{ -} - -void MMUWrite32(uint32_t address, uint32_t data, uint32_t who/*= UNKNOWN*/) -{ -} - -void MMUWrite64(uint32_t address, uint64_t data, uint32_t who/*= UNKNOWN*/) -{ -} - -uint8_t MMURead8(uint32_t address, uint32_t who/*= UNKNOWN*/) -{ - // Search for address in the memory map - // NOTE: This assumes that all entries are linear and sorted in ascending order! - - MemDesc memory; - uint8_t byte = 0xFE; - - uint32_t i = 0; - while (true) - { - if (address <= memoryMap[i].endAddr) - { - if (address >= memoryMap[i].startAddr) - { - memory = memoryMap[i]; - break; - } - else - return 0xFF; // Wasn't found... - } - - i++; - - if (memoryMap[i].startAddr == 0xFFFFFF) - return 0xFF; // Exhausted the list, so bail! - } - - uint32_t offset = address - memory.startAddr; - uint32_t size = memory.endAddr - memory.startAddr + 1; - uint8_t byteShift[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; - - if (memory.type == MM_RAM || memory.type == MM_ROM) - { - byte = ((uint8_t *)memory.readFunc)[offset]; - } - else if (memory.type == MM_IO_R || memory.type == MM_IO) - { - // Problem here: We don't know yet how wide the function is, so we don't know - // how to properly cast it. We COULD ignore the problem by passing in/receiving - // 64-bits of data and letting the function make heads or tails of it, but we - // still have the problem of, say, taking a byte from a 32-bit value. -/* -We can do like so: - uint8_t byteShift[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; - size = memory.endAddr - memory.startAddr + 1; - byte = (returnValFromFunc >> byteShift[offset]) & 0xFF; - -Let's see, will this work depending on the endianess? -uint32_t dword -accessing it like so: -((uint8_t *)dword &)[0] --> should give us high byte -but if we assign it directly... -dword = 0x12345678 --> becomes 78 56 34 12 in memory, ptr[0] will be 78 in LE! -dword = 0x12345678 --> becomes 12 34 56 78 in memory, ptr[0] will be 12 in BE! - -So we're in danger if we use the variables directly! We'd need something like -#define ENDIAN_SAFE_16(x) swap lo & hi bytes on LE systems -#define ENDIAN_SAFE_16(x) do nothing on BE systems - -Then, if we want to use a jaguar variable, we need to cast it like so: -uint16_t my_vbb = ENDIAN_SAFE_16(vbb); - -We have something like this already in jaguar.h, since we treat I/O spaces like -contiguous memory anyway... For reference: - -// Some handy macros to help converting native endian to big endian (jaguar native) -// & vice versa - -#define SET64(r, a, v) r[(a)] = ((v) & 0xFF00000000000000) >> 56, r[(a)+1] = ((v) & 0x00FF000000000000) >> 48, \ - r[(a)+2] = ((v) & 0x0000FF0000000000) >> 40, r[(a)+3] = ((v) & 0x000000FF00000000) >> 32, \ - r[(a)+4] = ((v) & 0xFF000000) >> 24, r[(a)+5] = ((v) & 0x00FF0000) >> 16, \ - r[(a)+6] = ((v) & 0x0000FF00) >> 8, r[(a)+7] = (v) & 0x000000FF -#define GET64(r, a) (((uint64)r[(a)] << 56) | ((uint64)r[(a)+1] << 48) | \ - ((uint64)r[(a)+2] << 40) | ((uint64)r[(a)+3] << 32) | \ - ((uint64)r[(a)+4] << 24) | ((uint64)r[(a)+5] << 16) | \ - ((uint64)r[(a)+6] << 8) | (uint64)r[(a)+7]) -#define SET32(r, a, v) r[(a)] = ((v) & 0xFF000000) >> 24, r[(a)+1] = ((v) & 0x00FF0000) >> 16, \ - r[(a)+2] = ((v) & 0x0000FF00) >> 8, r[(a)+3] = (v) & 0x000000FF -#define GET32(r, a) ((r[(a)] << 24) | (r[(a)+1] << 16) | (r[(a)+2] << 8) | r[(a)+3]) -#define SET16(r, a, v) r[(a)] = ((v) & 0xFF00) >> 8, r[(a)+1] = (v) & 0xFF -#define GET16(r, a) ((r[(a)] << 8) | r[(a)+1]) -*/ - // Confused? Let me enlighten... What we're doing here is casting - // data1 as a pointer to a function which returns a Window pointer and - // which takes no parameters (the "(Window *(*)(void))" part), then - // derefencing it (the "*" in front of that) in order to call the - // function that it points to. Clear as mud? Yeah, I hate function - // pointers too, but what else are you gonna do? -// mainWindow = (*(Window *(*)(void))event.user.data1)(); -// uint32_t retVal = (*(uint32(*)(uint32))memory.readFunc)(offset); -//#define FUNC_CAST(x) (*(uint32(*)(uint32))x) -// uint32_t retVal = FUNC_CAST(memory.readFunc)(offset); -#define FUNC_CAST(retVal, function, params) (*(retVal(*)(params))function) - uint64_t retVal = FUNC_CAST(uint64_t, memory.readFunc, uint32_t)(offset); - byte = (retVal >> byteShift[offset]) & 0xFF; - } - else if (memory.type == MM_IO_W) - { - byte = 0xFF; // Write only, what do we return? A fixed value? - } - - return byte; -} - -uint16_t MMURead16(uint32_t address, uint32_t who/*= UNKNOWN*/) -{ - return 0; -} - -uint32_t MMURead32(uint32_t address, uint32_t who/*= UNKNOWN*/) -{ - return 0; -} - -uint64_t MMURead64(uint32_t address, uint32_t who/*= UNKNOWN*/) -{ - return 0; -} - diff --git a/waterbox/virtualjaguar/src/mmu.h b/waterbox/virtualjaguar/src/mmu.h deleted file mode 100644 index 36ef8d7bc5..0000000000 --- a/waterbox/virtualjaguar/src/mmu.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// mmu.h -// -// Jaguar Memory Manager Unit -// -// by James L. Hammons -// - -#ifndef __MMU_H__ -#define __MMU_H__ - -//#include "types.h" -#include "memory.h" - -void MMUWrite8(uint32_t address, uint8_t data, uint32_t who = UNKNOWN); -void MMUWrite16(uint32_t address, uint16_t data, uint32_t who = UNKNOWN); -void MMUWrite32(uint32_t address, uint32_t data, uint32_t who = UNKNOWN); -void MMUWrite64(uint32_t address, uint64_t data, uint32_t who = UNKNOWN); -uint8_t MMURead8(uint32_t address, uint32_t who = UNKNOWN); -uint16_t MMURead16(uint32_t address, uint32_t who = UNKNOWN); -uint32_t MMURead32(uint32_t address, uint32_t who = UNKNOWN); -uint64_t MMURead64(uint32_t address, uint32_t who = UNKNOWN); - -#endif // __MMU_H__ diff --git a/waterbox/virtualjaguar/src/op.cpp b/waterbox/virtualjaguar/src/op.cpp index f8132e49f0..3de2d3ef19 100644 --- a/waterbox/virtualjaguar/src/op.cpp +++ b/waterbox/virtualjaguar/src/op.cpp @@ -19,14 +19,10 @@ #include #include "gpu.h" #include "jaguar.h" -#include "log.h" #include "m68000/m68kinterface.h" #include "memory.h" #include "tom.h" -//#define OP_DEBUG -//#define OP_DEBUG_BMP - #define BLEND_Y(dst, src) op_blend_y[(((uint16_t)dst<<8)) | ((uint16_t)(src))] #define BLEND_CR(dst, src) op_blend_cr[(((uint16_t)dst)<<8) | ((uint16_t)(src))] @@ -42,22 +38,11 @@ #define CONDITION_OP_FLAG_SET 3 #define CONDITION_SECOND_HALF_LINE 4 -#if 0 -#define OPFLAG_RELEASE 8 // Bus release bit -#define OPFLAG_TRANS 4 // Transparency bit -#define OPFLAG_RMW 2 // Read-Modify-Write bit -#define OPFLAG_REFLECT 1 // Horizontal mirror bit -#endif - // Private function prototypes void OPProcessFixedBitmap(uint64_t p0, uint64_t p1, bool render); void OPProcessScaledBitmap(uint64_t p0, uint64_t p1, uint64_t p2, bool render); void OPDiscoverObjects(uint32_t address); -void OPDumpObjectList(void); -void DumpScaledObject(uint64_t p0, uint64_t p1, uint64_t p2); -void DumpFixedObject(uint64_t p0, uint64_t p1); -void DumpBitmapCore(uint64_t p0, uint64_t p1); uint64_t OPLoadPhrase(uint32_t offset); // Local global variables @@ -65,38 +50,24 @@ uint64_t OPLoadPhrase(uint32_t offset); // Blend tables (64K each) static uint8_t op_blend_y[0x10000]; static uint8_t op_blend_cr[0x10000]; -// There may be a problem with this "RAM" overlapping (and thus being independent of) -// some of the regular TOM RAM... -//#warning objectp_ram is separated from TOM RAM--need to fix that! -//static uint8_t objectp_ram[0x40]; // This is based at $F00000 -uint8_t objectp_running = 0; -//bool objectp_stop_reading_list; -static uint8_t op_bitmap_bit_depth[8] = { 1, 2, 4, 8, 16, 24, 32, 0 }; -//static uint32_t op_bitmap_bit_size[8] = -// { (uint32_t)(0.125*65536), (uint32_t)(0.25*65536), (uint32_t)(0.5*65536), (uint32_t)(1*65536), -// (uint32_t)(2*65536), (uint32_t)(1*65536), (uint32_t)(1*65536), (uint32_t)(1*65536) }; static uint32_t op_pointer; int32_t phraseWidthToPixels[8] = { 64, 32, 16, 8, 4, 2, 0, 0 }; - // // Object Processor initialization // void OPInit(void) { - // Here we calculate the saturating blend of a signed 4-bit value and an - // existing Cyan/Red value as well as a signed 8-bit value and an existing intensity... - // Note: CRY is 4 bits Cyan, 4 bits Red, 16 bits intensitY for(int i=0; i<256*256; i++) { int y = (i >> 8) & 0xFF; - int dy = (int8_t)i; // Sign extend the Y index + int dy = (int8_t)i; int c1 = (i >> 8) & 0x0F; - int dc1 = (int8_t)(i << 4) >> 4; // Sign extend the R index + int dc1 = (int8_t)(i << 4) >> 4; int c2 = (i >> 12) & 0x0F; - int dc2 = (int8_t)(i & 0xF0) >> 4; // Sign extend the C index + int dc2 = (int8_t)(i & 0xF0) >> 4; y += dy; @@ -127,78 +98,24 @@ void OPInit(void) OPReset(); } - // // Object Processor reset // void OPReset(void) { -// memset(objectp_ram, 0x00, 0x40); - objectp_running = 0; } - -static const char * opType[8] = -{ "(BITMAP)", "(SCALED BITMAP)", "(GPU INT)", "(BRANCH)", "(STOP)", "???", "???", "???" }; -static const char * ccType[8] = - { "==", "<", ">", "(opflag set)", "(second half line)", "?", "?", "?" }; static uint32_t object[8192]; static uint32_t numberOfObjects; -//static uint32_t objectLink[8192]; -//static uint32_t numberOfLinks; - void OPDone(void) { -//#warning "!!! Fix OL dump so that it follows links !!!" -// const char * opType[8] = -// { "(BITMAP)", "(SCALED BITMAP)", "(GPU INT)", "(BRANCH)", "(STOP)", "???", "???", "???" }; -// const char * ccType[8] = -// { "\"==\"", "\"<\"", "\">\"", "(opflag set)", "(second half line)", "?", "?", "?" }; - - uint32_t olp = OPGetListPointer(); - WriteLog("\nOP: OLP = $%08X\n", olp); - WriteLog("OP: Phrase dump\n ----------\n"); - -#if 0 - for(uint32_t i=0; i<0x100; i+=8) - { - uint32_t hi = JaguarReadLong(olp + i, OP), lo = JaguarReadLong(olp + i + 4, OP); - WriteLog("\t%08X: %08X %08X %s", olp + i, hi, lo, opType[lo & 0x07]); - - if ((lo & 0x07) == 3) - { - uint16_t ypos = (lo >> 3) & 0x7FF; - uint8_t cc = (lo >> 14) & 0x03; - uint32_t link = ((hi << 11) | (lo >> 21)) & 0x3FFFF8; - WriteLog(" YPOS=%u, CC=%s, link=%08X", ypos, ccType[cc], link); - } - - WriteLog("\n"); - - if ((lo & 0x07) == 0) - DumpFixedObject(OPLoadPhrase(olp+i), OPLoadPhrase(olp+i+8)); - - if ((lo & 0x07) == 1) - DumpScaledObject(OPLoadPhrase(olp+i), OPLoadPhrase(olp+i+8), OPLoadPhrase(olp+i+16)); - } - - WriteLog("\n"); -#else -//#warning "!!! Fix lockup in OPDiscoverObjects() !!!" -//temp, to keep the following function from locking up on bad/weird OLs -//return; - numberOfObjects = 0; - OPDiscoverObjects(olp); - OPDumpObjectList(); -#endif + OPDiscoverObjects(OPGetListPointer()); } - bool OPObjectExists(uint32_t address) { - // Yes, we really do a linear search, every time. :-/ for(uint32_t i=0; i 0) can be treated as a GOTO, so - // don't do any discovery in that case. Otherwise, have at it: if (((lo & 0xFFFF) != 0x7FFB) && ((lo & 0xFFFF) != 0x8003)) - // Recursion needed to follow all links! This does depth-first - // recursion on the not-taken objects OPDiscoverObjects(address + 8); } - // Get the next object... address = link; } while (objectType != 4); } - -void OPDumpObjectList(void) -{ - for(uint32_t i=0; i> 21)) & 0x3FFFF8; - WriteLog("%08X: %08X %08X %s -> $%08X", address, hi, lo, opType[objectType], link); - - if (objectType == 3) - { - uint16_t ypos = (lo >> 3) & 0x7FF; - uint8_t cc = (lo >> 14) & 0x07; // Proper # of bits == 3 - WriteLog(" YPOS %s %u", ccType[cc], ypos); - } - - WriteLog("\n"); - - // Yes, this is how the OP finds follow-on phrases for bitmap/scaled - // bitmap objects...! - if (objectType == 0) - DumpFixedObject(OPLoadPhrase(address + 0), - OPLoadPhrase(address | 0x08)); - - if (objectType == 1) - DumpScaledObject(OPLoadPhrase(address + 0), - OPLoadPhrase(address | 0x08), OPLoadPhrase(address | 0x10)); - - if (address == link) // Ruh roh... - { - // Runaway recursive link is bad! - WriteLog("***** SELF REFERENTIAL LINK *****\n\n"); - } - } - - WriteLog("\n"); -} - - -// -// Object Processor memory access -// Memory range: F00010 - F00027 -// -// F00010-F00017 R xxxxxxxx xxxxxxxx OB - current object code from the graphics processor -// F00020-F00023 W xxxxxxxx xxxxxxxx OLP - start of the object list -// F00026 W -------- -------x OBF - object processor flag -// - -#if 0 -uint8_t OPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) -{ - offset &= 0x3F; - return objectp_ram[offset]; -} - -uint16_t OPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) -{ - offset &= 0x3F; - return GET16(objectp_ram, offset); -} - -void OPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) -{ - offset &= 0x3F; - objectp_ram[offset] = data; -} - -void OPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) -{ - offset &= 0x3F; - SET16(objectp_ram, offset, data); - -/*if (offset == 0x20) -WriteLog("OP: Setting lo list pointer: %04X\n", data); -if (offset == 0x22) -WriteLog("OP: Setting hi list pointer: %04X\n", data);//*/ -} -#endif - - uint32_t OPGetListPointer(void) { - // Note: This register is LO / HI WORD, hence the funky look of this... return GET16(tomRam8, 0x20) | (GET16(tomRam8, 0x22) << 16); } - -// This is WRONG, since the OBF is only 16 bits wide!!! [FIXED] - uint32_t OPGetStatusRegister(void) { return GET16(tomRam8, 0x26); } - -// This is WRONG, since the OBF is only 16 bits wide!!! [FIXED] - void OPSetStatusRegister(uint32_t data) { tomRam8[0x26] = (data & 0x0000FF00) >> 8; tomRam8[0x27] |= (data & 0xFE); } - void OPSetCurrentObject(uint64_t object) { -//Not sure this is right... Wouldn't it just be stored 64 bit BE? - // Stored as least significant 32 bits first, ms32 last in big endian -/* objectp_ram[0x13] = object & 0xFF; object >>= 8; - objectp_ram[0x12] = object & 0xFF; object >>= 8; - objectp_ram[0x11] = object & 0xFF; object >>= 8; - objectp_ram[0x10] = object & 0xFF; object >>= 8; - - objectp_ram[0x17] = object & 0xFF; object >>= 8; - objectp_ram[0x16] = object & 0xFF; object >>= 8; - objectp_ram[0x15] = object & 0xFF; object >>= 8; - objectp_ram[0x14] = object & 0xFF;*/ -// Let's try regular good old big endian... tomRam8[0x17] = object & 0xFF; object >>= 8; tomRam8[0x16] = object & 0xFF; object >>= 8; tomRam8[0x15] = object & 0xFF; object >>= 8; @@ -380,473 +184,169 @@ void OPSetCurrentObject(uint64_t object) uint64_t OPLoadPhrase(uint32_t offset) { - offset &= ~0x07; // 8 byte alignment + offset &= ~0x07; return ((uint64_t)JaguarReadLong(offset, OP) << 32) | (uint64_t)JaguarReadLong(offset+4, OP); } - void OPStorePhrase(uint32_t offset, uint64_t p) { - offset &= ~0x07; // 8 byte alignment + offset &= ~0x07; JaguarWriteLong(offset, p >> 32, OP); JaguarWriteLong(offset + 4, p & 0xFFFFFFFF, OP); } - -// -// Debugging routines -// -void DumpScaledObject(uint64_t p0, uint64_t p1, uint64_t p2) -{ - WriteLog(" %08X %08X\n", (uint32_t)(p1>>32), (uint32_t)(p1&0xFFFFFFFF)); - WriteLog(" %08X %08X\n", (uint32_t)(p2>>32), (uint32_t)(p2&0xFFFFFFFF)); - DumpBitmapCore(p0, p1); - uint32_t hscale = p2 & 0xFF; - uint32_t vscale = (p2 >> 8) & 0xFF; - uint32_t remainder = (p2 >> 16) & 0xFF; - WriteLog(" [hsc: %02X, vsc: %02X, rem: %02X]\n", hscale, vscale, remainder); -} - - -void DumpFixedObject(uint64_t p0, uint64_t p1) -{ - WriteLog(" %08X %08X\n", (uint32_t)(p1>>32), (uint32_t)(p1&0xFFFFFFFF)); - DumpBitmapCore(p0, p1); -} - - -void DumpBitmapCore(uint64_t p0, uint64_t p1) -{ - uint32_t bdMultiplier[8] = { 64, 32, 16, 8, 4, 2, 1, 1 }; - uint8_t bitdepth = (p1 >> 12) & 0x07; -//WAS: int16_t ypos = ((p0 >> 3) & 0x3FF); // ??? What if not interlaced (/2)? - int16_t ypos = ((p0 >> 3) & 0x7FF); // ??? What if not interlaced (/2)? - int32_t xpos = p1 & 0xFFF; - xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos); // Sign extend that mutha! - uint32_t iwidth = ((p1 >> 28) & 0x3FF); - uint32_t dwidth = ((p1 >> 18) & 0x3FF); // Unsigned! - uint16_t height = ((p0 >> 14) & 0x3FF); - uint32_t link = ((p0 >> 24) & 0x7FFFF) << 3; - uint32_t ptr = ((p0 >> 43) & 0x1FFFFF) << 3; - uint32_t firstPix = (p1 >> 49) & 0x3F; - uint8_t flags = (p1 >> 45) & 0x0F; - uint8_t idx = (p1 >> 38) & 0x7F; - uint32_t pitch = (p1 >> 15) & 0x07; - WriteLog(" [%u x %u @ (%i, %u) (iw:%u, dw:%u) (%u bpp), p:%08X fp:%02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n", - iwidth * bdMultiplier[bitdepth], - height, xpos, ypos, iwidth, dwidth, op_bitmap_bit_depth[bitdepth], - ptr, firstPix, (flags&OPFLAG_REFLECT ? "REFLECT " : ""), - (flags&OPFLAG_RMW ? "RMW " : ""), (flags&OPFLAG_TRANS ? "TRANS " : ""), - (flags&OPFLAG_RELEASE ? "RELEASE" : ""), idx, pitch); -} - - // // Object Processor main routine // -#warning "Need to fix this so that when an GPU object IRQ happens, we can pick up OP processing where we left off. !!! FIX !!!" void OPProcessList(int halfline, bool render) { -#warning "!!! NEED TO HANDLE MULTIPLE FIELDS PROPERLY !!!" -// We ignore them, for now; not good D-: -// N.B.: Half-lines are exactly that, half-lines. When in interlaced mode, it -// draws the screen exactly the same way as it does in non, one line at a -// time. The only way you know you're in field #2 is that the topmost bit -// of VC is set. Half-line mode is so you can draw higher horizontal -// resolutions than you normally could, as the line buffer is only 720 -// pixels wide... halfline &= 0x7FF; -extern int op_start_log; - op_pointer = OPGetListPointer(); -// objectp_stop_reading_list = false; + uint32_t opCyclesToRun = 30000; -//WriteLog("OP: Processing line #%u (OLP=%08X)...\n", halfline, op_pointer); -//op_done(); - -// *** BEGIN OP PROCESSOR TESTING ONLY *** -extern bool interactiveMode; -extern bool iToggle; -extern int objectPtr; -bool inhibit; -int bitmapCounter = 0; -// *** END OP PROCESSOR TESTING ONLY *** - - uint32_t opCyclesToRun = 30000; // This is a pulled-out-of-the-air value (will need to be fixed, obviously!) - -// if (op_pointer) WriteLog(" new op list at 0x%.8x halfline %i\n",op_pointer,halfline); while (op_pointer) { -// *** BEGIN OP PROCESSOR TESTING ONLY *** -if (interactiveMode && bitmapCounter == objectPtr) - inhibit = iToggle; -else - inhibit = false; -// *** END OP PROCESSOR TESTING ONLY *** -// if (objectp_stop_reading_list) -// return; - uint64_t p0 = OPLoadPhrase(op_pointer); op_pointer += 8; -//WriteLog("\t%08X type %i\n", op_pointer, (uint8_t)p0 & 0x07); - -#if 1 -if (halfline == TOMGetVDB() && op_start_log) -//if (halfline == 215 && op_start_log) -//if (halfline == 28 && op_start_log) -//if (halfline == 0) -{ -WriteLog("%08X --> phrase %08X %08X", op_pointer - 8, (int)(p0>>32), (int)(p0&0xFFFFFFFF)); -if ((p0 & 0x07) == OBJECT_TYPE_BITMAP) -{ -WriteLog(" (BITMAP) "); -uint64_t p1 = OPLoadPhrase(op_pointer); -WriteLog("\n%08X --> phrase %08X %08X ", op_pointer, (int)(p1>>32), (int)(p1&0xFFFFFFFF)); - uint8_t bitdepth = (p1 >> 12) & 0x07; -//WAS: int16_t ypos = ((p0 >> 3) & 0x3FF); // ??? What if not interlaced (/2)? - int16_t ypos = ((p0 >> 3) & 0x7FF); // ??? What if not interlaced (/2)? -int32_t xpos = p1 & 0xFFF; -xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos); - uint32_t iwidth = ((p1 >> 28) & 0x3FF); - uint32_t dwidth = ((p1 >> 18) & 0x3FF); // Unsigned! - uint16_t height = ((p0 >> 14) & 0x3FF); - uint32_t link = ((p0 >> 24) & 0x7FFFF) << 3; - uint32_t ptr = ((p0 >> 43) & 0x1FFFFF) << 3; - uint32_t firstPix = (p1 >> 49) & 0x3F; - uint8_t flags = (p1 >> 45) & 0x0F; - uint8_t idx = (p1 >> 38) & 0x7F; - uint32_t pitch = (p1 >> 15) & 0x07; -WriteLog("\n [%u (%u) x %u @ (%i, %u) (%u bpp), l: %08X, p: %08X fp: %02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n", - iwidth, dwidth, height, xpos, ypos, op_bitmap_bit_depth[bitdepth], link, ptr, firstPix, (flags&OPFLAG_REFLECT ? "REFLECT " : ""), (flags&OPFLAG_RMW ? "RMW " : ""), (flags&OPFLAG_TRANS ? "TRANS " : ""), (flags&OPFLAG_RELEASE ? "RELEASE" : ""), idx, pitch); -} -if ((p0 & 0x07) == OBJECT_TYPE_SCALE) -{ -WriteLog(" (SCALED BITMAP)"); -uint64_t p1 = OPLoadPhrase(op_pointer), p2 = OPLoadPhrase(op_pointer+8); -WriteLog("\n%08X --> phrase %08X %08X ", op_pointer, (int)(p1>>32), (int)(p1&0xFFFFFFFF)); -WriteLog("\n%08X --> phrase %08X %08X ", op_pointer+8, (int)(p2>>32), (int)(p2&0xFFFFFFFF)); - uint8_t bitdepth = (p1 >> 12) & 0x07; -//WAS: int16_t ypos = ((p0 >> 3) & 0x3FF); // ??? What if not interlaced (/2)? - int16_t ypos = ((p0 >> 3) & 0x7FF); // ??? What if not interlaced (/2)? -int32_t xpos = p1 & 0xFFF; -xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos); - uint32_t iwidth = ((p1 >> 28) & 0x3FF); - uint32_t dwidth = ((p1 >> 18) & 0x3FF); // Unsigned! - uint16_t height = ((p0 >> 14) & 0x3FF); - uint32_t link = ((p0 >> 24) & 0x7FFFF) << 3; - uint32_t ptr = ((p0 >> 43) & 0x1FFFFF) << 3; - uint32_t firstPix = (p1 >> 49) & 0x3F; - uint8_t flags = (p1 >> 45) & 0x0F; - uint8_t idx = (p1 >> 38) & 0x7F; - uint32_t pitch = (p1 >> 15) & 0x07; -WriteLog("\n [%u (%u) x %u @ (%i, %u) (%u bpp), l: %08X, p: %08X fp: %02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n", - iwidth, dwidth, height, xpos, ypos, op_bitmap_bit_depth[bitdepth], link, ptr, firstPix, (flags&OPFLAG_REFLECT ? "REFLECT " : ""), (flags&OPFLAG_RMW ? "RMW " : ""), (flags&OPFLAG_TRANS ? "TRANS " : ""), (flags&OPFLAG_RELEASE ? "RELEASE" : ""), idx, pitch); - uint32_t hscale = p2 & 0xFF; - uint32_t vscale = (p2 >> 8) & 0xFF; - uint32_t remainder = (p2 >> 16) & 0xFF; -WriteLog(" [hsc: %02X, vsc: %02X, rem: %02X]\n", hscale, vscale, remainder); -} -if ((p0 & 0x07) == OBJECT_TYPE_GPU) -WriteLog(" (GPU)\n"); -if ((p0 & 0x07) == OBJECT_TYPE_BRANCH) -{ -WriteLog(" (BRANCH)\n"); -uint8_t * jaguarMainRam = GetRamPtr(); -WriteLog("[RAM] --> "); -for(int k=0; k<8; k++) - WriteLog("%02X ", jaguarMainRam[op_pointer-8 + k]); -WriteLog("\n"); -} -if ((p0 & 0x07) == OBJECT_TYPE_STOP) -WriteLog(" --> List end\n\n"); -} -#endif switch ((uint8_t)p0 & 0x07) { - case OBJECT_TYPE_BITMAP: - { - uint16_t ypos = (p0 >> 3) & 0x7FF; -// This is only theory implied by Rayman...! -// It seems that if the YPOS is zero, then bump the YPOS value so that it -// coincides with the VDB value. With interlacing, this would be slightly more -// tricky. There's probably another bit somewhere that enables this mode--but -// so far, doesn't seem to affect any other game in a negative way (that I've -// seen). Either that, or it's an undocumented bug... - -//No, the reason this was needed is that the OP code before was wrong. Any value -//less than VDB will get written to the top line of the display! -#if 0 -// Not so sure... Let's see what happens here... -// No change... - if (ypos == 0) - ypos = TOMReadWord(0xF00046, OP) / 2; // Get the VDB value -#endif -// Actually, no. Any item less than VDB will get only the lines that hang over -// VDB displayed. Actually, this is incorrect. It seems that VDB value is wrong -// somewhere and that's what's causing things to fuck up. Still no idea why. - - uint32_t height = (p0 & 0xFFC000) >> 14; - uint32_t oldOPP = op_pointer - 8; -// *** BEGIN OP PROCESSOR TESTING ONLY *** -if (inhibit && op_start_log) - WriteLog("!!! ^^^ This object is INHIBITED! ^^^ !!!\n"); -bitmapCounter++; -if (!inhibit) // For OP testing only! -// *** END OP PROCESSOR TESTING ONLY *** - if (halfline >= ypos && height > 0) + case OBJECT_TYPE_BITMAP: { - // Believe it or not, this is what the OP actually does... - // which is why they're required to be on a dphrase boundary! - uint64_t p1 = OPLoadPhrase(oldOPP | 0x08); -//unneeded op_pointer += 8; -//WriteLog("OP: Writing halfline %d with ypos == %d...\n", halfline, ypos); -//WriteLog("--> Writing %u BPP bitmap...\n", op_bitmap_bit_depth[(p1 >> 12) & 0x07]); -// OPProcessFixedBitmap(halfline, p0, p1, render); - OPProcessFixedBitmap(p0, p1, render); + uint16_t ypos = (p0 >> 3) & 0x7FF; + uint32_t height = (p0 & 0xFFC000) >> 14; + uint32_t oldOPP = op_pointer - 8; - // OP write-backs - - height--; - - uint64_t data = (p0 & 0xFFFFF80000000000LL) >> 40; - uint64_t dwidth = (p1 & 0xFFC0000) >> 15; - data += dwidth; - - p0 &= ~0xFFFFF80000FFC000LL; // Mask out old data... - p0 |= (uint64_t)height << 14; - p0 |= data << 40; - OPStorePhrase(oldOPP, p0); - } - - // OP bottom 3 bits are hardwired to zero. The link address - // reflects this, so we only need the top 19 bits of the address - // (which is why we only shift 21, and not 24). - op_pointer = (p0 & 0x000007FFFF000000LL) >> 21; - - // KLUDGE: Seems that memory access is mirrored in the first 8MB of - // memory... - if (op_pointer > 0x1FFFFF && op_pointer < 0x800000) - op_pointer &= 0xFF1FFFFF; // Knock out bits 21-23 - - break; - } - case OBJECT_TYPE_SCALE: - { -//WAS: uint16_t ypos = (p0 >> 3) & 0x3FF; - uint16_t ypos = (p0 >> 3) & 0x7FF; - uint32_t height = (p0 & 0xFFC000) >> 14; - uint32_t oldOPP = op_pointer - 8; -//WriteLog("OP: Scaled Object (ypos=%04X, height=%04X", ypos, height); -// *** BEGIN OP PROCESSOR TESTING ONLY *** -if (inhibit && op_start_log) -{ - WriteLog("!!! ^^^ This object is INHIBITED! ^^^ !!! (halfline=%u, ypos=%u, height=%u)\n", halfline, ypos, height); - DumpScaledObject(p0, OPLoadPhrase(op_pointer), OPLoadPhrase(op_pointer+8)); -} -bitmapCounter++; -if (!inhibit) // For OP testing only! -// *** END OP PROCESSOR TESTING ONLY *** - if (halfline >= ypos && height > 0) - { - // Believe it or not, this is what the OP actually does... - // which is why they're required to be on a qphrase boundary! - uint64_t p1 = OPLoadPhrase(oldOPP | 0x08); - uint64_t p2 = OPLoadPhrase(oldOPP | 0x10); -//unneeded op_pointer += 16; - OPProcessScaledBitmap(p0, p1, p2, render); - - // OP write-backs - - uint16_t remainder = (p2 >> 16) & 0xFF;//, vscale = p2 >> 8; - uint8_t /*remainder = p2 >> 16,*/ vscale = p2 >> 8; -//Actually, we should skip this object if it has a vscale of zero. -//Or do we? Not sure... Atari Karts has a few lines that look like: -// (SCALED BITMAP) -//000E8268 --> phrase 00010000 7000B00D -// [7 (0) x 1 @ (13, 0) (8 bpp), l: 000E82A0, p: 000E0FC0 fp: 00, fl:RELEASE, idx:00, pt:01] -// [hsc: 9A, vsc: 00, rem: 00] -// Could it be the vscale is overridden if the DWIDTH is zero? Hmm... -//WriteLog("OP: Scaled bitmap processing (rem=%02X, vscale=%02X)...\n", remainder, vscale);//*/ - - if (vscale == 0) - vscale = 0x20; // OP bug??? Nope, it isn't...! Or is it? - -//extern int start_logging; -//if (start_logging) -// WriteLog("--> Returned from scaled bitmap processing (rem=%02X, vscale=%02X)...\n", remainder, vscale);//*/ -//Locks up here: -//--> Returned from scaled bitmap processing (rem=20, vscale=80)... -//There are other problems here, it looks like... -//Another lock up: -//About to execute OP (508)... -/* -OP: Scaled bitmap 4x? 4bpp at 38,? hscale=7C fpix=0 data=00075E28 pitch 1 hflipped=no dwidth=? (linked to 00071118) Transluency=no ---> Returned from scaled bitmap processing (rem=50, vscale=7C)... -OP: Scaled bitmap 4x? 4bpp at 38,? hscale=7C fpix=0 data=00075E28 pitch 1 hflipped=no dwidth=? (linked to 00071118) Transluency=no ---> Returned from scaled bitmap processing (rem=30, vscale=7C)... -OP: Scaled bitmap 4x? 4bpp at 38,? hscale=7C fpix=0 data=00075E28 pitch 1 hflipped=no dwidth=? (linked to 00071118) Transluency=no ---> Returned from scaled bitmap processing (rem=10, vscale=7C)... -OP: Scaled bitmap 4x? 4bpp at 36,? hscale=7E fpix=0 data=000756A8 pitch 1 hflipped=no dwidth=? (linked to 00073058) Transluency=no ---> Returned from scaled bitmap processing (rem=00, vscale=7E)... -OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756C8 pitch 1 hflipped=no dwidth=? (linked to 00073078) Transluency=no ---> Returned from scaled bitmap processing (rem=00, vscale=80)... -OP: Scaled bitmap 4x? 4bpp at 36,? hscale=7E fpix=0 data=000756C8 pitch 1 hflipped=no dwidth=? (linked to 00073058) Transluency=no ---> Returned from scaled bitmap processing (rem=5E, vscale=7E)... -OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipped=no dwidth=? (linked to 00073078) Transluency=no ---> Returned from scaled bitmap processing (rem=60, vscale=80)... -OP: Scaled bitmap 4x? 4bpp at 36,? hscale=7E fpix=0 data=000756C8 pitch 1 hflipped=no dwidth=? (linked to 00073058) Transluency=no ---> Returned from scaled bitmap processing (rem=3E, vscale=7E)... -OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipped=no dwidth=? (linked to 00073078) Transluency=no ---> Returned from scaled bitmap processing (rem=40, vscale=80)... -OP: Scaled bitmap 4x? 4bpp at 36,? hscale=7E fpix=0 data=000756C8 pitch 1 hflipped=no dwidth=? (linked to 00073058) Transluency=no ---> Returned from scaled bitmap processing (rem=1E, vscale=7E)... -OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipped=no dwidth=? (linked to 00073078) Transluency=no ---> Returned from scaled bitmap processing (rem=20, vscale=80)... -*/ -//Here's another problem: -// [hsc: 20, vsc: 20, rem: 00] -// Since we're not checking for $E0 (but that's what we get from the above), we -// end up repeating this halfline unnecessarily... !!! FIX !!! [DONE, but... -// still not quite right. Either that, or the Accolade team that wrote Bubsy -// screwed up royal.] -//Also note: $E0 = 7.0 which IS a legal vscale value... - -// if (remainder & 0x80) // I.e., it's negative -// if ((remainder & 0x80) || remainder == 0) // I.e., it's <= 0 -// if ((remainder - 1) >= 0xE0) // I.e., it's <= 0 -// if ((remainder >= 0xE1) || remainder == 0)// I.e., it's <= 0 -// if ((remainder >= 0xE1 && remainder <= 0xFF) || remainder == 0)// I.e., it's <= 0 -// if (remainder <= 0x20) // I.e., it's <= 1.0 - // I.e., it's < 1.0f -> means it'll go negative when we subtract 1.0f. - if (remainder < 0x20) + if (halfline >= ypos && height > 0) { + uint64_t p1 = OPLoadPhrase(oldOPP | 0x08); + OPProcessFixedBitmap(p0, p1, render); + + height--; + uint64_t data = (p0 & 0xFFFFF80000000000LL) >> 40; uint64_t dwidth = (p1 & 0xFFC0000) >> 15; + data += dwidth; -// while (remainder & 0x80) -// while ((remainder & 0x80) || remainder == 0) -// while ((remainder - 1) >= 0xE0) -// while ((remainder >= 0xE1) || remainder == 0) -// while ((remainder >= 0xE1 && remainder <= 0xFF) || remainder == 0) -// while (remainder <= 0x20) - while (remainder < 0x20) - { - remainder += vscale; - - if (height) - height--; - - data += dwidth; - } - - p0 &= ~0xFFFFF80000FFC000LL; // Mask out old data... + p0 &= ~0xFFFFF80000FFC000LL; p0 |= (uint64_t)height << 14; p0 |= data << 40; OPStorePhrase(oldOPP, p0); } - remainder -= 0x20; // 1.0f in [3.5] fixed point format + op_pointer = (p0 & 0x000007FFFF000000LL) >> 21; -//if (start_logging) -// WriteLog("--> Finished writebacks...\n");//*/ + if (op_pointer > 0x1FFFFF && op_pointer < 0x800000) + op_pointer &= 0xFF1FFFFF; -//WriteLog(" [%08X%08X -> ", (uint32_t)(p2>>32), (uint32_t)(p2&0xFFFFFFFF)); - p2 &= ~0x0000000000FF0000LL; - p2 |= (uint64_t)remainder << 16; -//WriteLog("%08X%08X]\n", (uint32_t)(p2>>32), (uint32_t)(p2&0xFFFFFFFF)); - OPStorePhrase(oldOPP + 16, p2); -//remainder = (uint8_t)(p2 >> 16), vscale = (uint8_t)(p2 >> 8); -//WriteLog(" [after]: rem=%02X, vscale=%02X\n", remainder, vscale); + break; } - - // OP bottom 3 bits are hardwired to zero. The link address - // reflects this, so we only need the top 19 bits of the address - // (which is why we only shift 21, and not 24). - op_pointer = (p0 & 0x000007FFFF000000LL) >> 21; - - // KLUDGE: Seems that memory access is mirrored in the first 8MB of - // memory... - if (op_pointer > 0x1FFFFF && op_pointer < 0x800000) - op_pointer &= 0xFF1FFFFF; // Knock out bits 21-23 - - break; - } - case OBJECT_TYPE_GPU: - { -//WriteLog("OP: Asserting GPU IRQ #3...\n"); -#warning "Need to fix OP GPU IRQ handling! !!! FIX !!!" - OPSetCurrentObject(p0); - GPUSetIRQLine(3, ASSERT_LINE); -//Also, OP processing is suspended from this point until OBF (F00026) is written to... -// !!! FIX !!! -//Do something like: -//OPSuspendedByGPU = true; -//Dunno if the OP keeps processing from where it was interrupted, or if it just continues -//on the next halfline... -// --> It continues from where it was interrupted! !!! FIX !!! - break; - } - case OBJECT_TYPE_BRANCH: - { - uint16_t ypos = (p0 >> 3) & 0x7FF; - // JTRM is wrong: CC is bits 14-16 (3 bits, *not* 2) - uint8_t cc = (p0 >> 14) & 0x07; - uint32_t link = (p0 >> 21) & 0x3FFFF8; - - switch (cc) + case OBJECT_TYPE_SCALE: { - case CONDITION_EQUAL: - if (halfline == ypos || ypos == 0x7FF) - op_pointer = link; - break; - case CONDITION_LESS_THAN: - if (halfline < ypos) - op_pointer = link; - break; - case CONDITION_GREATER_THAN: - if (halfline > ypos) - op_pointer = link; - break; - case CONDITION_OP_FLAG_SET: - if (OPGetStatusRegister() & 0x01) - op_pointer = link; - break; - case CONDITION_SECOND_HALF_LINE: - // Branch if bit 10 of HC is set... - if (TOMGetHC() & 0x0400) - op_pointer = link; - break; - default: - // Basically, if you do this, the OP does nothing. :-) - WriteLog("OP: Unimplemented branch condition %i\n", cc); - } - break; - } - case OBJECT_TYPE_STOP: - { - OPSetCurrentObject(p0); + uint16_t ypos = (p0 >> 3) & 0x7FF; + uint32_t height = (p0 & 0xFFC000) >> 14; + uint32_t oldOPP = op_pointer - 8; - if ((p0 & 0x08) && TOMIRQEnabled(IRQ_OPFLAG)) + if (halfline >= ypos && height > 0) + { + uint64_t p1 = OPLoadPhrase(oldOPP | 0x08); + uint64_t p2 = OPLoadPhrase(oldOPP | 0x10); + OPProcessScaledBitmap(p0, p1, p2, render); + + uint16_t remainder = (p2 >> 16) & 0xFF; + uint8_t vscale = p2 >> 8; + + if (vscale == 0) + vscale = 0x20; + + if (remainder < 0x20) + { + uint64_t data = (p0 & 0xFFFFF80000000000LL) >> 40; + uint64_t dwidth = (p1 & 0xFFC0000) >> 15; + + while (remainder < 0x20) + { + remainder += vscale; + + if (height) + height--; + + data += dwidth; + } + + p0 &= ~0xFFFFF80000FFC000LL; + p0 |= (uint64_t)height << 14; + p0 |= data << 40; + OPStorePhrase(oldOPP, p0); + } + + remainder -= 0x20; + + p2 &= ~0x0000000000FF0000LL; + p2 |= (uint64_t)remainder << 16; + OPStorePhrase(oldOPP + 16, p2); + } + + op_pointer = (p0 & 0x000007FFFF000000LL) >> 21; + + if (op_pointer > 0x1FFFFF && op_pointer < 0x800000) + op_pointer &= 0xFF1FFFFF; + + break; + } + case OBJECT_TYPE_GPU: { - TOMSetPendingObjectInt(); - m68k_set_irq(2); // Cause a 68K IPL 2 to occur... + OPSetCurrentObject(p0); + GPUSetIRQLine(3, ASSERT_LINE); + break; } + case OBJECT_TYPE_BRANCH: + { + uint16_t ypos = (p0 >> 3) & 0x7FF; + uint8_t cc = (p0 >> 14) & 0x07; + uint32_t link = (p0 >> 21) & 0x3FFFF8; - // Bail out, we're done... - return; - } - default: - WriteLog("OP: Unknown object type %i\n", (uint8_t)p0 & 0x07); + switch (cc) + { + case CONDITION_EQUAL: + if (halfline == ypos || ypos == 0x7FF) + op_pointer = link; + break; + case CONDITION_LESS_THAN: + if (halfline < ypos) + op_pointer = link; + break; + case CONDITION_GREATER_THAN: + if (halfline > ypos) + op_pointer = link; + break; + case CONDITION_OP_FLAG_SET: + if (OPGetStatusRegister() & 0x01) + op_pointer = link; + break; + case CONDITION_SECOND_HALF_LINE: + if (TOMGetHC() & 0x0400) + op_pointer = link; + break; + } + break; + } + case OBJECT_TYPE_STOP: + { + OPSetCurrentObject(p0); + + if ((p0 & 0x08) && TOMIRQEnabled(IRQ_OPFLAG)) + { + TOMSetPendingObjectInt(); + m68k_set_irq(2); + } + + return; + } } - // Here is a little sanity check to keep the OP from locking up the - // machine when fed bad data. Better would be to count how many actual - // cycles it used and bail out/reenter to properly simulate an - // overloaded OP... !!! FIX !!! -#warning "Better would be to count how many actual cycles it used and bail out/reenter to properly simulate an overloaded OP... !!! FIX !!!" opCyclesToRun--; if (!opCyclesToRun) @@ -854,232 +354,93 @@ OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipp } } - // // Store fixed size bitmap in line buffer // void OPProcessFixedBitmap(uint64_t p0, uint64_t p1, bool render) { -// Need to make sure that when writing that it stays within the line buffer... -// LBUF ($F01800 - $F01D9E) 360 x 32-bit RAM - uint8_t depth = (p1 >> 12) & 0x07; // Color depth of image - int32_t xpos = ((int16_t)((p1 << 4) & 0xFFFF)) >> 4;// Image xpos in LBUF - uint32_t iwidth = (p1 >> 28) & 0x3FF; // Image width in *phrases* - uint32_t data = (p0 >> 40) & 0xFFFFF8; // Pixel data address + uint8_t depth = (p1 >> 12) & 0x07; + int32_t xpos = ((int16_t)((p1 << 4) & 0xFFFF)) >> 4; + uint32_t iwidth = (p1 >> 28) & 0x3FF; + uint32_t data = (p0 >> 40) & 0xFFFFF8; uint32_t firstPix = (p1 >> 49) & 0x3F; - // "The LSB is significant only for scaled objects..." -JTRM - // "In 1 BPP mode, all five bits are significant. In 2 BPP mode, the top - // four are significant..." firstPix &= 0x3E; -// We can ignore the RELEASE (high order) bit for now--probably forever...! -// uint8_t flags = (p1 >> 45) & 0x0F; // REFLECT, RMW, TRANS, RELEASE -//Optimize: break these out to their own BOOL values - uint8_t flags = (p1 >> 45) & 0x07; // REFLECT (0), RMW (1), TRANS (2) + uint8_t flags = (p1 >> 45) & 0x07; bool flagREFLECT = (flags & OPFLAG_REFLECT ? true : false), flagRMW = (flags & OPFLAG_RMW ? true : false), flagTRANS = (flags & OPFLAG_TRANS ? true : false); -// "For images with 1 to 4 bits/pixel the top 7 to 4 bits of the index -// provide the most significant bits of the palette address." - uint8_t index = (p1 >> 37) & 0xFE; // CLUT index offset (upper pix, 1-4 bpp) - uint32_t pitch = (p1 >> 15) & 0x07; // Phrase pitch - pitch <<= 3; // Optimization: Multiply pitch by 8 -// int16_t scanlineWidth = tom_getVideoModeWidth(); + uint8_t index = (p1 >> 37) & 0xFE; + uint32_t pitch = (p1 >> 15) & 0x07; + pitch <<= 3; + uint8_t * tomRam8 = TOMGetRamPointer(); uint8_t * paletteRAM = &tomRam8[0x400]; - // This is OK as long as it's used correctly: For 16-bit RAM to RAM direct - // copies--NOT for use when using endian-corrected data (i.e., any of the - // *_word_read functions!) uint16_t * paletteRAM16 = (uint16_t *)paletteRAM; -// WriteLog("bitmap %ix? %ibpp at %i,? firstpix=? data=0x%.8x pitch %i hflipped=%s dwidth=? (linked to ?) RMW=%s Tranparent=%s\n", -// iwidth, op_bitmap_bit_depth[bitdepth], xpos, ptr, pitch, (flags&OPFLAG_REFLECT ? "yes" : "no"), (flags&OPFLAG_RMW ? "yes" : "no"), (flags&OPFLAG_TRANS ? "yes" : "no")); + if (iwidth == 0) + iwidth = 1; -// Is it OK to have a 0 for the data width??? (i.e., undocumented?) -// Seems to be... Seems that dwidth *can* be zero (i.e., reuse same line) as -// well. -// Pitch == 0 is OK too... - -//kludge: Seems that the OP treats iwidth == 0 as iwidth == 1... Need to -// investigate on real hardware... -#warning "!!! Need to investigate iwidth == 0 behavior on real hardware !!!" -if (iwidth == 0) - iwidth = 1; - -// if (!render || op_pointer == 0 || ptr == 0 || pitch == 0) -//I'm not convinced that we need to concern ourselves with data & op_pointer -//here either! if (!render || iwidth == 0) return; -//OK, so we know the position in the line buffer is correct. It's the clipping -//in 24bpp mode that's wrong! -#if 0 -//This is a total kludge, based upon the fact that 24BPP mode puts *4* bytes -//into the line buffer for each pixel. -if (depth == 5) // i.e., 24bpp mode... - xpos >>= 1; // Cut it in half... -#endif - -//#define OP_DEBUG_BMP -//#ifdef OP_DEBUG_BMP -// WriteLog("bitmap %ix%i %ibpp at %i,%i firstpix=%i data=0x%.8x pitch %i hflipped=%s dwidth=%i (linked to 0x%.8x) Transluency=%s\n", -// iwidth, height, op_bitmap_bit_depth[bitdepth], xpos, ypos, firstPix, ptr, pitch, (flags&OPFLAG_REFLECT ? "yes" : "no"), dwidth, op_pointer, (flags&OPFLAG_RMW ? "yes" : "no")); -//#endif - -// int32_t leftMargin = xpos, rightMargin = (xpos + (phraseWidthToPixels[depth] * iwidth)) - 1; int32_t startPos = xpos, endPos = xpos + (!flagREFLECT ? (phraseWidthToPixels[depth] * iwidth) - 1 : -((phraseWidthToPixels[depth] * iwidth) + 1)); - uint32_t clippedWidth = 0, phraseClippedWidth = 0, dataClippedWidth = 0;//, phrasePixel = 0; - bool in24BPPMode = (((GET16(tomRam8, 0x0028) >> 1) & 0x03) == 1 ? true : false); // VMODE - // This is correct, the OP line buffer is a constant size... + uint32_t clippedWidth = 0, phraseClippedWidth = 0, dataClippedWidth = 0; + bool in24BPPMode = (((GET16(tomRam8, 0x0028) >> 1) & 0x03) == 1 ? true : false); + int32_t limit = 720; int32_t lbufWidth = 719; - // If the image is completely to the left or right of the line buffer, then - // bail. -//If in REFLECT mode, then these values are swapped! !!! FIX !!! [DONE] -//There are four possibilities: -// 1. image sits on left edge and no REFLECT; starts out of bounds but ends in bounds. -// 2. image sits on left edge and REFLECT; starts in bounds but ends out of bounds. -// 3. image sits on right edge and REFLECT; starts out of bounds but ends in bounds. -// 4. image sits on right edge and no REFLECT; starts in bounds but ends out of bounds. -//Numbers 2 & 4 can be caught by checking the LBUF clip while in the inner loop, -// numbers 1 & 3 are of concern. -// This *indirectly* handles only cases 2 & 4! And is WRONG is REFLECT is set...! -// if (rightMargin < 0 || leftMargin > lbufWidth) - -// It might be easier to swap these (if REFLECTed) and just use XPOS down below... -// That way, you could simply set XPOS to leftMargin if !REFLECT and to rightMargin otherwise. -// Still have to be careful with the DATA and IWIDTH values though... - -// if ((!flagREFLECT && (rightMargin < 0 || leftMargin > lbufWidth)) -// || (flagREFLECT && (leftMargin < 0 || rightMargin > lbufWidth))) -// return; if ((!flagREFLECT && (endPos < 0 || startPos > lbufWidth)) || (flagREFLECT && (startPos < 0 || endPos > lbufWidth))) return; - // Otherwise, find the clip limits and clip the phrase as well... - // NOTE: I'm fudging here by letting the actual blit overstep the bounds of the - // line buffer, but it shouldn't matter since there are two unused line - // buffers below and nothing above and I'll at most write 8 bytes outside - // the line buffer... I could use a fractional clip begin/end value, but - // this makes the blit a *lot* more hairy. I might fix this in the future - // if it becomes necessary. (JLH) - // Probably wouldn't be *that* hairy. Just use a delta that tells the inner loop - // which pixel in the phrase is being written, and quit when either end of phrases - // is reached or line buffer extents are surpassed. - -//This stuff is probably wrong as well... !!! FIX !!! -//The strange thing is that it seems to work, but that's no guarantee that it's bulletproof! -//Yup. Seems that JagMania doesn't work correctly with this... -//Dunno if this is the problem, but Atari Karts is showing *some* of the road now... -// if (!flagREFLECT) - -/* - if (leftMargin < 0) - clippedWidth = 0 - leftMargin, - phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth], - leftMargin = 0 - (clippedWidth % phraseWidthToPixels[depth]); -// leftMargin = 0; - - if (rightMargin > lbufWidth) - clippedWidth = rightMargin - lbufWidth, - phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth];//, -// rightMargin = lbufWidth + (clippedWidth % phraseWidthToPixels[depth]); -// rightMargin = lbufWidth; -*/ -if (depth > 5) - WriteLog("OP: We're about to encounter a divide by zero error!\n"); - // NOTE: We're just using endPos to figure out how much, if any, to clip by. - // ALSO: There may be another case where we start out of bounds and end out - // of bounds...! - // !!! FIX !!! - if (startPos < 0) // Case #1: Begin out, end in, L to R + if (startPos < 0) clippedWidth = 0 - startPos, dataClippedWidth = phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth], startPos = 0 - (clippedWidth % phraseWidthToPixels[depth]); - if (endPos < 0) // Case #2: Begin in, end out, R to L + if (endPos < 0) clippedWidth = 0 - endPos, phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth]; - if (endPos > lbufWidth) // Case #3: Begin in, end out, L to R + if (endPos > lbufWidth) clippedWidth = endPos - lbufWidth, phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth]; - if (startPos > lbufWidth) // Case #4: Begin out, end in, R to L + if (startPos > lbufWidth) clippedWidth = startPos - lbufWidth, dataClippedWidth = phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth], startPos = lbufWidth + (clippedWidth % phraseWidthToPixels[depth]); -//printf("> 5) | 0x02; - // Fetch 1st phrase... uint64_t pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); -//Note that firstPix should only be honored *if* we start with the 1st phrase of the bitmap -//i.e., we didn't clip on the margin... !!! FIX !!! - pixels <<= firstPix; // Skip first N pixels (N=firstPix)... - int i = firstPix; // Start counter at right spot... + pixels <<= firstPix; + int i = firstPix; while (iwidth--) { while (i++ < 64) { uint8_t bit = pixels >> 63; -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bit == 0) -#else - if (flagTRANS && (paletteRAM16[index | bit] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) -//Optimize: Set palleteRAM16 to beginning of palette RAM + index*2 and use only [bit] as index... -//Won't optimize RMW case though... - // This is the *only* correct use of endian-dependent code - // (i.e., mem-to-mem direct copying)! *(uint16_t *)currentLineBuffer = paletteRAM16[index | bit]; else *currentLineBuffer = @@ -1091,40 +452,27 @@ if (depth > 5) currentLineBuffer += lbufDelta; pixels <<= 1; } + i = 0; - // Fetch next phrase... data += pitch; pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); } } - else if (depth == 1) // 2 BPP + else if (depth == 1) { -if (firstPix) - WriteLog("OP: Fixed bitmap @ 2 BPP requesting FIRSTPIX! (fp=%u)\n", firstPix); - index &= 0xFC; // Top six bits form CLUT index - // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it. + index &= 0xFC; int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; while (iwidth--) { - // Fetch phrase... uint64_t pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); data += pitch; for(int i=0; i<32; i++) { uint8_t bits = pixels >> 62; -// Seems to me that both of these are in the same endian, so we could cast it as -// uint16_t * and do straight across copies (what about 24 bpp? Treat it differently...) -// This only works for the palettized modes (1 - 8 BPP), since we actually have to -// copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?) -// No, it isn't because we read the memory in an endian safe way--this *won't* work... -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bits == 0) -#else - if (flagTRANS && (paletteRAM16[index | bits] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) @@ -1141,34 +489,21 @@ if (firstPix) } } } - else if (depth == 2) // 4 BPP + else if (depth == 2) { -if (firstPix) - WriteLog("OP: Fixed bitmap @ 4 BPP requesting FIRSTPIX! (fp=%u)\n", firstPix); - index &= 0xF0; // Top four bits form CLUT index - // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it. + index &= 0xF0; int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; while (iwidth--) { - // Fetch phrase... uint64_t pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); data += pitch; for(int i=0; i<16; i++) { uint8_t bits = pixels >> 60; -// Seems to me that both of these are in the same endian, so we could cast it as -// uint16_t * and do straight across copies (what about 24 bpp? Treat it differently...) -// This only works for the palettized modes (1 - 8 BPP), since we actually have to -// copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?) -// No, it isn't because we read the memory in an endian safe way--this *won't* work... -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bits == 0) -#else - if (flagTRANS && (paletteRAM16[index | bits] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) @@ -1185,38 +520,22 @@ if (firstPix) } } } - else if (depth == 3) // 8 BPP + else if (depth == 3) { - // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it. int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; - // Fetch 1st phrase... uint64_t pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); -//Note that firstPix should only be honored *if* we start with the 1st phrase of the bitmap -//i.e., we didn't clip on the margin... !!! FIX !!! - firstPix &= 0x30; // Only top two bits are valid for 8 BPP - pixels <<= firstPix; // Skip first N pixels (N=firstPix)... - int i = firstPix >> 3; // Start counter at right spot... + firstPix &= 0x30; + pixels <<= firstPix; + int i = firstPix >> 3; while (iwidth--) { while (i++ < 8) { uint8_t bits = pixels >> 56; -// Seems to me that both of these are in the same endian, so we could cast it as -// uint16_t * and do straight across copies (what about 24 bpp? Treat it differently...) -// This only works for the palettized modes (1 - 8 BPP), since we actually have to -// copy data from memory in 16 BPP mode (or does it? Isn't this the same as the CLUT case?) -// No, it isn't because we read the memory in an endian safe way--this *won't* work... -//This would seem to be problematic... -//Because it's the palette entry being zero that makes the pixel transparent... -//Let's try it and see. -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bits == 0) -#else - if (flagTRANS && (paletteRAM16[bits] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) @@ -1232,38 +551,26 @@ if (firstPix) pixels <<= 8; } i = 0; - // Fetch next phrase... + data += pitch; pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); } } - else if (depth == 4) // 16 BPP + else if (depth == 4) { -if (firstPix) - WriteLog("OP: Fixed bitmap @ 16 BPP requesting FIRSTPIX! (fp=%u)\n", firstPix); - // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it. int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; while (iwidth--) { - // Fetch phrase... uint64_t pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); data += pitch; for(int i=0; i<4; i++) { uint8_t bitsHi = pixels >> 56, bitsLo = pixels >> 48; -// Seems to me that both of these are in the same endian, so we could cast it -// as uint16_t * and do straight across copies (what about 24 bpp? Treat it -// differently...) This only works for the palettized modes (1 - 8 BPP), since -// we actually have to copy data from memory in 16 BPP mode (or does it? Isn't -// this the same as the CLUT case?) No, it isn't because we read the memory in -// an endian safe way--it *won't* work... -//This doesn't seem right... Let's try the encoded black value ($8800): -//Apparently, CRY 0 maps to $8800... + if (flagTRANS && ((bitsLo | bitsHi) == 0)) -// if (flagTRANS && (bitsHi == 0x88) && (bitsLo == 0x00)) - ; // Do nothing... + ; else { if (!flagRMW) @@ -1281,31 +588,22 @@ if (firstPix) } } } - else if (depth == 5) // 24 BPP + else if (depth == 5) { -//Looks like Iron Soldier is the only game that uses 24BPP mode... -//There *might* be others... -//WriteLog("OP: Writing 24 BPP bitmap!\n"); -if (firstPix) - WriteLog("OP: Fixed bitmap @ 24 BPP requesting FIRSTPIX! (fp=%u)\n", firstPix); - // Not sure, but I think RMW only works with 16 BPP and below, and only in CRY mode... - // The LSB of flags is OPFLAG_REFLECT, so sign extend it and OR 4 into it. int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 4) | 0x04; while (iwidth--) { - // Fetch phrase... uint64_t pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); data += pitch; for(int i=0; i<2; i++) { - // We don't use a 32-bit var here because of endian issues...! uint8_t bits3 = pixels >> 56, bits2 = pixels >> 48, bits1 = pixels >> 40, bits0 = pixels >> 32; if (flagTRANS && (bits3 | bits2 | bits1 | bits0) == 0) - ; // Do nothing... + ; else *currentLineBuffer = bits3, *(currentLineBuffer + 1) = bits2, @@ -1319,240 +617,78 @@ if (firstPix) } } - // // Store scaled bitmap in line buffer // void OPProcessScaledBitmap(uint64_t p0, uint64_t p1, uint64_t p2, bool render) { -// Need to make sure that when writing that it stays within the line buffer... -// LBUF ($F01800 - $F01D9E) 360 x 32-bit RAM - uint8_t depth = (p1 >> 12) & 0x07; // Color depth of image - int32_t xpos = ((int16_t)((p1 << 4) & 0xFFFF)) >> 4;// Image xpos in LBUF - uint32_t iwidth = (p1 >> 28) & 0x3FF; // Image width in *phrases* - uint32_t data = (p0 >> 40) & 0xFFFFF8; // Pixel data address -//#ifdef OP_DEBUG_BMP -// Prolly should use this... Though not sure exactly how. -//Use the upper bits as an offset into the phrase depending on the BPP. That's how! + uint8_t depth = (p1 >> 12) & 0x07; + int32_t xpos = ((int16_t)((p1 << 4) & 0xFFFF)) >> 4; + uint32_t iwidth = (p1 >> 28) & 0x3FF; + uint32_t data = (p0 >> 40) & 0xFFFFF8; + uint32_t firstPix = (p1 >> 49) & 0x3F; -//This is WEIRD! I'm sure I saw Atari Karts request 8 BPP FIRSTPIX! What happened??? -if (firstPix) - WriteLog("OP: FIRSTPIX != 0! (Scaled BM)\n"); -//#endif -// We can ignore the RELEASE (high order) bit for now--probably forever...! -// uint8_t flags = (p1 >> 45) & 0x0F; // REFLECT, RMW, TRANS, RELEASE -//Optimize: break these out to their own BOOL values [DONE] - uint8_t flags = (p1 >> 45) & 0x07; // REFLECT (0), RMW (1), TRANS (2) + + uint8_t flags = (p1 >> 45) & 0x07; bool flagREFLECT = (flags & OPFLAG_REFLECT ? true : false), flagRMW = (flags & OPFLAG_RMW ? true : false), flagTRANS = (flags & OPFLAG_TRANS ? true : false); - uint8_t index = (p1 >> 37) & 0xFE; // CLUT index offset (upper pix, 1-4 bpp) - uint32_t pitch = (p1 >> 15) & 0x07; // Phrase pitch + uint8_t index = (p1 >> 37) & 0xFE; + uint32_t pitch = (p1 >> 15) & 0x07; uint8_t * tomRam8 = TOMGetRamPointer(); uint8_t * paletteRAM = &tomRam8[0x400]; - // This is OK as long as it's used correctly: For 16-bit RAM to RAM direct - // copies--NOT for use when using endian-corrected data (i.e., any of the - // *ReadWord functions!) uint16_t * paletteRAM16 = (uint16_t *)paletteRAM; uint16_t hscale = p2 & 0xFF; -// Hmm. It seems that fixing the horizontal scale necessitated re-fixing this. -// Not sure why, but seems to be consistent with the vertical scaling now (and -// it may turn out to be wrong!)... - uint16_t horizontalRemainder = hscale; // Not sure if it starts full, but seems reasonable [It's not!] -// uint8_t horizontalRemainder = 0; // Let's try zero! Seems to work! Yay! [No, it doesn't!] + uint16_t horizontalRemainder = hscale; int32_t scaledWidthInPixels = (iwidth * phraseWidthToPixels[depth] * hscale) >> 5; uint32_t scaledPhrasePixels = (phraseWidthToPixels[depth] * hscale) >> 5; -// WriteLog("bitmap %ix? %ibpp at %i,? firstpix=? data=0x%.8x pitch %i hflipped=%s dwidth=? (linked to ?) RMW=%s Tranparent=%s\n", -// iwidth, op_bitmap_bit_depth[bitdepth], xpos, ptr, pitch, (flags&OPFLAG_REFLECT ? "yes" : "no"), (flags&OPFLAG_RMW ? "yes" : "no"), (flags&OPFLAG_TRANS ? "yes" : "no")); - -// Looks like an hscale of zero means don't draw! if (!render || iwidth == 0 || hscale == 0) return; -/*extern int start_logging; -if (start_logging) - WriteLog("OP: Scaled bitmap %ix? %ibpp at %i,? hscale=%02X fpix=%i data=%08X pitch %i hflipped=%s dwidth=? (linked to %08X) Transluency=%s\n", - iwidth, op_bitmap_bit_depth[depth], xpos, hscale, firstPix, data, pitch, (flagREFLECT ? "yes" : "no"), op_pointer, (flagRMW ? "yes" : "no"));*/ -//#define OP_DEBUG_BMP -//#ifdef OP_DEBUG_BMP -// WriteLog("OP: Scaled bitmap %ix%i %ibpp at %i,%i firstpix=%i data=0x%.8x pitch %i hflipped=%s dwidth=%i (linked to 0x%.8x) Transluency=%s\n", -// iwidth, height, op_bitmap_bit_depth[bitdepth], xpos, ypos, firstPix, ptr, pitch, (flags&OPFLAG_REFLECT ? "yes" : "no"), dwidth, op_pointer, (flags&OPFLAG_RMW ? "yes" : "no")); -//#endif - int32_t startPos = xpos, endPos = xpos + (!flagREFLECT ? scaledWidthInPixels - 1 : -(scaledWidthInPixels + 1)); uint32_t clippedWidth = 0, phraseClippedWidth = 0, dataClippedWidth = 0; - bool in24BPPMode = (((GET16(tomRam8, 0x0028) >> 1) & 0x03) == 1 ? true : false); // VMODE - // Not sure if this is Jaguar Two only location or what... - // From the docs, it is... If we want to limit here we should think of something else. -// int32_t limit = GET16(tom_ram_8, 0x0008); // LIMIT + bool in24BPPMode = (((GET16(tomRam8, 0x0028) >> 1) & 0x03) == 1 ? true : false); + int32_t limit = 720; -// int32_t lbufWidth = (!in24BPPMode ? limit - 1 : (limit / 2) - 1); // Zero based limit... - int32_t lbufWidth = 719; // Zero based limit... - - // If the image is completely to the left or right of the line buffer, then bail. -//If in REFLECT mode, then these values are swapped! !!! FIX !!! [DONE] -//There are four possibilities: -// 1. image sits on left edge and no REFLECT; starts out of bounds but ends in bounds. -// 2. image sits on left edge and REFLECT; starts in bounds but ends out of bounds. -// 3. image sits on right edge and REFLECT; starts out of bounds but ends in bounds. -// 4. image sits on right edge and no REFLECT; starts in bounds but ends out of bounds. -//Numbers 2 & 4 can be caught by checking the LBUF clip while in the inner loop, -// numbers 1 & 3 are of concern. -// This *indirectly* handles only cases 2 & 4! And is WRONG if REFLECT is set...! -// if (rightMargin < 0 || leftMargin > lbufWidth) - -// It might be easier to swap these (if REFLECTed) and just use XPOS down below... -// That way, you could simply set XPOS to leftMargin if !REFLECT and to rightMargin otherwise. -// Still have to be careful with the DATA and IWIDTH values though... + int32_t lbufWidth = 719; if ((!flagREFLECT && (endPos < 0 || startPos > lbufWidth)) || (flagREFLECT && (startPos < 0 || endPos > lbufWidth))) return; - // Otherwise, find the clip limits and clip the phrase as well... - // NOTE: I'm fudging here by letting the actual blit overstep the bounds of - // the line buffer, but it shouldn't matter since there are two - // unused line buffers below and nothing above and I'll at most write - // 40 bytes outside the line buffer... I could use a fractional clip - // begin/end value, but this makes the blit a *lot* more hairy. I - // might fix this in the future if it becomes necessary. (JLH) - // Probably wouldn't be *that* hairy. Just use a delta that tells the - // inner loop which pixel in the phrase is being written, and quit - // when either end of phrases is reached or line buffer extents are - // surpassed. + uint32_t scaledPhrasePixelsUS = phraseWidthToPixels[depth] * hscale; -//This stuff is probably wrong as well... !!! FIX !!! -//The strange thing is that it seems to work, but that's no guarantee that it's -//bulletproof! -//Yup. Seems that JagMania doesn't work correctly with this... -//Dunno if this is the problem, but Atari Karts is showing *some* of the road -//now... -//Actually, it is! Or, it was. It doesn't seem to be clipping here, so the -//problem lies elsewhere! Hmm. Putting the scaling code into the 1/2/8 BPP cases -//seems to draw the ground a bit more accurately... Strange! -//It's probably a case of the REFLECT flag being set and the background being -//written from the right side of the screen... -//But no, it isn't... At least if the diagnostics are telling the truth! - - // NOTE: We're just using endPos to figure out how much, if any, to clip by. - // ALSO: There may be another case where we start out of bounds and end out - // of bounds...! - // !!! FIX !!! - -//There's a problem here with scaledPhrasePixels in that it can be forced to -//zero when the scaling factor is small. So fix it already! !!! FIX !!! -/*if (scaledPhrasePixels == 0) -{ - WriteLog("OP: [Scaled] We're about to encounter a divide by zero error!\n"); - DumpScaledObject(p0, p1, p2); -}//*/ -//NOTE: I'm almost 100% sure that this is wrong... And it is! :-p - -//Try a simple example... -// Let's say we have a 8 BPP scanline with an hscale of $80 (4). Our xpos is -10, -// non-flipped. Pixels in the bitmap are XYZXYZXYZXYZXYZ. -// Scaled up, they would be XXXXYYYYZZZZXXXXYYYYZZZZXXXXYYYYZZZZ... -// -// Normally, we would expect this in the line buffer: -// ZZXXXXYYYYZZZZXXXXYYYYZZZZ... -// -// But instead we're getting: -// XXXXYYYYZZZZXXXXYYYYZZZZ... -// -// or are we??? It would seem so, simply by virtue of the fact that we're NOT starting -// on negative boundary--or are we? Hmm... -// cw = 10, dcw = pcw = 10 / ([8 * 4 = 32] 32) = 0, sp = -10 -// -// Let's try a real world example: -// -//OP: Scaled bitmap (70, 8 BPP, spp=28) sp (-400) < 0... [new sp=-8, cw=400, dcw=pcw=14] -//OP: Scaled bitmap (6F, 8 BPP, spp=27) sp (-395) < 0... [new sp=-17, cw=395, dcw=pcw=14] -// -// Really, spp is 27.75 in the second case... -// So... If we do 395 / 27.75, we get 14. Ok so far... If we scale that against the -// start position (14 * 27.75), we get -6.5... NOT -17! - -//Now it seems we're working OK, at least for the first case... -uint32_t scaledPhrasePixelsUS = phraseWidthToPixels[depth] * hscale; - - if (startPos < 0) // Case #1: Begin out, end in, L to R -{ -extern int start_logging; -if (start_logging) - WriteLog("OP: Scaled bitmap (%02X, %u BPP, spp=%u) start pos (%i) < 0...", hscale, op_bitmap_bit_depth[depth], scaledPhrasePixels, startPos); -// clippedWidth = 0 - startPos, + if (startPos < 0) clippedWidth = (0 - startPos) << 5, -// dataClippedWidth = phraseClippedWidth = clippedWidth / scaledPhrasePixels, dataClippedWidth = phraseClippedWidth = (clippedWidth / scaledPhrasePixelsUS) >> 5, -// startPos = 0 - (clippedWidth % scaledPhrasePixels); startPos += (dataClippedWidth * scaledPhrasePixelsUS) >> 5; -if (start_logging) - WriteLog(" [new sp=%i, cw=%i, dcw=pcw=%i]\n", startPos, clippedWidth, dataClippedWidth); -} - if (endPos < 0) // Case #2: Begin in, end out, R to L + if (endPos < 0) clippedWidth = 0 - endPos, phraseClippedWidth = clippedWidth / scaledPhrasePixels; - if (endPos > lbufWidth) // Case #3: Begin in, end out, L to R + if (endPos > lbufWidth) clippedWidth = endPos - lbufWidth, phraseClippedWidth = clippedWidth / scaledPhrasePixels; - if (startPos > lbufWidth) // Case #4: Begin out, end in, R to L + if (startPos > lbufWidth) clippedWidth = startPos - lbufWidth, dataClippedWidth = phraseClippedWidth = clippedWidth / scaledPhrasePixels, startPos = lbufWidth + (clippedWidth % scaledPhrasePixels); -extern int op_start_log; -if (op_start_log && clippedWidth != 0) - WriteLog("OP: Clipped line. SP=%i, EP=%i, clip=%u, iwidth=%u, hscale=%02X\n", startPos, endPos, clippedWidth, iwidth, hscale); -if (op_start_log && startPos == 13) -{ - WriteLog("OP: Scaled line. SP=%i, EP=%i, clip=%u, iwidth=%u, hscale=%02X, depth=%u, firstPix=%u\n", startPos, endPos, clippedWidth, iwidth, hscale, depth, firstPix); - DumpScaledObject(p0, p1, p2); - if (iwidth == 7) - { - WriteLog(" %08X: ", data); - for(int i=0; i<7*8; i++) - WriteLog("%02X ", JaguarReadByte(data+i)); - WriteLog("\n"); - } -} - // If the image is sitting on the line buffer left or right edge, we need to compensate - // by decreasing the image phrase width accordingly. iwidth -= phraseClippedWidth; - // Also, if we're clipping the phrase we need to make sure we're in the correct part of - // the pixel data. -// data += phraseClippedWidth * (pitch << 3); data += dataClippedWidth * (pitch << 3); - // NOTE: When the bitmap is in REFLECT mode, the XPOS marks the *right* side of the - // bitmap! This makes clipping & etc. MUCH, much easier...! -// uint32_t lbufAddress = 0x1800 + (!in24BPPMode ? leftMargin * 2 : leftMargin * 4); -// uint32_t lbufAddress = 0x1800 + (!in24BPPMode ? startPos * 2 : startPos * 4); uint32_t lbufAddress = 0x1800 + startPos * 2; uint8_t * currentLineBuffer = &tomRam8[lbufAddress]; -//uint8_t * lineBufferLowerLimit = &tom_ram_8[0x1800], -// * lineBufferUpperLimit = &tom_ram_8[0x1800 + 719]; - // Render. - -// Hmm. We check above for 24 BPP mode, but don't do anything about it below... -// If we *were* in 24 BPP mode, how would you convert CRY to RGB24? Seems to me -// that if you're in CRY mode then you wouldn't be able to use 24 BPP bitmaps -// anyway. -// This seems to be the case (at least according to the Midsummer docs)...! - - if (depth == 0) // 1 BPP + if (depth == 0) { -if (firstPix != 0) - WriteLog("OP: Scaled bitmap @ 1 BPP requesting FIRSTPIX!\n"); - // The LSB of flags is OPFLAG_REFLECT, so sign extend it and or 2 into it. int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; int pixCount = 0; @@ -1562,17 +698,11 @@ if (firstPix != 0) { uint8_t bits = pixels >> 63; -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bits == 0) -#else - if (flagTRANS && (paletteRAM16[index | bits] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) - // This is the *only* correct use of endian-dependent code - // (i.e., mem-to-mem direct copying)! *(uint16_t *)currentLineBuffer = paletteRAM16[index | bits]; else *currentLineBuffer = @@ -1583,26 +713,13 @@ if (firstPix != 0) currentLineBuffer += lbufDelta; -/* -The reason we subtract the horizontalRemainder *after* the test is because we had too few -bytes for horizontalRemainder to properly recognize a negative number. But now it's 16 bits -wide, so we could probably go back to that (as long as we make it an int16_t and not a uint16!) -*/ -/* horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format - while (horizontalRemainder & 0x80) - { - horizontalRemainder += hscale; - pixCount++; - pixels <<= 1; - }//*/ -// while (horizontalRemainder <= 0x20) // I.e., it's <= 1.0 (*before* subtraction) - while (horizontalRemainder < 0x20) // I.e., it's <= 1.0 (*before* subtraction) + while (horizontalRemainder < 0x20) { horizontalRemainder += hscale; pixCount++; pixels <<= 1; } - horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format + horizontalRemainder -= 0x20; if (pixCount > 63) { @@ -1616,12 +733,9 @@ wide, so we could probably go back to that (as long as we make it an int16_t and } } } - else if (depth == 1) // 2 BPP + else if (depth == 1) { -if (firstPix != 0) - WriteLog("OP: Scaled bitmap @ 2 BPP requesting FIRSTPIX!\n"); - index &= 0xFC; // Top six bits form CLUT index - // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it. + index &= 0xFC; int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; int pixCount = 0; @@ -1631,17 +745,11 @@ if (firstPix != 0) { uint8_t bits = pixels >> 62; -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bits == 0) -#else - if (flagTRANS && (paletteRAM16[index | bits] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) - // This is the *only* correct use of endian-dependent code - // (i.e., mem-to-mem direct copying)! *(uint16_t *)currentLineBuffer = paletteRAM16[index | bits]; else *currentLineBuffer = @@ -1652,21 +760,13 @@ if (firstPix != 0) currentLineBuffer += lbufDelta; -/* horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format - while (horizontalRemainder & 0x80) - { - horizontalRemainder += hscale; - pixCount++; - pixels <<= 2; - }//*/ -// while (horizontalRemainder <= 0x20) // I.e., it's <= 0 (*before* subtraction) - while (horizontalRemainder < 0x20) // I.e., it's <= 1.0 (*before* subtraction) + while (horizontalRemainder < 0x20) { horizontalRemainder += hscale; pixCount++; pixels <<= 2; } - horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format + horizontalRemainder -= 0x20; if (pixCount > 31) { @@ -1680,12 +780,9 @@ if (firstPix != 0) } } } - else if (depth == 2) // 4 BPP + else if (depth == 2) { -if (firstPix != 0) - WriteLog("OP: Scaled bitmap @ 4 BPP requesting FIRSTPIX!\n"); - index &= 0xF0; // Top four bits form CLUT index - // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it. + index &= 0xF0; int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; int pixCount = 0; @@ -1695,17 +792,11 @@ if (firstPix != 0) { uint8_t bits = pixels >> 60; -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bits == 0) -#else - if (flagTRANS && (paletteRAM16[index | bits] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) - // This is the *only* correct use of endian-dependent code - // (i.e., mem-to-mem direct copying)! *(uint16_t *)currentLineBuffer = paletteRAM16[index | bits]; else *currentLineBuffer = @@ -1716,21 +807,13 @@ if (firstPix != 0) currentLineBuffer += lbufDelta; -/* horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format - while (horizontalRemainder & 0x80) - { - horizontalRemainder += hscale; - pixCount++; - pixels <<= 4; - }//*/ -// while (horizontalRemainder <= 0x20) // I.e., it's <= 0 (*before* subtraction) - while (horizontalRemainder < 0x20) // I.e., it's <= 0 (*before* subtraction) + while (horizontalRemainder < 0x20) { horizontalRemainder += hscale; pixCount++; pixels <<= 4; } - horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format + horizontalRemainder -= 0x20; if (pixCount > 15) { @@ -1744,11 +827,8 @@ if (firstPix != 0) } } } - else if (depth == 3) // 8 BPP + else if (depth == 3) { -if (firstPix) - WriteLog("OP: Scaled bitmap @ 8 BPP requesting FIRSTPIX! (fp=%u)\n", firstPix); - // The LSB is OPFLAG_REFLECT, so sign extend it and or 2 into it. int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; int pixCount = 0; @@ -1758,22 +838,12 @@ if (firstPix) { uint8_t bits = pixels >> 56; -#ifndef OP_USES_PALETTE_ZERO if (flagTRANS && bits == 0) -#else - if (flagTRANS && (paletteRAM16[bits] == 0)) -#endif - ; // Do nothing... + ; else { if (!flagRMW) - // This is the *only* correct use of endian-dependent code - // (i.e., mem-to-mem direct copying)! *(uint16_t *)currentLineBuffer = paletteRAM16[bits]; -/* { - if (currentLineBuffer >= lineBufferLowerLimit && currentLineBuffer <= lineBufferUpperLimit) - *(uint16_t *)currentLineBuffer = paletteRAM16[bits]; - }*/ else *currentLineBuffer = BLEND_CR(*currentLineBuffer, paletteRAM[bits << 1]), @@ -1783,14 +853,13 @@ if (firstPix) currentLineBuffer += lbufDelta; -// while (horizontalRemainder <= 0x20) // I.e., it's <= 0 (*before* subtraction) - while (horizontalRemainder < 0x20) // I.e., it's <= 1.0 (*before* subtraction) + while (horizontalRemainder < 0x20) { horizontalRemainder += hscale; pixCount++; pixels <<= 8; } - horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format + horizontalRemainder -= 0x20; if (pixCount > 7) { @@ -1804,11 +873,8 @@ if (firstPix) } } } - else if (depth == 4) // 16 BPP + else if (depth == 4) { -if (firstPix != 0) - WriteLog("OP: Scaled bitmap @ 16 BPP requesting FIRSTPIX!\n"); - // The LSB is OPFLAG_REFLECT, so sign extend it and OR 2 into it. int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 5) | 0x02; int pixCount = 0; @@ -1818,11 +884,8 @@ if (firstPix != 0) { uint8_t bitsHi = pixels >> 56, bitsLo = pixels >> 48; -//This doesn't seem right... Let's try the encoded black value ($8800): -//Apparently, CRY 0 maps to $8800... - if (flagTRANS && ((bitsLo | bitsHi) == 0)) -// if (flagTRANS && (bitsHi == 0x88) && (bitsLo == 0x00)) - ; // Do nothing... + if (flagTRANS && ((bitsLo | bitsHi) == 0)) + ; else { if (!flagRMW) @@ -1837,22 +900,14 @@ if (firstPix != 0) currentLineBuffer += lbufDelta; -/* horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format - while (horizontalRemainder & 0x80) - { - horizontalRemainder += hscale; - pixCount++; - pixels <<= 16; - }//*/ -// while (horizontalRemainder <= 0x20) // I.e., it's <= 0 (*before* subtraction) - while (horizontalRemainder < 0x20) // I.e., it's <= 1.0 (*before* subtraction) + while (horizontalRemainder < 0x20) { horizontalRemainder += hscale; pixCount++; pixels <<= 16; } - horizontalRemainder -= 0x20; // Subtract 1.0f in [3.5] fixed point format -//*/ + horizontalRemainder -= 0x20; + if (pixCount > 3) { int phrasesToSkip = pixCount / 4, pixelShift = pixCount % 4; @@ -1867,21 +922,14 @@ if (firstPix != 0) } } } - else if (depth == 5) // 24 BPP + else if (depth == 5) { -//I'm not sure that you can scale a 24 BPP bitmap properly--the JTRM seem to indicate as much. -WriteLog("OP: Writing 24 BPP scaled bitmap!\n"); -if (firstPix != 0) - WriteLog("OP: Scaled bitmap @ 24 BPP requesting FIRSTPIX!\n"); - // Not sure, but I think RMW only works with 16 BPP and below, and only in CRY mode... - // The LSB is OPFLAG_REFLECT, so sign extend it and or 4 into it. int32_t lbufDelta = ((int8_t)((flags << 7) & 0xFF) >> 4) | 0x04; while (iwidth--) { - // Fetch phrase... uint64_t pixels = ((uint64_t)JaguarReadLong(data, OP) << 32) | JaguarReadLong(data + 4, OP); - data += pitch << 3; // Multiply pitch * 8 (optimize: precompute this value) + data += pitch << 3; for(int i=0; i<2; i++) { @@ -1889,7 +937,7 @@ if (firstPix != 0) bits1 = pixels >> 40, bits0 = pixels >> 32; if (flagTRANS && (bits3 | bits2 | bits1 | bits0) == 0) - ; // Do nothing... + ; else *currentLineBuffer = bits3, *(currentLineBuffer + 1) = bits2, diff --git a/waterbox/virtualjaguar/src/settings.cpp b/waterbox/virtualjaguar/src/settings.cpp index 7cf1efaea4..21c0a92268 100644 --- a/waterbox/virtualjaguar/src/settings.cpp +++ b/waterbox/virtualjaguar/src/settings.cpp @@ -14,7 +14,4 @@ #include "settings.h" -// Global variables - VJSettings vjs; - diff --git a/waterbox/virtualjaguar/src/settings.h b/waterbox/virtualjaguar/src/settings.h index 0b196b72d0..4e49d3227f 100644 --- a/waterbox/virtualjaguar/src/settings.h +++ b/waterbox/virtualjaguar/src/settings.h @@ -5,66 +5,18 @@ #ifndef __SETTINGS_H__ #define __SETTINGS_H__ -#define MAX_PATH 69 - -// MAX_PATH isn't defined in stdlib.h on *nix, so we do it here... -#ifdef __GCCUNIX__ -#include -#define MAX_PATH _POSIX_PATH_MAX -#else -#include // for MAX_PATH on MinGW/Darwin -// Kludge for Win64 -#ifndef MAX_PATH -#define MAX_PATH _MAX_PATH // Urgh. -#endif -#endif #include // Settings struct struct VJSettings { - bool useJoystick; - int32_t joyport; // Joystick port - bool hardwareTypeNTSC; // Set to false for PAL + bool hardwareTypeNTSC; bool useJaguarBIOS; - bool GPUEnabled; - bool DSPEnabled; - bool usePipelinedDSP; - bool fullscreen; - bool useOpenGL; - uint32_t glFilter; bool hardwareTypeAlpine; - bool audioEnabled; - uint32_t frameSkip; - uint32_t renderType; - bool allowWritesToROM; - uint32_t biosType; bool useFastBlitter; - - // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, * - - uint32_t p1KeyBindings[21]; - uint32_t p2KeyBindings[21]; - - // Paths - - char ROMPath[MAX_PATH]; - char jagBootPath[MAX_PATH]; - char CDBootPath[MAX_PATH]; - char EEPROMPath[MAX_PATH]; - char alpineROMPath[MAX_PATH]; - char absROMPath[MAX_PATH]; }; -// Render types - -enum { RT_NORMAL = 0, RT_TV = 1 }; - -// BIOS types - -enum { BT_K_SERIES, BT_M_SERIES, BT_STUBULATOR_1, BT_STUBULATOR_2 }; - // Exported variables extern VJSettings vjs; diff --git a/waterbox/virtualjaguar/src/state.cpp b/waterbox/virtualjaguar/src/state.cpp deleted file mode 100644 index 10fe306d95..0000000000 --- a/waterbox/virtualjaguar/src/state.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// -// state.cpp: VJ machine state save/load support -// -// by James Hammons -// (C) 2010 Underground Software -// -// JLH = James Hammons -// -// Who When What -// --- ---------- ------------------------------------------------------------- -// JLH 01/16/2010 Created this log ;-) -// - -#include "state.h" - -bool SaveState(void) -{ - return false; -} - -bool LoadState(void) -{ - return false; -} - diff --git a/waterbox/virtualjaguar/src/state.h b/waterbox/virtualjaguar/src/state.h deleted file mode 100644 index 54e3730121..0000000000 --- a/waterbox/virtualjaguar/src/state.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// state.h: Machine state save/load support -// -// by James L. Hammons -// - -#ifndef __STATE_H__ -#define __STATE_H__ - -bool SaveState(void); -bool LoadState(void); - -#endif // __STATE_H__ diff --git a/waterbox/virtualjaguar/src/tom.cpp b/waterbox/virtualjaguar/src/tom.cpp index ac67a3fcb4..450bfcb855 100644 --- a/waterbox/virtualjaguar/src/tom.cpp +++ b/waterbox/virtualjaguar/src/tom.cpp @@ -13,260 +13,20 @@ // JLH 01/16/2010 Created this log ;-) // JLH 01/20/2011 Change rendering to RGBA, removed unnecessary code // -// Note: TOM has only a 16K memory space -// -// ------------------------------------------------------------ -// TOM REGISTERS (Mapped by Aaron Giles) -// ------------------------------------------------------------ -// F00000-F0FFFF R/W xxxxxxxx xxxxxxxx Internal Registers -// F00000 R/W -x-xx--- xxxxxxxx MEMCON1 - memory config reg 1 -// -x------ -------- (CPU32 - is the CPU 32bits?) -// ---xx--- -------- (IOSPEED - external I/O clock cycles) -// -------- x------- (FASTROM - reduces ROM clock cycles) -// -------- -xx----- (DRAMSPEED - sets RAM clock cycles) -// -------- ---xx--- (ROMSPEED - sets ROM clock cycles) -// -------- -----xx- (ROMWIDTH - sets width of ROM: 8,16,32,64 bits) -// -------- -------x (ROMHI - controls ROM mapping) -// F00002 R/W --xxxxxx xxxxxxxx MEMCON2 - memory config reg 2 -// --x----- -------- (HILO - image display bit order) -// ---x---- -------- (BIGEND - big endian addressing?) -// ----xxxx -------- (REFRATE - DRAM refresh rate) -// -------- xx------ (DWIDTH1 - DRAM1 width: 8,16,32,64 bits) -// -------- --xx---- (COLS1 - DRAM1 columns: 256,512,1024,2048) -// -------- ----xx-- (DWIDTH0 - DRAM0 width: 8,16,32,64 bits) -// -------- ------xx (COLS0 - DRAM0 columns: 256,512,1024,2048) -// F00004 R/W -----xxx xxxxxxxx HC - horizontal count -// -----x-- -------- (which half of the display) -// ------xx xxxxxxxx (10-bit counter) -// F00006 R/W ----xxxx xxxxxxxx VC - vertical count -// ----x--- -------- (which field is being generated) -// -----xxx xxxxxxxx (11-bit counter) -// F00008 R -----xxx xxxxxxxx LPH - light pen horizontal position -// F0000A R -----xxx xxxxxxxx LPV - light pen vertical position -// F00010-F00017 R xxxxxxxx xxxxxxxx OB - current object code from the graphics processor -// F00020-F00023 W xxxxxxxx xxxxxxxx OLP - start of the object list -// F00026 W -------- -------x OBF - object processor flag -// F00028 W ----xxxx xxxxxxxx VMODE - video mode -// W ----xxx- -------- (PWIDTH1-8 - width of pixel in video clock cycles) -// W -------x -------- (VARMOD - enable variable color resolution) -// W -------- x------- (BGEN - clear line buffer to BG color) -// W -------- -x------ (CSYNC - enable composite sync on VSYNC) -// W -------- --x----- (BINC - local border color if INCEN) -// W -------- ---x---- (INCEN - encrustation enable) -// W -------- ----x--- (GENLOCK - enable genlock) -// W -------- -----xx- (MODE - CRY16,RGB24,DIRECT16,RGB16) -// W -------- -------x (VIDEN - enables video) -// F0002A W xxxxxxxx xxxxxxxx BORD1 - border color (red/green) -// F0002C W -------- xxxxxxxx BORD2 - border color (blue) -// F0002E W ------xx xxxxxxxx HP - horizontal period -// F00030 W -----xxx xxxxxxxx HBB - horizontal blanking begin -// F00032 W -----xxx xxxxxxxx HBE - horizontal blanking end -// F00034 W -----xxx xxxxxxxx HSYNC - horizontal sync -// F00036 W ------xx xxxxxxxx HVS - horizontal vertical sync -// F00038 W -----xxx xxxxxxxx HDB1 - horizontal display begin 1 -// F0003A W -----xxx xxxxxxxx HDB2 - horizontal display begin 2 -// F0003C W -----xxx xxxxxxxx HDE - horizontal display end -// F0003E W -----xxx xxxxxxxx VP - vertical period -// F00040 W -----xxx xxxxxxxx VBB - vertical blanking begin -// F00042 W -----xxx xxxxxxxx VBE - vertical blanking end -// F00044 W -----xxx xxxxxxxx VS - vertical sync -// F00046 W -----xxx xxxxxxxx VDB - vertical display begin -// F00048 W -----xxx xxxxxxxx VDE - vertical display end -// F0004A W -----xxx xxxxxxxx VEB - vertical equalization begin -// F0004C W -----xxx xxxxxxxx VEE - vertical equalization end -// F0004E W -----xxx xxxxxxxx VI - vertical interrupt -// F00050 W xxxxxxxx xxxxxxxx PIT0 - programmable interrupt timer 0 -// F00052 W xxxxxxxx xxxxxxxx PIT1 - programmable interrupt timer 1 -// F00054 W ------xx xxxxxxxx HEQ - horizontal equalization end -// F00058 W xxxxxxxx xxxxxxxx BG - background color -// F000E0 R/W ---xxxxx ---xxxxx INT1 - CPU interrupt control register -// ---x---- -------- (C_JERCLR - clear pending Jerry ints) -// ----x--- -------- (C_PITCLR - clear pending PIT ints) -// -----x-- -------- (C_OPCLR - clear pending object processor ints) -// ------x- -------- (C_GPUCLR - clear pending graphics processor ints) -// -------x -------- (C_VIDCLR - clear pending video timebase ints) -// -------- ---x---- (C_JERENA - enable Jerry ints) -// -------- ----x--- (C_PITENA - enable PIT ints) -// -------- -----x-- (C_OPENA - enable object processor ints) -// -------- ------x- (C_GPUENA - enable graphics processor ints) -// -------- -------x (C_VIDENA - enable video timebase ints) -// F000E2 W -------- -------- INT2 - CPU interrupt resume register -// F00400-F005FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table A -// F00600-F007FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table B -// F00800-F00D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer A -// F01000-F0159F R/W xxxxxxxx xxxxxxxx LBUF - line buffer B -// F01800-F01D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer currently selected -// ------------------------------------------------------------ -// F02000-F021FF R/W xxxxxxxx xxxxxxxx GPU control registers -// F02100 R/W xxxxxxxx xxxxxxxx G_FLAGS - GPU flags register -// R/W x------- -------- (DMAEN - DMA enable) -// R/W -x------ -------- (REGPAGE - register page) -// W --x----- -------- (G_BLITCLR - clear blitter interrupt) -// W ---x---- -------- (G_OPCLR - clear object processor int) -// W ----x--- -------- (G_PITCLR - clear PIT interrupt) -// W -----x-- -------- (G_JERCLR - clear Jerry interrupt) -// W ------x- -------- (G_CPUCLR - clear CPU interrupt) -// R/W -------x -------- (G_BLITENA - enable blitter interrupt) -// R/W -------- x------- (G_OPENA - enable object processor int) -// R/W -------- -x------ (G_PITENA - enable PIT interrupt) -// R/W -------- --x----- (G_JERENA - enable Jerry interrupt) -// R/W -------- ---x---- (G_CPUENA - enable CPU interrupt) -// R/W -------- ----x--- (IMASK - interrupt mask) -// R/W -------- -----x-- (NEGA_FLAG - ALU negative) -// R/W -------- ------x- (CARRY_FLAG - ALU carry) -// R/W -------- -------x (ZERO_FLAG - ALU zero) -// F02104 W -------- ----xxxx G_MTXC - matrix control register -// W -------- ----x--- (MATCOL - column/row major) -// W -------- -----xxx (MATRIX3-15 - matrix width) -// F02108 W ----xxxx xxxxxx-- G_MTXA - matrix address register -// F0210C W -------- -----xxx G_END - data organization register -// W -------- -----x-- (BIG_INST - big endian instruction fetch) -// W -------- ------x- (BIG_PIX - big endian pixels) -// W -------- -------x (BIG_IO - big endian I/O) -// F02110 R/W xxxxxxxx xxxxxxxx G_PC - GPU program counter -// F02114 R/W xxxxxxxx xx-xxxxx G_CTRL - GPU control/status register -// R xxxx---- -------- (VERSION - GPU version code) -// R/W ----x--- -------- (BUS_HOG - hog the bus!) -// R/W -----x-- -------- (G_BLITLAT - blitter interrupt latch) -// R/W ------x- -------- (G_OPLAT - object processor int latch) -// R/W -------x -------- (G_PITLAT - PIT interrupt latch) -// R/W -------- x------- (G_JERLAT - Jerry interrupt latch) -// R/W -------- -x------ (G_CPULAT - CPU interrupt latch) -// R/W -------- ---x---- (SINGLE_GO - single step one instruction) -// R/W -------- ----x--- (SINGLE_STEP - single step mode) -// R/W -------- -----x-- (FORCEINT0 - cause interrupt 0 on GPU) -// R/W -------- ------x- (CPUINT - send GPU interrupt to CPU) -// R/W -------- -------x (GPUGO - enable GPU execution) -// F02118-F0211B R/W xxxxxxxx xxxxxxxx G_HIDATA - high data register -// F0211C-F0211F R xxxxxxxx xxxxxxxx G_REMAIN - divide unit remainder -// F0211C W -------- -------x G_DIVCTRL - divide unit control -// W -------- -------x (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide) -// ------------------------------------------------------------ -// BLITTER REGISTERS -// ------------------------------------------------------------ -// F02200-F022FF R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Blitter registers -// F02200 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_BASE - A1 base register -// F02204 W -------- ---xxxxx -xxxxxxx xxxxx-xx A1_FLAGS - A1 flags register -// W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta) -// W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta) -// W -------- -----x-- -------- -------- (Y add control) -// W -------- ------xx -------- -------- (X add control) -// W -------- -------- -xxxxxx- -------- (width in 6-bit floating point) -// W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset) -// W -------- -------- -------- --xxx--- (PIXEL - pixel size) -// W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch) -// F02208 W -xxxxxxx xxxxxxxx -xxxxxxx xxxxxxxx A1_CLIP - A1 clipping size -// W -xxxxxxx xxxxxxxx -------- -------- (height) -// W -------- -------- -xxxxxxx xxxxxxxx (width) -// F0220C R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_PIXEL - A1 pixel pointer -// R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value) -// R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value) -// F02210 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_STEP - A1 step value -// W xxxxxxxx xxxxxxxx -------- -------- (Y step value) -// W -------- -------- xxxxxxxx xxxxxxxx (X step value) -// F02214 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FSTEP - A1 step fraction value -// W xxxxxxxx xxxxxxxx -------- -------- (Y step fraction value) -// W -------- -------- xxxxxxxx xxxxxxxx (X step fraction value) -// F02218 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FPIXEL - A1 pixel pointer fraction -// R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel fraction value) -// R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel fraction value) -// F0221C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_INC - A1 increment -// W xxxxxxxx xxxxxxxx -------- -------- (Y increment) -// W -------- -------- xxxxxxxx xxxxxxxx (X increment) -// F02220 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FINC - A1 increment fraction -// W xxxxxxxx xxxxxxxx -------- -------- (Y increment fraction) -// W -------- -------- xxxxxxxx xxxxxxxx (X increment fraction) -// F02224 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_BASE - A2 base register -// F02228 W -------- ---xxxxx -xxxxxxx xxxxx-xx A2_FLAGS - A2 flags register -// W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta) -// W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta) -// W -------- -----x-- -------- -------- (Y add control) -// W -------- ------xx -------- -------- (X add control) -// W -------- -------- -xxxxxx- -------- (width in 6-bit floating point) -// W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset) -// W -------- -------- -------- --xxx--- (PIXEL - pixel size) -// W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch) -// F0222C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_MASK - A2 window mask -// F02230 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_PIXEL - A2 pixel pointer -// R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value) -// R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value) -// F02234 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_STEP - A2 step value -// W xxxxxxxx xxxxxxxx -------- -------- (Y step value) -// W -------- -------- xxxxxxxx xxxxxxxx (X step value) -// F02238 W -xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - command register -// W -x------ -------- -------- -------- (SRCSHADE - modify source intensity) -// W --x----- -------- -------- -------- (BUSHI - hi priority bus) -// W ---x---- -------- -------- -------- (BKGWREN - writeback destination) -// W ----x--- -------- -------- -------- (DCOMPEN - write inhibit from data comparator) -// W -----x-- -------- -------- -------- (BCOMPEN - write inhibit from bit coparator) -// W ------x- -------- -------- -------- (CMPDST - compare dest instead of src) -// W -------x xxx----- -------- -------- (logical operation) -// W -------- ---xxx-- -------- -------- (ZMODE - Z comparator mode) -// W -------- ------x- -------- -------- (ADDDSEL - select sum of src & dst) -// W -------- -------x -------- -------- (PATDSEL - select pattern data) -// W -------- -------- x------- -------- (TOPNEN - enable carry into top intensity nibble) -// W -------- -------- -x------ -------- (TOPBEN - enable carry into top intensity byte) -// W -------- -------- --x----- -------- (ZBUFF - enable Z updates in inner loop) -// W -------- -------- ---x---- -------- (GOURD - enable gouraud shading in inner loop) -// W -------- -------- ----x--- -------- (DSTA2 - reverses A2/A1 roles) -// W -------- -------- -----x-- -------- (UPDA2 - add A2 step to A2 in outer loop) -// W -------- -------- ------x- -------- (UPDA1 - add A1 step to A1 in outer loop) -// W -------- -------- -------x -------- (UPDA1F - add A1 fraction step to A1 in outer loop) -// W -------- -------- -------- x------- (diagnostic use) -// W -------- -------- -------- -x------ (CLIP_A1 - clip A1 to window) -// W -------- -------- -------- --x----- (DSTWRZ - enable dest Z write in inner loop) -// W -------- -------- -------- ---x---- (DSTENZ - enable dest Z read in inner loop) -// W -------- -------- -------- ----x--- (DSTEN - enables dest data read in inner loop) -// W -------- -------- -------- -----x-- (SRCENX - enable extra src read at start of inner) -// W -------- -------- -------- ------x- (SRCENZ - enables source Z read in inner loop) -// W -------- -------- -------- -------x (SRCEN - enables source data read in inner loop) -// F02238 R xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - status register -// R xxxxxxxx xxxxxxxx -------- -------- (inner count) -// R -------- -------- xxxxxxxx xxxxxx-- (diagnostics) -// R -------- -------- -------- ------x- (STOPPED - when stopped in collision detect) -// R -------- -------- -------- -------x (IDLE - when idle) -// F0223C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_COUNT - counters register -// W xxxxxxxx xxxxxxxx -------- -------- (outer loop count) -// W -------- -------- xxxxxxxx xxxxxxxx (inner loop count) -// F02240-F02247 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCD - source data register -// F02248-F0224F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTD - destination data register -// F02250-F02257 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTZ - destination Z register -// F02258-F0225F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ1 - source Z register 1 -// F02260-F02267 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ2 - source Z register 2 -// F02268-F0226F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_PATD - pattern data register -// F02270 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_IINC - intensity increment -// F02274 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_ZINC - Z increment -// F02278 W -------- -------- -------- -----xxx B_STOP - collision control -// W -------- -------- -------- -----x-- (STOPEN - enable blitter collision stops) -// W -------- -------- -------- ------x- (ABORT - abort after stop) -// W -------- -------- -------- -------x (RESUME - resume after stop) -// F0227C W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I3 - intensity 3 -// F02280 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I2 - intensity 2 -// F02284 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I1 - intensity 1 -// F02288 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I0 - intensity 0 -// F0228C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z3 - Z3 -// F02290 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z2 - Z2 -// F02294 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z1 - Z1 -// F02298 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z0 - Z0 -// ------------------------------------------------------------ #include "tom.h" -#include // For memset() -#include // For rand() +#include +#include #include "blitter.h" #include "cry2rgb.h" #include "event.h" #include "gpu.h" #include "jaguar.h" -#include "log.h" #include "m68000/m68kinterface.h" -//#include "memory.h" #include "op.h" #include "settings.h" -#define NEW_TIMER_SYSTEM - // TOM registers (offset from $F00000) #define MEMCON1 0x00 @@ -306,46 +66,16 @@ #define INT1 0xE0 #define INT2 0xE2 -// Arbitrary video cutoff values (i.e., first/last visible spots on a TV, in HC -// ticks) -// Also note that VC is in *half* lines, i.e. divide by 2 to get the scanline -/*#define LEFT_VISIBLE_HC 208 -#define RIGHT_VISIBLE_HC 1528//*/ -// These were right for Rayman, but that one is offset on a real TV too. -//#define LEFT_VISIBLE_HC 208 -//#define RIGHT_VISIBLE_HC 1488 -// This is more like a real TV display... -//#define LEFT_VISIBLE_HC (208 - 32) -//#define RIGHT_VISIBLE_HC (1488 - 32) -// Split the difference? (Seems to be OK for the most part...) - -// (-10 +10)*4 is for opening up the display by 16 pixels (may go to 20). Need to change VIRTUAL_SCREEN_WIDTH to match this as well (went from 320 to 340; this is 4 HCs per one of those pixels). -//NB: Went back to 330. May shrink more. :-) -//#define LEFT_VISIBLE_HC (208 - 16 - (8 * 4)) -//#define LEFT_VISIBLE_HC (208 - 16 - (3 * 4)) #define LEFT_VISIBLE_HC (208 - 16 - (1 * 4)) -//#define RIGHT_VISIBLE_HC (1488 - 16 + (10 * 4)) #define RIGHT_VISIBLE_HC (LEFT_VISIBLE_HC + (VIRTUAL_SCREEN_WIDTH * 4)) -//#define TOP_VISIBLE_VC 25 -//#define BOTTOM_VISIBLE_VC 503 #define TOP_VISIBLE_VC 31 #define BOTTOM_VISIBLE_VC 511 -//Are these PAL horizontals correct? -//They seem to be for the most part, but there are some games that seem to be -//shifted over to the right from this "window". -//#define LEFT_VISIBLE_HC_PAL (208 - 16 - (4 * 4)) -//#define LEFT_VISIBLE_HC_PAL (208 - 16 - (-1 * 4)) #define LEFT_VISIBLE_HC_PAL (208 - 16 - (-3 * 4)) -//#define RIGHT_VISIBLE_HC_PAL (1488 - 16 + (10 * 4)) #define RIGHT_VISIBLE_HC_PAL (LEFT_VISIBLE_HC_PAL + (VIRTUAL_SCREEN_WIDTH * 4)) #define TOP_VISIBLE_VC_PAL 67 #define BOTTOM_VISIBLE_VC_PAL 579 -//This can be defined in the makefile as well... -//(It's easier to do it here, though...) -//#define TOM_DEBUG - uint8_t tomRam8[0x4000]; uint32_t tomWidth, tomHeight; uint32_t tomTimerPrescaler; @@ -354,15 +84,9 @@ int32_t tomTimerCounter; uint16_t tom_jerry_int_pending, tom_timer_int_pending, tom_object_int_pending, tom_gpu_int_pending, tom_video_int_pending; -// These are set by the "user" of the Jaguar core lib, since these are -// OS/system dependent. uint32_t * screenBuffer; uint32_t screenPitch; -static const char * videoMode_to_str[8] = - { "16 BPP CRY", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB", - "Mixed mode", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB" }; - typedef void (render_xxx_scanline_fn)(uint32_t *); // Private function prototypes @@ -373,7 +97,6 @@ void tom_render_16bpp_direct_scanline(uint32_t * backbuffer); void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer); void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer); -//render_xxx_scanline_fn * scanline_render_normal[] = render_xxx_scanline_fn * scanline_render[] = { tom_render_16bpp_cry_scanline, @@ -386,192 +109,17 @@ render_xxx_scanline_fn * scanline_render[] = tom_render_16bpp_rgb_scanline }; -// Screen info for various games [PAL]... -/* -BIOS -TOM: Horizontal Period written by M68K: 850 (+1*2 = 1702) -TOM: Horizontal Blank Begin written by M68K: 1711 -TOM: Horizontal Blank End written by M68K: 158 -TOM: Horizontal Display End written by M68K: 1696 -TOM: Horizontal Display Begin 1 written by M68K: 166 -TOM: Vertical Period written by M68K: 623 (non-interlaced) -TOM: Vertical Blank End written by M68K: 34 -TOM: Vertical Display Begin written by M68K: 46 -TOM: Vertical Display End written by M68K: 526 -TOM: Vertical Blank Begin written by M68K: 600 -TOM: Vertical Sync written by M68K: 618 -TOM: Horizontal Display End written by M68K: 1665 -TOM: Horizontal Display Begin 1 written by M68K: 203 -TOM: Vertical Display Begin written by M68K: 38 -TOM: Vertical Display End written by M68K: 518 -TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 151) -TOM: Horizontal Display End written by M68K: 1713 -TOM: Horizontal Display Begin 1 written by M68K: 157 -TOM: Vertical Display Begin written by M68K: 35 -TOM: Vertical Display End written by M68K: 2047 -Horizontal range: 157 - 1713 (width: 1557 / 4 = 389.25, / 5 = 315.4) - -Asteroid -TOM: Horizontal Period written by M68K: 845 (+1*2 = 1692) -TOM: Horizontal Blank Begin written by M68K: 1700 -TOM: Horizontal Blank End written by M68K: 122 -TOM: Horizontal Display End written by M68K: 1600 -TOM: Horizontal Display Begin 1 written by M68K: 268 -TOM: Vertical Period written by M68K: 523 (non-interlaced) -TOM: Vertical Blank End written by M68K: 40 -TOM: Vertical Display Begin written by M68K: 44 -TOM: Vertical Display End written by M68K: 492 -TOM: Vertical Blank Begin written by M68K: 532 -TOM: Vertical Sync written by M68K: 513 -TOM: Video Mode written by M68K: 04C7. PWIDTH = 3, MODE = 16 BPP RGB, flags: BGEN (VC = 461) - -Rayman -TOM: Horizontal Display End written by M68K: 1713 -TOM: Horizontal Display Begin 1 written by M68K: 157 -TOM: Vertical Display Begin written by M68K: 35 -TOM: Vertical Display End written by M68K: 2047 -TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 89) -TOM: Horizontal Display Begin 1 written by M68K: 208 -TOM: Horizontal Display End written by M68K: 1662 -TOM: Vertical Display Begin written by M68K: 100 -TOM: Vertical Display End written by M68K: 2047 -TOM: Video Mode written by M68K: 07C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN VARMOD (VC = 205) -Horizontal range: 208 - 1662 (width: 1455 / 4 = 363.5) - -Alien vs Predator -TOM: Vertical Display Begin written by M68K: 96 -TOM: Vertical Display End written by M68K: 2047 -TOM: Horizontal Display Begin 1 written by M68K: 239 -TOM: Horizontal Display End written by M68K: 1692 -TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 378) -TOM: Vertical Display Begin written by M68K: 44 -TOM: Vertical Display End written by M68K: 2047 -TOM: Horizontal Display Begin 1 written by M68K: 239 -TOM: Horizontal Display End written by M68K: 1692 -TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 559) -TOM: Vertical Display Begin written by M68K: 84 -TOM: Vertical Display End written by M68K: 2047 -TOM: Horizontal Display Begin 1 written by M68K: 239 -TOM: Horizontal Display End written by M68K: 1692 -TOM: Vertical Display Begin written by M68K: 44 -TOM: Vertical Display End written by M68K: 2047 -TOM: Horizontal Display Begin 1 written by M68K: 239 -TOM: Horizontal Display End written by M68K: 1692 -Horizontal range: 239 - 1692 (width: 1454 / 4 = 363.5) - -*/ - -// Screen info for various games [NTSC]... -/* -Doom -TOM: Horizontal Display End written by M68K: 1727 -TOM: Horizontal Display Begin 1 written by M68K: 123 -TOM: Vertical Display Begin written by M68K: 25 -TOM: Vertical Display End written by M68K: 2047 -TOM: Video Mode written by M68K: 0EC1. PWIDTH = 8, MODE = 16 BPP CRY, flags: BGEN (VC = 5) -Also does PWIDTH = 4... -Vertical resolution: 238 lines - -Rayman -TOM: Horizontal Display End written by M68K: 1727 -TOM: Horizontal Display Begin 1 written by M68K: 123 -TOM: Vertical Display Begin written by M68K: 25 -TOM: Vertical Display End written by M68K: 2047 -TOM: Vertical Interrupt written by M68K: 507 -TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 92) -TOM: Horizontal Display Begin 1 written by M68K: 208 -TOM: Horizontal Display End written by M68K: 1670 -Display starts at 31, then 52! -Vertical resolution: 238 lines - -Atari Karts -TOM: Horizontal Display End written by M68K: 1727 -TOM: Horizontal Display Begin 1 written by M68K: 123 -TOM: Vertical Display Begin written by M68K: 25 -TOM: Vertical Display End written by M68K: 2047 -TOM: Video Mode written by GPU: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 4) -TOM: Video Mode written by GPU: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 508) -Display starts at 31 (PWIDTH = 4), 24 (PWIDTH = 5) - -Iron Soldier -TOM: Vertical Interrupt written by M68K: 2047 -TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 0) -TOM: Horizontal Display End written by M68K: 1727 -TOM: Horizontal Display Begin 1 written by M68K: 123 -TOM: Vertical Display Begin written by M68K: 25 -TOM: Vertical Display End written by M68K: 2047 -TOM: Vertical Interrupt written by M68K: 507 -TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 369) -TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 510) -TOM: Video Mode written by M68K: 06C3. PWIDTH = 4, MODE = 24 BPP RGB, flags: BGEN (VC = 510) -Display starts at 31 -Vertical resolution: 238 lines -[Seems to be a problem between the horizontal positioning of the 16-bit CRY & 24-bit RGB] - -JagMania -TOM: Horizontal Period written by M68K: 844 (+1*2 = 1690) -TOM: Horizontal Blank Begin written by M68K: 1713 -TOM: Horizontal Blank End written by M68K: 125 -TOM: Horizontal Display End written by M68K: 1696 -TOM: Horizontal Display Begin 1 written by M68K: 166 -TOM: Vertical Period written by M68K: 523 (non-interlaced) -TOM: Vertical Blank End written by M68K: 24 -TOM: Vertical Display Begin written by M68K: 46 -TOM: Vertical Display End written by M68K: 496 -TOM: Vertical Blank Begin written by M68K: 500 -TOM: Vertical Sync written by M68K: 517 -TOM: Vertical Interrupt written by M68K: 497 -TOM: Video Mode written by M68K: 04C1. PWIDTH = 3, MODE = 16 BPP CRY, flags: BGEN (VC = 270) -Display starts at 55 - -Double Dragon V -TOM: Horizontal Display End written by M68K: 1727 -TOM: Horizontal Display Begin 1 written by M68K: 123 -TOM: Vertical Display Begin written by M68K: 25 -TOM: Vertical Display End written by M68K: 2047 -TOM: Vertical Interrupt written by M68K: 507 -TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 9) - -Dino Dudes -TOM: Horizontal Display End written by M68K: 1823 -TOM: Horizontal Display Begin 1 written by M68K: 45 -TOM: Vertical Display Begin written by M68K: 40 -TOM: Vertical Display End written by M68K: 2047 -TOM: Vertical Interrupt written by M68K: 491 -TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 398) -Display starts at 11 (123 - 45 = 78, 78 / 4 = 19 pixels to skip) -Width is 417, so maybe width of 379 would be good (starting at 123, ending at 1639) -Vertical resolution: 238 lines - -Flashback -TOM: Horizontal Display End written by M68K: 1727 -TOM: Horizontal Display Begin 1 written by M68K: 188 -TOM: Vertical Display Begin written by M68K: 1 -TOM: Vertical Display End written by M68K: 2047 -TOM: Vertical Interrupt written by M68K: 483 -TOM: Video Mode written by M68K: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 99) -Width would be 303 with above scheme, but border width would be 13 pixels - -Trevor McFur -Vertical resolution: 238 lines -*/ - -// 16-bit color lookup tables uint32_t RGB16ToRGB32[0x10000]; uint32_t CRY16ToRGB32[0x10000]; uint32_t MIX16ToRGB32[0x10000]; - -#warning "This is not endian-safe. !!! FIX !!!" void TOMFillLookupTables(void) { - // NOTE: Jaguar 16-bit (non-CRY) color is RBG 556 like so: - // RRRR RBBB BBGG GGGG for(uint32_t i=0; i<0x10000; i++) RGB16ToRGB32[i] = - ((i & 0xF800) << 8) // Red - | ((i & 0x003F) << 10) // Green - | ((i & 0x07C0) >> 3); // Blue + ((i & 0xF800) << 8) + | ((i & 0x003F) << 10) + | ((i & 0x07C0) >> 3); for(uint32_t i=0; i<0x10000; i++) { @@ -588,105 +136,77 @@ void TOMFillLookupTables(void) } } - void TOMSetPendingJERRYInt(void) { tom_jerry_int_pending = 1; } - void TOMSetPendingTimerInt(void) { tom_timer_int_pending = 1; } - void TOMSetPendingObjectInt(void) { tom_object_int_pending = 1; } - void TOMSetPendingGPUInt(void) { tom_gpu_int_pending = 1; } - void TOMSetPendingVideoInt(void) { tom_video_int_pending = 1; } - uint8_t * TOMGetRamPointer(void) { return tomRam8; } - uint8_t TOMGetVideoMode(void) { uint16_t vmode = GET16(tomRam8, VMODE); return ((vmode & VARMOD) >> 6) | ((vmode & MODE) >> 1); } - -//Used in only one place (and for debug purposes): OBJECTP.CPP -#warning "Used in only one place (and for debug purposes): OBJECTP.CPP !!! FIX !!!" uint16_t TOMGetVDB(void) { return GET16(tomRam8, VDB); } - uint16_t TOMGetHC(void) { return GET16(tomRam8, HC); } - uint16_t TOMGetVP(void) { return GET16(tomRam8, VP); } - uint16_t TOMGetMEMCON1(void) { return GET16(tomRam8, MEMCON1); } - -#define LEFT_BG_FIX // // 16 BPP CRY/RGB mixed mode rendering // void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer) { -//CHANGED TO 32BPP RENDERING uint16_t width = tomWidth; uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; - //New stuff--restrict our drawing... uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; - //NOTE: May have to check HDB2 as well! - // Get start position in HC ticks int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); - // Convert to pixels startPos /= pwidth; if (startPos < 0) - // This is x2 because current_line_buffer is uint8_t & we're in a 16bpp mode current_line_buffer += 2 * -startPos; else -//This case doesn't properly handle the "start on the right side of virtual screen" case -//Dunno why--looks Ok... -//What *is* for sure wrong is that it doesn't copy the linebuffer's BG pixels... [FIXED NOW] -//This should likely be 4 instead of 2 (?--not sure) -// Actually, there should be NO multiplier, as startPos is expressed in PIXELS -// and so is the backbuffer. -#ifdef LEFT_BG_FIX { uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; uint32_t pixel = (r << 16) | (g << 8) | b; @@ -696,9 +216,6 @@ void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer) width -= startPos; } -#else - backbuffer += 2 * startPos, width -= startPos; -#endif while (width) { @@ -709,26 +226,21 @@ void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer) } } - // // 16 BPP CRY mode rendering // void tom_render_16bpp_cry_scanline(uint32_t * backbuffer) { -//CHANGED TO 32BPP RENDERING uint16_t width = tomWidth; uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; - //New stuff--restrict our drawing... uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; - //NOTE: May have to check HDB2 as well! - int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);// Get start position in HC ticks + int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); startPos /= pwidth; if (startPos < 0) current_line_buffer += 2 * -startPos; else -#ifdef LEFT_BG_FIX { uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; uint32_t pixel = (r << 16) | (g << 8) | b; @@ -738,10 +250,6 @@ void tom_render_16bpp_cry_scanline(uint32_t * backbuffer) width -= startPos; } -#else -//This should likely be 4 instead of 2 (?--not sure) - backbuffer += 2 * startPos, width -= startPos; -#endif while (width) { @@ -752,26 +260,21 @@ void tom_render_16bpp_cry_scanline(uint32_t * backbuffer) } } - // // 24 BPP mode rendering // void tom_render_24bpp_scanline(uint32_t * backbuffer) { -//CHANGED TO 32BPP RENDERING uint16_t width = tomWidth; uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; - //New stuff--restrict our drawing... uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; - //NOTE: May have to check HDB2 as well! - int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks + int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); startPos /= pwidth; if (startPos < 0) current_line_buffer += 4 * -startPos; else -#ifdef LEFT_BG_FIX { uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; uint32_t pixel = (r << 16) | (g << 8) | b; @@ -781,10 +284,6 @@ void tom_render_24bpp_scanline(uint32_t * backbuffer) width -= startPos; } -#else -//This should likely be 4 instead of 2 (?--not sure) - backbuffer += 2 * startPos, width -= startPos; -#endif while (width) { @@ -797,9 +296,6 @@ void tom_render_24bpp_scanline(uint32_t * backbuffer) } } - -// Seems to me that this is NOT a valid mode--the JTRM seems to imply that you -// would need extra hardware outside of the Jaguar console to support this! // // 16 BPP direct mode rendering // @@ -817,28 +313,21 @@ void tom_render_16bpp_direct_scanline(uint32_t * backbuffer) } } - // // 16 BPP RGB mode rendering // void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer) { -//CHANGED TO 32BPP RENDERING - // 16 BPP RGB: 0-5 green, 6-10 blue, 11-15 red - uint16_t width = tomWidth; uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; - //New stuff--restrict our drawing... uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; - //NOTE: May have to check HDB2 as well! - int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks + int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); startPos /= pwidth; if (startPos < 0) current_line_buffer += 2 * -startPos; else -#ifdef LEFT_BG_FIX { uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; uint32_t pixel = (r << 16) | (g << 8) | b; @@ -848,10 +337,6 @@ void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer) width -= startPos; } -#else -//This should likely be 4 instead of 2 (?--not sure) - backbuffer += 2 * startPos, width -= startPos; -#endif while (width) { @@ -862,7 +347,6 @@ void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer) } } - // // Process a single halfline // @@ -872,72 +356,12 @@ void TOMExecHalfline(uint16_t halfline, bool render) halfline &= 0x07FF; bool inActiveDisplayArea = true; - // Execute OP only on even halflines (skip higher resolutions for now...) if (halfline & 0x01) return; -//Hm, it seems that the OP needs to execute from zero, so let's try it: -// And it works! But need to do some optimizations in the OP to keep it from -// attempting to do a scanline render in the non-display area... [DONE] -//this seems to cause a regression in certain games, like rayman -//which means I have to dig thru the asic nets to see what's wrong... -/* -No, the OP doesn't start until VDB, that much is certain. The thing is, VDB is -the HALF line that the OP starts on--which means that it needs to start at -VDB / 2!!! - -Hrm, doesn't seem to be enough, though it should be... still sticks for 20 -frames. - -What triggers this is writing $FFFF to VDE. This causes the OP start signal in VID to latch on, which in effect sets VDB to zero. So that much is correct. But -the thing with Rayman is that it shouldn't cause the graphical glitches seen -there, so still have to investigate what's going on there. By all rights, it -shouldn't glitch because: - -00006C00: 0000000D 82008F73 (BRANCH) YPOS=494, CC=">", link=$00006C10 -00006C08: 000003FF 00008173 (BRANCH) YPOS=46, CC=">", link=$001FF800 -00006C10: 00000000 0000000C (STOP) -001FF800: 12FC2BFF 02380000 (BITMAP) - 00008004 8180CFF1 - -Even if the OP is running all the time, the link should tell it to stop at the -right place (which it seems to do). But we still get glitchy screen. - -Seems the glitchy screen went away... Maybe the GPU alignment fixes fixed it??? -Just need to add the proper checking here then. - -Some numbers, courtesy of the Jaguar BIOS: -// NTSC: -VP, 523 // Vertical Period (1-based; in this case VP = 524) -VBE, 24 // Vertical Blank End -VDB, 38 // Vertical Display Begin -VDE, 518 // Vertical Display End -VBB, 500 // Vertical Blank Begin -VS, 517 // Vertical Sync - -// PAL Jaguar -VP, 623 // Vertical Period (1-based; in this case VP = 624) -VBE, 34 // Vertical Blank End -VDB, 38 // Vertical Display Begin -VDE, 518 // Vertical Display End -VBB, 600 // Vertical Blank Begin -VS, 618 // Vertical Sync - -Numbers for KM, NTSC: -KM: (Note that with VDE <= 507, the OP starts at VDB as expected) -TOM: Vertical Display Begin written by M68K: 41 -TOM: Vertical Display End written by M68K: 2047 -TOM: Vertical Interrupt written by M68K: 491 -*/ - - // Initial values that "well behaved" programs use uint16_t startingHalfline = GET16(tomRam8, VDB); uint16_t endingHalfline = GET16(tomRam8, VDE); - // Simulate the OP start bug here! - // Really, this value is somewhere around 507 for an NTSC Jaguar. But this - // should work in a majority of cases, at least until we can figure it out - // properly. if (endingHalfline > GET16(tomRam8, VP)) startingHalfline = 0; @@ -948,8 +372,7 @@ TOM: Vertical Interrupt written by M68K: 491 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; uint8_t bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1]; - // Clear line buffer with BG - if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)... + if (GET16(tomRam8, VMODE) & BGEN) for(uint32_t i=0; i<720; i++) *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO; @@ -959,97 +382,25 @@ TOM: Vertical Interrupt written by M68K: 491 else inActiveDisplayArea = false; - // Take PAL into account... - uint16_t topVisible = (vjs.hardwareTypeNTSC ? TOP_VISIBLE_VC : TOP_VISIBLE_VC_PAL), bottomVisible = (vjs.hardwareTypeNTSC ? BOTTOM_VISIBLE_VC : BOTTOM_VISIBLE_VC_PAL); uint32_t * TOMCurrentLine = 0; - // Bit 0 in VP is interlace flag. 0 = interlace, 1 = non-interlaced if (tomRam8[VP + 1] & 0x01) - TOMCurrentLine = &(screenBuffer[((halfline - topVisible) / 2) * screenPitch]);//non-interlace + TOMCurrentLine = &(screenBuffer[((halfline - topVisible) / 2) * screenPitch]); else - TOMCurrentLine = &(screenBuffer[(((halfline - topVisible) / 2) * screenPitch * 2) + (field2 ? 0 : screenPitch)]);//interlace - - // Here's our virtualized scanline code... + TOMCurrentLine = &(screenBuffer[(((halfline - topVisible) / 2) * screenPitch * 2) + (field2 ? 0 : screenPitch)]); if ((halfline >= topVisible) && (halfline < bottomVisible)) { if (inActiveDisplayArea) { -#warning "The following doesn't put BORDER color on the sides... !!! FIX !!!" - if (vjs.renderType == RT_NORMAL) - { - scanline_render[TOMGetVideoMode()](TOMCurrentLine); - } - else - { - // TV type render -/* - tom_render_16bpp_cry_scanline, - tom_render_24bpp_scanline, - tom_render_16bpp_direct_scanline, - tom_render_16bpp_rgb_scanline, - tom_render_16bpp_cry_rgb_mix_scanline, - tom_render_24bpp_scanline, - tom_render_16bpp_direct_scanline, - tom_render_16bpp_rgb_scanline -#define VMODE 0x28 -#define MODE 0x0006 // Line buffer to video generator mode -#define VARMOD 0x0100 // Mixed CRY/RGB16 mode (only works in MODE 0!) -*/ - uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; - uint8_t mode = ((GET16(tomRam8, VMODE) & MODE) >> 1); - bool varmod = GET16(tomRam8, VMODE) & VARMOD; -//The video texture line buffer ranges from 0 to 1279, with its left edge -//starting at LEFT_VISIBLE_HC. So, we need to start writing into the backbuffer -//at HDB1, using pwidth as our scaling factor. The way it generates its image -//on a real TV! - -//So, for example, if HDB1 is less than LEFT_VISIBLE_HC, then we have to figure -//out where in the VTLB that we start writing pixels from the Jaguar line -//buffer (VTLB start=0, JLB=something). -#if 0 -// -// 24 BPP mode rendering -// -void tom_render_24bpp_scanline(uint32_t * backbuffer) -{ -//CHANGED TO 32BPP RENDERING - uint16_t width = tomWidth; - uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; - - //New stuff--restrict our drawing... - uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; - //NOTE: May have to check HDB2 as well! - int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks - startPos /= pwidth; - if (startPos < 0) - current_line_buffer += 4 * -startPos; - else -//This should likely be 4 instead of 2 (?--not sure) - backbuffer += 2 * startPos, width -= startPos; - - while (width) - { - uint32_t g = *current_line_buffer++; - uint32_t r = *current_line_buffer++; - current_line_buffer++; - uint32_t b = *current_line_buffer++; - *backbuffer++ = (r << 16) | (g << 8) | b; - width--; - } -} -#endif - - } + scanline_render[TOMGetVideoMode()](TOMCurrentLine); } else { - // If outside of VDB & VDE, then display the border color uint32_t * currentLineBuffer = TOMCurrentLine; uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; -//Hm. uint32_t pixel = 0xFF000000 | (b << 16) | (g << 8) | r; uint32_t pixel = (r << 16) | (g << 8) | b; for(uint32_t i=0; i 0.25:1 (1:4) pixels (X:Y ratio) - // PWIDTH = 2 -> 0.50:1 (1:2) pixels - // PWIDTH = 3 -> 0.75:1 (3:4) pixels - // PWIDTH = 4 -> 1.00:1 (1:1) pixels - // PWIDTH = 5 -> 1.25:1 (5:4) pixels - // PWIDTH = 6 -> 1.50:1 (3:2) pixels - // PWIDTH = 7 -> 1.75:1 (7:4) pixels - // PWIDTH = 8 -> 2.00:1 (2:1) pixels - - // Also note that the JTRM says that PWIDTH of 4 gives pixels that are - // "about" square--this implies that the other modes have pixels that are - // *not* square (and they aren't)! - // Also, I seriously doubt that you will see any games that use PWIDTH = 1! - - // To make it easier to make a quasi-fixed display size, we restrict the - // viewing area to an arbitrary range of the Horizontal Count. uint16_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; return (vjs.hardwareTypeNTSC ? RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC : RIGHT_VISIBLE_HC_PAL - LEFT_VISIBLE_HC_PAL) / pwidth; } @@ -1108,59 +436,13 @@ uint32_t TOMGetVideoModeWidth(void) uint32_t TOMGetVideoModeHeight(void) { - // Set virtual screen height to 240 (NTSC) or 256 (PAL) lines... return (vjs.hardwareTypeNTSC ? 240 : 256); } - // // TOM reset code // Now PAL friendly! // -/* -The values in TOMReset come from the Jaguar BIOS. -These values are from BJL: - -NSTC: -CLK2 181 -HP 844 -HBB 1713 -HBE 125 -HS 1741 -HVS 651 -HEQ 784 -HDE 1696 -HDB1 166 -HDB2 166 -VP 523 -VEE 6 -VBE 24 -VDB 46 -VDE 496 -VBB 500 -VEB 511 -VS 517 - -PAL: -CLK2 226 -HP 850 -HBB 1711 -HBE 158 -HS 1749 -HVS 601 -HEQ 787 -HDE 1696 -HDB1 166 -HDB2 166 -VP 625 -VEE 6 -VBE 34 -VDB 46 -VDE 429 -VBB 600 -VEB 613 -VS 618 -*/ void TOMReset(void) { OPReset(); @@ -1170,36 +452,35 @@ void TOMReset(void) if (vjs.hardwareTypeNTSC) { SET16(tomRam8, MEMCON1, 0x1861); -// SET16(tomRam8, MEMCON1, 0x1865);//Bunch of BS SET16(tomRam8, MEMCON2, 0x35CC); - SET16(tomRam8, HP, 844); // Horizontal Period (1-based; HP=845) - SET16(tomRam8, HBB, 1713); // Horizontal Blank Begin - SET16(tomRam8, HBE, 125); // Horizontal Blank End - SET16(tomRam8, HDE, 1665); // Horizontal Display End - SET16(tomRam8, HDB1, 203); // Horizontal Display Begin 1 - SET16(tomRam8, VP, 523); // Vertical Period (1-based; in this case VP = 524) - SET16(tomRam8, VBE, 24); // Vertical Blank End - SET16(tomRam8, VDB, 38); // Vertical Display Begin - SET16(tomRam8, VDE, 518); // Vertical Display End - SET16(tomRam8, VBB, 500); // Vertical Blank Begin - SET16(tomRam8, VS, 517); // Vertical Sync + SET16(tomRam8, HP, 844); + SET16(tomRam8, HBB, 1713); + SET16(tomRam8, HBE, 125); + SET16(tomRam8, HDE, 1665); + SET16(tomRam8, HDB1, 203); + SET16(tomRam8, VP, 523); + SET16(tomRam8, VBE, 24); + SET16(tomRam8, VDB, 38); + SET16(tomRam8, VDE, 518); + SET16(tomRam8, VBB, 500); + SET16(tomRam8, VS, 517); SET16(tomRam8, VMODE, 0x06C1); } - else // PAL Jaguar + else { SET16(tomRam8, MEMCON1, 0x1861); SET16(tomRam8, MEMCON2, 0x35CC); - SET16(tomRam8, HP, 850); // Horizontal Period - SET16(tomRam8, HBB, 1711); // Horizontal Blank Begin - SET16(tomRam8, HBE, 158); // Horizontal Blank End - SET16(tomRam8, HDE, 1665); // Horizontal Display End - SET16(tomRam8, HDB1, 203); // Horizontal Display Begin 1 - SET16(tomRam8, VP, 623); // Vertical Period (1-based; in this case VP = 624) - SET16(tomRam8, VBE, 34); // Vertical Blank End - SET16(tomRam8, VDB, 38); // Vertical Display Begin - SET16(tomRam8, VDE, 518); // Vertical Display End - SET16(tomRam8, VBB, 600); // Vertical Blank Begin - SET16(tomRam8, VS, 618); // Vertical Sync + SET16(tomRam8, HP, 850); + SET16(tomRam8, HBB, 1711); + SET16(tomRam8, HBE, 158); + SET16(tomRam8, HDE, 1665); + SET16(tomRam8, HDB1, 203); + SET16(tomRam8, VP, 623); + SET16(tomRam8, VBE, 34); + SET16(tomRam8, VDB, 38); + SET16(tomRam8, VDE, 518); + SET16(tomRam8, VBB, 600); + SET16(tomRam8, VS, 618); SET16(tomRam8, VMODE, 0x06C1); } @@ -1212,77 +493,20 @@ void TOMReset(void) tom_gpu_int_pending = 0; tom_video_int_pending = 0; - tomTimerPrescaler = 0; // TOM PIT is disabled + tomTimerPrescaler = 0; tomTimerDivider = 0; tomTimerCounter = 0; } - -// -// Dump all TOM register values to the log -// -void TOMDumpIORegistersToLog(void) -{ - WriteLog("\n\n---------------------------------------------------------------------\n"); - WriteLog("TOM I/O Registers\n"); - WriteLog("---------------------------------------------------------------------\n"); - WriteLog("F000%02X (MEMCON1): $%04X\n", MEMCON1, GET16(tomRam8, MEMCON1)); - WriteLog("F000%02X (MEMCON2): $%04X\n", MEMCON2, GET16(tomRam8, MEMCON2)); - WriteLog("F000%02X (HC): $%04X\n", HC, GET16(tomRam8, HC)); - WriteLog("F000%02X (VC): $%04X\n", VC, GET16(tomRam8, VC)); - WriteLog("F000%02X (OLP): $%08X\n", OLP, GET32(tomRam8, OLP)); - WriteLog("F000%02X (OBF): $%04X\n", OBF, GET16(tomRam8, OBF)); - WriteLog("F000%02X (VMODE): $%04X\n", VMODE, GET16(tomRam8, VMODE)); - WriteLog("F000%02X (BORD1): $%04X\n", BORD1, GET16(tomRam8, BORD1)); - WriteLog("F000%02X (BORD2): $%04X\n", BORD2, GET16(tomRam8, BORD2)); - WriteLog("F000%02X (HP): $%04X\n", HP, GET16(tomRam8, HP)); - WriteLog("F000%02X (HBB): $%04X\n", HBB, GET16(tomRam8, HBB)); - WriteLog("F000%02X (HBE): $%04X\n", HBE, GET16(tomRam8, HBE)); - WriteLog("F000%02X (HS): $%04X\n", HS, GET16(tomRam8, HS)); - WriteLog("F000%02X (HVS): $%04X\n", HVS, GET16(tomRam8, HVS)); - WriteLog("F000%02X (HDB1): $%04X\n", HDB1, GET16(tomRam8, HDB1)); - WriteLog("F000%02X (HDB2): $%04X\n", HDB2, GET16(tomRam8, HDB2)); - WriteLog("F000%02X (HDE): $%04X\n", HDE, GET16(tomRam8, HDE)); - WriteLog("F000%02X (VP): $%04X\n", VP, GET16(tomRam8, VP)); - WriteLog("F000%02X (VBB): $%04X\n", VBB, GET16(tomRam8, VBB)); - WriteLog("F000%02X (VBE): $%04X\n", VBE, GET16(tomRam8, VBE)); - WriteLog("F000%02X (VS): $%04X\n", VS, GET16(tomRam8, VS)); - WriteLog("F000%02X (VDB): $%04X\n", VDB, GET16(tomRam8, VDB)); - WriteLog("F000%02X (VDE): $%04X\n", VDE, GET16(tomRam8, VDE)); - WriteLog("F000%02X (VEB): $%04X\n", VEB, GET16(tomRam8, VEB)); - WriteLog("F000%02X (VEE): $%04X\n", VEE, GET16(tomRam8, VEE)); - WriteLog("F000%02X (VI): $%04X\n", VI, GET16(tomRam8, VI)); - WriteLog("F000%02X (PIT0): $%04X\n", PIT0, GET16(tomRam8, PIT0)); - WriteLog("F000%02X (PIT1): $%04X\n", PIT1, GET16(tomRam8, PIT1)); - WriteLog("F000%02X (HEQ): $%04X\n", HEQ, GET16(tomRam8, HEQ)); - WriteLog("F000%02X (BG): $%04X\n", BG, GET16(tomRam8, BG)); - WriteLog("F000%02X (INT1): $%04X\n", INT1, GET16(tomRam8, INT1)); - WriteLog("F000%02X (INT2): $%04X\n", INT2, GET16(tomRam8, INT2)); - WriteLog("---------------------------------------------------------------------\n\n\n"); -} - - // // TOM byte access (read) // -uint8_t TOMReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint8_t TOMReadByte(uint32_t offset, uint32_t who) { -//???Is this needed??? -// It seems so. Perhaps it's the +$8000 offset being written to (32-bit interface)? -// However, the 32-bit interface is WRITE ONLY, so that can't be it... -// Also, the 68K CANNOT make use of the 32-bit interface, since its bus width is only 16-bits... -// offset &= 0xFF3FFF; - -#ifdef TOM_DEBUG - WriteLog("TOM: Reading byte at %06X for %s\n", offset, whoName[who]); -#endif - if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) return GPUReadByte(offset, who); else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000)) return GPUReadByte(offset, who); -/* else if ((offset >= 0xF00010) && (offset < 0xF00028)) - return OPReadByte(offset, who);*/ else if ((offset >= 0xF02200) && (offset < 0xF022A0)) return BlitterReadByte(offset, who); else if (offset == 0xF00050) @@ -1297,53 +521,24 @@ uint8_t TOMReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) return tomRam8[offset & 0x3FFF]; } - // // TOM word access (read) // -uint16_t TOMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) +uint16_t TOMReadWord(uint32_t offset, uint32_t who) { -//???Is this needed??? -// offset &= 0xFF3FFF; -#ifdef TOM_DEBUG - WriteLog("TOM: Reading word at %06X for %s\n", offset, whoName[who]); -#endif -if (offset >= 0xF02000 && offset <= 0xF020FF) - WriteLog("TOM: ReadWord attempted from GPU register file by %s (unimplemented)!\n", whoName[who]); - if (offset == 0xF000E0) { - // For reading, should only return the lower 5 bits... uint16_t data = (tom_jerry_int_pending << 4) | (tom_timer_int_pending << 3) | (tom_object_int_pending << 2) | (tom_gpu_int_pending << 1) | (tom_video_int_pending << 0); - //WriteLog("tom: interrupt status is 0x%.4x \n",data); return data; } -//Shoud be handled by the jaguar main loop now... And it is! ;-) -/* else if (offset == 0xF00006) // VC - // What if we're in interlaced mode? - // According to docs, in non-interlace mode VC is ALWAYS even... -// return (tom_scanline << 1);// + 1; -//But it's causing Rayman to be fucked up... Why??? -//Because VC is even in NI mode when calling the OP! That's why! - return (tom_scanline << 1) + 1;//*/ -/* -// F00004 R/W -----xxx xxxxxxxx HC - horizontal count -// -----x-- -------- (which half of the display) -// ------xx xxxxxxxx (10-bit counter) -*/ -// This is a kludge to get the HC working somewhat... What we really should do here -// is check what the global time is at the time of the read and calculate the correct HC... -// !!! FIX !!! else if (offset == 0xF00004) return rand() & 0x03FF; else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE + 0x20)) return GPUReadWord(offset, who); else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000)) return GPUReadWord(offset, who); -/* else if ((offset >= 0xF00010) && (offset < 0xF00028)) - return OPReadWord(offset, who);*/ else if ((offset >= 0xF02200) && (offset < 0xF022A0)) return BlitterReadWord(offset, who); else if (offset == 0xF00050) @@ -1355,64 +550,35 @@ if (offset >= 0xF02000 && offset <= 0xF020FF) return (TOMReadByte(offset, who) << 8) | TOMReadByte(offset + 1, who); } - -#define TOM_STRICT_MEMORY_ACCESS // // TOM byte access (write) // -void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) +void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who) { - // Moved here tentatively, so we can see everything written to TOM. tomRam8[offset & 0x3FFF] = data; -#ifdef TOM_DEBUG - WriteLog("TOM: Writing byte %02X at %06X", data, offset); -#endif -//???Is this needed??? -// Perhaps on the writes--32-bit writes that is! And masked with FF7FFF... -#ifndef TOM_STRICT_MEMORY_ACCESS - offset &= 0xFF3FFF; -#else - // "Fast" (32-bit only) write access to the GPU -// if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF)) if ((offset >= 0xF08000) && (offset <= 0xF0BFFF)) offset &= 0xFF7FFF; -#endif -#ifdef TOM_DEBUG - WriteLog(" -->[%06X] by %s\n", offset, whoName[who]); -#endif -#ifdef TOM_STRICT_MEMORY_ACCESS - // Sanity check ("Aww, there ain't no Sanity Clause...") if ((offset < 0xF00000) || (offset > 0xF03FFF)) return; -#endif if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) { GPUWriteByte(offset, data, who); - return; } else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000)) { GPUWriteByte(offset, data, who); - return; } -/* else if ((offset >= 0xF00010) && (offset < 0xF00028)) - { - OPWriteByte(offset, data, who); - return; - }*/ else if ((offset >= 0xF02200) && (offset < 0xF022A0)) { BlitterWriteByte(offset, data, who); - return; } else if (offset == 0xF00050) { tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | (data << 8); TOMResetPIT(); - return; } else if (offset == 0xF00051) { @@ -1424,62 +590,32 @@ void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) { tomTimerDivider = (tomTimerDivider & 0x00FF) | (data << 8); TOMResetPIT(); - return; } else if (offset == 0xF00053) { tomTimerDivider = (tomTimerDivider & 0xFF00) | data; TOMResetPIT(); - return; } - else if (offset >= 0xF00400 && offset <= 0xF007FF) // CLUT (A & B) + else if (offset >= 0xF00400 && offset <= 0xF007FF) { - // Writing to one CLUT writes to the other - offset &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF) + offset &= 0x5FF; tomRam8[offset] = data, tomRam8[offset + 0x200] = data; } - -// tomRam8[offset & 0x3FFF] = data; } - // // TOM word access (write) // -void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) +void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who) { - // Moved here tentatively, so we can see everything written to TOM. tomRam8[(offset + 0) & 0x3FFF] = data >> 8; tomRam8[(offset + 1) & 0x3FFF] = data & 0xFF; -#ifdef TOM_DEBUG - WriteLog("TOM: Writing byte %04X at %06X", data, offset); -#endif -//???Is this needed??? Yes, but we need to be more vigilant than this. -#ifndef TOM_STRICT_MEMORY_ACCESS - offset &= 0xFF3FFF; -#else - // "Fast" (32-bit only) write access to the GPU -// if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF)) if ((offset >= 0xF08000) && (offset <= 0xF0BFFF)) offset &= 0xFF7FFF; -#endif -#ifdef TOM_DEBUG - WriteLog(" -->[%06X] by %s\n", offset, whoName[who]); -#endif -#ifdef TOM_STRICT_MEMORY_ACCESS - // Sanity check if ((offset < 0xF00000) || (offset > 0xF03FFF)) return; -#endif - -//if (offset == 0xF00000 + MEMCON1) -// WriteLog("TOM: Memory Configuration 1 written by %s: %04X\n", whoName[who], data); -//if (offset == 0xF00000 + MEMCON2) -// WriteLog("TOM: Memory Configuration 2 written by %s: %04X\n", whoName[who], data); -if (offset >= 0xF02000 && offset <= 0xF020FF) - WriteLog("TOM: WriteWord attempted to GPU register file by %s (unimplemented)!\n", whoName[who]); if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) { @@ -1491,17 +627,6 @@ if (offset >= 0xF02000 && offset <= 0xF020FF) GPUWriteWord(offset, data, who); return; } -//What's so special about this? -/* else if ((offset >= 0xF00000) && (offset < 0xF00002)) - { - TOMWriteByte(offset, data >> 8); - TOMWriteByte(offset+1, data & 0xFF); - }*/ -/* else if ((offset >= 0xF00010) && (offset < 0xF00028)) - { - OPWriteWord(offset, data, who); - return; - }*/ else if (offset == 0xF00050) { tomTimerPrescaler = data; @@ -1516,7 +641,6 @@ if (offset >= 0xF02000 && offset <= 0xF020FF) } else if (offset == 0xF000E0) { -//Check this out... if (data & 0x0100) tom_video_int_pending = 0; if (data & 0x0200) @@ -1527,109 +651,26 @@ if (offset >= 0xF02000 && offset <= 0xF020FF) tom_timer_int_pending = 0; if (data & 0x1000) tom_jerry_int_pending = 0; - -// return; } else if ((offset >= 0xF02200) && (offset <= 0xF0229F)) { BlitterWriteWord(offset, data, who); return; } - else if (offset >= 0xF00400 && offset <= 0xF007FE) // CLUT (A & B) + else if (offset >= 0xF00400 && offset <= 0xF007FE) { - // Writing to one CLUT writes to the other - offset &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF) -// Watch out for unaligned writes here! (Not fixed yet) -#warning "!!! Watch out for unaligned writes here !!! FIX !!!" + offset &= 0x5FF; SET16(tomRam8, offset, data); SET16(tomRam8, offset + 0x200, data); } offset &= 0x3FFF; - if (offset == 0x28) // VMODE (Why? Why not OBF?) -//Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!! -#warning "Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!" - objectp_running = 1; if (offset >= 0x30 && offset <= 0x4E) - data &= 0x07FF; // These are (mostly) 11-bit registers + data &= 0x07FF; if (offset == 0x2E || offset == 0x36 || offset == 0x54) - data &= 0x03FF; // These are all 10-bit registers + data &= 0x03FF; -// Fix a lockup bug... :-P -// TOMWriteByte(0xF00000 | offset, data >> 8, who); -// TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who); - -if (offset == MEMCON1) - WriteLog("TOM: Memory Config 1 written by %s: $%04X\n", whoName[who], data); -if (offset == MEMCON2) - WriteLog("TOM: Memory Config 2 written by %s: $%04X\n", whoName[who], data); -//if (offset == OLP) -// WriteLog("TOM: Object List Pointer written by %s: $%04X\n", whoName[who], data); -//if (offset == OLP + 2) -// WriteLog("TOM: Object List Pointer +2 written by %s: $%04X\n", whoName[who], data); -//if (offset == OBF) -// WriteLog("TOM: Object Processor Flag written by %s: %u\n", whoName[who], data); -if (offset == VMODE) - WriteLog("TOM: Video Mode written by %s: %04X. PWIDTH = %u, MODE = %s, flags:%s%s (VC = %u) (M68K PC = %06X)\n", whoName[who], data, ((data >> 9) & 0x07) + 1, videoMode_to_str[(data & MODE) >> 1], (data & BGEN ? " BGEN" : ""), (data & VARMOD ? " VARMOD" : ""), GET16(tomRam8, VC), m68k_get_reg(NULL, M68K_REG_PC)); -if (offset == BORD1) - WriteLog("TOM: Border 1 written by %s: $%04X\n", whoName[who], data); -if (offset == BORD2) - WriteLog("TOM: Border 2 written by %s: $%04X\n", whoName[who], data); -if (offset == HP) - WriteLog("TOM: Horizontal Period written by %s: %u (+1*2 = %u)\n", whoName[who], data, (data + 1) * 2); -if (offset == HBB) - WriteLog("TOM: Horizontal Blank Begin written by %s: %u\n", whoName[who], data); -if (offset == HBE) - WriteLog("TOM: Horizontal Blank End written by %s: %u\n", whoName[who], data); -if (offset == HS) - WriteLog("TOM: Horizontal Sync written by %s: %u\n", whoName[who], data); -if (offset == HVS) - WriteLog("TOM: Horizontal Vertical Sync written by %s: %u\n", whoName[who], data); -if (offset == HDB1) - WriteLog("TOM: Horizontal Display Begin 1 written by %s: %u\n", whoName[who], data); -if (offset == HDB2) - WriteLog("TOM: Horizontal Display Begin 2 written by %s: %u\n", whoName[who], data); -if (offset == HDE) - WriteLog("TOM: Horizontal Display End written by %s: %u\n", whoName[who], data); -if (offset == VP) - WriteLog("TOM: Vertical Period written by %s: %u (%sinterlaced)\n", whoName[who], data, (data & 0x01 ? "non-" : "")); -if (offset == VBB) - WriteLog("TOM: Vertical Blank Begin written by %s: %u\n", whoName[who], data); -if (offset == VBE) - WriteLog("TOM: Vertical Blank End written by %s: %u\n", whoName[who], data); -if (offset == VS) - WriteLog("TOM: Vertical Sync written by %s: %u\n", whoName[who], data); -if (offset == VDB) - WriteLog("TOM: Vertical Display Begin written by %s: %u\n", whoName[who], data); -if (offset == VDE) - WriteLog("TOM: Vertical Display End written by %s: %u\n", whoName[who], data); -if (offset == VEB) - WriteLog("TOM: Vertical Equalization Begin written by %s: %u\n", whoName[who], data); -if (offset == VEE) - WriteLog("TOM: Vertical Equalization End written by %s: %u\n", whoName[who], data); -if (offset == VI) - WriteLog("TOM: Vertical Interrupt written by %s: %u\n", whoName[who], data); -if (offset == PIT0) - WriteLog("TOM: PIT0 written by %s: %u\n", whoName[who], data); -if (offset == PIT1) - WriteLog("TOM: PIT1 written by %s: %u\n", whoName[who], data); -if (offset == HEQ) - WriteLog("TOM: Horizontal Equalization End written by %s: %u\n", whoName[who], data); -//if (offset == BG) -// WriteLog("TOM: Background written by %s: %u\n", whoName[who], data); -//if (offset == INT1) -// WriteLog("TOM: CPU Interrupt Control written by %s: $%04X (%s%s%s%s%s)\n", whoName[who], data, (data & 0x01 ? "Video" : ""), (data & 0x02 ? " GPU" : ""), (data & 0x04 ? " OP" : ""), (data & 0x08 ? " TOMPIT" : ""), (data & 0x10 ? " Jerry" : "")); - - // detect screen resolution changes -//This may go away in the future, if we do the virtualized screen thing... -//This may go away soon! -// TOM Shouldn't be mucking around with this, it's up to the host system to properly -// handle this kind of crap. -// NOTE: This is needed somehow, need to get rid of the dependency on this crap. -// N.B.: It's used in the rendering functions... So... -#warning "!!! Need to get rid of this dependency !!!" -#if 1 if ((offset >= 0x28) && (offset <= 0x4F)) { uint32_t width = TOMGetVideoModeWidth(), height = TOMGetVideoModeHeight(); @@ -1637,45 +678,19 @@ if (offset == HEQ) if ((width != tomWidth) || (height != tomHeight)) { tomWidth = width, tomHeight = height; - -#warning "!!! TOM: ResizeScreen commented out !!!" -// No need to resize anything, since we're prepared for this... -// if (vjs.renderType == RT_NORMAL) -// ResizeScreen(tomWidth, tomHeight); } } -#endif } - int TOMIRQEnabled(int irq) { - // This is the correct byte in big endian... D'oh! -// return jaguar_byte_read(0xF000E1) & (1 << irq); - return tomRam8[INT1 + 1/*0xE1*/] & (1 << irq); + return tomRam8[INT1 + 1] & (1 << irq); } - -// NEW: -// TOM Programmable Interrupt Timer handler -// NOTE: TOM's PIT is only enabled if the prescaler is != 0 -// The PIT only generates an interrupt when it counts down to zero, not when loaded! - void TOMPITCallback(void); - void TOMResetPIT(void) { -#ifndef NEW_TIMER_SYSTEM -//Probably should *add* this amount to the counter to retain cycle accuracy! !!! FIX !!! [DONE] -//Also, why +1??? 'Cause that's what it says in the JTRM...! -//There is a small problem with this approach: If both the prescaler and the divider are equal -//to $FFFF then the counter won't be large enough to handle it. !!! FIX !!! - if (tom_timer_prescaler) - tom_timer_counter += (1 + tom_timer_prescaler) * (1 + tom_timer_divider); -// WriteLog("tom: reseting timer to 0x%.8x (%i)\n",tom_timer_counter,tom_timer_counter); -#else - // Need to remove previous timer from the queue, if it exists... RemoveCallback(TOMPITCallback); if (tomTimerPrescaler) @@ -1683,16 +698,8 @@ void TOMResetPIT(void) double usecs = (float)(tomTimerPrescaler + 1) * (float)(tomTimerDivider + 1) * RISC_CYCLE_IN_USEC; SetCallbackTime(TOMPITCallback, usecs); } -#endif } - -// -// TOM Programmable Interrupt Timer handler -// NOTE: TOM's PIT is only enabled if the prescaler is != 0 -// -//NOTE: This is only used by the old execution code... Safe to remove -// once the timer system is stable. void TOMExecPIT(uint32_t cycles) { if (tomTimerPrescaler) @@ -1702,27 +709,23 @@ void TOMExecPIT(uint32_t cycles) if (tomTimerCounter <= 0) { TOMSetPendingTimerInt(); - GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // GPUSetIRQLine does the 'IRQ enabled' checking + GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); if (TOMIRQEnabled(IRQ_TIMER)) - m68k_set_irq(2); // Cause a 68000 IPL 2... + m68k_set_irq(2); TOMResetPIT(); } } } - void TOMPITCallback(void) { -// INT1_RREG |= 0x08; // Set TOM PIT interrupt pending TOMSetPendingTimerInt(); - GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking + GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); -// if (INT1_WREG & 0x08) if (TOMIRQEnabled(IRQ_TIMER)) - m68k_set_irq(2); // Generate a 68K IPL 2... + m68k_set_irq(2); TOMResetPIT(); } - diff --git a/waterbox/virtualjaguar/src/tom.h b/waterbox/virtualjaguar/src/tom.h index 4ac5736b41..2f664056d7 100644 --- a/waterbox/virtualjaguar/src/tom.h +++ b/waterbox/virtualjaguar/src/tom.h @@ -12,11 +12,6 @@ #define VIDEO_MODE_16BPP_DIRECT 2 #define VIDEO_MODE_16BPP_RGB 3 -// Virtual screen size stuff - -// NB: This virtual width is for PWIDTH = 4 -//#define VIRTUAL_SCREEN_WIDTH 320 -//was:340, 330 #define VIRTUAL_SCREEN_WIDTH 326 #define VIRTUAL_SCREEN_HEIGHT_NTSC 240 #define VIRTUAL_SCREEN_HEIGHT_PAL 256 diff --git a/waterbox/virtualjaguar/src/universalhdr.cpp b/waterbox/virtualjaguar/src/universalhdr.cpp deleted file mode 100644 index dff42d3c9f..0000000000 --- a/waterbox/virtualjaguar/src/universalhdr.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// -// Universal Header for Jaguar carts -// -// (C) 2011 Underground Software -// -// JLH = James Hammons -// -// Who When What -// --- ---------- ------------------------------------------------------------- -// JLH 06/28/2011 Created this file ;-) -// - -// -// This file was automagically generated by bin2c (by James Hammons) -// - -unsigned char universalCartHeader[0x2000] = { - 0xF6, 0x42, 0x23, 0x3C, 0x0D, 0xAC, 0x1D, 0x8D, 0xB0, 0x23, 0x71, 0x53, 0xBE, 0x87, 0x11, 0x17, 0x98, 0x27, 0x04, 0x26, 0x22, 0xC1, 0xBE, 0x1F, 0x79, 0x30, 0xDB, 0x90, 0xC6, 0xC8, 0x13, 0xF8, - 0x09, 0x41, 0x99, 0x78, 0x51, 0xCB, 0xFF, 0x8C, 0xF9, 0x7F, 0x75, 0xF0, 0x6B, 0x0E, 0xFE, 0x13, 0x2D, 0x84, 0xD8, 0x21, 0xE5, 0x91, 0xD4, 0x01, 0x3F, 0x23, 0x5E, 0x13, 0xAE, 0xF2, 0x2F, 0xEF, - 0x6C, 0x09, 0xD8, 0x06, 0x9F, 0x39, 0x27, 0x8F, 0x6D, 0x4F, 0x03, 0xD3, 0xD9, 0x84, 0x3D, 0xEA, 0xAB, 0xB7, 0x48, 0xF1, 0xE6, 0x98, 0x51, 0x27, 0xF0, 0x6E, 0x94, 0x0E, 0x90, 0x92, 0xC8, 0xF4, - 0x50, 0x3B, 0x46, 0x58, 0x08, 0x23, 0xE0, 0x4B, 0xD2, 0x3C, 0x1C, 0xC5, 0x30, 0x6B, 0x11, 0x24, 0xFA, 0xC6, 0x78, 0x29, 0xD1, 0x53, 0x5A, 0x64, 0xE0, 0x91, 0x5A, 0x16, 0xEC, 0xD9, 0x87, 0xC4, - 0xD8, 0x2D, 0x16, 0x98, 0x6A, 0x85, 0x29, 0x01, 0xF7, 0x25, 0xFB, 0xF6, 0xF9, 0xC1, 0x0F, 0x38, 0xA7, 0xB3, 0x9B, 0x1E, 0xC6, 0x19, 0x69, 0x1E, 0x6B, 0x05, 0x01, 0x77, 0xD0, 0xCD, 0x09, 0xF0, - 0xA7, 0x0F, 0xAA, 0x76, 0x24, 0x92, 0x26, 0x28, 0xEF, 0x72, 0xE4, 0x86, 0x41, 0x3B, 0x83, 0x22, 0x3C, 0x07, 0x4F, 0x67, 0x0B, 0xB6, 0x27, 0x5F, 0x7C, 0xD7, 0xEC, 0x52, 0xF6, 0xBF, 0x44, 0xEE, - 0x9C, 0x6B, 0x33, 0x0A, 0x36, 0xBE, 0x4C, 0xEB, 0x3E, 0x34, 0xE4, 0x3A, 0xFD, 0xF6, 0x75, 0x87, 0xB1, 0xED, 0xF6, 0x51, 0x72, 0x06, 0x99, 0x28, 0x10, 0x71, 0xD7, 0x44, 0x7E, 0xDE, 0x0F, 0x96, - 0xF3, 0x84, 0x01, 0xFF, 0x59, 0x71, 0x33, 0xB2, 0x18, 0x55, 0x4E, 0x56, 0x43, 0x4C, 0xA6, 0xE9, 0x72, 0xE2, 0x4A, 0x9F, 0x04, 0x9A, 0x87, 0xF1, 0x73, 0x92, 0x86, 0x3E, 0x80, 0x07, 0x55, 0x1C, - 0xCE, 0x57, 0x76, 0xD3, 0x1C, 0xC9, 0x43, 0x82, 0x7D, 0xCF, 0x19, 0x49, 0x6E, 0xFB, 0x19, 0x60, 0x74, 0x72, 0xD6, 0x90, 0x37, 0x81, 0x78, 0xFB, 0x10, 0x01, 0x7E, 0xE5, 0x5C, 0xB7, 0x81, 0x88, - 0xE2, 0xEB, 0x07, 0xA2, 0x75, 0x10, 0x35, 0x11, 0xCB, 0xE9, 0x2E, 0x75, 0x39, 0x79, 0x3E, 0x76, 0xB8, 0xF8, 0x5A, 0x88, 0xFF, 0x6C, 0x77, 0x07, 0xBD, 0xCE, 0x05, 0xF6, 0xD2, 0x29, 0x03, 0x5F, - 0xBE, 0x04, 0x51, 0xD8, 0xF7, 0x15, 0x07, 0xF9, 0xBE, 0xD9, 0x12, 0x27, 0x3D, 0xE0, 0xF2, 0xC0, 0x20, 0x2F, 0xBF, 0xA6, 0xBA, 0x76, 0x6B, 0x69, 0x8F, 0x05, 0x41, 0x01, 0x4D, 0x9E, 0xF0, 0x79, - 0x87, 0xAF, 0x8C, 0xDB, 0xFB, 0x30, 0xE3, 0xC9, 0x51, 0x29, 0x2A, 0x3E, 0x91, 0x3A, 0xE0, 0x52, 0xEE, 0x45, 0xE6, 0x79, 0x5A, 0x3D, 0x92, 0x12, 0x12, 0x1F, 0x6C, 0x62, 0xA2, 0x9B, 0x99, 0xAC, - 0xD8, 0x32, 0xF3, 0xF4, 0xCF, 0x4A, 0x09, 0x56, 0x5A, 0x0D, 0x76, 0x84, 0xE1, 0x5A, 0xFF, 0x23, 0x69, 0xD2, 0x03, 0xE6, 0x2E, 0x47, 0xC6, 0x54, 0x09, 0xA3, 0x47, 0x6E, 0x5B, 0x5A, 0xA1, 0xE8, - 0x25, 0xC5, 0xA5, 0x61, 0x64, 0xB8, 0x82, 0xC8, 0x17, 0x1A, 0x8A, 0xC8, 0x1D, 0xEC, 0x49, 0x94, 0x1E, 0x00, 0xA0, 0x23, 0x39, 0x35, 0xF3, 0xB2, 0xA7, 0x54, 0x47, 0x90, 0xCB, 0x52, 0x40, 0x78, - 0xA3, 0x33, 0x88, 0xEB, 0x23, 0x0A, 0x29, 0x1B, 0xC7, 0xB7, 0xE2, 0x10, 0x75, 0x9F, 0x27, 0x5B, 0xE3, 0x00, 0x63, 0x6F, 0x12, 0x55, 0x20, 0x0B, 0x44, 0xB2, 0x67, 0xEF, 0x74, 0x15, 0x17, 0xBB, - 0x7B, 0xB7, 0x95, 0x78, 0xC0, 0xFE, 0x2C, 0x99, 0xDD, 0xFF, 0xDC, 0xFC, 0x43, 0xAF, 0x42, 0xC2, 0x27, 0x8A, 0x53, 0x9E, 0x62, 0x0B, 0x12, 0x8E, 0xD3, 0x5E, 0x76, 0x0F, 0x2B, 0x9D, 0x6D, 0x8D, - 0x28, 0x44, 0xA0, 0xB4, 0xB1, 0x22, 0xA8, 0x9D, 0x2C, 0x01, 0x90, 0x04, 0xAB, 0x0D, 0x60, 0x29, 0x60, 0xD7, 0x49, 0x02, 0x24, 0x9E, 0x10, 0x1D, 0xE6, 0x1C, 0x58, 0xC9, 0xFC, 0x14, 0x97, 0x92, - 0x23, 0x1E, 0x74, 0xDE, 0x23, 0xAF, 0xA7, 0xB6, 0xDB, 0x52, 0x78, 0xDA, 0x5E, 0x6C, 0x16, 0x6B, 0x36, 0x17, 0xBC, 0x01, 0x7F, 0x6A, 0x55, 0xA7, 0x7D, 0xC0, 0x60, 0xFD, 0x50, 0x72, 0x78, 0x62, - 0x14, 0xFD, 0x06, 0xF7, 0x0F, 0x1E, 0x82, 0xCC, 0xFB, 0x0B, 0x62, 0x06, 0x78, 0x1D, 0x80, 0x0B, 0x55, 0xAE, 0xC9, 0x25, 0x61, 0x65, 0x88, 0xDB, 0x23, 0x0E, 0x0D, 0xFB, 0xD9, 0x3B, 0x41, 0x33, - 0x85, 0xC8, 0x9F, 0x61, 0xBC, 0xC9, 0x17, 0x22, 0x29, 0x4E, 0x41, 0xCA, 0xA5, 0x4F, 0xDF, 0x7B, 0xF0, 0xB7, 0xC3, 0xA4, 0x93, 0xB2, 0xF2, 0xE7, 0x4D, 0x3B, 0x46, 0x21, 0x22, 0xD9, 0x50, 0x9F, - 0x2E, 0x7F, 0x2B, 0xA3, 0xD2, 0xA1, 0x24, 0x68, 0xE4, 0xBF, 0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x04, 0x04, 0x04, 0x04, 0x00, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; diff --git a/waterbox/virtualjaguar/src/universalhdr.h b/waterbox/virtualjaguar/src/universalhdr.h deleted file mode 100644 index 6f0ce532ac..0000000000 --- a/waterbox/virtualjaguar/src/universalhdr.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// Universal Header for Jaguar carts -// - -#ifndef __UNIVERSALHDR_H__ -#define __UNIVERSALHDR_H__ - -extern unsigned char universalCartHeader[]; - -#endif // __UNIVERSALHDR_H__ diff --git a/waterbox/virtualjaguar/src/wavetable.cpp b/waterbox/virtualjaguar/src/wavetable.cpp index 7f576e6d74..7bcb987fe7 100644 --- a/waterbox/virtualjaguar/src/wavetable.cpp +++ b/waterbox/virtualjaguar/src/wavetable.cpp @@ -10,6 +10,8 @@ // JLH 01/16/2010 Created this log ;-) // +#include "wavetable.h" + // // In a real Jaguar, these are 16-bit values that are sign-extended to 32 bits. // Each entry has 128 values (e.g., SINE goes from F1D200-F1D3FF) @@ -17,7 +19,7 @@ // NOTE: This can probably be converted to 32-bit table, since I don't think // that unaligned access is allowed... -/*const*/ unsigned char waveTableROM[4096] = +const uint8_t waveTableROM[4096] = { 0xFF, 0xFF, 0xC2, 0x01, 0xFF, 0xFF, 0xC4, 0x01, 0xFF, 0xFF, 0xC6, 0x01, 0xFF, 0xFF, 0xC8, 0x01, 0xFF, 0xFF, 0xCA, 0x01, 0xFF, 0xFF, 0xCC, 0x01, 0xFF, 0xFF, 0xCE, 0x01, 0xFF, 0xFF, 0xD0, 0x01, diff --git a/waterbox/virtualjaguar/src/wavetable.h b/waterbox/virtualjaguar/src/wavetable.h index cfd905c108..23d847552a 100644 --- a/waterbox/virtualjaguar/src/wavetable.h +++ b/waterbox/virtualjaguar/src/wavetable.h @@ -11,7 +11,8 @@ #ifndef __WAVETABLE_H__ #define __WAVETABLE_H__ -// How to preserve const-ness of this stuff without introducing tons of hairiness? -extern /*const*/ unsigned char waveTableROM[]; +#include + +extern const uint8_t waveTableROM[]; #endif // __WAVETABLE_H__