~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Source/Core/Core/Src/DSP/Jit/DSPJitMultiplier.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 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
 
 
8
// Multiplier and product register control
 
9
 
 
10
#include "../DSPAnalyzer.h"
 
11
#include "../DSPEmitter.h"
 
12
#include "../DSPIntUtil.h"
 
13
 
 
14
using namespace Gen;
 
15
 
 
16
// Returns s64 in RAX
 
17
// In: RCX = s16 a, RAX = s16 b
 
18
void DSPEmitter::multiply()
 
19
{
 
20
#ifdef _M_X64
 
21
//      prod = (s16)a * (s16)b; //signed
 
22
        IMUL(64, R(ECX));
 
23
 
 
24
//      Conditionally multiply by 2.
 
25
//      if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0)
 
26
        OpArg sr_reg;
 
27
        gpr.getReg(DSP_REG_SR,sr_reg);
 
28
        TEST(16, sr_reg, Imm16(SR_MUL_MODIFY));
 
29
        FixupBranch noMult2 = J_CC(CC_NZ);
 
30
//              prod <<= 1;
 
31
        LEA(64, RAX, MRegSum(RAX,RAX));
 
32
        SetJumpTarget(noMult2);
 
33
        gpr.putReg(DSP_REG_SR, false);
 
34
//      return prod;
 
35
#endif
 
36
}
 
37
 
 
38
// Returns s64 in RAX
 
39
// Clobbers RDX
 
40
void DSPEmitter::multiply_add()
 
41
{
 
42
#ifdef _M_X64
 
43
//      s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign);
 
44
        multiply();
 
45
        MOV(64, R(RDX), R(RAX));
 
46
        get_long_prod();
 
47
        ADD(64, R(RAX), R(RDX));
 
48
//      return prod;
 
49
#endif
 
50
}
 
51
 
 
52
// Returns s64 in RAX
 
53
// Clobbers RDX
 
54
void DSPEmitter::multiply_sub()
 
55
{
 
56
#ifdef _M_X64
 
57
//      s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign);
 
58
        multiply();
 
59
        MOV(64, R(RDX), R(RAX));
 
60
        get_long_prod();
 
61
        SUB(64, R(RAX), R(RDX));
 
62
//      return prod;
 
63
#endif
 
64
}
 
65
 
 
66
// Only MULX family instructions have unsigned/mixed support.
 
67
// Returns s64 in EAX
 
68
// In: RCX = s16 a, RAX = s16 b
 
69
// Returns s64 in RAX
 
70
void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
 
71
{
 
72
#ifdef _M_X64
 
73
//      s64 result;
 
74
 
 
75
//      if ((axh0==0) && (axh1==0))
 
76
//              result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used
 
77
//      else if ((axh0==0) && (axh1==1))
 
78
//              result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0  * (s16)axh.1
 
79
//      else if ((axh0==1) && (axh1==0))
 
80
//              result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1  * (s16)axh.0
 
81
//      else
 
82
//              result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used
 
83
 
 
84
 
 
85
//      if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned
 
86
        OpArg sr_reg;
 
87
        gpr.getReg(DSP_REG_SR,sr_reg);
 
88
        TEST(16, sr_reg, Imm16(SR_MUL_UNSIGNED));
 
89
        FixupBranch unsignedMul = J_CC(CC_NZ);
 
90
        //              prod = (s16)a * (s16)b; //signed
 
91
        MOVSX(64, 16, RAX, R(RAX));
 
92
        IMUL(64, R(RCX));
 
93
        FixupBranch signedMul = J(true);
 
94
 
 
95
        SetJumpTarget(unsignedMul);
 
96
        DSPJitRegCache c(gpr);
 
97
        gpr.putReg(DSP_REG_SR, false);
 
98
        if ((axh0==0) && (axh1==0))
 
99
        {
 
100
                // unsigned support ON if both ax?.l regs are used
 
101
//              prod = (u32)(a * b);
 
102
                MOVZX(64, 16, RCX, R(RCX));
 
103
                MOVZX(64, 16, RAX, R(RAX));
 
104
                MUL(64, R(RCX));
 
105
        }
 
106
        else if ((axh0==0) && (axh1==1))
 
107
        {
 
108
                // mixed support ON (u16)axl.0  * (s16)axh.1
 
109
//              prod = a * (s16)b;
 
110
                X64Reg tmp;
 
111
                gpr.getFreeXReg(tmp);
 
112
                MOV(64, R(tmp), R(RAX));
 
113
                MOVZX(64, 16, RAX, R(RCX));
 
114
                IMUL(64, R(tmp));
 
115
                gpr.putXReg(tmp);
 
116
        }
 
117
        else if ((axh0==1) && (axh1==0))
 
118
        {
 
119
                // mixed support ON (u16)axl.1  * (s16)axh.0
 
120
//              prod = (s16)a * b;
 
121
                MOVZX(64, 16, RAX, R(RAX));
 
122
                IMUL(64, R(RCX));
 
123
        }
 
124
        else
 
125
        {
 
126
                // unsigned support OFF if both ax?.h regs are used
 
127
//              prod = (s16)a * (s16)b; //signed
 
128
                MOVSX(64, 16, RAX, R(RAX));
 
129
                IMUL(64, R(RCX));
 
130
        }
 
131
 
 
132
        gpr.flushRegs(c);
 
133
        SetJumpTarget(signedMul);
 
134
 
 
135
        //      Conditionally multiply by 2.
 
136
//      if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0)
 
137
        TEST(16, sr_reg, Imm16(SR_MUL_MODIFY));
 
138
        FixupBranch noMult2 = J_CC(CC_NZ);
 
139
//              prod <<= 1;
 
140
        LEA(64, RAX, MRegSum(RAX,RAX));
 
141
        SetJumpTarget(noMult2);
 
142
        gpr.putReg(DSP_REG_SR, false);
 
143
//      return prod;
 
144
#endif
 
145
}
 
