Commit | Line | Data |
---|---|---|
cf76e892 JPM |
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 |