1 // Copyright 2009 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Core/DSP/Interpreter/DSPIntExtOps.h"
6
7 #include "Core/DSP/DSPMemoryMap.h"
8 #include "Core/DSP/DSPTables.h"
9 #include "Core/DSP/Interpreter/DSPIntUtil.h"
10
11 // not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS
12 // dspjit64 without it)
13 //#define PRECISE_BACKLOG
14
15 // Extended opcodes do not exist on their own. These opcodes can only be
16 // attached to opcodes that allow extending (8 (or 7) lower bits of opcode not used by
17 // opcode). Extended opcodes do not modify program counter $pc register.
18
19 // Most of the suffixes increment or decrement one or more addressing registers
20 // (the first four, ARx). The increment/decrement is either 1, or the
21 // corresponding "index" register (the second four, IXx). The addressing
22 // registers will wrap in odd ways, dictated by the corresponding wrapping
23 // register, WR0-3.
24
25 namespace DSP
26 {
WriteToBackLog(int i,int idx,u16 value)27 static void WriteToBackLog(int i, int idx, u16 value)
28 {
29 writeBackLog[i] = value;
30 writeBackLogIdx[i] = idx;
31 }
32
33 namespace Interpreter::Ext
34 {
IsSameMemArea(u16 a,u16 b)35 static bool IsSameMemArea(u16 a, u16 b)
36 {
37 // LM: tested on Wii
38 return (a >> 10) == (b >> 10);
39 }
40
41 // DR $arR
42 // xxxx xxxx 0000 01rr
43 // Decrement addressing register $arR.
dr(const UDSPInstruction opc)44 void dr(const UDSPInstruction opc)
45 {
46 WriteToBackLog(0, opc & 0x3, dsp_decrement_addr_reg(opc & 0x3));
47 }
48
49 // IR $arR
50 // xxxx xxxx 0000 10rr
51 // Increment addressing register $arR.
ir(const UDSPInstruction opc)52 void ir(const UDSPInstruction opc)
53 {
54 WriteToBackLog(0, opc & 0x3, dsp_increment_addr_reg(opc & 0x3));
55 }
56
57 // NR $arR
58 // xxxx xxxx 0000 11rr
59 // Add corresponding indexing register $ixR to addressing register $arR.
nr(const UDSPInstruction opc)60 void nr(const UDSPInstruction opc)
61 {
62 u8 reg = opc & 0x3;
63
64 WriteToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]));
65 }
66
67 // MV $axD.D, $acS.S
68 // xxxx xxxx 0001 ddss
69 // Move value of $acS.S to the $axD.D.
mv(const UDSPInstruction opc)70 void mv(const UDSPInstruction opc)
71 {
72 u8 sreg = (opc & 0x3) + DSP_REG_ACL0;
73 u8 dreg = ((opc >> 2) & 0x3);
74
75 switch (sreg)
76 {
77 case DSP_REG_ACL0:
78 case DSP_REG_ACL1:
79 WriteToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
80 break;
81 case DSP_REG_ACM0:
82 case DSP_REG_ACM1:
83 WriteToBackLog(0, dreg + DSP_REG_AXL0, dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
84 break;
85 }
86 }
87
88 // S @$arD, $acS.S
89 // xxxx xxxx 001s s0dd
90 // Store value of $acS.S in the memory pointed by register $arD.
91 // Post increment register $arD.
s(const UDSPInstruction opc)92 void s(const UDSPInstruction opc)
93 {
94 u8 dreg = opc & 0x3;
95 u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
96
97 switch (sreg)
98 {
99 case DSP_REG_ACL0:
100 case DSP_REG_ACL1:
101 dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
102 break;
103 case DSP_REG_ACM0:
104 case DSP_REG_ACM1:
105 dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
106 break;
107 }
108 WriteToBackLog(0, dreg, dsp_increment_addr_reg(dreg));
109 }
110
111 // SN @$arD, $acS.S
112 // xxxx xxxx 001s s1dd
113 // Store value of register $acS.S in the memory pointed by register $arD.
114 // Add indexing register $ixD to register $arD.
sn(const UDSPInstruction opc)115 void sn(const UDSPInstruction opc)
116 {
117 u8 dreg = opc & 0x3;
118 u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
119
120 switch (sreg)
121 {
122 case DSP_REG_ACL0:
123 case DSP_REG_ACL1:
124 dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
125 break;
126 case DSP_REG_ACM0:
127 case DSP_REG_ACM1:
128 dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
129 break;
130 }
131 WriteToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]));
132 }
133
134 // L $axD.D, @$arS
135 // xxxx xxxx 01dd d0ss
136 // Load $axD.D/$acD.D with value from memory pointed by register $arS.
137 // Post increment register $arS.
l(const UDSPInstruction opc)138 void l(const UDSPInstruction opc)
139 {
140 u8 sreg = opc & 0x3;
141 u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
142
143 if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT))
144 {
145 u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]);
146 WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000);
147 WriteToBackLog(1, dreg, val);
148 WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
149 WriteToBackLog(3, sreg, dsp_increment_addr_reg(sreg));
150 }
151 else
152 {
153 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg]));
154 WriteToBackLog(1, sreg, dsp_increment_addr_reg(sreg));
155 }
156 }
157
158 // LN $axD.D, @$arS
159 // xxxx xxxx 01dd d0ss
160 // Load $axD.D/$acD.D with value from memory pointed by register $arS.
161 // Add indexing register $ixS to register $arS.
ln(const UDSPInstruction opc)162 void ln(const UDSPInstruction opc)
163 {
164 u8 sreg = opc & 0x3;
165 u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
166
167 if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT))
168 {
169 u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]);
170 WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000);
171 WriteToBackLog(1, dreg, val);
172 WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
173 WriteToBackLog(3, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
174 }
175 else
176 {
177 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg]));
178 WriteToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
179 }
180 }
181
182 // LS $axD.D, $acS.m108
183 // xxxx xxxx 10dd 000s
184 // Load register $axD.D with value from memory pointed by register
185 // $ar0. Store value from register $acS.m to memory location pointed by
186 // register $ar3. Increment both $ar0 and $ar3.
ls(const UDSPInstruction opc)187 void ls(const UDSPInstruction opc)
188 {
189 u8 sreg = opc & 0x1;
190 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
191
192 dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
193
194 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
195 WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
196 WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
197 }
198
199 // LSN $axD.D, $acS.m
200 // xxxx xxxx 10dd 010s
201 // Load register $axD.D with value from memory pointed by register
202 // $ar0. Store value from register $acS.m to memory location pointed by
203 // register $ar3. Add corresponding indexing register $ix0 to addressing
204 // register $ar0 and increment $ar3.
lsn(const UDSPInstruction opc)205 void lsn(const UDSPInstruction opc)
206 {
207 u8 sreg = opc & 0x1;
208 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
209
210 dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
211
212 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
213 WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
214 WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
215 }
216
217 // LSM $axD.D, $acS.m
218 // xxxx xxxx 10dd 100s
219 // Load register $axD.D with value from memory pointed by register
220 // $ar0. Store value from register $acS.m to memory location pointed by
221 // register $ar3. Add corresponding indexing register $ix3 to addressing
222 // register $ar3 and increment $ar0.
lsm(const UDSPInstruction opc)223 void lsm(const UDSPInstruction opc)
224 {
225 u8 sreg = opc & 0x1;
226 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
227
228 dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
229
230 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
231 WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
232 WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
233 }
234
235 // LSMN $axD.D, $acS.m
236 // xxxx xxxx 10dd 110s
237 // Load register $axD.D with value from memory pointed by register
238 // $ar0. Store value from register $acS.m to memory location pointed by
239 // register $ar3. Add corresponding indexing register $ix0 to addressing
240 // register $ar0 and add corresponding indexing register $ix3 to addressing
241 // register $ar3.
lsnm(const UDSPInstruction opc)242 void lsnm(const UDSPInstruction opc)
243 {
244 u8 sreg = opc & 0x1;
245 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
246
247 dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
248
249 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
250 WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
251 WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
252 }
253
254 // SL $acS.m, $axD.D
255 // xxxx xxxx 10dd 001s
256 // Store value from register $acS.m to memory location pointed by register
257 // $ar0. Load register $axD.D with value from memory pointed by register
258 // $ar3. Increment both $ar0 and $ar3.
sl(const UDSPInstruction opc)259 void sl(const UDSPInstruction opc)
260 {
261 u8 sreg = opc & 0x1;
262 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
263
264 dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
265
266 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
267 WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
268 WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
269 }
270
271 // SLN $acS.m, $axD.D
272 // xxxx xxxx 10dd 011s
273 // Store value from register $acS.m to memory location pointed by register
274 // $ar0. Load register $axD.D with value from memory pointed by register
275 // $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
276 // and increment $ar3.
sln(const UDSPInstruction opc)277 void sln(const UDSPInstruction opc)
278 {
279 u8 sreg = opc & 0x1;
280 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
281
282 dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
283
284 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
285 WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
286 WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
287 }
288
289 // SLM $acS.m, $axD.D
290 // xxxx xxxx 10dd 101s
291 // Store value from register $acS.m to memory location pointed by register
292 // $ar0. Load register $axD.D with value from memory pointed by register
293 // $ar3. Add corresponding indexing register $ix3 to addressing register $ar3
294 // and increment $ar0.
slm(const UDSPInstruction opc)295 void slm(const UDSPInstruction opc)
296 {
297 u8 sreg = opc & 0x1;
298 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
299
300 dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
301
302 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
303 WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
304 WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
305 }
306
307 // SLMN $acS.m, $axD.D
308 // xxxx xxxx 10dd 111s
309 // Store value from register $acS.m to memory location pointed by register
310 // $ar0. Load register $axD.D with value from memory pointed by register
311 // $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
312 // and add corresponding indexing register $ix3 to addressing register $ar3.
slnm(const UDSPInstruction opc)313 void slnm(const UDSPInstruction opc)
314 {
315 u8 sreg = opc & 0x1;
316 u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
317
318 dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
319
320 WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
321 WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
322 WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
323 }
324
325 // LD $ax0.d, $ax1.r, @$arS
326 // xxxx xxxx 11dr 00ss
327 // example for "nx'ld $AX0.L, $AX1.L, @$AR3"
328 // Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 to AX0.L.
329 // Increments AR0 and AR3.
330 // If AR0 and AR3 point into the same memory page (upper 6 bits of addr are the same -> games are
331 // not doing that!)
332 // then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L.
333 // If AR0 points into an invalid memory page (ie 0x2000), then AX0.H keeps its old value. (not
334 // implemented yet)
335 // If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not
336 // implemented yet)
ld(const UDSPInstruction opc)337 void ld(const UDSPInstruction opc)
338 {
339 u8 dreg = (opc >> 5) & 0x1;
340 u8 rreg = (opc >> 4) & 0x1;
341 u8 sreg = opc & 0x3;
342
343 WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
344
345 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
346 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
347 else
348 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
349
350 WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
351
352 WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
353 }
354
355 // LDAX $axR, @$arS
356 // xxxx xxxx 11sr 0011
ldax(const UDSPInstruction opc)357 void ldax(const UDSPInstruction opc)
358 {
359 u8 sreg = (opc >> 5) & 0x1;
360 u8 rreg = (opc >> 4) & 0x1;
361
362 WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
363
364 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
365 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
366 else
367 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
368
369 WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
370
371 WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
372 }
373
374 // LDN $ax0.d, $ax1.r, @$arS
375 // xxxx xxxx 11dr 01ss
ldn(const UDSPInstruction opc)376 void ldn(const UDSPInstruction opc)
377 {
378 u8 dreg = (opc >> 5) & 0x1;
379 u8 rreg = (opc >> 4) & 0x1;
380 u8 sreg = opc & 0x3;
381
382 WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
383
384 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
385 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
386 else
387 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
388
389 WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
390
391 WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
392 }
393
394 // LDAXN $axR, @$arS
395 // xxxx xxxx 11sr 0111
ldaxn(const UDSPInstruction opc)396 void ldaxn(const UDSPInstruction opc)
397 {
398 u8 sreg = (opc >> 5) & 0x1;
399 u8 rreg = (opc >> 4) & 0x1;
400
401 WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
402
403 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
404 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
405 else
406 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
407
408 WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
409
410 WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
411 }
412
413 // LDM $ax0.d, $ax1.r, @$arS
414 // xxxx xxxx 11dr 10ss
ldm(const UDSPInstruction opc)415 void ldm(const UDSPInstruction opc)
416 {
417 u8 dreg = (opc >> 5) & 0x1;
418 u8 rreg = (opc >> 4) & 0x1;
419 u8 sreg = opc & 0x3;
420
421 WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
422
423 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
424 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
425 else
426 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
427
428 WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
429
430 WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
431 }
432
433 // LDAXM $axR, @$arS
434 // xxxx xxxx 11sr 1011
ldaxm(const UDSPInstruction opc)435 void ldaxm(const UDSPInstruction opc)
436 {
437 u8 sreg = (opc >> 5) & 0x1;
438 u8 rreg = (opc >> 4) & 0x1;
439
440 WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
441
442 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
443 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
444 else
445 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
446
447 WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
448
449 WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
450 }
451
452 // LDNM $ax0.d, $ax1.r, @$arS
453 // xxxx xxxx 11dr 11ss
ldnm(const UDSPInstruction opc)454 void ldnm(const UDSPInstruction opc)
455 {
456 u8 dreg = (opc >> 5) & 0x1;
457 u8 rreg = (opc >> 4) & 0x1;
458 u8 sreg = opc & 0x3;
459
460 WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
461
462 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
463 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
464 else
465 WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
466
467 WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
468
469 WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
470 }
471
472 // LDAXNM $axR, @$arS
473 // xxxx xxxx 11dr 1111
ldaxnm(const UDSPInstruction opc)474 void ldaxnm(const UDSPInstruction opc)
475 {
476 u8 sreg = (opc >> 5) & 0x1;
477 u8 rreg = (opc >> 4) & 0x1;
478
479 WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
480
481 if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
482 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
483 else
484 WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
485
486 WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
487
488 WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
489 }
490
nop(const UDSPInstruction opc)491 void nop(const UDSPInstruction opc)
492 {
493 }
494 } // namespace Interpreter::Ext
495
496 // The ext ops are calculated in parallel with the actual op. That means that
497 // both the main op and the ext op see the same register state as input. The
498 // output is simple as long as the main and ext ops don't change the same
499 // register. If they do the output is the bitwise or of the result of both the
500 // main and ext ops.
501
502 // The ext op are writing their output into the backlog which is
503 // being applied to the real registers after the main op was executed
ApplyWriteBackLog()504 void ApplyWriteBackLog()
505 {
506 // always make sure to have an extra entry at the end w/ -1 to avoid
507 // infinitive loops
508 for (int i = 0; writeBackLogIdx[i] != -1; i++)
509 {
510 u16 value = writeBackLog[i];
511 #ifdef PRECISE_BACKLOG
512 value |= Interpreter::dsp_op_read_reg(writeBackLogIdx[i]);
513 #endif
514 Interpreter::dsp_op_write_reg(writeBackLogIdx[i], value);
515
516 // Clear back log
517 writeBackLogIdx[i] = -1;
518 }
519 }
520
521 // This function is being called in the main op after all input regs were read
522 // and before it writes into any regs. This way we can always use bitwise or to
523 // apply the ext command output, because if the main op didn't change the value
524 // then 0 | ext output = ext output and if it did then bitwise or is still the
525 // right thing to do
526 // Only needed for cases when mainop and extended are modifying the same ACC
527 // Games are not doing that + in motorola (similar DSP) dox this is forbidden to do.
ZeroWriteBackLog()528 void ZeroWriteBackLog()
529 {
530 #ifdef PRECISE_BACKLOG
531 // always make sure to have an extra entry at the end w/ -1 to avoid
532 // infinitive loops
533 for (int i = 0; writeBackLogIdx[i] != -1; i++)
534 {
535 Interpreter::dsp_op_write_reg(writeBackLogIdx[i], 0);
536 }
537 #endif
538 }
539
ZeroWriteBackLogPreserveAcc(u8 acc)540 void ZeroWriteBackLogPreserveAcc(u8 acc)
541 {
542 #ifdef PRECISE_BACKLOG
543 for (int i = 0; writeBackLogIdx[i] != -1; i++)
544 {
545 // acc0
546 if ((acc == 0) &&
547 ((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) ||
548 (writeBackLogIdx[i] == DSP_REG_ACH0)))
549 continue;
550
551 // acc1
552 if ((acc == 1) &&
553 ((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) ||
554 (writeBackLogIdx[i] == DSP_REG_ACH1)))
555 continue;
556
557 Interpreter::dsp_op_write_reg(writeBackLogIdx[i], 0);
558 }
559 #endif
560 }
561 } // namespace DSP
562