146
 
 
147
//----
 
148
 
 
149
// CLRP
 
150
// 1000 0100 xxxx xxxx
 
151
// Clears product register $prod.
 
152
// Magic numbers taken from duddie's doc
 
153
 
 
154
// 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0
 
155
 
 
156
// It's not ok, to just zero all of them, correct values should be set because of
 
157
// direct use of prod regs by AX/AXWII (look @that part of ucode).
 
158
void DSPEmitter::clrp(const UDSPInstruction opc)
 
159
{
 
160
        //64bit move to memory does not work. use 2 32bits
 
161
        MOV(32, M(((u32*)&g_dsp.r.prod.val)+0), Imm32(0xfff00000U));
 
162
        MOV(32, M(((u32*)&g_dsp.r.prod.val)+1), Imm32(0x001000ffU));
 
163
}
 
164
 
 
165
// TSTPROD
 
166
// 1000 0101 xxxx xxxx
 
167
// Test prod regs value.
 
168
 
 
169
// flags out: --xx xx0x
 
170
void DSPEmitter::tstprod(const UDSPInstruction opc)
 
171
{
 
172
#ifdef _M_X64
 
173
        if (FlagsNeeded())
 
174
        {
 
175
//              s64 prod = dsp_get_long_prod();
 
176
                get_long_prod();
 
177
//              Update_SR_Register64(prod);
 
178
                Update_SR_Register64();
 
179
        }
 
180
#else
 
181
        Default(opc);
 
182
#endif
 
183
}
 
184
 
 
185
//----
 
186
 
 
187
// MOVP $acD
 
188
// 0110 111d xxxx xxxx
 
189
// Moves multiply product from $prod register to accumulator $acD register.
 
190
 
 
191
// flags out: --xx xx0x
 
192
void DSPEmitter::movp(const UDSPInstruction opc)
 
193
{
 
194
#ifdef _M_X64
 
195
        u8 dreg = (opc >> 8) & 0x1;
 
196
 
 
197
//      s64 acc = dsp_get_long_prod();
 
198
        get_long_prod();
 
199
//      dsp_set_long_acc(dreg, acc);
 
200
        set_long_acc(dreg);
 
201
//      Update_SR_Register64(acc);
 
202
        if (FlagsNeeded())
 
203
        {
 
204
                Update_SR_Register64();
 
205
        }
 
206
#else
 
207
        Default(opc);
 
208
#endif
 
209
}
 
210
 
 
211
// MOVNP $acD
 
212
// 0111 111d xxxx xxxx 
 
213
// Moves negative of multiply product from $prod register to accumulator
 
214
// $acD register.
 
215
 
 
216
// flags out: --xx xx0x
 
217
void DSPEmitter::movnp(const UDSPInstruction opc)
 
218
{
 
219
#ifdef _M_X64
 
220
        u8 dreg = (opc >> 8) & 0x1;
 
221
 
 
222
//      s64 acc = -dsp_get_long_prod();
 
223
        get_long_prod();
 
224
        NEG(64, R(EAX));
 
225
//      dsp_set_long_acc(dreg, acc);
 
226
        set_long_acc(dreg);
 
227
//      Update_SR_Register64(acc);
 
228
        if (FlagsNeeded())
 
229
        {
 
230
                Update_SR_Register64();
 
231
        }
 
232
#else
 
233
        Default(opc);
 
234
#endif
 
235
}
 
