Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/chip/armdsp/opcodes.cpp
2 views
1
#ifdef ARMDSP_CPP
2
3
bool ArmDSP::condition() {
4
uint4 condition = instruction >> 28;
5
switch(condition) {
6
case 0: return cpsr.z == 1; //EQ (equal)
7
case 1: return cpsr.z == 0; //NE (not equal)
8
case 2: return cpsr.c == 1; //CS (carry set)
9
case 3: return cpsr.c == 0; //CC (carry clear)
10
case 4: return cpsr.n == 1; //MI (negative)
11
case 5: return cpsr.n == 0; //PL (positive)
12
case 6: return cpsr.v == 1; //VS (overflow)
13
case 7: return cpsr.v == 0; //VC (no overflow)
14
case 8: return cpsr.c == 1 && cpsr.z == 0; //HI (unsigned higher)
15
case 9: return cpsr.c == 0 || cpsr.z == 1; //LS (unsigned lower or same)
16
case 10: return cpsr.n == cpsr.v; //GE (signed greater than or equal)
17
case 11: return cpsr.n != cpsr.v; //LT (signed less than)
18
case 12: return cpsr.z == 0 && cpsr.n == cpsr.v; //GT (signed greater than)
19
case 13: return cpsr.z == 1 || cpsr.n != cpsr.v; //LE (signed less than or equal)
20
case 14: return true; //AL (always)
21
case 15: return false; //NV (never)
22
}
23
}
24
25
//rd = target
26
//rn = source
27
//rm = modifier
28
//ri = original target
29
//ro = modified target
30
void ArmDSP::opcode(uint32 rm) {
31
uint4 opcode = instruction >> 21;
32
uint1 save = instruction >> 20;
33
uint4 n = instruction >> 16;
34
uint4 d = instruction >> 12;
35
36
uint32 rn = r[n];
37
38
//comparison opcodes always update flags (debug test)
39
//this can be removed later: s=0 opcode=8-11 is invalid
40
if(opcode >= 8 && opcode <= 11) assert(save == 1);
41
42
auto test = [&](uint32 result) {
43
if(save) {
44
cpsr.n = result >> 31;
45
cpsr.z = result == 0;
46
cpsr.c = shiftercarry;
47
}
48
return result;
49
};
50
51
auto math = [&](uint32 source, uint32 modify, bool carry) {
52
uint32 result = source + modify + carry;
53
if(save) {
54
uint32 overflow = ~(source ^ modify) & (source ^ result);
55
cpsr.n = result >> 31;
56
cpsr.z = result == 0;
57
cpsr.c = (1u << 31) & (overflow ^ source ^ modify ^ result);
58
cpsr.v = (1u << 31) & (overflow);
59
}
60
return result;
61
};
62
63
switch(opcode) {
64
case 0: r[d] = test(rn & rm); break; //AND
65
case 1: r[d] = test(rn ^ rm); break; //EOR
66
case 2: r[d] = math(rn, ~rm, 1); break; //SUB
67
case 3: r[d] = math(rm, ~rn, 1); break; //RSB
68
case 4: r[d] = math(rn, rm, 0); break; //ADD
69
case 5: r[d] = math(rn, rm, cpsr.c); break; //ADC
70
case 6: r[d] = math(rn, ~rm, cpsr.c); break; //SBC
71
case 7: r[d] = math(rm, ~rn, cpsr.c); break; //RSC
72
case 8: test(rn & rm); break; //TST
73
case 9: test(rn ^ rm); break; //TEQ
74
case 10: math(rn, ~rm, 1); break; //CMP
75
case 11: math(rn, rm, 0); break; //CMN
76
case 12: r[d] = test(rn | rm); break; //ORR
77
case 13: r[d] = test(rm); break; //MOV
78
case 14: r[d] = test(rn &~rm); break; //BIC
79
case 15: r[d] = test(~rm); break; //MVN
80
}
81
}
82
83
//logical shift left
84
void ArmDSP::lsl(bool &c, uint32 &rm, uint32 rs) {
85
while(rs--) {
86
c = rm >> 31;
87
rm <<= 1;
88
}
89
}
90
91
//logical shift right
92
void ArmDSP::lsr(bool &c, uint32 &rm, uint32 rs) {
93
while(rs--) {
94
c = rm & 1;
95
rm >>= 1;
96
}
97
}
98
99
//arithmetic shift right
100
void ArmDSP::asr(bool &c, uint32 &rm, uint32 rs) {
101
while(rs--) {
102
c = rm & 1;
103
rm = (int32)rm >> 1;
104
}
105
}
106
107
//rotate right
108
void ArmDSP::ror(bool &c, uint32 &rm, uint32 rs) {
109
while(rs--) {
110
c = rm & 1;
111
rm = (rm << 31) | (rm >> 1);
112
}
113
}
114
115
//rotate right with extend
116
void ArmDSP::rrx(bool &c, uint32 &rm) {
117
bool carry = c;
118
c = rm & 1;
119
rm = (carry << 31) | (rm >> 1);
120
}
121
122
//(mul,mla){condition}{s} rd,rm,rs,rn
123
//cccc 0000 00as dddd nnnn ssss 1001 mmmm
124
//c = condition
125
//a = accumulate
126
//s = save flags
127
//d = rd
128
//n = rn
129
//s = rs
130
//n = rm
131
void ArmDSP::op_multiply() {
132
uint1 accumulate = instruction >> 21;
133
uint1 save = instruction >> 20;
134
uint4 d = instruction >> 16;
135
uint4 n = instruction >> 12;
136
uint4 s = instruction >> 8;
137
uint4 m = instruction >> 0;
138
139
//Booth's algorithm: two bit steps
140
uint32 temp = r[s];
141
while(temp) {
142
temp >>= 2;
143
tick();
144
}
145
r[d] = r[m] * r[s];
146
147
if(accumulate) {
148
tick();
149
r[d] += r[n];
150
}
151
152
if(save) {
153
cpsr.n = r[d] >> 31;
154
cpsr.z = r[d] == 0;
155
cpsr.c = 0; //undefined
156
}
157
}
158
159
//mrs{condition} rd,(c,s)psr
160
//cccc 0001 0r00 ++++ dddd ---- 0000 ----
161
//c = condition
162
//r = SPSR (0 = CPSR)
163
//d = rd
164
void ArmDSP::op_move_to_register_from_status_register() {
165
uint1 source = instruction >> 22;
166
uint4 d = instruction >> 12;
167
168
r[d] = source ? spsr : cpsr;
169
}
170
171
//msr{condition} (c,s)psr:{fields},rm
172
//cccc 0001 0r10 ffff ++++ ---- 0000 mmmm
173
//c = condition
174
//r = SPSR (0 = CPSR)
175
//f = field mask
176
//m = rm
177
void ArmDSP::op_move_to_status_register_from_register() {
178
uint1 source = instruction >> 22;
179
uint4 field = instruction >> 16;
180
uint4 m = instruction;
181
182
PSR &psr = source ? spsr : cpsr;
183
if(field & 1) psr.setc(r[m]);
184
if(field & 2) psr.setx(r[m]);
185
if(field & 4) psr.sets(r[m]);
186
if(field & 8) psr.setf(r[m]);
187
}
188
189
//{opcode}{condition}{s} rd,rm {shift} #immediate
190
//{opcode}{condition} rn,rm {shift} #immediate
191
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
192
//cccc 000o ooos nnnn dddd llll lss0 mmmm
193
//c = condition
194
//o = opcode
195
//s = save flags
196
//n = rn
197
//d = rd
198
//l = shift immmediate
199
//s = shift
200
//m = rm
201
void ArmDSP::op_data_immediate_shift() {
202
uint1 save = instruction >> 20;
203
uint5 shift = instruction >> 7;
204
uint2 mode = instruction >> 5;
205
uint4 m = instruction;
206
207
uint32 rs = shift;
208
uint32 rm = r[m];
209
bool c = cpsr.c;
210
211
if(mode == 0) lsl(c, rm, rs);
212
if(mode == 1) lsr(c, rm, rs ? rs : 32);
213
if(mode == 2) asr(c, rm, rs ? rs : 32);
214
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
215
216
shiftercarry = c;
217
opcode(rm);
218
}
219
220
//{opcode}{condition}{s} rd,rm {shift} rs
221
//{opcode}{condition} rn,rm {shift} rs
222
//{opcode}{condition}{s} rd,rn,rm {shift} rs
223
//cccc 000o ooos nnnn dddd ssss 0ss1 mmmm
224
//c = condition
225
//o = opcode
226
//s = save flags
227
//n = rn
228
//d = rd
229
//s = rs
230
//s = shift
231
//m = rm
232
void ArmDSP::op_data_register_shift() {
233
uint1 save = instruction >> 20;
234
uint4 s = instruction >> 8;
235
uint2 mode = instruction >> 5;
236
uint4 m = instruction >> 0;
237
238
uint8 rs = r[s];
239
uint32 rm = r[m];
240
bool c = cpsr.c;
241
242
if(mode == 0) lsl(c, rm, rs < 33 ? rs : 33);
243
if(mode == 1) lsr(c, rm, rs < 33 ? rs : 33);
244
if(mode == 2) asr(c, rm, rs < 32 ? rs : 32);
245
if(mode == 3 && rs) ror(c, rm, rs & 31 == 0 ? 32 : rs & 31);
246
247
shiftercarry = c;
248
opcode(rm);
249
}
250
251
//{opcode}{condition}{s} rd,#immediate
252
//{opcode}{condition} rn,#immediate
253
//{opcode}{condition}{s} rd,rn,#immediate
254
//cccc 001o ooos nnnn dddd llll iiii iiii
255
//c = condition
256
//o = opcode
257
//s = save flags
258
//n = rn
259
//d = rd
260
//l = shift immediate
261
//i = immediate
262
void ArmDSP::op_data_immediate() {
263
uint1 save = instruction >> 20;
264
uint4 shift = instruction >> 8;
265
uint8 immediate = instruction;
266
267
uint32 rs = shift << 1;
268
uint32 rm = (immediate >> rs) | (immediate << (32 - rs));
269
if(rs) shiftercarry = immediate >> 31;
270
271
opcode(rm);
272
}
273
274
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
275
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
276
//cccc 010p ubwl nnnn dddd iiii iiii iiii
277
//c = condition
278
//p = pre (0 = post-indexed addressing)
279
//u = up (add/sub offset to base)
280
//b = byte (1 = 32-bit)
281
//w = writeback
282
//l = load (0 = save)
283
//n = rn
284
//d = rd
285
//i = immediate
286
void ArmDSP::op_move_immediate_offset() {
287
uint1 p = instruction >> 24;
288
uint1 u = instruction >> 23;
289
uint1 b = instruction >> 22;
290
uint1 w = instruction >> 21;
291
uint1 l = instruction >> 20;
292
uint4 n = instruction >> 16;
293
uint4 d = instruction >> 12;
294
uint12 rm = instruction;
295
296
uint32 rn = r[n];
297
auto &rd = r[d];
298
299
if(p == 1) rn = u ? rn + rm : rn - rm;
300
if(l) rd = b ? bus_readbyte(rn) : bus_readword(rn);
301
else b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);
302
if(p == 0) rn = u ? rn + rm : rn - rm;
303
304
if(p == 0 || w == 1) r[n] = rn;
305
}
306
307
//(ldr)(str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
308
//(ldr)(str){condition}{b} rd,[rn],rm {mode} #immediate
309
//cccc 011p ubwl nnnn dddd llll lss0 mmmm
310
//c = condition
311
//p = pre (0 = post-indexed addressing)
312
//u = up
313
//b = byte (1 = 32-bit)
314
//w = writeback
315
//l = load (0 = save)
316
//n = rn
317
//d = rd
318
//l = shift immediate
319
//s = shift mode
320
//m = rm
321
void ArmDSP::op_move_register_offset() {
322
uint1 p = instruction >> 24;
323
uint1 u = instruction >> 23;
324
uint1 b = instruction >> 22;
325
uint1 w = instruction >> 21;
326
uint1 l = instruction >> 20;
327
uint4 n = instruction >> 16;
328
uint4 d = instruction >> 12;
329
uint5 immediate = instruction >> 7;
330
uint2 mode = instruction >> 5;
331
uint4 m = instruction;
332
333
uint32 rn = r[n];
334
auto &rd = r[d];
335
uint32 rs = immediate;
336
uint32 rm = r[m];
337
bool c = cpsr.c;
338
339
if(mode == 0) lsl(c, rm, rs);
340
if(mode == 1) lsr(c, rm, rs ? rs : 32);
341
if(mode == 2) asr(c, rm, rs ? rs : 32);
342
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
343
344
if(p == 1) rn = u ? rn + rm : rn - rm;
345
if(l) rd = b ? bus_readbyte(rn) : bus_readword(rn);
346
else b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);
347
if(p == 0) rn = u ? rn + rm : rn - rm;
348
349
if(p == 0 || w == 1) r[n] = rn;
350
}
351
352
//(ldm,stm){condition}{mode} rn{!},{r...}
353
//cccc 100p uswl nnnn llll llll llll llll
354
//c = condition
355
//p = pre (0 = post-indexed addressing)
356
//u = up (add/sub offset to base)
357
//s = ???
358
//w = writeback
359
//l = load (0 = save)
360
//n = rn
361
//l = register list
362
void ArmDSP::op_move_multiple() {
363
uint1 p = instruction >> 24;
364
uint1 u = instruction >> 23;
365
uint1 s = instruction >> 22;
366
uint1 w = instruction >> 21;
367
uint1 l = instruction >> 20;
368
uint4 n = instruction >> 16;
369
uint16 list = instruction;
370
371
uint32 rn = r[n];
372
if(p == 0 && u == 1) rn = rn + 0; //IA
373
if(p == 1 && u == 1) rn = rn + 4; //IB
374
if(p == 1 && u == 0) rn = rn - bit::count(list) * 4 + 0; //DB
375
if(p == 0 && u == 0) rn = rn - bit::count(list) * 4 + 4; //DA
376
377
for(unsigned n = 0; n < 16; n++) {
378
if(list & (1 << n)) {
379
if(l) r[n] = bus_readword(rn);
380
else bus_writeword(rn, r[n]);
381
rn += 4;
382
}
383
}
384
385
if(w) {
386
if(u == 1) r[n] = r[n] + bit::count(list) * 4; //IA, IB
387
if(u == 0) r[n] = r[n] - bit::count(list) * 4; //DA, DB
388
}
389
}
390
391
//b{l}{condition} address
392
//cccc 101l dddd dddd dddd dddd dddd dddd
393
//c = condition
394
//l = link
395
//d = displacement (24-bit signed)
396
void ArmDSP::op_branch() {
397
uint1 l = instruction >> 24;
398
int24 displacement = instruction;
399
400
if(l) r[14] = r[15] - 4;
401
r[15] += displacement * 4;
402
}
403
404
#endif
405
406