1 // Copyright 2009 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 //
5 // Additional copyrights go to Duddie and Tratax (c) 2004
6 
7 #include "Core/DSP/DSPMemoryMap.h"
8 #include "Core/DSP/Interpreter/DSPIntUtil.h"
9 #include "Core/DSP/Interpreter/DSPInterpreter.h"
10 
11 namespace DSP::Interpreter
12 {
13 // SRS @M, $(0x18+S)
14 // 0010 1sss mmmm mmmm
15 // Move value from register $(0x18+S) to data memory pointed by address
16 // CR[0-7] | M. That is, the upper 8 bits of the address are the
17 // bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate.
18 // Note: pc+=2 in duddie's doc seems wrong
srs(const UDSPInstruction opc)19 void srs(const UDSPInstruction opc)
20 {
21   u8 reg = ((opc >> 8) & 0x7) + 0x18;
22   u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
23 
24   if (reg >= DSP_REG_ACM0)
25     dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0));
26   else
27     dsp_dmem_write(addr, dsp_op_read_reg(reg));
28 }
29 
30 // LRS $(0x18+D), @M
31 // 0010 0ddd mmmm mmmm
32 // Move value from data memory pointed by address CR[0-7] | M to register
33 // $(0x18+D).  That is, the upper 8 bits of the address are the bottom 8 bits
34 // from CR, and the lower 8 bits are from the 8-bit immediate.
lrs(const UDSPInstruction opc)35 void lrs(const UDSPInstruction opc)
36 {
37   u8 reg = ((opc >> 8) & 0x7) + 0x18;
38   u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
39   dsp_op_write_reg(reg, dsp_dmem_read(addr));
40   dsp_conditional_extend_accum(reg);
41 }
42 
43 // LR $D, @M
44 // 0000 0000 110d dddd
45 // mmmm mmmm mmmm mmmm
46 // Move value from data memory pointed by address M to register $D.
lr(const UDSPInstruction opc)47 void lr(const UDSPInstruction opc)
48 {
49   u8 reg = opc & 0x1F;
50   u16 addr = dsp_fetch_code();
51   u16 val = dsp_dmem_read(addr);
52   dsp_op_write_reg(reg, val);
53   dsp_conditional_extend_accum(reg);
54 }
55 
56 // SR @M, $S
57 // 0000 0000 111s ssss
58 // mmmm mmmm mmmm mmmm
59 // Store value from register $S to a memory pointed by address M.
sr(const UDSPInstruction opc)60 void sr(const UDSPInstruction opc)
61 {
62   u8 reg = opc & 0x1F;
63   u16 addr = dsp_fetch_code();
64 
65   if (reg >= DSP_REG_ACM0)
66     dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0));
67   else
68     dsp_dmem_write(addr, dsp_op_read_reg(reg));
69 }
70 
71 // SI @M, #I
72 // 0001 0110 mmmm mmmm
73 // iiii iiii iiii iiii
74 // Store 16-bit immediate value I to a memory location pointed by address
75 // M (M is 8-bit value sign extended).
si(const UDSPInstruction opc)76 void si(const UDSPInstruction opc)
77 {
78   u16 addr = (s8)opc;
79   u16 imm = dsp_fetch_code();
80   dsp_dmem_write(addr, imm);
81 }
82 
83 // LRR $D, @$S
84 // 0001 1000 0ssd dddd
85 // Move value from data memory pointed by addressing register $S to register $D.
lrr(const UDSPInstruction opc)86 void lrr(const UDSPInstruction opc)
87 {
88   u8 sreg = (opc >> 5) & 0x3;
89   u8 dreg = opc & 0x1f;
90 
91   u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
92   dsp_op_write_reg(dreg, val);
93   dsp_conditional_extend_accum(dreg);
94 }
95 
96 // LRRD $D, @$S
97 // 0001 1000 1ssd dddd
98 // Move value from data memory pointed by addressing register $S to register $D.
99 // Decrement register $S.
lrrd(const UDSPInstruction opc)100 void lrrd(const UDSPInstruction opc)
101 {
102   u8 sreg = (opc >> 5) & 0x3;
103   u8 dreg = opc & 0x1f;
104 
105   u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
106   dsp_op_write_reg(dreg, val);
107   dsp_conditional_extend_accum(dreg);
108   g_dsp.r.ar[sreg] = dsp_decrement_addr_reg(sreg);
109 }
110 
111 // LRRI $D, @$S
112 // 0001 1001 0ssd dddd
113 // Move value from data memory pointed by addressing register $S to register $D.
114 // Increment register $S.
lrri(const UDSPInstruction opc)115 void lrri(const UDSPInstruction opc)
116 {
117   u8 sreg = (opc >> 5) & 0x3;
118   u8 dreg = opc & 0x1f;
119 
120   u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
121   dsp_op_write_reg(dreg, val);
122   dsp_conditional_extend_accum(dreg);
123   g_dsp.r.ar[sreg] = dsp_increment_addr_reg(sreg);
124 }
125 
126 // LRRN $D, @$S
127 // 0001 1001 1ssd dddd
128 // Move value from data memory pointed by addressing register $S to register $D.
129 // Add indexing register $(0x4+S) to register $S.
lrrn(const UDSPInstruction opc)130 void lrrn(const UDSPInstruction opc)
131 {
132   u8 sreg = (opc >> 5) & 0x3;
133   u8 dreg = opc & 0x1f;
134 
135   u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
136   dsp_op_write_reg(dreg, val);
137   dsp_conditional_extend_accum(dreg);
138   g_dsp.r.ar[sreg] = dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]);
139 }
140 
141 // SRR @$D, $S
142 // 0001 1010 0dds ssss
143 // Store value from source register $S to a memory location pointed by
144 // addressing register $D.
srr(const UDSPInstruction opc)145 void srr(const UDSPInstruction opc)
146 {
147   u8 dreg = (opc >> 5) & 0x3;
148   u8 sreg = opc & 0x1f;
149 
150   if (sreg >= DSP_REG_ACM0)
151     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
152   else
153     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
154 }
155 
156 // SRRD @$D, $S
157 // 0001 1010 1dds ssss
158 // Store value from source register $S to a memory location pointed by
159 // addressing register $D. Decrement register $D.
srrd(const UDSPInstruction opc)160 void srrd(const UDSPInstruction opc)
161 {
162   u8 dreg = (opc >> 5) & 0x3;
163   u8 sreg = opc & 0x1f;
164 
165   if (sreg >= DSP_REG_ACM0)
166     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
167   else
168     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
169 
170   g_dsp.r.ar[dreg] = dsp_decrement_addr_reg(dreg);
171 }
172 
173 // SRRI @$D, $S
174 // 0001 1011 0dds ssss
175 // Store value from source register $S to a memory location pointed by
176 // addressing register $D. Increment register $D.
srri(const UDSPInstruction opc)177 void srri(const UDSPInstruction opc)
178 {
179   u8 dreg = (opc >> 5) & 0x3;
180   u8 sreg = opc & 0x1f;
181 
182   if (sreg >= DSP_REG_ACM0)
183     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
184   else
185     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
186 
187   g_dsp.r.ar[dreg] = dsp_increment_addr_reg(dreg);
188 }
189 
190 // SRRN @$D, $S
191 // 0001 1011 1dds ssss
192 // Store value from source register $S to a memory location pointed by
193 // addressing register $D. Add DSP_REG_IX0 register to register $D.
srrn(const UDSPInstruction opc)194 void srrn(const UDSPInstruction opc)
195 {
196   u8 dreg = (opc >> 5) & 0x3;
197   u8 sreg = opc & 0x1f;
198 
199   if (sreg >= DSP_REG_ACM0)
200     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
201   else
202     dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
203 
204   g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]);
205 }
206 
207 // ILRR $acD.m, @$arS
208 // 0000 001d 0001 00ss
209 // Move value from instruction memory pointed by addressing register
210 // $arS to mid accumulator register $acD.m.
ilrr(const UDSPInstruction opc)211 void ilrr(const UDSPInstruction opc)
212 {
213   u16 reg = opc & 0x3;
214   u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
215 
216   g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
217   dsp_conditional_extend_accum(dreg);
218 }
219 
220 // ILRRD $acD.m, @$arS
221 // 0000 001d 0001 01ss
222 // Move value from instruction memory pointed by addressing register
223 // $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
ilrrd(const UDSPInstruction opc)224 void ilrrd(const UDSPInstruction opc)
225 {
226   u16 reg = opc & 0x3;
227   u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
228 
229   g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
230   dsp_conditional_extend_accum(dreg);
231   g_dsp.r.ar[reg] = dsp_decrement_addr_reg(reg);
232 }
233 
234 // ILRRI $acD.m, @$S
235 // 0000 001d 0001 10ss
236 // Move value from instruction memory pointed by addressing register
237 // $arS to mid accumulator register $acD.m. Increment addressing register $arS.
ilrri(const UDSPInstruction opc)238 void ilrri(const UDSPInstruction opc)
239 {
240   u16 reg = opc & 0x3;
241   u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
242 
243   g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
244   dsp_conditional_extend_accum(dreg);
245   g_dsp.r.ar[reg] = dsp_increment_addr_reg(reg);
246 }
247 
248 // ILRRN $acD.m, @$arS
249 // 0000 001d 0001 11ss
250 // Move value from instruction memory pointed by addressing register
251 // $arS to mid accumulator register $acD.m. Add corresponding indexing
252 // register $ixS to addressing register $arS.
ilrrn(const UDSPInstruction opc)253 void ilrrn(const UDSPInstruction opc)
254 {
255   u16 reg = opc & 0x3;
256   u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
257 
258   g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
259   dsp_conditional_extend_accum(dreg);
260   g_dsp.r.ar[reg] = dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]);
261 }
262 }  // namespace DSP::Interpreter
263