236
 
 
237
// MOVPZ $acD
 
238
// 1111 111d xxxx xxxx
 
239
// Moves multiply product from $prod register to accumulator $acD
 
240
// register and sets (rounds) $acD.l to 0
 
241
 
 
242
// flags out: --xx xx0x
 
243
void DSPEmitter::movpz(const UDSPInstruction opc)
 
244
{
 
245
#ifdef _M_X64
 
246
        u8 dreg = (opc >> 8) & 0x01;
 
247
 
 
248
//      s64 acc = dsp_get_long_prod_round_prodl();
 
249
        get_long_prod_round_prodl();
 
250
//      dsp_set_long_acc(dreg, acc);
 
251
        set_long_acc(dreg);
 
252
//      Update_SR_Register64(acc);
 
253
        if (FlagsNeeded())
 
254
        {
 
255
                Update_SR_Register64();
 
256
        }
 
257
#else
 
258
        Default(opc);
 
259
#endif
 
260
}
 
261
 
 
262
// ADDPAXZ $acD, $axS
 
263
// 1111 10sd xxxx xxxx
 
264
// Adds secondary accumulator $axS to product register and stores result
 
265
// in accumulator register. Low 16-bits of $acD ($acD.l) are set (round) to 0.
 
266
 
 
267
// flags out: --xx xx0x
 
268
void DSPEmitter::addpaxz(const UDSPInstruction opc)
 
269
{
 
270
#ifdef _M_X64
 
271
        u8 dreg = (opc >> 8) & 0x1;
 
272
        u8 sreg = (opc >> 9) & 0x1;
 
273
 
 
274
//      s64 ax = dsp_get_long_acx(sreg);
 
275
        X64Reg tmp1;
 
276
        gpr.getFreeXReg(tmp1);
 
277
        get_long_acx(sreg, tmp1);
 
278
        MOV(64, R(RDX), R(tmp1));
 
279
//      s64 res = prod + (ax & ~0xffff);
 
280
        MOV(64, R(RAX), Imm64(~0xffff));
 
281
        AND(64, R(RDX), R(RAX));
 
282
//      s64 prod = dsp_get_long_prod_round_prodl();
 
283
        get_long_prod_round_prodl();
 
284
        ADD(64, R(RAX), R(RDX));
 
285
 
 
286
//      s64 oldprod = dsp_get_long_prod();
 
287
//      dsp_set_long_acc(dreg, res);
 
288
//      res = dsp_get_long_acc(dreg);
 
289
//      Update_SR_Register64(res, isCarry(oldprod, res), false); 
 
290
        if (FlagsNeeded())
 
291
        {
 
292
                get_long_prod(RDX);
 
293
                MOV(64, R(RCX), R(RAX));
 
294
                set_long_acc(dreg, RCX);
 
295
                Update_SR_Register64_Carry(EAX, tmp1);
 
296
        }
 
297
        else
 
298
        {
 
299
                set_long_acc(dreg, RAX);
 
300
        }
 
301
        gpr.putXReg(tmp1);
 
302
#else
 
303
        Default(opc);
 
304
#endif
 
305
}
 
306
 
 
307
//----
 
308
 
 
309
// MULAXH
 
310
// 1000 0011 xxxx xxxx
 
311
// Multiply $ax0.h by $ax0.h 
 
312
void DSPEmitter::mulaxh(const UDSPInstruction opc)
 
313
{
 
314
#ifdef _M_X64
 
315
//      s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0));
 
316
        dsp_op_read_reg(DSP_REG_AXH0, RCX, SIGN);
 
317
        MOV(64, R(RAX), R(RCX));
 
318
        multiply();
 
319
//      dsp_set_long_prod(prod);
 
320
        set_long_prod();
 
321
#else
 
322
        Default(opc);
 
323
#endif
 
324
}
 
325
 
 
326
//----
 
327
 
 
328
// MUL $axS.l, $axS.h
 
329
// 1001 s000 xxxx xxxx
 
330
// Multiply low part $axS.l of secondary accumulator $axS by high part
 
331
// $axS.h of secondary accumulator $axS (treat them both as signed).
 
332
void DSPEmitter::mul(const UDSPInstruction opc)
 
