| 1 | // |
| 2 | // mmu.cpp |
| 3 | // |
| 4 | // Jaguar Memory Manager Unit |
| 5 | // |
| 6 | // by James Hammons |
| 7 | // |
| 8 | // JLH = James Hammons <jlhamm@acm.org> |
| 9 | // |
| 10 | // WHO WHEN WHAT |
| 11 | // --- ---------- ----------------------------------------------------------- |
| 12 | // JLH 11/25/2009 Created this file. :-) |
| 13 | // |
| 14 | |
| 15 | #include "mmu.h" |
| 16 | |
| 17 | #include <stdlib.h> // For NULL definition |
| 18 | #include "dac.h" |
| 19 | //#include "jaguar.h" |
| 20 | //#include "memory.h" |
| 21 | #include "jagbios.h" |
| 22 | #include "wavetable.h" |
| 23 | |
| 24 | |
| 25 | #ifdef USE_NEW_MMU |
| 26 | |
| 27 | /* |
| 28 | Addresses to be handled: |
| 29 | |
| 30 | SYSTEM SETUP REGISTERS |
| 31 | |
| 32 | *MEMCON1 Memory Control Register 1 F00000 RW |
| 33 | *MEMCON2 Memory Control Register 2 F00002 RW |
| 34 | HC Horizontal Count F00004 RW |
| 35 | VC Vertical Count F00006 RW |
| 36 | LPH Light Pen Horizontal F00008 RO |
| 37 | LPV Light Pen Vertical F0000A RO |
| 38 | OB[0-3] Object Data Field F00010-16 RO |
| 39 | OLP Object List Pointer F00020-23 WO |
| 40 | OBF Object Flag F00026 WO |
| 41 | VMODE Video Mode F00028 WO |
| 42 | BORD1 Border Colour (Red & Green) F0002A WO |
| 43 | BORD2 Border Colour (Blue) F0002C WO |
| 44 | *HP Horizontal Period F0002E WO |
| 45 | *HBB Horizontal Blank Begin F00030 WO |
| 46 | *HBE Horizontal Blank End F00032 WO |
| 47 | *HS Horizontal Sync F00034 WO |
| 48 | *HVS Horizontal Vertical Sync F00036 WO |
| 49 | HDB1 Horizontal Display Begin 1 F00038 WO |
| 50 | HDB2 Horizontal Display Begin 2 F0003A WO |
| 51 | HDE Horizontal Display End F0003C WO |
| 52 | *VP Vertical Period F0003E WO |
| 53 | *VBB Vertical Blank Begin F00040 WO |
| 54 | *VBE Vertical Blank End F00042 WO |
| 55 | *VS Vertical Sync F00044 WO |
| 56 | VDB Vertical Display Begin F00046 WO |
| 57 | VDE Vertical Display End F00048 WO |
| 58 | *VEB Vertical Equalization Begin F0004A WO |
| 59 | *VEE Vertical Equalization End F0004C WO |
| 60 | VI Vertical Interrupt F0004E WO |
| 61 | PIT[0-1] Programmable Interrupt Timer F00050-52 WO |
| 62 | *HEQ Horizontal Equalization End F00054 WO |
| 63 | BG Background Colour F00058 WO |
| 64 | INT1 CPU Interrupt Control Register F000E0 RW |
| 65 | INT2 CPU Interrupt Resume Register F000E2 WO |
| 66 | CLUT Colour Look-Up Table F00400-7FE RW |
| 67 | LBUF Line Buffer F00800-1D9E RW |
| 68 | |
| 69 | GPU REGISTERS |
| 70 | |
| 71 | G_FLAGS GPU Flags Register F02100 RW |
| 72 | G_MTXC Matrix Control Register F02104 WO |
| 73 | G_MTXA Matrix Address Register F02108 WO |
| 74 | G_END Data Organization Register F0210C WO |
| 75 | G_PC GPU Program Counter F02110 RW |
| 76 | G_CTRL GPU Control/Status Register F02114 RW |
| 77 | G_HIDATA High Data Register F02118 RW |
| 78 | G_REMAIN Divide Unit Remainder F0211C RO |
| 79 | G_DIVCTRL Divide Unit Control F0211C WO |
| 80 | |
| 81 | BLITTER REGISTERS |
| 82 | |
| 83 | A1_BASE A1 Base Register F02200 WO |
| 84 | A1_FLAGS Flags Register F02204 WO |
| 85 | A1_CLIP A1 Clipping Size F02208 WO |
| 86 | A1_PIXEL A1 Pixel Pointer F0220C WO |
| 87 | F02204 RO |
| 88 | A1_STEP A1 Step Value F02210 WO |
| 89 | A1_FSTEP A1 Step Fraction Value F02214 WO |
| 90 | A1_FPIXEL A1 Pixel Pointer Fraction F02218 RW |
| 91 | A1_INC A1 Increment F0221C WO |
| 92 | A1_FINC A1 Increment Fraction F02220 WO |
| 93 | A2_BASE A2 Base Register F02224 WO |
| 94 | A2_FLAGS A2 Flags Register F02228 WO |
| 95 | A2_MASK A2 Window Mask F0222C WO |
| 96 | A2_PIXEL A2 Pixel Pointer F02230 WO |
| 97 | F0222C RO |
| 98 | A2_STEP A2 Step Value F02234 WO |
| 99 | B_CMD Command/Status Register F02238 RW |
| 100 | B_COUNT Counters Register F0223C WO |
| 101 | B_SRCD Source Data Register F02240 WO |
| 102 | B_DSTD Destination Data Register F02248 WO |
| 103 | B_DSTZ Destination Z Register F02250 WO |
| 104 | B_SRCZ1 Source Z Register 1 F02258 WO |
| 105 | B_SRCZ2 Source Z Register 2 F02260 WO |
| 106 | B_PATD Pattern Data Register F02268 WO |
| 107 | B_IINC Intensity Increment F02270 WO |
| 108 | B_ZINC Z Increment F02274 WO |
| 109 | B_STOP Collision Control F02278 WO |
| 110 | B_I3 Intensity 3 F0227C WO |
| 111 | B_I2 Intensity 2 F02280 WO |
| 112 | B_I1 Intensity 1 F02284 WO |
| 113 | B_I0 Intensity 0 F02288 WO |
| 114 | B_Z3 Z 3 F0228C WO |
| 115 | B_Z2 Z 2 F02290 WO |
| 116 | B_Z1 Z 1 F02294 WO |
| 117 | B_Z0 Z 0 F02298 WO |
| 118 | |
| 119 | JERRY REGISTERS |
| 120 | |
| 121 | *CLK1 Processor Clock Divider F10010 WO |
| 122 | *CLK2 Video Clock Divider F10012 WO |
| 123 | *CLK3 Chroma Clock Divider F10014 WO |
| 124 | JPIT1 Timer 1 Pre-scaler F10000 WO |
| 125 | JPIT3 Timer 2 Pre-scaler F10004 WO |
| 126 | JPIT2 Timer 1 Divider F10002 WO |
| 127 | JPIT4 Timer 2 Divider F10006 WO |
| 128 | J_INT Interrup Control Register F10020 RW |
| 129 | SCLK Serial Clock Frequency F1A150 WO |
| 130 | SMODE Serial Mode F1A154 WO |
| 131 | LTXD Left Transmit Data F1A148 WO |
| 132 | RTXD Right Transmit Data F1A14C WO |
| 133 | LRXD Left Receive Data F1A148 RO |
| 134 | RRXD Right Receive Data F1A14C RO |
| 135 | L_I2S Left I2S Serial Interface F1A148 RW |
| 136 | R_I2S Right I2S Serial Interface F1A14C RW |
| 137 | SSTAT Serial Status F1A150 RO |
| 138 | ASICLK Asynchronous Serial Interface Clock F10034 RW |
| 139 | ASICTRL Asynchronous Serial Control F10032 WO |
| 140 | ASISTAT Asynchronous Serial Status F10032 RO |
| 141 | ASIDATA Asynchronous Serial Data F10030 RW |
| 142 | |
| 143 | JOYSTICK REGISTERS |
| 144 | |
| 145 | JOYSTICK Joystick Register F14000 RW |
| 146 | JOYBUTS Button Register F14002 RW |
| 147 | |
| 148 | DSP REGISTERS |
| 149 | |
| 150 | D_FLAGS DSP Flags Register F1A100 RW |
| 151 | D_MTXC DSP Matrix Control Register F1A104 WO |
| 152 | D_MTXA DSP Matrix Address Register F1A108 WO |
| 153 | D_END DSP Data Organization Register F1A10C WO |
| 154 | D_PC DSP Program Counter F1A110 RW |
| 155 | D_CTRL DSP Control/Status Register F1A114 RW |
| 156 | D_MOD Modulo Instruction Mask F1A118 WO |
| 157 | D_REMAIN Divide Unit Remainder F1A11C RO |
| 158 | D_DIVCTRL Divide Unit Control F1A11C WO |
| 159 | D_MACHI MAC High Result Bits F1A120 RO |
| 160 | */ |
| 161 | |
| 162 | /* |
| 163 | The approach here is to have a list of addresses and who handles them. Could be |
| 164 | a one-to-one memory location up to a range for each function. Will look |
| 165 | something like this: |
| 166 | |
| 167 | { 0xF14000, 0xF14001, MM_IO, JoystickReadHandler, JoystickWriteHandler }, |
| 168 | |
| 169 | Would be nice to have a way of either calling a handler function or reading/writing |
| 170 | directly to/from a variable or array... |
| 171 | */ |
| 172 | |
| 173 | enum MemType { MM_NOP = 0, MM_RAM = 1, MM_ROM = 2, MM_IO_R = 4, MM_IO_W = 8, MM_IO = 12 }; |
| 174 | |
| 175 | /* |
| 176 | Would be nice to have different structs tailored to different memory access types, |
| 177 | but if we don't do that, we can encode things as follows: |
| 178 | |
| 179 | MM_NOP: readFunc = writeFunc = NULL |
| 180 | MM_RAM: readFunc = byte array pointer, writeFunc = NULL |
| 181 | MM_ROM: readFunc = byte array pointer, writeFunc = NULL |
| 182 | MM_IO_R: readFunc = function pointer to read function, writeFunc = NULL |
| 183 | MM_IO_W: readFunc = NULL, writeFunc = function pointer to write function |
| 184 | MM_IO: readFunc = function pointer to read function, writeFunc = function pointer to write function |
| 185 | |
| 186 | There may be a need to have readFunc do both read & write functions (makes sense? perhaps) |
| 187 | |
| 188 | Should we have a read mask as well, for the purposes of reading? |
| 189 | */ |
| 190 | |
| 191 | struct MemDesc { |
| 192 | uint32_t startAddr; |
| 193 | uint32_t endAddr; |
| 194 | MemType type; |
| 195 | // (void (* ioFunc)(uint32, uint32)); // <-- could also be a pointer to RAM... |
| 196 | void * readFunc; // This is read & write with MM_IO |
| 197 | void * writeFunc; |
| 198 | uint32_t mask; |
| 199 | }; |
| 200 | |
| 201 | |
| 202 | MemDesc memoryMap[] = { |
| 203 | { 0x000000, 0x1FFFFF, MM_RAM, jaguarMainRAM }, |
| 204 | { 0x200000, 0x3FFFFF, MM_RAM, jaguarMainRAM }, // Mirror of 1st 2 megs or next 2nd 2 megs of ram |
| 205 | { 0x400000, 0x5FFFFF, MM_RAM, jaguarMainRAM }, // " " or next 3rd 2 megs of ram |
| 206 | { 0x600000, 0x7FFFFF, MM_RAM, jaguarMainRAM }, // " " or next 4th 2 megs of ram |
| 207 | { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM }, |
| 208 | |
| 209 | { 0xDFFF00, 0xDFFF03, MM_IO, &butch }, // base of Butch == interrupt control register, R/W |
| 210 | { 0xDFFF04, 0xDFFF07, MM_IO, &dscntrl }, // DSA control register, R/W |
| 211 | { 0xDFFF0A, 0xDFFF0B, MM_IO, &ds_data }, // DSA TX/RX data, R/W |
| 212 | { 0xDFFF10, 0xDFFF13, MM_IO, &i2cntrl }, // i2s bus control register, R/W |
| 213 | { 0xDFFF14, 0xDFFF17, MM_IO, &sbcntrl }, // CD subcode control register, R/W |
| 214 | { 0xDFFF18, 0xDFFF1B, MM_IO, &subdata }, // Subcode data register A |
| 215 | { 0xDFFF1C, 0xDFFF1F, MM_IO, &subdatb }, // Subcode data register B |
| 216 | { 0xDFFF20, 0xDFFF23, MM_IO, &sb_time }, // Subcode time and compare enable (D24) |
| 217 | { 0xDFFF24, 0xDFFF27, MM_IO, &fifo_data }, // i2s FIFO data |
| 218 | { 0xDFFF28, 0xDFFF2B, MM_IO, &i2sdat2 }, // i2s FIFO data (old) |
| 219 | { 0xDFFF2C, 0xDFFF2F, MM_IO, &unknown }, // Seems to be some sort of I2S interface |
| 220 | |
| 221 | { 0xE00000, 0xE1FFFF, MM_ROM, jaguarBootROM }, |
| 222 | |
| 223 | // TOM REGISTERS |
| 224 | |
| 225 | { 0xF00000, 0xF00001, MM_IO, &memcon1 }, // *MEMCON1 Memory Control Register 1 F00000 RW |
| 226 | { 0xF00002, 0xF00003, MM_IO, &memcon2 }, // *MEMCON2 Memory Control Register 2 F00002 RW |
| 227 | { 0xF00004, 0xF00005, MM_IO, &hc }, // HC Horizontal Count F00004 RW |
| 228 | { 0xF00006, 0xF00007, MM_IO, &vc }, // VC Vertical Count F00006 RW |
| 229 | { 0xF00008, 0xF00009, MM_IO_R, &lph }, // LPH Light Pen Horizontal F00008 RO |
| 230 | { 0xF0000A, 0xF0000B, MM_IO_R, &lpv }, // LPV Light Pen Vertical F0000A RO |
| 231 | { 0xF00010, 0xF00017, MM_IO_R, &obData }, // OB[0-3] Object Data Field F00010-16 RO |
| 232 | { 0xF00020, 0xF00023, MM_IO_W, &olp }, // OLP Object List Pointer F00020-23 WO |
| 233 | { 0xF00026, 0xF00027, MM_IO_W, &obf }, // OBF Object Flag F00026 WO |
| 234 | { 0xF00028, 0xF00029, MM_IO_W, &vmode }, // VMODE Video Mode F00028 WO |
| 235 | { 0xF0002A, 0xF0002B, MM_IO_W, &bord1 }, // BORD1 Border Colour (Red & Green) F0002A WO |
| 236 | { 0xF0002C, 0xF0002D, MM_IO_W, &bord2 }, // BORD2 Border Colour (Blue) F0002C WO |
| 237 | { 0xF0002E, 0xF0002F, MM_IO_W, &hp }, // *HP Horizontal Period F0002E WO |
| 238 | { 0xF00030, 0xF00031, MM_IO_W, &hbb }, // *HBB Horizontal Blank Begin F00030 WO |
| 239 | { 0xF00032, 0xF00033, MM_IO_W, &hbe }, // *HBE Horizontal Blank End F00032 WO |
| 240 | { 0xF00034, 0xF00035, MM_IO_W, &hs }, // *HS Horizontal Sync F00034 WO |
| 241 | { 0xF00036, 0xF00037, MM_IO_W, &hvs }, // *HVS Horizontal Vertical Sync F00036 WO |
| 242 | { 0xF00038, 0xF00039, MM_IO_W, &hdb1 }, // HDB1 Horizontal Display Begin 1 F00038 WO |
| 243 | { 0xF0003A, 0xF0003B, MM_IO_W, &hdb2 }, // HDB2 Horizontal Display Begin 2 F0003A WO |
| 244 | { 0xF0003C, 0xF0003D, MM_IO_W, &hde }, // HDE Horizontal Display End F0003C WO |
| 245 | { 0xF0003E, 0xF0003F, MM_IO_W, &vp }, // *VP Vertical Period F0003E WO |
| 246 | { 0xF00040, 0xF00041, MM_IO_W, &vbb }, // *VBB Vertical Blank Begin F00040 WO |
| 247 | { 0xF00042, 0xF00043, MM_IO_W, &vbe }, // *VBE Vertical Blank End F00042 WO |
| 248 | { 0xF00044, 0xF00045, MM_IO_W, &vs }, // *VS Vertical Sync F00044 WO |
| 249 | { 0xF00046, 0xF00047, MM_IO_W, &vdb }, // VDB Vertical Display Begin F00046 WO |
| 250 | { 0xF00048, 0xF00049, MM_IO_W, &vde }, // VDE Vertical Display End F00048 WO |
| 251 | { 0xF0004A, 0xF0004B, MM_IO_W, &veb }, // *VEB Vertical Equalization Begin F0004A WO |
| 252 | { 0xF0004C, 0xF0004D, MM_IO_W, &vee }, // *VEE Vertical Equalization End F0004C WO |
| 253 | { 0xF0004E, 0xF0004F, MM_IO_W, &vi }, // VI Vertical Interrupt F0004E WO |
| 254 | { 0xF00050, 0xF00051, MM_IO_W, &pit0 }, // PIT[0-1] Programmable Interrupt Timer F00050-52 WO |
| 255 | { 0xF00052, 0xF00053, MM_IO_W, &pit1 }, |
| 256 | { 0xF00054, 0xF00055, MM_IO_W, &heq }, // *HEQ Horizontal Equalization End F00054 WO |
| 257 | { 0xF00058, 0xF0005B, MM_IO_W, &bg }, // BG Background Colour F00058 WO |
| 258 | { 0xF000E0, 0xF000E1, MM_IO, &int1 }, // INT1 CPU Interrupt Control Register F000E0 RW |
| 259 | { 0xF000E2, 0xF000E3, MM_IO_W, &int2 }, // INT2 CPU Interrupt Resume Register F000E2 WO |
| 260 | //Some of these RAM spaces may be 16- or 32-bit only... in which case, we need |
| 261 | //to cast appropriately (in memory.cpp, that is)... |
| 262 | { 0xF00400, 0xF005FF, MM_RAM, clut }, // CLUT Colour Look-Up Table F00400-7FE RW |
| 263 | { 0xF00600, 0xF007FF, MM_RAM, clut }, |
| 264 | { 0xF00800, 0xF01D9F, MM_RAM, lbuf }, // LBUF Line Buffer F00800-1D9E RW |
| 265 | //Need high speed RAM interface for GPU & DSP (we have it now...) |
| 266 | |
| 267 | // GPU REGISTERS |
| 268 | |
| 269 | { 0xF02100, 0xF02103, MM_IO, &g_flags }, // G_FLAGS GPU Flags Register F02100 RW |
| 270 | { 0xF02104, 0xF02107, MM_IO_W, &g_mtxc }, // G_MTXC Matrix Control Register F02104 WO |
| 271 | { 0xF02108, 0xF0210B, MM_IO_W, &g_mtxa }, // G_MTXA Matrix Address Register F02108 WO |
| 272 | { 0xF0210C, 0xF0210F, MM_IO_W, &g_end }, // G_END Data Organization Register F0210C WO |
| 273 | { 0xF02110, 0xF02113, MM_IO, &g_pc }, // G_PC GPU Program Counter F02110 RW |
| 274 | { 0xF02114, 0xF02117, MM_IO, &g_ctrl }, // G_CTRL GPU Control/Status Register F02114 RW |
| 275 | { 0xF02118, 0xF0211B, MM_IO, &g_hidata }, // G_HIDATA High Data Register F02118 RW |
| 276 | { 0xF0211C, 0xF0211F, MM_IO, &g_remain, &g_divctrl }, // G_REMAIN Divide Unit Remainder F0211C RO |
| 277 | // G_DIVCTRL Divide Unit Control F0211C WO |
| 278 | { 0xF03000, 0xF03FFF, MM_RAM, gpuRAM }, |
| 279 | |
| 280 | // BLITTER REGISTERS |
| 281 | |
| 282 | { 0xF02200, 0xF02203, MM_IO_W, &a1_base }, // A1_BASE A1 Base Register F02200 WO |
| 283 | { 0xF02204, 0xF02207, MM_IO, &a1_pixel, &a1_flags }, // A1_FLAGS Flags Register F02204 WO |
| 284 | { 0xF02208, 0xF0220B, MM_IO_W, &a1_clip }, // A1_CLIP A1 Clipping Size F02208 WO |
| 285 | { 0xF0220C, 0xF0220F, MM_IO_W, &a1_pixel }, // A1_PIXEL A1 Pixel Pointer F0220C WO |
| 286 | // F02204 RO |
| 287 | { 0xF02210, 0xF02213, MM_IO_W, &a1_step }, // A1_STEP A1 Step Value F02210 WO |
| 288 | { 0xF02214, 0xF02217, MM_IO_W, &a1_fstep }, // A1_FSTEP A1 Step Fraction Value F02214 WO |
| 289 | { 0xF02218, 0xF0221B, MM_IO, &a1_fpixel }, // A1_FPIXEL A1 Pixel Pointer Fraction F02218 RW |
| 290 | { 0xF0221C, 0xF0221F, MM_IO_W, &a1_inc }, // A1_INC A1 Increment F0221C WO |
| 291 | { 0xF02220, 0xF02223, MM_IO_W, &a1_finc }, // A1_FINC A1 Increment Fraction F02220 WO |
| 292 | { 0xF02224, 0xF02227, MM_IO_W, &a2_base }, // A2_BASE A2 Base Register F02224 WO |
| 293 | { 0xF02228, 0xF0222B, MM_IO_W, &a2_flags }, // A2_FLAGS A2 Flags Register F02228 WO |
| 294 | { 0xF0222C, 0xF0222F, MM_IO, &a2_pixel, &a2_mask }, // A2_MASK A2 Window Mask F0222C WO |
| 295 | { 0xF02230, 0xF02233, MM_IO_W, &a2_pixel }, // A2_PIXEL A2 Pixel Pointer F02230 WO |
| 296 | // F0222C RO |
| 297 | { 0xF02234, 0xF02237, MM_IO_W, &a2_step }, // A2_STEP A2 Step Value F02234 WO |
| 298 | { 0xF02238, 0xF0223B, MM_IO, &b_cmd }, // B_CMD Command/Status Register F02238 RW |
| 299 | { 0xF0223C, 0xF0223F, MM_IO_W, &b_count }, // B_COUNT Counters Register F0223C WO |
| 300 | { 0xF02240, 0xF02247, MM_IO_W, &b_srcd }, // B_SRCD Source Data Register F02240 WO |
| 301 | { 0xF02248, 0xF0224F, MM_IO_W, &b_dstd }, // B_DSTD Destination Data Register F02248 WO |
| 302 | { 0xF02250, 0xF02258, MM_IO_W, &b_dstz }, // B_DSTZ Destination Z Register F02250 WO |
| 303 | { 0xF02258, 0xF0225F, MM_IO_W, &b_srcz1 }, // B_SRCZ1 Source Z Register 1 F02258 WO |
| 304 | { 0xF02260, 0xF02267, MM_IO_W, &b_srcz2 }, // B_SRCZ2 Source Z Register 2 F02260 WO |
| 305 | { 0xF02268, 0xF0226F, MM_IO_W, &b_patd }, // B_PATD Pattern Data Register F02268 WO |
| 306 | { 0xF02270, 0xF02273, MM_IO_W, &b_iinc }, // B_IINC Intensity Increment F02270 WO |
| 307 | { 0xF02274, 0xF02277, MM_IO_W, &b_zinc }, // B_ZINC Z Increment F02274 WO |
| 308 | { 0xF02278, 0xF0227B, MM_IO_W, &b_stop }, // B_STOP Collision Control F02278 WO |
| 309 | { 0xF0227C, 0xF0227F, MM_IO_W, &b_i3 }, // B_I3 Intensity 3 F0227C WO |
| 310 | { 0xF02280, 0xF02283, MM_IO_W, &b_i2 }, // B_I2 Intensity 2 F02280 WO |
| 311 | { 0xF02284, 0xF02287, MM_IO_W, &b_i1 }, // B_I1 Intensity 1 F02284 WO |
| 312 | { 0xF02288, 0xF0228B, MM_IO_W, &b_i0 }, // B_I0 Intensity 0 F02288 WO |
| 313 | { 0xF0228C, 0xF0228F, MM_IO_W, &b_z3 }, // B_Z3 Z 3 F0228C WO |
| 314 | { 0xF02290, 0xF02293, MM_IO_W, &b_z2 }, // B_Z2 Z 2 F02290 WO |
| 315 | { 0xF02294, 0xF02297, MM_IO_W, &b_z1 }, // B_Z1 Z 1 F02294 WO |
| 316 | { 0xF02298, 0xF0229B, MM_IO_W, &b_z0 }, // B_Z0 Z 0 F02298 WO |
| 317 | |
| 318 | // JTRM sez ALL GPU address space is accessible from $8000 offset as "fast" 32-bit WO access |
| 319 | // Dunno if anything actually USED it tho... :-P |
| 320 | { 0xF0A100, 0xF0A103, MM_IO_W, &g_flags }, // G_FLAGS GPU Flags Register F02100 RW |
| 321 | { 0xF0A104, 0xF0A107, MM_IO_W, &g_mtxc }, // G_MTXC Matrix Control Register F02104 WO |
| 322 | { 0xF0A108, 0xF0A10B, MM_IO_W, &g_mtxa }, // G_MTXA Matrix Address Register F02108 WO |
| 323 | { 0xF0A10C, 0xF0A10F, MM_IO_W, &g_end }, // G_END Data Organization Register F0210C WO |
| 324 | { 0xF0A110, 0xF0A113, MM_IO_W, &g_pc }, // G_PC GPU Program Counter F02110 RW |
| 325 | { 0xF0A114, 0xF0A117, MM_IO_W, &g_ctrl }, // G_CTRL GPU Control/Status Register F02114 RW |
| 326 | { 0xF0A118, 0xF0A11B, MM_IO_W, &g_hidata }, // G_HIDATA High Data Register F02118 RW |
| 327 | { 0xF0A11C, 0xF0A11F, MM_IO_W, &g_divctrl }, // G_REMAIN Divide Unit Remainder F0211C RO |
| 328 | { 0xF0B000, 0xF0BFFF, MM_IO_W, gpuRAM }, // "Fast" interface to GPU RAM |
| 329 | |
| 330 | // JERRY REGISTERS |
| 331 | |
| 332 | { 0xF10000, 0xF10001, MM_IO_W, &jpit1 }, // JPIT1 Timer 1 Pre-scaler F10000 WO |
| 333 | { 0xF10002, 0xF10003, MM_IO_W, &jpit2 }, // JPIT2 Timer 1 Divider F10002 WO |
| 334 | { 0xF10004, 0xF10005, MM_IO_W, &jpit3 }, // JPIT3 Timer 2 Pre-scaler F10004 WO |
| 335 | { 0xF10006, 0xF10007, MM_IO_W, &jpit4 }, // JPIT4 Timer 2 Divider F10006 WO |
| 336 | { 0xF10010, 0xF10011, MM_IO_W, &clk1 }, // *CLK1 Processor Clock Divider F10010 WO |
| 337 | { 0xF10012, 0xF10013, MM_IO_W, &clk2 }, // *CLK2 Video Clock Divider F10012 WO |
| 338 | { 0xF10014, 0xF10015, MM_IO_W, &clk3 }, // *CLK3 Chroma Clock Divider F10014 WO |
| 339 | { 0xF10020, 0xF10021, MM_IO, &j_int }, // J_INT Interrup Control Register F10020 RW |
| 340 | { 0xF10030, 0xF10031, MM_IO, &asidata }, // ASIDATA Asynchronous Serial Data F10030 RW |
| 341 | { 0xF10032, 0xF10033, MM_IO, &asistat, &asictrl }, // ASICTRL Asynchronous Serial Control F10032 WO |
| 342 | // ASISTAT Asynchronous Serial Status F10032 RO |
| 343 | { 0xF10034, 0xF10035, MM_IO, &asiclk }, // ASICLK Asynchronous Serial Interface Clock F10034 RW |
| 344 | { 0xF10036, 0xF10037, MM_IO_R, &jpit1 }, // JPIT1 Timer 1 Pre-scaler F10036 RO |
| 345 | { 0xF10038, 0xF10039, MM_IO_R, &jpit2 }, // JPIT2 Timer 1 Divider F10038 RO |
| 346 | { 0xF1003A, 0xF1003B, MM_IO_R, &jpit3 }, // JPIT3 Timer 2 Pre-scaler F1003A RO |
| 347 | { 0xF1003C, 0xF1003D, MM_IO_R, &jpit4 }, // JPIT4 Timer 2 Divider F1003C RO |
| 348 | |
| 349 | { 0xF14000, 0xF14001, MM_IO, &joystick }, // JOYSTICK Joystick Register F14000 RW |
| 350 | { 0xF14002, 0xF14003, MM_IO, &joybuts }, // JOYBUTS Button Register F14002 RW |
| 351 | |
| 352 | // DSP REGISTERS |
| 353 | |
| 354 | { 0xF1A100, 0xF1A103, MM_IO, &d_flags }, // D_FLAGS DSP Flags Register F1A100 RW |
| 355 | { 0xF1A104, 0xF1A107, MM_IO_W, &d_mtxc }, // D_MTXC DSP Matrix Control Register F1A104 WO |
| 356 | { 0xF1A108, 0xF1A10B, MM_IO_W, &d_mtxa }, // D_MTXA DSP Matrix Address Register F1A108 WO |
| 357 | { 0xF1A10C, 0xF1A10F, MM_IO_W, &d_end }, // D_END DSP Data Organization Register F1A10C WO |
| 358 | { 0xF1A110, 0xF1A113, MM_IO, &d_pc }, // D_PC DSP Program Counter F1A110 RW |
| 359 | { 0xF1A114, 0xF1A117, MM_IO, &d_ctrl }, // D_CTRL DSP Control/Status Register F1A114 RW |
| 360 | { 0xF1A118, 0xF1A11B, MM_IO_W, &d_mod }, // D_MOD Modulo Instruction Mask F1A118 WO |
| 361 | { 0xF1A11C, 0xF1A11F, MM_IO_W, &d_remain, &d_divctrl }, // D_REMAIN Divide Unit Remainder F1A11C RO |
| 362 | // D_DIVCTRL Divide Unit Control F1A11C WO |
| 363 | { 0xF1A120, 0xF1A123, MM_IO_R, &d_machi }, // D_MACHI MAC High Result Bits F1A120 RO |
| 364 | |
| 365 | |
| 366 | { 0xF1A148, 0xF1A149, MM_IO, &lrxd, <xd }, // LTXD Left Transmit Data F1A148 WO |
| 367 | // LRXD Left Receive Data F1A148 RO |
| 368 | // L_I2S Left I2S Serial Interface F1A148 RW |
| 369 | { 0xF1A14C, 0xF1A14D, MM_IO, &rrxd, &rtxd }, // RTXD Right Transmit Data F1A14C WO |
| 370 | // RRXD Right Receive Data F1A14C RO |
| 371 | // R_I2S Right I2S Serial Interface F1A14C RW |
| 372 | { 0xF1A150, 0xF1A150, MM_IO, &sstat, &sclk }, // SCLK Serial Clock Frequency F1A150 WO |
| 373 | // SSTAT Serial Status F1A150 RO |
| 374 | { 0xF1A154, 0xF1A157, MM_IO_W, &smode }, // SMODE Serial Mode F1A154 WO |
| 375 | |
| 376 | { 0xF1B000, 0xF1CFFF, MM_RAM, dspRAM }, // F1B000-F1CFFF R/W xxxxxxxx xxxxxxxx Local DSP RAM |
| 377 | { 0xF1D000, 0xF1DFFF, MM_ROM, waveTableROM }, |
| 378 | // hi-speed interface for DSP??? Ain't no such thang... |
| 379 | { 0xFFFFFF, 0xFFFFFF, MM_NOP } // End of memory address sentinel |
| 380 | }; |
| 381 | |
| 382 | #if 0 |
| 383 | |
| 384 | // Jaguar Memory map/handlers |
| 385 | uint32_t memoryMap[] = { |
| 386 | { 0x000000, 0x3FFFFF, MM_RAM, jaguarMainRAM }, |
| 387 | { 0x800000, 0xDFFEFF, MM_ROM, jaguarMainROM }, |
| 388 | // Note that this is really memory mapped I/O region... |
| 389 | // { 0xDFFF00, 0xDFFFFF, MM_RAM, cdRAM }, |
| 390 | { 0xDFFF00, 0xDFFF03, MM_IO, cdBUTCH }, // base of Butch == interrupt control register, R/W |
| 391 | { 0xDFFF04, 0xDFFF07, MM_IO, cdDSCNTRL }, // DSA control register, R/W |
| 392 | { 0xDFFF0A, 0xDFFF0B, MM_IO, cdDS_DATA }, // DSA TX/RX data, R/W |
| 393 | { 0xDFFF10, 0xDFFF13, MM_IO, cdI2CNTRL }, // i2s bus control register, R/W |
| 394 | { 0xDFFF14, 0xDFFF17, MM_IO, cdSBCNTRL }, // CD subcode control register, R/W |
| 395 | { 0xDFFF18, 0xDFFF1B, MM_IO, cdSUBDATA }, // Subcode data register A |
| 396 | { 0xDFFF1C, 0xDFFF1F, MM_IO, cdSUBDATB }, // Subcode data register B |
| 397 | { 0xDFFF20, 0xDFFF23, MM_IO, cdSB_TIME }, // Subcode time and compare enable (D24) |
| 398 | { 0xDFFF24, 0xDFFF27, MM_IO, cdFIFO_DATA }, // i2s FIFO data |
| 399 | { 0xDFFF28, 0xDFFF2B, MM_IO, cdI2SDAT2 }, // i2s FIFO data (old) |
| 400 | { 0xDFFF2C, 0xDFFF2F, MM_IO, cdUNKNOWN }, // Seems to be some sort of I2S interface |
| 401 | |
| 402 | { 0xE00000, 0xE3FFFF, MM_ROM, jaguarBootROM }, |
| 403 | |
| 404 | // { 0xF00000, 0xF0FFFF, MM_IO, TOM_REGS_RW }, |
| 405 | { 0xF00050, 0xF00051, MM_IO, tomTimerPrescaler }, |
| 406 | { 0xF00052, 0xF00053, MM_IO, tomTimerDivider }, |
| 407 | { 0xF00400, 0xF005FF, MM_RAM, tomRAM }, // CLUT A&B: How to link these? Write to one writes to the other... |
| 408 | { 0xF00600, 0xF007FF, MM_RAM, tomRAM }, // Actually, this is a good approach--just make the reads the same as well |
| 409 | //What about LBUF writes??? |
| 410 | { 0xF02100, 0xF0211F, MM_IO, GPUWriteByte }, // GPU CONTROL |
| 411 | { 0xF02200, 0xF0229F, MM_IO, BlitterWriteByte }, // BLITTER |
| 412 | { 0xF03000, 0xF03FFF, MM_RAM, GPUWriteByte }, // GPU RAM |
| 413 | |
| 414 | { 0xF10000, 0xF1FFFF, MM_IO, JERRY_REGS_RW }, |
| 415 | |
| 416 | /* |
| 417 | EEPROM: |
| 418 | { 0xF14001, 0xF14001, MM_IO_RO, eepromFOO } |
| 419 | { 0xF14801, 0xF14801, MM_IO_WO, eepromBAR } |
| 420 | { 0xF15001, 0xF15001, MM_IO_RW, eepromBAZ } |
| 421 | |
| 422 | JOYSTICK: |
| 423 | { 0xF14000, 0xF14003, MM_IO, joystickFoo } |
| 424 | 0 = pad0/1 button values (4 bits each), RO(?) |
| 425 | 1 = pad0/1 index value (4 bits each), WO |
| 426 | 2 = unused, RO |
| 427 | 3 = NTSC/PAL, certain button states, RO |
| 428 | |
| 429 | JOYSTICK $F14000 Read/Write |
| 430 | 15.....8 7......0 |
| 431 | Read fedcba98 7654321q f-1 Signals J15 to J1 |
| 432 | q Cartridge EEPROM output data |
| 433 | Write exxxxxxm 76543210 e 1 = enable J7-J0 outputs |
| 434 | 0 = disable J7-J0 outputs |
| 435 | x don't care |
| 436 | m Audio mute |
| 437 | 0 = Audio muted (reset state) |
| 438 | 1 = Audio enabled |
| 439 | 7-4 J7-J4 outputs (port 2) |
| 440 | 3-0 J3-J0 outputs (port 1) |
| 441 | JOYBUTS $F14002 Read Only |
| 442 | 15.....8 7......0 |
| 443 | Read xxxxxxxx rrdv3210 x don't care |
| 444 | r Reserved |
| 445 | d Reserved |
| 446 | v 1 = NTSC Video hardware |
| 447 | 0 = PAL Video hardware |
| 448 | 3-2 Button inputs B3 & B2 (port 2) |
| 449 | 1-0 Button inputs B1 & B0 (port 1) |
| 450 | |
| 451 | J4 J5 J6 J7 Port 2 B2 B3 J12 J13 J14 J15 |
| 452 | J3 J2 J1 J0 Port 1 B0 B1 J8 J9 J10 J11 |
| 453 | 0 0 0 0 |
| 454 | 0 0 0 1 |
| 455 | 0 0 1 0 |
| 456 | 0 0 1 1 |
| 457 | 0 1 0 0 |
| 458 | 0 1 0 1 |
| 459 | 0 1 1 0 |
| 460 | 0 1 1 1 Row 3 C3 Option # 9 6 3 |
| 461 | 1 0 0 0 |
| 462 | 1 0 0 1 |
| 463 | 1 0 1 0 |
| 464 | 1 0 1 1 Row 2 C2 C 0 8 5 2 |
| 465 | 1 1 0 0 |
| 466 | 1 1 0 1 Row 1 C1 B * 7 4 1 |
| 467 | 1 1 1 0 Row 0 Pause A Up Down Left Right |
| 468 | 1 1 1 1 |
| 469 | |
| 470 | 0 bit read in any position means that button is pressed. |
| 471 | C3 = C2 = 1 means std. Jag. cntrlr. or nothing attached. |
| 472 | */ |
| 473 | }; |
| 474 | #endif |
| 475 | |
| 476 | void MMUWrite8(uint32_t address, uint8_t data, uint32_t who/*= UNKNOWN*/) |
| 477 | { |
| 478 | } |
| 479 | |
| 480 | void MMUWrite16(uint32_t address, uint16_t data, uint32_t who/*= UNKNOWN*/) |
| 481 | { |
| 482 | } |
| 483 | |
| 484 | void MMUWrite32(uint32_t address, uint32_t data, uint32_t who/*= UNKNOWN*/) |
| 485 | { |
| 486 | } |
| 487 | |
| 488 | void MMUWrite64(uint32_t address, uint64_t data, uint32_t who/*= UNKNOWN*/) |
| 489 | { |
| 490 | } |
| 491 | |
| 492 | uint8_t MMURead8(uint32_t address, uint32_t who/*= UNKNOWN*/) |
| 493 | { |
| 494 | // Search for address in the memory map |
| 495 | // NOTE: This assumes that all entries are linear and sorted in ascending order! |
| 496 | |
| 497 | MemDesc memory; |
| 498 | uint8_t byte = 0xFE; |
| 499 | |
| 500 | uint32_t i = 0; |
| 501 | while (true) |
| 502 | { |
| 503 | if (address <= memoryMap[i].endAddr) |
| 504 | { |
| 505 | if (address >= memoryMap[i].startAddr) |
| 506 | { |
| 507 | memory = memoryMap[i]; |
| 508 | break; |
| 509 | } |
| 510 | else |
| 511 | return 0xFF; // Wasn't found... |
| 512 | } |
| 513 | |
| 514 | i++; |
| 515 | |
| 516 | if (memoryMap[i].startAddr == 0xFFFFFF) |
| 517 | return 0xFF; // Exhausted the list, so bail! |
| 518 | } |
| 519 | |
| 520 | uint32_t offset = address - memory.startAddr; |
| 521 | //uint32_t size = memory.endAddr - memory.startAddr + 1; |
| 522 | uint8_t byteShift[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; |
| 523 | |
| 524 | if (memory.type == MM_RAM || memory.type == MM_ROM) |
| 525 | { |
| 526 | byte = ((uint8_t *)memory.readFunc)[offset]; |
| 527 | } |
| 528 | else if (memory.type == MM_IO_R || memory.type == MM_IO) |
| 529 | { |
| 530 | // Problem here: We don't know yet how wide the function is, so we don't know |
| 531 | // how to properly cast it. We COULD ignore the problem by passing in/receiving |
| 532 | // 64-bits of data and letting the function make heads or tails of it, but we |
| 533 | // still have the problem of, say, taking a byte from a 32-bit value. |
| 534 | /* |
| 535 | We can do like so: |
| 536 | uint8_t byteShift[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; |
| 537 | size = memory.endAddr - memory.startAddr + 1; |
| 538 | byte = (returnValFromFunc >> byteShift[offset]) & 0xFF; |
| 539 | |
| 540 | Let's see, will this work depending on the endianess? |
| 541 | uint32_t dword |
| 542 | accessing it like so: |
| 543 | ((uint8_t *)dword &)[0] --> should give us high byte |
| 544 | but if we assign it directly... |
| 545 | dword = 0x12345678 --> becomes 78 56 34 12 in memory, ptr[0] will be 78 in LE! |
| 546 | dword = 0x12345678 --> becomes 12 34 56 78 in memory, ptr[0] will be 12 in BE! |
| 547 | |
| 548 | So we're in danger if we use the variables directly! We'd need something like |
| 549 | #define ENDIAN_SAFE_16(x) swap lo & hi bytes on LE systems |
| 550 | #define ENDIAN_SAFE_16(x) do nothing on BE systems |
| 551 | |
| 552 | Then, if we want to use a jaguar variable, we need to cast it like so: |
| 553 | uint16_t my_vbb = ENDIAN_SAFE_16(vbb); |
| 554 | |
| 555 | We have something like this already in jaguar.h, since we treat I/O spaces like |
| 556 | contiguous memory anyway... For reference: |
| 557 | |
| 558 | // Some handy macros to help converting native endian to big endian (jaguar native) |
| 559 | // & vice versa |
| 560 | |
| 561 | #define SET64(r, a, v) r[(a)] = ((v) & 0xFF00000000000000) >> 56, r[(a)+1] = ((v) & 0x00FF000000000000) >> 48, \ |
| 562 | r[(a)+2] = ((v) & 0x0000FF0000000000) >> 40, r[(a)+3] = ((v) & 0x000000FF00000000) >> 32, \ |
| 563 | r[(a)+4] = ((v) & 0xFF000000) >> 24, r[(a)+5] = ((v) & 0x00FF0000) >> 16, \ |
| 564 | r[(a)+6] = ((v) & 0x0000FF00) >> 8, r[(a)+7] = (v) & 0x000000FF |
| 565 | #define GET64(r, a) (((uint64)r[(a)] << 56) | ((uint64)r[(a)+1] << 48) | \ |
| 566 | ((uint64)r[(a)+2] << 40) | ((uint64)r[(a)+3] << 32) | \ |
| 567 | ((uint64)r[(a)+4] << 24) | ((uint64)r[(a)+5] << 16) | \ |
| 568 | ((uint64)r[(a)+6] << 8) | (uint64)r[(a)+7]) |
| 569 | #define SET32(r, a, v) r[(a)] = ((v) & 0xFF000000) >> 24, r[(a)+1] = ((v) & 0x00FF0000) >> 16, \ |
| 570 | r[(a)+2] = ((v) & 0x0000FF00) >> 8, r[(a)+3] = (v) & 0x000000FF |
| 571 | #define GET32(r, a) ((r[(a)] << 24) | (r[(a)+1] << 16) | (r[(a)+2] << 8) | r[(a)+3]) |
| 572 | #define SET16(r, a, v) r[(a)] = ((v) & 0xFF00) >> 8, r[(a)+1] = (v) & 0xFF |
| 573 | #define GET16(r, a) ((r[(a)] << 8) | r[(a)+1]) |
| 574 | */ |
| 575 | // Confused? Let me enlighten... What we're doing here is casting |
| 576 | // data1 as a pointer to a function which returns a Window pointer and |
| 577 | // which takes no parameters (the "(Window *(*)(void))" part), then |
| 578 | // derefencing it (the "*" in front of that) in order to call the |
| 579 | // function that it points to. Clear as mud? Yeah, I hate function |
| 580 | // pointers too, but what else are you gonna do? |
| 581 | // mainWindow = (*(Window *(*)(void))event.user.data1)(); |
| 582 | // uint32_t retVal = (*(uint32(*)(uint32))memory.readFunc)(offset); |
| 583 | //#define FUNC_CAST(x) (*(uint32(*)(uint32))x) |
| 584 | // uint32_t retVal = FUNC_CAST(memory.readFunc)(offset); |
| 585 | #define FUNC_CAST(retVal, function, params) (*(retVal(*)(params))function) |
| 586 | uint64_t retVal = FUNC_CAST(uint64_t, memory.readFunc, uint32_t)(offset); |
| 587 | byte = (retVal >> byteShift[offset]) & 0xFF; |
| 588 | } |
| 589 | else if (memory.type == MM_IO_W) |
| 590 | { |
| 591 | byte = 0xFF; // Write only, what do we return? A fixed value? |
| 592 | } |
| 593 | |
| 594 | return byte; |
| 595 | } |
| 596 | |
| 597 | uint16_t MMURead16(uint32_t address, uint32_t who/*= UNKNOWN*/) |
| 598 | { |
| 599 | return 0; |
| 600 | } |
| 601 | |
| 602 | uint32_t MMURead32(uint32_t address, uint32_t who/*= UNKNOWN*/) |
| 603 | { |
| 604 | return 0; |
| 605 | } |
| 606 | |
| 607 | uint64_t MMURead64(uint32_t address, uint32_t who/*= UNKNOWN*/) |
| 608 | { |
| 609 | return 0; |
| 610 | } |
| 611 | |
| 612 | |
| 613 | #endif |