pandora: fix readme and pxml version
[picodrive.git] / pico / pico / memory.c
CommitLineData
cff531af 1/*
2 * PicoDrive
3 * (C) notaz, 2008
f1b425e3 4 * (C) irixxxx, 2024
cff531af 5 *
6 * This work is licensed under the terms of MAME license.
7 * See COPYING file in the top-level directory.
8 */
efcba75f 9#include "../pico_int.h"
45f2f245 10#include "../memory.h"
0e732d77 11#include <platform/common/input_pico.h>
12#include <sys/time.h>
9037e45d 13
45f2f245 14/*
15void dump(u16 w)
9037e45d 16{
45f2f245 17 static FILE *f[0x10] = { NULL, };
18 char fname[32];
19 int num = PicoPicohw.r12 & 0xf;
9037e45d 20
45f2f245 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*/
9037e45d 29
0e732d77 30u64 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
f1b425e3 44static u32 PicoRead16_pico(u32 a)
45f2f245 45{
46 u32 d = 0;
9037e45d 47
f1b425e3 48 switch (a & 0x1e)
406c96c5 49 {
f1b425e3 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;
79483b5e 55 case 0x04: d = (PicoPicohw.pen_pos[0] >> 8); break;
f1b425e3 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;
0e732d77 59 case 0x0c: d = (1 << (PicoPicohw.page & 7)) - 1;
f563beb7 60 if (PicoPicohw.page == 7) d = 0x2a; // 0b00101010
0e732d77 61 break;
f1b425e3 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;
406c96c5 67 }
9037e45d 68 return d;
69}
70
f1b425e3 71static u32 PicoRead8_pico(u32 a)
9037e45d 72{
45f2f245 73 u32 d = 0;
9037e45d 74
f1b425e3 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 }
9037e45d 81
f1b425e3 82 elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
9037e45d 83 return d;
84}
85
45f2f245 86static void PicoWrite8_pico(u32 a, u32 d)
9037e45d 87{
45f2f245 88 switch (a & ~0x800000) {
fa22af4c 89 case 0x19: case 0x1b: case 0x1d: case 0x1f: break; // 'S' 'E' 'G' 'A'
90 default:
45f2f245 91 elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
fa22af4c 92 break;
93 }
9037e45d 94}
95
45f2f245 96static void PicoWrite16_pico(u32 a, u32 d)
9037e45d 97{
582890c0 98 //if (a == 0x800010) dump(d);
ef4eb506 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) {
fa22af4c 108 elprintf(EL_ANOMALY|EL_PICOHW, "xpcm_buffer overflow!");
ef4eb506 109 PicoPicohw.xpcm_ptr++;
110 }
111 }
213c16ad 112 else if (a == 0x800012) {
213c16ad 113 PicoPicohw.r12 = d;
f1b425e3 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 }
f563beb7 126 // TODO: other bits used in software: 0x3f00.
213c16ad 127 }
fa22af4c 128 else
45f2f245 129 elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
9037e45d 130}
131
0e732d77 132static u32 PicoRead8_pico_kb(u32 a)
133{
134 u32 d = 0;
bac44b18 135 if (!(PicoIn.opt & POPT_EN_KBD)) {
0e732d77 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
20c9a3ba 142 u32 key_shift = (PicoIn.kbd & 0xff00) >> 8;
143 u32 key = (PicoIn.kbd & 0x00ff);
0e732d77 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
20c9a3ba 151 // override the parsed key code with PEVB_KBD_SHIFT,
0e732d77 152 // otherwise it will be zero and the game won't clear its Shift key state.
153 u32 key_code = (key_shift
154 && !key
fabe161e 155 && PicoPicohw.kb.key_state != PKEY_UP
156 && PicoPicohw.kb.shift_state != PSHIFT_UP_HELD_DOWN)
0e732d77 157 ? key_shift
fabe161e 158 : PicoPicohw.kb.shift_state == PSHIFT_UP ? PEVB_KBD_LSHIFT : key;
0e732d77 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
f563beb7 177 if (PicoPicohw.kb.active) {
20c9a3ba 178 if (key == PEVB_KBD_CAPSLOCK && PicoPicohw.kb.has_caps_lock == 1) {
0e732d77 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;
f563beb7 187 if (PicoPicohw.kb.active) {
0e732d77 188 if (key) {
fabe161e 189 PicoPicohw.kb.key_state = PKEY_DOWN;
0e732d77 190 }
191 if (!key) {
fabe161e 192 PicoPicohw.kb.key_state = !PicoPicohw.kb.key_state ? 0 : (PicoPicohw.kb.key_state + 1) % (PKEY_UP + 1);
0e732d77 193 PicoPicohw.kb.start_time_keydown = 0;
194 }
195 if (key_shift && !key) {
fabe161e 196 if (PicoPicohw.kb.shift_state < PSHIFT_RELEASED_HELD_DOWN) {
0e732d77 197 PicoPicohw.kb.shift_state++;
198 }
199 PicoPicohw.kb.start_time_keydown = 0;
200 }
201 if (!key_shift) {
fabe161e 202 PicoPicohw.kb.shift_state = !PicoPicohw.kb.shift_state ? 0 : (PicoPicohw.kb.shift_state + 1) % (PSHIFT_UP + 1);
0e732d77 203 }
204
fabe161e 205 if (PicoPicohw.kb.key_state == PKEY_DOWN || PicoPicohw.kb.shift_state == PSHIFT_DOWN) {
0e732d77 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();
fabe161e 210 if (PicoPicohw.kb.key_state == PKEY_DOWN)
211 elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PKEY DOWN\n");
0e732d77 212 else
fabe161e 213 elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PSHIFT DOWN\n");
0e732d77 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
20c9a3ba 219 && key_code != PEVB_KBD_CAPSLOCK
576c1b8a 220 && key_code != PEVB_KBD_LSHIFT) {
0e732d77 221 d |= 8; // Send key down a.k.a. make
fabe161e 222 if (PicoPicohw.kb.key_state == PKEY_DOWN)
223 elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PKEY DOWN\n");
0e732d77 224 else
fabe161e 225 elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PSHIFT DOWN\n");
0e732d77 226 }
e979d6d7 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 }
0e732d77 231 }
fabe161e 232 if (PicoPicohw.kb.key_state == PKEY_UP
233 || PicoPicohw.kb.shift_state == PSHIFT_UP_HELD_DOWN
234 || PicoPicohw.kb.shift_state == PSHIFT_UP) {
0e732d77 235 d |= 1; // Send key up a.k.a. break
236 PicoPicohw.kb.start_time_keydown = 0;
fabe161e 237 if (PicoPicohw.kb.key_state == PKEY_UP)
238 elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PKEY UP\n");
0e732d77 239 else
fabe161e 240 elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: PSHIFT UP\n");
0e732d77 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
265static 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
273static 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
302static 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}
9037e45d 308
309PICO_INTERNAL void PicoMemSetupPico(void)
310{
67c81ee2 311 PicoMemSetup();
45f2f245 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);
9037e45d 321
0e732d77 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}