333
{
 
334
#ifdef _M_X64
 
335
        u8 sreg  = (opc >> 11) & 0x1;
 
336
 
 
337
//      u16 axl = dsp_get_ax_l(sreg);
 
338
        dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN);
 
339
//      u16 axh = dsp_get_ax_h(sreg);
 
340
        dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN);
 
341
//      s64 prod = dsp_multiply(axh, axl);
 
342
        multiply();
 
343
//      dsp_set_long_prod(prod);
 
344
        set_long_prod();
 
345
#else
 
346
        Default(opc);
 
347
#endif
 
348
}
 
349
 
 
350
// MULAC $axS.l, $axS.h, $acR
 
351
// 1001 s10r xxxx xxxx
 
352
// Add product register to accumulator register $acR. Multiply low part
 
353
// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
 
354
// accumulator $axS (treat them both as signed).
 
355
 
 
356
// flags out: --xx xx0x
 
357
void DSPEmitter::mulac(const UDSPInstruction opc)
 
358
{
 
359
#ifdef _M_X64
 
360
        u8 rreg = (opc >> 8) & 0x1;
 
361
        u8 sreg = (opc >> 11) & 0x1;
 
362
 
 
363
//      s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
 
364
        get_long_acc(rreg);
 
365
        MOV(64, R(RDX), R(RAX));
 
366
        get_long_prod();
 
367
        ADD(64, R(RAX), R(RDX));
 
368
        PUSH(64, R(RAX));
 
369
//      u16 axl = dsp_get_ax_l(sreg);
 
370
        dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN);
 
371
//      u16 axh = dsp_get_ax_h(sreg);
 
372
        dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN);
 
373
//      s64 prod = dsp_multiply(axl, axh);
 
374
        multiply();
 
375
//      dsp_set_long_prod(prod);
 
376
        set_long_prod();
 
377
//      dsp_set_long_acc(rreg, acc);
 
378
        POP(64, R(RAX));
 
379
        set_long_acc(rreg);
 
380
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
381
        if (FlagsNeeded())
 
382
        {
 
383
                Update_SR_Register64();
 
384
        }
 
385
#else
 
386
        Default(opc);
 
387
#endif
 
388
}
 
389
 
 
390
// MULMV $axS.l, $axS.h, $acR
 
391
// 1001 s11r xxxx xxxx
 
392
// Move product register to accumulator register $acR. Multiply low part
 
393
// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
 
394
// accumulator $axS (treat them both as signed).
 
395
 
 
396
// flags out: --xx xx0x
 
397
void DSPEmitter::mulmv(const UDSPInstruction opc)
 
398
{
 
399
#ifdef _M_X64
 
400
        u8 rreg  = (opc >> 8) & 0x1;
 
401
 
 
402
//      s64 acc = dsp_get_long_prod();
 
403
        get_long_prod();
 
404
        PUSH(64, R(RAX));
 
405
        mul(opc);
 
406
//      dsp_set_long_acc(rreg, acc);
 
407
        POP(64, R(RAX));
 
408
        set_long_acc(rreg);
 
409
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
410
        if (FlagsNeeded())
 
411
        {
 
412
                Update_SR_Register64();
 
413
        }
 
414
#else
 
415
        Default(opc);
 
416
#endif
 
417
}
 
418
 
 
419
// MULMVZ $axS.l, $axS.h, $acR
 
420
// 1001 s01r xxxx xxxx
 
421
// Move product register to accumulator register $acR and clear (round) low part
 
422
// of accumulator register $acR.l. Multiply low part $axS.l of secondary
 
423
// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat
 
424
// them both as signed).
 
425
 
 
426
// flags out: --xx xx0x
 
427
void DSPEmitter::mulmvz(const UDSPInstruction opc)
 
428
{
 
429
#ifdef _M_X64
 
430
        u8 rreg = (opc >> 8) & 0x1;
 
431
 
 
432
//      s64 acc = dsp_get_long_prod_round_prodl();
 
433
        get_long_prod_round_prodl(RDX);
 
434
//      dsp_set_long_acc(rreg, acc);
 
435
        set_long_acc(rreg, RDX);
 
436
        mul(opc);
 
437
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
438
        if (FlagsNeeded())
 
439
        {
 
440
                Update_SR_Register64(RDX);
 
441
        }
 
442
#else
 
443
        Default(opc);
 
444
#endif
 
445
}
 
446
 
 
447
//----
 
448
 
 
449
// MULX $ax0.S, $ax1.T
 
450
// 101s t000 xxxx xxxx
 
