more wip SVP code
[picodrive.git] / Pico / carthw / svp / ssp16.c
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.
134  */
135
136 #include "../../PicoInt.h"
137
138 #define rX     ssp->gr[SSP_X].l
139 #define rY     ssp->gr[SSP_Y].l
140 #define rA     ssp->gr[SSP_A]           // 4
141 #define rST    ssp->gr[SSP_ST].l
142 #define rSTACK ssp->gr[SSP_STACK].l
143 #define rPC    ssp->gr[SSP_PC].l
144 #define rP     ssp->gr[SSP_P]           // 8
145 #define rPM0   ssp->gr[SSP_PM0].l
146 #define rPM1   ssp->gr[SSP_PM1].l
147 #define rPM2   ssp->gr[SSP_PM2].l
148 #define rXST   ssp->gr[SSP_XST].l       // 12
149 #define rPM4   ssp->gr[SSP_PM4].l       // 14
150 #define rPMC   ssp->gr[SSP_PMC].l
151 #define rAL    ssp->gr[SSP_A].l
152
153 #define GET_PC() (PC - (unsigned short *)Pico.rom)
154 #define SET_PC() PC = (unsigned short *)Pico.rom + rPC
155
156 void ssp1601_reset(ssp1601_t *ssp)
157 {
158         ssp->emu_status = 0;
159         ssp->gr[SSP_GR0].v = 0xffff;
160         rPC = 0x400;
161         rSTACK = 5; // ?
162 }
163
164
165 void ssp1601_run(ssp1601_t *ssp, int cycles)
166 {
167         unsigned short *PC;
168         int op;
169
170         SET_PC();
171
172         while (cycles > 0)
173         {
174                 op = *PC;
175                 switch (op >> 9)
176                 {
177                         // ld d, s
178                         case 0:
179                         {
180                                 int s, d, opdata = 0;
181                                 if (op == 0) break; // nop
182                                 s =  op & 0x0f;
183                                 d = (op & 0xf0) >> 4;
184                                 if (s == SSP_A || s == SSP_P) opdata |= 1; // src is 32bit
185                                 if (d == SSP_A || d == SSP_P) opdata |= 2; // dst is 32bit
186                                 if (s == SSP_STACK) opdata |= 4; // src is stack
187                                 if (d == SSP_STACK) opdata |= 8; // dst is stack
188                                 switch (opdata)
189                                 {
190                                         case 0x0: ssp->gr[d].l = ssp->gr[s].l; break; // 16 <- 16
191                                         case 0x1: ssp->gr[d].l = ssp->gr[s].h; break; // 16 <- 32
192                                         case 0x2: ssp->gr[d].h = ssp->gr[s].l; break; // 32 <- 16
193                                                   // TODO: MAME claims that only hi word is transfered. Go figure.
194                                         case 0x3: ssp->gr[d].v = ssp->gr[s].v; break; // 32 <- 32
195                                         case 0x4: ; // TODO
196                                 }
197                                 if (d == SSP_PC)
198                                 {
199                                         SET_PC();
200                                         cycles--;
201                                 }
202                                 break;
203                         }
204
205                         default:
206                         elprintf(0xffff, "ssp: unhandled op %04x @ %04x", op, GET_PC()<<1);
207                         break;
208                 }
209                 cycles--;
210                 PC++;
211         }
212
213         rPC = GET_PC();
214 }
215