1
// Copyright 2013 Dolphin Emulator Project
2
// Licensed under GPLv2
3
// Refer to the license.txt file included.
5
// Additional copyrights go to Duddie and Tratax (c) 2004
8
// Multiplier and product register control
10
#include "../DSPAnalyzer.h"
11
#include "../DSPEmitter.h"
12
#include "../DSPIntUtil.h"
17
// In: RCX = s16 a, RAX = s16 b
18
void DSPEmitter::multiply()
21
// prod = (s16)a * (s16)b; //signed
24
// Conditionally multiply by 2.
25
// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0)
27
gpr.getReg(DSP_REG_SR,sr_reg);
28
TEST(16, sr_reg, Imm16(SR_MUL_MODIFY));
29
FixupBranch noMult2 = J_CC(CC_NZ);
31
LEA(64, RAX, MRegSum(RAX,RAX));
32
SetJumpTarget(noMult2);
33
gpr.putReg(DSP_REG_SR, false);
40
void DSPEmitter::multiply_add()
43
// s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign);
45
MOV(64, R(RDX), R(RAX));
47
ADD(64, R(RAX), R(RDX));
54
void DSPEmitter::multiply_sub()
57
// s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign);
59
MOV(64, R(RDX), R(RAX));
61
SUB(64, R(RAX), R(RDX));
66
// Only MULX family instructions have unsigned/mixed support.
68
// In: RCX = s16 a, RAX = s16 b
70
void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1)
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
82
// result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used
85
// if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned
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));
93
FixupBranch signedMul = J(true);
95
SetJumpTarget(unsignedMul);
96
DSPJitRegCache c(gpr);
97
gpr.putReg(DSP_REG_SR, false);
98
if ((axh0==0) && (axh1==0))
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));
106
else if ((axh0==0) && (axh1==1))
108
// mixed support ON (u16)axl.0 * (s16)axh.1
109
// prod = a * (s16)b;
111
gpr.getFreeXReg(tmp);
112
MOV(64, R(tmp), R(RAX));
113
MOVZX(64, 16, RAX, R(RCX));
117
else if ((axh0==1) && (axh1==0))
119
// mixed support ON (u16)axl.1 * (s16)axh.0
120
// prod = (s16)a * b;
121
MOVZX(64, 16, RAX, R(RAX));
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));
133
SetJumpTarget(signedMul);
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);
140
LEA(64, RAX, MRegSum(RAX,RAX));
141
SetJumpTarget(noMult2);
142
gpr.putReg(DSP_REG_SR, false);
150
// 1000 0100 xxxx xxxx
151
// Clears product register $prod.
152
// Magic numbers taken from duddie's doc
154
// 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0
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)
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));
166
// 1000 0101 xxxx xxxx
167
// Test prod regs value.
169
// flags out: --xx xx0x
170
void DSPEmitter::tstprod(const UDSPInstruction opc)
175
// s64 prod = dsp_get_long_prod();
177
// Update_SR_Register64(prod);
178
Update_SR_Register64();
188
// 0110 111d xxxx xxxx
189
// Moves multiply product from $prod register to accumulator $acD register.
191
// flags out: --xx xx0x
192
void DSPEmitter::movp(const UDSPInstruction opc)
195
u8 dreg = (opc >> 8) & 0x1;
197
// s64 acc = dsp_get_long_prod();
199
// dsp_set_long_acc(dreg, acc);
201
// Update_SR_Register64(acc);
204
Update_SR_Register64();
212
// 0111 111d xxxx xxxx
213
// Moves negative of multiply product from $prod register to accumulator
216
// flags out: --xx xx0x
217
void DSPEmitter::movnp(const UDSPInstruction opc)
220
u8 dreg = (opc >> 8) & 0x1;
222
// s64 acc = -dsp_get_long_prod();
225
// dsp_set_long_acc(dreg, acc);
227
// Update_SR_Register64(acc);
230
Update_SR_Register64();
238
// 1111 111d xxxx xxxx
239
// Moves multiply product from $prod register to accumulator $acD
240
// register and sets (rounds) $acD.l to 0
242
// flags out: --xx xx0x
243
void DSPEmitter::movpz(const UDSPInstruction opc)
246
u8 dreg = (opc >> 8) & 0x01;
248
// s64 acc = dsp_get_long_prod_round_prodl();
249
get_long_prod_round_prodl();
250
// dsp_set_long_acc(dreg, acc);
252
// Update_SR_Register64(acc);
255
Update_SR_Register64();
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.
267
// flags out: --xx xx0x
268
void DSPEmitter::addpaxz(const UDSPInstruction opc)
271
u8 dreg = (opc >> 8) & 0x1;
272
u8 sreg = (opc >> 9) & 0x1;
274
// s64 ax = dsp_get_long_acx(sreg);
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));
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);
293
MOV(64, R(RCX), R(RAX));
294
set_long_acc(dreg, RCX);
295
Update_SR_Register64_Carry(EAX, tmp1);
299
set_long_acc(dreg, RAX);
310
// 1000 0011 xxxx xxxx
311
// Multiply $ax0.h by $ax0.h
312
void DSPEmitter::mulaxh(const UDSPInstruction opc)
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));
319
// dsp_set_long_prod(prod);
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)
335
u8 sreg = (opc >> 11) & 0x1;
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);
343
// dsp_set_long_prod(prod);
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).
356
// flags out: --xx xx0x
357
void DSPEmitter::mulac(const UDSPInstruction opc)
360
u8 rreg = (opc >> 8) & 0x1;
361
u8 sreg = (opc >> 11) & 0x1;
363
// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
365
MOV(64, R(RDX), R(RAX));
367
ADD(64, R(RAX), R(RDX));
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);
375
// dsp_set_long_prod(prod);
377
// dsp_set_long_acc(rreg, acc);
380
// Update_SR_Register64(dsp_get_long_acc(rreg));
383
Update_SR_Register64();
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).
396
// flags out: --xx xx0x
397
void DSPEmitter::mulmv(const UDSPInstruction opc)
400
u8 rreg = (opc >> 8) & 0x1;
402
// s64 acc = dsp_get_long_prod();
406
// dsp_set_long_acc(rreg, acc);
409
// Update_SR_Register64(dsp_get_long_acc(rreg));
412
Update_SR_Register64();
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).
426
// flags out: --xx xx0x
427
void DSPEmitter::mulmvz(const UDSPInstruction opc)
430
u8 rreg = (opc >> 8) & 0x1;
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);
437
// Update_SR_Register64(dsp_get_long_acc(rreg));
440
Update_SR_Register64(RDX);
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)
456
u8 treg = ((opc >> 11) & 0x1);
457
u8 sreg = ((opc >> 12) & 0x1);
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);
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.
478
// flags out: --xx xx0x
479
void DSPEmitter::mulxac(const UDSPInstruction opc)
482
u8 rreg = (opc >> 8) & 0x1;
483
u8 treg = (opc >> 11) & 0x1;
484
u8 sreg = (opc >> 12) & 0x1;
486
// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
488
gpr.getFreeXReg(tmp1);
489
get_long_acc(rreg, tmp1);
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);
499
// dsp_set_long_prod(prod);
501
// dsp_set_long_acc(rreg, acc);
502
set_long_acc(rreg, tmp1);
503
// Update_SR_Register64(dsp_get_long_acc(rreg));
506
Update_SR_Register64(tmp1);
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.
520
// flags out: --xx xx0x
521
void DSPEmitter::mulxmv(const UDSPInstruction opc)
524
u8 rreg = ((opc >> 8) & 0x1);
525
u8 treg = (opc >> 11) & 0x1;
526
u8 sreg = (opc >> 12) & 0x1;
528
// s64 acc = dsp_get_long_prod();
530
gpr.getFreeXReg(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);
539
// dsp_set_long_prod(prod);
541
// dsp_set_long_acc(rreg, acc);
542
set_long_acc(rreg, tmp1);
543
// Update_SR_Register64(dsp_get_long_acc(rreg));
546
Update_SR_Register64(tmp1);
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.
561
// flags out: --xx xx0x
562
void DSPEmitter::mulxmvz(const UDSPInstruction opc)
565
u8 rreg = (opc >> 8) & 0x1;
566
u8 treg = (opc >> 11) & 0x1;
567
u8 sreg = (opc >> 12) & 0x1;
569
// s64 acc = dsp_get_long_prod_round_prodl();
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);
580
// dsp_set_long_prod(prod);
582
// dsp_set_long_acc(rreg, acc);
583
set_long_acc(rreg, tmp1);
584
// Update_SR_Register64(dsp_get_long_acc(rreg));
587
Update_SR_Register64(tmp1);
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)
604
u8 treg = (opc >> 11) & 0x1;
605
u8 sreg = (opc >> 12) & 0x1;
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);
613
// dsp_set_long_prod(prod);
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.
626
// flags out: --xx xx0x
627
void DSPEmitter::mulcac(const UDSPInstruction opc)
630
u8 rreg = (opc >> 8) & 0x1;
631
u8 treg = (opc >> 11) & 0x1;
632
u8 sreg = (opc >> 12) & 0x1;
634
// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
636
MOV(64, R(RDX), R(RAX));
638
ADD(64, R(RAX), R(RDX));
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);
646
// dsp_set_long_prod(prod);
648
// dsp_set_long_acc(rreg, acc);
651
// Update_SR_Register64(dsp_get_long_acc(rreg));
654
Update_SR_Register64();
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
668
// flags out: --xx xx0x
669
void DSPEmitter::mulcmv(const UDSPInstruction opc)
672
u8 rreg = (opc >> 8) & 0x1;
673
u8 treg = (opc >> 11) & 0x1;
674
u8 sreg = (opc >> 12) & 0x1;
676
// s64 acc = dsp_get_long_prod();
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);
685
// dsp_set_long_prod(prod);
687
// dsp_set_long_acc(rreg, acc);
690
// Update_SR_Register64(dsp_get_long_acc(rreg));
693
Update_SR_Register64();
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.
708
// flags out: --xx xx0x
709
void DSPEmitter::mulcmvz(const UDSPInstruction opc)
712
u8 rreg = (opc >> 8) & 0x1;
713
u8 treg = (opc >> 11) & 0x1;
714
u8 sreg = (opc >> 12) & 0x1;
716
// s64 acc = dsp_get_long_prod_round_prodl();
717
get_long_prod_round_prodl();
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);
725
// dsp_set_long_prod(prod);
727
// dsp_set_long_acc(rreg, acc);
730
// Update_SR_Register64(dsp_get_long_acc(rreg));
733
Update_SR_Register64();
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)
750
u8 treg = (opc >> 8) & 0x1;
751
u8 sreg = (opc >> 9) & 0x1;
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);
759
// dsp_set_long_prod(prod);
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)
774
u8 treg = (opc >> 8) & 0x1;
775
u8 sreg = (opc >> 9) & 0x1;
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);
783
// dsp_set_long_prod(prod);
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
795
void DSPEmitter::maddc(const UDSPInstruction opc)
798
u8 treg = (opc >> 8) & 0x1;
799
u8 sreg = (opc >> 9) & 0x1;
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);
807
// dsp_set_long_prod(prod);
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
819
void DSPEmitter::msubc(const UDSPInstruction opc)
822
u8 treg = (opc >> 8) & 0x1;
823
u8 sreg = (opc >> 9) & 0x1;
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);
831
// dsp_set_long_prod(prod);
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)
846
u8 sreg = (opc >> 8) & 0x1;
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);
854
// dsp_set_long_prod(prod);
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)
869
u8 sreg = (opc >> 8) & 0x1;
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);
877
// dsp_set_long_prod(prod);