451
// Multiply one part $ax0 by one part $ax1.
 
452
// Part is selected by S and T bits. Zero selects low part, one selects high part.
 
453
void DSPEmitter::mulx(const UDSPInstruction opc)
 
454
{
 
455
#ifdef _M_X64
 
456
        u8 treg = ((opc >> 11) & 0x1);
 
457
        u8 sreg = ((opc >> 12) & 0x1);
 
458
 
 
459
//      u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
 
460
        dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN);
 
461
//      u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
 
462
        dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN);
 
463
//      s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
 
464
        multiply_mulx(sreg, treg);
 
465
//      dsp_set_long_prod(prod);
 
466
        set_long_prod();
 
467
#else
 
468
        Default(opc);
 
469
#endif
 
470
}
 
471
 
 
472
// MULXAC $ax0.S, $ax1.T, $acR
 
473
// 101s t01r xxxx xxxx
 
474
// Add product register to accumulator register $acR. Multiply one part
 
475
// $ax0 by one part $ax1. Part is selected by S and
 
476
// T bits. Zero selects low part, one selects high part.
 
477
 
 
478
// flags out: --xx xx0x
 
479
void DSPEmitter::mulxac(const UDSPInstruction opc)
 
480
{
 
481
#ifdef _M_X64
 
482
        u8 rreg = (opc >> 8) & 0x1;
 
483
        u8 treg = (opc >> 11) & 0x1;
 
484
        u8 sreg = (opc >> 12) & 0x1;
 
485
 
 
486
//      s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
 
487
        X64Reg tmp1;
 
488
        gpr.getFreeXReg(tmp1);
 
489
        get_long_acc(rreg, tmp1);
 
490
        get_long_prod();
 
491
        ADD(64, R(tmp1), R(RAX));
 
492
//      u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
 
493
        dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN);
 
494
//      u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
 
495
        dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN);
 
496
//      s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
 
497
        multiply_mulx(sreg, treg);
 
498
 
 
499
//      dsp_set_long_prod(prod);
 
500
        set_long_prod();
 
501
//      dsp_set_long_acc(rreg, acc);
 
502
        set_long_acc(rreg, tmp1);
 
503
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
504
        if (FlagsNeeded())
 
505
        {
 
506
                Update_SR_Register64(tmp1);
 
507
        }
 
508
        gpr.putXReg(tmp1);
 
509
#else
 
510
        Default(opc);
 
511
#endif
 
512
}
 
513
 
 
514
// MULXMV $ax0.S, $ax1.T, $acR
 
515
// 101s t11r xxxx xxxx
 
516
// Move product register to accumulator register $acR. Multiply one part
 
517
// $ax0 by one part $ax1. Part is selected by S and
 
518
// T bits. Zero selects low part, one selects high part.
 
519
 
 
520
// flags out: --xx xx0x
 
521
void DSPEmitter::mulxmv(const UDSPInstruction opc)
 
522
{
 
523
#ifdef _M_X64
 
524
        u8 rreg = ((opc >> 8) & 0x1);
 
525
        u8 treg = (opc >> 11) & 0x1;
 
526
        u8 sreg = (opc >> 12) & 0x1;
 
527
 
 
528
//      s64 acc = dsp_get_long_prod();
 
529
        X64Reg tmp1;
 
530
        gpr.getFreeXReg(tmp1);
 
531
        get_long_prod(tmp1);
 
532
//      u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
 
533
        dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN);
 
534
//      u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
 
535
        dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN);
 
536
//      s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
 
537
        multiply_mulx(sreg, treg);
 
538
 
 
539
//      dsp_set_long_prod(prod);
 
540
        set_long_prod();
 
541
//      dsp_set_long_acc(rreg, acc);
 
542
        set_long_acc(rreg, tmp1);
 
543
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
544
        if (FlagsNeeded())
 
545
        {
 
546
                Update_SR_Register64(tmp1);
 
547
        }
 
548
        gpr.putXReg(tmp1);
 
549
#else
 
550
        Default(opc);
 
551
#endif
 
552
}
 
553
 
 
554
// MULXMV $ax0.S, $ax1.T, $acR
 
555
// 101s t01r xxxx xxxx
 
556
// Move product register to accumulator register $acR and clear (round) low part
 
557
// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1
 
558
// Part is selected by S and T bits. Zero selects low part,
 
559
// one selects high part.
 
560
 
 
561
// flags out: --xx xx0x
 
562
void DSPEmitter::mulxmvz(const UDSPInstruction opc)
 
