ac5bebf7397ab96ed5bf0377b61021ba47d5442a
[picodrive.git] / pico / pico / memory.c
1 /*
2  * PicoDrive
3  * (C) notaz, 2008
4  * (C) irixxxx, 2024
5  *
6  * This work is licensed under the terms of MAME license.
7  * See COPYING file in the top-level directory.
8  */
9 #include "../pico_int.h"
10 #include "../memory.h"
11 #include <platform/common/input_pico.h>
12 #include <sys/time.h>
13
14 /*
15 void dump(u16 w)
16 {
17   static FILE *f[0x10] = { NULL, };
18   char fname[32];
19   int num = PicoPicohw.r12 & 0xf;
20
21   w = (w << 8) | (w >> 8);
22   sprintf(fname, "ldump%i.bin", num);
23   if (f[num] == NULL)
24     f[num] = fopen(fname, "wb");
25   fwrite(&w, 1, 2, f[num]);
26   //fclose(f);
27 }
28 */
29
30 u64 get_ticks(void)
31 {
32     struct timeval tv;
33     u64 ret;
34
35     gettimeofday(&tv, NULL);
36
37     ret = (unsigned)tv.tv_sec * 1000;
38     /* approximate /= 1000 */
39     ret += ((unsigned)tv.tv_usec * 4195) >> 22;
40
41     return ret;
42 }
43
44 static u32 PicoRead16_pico(u32 a)
45 {
46   u32 d = 0;
47
48   switch (a & 0x1e)
49   {
50     case 0x00: d = PicoPicohw.r1; break;
51     case 0x02: d  =  PicoIn.pad[0]&0x1f; // d-pad
52                d |= (PicoIn.pad[0]&0x20) << 2; // pen push -> C
53                d  = ~d;
54                break;
55     case 0x04: d = (PicoPicohw.pen_pos[0] >> 8);  break;
56     case 0x06: d =  PicoPicohw.pen_pos[0] & 0xff; break;
57     case 0x08: d = (PicoPicohw.pen_pos[1] >> 8);  break;
58     case 0x0a: d =  PicoPicohw.pen_pos[1] & 0xff; break;
59     case 0x0c: d = (1 << (PicoPicohw.page & 7)) - 1;
60                if (PicoPicohw.page == 7) d = 0x2a; // 0b00101010
61                break;
62     case 0x10: d = (PicoPicohw.fifo_bytes > 0x3f) ? 0 : (0x3f - PicoPicohw.fifo_bytes); break;
63     case 0x12: d = (PicoPicohw.fifo_bytes | !PicoPicoPCMBusyN()) ? 0 : 0x8000;
64                d |= PicoPicohw.r12 & 0x7fff;
65                break;
66     default:   elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc); break;
67   }
68   return d;
69 }
70
71 static u32 PicoRead8_pico(u32 a)
72 {
73   u32 d = 0;
74
75   if ((a & 0xffffe0) == 0x800000) // Pico I/O
76   {
77     d = PicoRead16_pico(a);
78     if (!(a & 1)) d >>= 8;
79     return d & 0xff;
80   }
81
82   elprintf(EL_UIO, "m68k unmapped r8  [%06x] @%06x", a, SekPc);
83   return d;
84 }
85
86 static void PicoWrite8_pico(u32 a, u32 d)
87 {
88   switch (a & ~0x800000) {
89     case 0x19: case 0x1b: case 0x1d: case 0x1f: break; // 'S' 'E' 'G' 'A'
90     default:
91       elprintf(EL_UIO, "m68k unmapped w8  [%06x]   %02x @%06x", a, d & 0xff, SekPc);
92       break;
93   }
94 }
95
96 static void PicoWrite16_pico(u32 a, u32 d)
97 {
98   //if (a == 0x800010) dump(d);
99   if (a == 0x800010)
100   {
101     PicoPicohw.fifo_bytes += 2;
102
103     if (PicoPicohw.xpcm_ptr < PicoPicohw.xpcm_buffer + XPCM_BUFFER_SIZE) {
104       *PicoPicohw.xpcm_ptr++ = d >> 8;
105       *PicoPicohw.xpcm_ptr++ = d;
106     }
107     else if (PicoPicohw.xpcm_ptr == PicoPicohw.xpcm_buffer + XPCM_BUFFER_SIZE) {
108       elprintf(EL_ANOMALY|EL_PICOHW, "xpcm_buffer overflow!");
109       PicoPicohw.xpcm_ptr++;
110     }
111   }
112   else if (a == 0x800012) {
113     PicoPicohw.r12 = d;
114
115     PicoPicoPCMGain(8 - (d & 0x0007)); // volume
116     PicoPicoPCMFilter((d & 0x00c0) >> 6); // low pass filter
117     PicoPicoPCMIrqEn(d & 0x4000); // PCM IRQ enable
118
119     if (d & 0x8000) { // PCM reset if 1 is written (dalmatians)?
120       PsndDoPCM(cycles_68k_to_z80(SekCyclesDone() - Pico.t.m68c_frame_start));
121       PicoPicoPCMResetN(0);
122       PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer;
123       PicoPicohw.fifo_bytes = 0;
124       PicoPicoPCMResetN(1);
125     }
126     // TODO: other bits used in software: 0x3f00.
127   }
128   else
129     elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
130 }
131
132 static u32 PicoRead8_pico_kb(u32 a)
133 {
134   u32 d = 0;
135   if (!(PicoIn.opt & POPT_EN_KBD)) {
136     elprintf(EL_PICOHW, "kb: r @%06X %04X = %04X\n", SekPc, a, d);
137     return d;
138   }
139
140   PicoPicohw.kb.has_read = 1;
141
142   u32 key_shift = (PicoIn.kbd & 0xff00) >> 8;
143   u32 key = (PicoIn.kbd & 0x00ff);
144
145   // The Shift key requires 2 key up events to be registered:
146   // SHIFT_UP_HELD_DOWN to allow the game to register the key down event
147   // for the next held down key(s), and SHIFT_UP when the Shift key
148   // is no longer held down.
149   //
150   // For the second key up event, we need to
151   // override the parsed key code with PEVB_KBD_SHIFT,
152   // otherwise it will be zero and the game won't clear its Shift key state.
153   u32 key_code = (key_shift
154       && !key
155       && PicoPicohw.kb.key_state != PKEY_UP
156       && PicoPicohw.kb.shift_state != PSHIFT_UP_HELD_DOWN)
157     ? key_shift
158     : PicoPicohw.kb.shift_state == PSHIFT_UP ? PEVB_KBD_LSHIFT : key;
159   u32 key_code_7654 = (key_code & 0xf0) >> 4;
160   u32 key_code_3210 = (key_code & 0x0f);
161   switch(PicoPicohw.kb.i) {
162     case 0x0: d = 1; // m5id
163       break;
164     case 0x1: d = 3; // m6id
165       break;
166     case 0x2: d = 4; // data size
167       break;
168     case 0x3: d = 0; // pad1 rldu
169       break;
170     case 0x4: d = 0; // pad2 sacb
171       break;
172     case 0x5: d = 0; // pad3 rxyz
173       break;
174     case 0x6: d = 0; // l&kbtype
175       break;
176     case 0x7: // cap/num/scr
177       if (PicoPicohw.kb.active) {
178         if (key == PEVB_KBD_CAPSLOCK && PicoPicohw.kb.has_caps_lock == 1) {
179           PicoPicohw.kb.caps_lock = PicoPicohw.kb.caps_lock == 4 ? 0 : 4;
180           PicoPicohw.kb.has_caps_lock = 0;
181         }
182         d = PicoPicohw.kb.caps_lock;
183       }
184       break;
185     case 0x8:
186       d = 6;
187       if (PicoPicohw.kb.active) {
188         if (key) {
189           PicoPicohw.kb.key_state = PKEY_DOWN;
190         }
191         if (!key) {
192           PicoPicohw.kb.key_state = !PicoPicohw.kb.key_state ? 0 : (PicoPicohw.kb.key_state + 1) % (PKEY_UP + 1);
193           PicoPicohw.kb.start_time_keydown = 0;
194         }
195         if (key_shift && !key) {
196           if (PicoPicohw.kb.shift_state < PSHIFT_RELEASED_HELD_DOWN) {
197             PicoPicohw.kb.shift_state++;
198           }
199           PicoPicohw.kb.start_time_keydown = 0;
200         }
201         if (!key_shift) {
202           PicoPicohw.kb.shift_state = !PicoPicohw.kb.shift_state ? 0 : (PicoPicohw.kb.shift_state + 1) % (PSHIFT_UP + 1);
203         }
204
205         if (PicoPicohw.kb.key_state == PKEY_DOWN || PicoPicohw.kb.shift_state == PSHIFT_DOWN) {
206           if (PicoPicohw.kb.start_time_keydown == 0) {
207             d |= 8; // Send key down a.k.a. make
208             PicoPicohw.kb.time_keydown = 0;
209             PicoPicohw.kb.start_time_keydown = get_ticks();
210            if (PicoPicohw.kb.key_state == PKEY_DOWN)
211               elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PKEY DOWN\n");
212            else
213               elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PSHIFT DOWN\n");
214           }
215           // Simulate key repeat while held down a.k.a. typematic
216           PicoPicohw.kb.time_keydown = get_ticks() - PicoPicohw.kb.start_time_keydown;
217           if (PicoPicohw.kb.time_keydown > 350
218                   // Modifier keys don't have typematic
219                   && key_code != PEVB_KBD_CAPSLOCK
220                   && key_code != PEVB_KBD_LSHIFT) {
221             d |= 8; // Send key down a.k.a. make
222            if (PicoPicohw.kb.key_state == PKEY_DOWN)
223               elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PKEY DOWN\n");
224            else
225               elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PSHIFT DOWN\n");
226           }
227           // Must register key up while typematic not active (expected by Kibodeu Piko)
228           if ((d & 8) == 0) {
229             d |= 1; // Send key up a.k.a. break
230           }
231         }
232         if (PicoPicohw.kb.key_state == PKEY_UP
233             || PicoPicohw.kb.shift_state == PSHIFT_UP_HELD_DOWN
234             || PicoPicohw.kb.shift_state == PSHIFT_UP) {
235           d |= 1; // Send key up a.k.a. break
236           PicoPicohw.kb.start_time_keydown = 0;
237            if (PicoPicohw.kb.key_state == PKEY_UP)
238               elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PKEY UP\n");
239            else
240               elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PSHIFT UP\n");
241         }
242       }
243       break;
244     case 0x9: d = key_code_7654; // data 7654
245       break;
246     case 0xa: d = key_code_3210; // data 3210
247       break;
248     case 0xb: d = 0; // ?
249       break;
250     case 0xc: d = 0; // ?
251       break;
252     default:
253       d = 0;
254       break;
255   }
256
257   if (PicoPicohw.kb.neg) {
258       d |= 0xfffffff0;
259   }
260
261   elprintf(EL_PICOHW, "kb: r @%06X %04X = %04X\n", SekPc, a, d);
262   return d;
263 }
264
265 static u32 PicoRead16_pico_kb(u32 a)
266 {
267   u32 d = PicoPicohw.kb.mem;
268
269   elprintf(EL_PICOHW, "kb: r16 @%06X %04X = %04X\n", SekPc, a, d);
270   return d;
271 }
272
273 static void PicoWrite8_pico_kb(u32 a, u32 d)
274 {
275   elprintf(EL_PICOHW, "kb: w @%06X %04X = %04X\n", SekPc, a, d);
276
277   switch(d) {
278     case 0x0:
279       PicoPicohw.kb.neg = 0;
280       PicoPicohw.kb.i++;
281       break;
282     case 0x20:
283       PicoPicohw.kb.neg = 1;
284       if (PicoPicohw.kb.has_read == 1) {
285         PicoPicohw.kb.i++;
286       }
287       break;
288     case 0x40:
289       break;
290     case 0x60:
291       PicoPicohw.kb.mode = !PicoPicohw.kb.mode;
292       PicoPicohw.kb.i = 0;
293       PicoPicohw.kb.has_read = 0;
294       break;
295     default:
296       break;
297   }
298
299   PicoPicohw.kb.mem = (PicoPicohw.kb.mem & 0xff00) | d;
300 }
301
302 static void PicoWrite16_pico_kb(u32 a, u32 d)
303 {
304   elprintf(EL_PICOHW, "kb: w16 @%06X %04X = %04X\n", SekPc, a, d);
305
306   PicoPicohw.kb.mem = d;
307 }
308
309 PICO_INTERNAL void PicoMemSetupPico(void)
310 {
311   PicoMemSetup();
312
313   // no MD IO or Z80 on Pico
314   m68k_map_unmap(0x400000, 0xbfffff);
315
316   // map Pico I/O
317   cpu68k_map_set(m68k_read8_map,   0x800000, 0x80ffff, PicoRead8_pico, 1);
318   cpu68k_map_set(m68k_read16_map,  0x800000, 0x80ffff, PicoRead16_pico, 1);
319   cpu68k_map_set(m68k_write8_map,  0x800000, 0x80ffff, PicoWrite8_pico, 1);
320   cpu68k_map_set(m68k_write16_map, 0x800000, 0x80ffff, PicoWrite16_pico, 1);
321
322   m68k_map_unmap(0x200000, 0x20ffff);
323
324   // map Pico PS/2 Peripheral I/O
325   cpu68k_map_set(m68k_read8_map,   0x200000, 0x20ffff, PicoRead8_pico_kb, 1);
326   cpu68k_map_set(m68k_read16_map,  0x200000, 0x20ffff, PicoRead16_pico_kb, 1);
327   cpu68k_map_set(m68k_write8_map,  0x200000, 0x20ffff, PicoWrite8_pico_kb, 1);
328   cpu68k_map_set(m68k_write16_map, 0x200000, 0x20ffff, PicoWrite16_pico_kb, 1);
329 }