32x: initial code (security code passes)
[picodrive.git] / pico / 32x / memory.c
1 #include "../pico_int.h"
2 #include "../memory.h"
3
4 static const char str_mars[] = "MARS";
5
6 struct Pico32xMem {
7   u8 sdram[0x40000];
8   u8 dram[0x40000]; // AKA fb
9   u8 m68k_rom[M68K_BANK_SIZE]; // 0x100
10 };
11
12 static struct Pico32xMem *Pico32xMem;
13
14 static u32 p32x_reg_read16(u32 a)
15 {
16   a &= 0x3e;
17
18   return Pico32x.regs[a / 2];
19 }
20
21 static void p32x_reg_write16(u32 a, u32 d)
22 {
23   a &= 0x3e;
24
25   if (a == 0 && !(Pico32x.regs[0] & 1)) {
26     Pico32x.regs[0] |= 1;
27     Pico32xStartup();
28     return;
29   }
30 }
31
32 static void p32x_reg_write8(u32 a, u32 d)
33 {
34   a &= 0x3f;
35
36   if (a == 1 && !(Pico32x.regs[0] & 1)) {
37     Pico32x.regs[0] |= 1;
38     Pico32xStartup();
39     return;
40   }
41 }
42
43 // VDP regs
44 static u32 p32x_vdp_read16(u32 a)
45 {
46   a &= 0x0e;
47
48   return Pico32x.vdp_regs[a / 2];
49 }
50
51 static void p32x_vdp_write16(u32 a, u32 d)
52 {
53   a &= 0x0e;
54
55   switch (a) {
56     case 0x0a:
57       Pico32x.pending_fb = d & 1;
58       if (Pico.video.status & 8) {
59         Pico32x.vdp_regs[0x0a/2] &= ~1;
60         Pico32x.vdp_regs[0x0a/2] |= d & 1;
61       }
62       break;
63   }
64 }
65
66 static void p32x_vdp_write8(u32 a, u32 d)
67 {
68   a &= 0x0f;
69
70   switch (a) {
71     case 0x0b:
72       Pico32x.pending_fb = d & 1;
73       if (Pico.video.status & 8) {
74         Pico32x.vdp_regs[0x0a/2] &= ~1;
75         Pico32x.vdp_regs[0x0a/2] |= d & 1;
76       }
77       break;
78   }
79 }
80
81 // default 32x handlers
82 u32 PicoRead8_32x(u32 a)
83 {
84   u32 d = 0;
85   if ((a & 0xffc0) == 0x5100) { // a15100
86     d = p32x_reg_read16(a);
87     goto out_16to8;
88   }
89
90   if ((a & 0xfff0) == 0x5180 && (Pico32x.regs[0] & 1)) {
91     d = p32x_vdp_read16(a);
92     goto out_16to8;
93   }
94
95   if ((a & 0xfffc) == 0x30ec) { // a130ec
96     d = str_mars[a & 3];
97     goto out;
98   }
99
100   elprintf(EL_UIO, "m68k unmapped r8  [%06x] @%06x", a, SekPc);
101   return d;
102
103 out_16to8:
104   if (a & 1)
105     d &= 0xff;
106   else
107     d >>= 8;
108
109 out:
110   elprintf(EL_32X, "m68k 32x r8  [%06x]   %02x @%06x", a, d, SekPc);
111   return d;
112 }
113
114 u32 PicoRead16_32x(u32 a)
115 {
116   u32 d = 0;
117   if ((a & 0xffc0) == 0x5100) { // a15100
118     d = p32x_reg_read16(a);
119     goto out;
120   }
121
122   if ((a & 0xfff0) == 0x5180 && (Pico32x.regs[0] & 1)) { // a15180
123     d = p32x_vdp_read16(a);
124     goto out;
125   }
126
127   if ((a & 0xfffc) == 0x30ec) { // a130ec
128     d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S';
129     goto out;
130   }
131
132   elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc);
133   return d;
134
135 out:
136   elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc);
137   return d;
138 }
139
140 void PicoWrite8_32x(u32 a, u32 d)
141 {
142   if ((a & 0xfc00) == 0x5000)
143     elprintf(EL_32X, "m68k 32x w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
144
145   if ((a & 0xffc0) == 0x5100) { // a15100
146     p32x_reg_write8(a, d);
147     return;
148   }
149
150   if ((a & 0xfff0) == 0x5180 && (Pico32x.regs[0] & 1)) { // a15180
151     p32x_vdp_write8(a, d);
152     return;
153   }
154
155   elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
156 }
157
158 void PicoWrite16_32x(u32 a, u32 d)
159 {
160   if ((a & 0xfc00) == 0x5000)
161     elprintf(EL_UIO, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
162
163   if ((a & 0xffc0) == 0x5100) { // a15100
164     p32x_reg_write16(a, d);
165     return;
166   }
167
168   if ((a & 0xfff0) == 0x5180 && (Pico32x.regs[0] & 1)) { // a15180
169     p32x_vdp_write16(a, d);
170     return;
171   }
172
173   elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
174 }
175
176 // hint vector is writeable
177 static void PicoWrite8_hint(u32 a, u32 d)
178 {
179   if ((a & 0xfffc) == 0x0070) {
180     Pico32xMem->m68k_rom[a ^ 1] = d;
181     return;
182   }
183
184   elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
185 }
186
187 static void PicoWrite16_hint(u32 a, u32 d)
188 {
189   if ((a & 0xfffc) == 0x0070) {
190     ((u16 *)Pico32xMem->m68k_rom)[a/2] = d;
191     return;
192   }
193
194   elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
195 }
196
197 #define HWSWAP(x) (((x) << 16) | ((x) >> 16))
198 void PicoMemSetup32x(void)
199 {
200   unsigned short *ps;
201   unsigned int *pl;
202   unsigned int rs, rs1;
203   int i;
204
205   Pico32xMem = calloc(1, sizeof(*Pico32xMem));
206   if (Pico32xMem == NULL) {
207     elprintf(EL_STATUS, "OOM");
208     return;
209   }
210
211   // generate 68k ROM
212   ps = (unsigned short *)Pico32xMem->m68k_rom;
213   pl = (unsigned int *)Pico32xMem->m68k_rom;
214   for (i = 1; i < 0xc0/4; i++)
215     pl[i] = HWSWAP(0x880200 + i * 6);
216
217   // fill with nops
218   for (i = 0xc0/2; i < 0x100/2; i++)
219     ps[i] = 0x4e71;
220
221   ps[0xc0/2] = 0x46fc;
222   ps[0xc2/2] = 0x2700; // move #0x2700,sr
223   ps[0xfe/2] = 0x60fe; // jump to self
224
225   // fill remaining mem with ROM
226   memcpy(Pico32xMem->m68k_rom + 0x100, Pico.rom + 0x100, M68K_BANK_SIZE - 0x100);
227
228   // cartridge area becomes unmapped
229   // XXX: we take the easy way and don't unmap ROM,
230   // so that we can avoid handling the RV bit.
231   // m68k_map_unmap(0x000000, 0x3fffff);
232
233   // MD ROM area
234   cpu68k_map_set(m68k_read8_map,   0x000000, M68K_BANK_SIZE - 1, Pico32xMem->m68k_rom, 0);
235   cpu68k_map_set(m68k_read16_map,  0x000000, M68K_BANK_SIZE - 1, Pico32xMem->m68k_rom, 0);
236   cpu68k_map_set(m68k_write8_map,  0x000000, M68K_BANK_SIZE - 1, PicoWrite8_hint, 1); // TODO verify
237   cpu68k_map_set(m68k_write16_map, 0x000000, M68K_BANK_SIZE - 1, PicoWrite16_hint, 1);
238
239   // 32X ROM (unbanked, XXX: consider mirroring?)
240   rs1 = rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
241   if (rs1 > 0x80000)
242     rs1 = 0x80000;
243   cpu68k_map_set(m68k_read8_map,   0x880000, 0x880000 + rs1 - 1, Pico.rom, 0);
244   cpu68k_map_set(m68k_read16_map,  0x880000, 0x880000 + rs1 - 1, Pico.rom, 0);
245
246   // 32X ROM (banked)
247   if (rs > 0x100000)
248     rs = 0x100000;
249   cpu68k_map_set(m68k_read8_map,   0x900000, 0x900000 + rs - 1, Pico.rom, 0);
250   cpu68k_map_set(m68k_read16_map,  0x900000, 0x900000 + rs - 1, Pico.rom, 0);
251 }
252