563
{
 
564
#ifdef _M_X64
 
565
        u8 rreg  = (opc >> 8) & 0x1;
 
566
        u8 treg = (opc >> 11) & 0x1;
 
567
        u8 sreg = (opc >> 12) & 0x1;
 
568
 
 
569
//      s64 acc = dsp_get_long_prod_round_prodl();
 
570
        X64Reg tmp1;
 
571
        gpr.getFreeXReg(tmp1);
 
572
        get_long_prod_round_prodl(tmp1);
 
573
//      u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
 
574
        dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN);
 
575
//      u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
 
576
        dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN);
 
577
//      s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
 
578
        multiply_mulx(sreg, treg);
 
579
 
 
580
//      dsp_set_long_prod(prod);
 
581
        set_long_prod();
 
582
//      dsp_set_long_acc(rreg, acc);
 
583
        set_long_acc(rreg, tmp1);
 
584
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
585
        if (FlagsNeeded())
 
586
        {
 
587
                Update_SR_Register64(tmp1);
 
588
        }
 
589
        gpr.putXReg(tmp1);
 
590
#else
 
591
        Default(opc);
 
592
#endif
 
593
}
 
594
 
 
595
//----
 
596
 
 
597
// MULC $acS.m, $axT.h
 
598
// 110s t000 xxxx xxxx
 
599
// Multiply mid part of accumulator register $acS.m by high part $axS.h of
 
600
// secondary accumulator $axS (treat them both as signed).
 
601
void DSPEmitter::mulc(const UDSPInstruction opc)
 
602
{
 
603
#ifdef _M_X64
 
604
        u8 treg = (opc >> 11) & 0x1;
 
605
        u8 sreg = (opc >> 12) & 0x1;
 
606
 
 
607
//      u16 accm = dsp_get_acc_m(sreg);
 
608
        get_acc_m(sreg, ECX);
 
609
//      u16 axh = dsp_get_ax_h(treg);
 
610
        dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN);
 
611
//      s64 prod = dsp_multiply(accm, axh);
 
612
        multiply();
 
613
//      dsp_set_long_prod(prod);
 
614
        set_long_prod();
 
615
#else
 
616
        Default(opc);
 
617
#endif
 
618
}
 
619
 
 
620
// MULCAC $acS.m, $axT.h, $acR
 
621
// 110s t10r xxxx xxxx
 
622
// Multiply mid part of accumulator register $acS.m by high part $axS.h of
 
623
// secondary accumulator $axS  (treat them both as signed). Add product
 
624
// register before multiplication to accumulator $acR.
 
625
 
 
626
// flags out: --xx xx0x
 
627
void DSPEmitter::mulcac(const UDSPInstruction opc)
 
628
{
 
629
#ifdef _M_X64
 
630
        u8 rreg = (opc >> 8) & 0x1;
 
631
        u8 treg  = (opc >> 11) & 0x1;
 
632
        u8 sreg  = (opc >> 12) & 0x1;
 
633
 
 
634
//      s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
 
635
        get_long_acc(rreg);
 
636
        MOV(64, R(RDX), R(RAX));
 
637
        get_long_prod();
 
638
        ADD(64, R(RAX), R(RDX));
 
639
        PUSH(64, R(RAX));
 
640
//      u16 accm = dsp_get_acc_m(sreg);
 
641
        get_acc_m(sreg, ECX);
 
642
//      u16 axh = dsp_get_ax_h(treg);
 
643
        dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN);
 
644
//      s64 prod = dsp_multiply(accm, axh);
 
645
        multiply();
 
646
//      dsp_set_long_prod(prod);
 
647
        set_long_prod();
 
648
//      dsp_set_long_acc(rreg, acc);
 
649
        POP(64, R(RAX));
 
650
        set_long_acc(rreg);
 
651
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
652
        if (FlagsNeeded())
 
653
        {
 
654
                Update_SR_Register64();
 
655
        }
 
656
#else
 
657
        Default(opc);
 
658
#endif
 
659
}
 
660
 
 
661
// MULCMV $acS.m, $axT.h, $acR
 
662
// 110s t11r xxxx xxxx
 
663
// Multiply mid part of accumulator register $acS.m by high part $axT.h of
 
664
// secondary accumulator $axT  (treat them both as signed). Move product
 
665
// register before multiplication to accumulator $acR.
 
666
// possible mistake in duddie's doc axT.h rather than axS.h
 
667
 
 
668
// flags out: --xx xx0x
 
669
void DSPEmitter::mulcmv(const UDSPInstruction opc)
 
