some more SVP work
[picodrive.git] / Pico / carthw / svp / ssp16.c
CommitLineData
f8ef8ff7 1// basic, incomplete SSP160x (SSP1601?) interpreter
2
3/*
4 * Register info
5 * most names taken from MAME code
6 *
7 * 0. "-"
8 * size: 16
9 * desc: Constant register with all bits set (0xffff).
10 *
11 * 1. "X"
12 * size: 16
13 * desc: Generic register. When set, updates P (P = X * Y * 2) ??
14 *
15 * 2. "Y"
16 * size: 16
17 * desc: Generic register. When set, updates P (P = X * Y * 2) ??
18 *
19 * 3. "A"
20 * size: 32
21 * desc: Accumulator.
22 *
23 * 4. "ST"
24 * size: 16
25 * desc: Status register. From MAME: bits 0-9 are CONTROL, other FLAG
26 * fedc ba98 7654 3210
27 * 210 - RPL (?) (e: "loop size", fir16_32.sc)
28 * 43 - RB (?)
29 * 5 - GP0_0 (ST5?) Changed before acessing AL (affects banking?).
30 * 6 - GP0_1 (ST6?) Cleared before acessing AL (affects banking?). Set after.
31 * 7 - IE (?) Not used by SVP code (never set, but preserved)?
32 * 8 - OP (?) Not used by SVP code (only cleared)?
33 * 9 - MACS (?) Not used by SVP code (only cleared)? (e: "mac shift")
34 * a - GPI_0 Interrupt 0 enable/status?
35 * b - GPI_1 Interrupt 1 enable/status?
36 * c - L L flag. Carry?
37 * d - Z Zero flag.
38 * e - OV Overflow flag.
39 * f - N Negative flag.
40 * seen directly changing code sequences:
41 * ldi ST, 0 ld A, ST ld A, ST ld A, ST ldi st, 20h
42 * ldi ST, 60h ori A, 60h and A, E8h and A, E8h
43 * ld ST, A ld ST, A ori 3
44 * ld ST, A
45 *
46 * 5. "STACK"
47 * size: 16
48 * desc: hw stack of 6 levels (according to datasheet)
49 *
50 * 6. "PC"
51 * size: 16
52 * desc: Program counter.
53 *
54 * 7. "P"
55 * size: 32
56 * desc: multiply result register. Updated after mp* instructions,
57 * or writes to X or Y (P = X * Y * 2) ??
58 * probably affected by MACS bit in ST.
59 *
60 * 8. "PM0" (PM from PMAR name from Tasco's docs)
61 * size: 16?
62 * desc: Programmable Memory access register.
63 * On reset, or when one (both?) GP0 bits are clear,
64 * acts as some additional status reg?
65 *
66 * 9. "PM1"
67 * size: 16?
68 * desc: Programmable Memory access register.
69 * This reg. is only used as PMAR.
70 *
71 * 10. "PM2"
72 * size: 16?
73 * desc: Programmable Memory access register.
74 * This reg. is only used as PMAR.
75 *
76 * 11. "XST"
77 * size: 16?
78 * desc: eXternal STate. Mapped to a15000 at 68k side.
79 * Can be programmed as PMAR? (only seen in test mode code)
80 *
81 * 12. "PM4"
82 * size: 16?
83 * desc: Programmable Memory access register.
84 * This reg. is only used as PMAR. The most used PMAR by VR.
85 *
86 * 13. (unused by VR)
87 *
88 * 14. "PMC" (PMC from PMAC name from Tasco's docs)
89 * size: 32?
90 * desc: Programmable Memory access Control. Set using 2 16bit writes,
91 * first address, then mode word. After setting PMAC, PMAR sould
92 * be accessed to program it.
93 *
94 * 15. "AL"
95 * size: 16
96 * desc: Accumulator Low. 16 least significant bits of accumulator (not 100% sure)
97 * (normally reading acc (ld X, A) you get 16 most significant bits).
98 *
99 *
100 * There are 8 8-bit pointer registers rX. r0-r3 (ri) point to RAM0, r4-r7 (rj) point to RAM1.
101 * They can be accessed directly, or 2 indirection levels can be used [ (r0), ((r0)) ],
102 * which work similar to * and ** operators in C.
103 *
104 * r0,r1,r2,r4,r5,r6 can be modified [ex: ldi r0, 5].
105 * 3 modifiers can be applied (optional):
106 * + : post-increment [ex: ld a, (r0+) ]
107 * - : post-decrement
108 * +!: same as '+' ???
109 *
110 * r3 and r7 are special and can not be changed (at least Samsung samples and SVP code never do).
111 * They are fixed to the start of their RAM banks. (They are probably changeable for ssp1605+,
112 * Samsung's old DSP page claims that).
113 * 1 of these 4 modifiers must be used (short form direct addressing?):
114 * |00: RAMx[0] [ex: (r3|00), 0] (based on sample code)
115 * |01: RAMx[1]
116 * |10: RAMx[2] ? maybe 10h? accortding to Div_c_dp.sc, 2
117 * |11: RAMx[3]
118 *
119 *
120 * Instruction notes
121 *
122 * mld (rj), (ri) [, b]
123 * operation: A = 0; P = (rj) * (ri)
124 * notes: based on IIR_4B.SC sample. flags? what is b???
125 * TODO: figure out if (rj) and (ri) get loaded in X and Y
126 *
127 * mpya (rj), (ri) [, b]
128 * name: multiply and add?
129 * operation: A += P; P = (rj) * (ri)
130 *
131 * mpys (rj), (ri), b
132 * name: multiply and subtract?
133 * notes: not used by VR code.
017512f2 134 *
135 *
136 * Assumptions in this code
137 * P is not directly writeable
f8ef8ff7 138 */
139
140#include "../../PicoInt.h"
141
017512f2 142#define u32 unsigned int
143
144// 0
145#define rX ssp->gr[SSP_X].h
146#define rY ssp->gr[SSP_Y].h
147#define rA ssp->gr[SSP_A].h
148#define rST ssp->gr[SSP_ST].h // 4
149#define rSTACK ssp->gr[SSP_STACK].h
150#define rPC ssp->gr[SSP_PC].h
151#define rP ssp->gr[SSP_P]
152#define rPM0 ssp->gr[SSP_PM0].h // 8
153#define rPM1 ssp->gr[SSP_PM1].h
154#define rPM2 ssp->gr[SSP_PM2].h
155#define rXST ssp->gr[SSP_XST].h
156#define rPM4 ssp->gr[SSP_PM4].h // 12
157// 13
158#define rPMC ssp->gr[SSP_PMC] // will keep addr in .h, mode in .l
f8ef8ff7 159#define rAL ssp->gr[SSP_A].l
160
161#define GET_PC() (PC - (unsigned short *)Pico.rom)
017512f2 162#define GET_PC_OFFS() ((unsigned int)PC - (unsigned int)Pico.rom)
163#define SET_PC(d) PC = (unsigned short *)Pico.rom + d
164
165#define REG_READ(r) (((r) <= 4) ? ssp->gr[r].h : read_handlers[r]())
166#define REG_WRITE(r,d) { \
167 int r1 = r; \
168 if (r1 > 4) write_handlers[r1](d); \
169 else if (r1 > 0) ssp->gr[r1].h = d; \
170}
171
172static ssp1601_t *ssp = NULL;
173static unsigned short *PC;
174static int g_cycles;
175
176// -----------------------------------------------------
177// register i/o handlers
178
179// 0-4, 13
180static u32 read_unknown(void)
181{
182 elprintf(EL_ANOMALY|EL_SVP, "ssp16: unknown read @ %04x", GET_PC_OFFS());
183 return 0;
184}
185
186static void write_unknown(u32 d)
187{
188 elprintf(EL_ANOMALY|EL_SVP, "ssp16: unknown write @ %04x", GET_PC_OFFS());
189}
190
191// 5
192static u32 read_STACK(void)
193{
194 u32 d = 0;
195 if (rSTACK < 6) {
196 d = ssp->stack[rSTACK];
197 rSTACK++;
198 } else
199 elprintf(EL_ANOMALY|EL_SVP, "ssp16: stack underflow! (%i) @ %04x", rSTACK, GET_PC_OFFS());
200 return d;
201}
202
203static void write_STACK(u32 d)
204{
205 if (rSTACK > 0) {
206 rSTACK--;
207 ssp->stack[rSTACK] = d;
208 } else
209 elprintf(EL_ANOMALY|EL_SVP, "ssp16: stack overflow! (%i) @ %04x", rSTACK, GET_PC_OFFS());
210}
211
212// 6
213static u32 read_PC(void)
214{
215 return GET_PC();
216}
217
218static void write_PC(u32 d)
219{
220 SET_PC(d);
221 g_cycles--;
222}
223
224// 7
225static u32 read_P(void)
226{
227 rP.v = (u32)rX * rY * 2;
228 return rP.h;
229}
230
231static u32 pm_io(int reg, int write, u32 d)
232{
233 if (ssp->emu_status & SSP_PMC_SET) {
234 elprintf(EL_SVP, "PM%i (%c) set to %08x @ %04x", reg, write ? 'w' : 'r', rPMC.v, GET_PC_OFFS());
235 ssp->pmac_read[write ? reg + 6 : reg] = rPMC.v;
236 ssp->emu_status &= ~SSP_PMC_SET;
237 return 0;
238 }
239
240 if (ssp->pmac_read[reg] != 0) {
241 elprintf(EL_SVP, "PM%i %c @ %04x", reg, write ? 'w' : 'r', GET_PC_OFFS());
242 // do something depending on mode
243 return 0;
244 }
245
246 return (u32)-1;
247}
248
249// 8
250static u32 read_PM0(void)
251{
252 u32 d = pm_io(0, 0, 0);
253 if (d != (u32)-1) return d;
254 elprintf(EL_SVP, "PM0 raw r %04x @ %04x", rPM0, GET_PC_OFFS());
255 return rPM0;
256}
257
258static void write_PM0(u32 d)
259{
260 u32 r = pm_io(0, 1, d);
261 if (r != (u32)-1) return;
262 elprintf(EL_SVP, "PM0 raw w %04x @ %04x", d, GET_PC_OFFS());
263 rPM0 = d;
264}
265
266// 9
267static u32 read_PM1(void)
268{
269 u32 d = pm_io(1, 0, 0);
270 if (d != (u32)-1) return d;
271 // can be removed?
272 elprintf(EL_SVP, "PM1 raw r %04x @ %04x", rPM1, GET_PC_OFFS());
273 return rPM0;
274}
275
276static void write_PM1(u32 d)
277{
278 u32 r = pm_io(1, 1, d);
279 if (r != (u32)-1) return;
280 // can be removed?
281 elprintf(EL_SVP, "PM1 raw w %04x @ %04x", d, GET_PC_OFFS());
282 rPM0 = d;
283}
284
285// 10
286static u32 read_PM2(void)
287{
288 u32 d = pm_io(2, 0, 0);
289 if (d != (u32)-1) return d;
290 // can be removed?
291 elprintf(EL_SVP, "PM2 raw r %04x @ %04x", rPM2, GET_PC_OFFS());
292 return rPM0;
293}
294
295static void write_PM2(u32 d)
296{
297 u32 r = pm_io(2, 1, d);
298 if (r != (u32)-1) return;
299 // can be removed?
300 elprintf(EL_SVP, "PM2 raw w %04x @ %04x", d, GET_PC_OFFS());
301 rPM0 = d;
302}
303
304// 11
305static u32 read_XST(void)
306{
307 // can be removed?
308 u32 d = pm_io(3, 0, 0);
309 if (d != (u32)-1) return d;
310
311 elprintf(EL_SVP, "XST raw r %04x @ %04x", rXST, GET_PC_OFFS());
312 return rPM0;
313}
f8ef8ff7 314
017512f2 315static void write_XST(u32 d)
f8ef8ff7 316{
017512f2 317 // can be removed?
318 u32 r = pm_io(3, 1, d);
319 if (r != (u32)-1) return;
320
321 elprintf(EL_SVP, "XST raw w %04x @ %04x", d, GET_PC_OFFS());
322 rPM0 = d;
323}
324
325// 12
326static u32 read_PM4(void)
327{
328 u32 d = pm_io(4, 0, 0);
329 if (d != (u32)-1) return d;
330 // can be removed?
331 elprintf(EL_SVP, "PM4 raw r %04x @ %04x", rPM4, GET_PC_OFFS());
332 return rPM0;
333}
334
335static void write_PM4(u32 d)
336{
337 u32 r = pm_io(4, 1, d);
338 if (r != (u32)-1) return;
339 // can be removed?
340 elprintf(EL_SVP, "PM4 raw w %04x @ %04x", d, GET_PC_OFFS());
341 rPM0 = d;
342}
343
344// 14
345static u32 read_PMC(void)
346{
347 if (ssp->emu_status & SSP_PMC_HAVE_ADDR) {
348 if (ssp->emu_status & SSP_PMC_SET)
349 elprintf(EL_ANOMALY|EL_SVP, "prev PMC not used @ %04x", GET_PC_OFFS());
350 ssp->emu_status |= SSP_PMC_SET;
351 return rPMC.l;
352 } else {
353 ssp->emu_status |= SSP_PMC_HAVE_ADDR;
354 return rPMC.h;
355 }
356}
357
358static void write_PMC(u32 d)
359{
360 if (ssp->emu_status & SSP_PMC_HAVE_ADDR) {
361 if (ssp->emu_status & SSP_PMC_SET)
362 elprintf(EL_ANOMALY|EL_SVP, "prev PMC not used @ %04x", GET_PC_OFFS());
363 ssp->emu_status |= SSP_PMC_SET;
364 rPMC.l = d;
365 } else {
366 ssp->emu_status |= SSP_PMC_HAVE_ADDR;
367 rPMC.h = d;
368 }
369}
370
371// 15
372static u32 read_AL(void)
373{
374 // TODO: figure out what's up with those blind reads..
375 return rAL;
376}
377
378static void write_AL(u32 d)
379{
380 rAL = d;
381}
382
383
384typedef u32 (*read_func_t)(void);
385typedef void (*write_func_t)(u32 d);
386
387static read_func_t read_handlers[16] =
388{
389 read_unknown, read_unknown, read_unknown, read_unknown, // -, X, Y, A
390 read_unknown, // 4 ST
391 read_STACK,
392 read_PC,
393 read_P,
394 read_PM0, // 8
395 read_PM1,
396 read_PM2,
397 read_XST,
398 read_PM4, // 12
399 read_unknown, // 13 gr13
400 read_PMC,
401 read_AL
402};
403
404static write_func_t write_handlers[16] =
405{
406 write_unknown, write_unknown, write_unknown, write_unknown, // -, X, Y, A
407 write_unknown, // 4 ST
408 write_STACK,
409 write_PC,
410 write_unknown, // 7 P
411 write_PM0, // 8
412 write_PM1,
413 write_PM2,
414 write_XST,
415 write_PM4, // 12
416 write_unknown, // 13 gr13
417 write_PMC,
418 write_AL
419};
420
421void ssp1601_reset(ssp1601_t *l_ssp)
422{
423 ssp = l_ssp;
f8ef8ff7 424 ssp->emu_status = 0;
017512f2 425 ssp->gr[SSP_GR0].v = 0xffff0000;
f8ef8ff7 426 rPC = 0x400;
017512f2 427 rSTACK = 6; // ? using descending stack
f8ef8ff7 428}
429
430
017512f2 431void ssp1601_run(int cycles)
f8ef8ff7 432{
f8ef8ff7 433 int op;
434
017512f2 435 SET_PC(rPC);
436 g_cycles = cycles;
f8ef8ff7 437
017512f2 438 while (g_cycles > 0)
f8ef8ff7 439 {
440 op = *PC;
441 switch (op >> 9)
442 {
443 // ld d, s
444 case 0:
f8ef8ff7 445 if (op == 0) break; // nop
017512f2 446 if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
447 // not sure. MAME claims that only hi word is transfered.
448 read_P(); // update P
449 ssp->gr[SSP_A].v = ssp->gr[SSP_P].v;
450 break;
f8ef8ff7 451 }
f8ef8ff7 452 {
017512f2 453 u32 d = REG_READ(op & 0x0f);
454 REG_WRITE((op & 0xf0) >> 4, d);
f8ef8ff7 455 }
017512f2 456 // flags?
f8ef8ff7 457 break;
f8ef8ff7 458
459 default:
017512f2 460 elprintf(EL_ANOMALY|EL_SVP, "ssp16: unhandled op %04x @ %04x", op, GET_PC_OFFS());
461 break;
f8ef8ff7 462 }
017512f2 463 g_cycles--;
f8ef8ff7 464 PC++;
465 }
466
017512f2 467 read_P(); // update P
f8ef8ff7 468 rPC = GET_PC();
017512f2 469
470 if (ssp->gr[SSP_GR0].v != 0xffff0000)
471 elprintf(EL_ANOMALY|EL_SVP, "ssp16: REG 0 corruption! %08x", ssp->gr[SSP_GR0].v);
f8ef8ff7 472}
473