Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/chip/necdsp/necdsp.cpp
2 views
1
#include <snes/snes.hpp>
2
3
#define NECDSP_CPP
4
namespace SNES {
5
6
#include "memory.cpp"
7
#include "disassembler.cpp"
8
#include "serialization.cpp"
9
NECDSP necdsp;
10
11
//zero 01-sep-2014 - dont clobber these when reconstructing!
12
unsigned NECDSP::frequency;
13
uint24 NECDSP::programROM[16384];
14
uint16 NECDSP::dataROM[2048];
15
unsigned NECDSP::programROMSize;
16
unsigned NECDSP::dataROMSize;
17
18
void NECDSP::Enter() { necdsp.enter(); }
19
20
void NECDSP::enter() {
21
while(true) {
22
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
23
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
24
}
25
26
uint24 opcode = programROM[regs.pc++];
27
switch(opcode >> 22) {
28
case 0: exec_op(opcode); break;
29
case 1: exec_rt(opcode); break;
30
case 2: exec_jp(opcode); break;
31
case 3: exec_ld(opcode); break;
32
}
33
34
int32 result = (int32)regs.k * regs.l; //sign + 30-bit result
35
regs.m = result >> 15; //store sign + top 15-bits
36
regs.n = result << 1; //store low 15-bits + zero
37
38
step(1);
39
synchronize_cpu();
40
}
41
}
42
43
void NECDSP::exec_op(uint24 opcode) {
44
uint2 pselect = opcode >> 20; //P select
45
uint4 alu = opcode >> 16; //ALU operation mode
46
uint1 asl = opcode >> 15; //accumulator select
47
uint2 dpl = opcode >> 13; //DP low modify
48
uint4 dphm = opcode >> 9; //DP high XOR modify
49
uint1 rpdcr = opcode >> 8; //RP decrement
50
uint4 src = opcode >> 4; //move source
51
uint4 dst = opcode >> 0; //move destination
52
53
uint16 idb;
54
switch(src) {
55
case 0: idb = regs.trb; break;
56
case 1: idb = regs.a; break;
57
case 2: idb = regs.b; break;
58
case 3: idb = regs.tr; break;
59
case 4: idb = regs.dp; break;
60
case 5: idb = regs.rp; break;
61
case 6: idb = dataROM[regs.rp]; break;
62
case 7: idb = 0x8000 - regs.flaga.s1; break;
63
case 8: idb = regs.dr; regs.sr.rqm = 1; break;
64
case 9: idb = regs.dr; break;
65
case 10: idb = regs.sr; break;
66
case 11: idb = regs.si; break; //MSB
67
case 12: idb = regs.si; break; //LSB
68
case 13: idb = regs.k; break;
69
case 14: idb = regs.l; break;
70
case 15: idb = dataRAM[regs.dp]; break;
71
}
72
73
if(alu) {
74
uint16 p, q, r;
75
Flag flag;
76
bool c;
77
78
switch(pselect) {
79
case 0: p = dataRAM[regs.dp]; break;
80
case 1: p = idb; break;
81
case 2: p = regs.m; break;
82
case 3: p = regs.n; break;
83
}
84
85
switch(asl) {
86
case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break;
87
case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break;
88
}
89
90
switch(alu) {
91
case 1: r = q | p; break; //OR
92
case 2: r = q & p; break; //AND
93
case 3: r = q ^ p; break; //XOR
94
case 4: r = q - p; break; //SUB
95
case 5: r = q + p; break; //ADD
96
case 6: r = q - p - c; break; //SBB
97
case 7: r = q + p + c; break; //ADC
98
case 8: r = q - 1; p = 1; break; //DEC
99
case 9: r = q + 1; p = 1; break; //INC
100
case 10: r = ~q; break; //CMP
101
case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR)
102
case 12: r = (q << 1) | c; break; //SHL1 (ROL)
103
case 13: r = (q << 2) | 3; break; //SHL2
104
case 14: r = (q << 4) | 15; break; //SHL4
105
case 15: r = (q << 8) | (q >> 8); break; //XCHG
106
}
107
108
flag.s0 = (r & 0x8000);
109
flag.z = (r == 0);
110
111
switch(alu) {
112
case 1: case 2: case 3: case 10: case 13: case 14: case 15: {
113
flag.c = 0;
114
flag.ov0 = 0;
115
flag.ov1 = 0;
116
break;
117
}
118
case 4: case 5: case 6: case 7: case 8: case 9: {
119
if(alu & 1) {
120
//addition
121
flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000;
122
flag.c = (r < q);
123
} else {
124
//subtraction
125
flag.ov0 = (q ^ r) & (q ^ p) & 0x8000;
126
flag.c = (r > q);
127
}
128
if(flag.ov0) {
129
flag.s1 = flag.ov1 ^ !(r & 0x8000);
130
flag.ov1 = !flag.ov1;
131
}
132
break;
133
}
134
case 11: {
135
flag.c = q & 1;
136
flag.ov0 = 0;
137
flag.ov1 = 0;
138
break;
139
}
140
case 12: {
141
flag.c = q >> 15;
142
flag.ov0 = 0;
143
flag.ov1 = 0;
144
break;
145
}
146
}
147
148
switch(asl) {
149
case 0: regs.a = r; regs.flaga = flag; break;
150
case 1: regs.b = r; regs.flagb = flag; break;
151
}
152
}
153
154
exec_ld((idb << 6) + dst);
155
156
switch(dpl) {
157
case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
158
case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC
159
case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR
160
}
161
162
regs.dp ^= dphm << 4;
163
164
if(rpdcr) regs.rp--;
165
}
166
167
void NECDSP::exec_rt(uint24 opcode) {
168
exec_op(opcode);
169
regs.pc = regs.stack[--regs.sp];
170
}
171
172
void NECDSP::exec_jp(uint24 opcode) {
173
uint9 brch = opcode >> 13; //branch
174
uint11 na = opcode >> 2; //next address
175
uint2 bank = opcode >> 0; //bank address
176
177
uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
178
179
switch(brch) {
180
case 0x000: regs.pc = regs.so; return; //JMPSO
181
182
case 0x080: if(regs.flaga.c == 0) regs.pc = jp; return; //JNCA
183
case 0x082: if(regs.flaga.c == 1) regs.pc = jp; return; //JCA
184
case 0x084: if(regs.flagb.c == 0) regs.pc = jp; return; //JNCB
185
case 0x086: if(regs.flagb.c == 1) regs.pc = jp; return; //JCB
186
187
case 0x088: if(regs.flaga.z == 0) regs.pc = jp; return; //JNZA
188
case 0x08a: if(regs.flaga.z == 1) regs.pc = jp; return; //JZA
189
case 0x08c: if(regs.flagb.z == 0) regs.pc = jp; return; //JNZB
190
case 0x08e: if(regs.flagb.z == 1) regs.pc = jp; return; //JZB
191
192
case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jp; return; //JNOVA0
193
case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jp; return; //JOVA0
194
case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jp; return; //JNOVB0
195
case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jp; return; //JOVB0
196
197
case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jp; return; //JNOVA1
198
case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jp; return; //JOVA1
199
case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jp; return; //JNOVB1
200
case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jp; return; //JOVB1
201
202
case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jp; return; //JNSA0
203
case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jp; return; //JSA0
204
case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jp; return; //JNSB0
205
case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jp; return; //JSB0
206
207
case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jp; return; //JNSA1
208
case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jp; return; //JSA1
209
case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jp; return; //JNSB1
210
case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jp; return; //JSB1
211
212
case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jp; return; //JDPL0
213
case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jp; return; //JDPLN0
214
case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jp; return; //JDPLF
215
case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jp; return; //JDPLNF
216
217
case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jp; return; //JNRQM
218
case 0x0be: if(regs.sr.rqm == 1) regs.pc = jp; return; //JRQM
219
220
case 0x100: regs.pc = jp & ~0x2000; return; //LJMP
221
case 0x101: regs.pc = jp | 0x2000; return; //HJMP
222
223
case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = jp & ~0x2000; return; //LCALL
224
case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = jp | 0x2000; return; //HCALL
225
}
226
}
227
228
void NECDSP::exec_ld(uint24 opcode) {
229
uint16 id = opcode >> 6; //immediate data
230
uint4 dst = opcode >> 0; //destination
231
232
switch(dst) {
233
case 0: break;
234
case 1: regs.a = id; break;
235
case 2: regs.b = id; break;
236
case 3: regs.tr = id; break;
237
case 4: regs.dp = id; break;
238
case 5: regs.rp = id; break;
239
case 6: regs.dr = id; regs.sr.rqm = 1; break;
240
case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); break;
241
case 8: regs.so = id; break; //LSB
242
case 9: regs.so = id; break; //MSB
243
case 10: regs.k = id; break;
244
case 11: regs.k = id; regs.l = dataROM[regs.rp]; break;
245
case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break;
246
case 13: regs.l = id; break;
247
case 14: regs.trb = id; break;
248
case 15: dataRAM[regs.dp] = id; break;
249
}
250
}
251
252
void NECDSP::init() {
253
}
254
255
void NECDSP::load() {
256
if(revision == Revision::uPD96050) {
257
cartridge.nvram.append({ "upd96050.ram", (uint8_t*)dataRAM, 4096 });
258
}
259
}
260
261
void NECDSP::unload() {
262
}
263
264
void NECDSP::power() {
265
if(revision == Revision::uPD7725) {
266
regs.pc.bits(11);
267
regs.rp.bits(10);
268
regs.dp.bits( 8);
269
}
270
271
if(revision == Revision::uPD96050) {
272
regs.pc.bits(14);
273
regs.rp.bits(11);
274
regs.dp.bits(11);
275
}
276
}
277
278
void NECDSP::reset() {
279
create(NECDSP::Enter, frequency);
280
281
for(unsigned n = 0; n < 16; n++) regs.stack[n] = 0x0000;
282
regs.pc = 0x0000;
283
regs.rp = 0x0000;
284
regs.dp = 0x0000;
285
regs.sp = 0x0;
286
regs.k = 0x0000;
287
regs.l = 0x0000;
288
regs.m = 0x0000;
289
regs.n = 0x0000;
290
regs.a = 0x0000;
291
regs.b = 0x0000;
292
regs.flaga = 0x00;
293
regs.flagb = 0x00;
294
regs.tr = 0x0000;
295
regs.trb = 0x0000;
296
regs.sr = 0x0000;
297
regs.dr = 0x0000;
298
regs.si = 0x0000;
299
regs.so = 0x0000;
300
}
301
302
NECDSP::NECDSP() {
303
}
304
305
NECDSP::~NECDSP() {
306
}
307
308
}
309
310