670
{
 
671
#ifdef _M_X64
 
672
        u8 rreg = (opc >> 8) & 0x1;
 
673
        u8 treg  = (opc >> 11) & 0x1;
 
674
        u8 sreg  = (opc >> 12) & 0x1;
 
675
 
 
676
//      s64 acc = dsp_get_long_prod();
 
677
        get_long_prod();
 
678
        PUSH(64, R(RAX));
 
679
//      u16 accm = dsp_get_acc_m(sreg);
 
680
        get_acc_m(sreg, ECX);
 
681
//      u16 axh = dsp_get_ax_h(treg);
 
682
        dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN);
 
683
//      s64 prod = dsp_multiply(accm, axh);
 
684
        multiply();
 
685
//      dsp_set_long_prod(prod);
 
686
        set_long_prod();
 
687
//      dsp_set_long_acc(rreg, acc);
 
688
        POP(64, R(RAX));
 
689
        set_long_acc(rreg);
 
690
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
691
        if (FlagsNeeded())
 
692
        {
 
693
                Update_SR_Register64();
 
694
        }
 
695
#else
 
696
        Default(opc);
 
697
#endif
 
698
}
 
699
 
 
700
// MULCMVZ $acS.m, $axT.h, $acR
 
701
// 110s t01r xxxx xxxx
 
702
// (fixed possible bug in duddie's description, s->t)
 
703
// Multiply mid part of accumulator register $acS.m by high part $axT.h of
 
704
// secondary accumulator $axT  (treat them both as signed). Move product
 
705
// register before multiplication to accumulator $acR, set (round) low part of 
 
706
// accumulator $acR.l to zero.
 
707
 
 
708
// flags out: --xx xx0x
 
709
void DSPEmitter::mulcmvz(const UDSPInstruction opc)
 
710
{
 
711
#ifdef _M_X64
 
712
        u8 rreg = (opc >> 8) & 0x1;
 
713
        u8 treg  = (opc >> 11) & 0x1;
 
714
        u8 sreg  = (opc >> 12) & 0x1;
 
715
 
 
716
//      s64 acc = dsp_get_long_prod_round_prodl();
 
717
        get_long_prod_round_prodl();
 
718
        PUSH(64, R(RAX));
 
719
//      u16 accm = dsp_get_acc_m(sreg);
 
720
        get_acc_m(sreg, ECX);
 
721
//      u16 axh = dsp_get_ax_h(treg);
 
722
        dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN);
 
723
//      s64 prod = dsp_multiply(accm, axh);
 
724
        multiply();
 
725
//      dsp_set_long_prod(prod);
 
726
        set_long_prod();
 
727
//      dsp_set_long_acc(rreg, acc);
 
728
        POP(64, R(RAX));
 
729
        set_long_acc(rreg);
 
730
//      Update_SR_Register64(dsp_get_long_acc(rreg));
 
731
        if (FlagsNeeded())
 
732
        {
 
733
                Update_SR_Register64();
 
734
        }
 
735
#else
 
736
        Default(opc);
 
737
#endif
 
738
}
 
739
 
 
740
//----
 
741
 
 
742
// MADDX ax0.S ax1.T
 
743
// 1110 00st xxxx xxxx
 
744
// Multiply one part of secondary accumulator $ax0 (selected by S) by
 
745
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
 
746
// signed) and add result to product register.
 
747
void DSPEmitter::maddx(const UDSPInstruction opc)
 
748
{
 
749
#ifdef _M_X64
 
750
        u8 treg = (opc >> 8) & 0x1;
 
751
        u8 sreg = (opc >> 9) & 0x1;
 
752
 
 
753
        //      u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
 
754
        dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN);
 
755
        //      u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
 
756
        dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN);
 
757
        //      s64 prod = dsp_multiply_add(val1, val2);
 
758
        multiply_add();
 
759
        //      dsp_set_long_prod(prod);
 
760
        set_long_prod();
 
761
#else
 
762
        Default(opc);
 
763
#endif
 
764
}
 
765
 
 
766
// MSUBX $(0x18+S*2), $(0x19+T*2)
 
767
// 1110 01st xxxx xxxx
 
768
// Multiply one part of secondary accumulator $ax0 (selected by S) by
 
769
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
 
770
// signed) and subtract result from product register.
 
771
void DSPEmitter::msubx(const UDSPInstruction opc)
 
772
{
 
773
#ifdef _M_X64
 
774
        u8 treg = (opc >> 8) & 0x1;
 
775
        u8 sreg = (opc >> 9) & 0x1;
 
776
 
 
777
        //      u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
 
778
        dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN);
 
779
        //      u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
 
780
        dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN);
 
781
        //      s64 prod = dsp_multiply_sub(val1, val2);
 
782
        multiply_sub();
 
783
        //      dsp_set_long_prod(prod);
 
784
        set_long_prod();
 
785
#else
 
786
        Default(opc);
 
787
#endif
 
788
}
 
789
 
 
790
// MADDC $acS.m, $axT.h
 
791
// 1110 10st xxxx xxxx
 
792
// Multiply middle part of accumulator $acS.m by high part of secondary
 
793
// accumulator $axT.h (treat them both as signed) and add result to product
 
794
// register.
 
795
void DSPEmitter::maddc(const UDSPInstruction opc)
 
796
{
 
797
#ifdef _M_X64
 
798
        u8 treg = (opc >> 8) & 0x1;
 
799
        u8 sreg = (opc >> 9) & 0x1;
 
800
 
 
801
//      u16 accm = dsp_get_acc_m(sreg);
 
802
        get_acc_m(sreg, ECX);
 
803
//      u16 axh = dsp_get_ax_h(treg);
 
804
        dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN);
 
805
//      s64 prod = dsp_multiply_add(accm, axh);
 
806
        multiply_add();
 
807
//      dsp_set_long_prod(prod);
 
808
        set_long_prod();
 
809
#else
 
810
        Default(opc);
 
811
#endif
 
812
}
 
813
 
 
814
// MSUBC $acS.m, $axT.h
 
815
// 1110 11st xxxx xxxx
 
816
// Multiply middle part of accumulator $acS.m by high part of secondary
 
817
// accumulator $axT.h (treat them both as signed) and subtract result from
 
818
// product register.
 
819
void DSPEmitter::msubc(const UDSPInstruction opc)
 
820
{
 
821
#ifdef _M_X64
 
822
        u8 treg = (opc >> 8) & 0x1;
 
823
        u8 sreg = (opc >> 9) & 0x1;
 
824
 
 
825
//      u16 accm = dsp_get_acc_m(sreg);
 
826
        get_acc_m(sreg, ECX);
 
827
//      u16 axh = dsp_get_ax_h(treg);
 
828
        dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN);
 
829
//      s64 prod = dsp_multiply_sub(accm, axh);
 
830
        multiply_sub();
 
831
//      dsp_set_long_prod(prod);
 
832
        set_long_prod();
 
833
#else
 
834
        Default(opc);
 
835
#endif
 
836
}
 
837
 
 
838
// MADD $axS.l, $axS.h
 
839
// 1111 001s xxxx xxxx
 
840
// Multiply low part $axS.l of secondary accumulator $axS by high part
 
841
// $axS.h of secondary accumulator $axS (treat them both as signed) and add
 
842
// result to product register.
 
843
void DSPEmitter::madd(const UDSPInstruction opc)
 
844
{
 
845
#ifdef _M_X64
 
846
        u8 sreg = (opc >> 8) & 0x1;
 
847
 
 
848
//      u16 axl = dsp_get_ax_l(sreg);
 
849
        dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN);
 
850
//      u16 axh = dsp_get_ax_h(sreg);
 
851
        dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN);
 
852
//      s64 prod = dsp_multiply_add(axl, axh);
 
853
        multiply_add();
 
854
//      dsp_set_long_prod(prod);
 
855
        set_long_prod();
 
856
#else
 
857
        Default(opc);
 
858
#endif
 
859
}
 
860
 
 
861
// MSUB $axS.l, $axS.h
 
862
// 1111 011s xxxx xxxx
 
863
// Multiply low part $axS.l of secondary accumulator $axS by high part
 
864
// $axS.h of secondary accumulator $axS (treat them both as signed) and
 
865
// subtract result from product register.
 
866
void DSPEmitter::msub(const UDSPInstruction opc)
 
867
{
 
868
#ifdef _M_X64
 
869
        u8 sreg = (opc >> 8) & 0x1;
 
870
 
 
871
//      u16 axl = dsp_get_ax_l(sreg);
 
872
        dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN);
 
873
//      u16 axh = dsp_get_ax_h(sreg);
 
874
        dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN);
 
875
//      s64 prod = dsp_multiply_sub(axl, axh);
 
876
        multiply_sub();
 
877
//      dsp_set_long_prod(prod);
 
878
        set_long_prod();
 
879
#else
 
880
        Default(opc);
 
881
#endif
 
882
}