diff --git a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp index 76a30b4e61..c62388537c 100644 --- a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp +++ b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp @@ -79,10 +79,15 @@ void nr(const UDSPInstruction& opc) { // Move value of $acS.l to the $axD.l. void mv(const UDSPInstruction& opc) { - u8 sreg = opc.hex & 0x3; + u8 sreg = (opc.hex & 0x3) + DSP_REG_ACL0; u8 dreg = ((opc.hex >> 2) & 0x3); - - writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r[sreg + DSP_REG_ACL0]); + +#if 0 //more tests + if ((sreg >= DSP_REG_ACM0) && (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT)) + writeToBackLog(0, dreg + DSP_REG_AXL0, ((u16)dsp_get_acc_h(sreg-DSP_REG_ACM0) & 0x0080) ? 0x8000 : 0x7fff); + else +#endif + writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r[sreg]); } // S @$D, $acD.l @@ -331,12 +336,12 @@ void ld(const UDSPInstruction& opc) writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); } else { - writeToBackLog(0, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); else - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); writeToBackLog(2, dreg, dsp_increment_addr_reg(dreg)); } @@ -363,12 +368,12 @@ void ldn(const UDSPInstruction& opc) writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg])); } else { - writeToBackLog(0, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); else - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); writeToBackLog(2, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg])); } @@ -396,12 +401,12 @@ void ldm(const UDSPInstruction& opc) writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); } else { - writeToBackLog(0, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); else - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); writeToBackLog(2, dreg, dsp_increment_addr_reg(dreg)); } @@ -429,12 +434,12 @@ void ldnm(const UDSPInstruction& opc) writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg])); } else { - writeToBackLog(0, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); if (IsSameMemArea(g_dsp.r[dreg], g_dsp.r[DSP_REG_AR3])) - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[dreg])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[dreg])); else - writeToBackLog(1, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r[DSP_REG_AR3])); writeToBackLog(2, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg])); } diff --git a/Source/Core/DSPCore/Src/DSPIntUtil.h b/Source/Core/DSPCore/Src/DSPIntUtil.h index bb34326c2c..53d01fc769 100644 --- a/Source/Core/DSPCore/Src/DSPIntUtil.h +++ b/Source/Core/DSPCore/Src/DSPIntUtil.h @@ -218,6 +218,13 @@ inline s64 dsp_get_long_prod() return val; } +inline s64 dsp_get_long_prod_prodl_zero() +{ + s64 tempprod = dsp_get_long_prod(); + tempprod = (tempprod & ~0xffff)+(((tempprod & 0xffff) >= 0x8000) ? 0x10000 : 0); + return tempprod; +} + // For accurate emulation, this is wrong - but the real prod registers behave // in completely bizarre ways. Probably not meaningful to emulate them accurately. inline void dsp_set_long_prod(s64 val) diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp index 4953c5d1c1..7c24dea14e 100644 --- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp +++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp @@ -48,9 +48,13 @@ void clrl(const UDSPInstruction& opc) { u8 reg = (opc.hex >> 8) & 0x1; - g_dsp.r[DSP_REG_ACL0 + reg] = 0; - Update_SR_Register64(dsp_get_long_acc(reg)); + s64 acc = dsp_get_long_acc(reg); + acc = (acc & ~0xffff) + (((acc & 0xffff) >= 0x8000) ? 0x10000 : 0); + zeroWriteBackLogPreserveAcc(reg); + + dsp_set_long_acc(reg, acc); + Update_SR_Register64(acc); } //---- diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp index fc89e0f2a6..4c1d4e7c1b 100644 --- a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp +++ b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp @@ -28,16 +28,16 @@ namespace DSPInterpreter { // Only MULX family instructions have unsigned support. -inline s64 dsp_get_multiply_prod(u16 a, u16 b, bool sign) +inline s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign) { s64 prod; -#if 0 //causing probs with all games atm - if (sign && g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED) - prod = (u64)a * (u64)b; // won't overflow 32-bits + if ((sign == 1) && (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)) //unsigned + prod = (u64)a * (u64)b; + else if ((sign == 2) && (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)) //mixed + prod = (u64)a * (s64)(s16)b; else -#endif - prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits + prod = (s64)(s16)a * (s64)(s16)b; // Conditionally multiply by 2. if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0) @@ -46,19 +46,19 @@ inline s64 dsp_get_multiply_prod(u16 a, u16 b, bool sign) return prod; } -s64 dsp_multiply(u16 a, u16 b, bool sign = false) +s64 dsp_multiply(u16 a, u16 b, u8 sign = 0) { s64 prod = dsp_get_multiply_prod(a, b, sign); return prod; } -s64 dsp_multiply_add(u16 a, u16 b, bool sign = false) +s64 dsp_multiply_add(u16 a, u16 b, u8 sign = 0) { s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); return prod; } -s64 dsp_multiply_sub(u16 a, u16 b, bool sign = false) +s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0) { s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); return prod; @@ -140,7 +140,7 @@ void movpz(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x01; - s64 acc = dsp_get_long_prod() & ~0xffff; + s64 acc = dsp_get_long_prod_prodl_zero(); zeroWriteBackLog(); @@ -153,23 +153,21 @@ void movpz(const UDSPInstruction& opc) // Adds secondary accumulator $axS to product register and stores result // in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0. // -// flags out: x-xx xxxx -// -// TEST THIS!! +// flags out: ?-xx xx?? void addpaxz(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; u8 sreg = (opc.hex >> 9) & 0x1; - s64 prod = dsp_get_long_prod() & ~0xffff; // hm, should we really mask here? + s64 prod = dsp_get_long_prod_prodl_zero(); s64 ax = dsp_get_long_acx(sreg); - s64 acc = (prod + ax) & ~0xffff; + s64 res = prod + (ax & ~0xffff); zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - acc = dsp_get_long_acc(dreg); - Update_SR_Register64(acc, isCarry2(prod, acc), isOverflow(prod, ax, acc)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res); } //---- @@ -260,13 +258,13 @@ void mulmv(const UDSPInstruction& opc) // accumulator $axS by high part $axS.h of secondary accumulator $axS (treat // them both as signed). // -// flags out: xx xx00 +// flags out: xx xx0x void mulmvz(const UDSPInstruction& opc) { u8 rreg = (opc.hex >> 8) & 0x1; u8 sreg = (opc.hex >> 11) & 0x1; - s64 acc = dsp_get_long_prod() & ~0xffff; + s64 acc = dsp_get_long_prod_prodl_zero(); u16 axl = dsp_get_ax_l(sreg); u16 axh = dsp_get_ax_h(sreg); s64 prod = dsp_multiply(axl, axh); @@ -282,7 +280,7 @@ void mulmvz(const UDSPInstruction& opc) // MULX $ax0.S, $ax1.T // 101s t000 xxxx xxxx -// Multiply one part $ax0 by one part $ax1 (treat them both as signed). +// Multiply one part $ax0 by one part $ax1. // Part is selected by S and T bits. Zero selects low part, one selects high part. void mulx(const UDSPInstruction& opc) { @@ -291,8 +289,40 @@ void mulx(const UDSPInstruction& opc) u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply(val1, val2, true); - + s64 prod; + + if (!treg && !sreg) + { + prod = dsp_multiply(val1, val2, 1); + } + else if (treg && !sreg) + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 2); + else if ((val1 >= 0x8000) && (val2 < 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else + prod = dsp_multiply(val1, val2, 0); + } + else if (!treg && sreg) + { + if ((val2 >= 0x8000) && (val1 >= 0x8000)) + prod = dsp_multiply(val2, val1, 2); + else if ((val2 >= 0x8000) && (val1 < 0x8000)) + prod = dsp_multiply(val2, val1, 1); + else + prod = dsp_multiply(val2, val1, 0); + } + else + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else if ((val1 >= 0x8000) || (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 0); + else + prod = dsp_multiply(val1, val2, 1); + } + zeroWriteBackLog(); dsp_set_long_prod(prod); @@ -301,7 +331,7 @@ void mulx(const UDSPInstruction& opc) // MULXAC $ax0.S, $ax1.T, $acR // 101s t01r xxxx xxxx // Add product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// $ax0 by one part $ax1. Part is selected by S and // T bits. Zero selects low part, one selects high part. // // flags out: xx xx00 @@ -314,7 +344,39 @@ void mulxac(const UDSPInstruction& opc) s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply(val1, val2, true); + s64 prod; + + if (!treg && !sreg) + { + prod = dsp_multiply(val1, val2, 1); + } + else if (treg && !sreg) + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 2); + else if ((val1 >= 0x8000) && (val2 < 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else + prod = dsp_multiply(val1, val2, 0); + } + else if (!treg && sreg) + { + if ((val2 >= 0x8000) && (val1 >= 0x8000)) + prod = dsp_multiply(val2, val1, 2); + else if ((val2 >= 0x8000) && (val1 < 0x8000)) + prod = dsp_multiply(val2, val1, 1); + else + prod = dsp_multiply(val2, val1, 0); + } + else + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else if ((val1 >= 0x8000) || (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 0); + else + prod = dsp_multiply(val1, val2, 1); + } zeroWriteBackLog(); @@ -326,7 +388,7 @@ void mulxac(const UDSPInstruction& opc) // MULXMV $ax0.S, $ax1.T, $acR // 101s t11r xxxx xxxx // Move product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// $ax0 by one part $ax1. Part is selected by S and // T bits. Zero selects low part, one selects high part. // // flags out: xx xx00 @@ -337,9 +399,41 @@ void mulxmv(const UDSPInstruction& opc) u8 sreg = (opc.hex >> 12) & 0x1; s64 acc = dsp_get_long_prod(); - s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply(val1, val2, true); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod; + + if (!treg && !sreg) + { + prod = dsp_multiply(val1, val2, 1); + } + else if (treg && !sreg) + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 2); + else if ((val1 >= 0x8000) && (val2 < 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else + prod = dsp_multiply(val1, val2, 0); + } + else if (!treg && sreg) + { + if ((val2 >= 0x8000) && (val1 >= 0x8000)) + prod = dsp_multiply(val2, val1, 2); + else if ((val2 >= 0x8000) && (val1 < 0x8000)) + prod = dsp_multiply(val2, val1, 1); + else + prod = dsp_multiply(val2, val1, 0); + } + else + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else if ((val1 >= 0x8000) || (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 0); + else + prod = dsp_multiply(val1, val2, 1); + } zeroWriteBackLog(); @@ -351,8 +445,8 @@ void mulxmv(const UDSPInstruction& opc) // MULXMV $ax0.S, $ax1.T, $acR // 101s t01r xxxx xxxx // Move product register to accumulator register $acR and clear low part -// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat -// them both as signed). Part is selected by S and T bits. Zero selects low part, +// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 +// Part is selected by S and T bits. Zero selects low part, // one selects high part. // // flags out: xx xx00 @@ -362,10 +456,42 @@ void mulxmvz(const UDSPInstruction& opc) u8 treg = (opc.hex >> 11) & 0x1; u8 sreg = (opc.hex >> 12) & 0x1; - s64 acc = dsp_get_long_prod() & ~0xffff; + s64 acc = dsp_get_long_prod_prodl_zero(); u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply(val1, val2, true); + s64 prod; + + if (!treg && !sreg) + { + prod = dsp_multiply(val1, val2, 1); + } + else if (treg && !sreg) + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 2); + else if ((val1 >= 0x8000) && (val2 < 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else + prod = dsp_multiply(val1, val2, 0); + } + else if (!treg && sreg) + { + if ((val2 >= 0x8000) && (val1 >= 0x8000)) + prod = dsp_multiply(val2, val1, 2); + else if ((val2 >= 0x8000) && (val1 < 0x8000)) + prod = dsp_multiply(val2, val1, 1); + else + prod = dsp_multiply(val2, val1, 0); + } + else + { + if ((val1 >= 0x8000) && (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 1); + else if ((val1 >= 0x8000) || (val2 >= 0x8000)) + prod = dsp_multiply(val1, val2, 0); + else + prod = dsp_multiply(val1, val2, 1); + } zeroWriteBackLog(); @@ -460,7 +586,7 @@ void mulcmvz(const UDSPInstruction& opc) u8 treg = (opc.hex >> 11) & 0x1; u8 sreg = (opc.hex >> 12) & 0x1; - s64 acc = dsp_get_long_prod() & ~0xffff; + s64 acc = dsp_get_long_prod_prodl_zero(); u16 accm = dsp_get_acc_m(sreg); u16 axh = dsp_get_ax_h(treg); s64 prod = dsp_multiply(accm, axh); diff --git a/Source/DSPTool/Src/main.cpp b/Source/DSPTool/Src/main.cpp index 37a0e4ff25..a9a9d8eaac 100644 --- a/Source/DSPTool/Src/main.cpp +++ b/Source/DSPTool/Src/main.cpp @@ -223,6 +223,10 @@ int main(int argc, const char *argv[]) printf("-o : Results from stdout redirected to a file\n"); printf("-h
: Output assembly results to a header\n"); printf("-p : Print results of DSPSpy register dump\n"); + printf("-ps : Print results of DSPSpy register dump (disable SR output)\n"); + printf("-pm : Print results of DSPSpy register dump (convert PROD values)\n"); + printf("-psm : Print results of DSPSpy register dump (convert PROD values/disable SR output)\n"); + return 0; } @@ -236,7 +240,8 @@ int main(int argc, const char *argv[]) std::string output_header_name; std::string output_name; - bool disassemble = false, compare = false, multiple = false, outputSize = false, force = false, print_results = false; + bool disassemble = false, compare = false, multiple = false, outputSize = false, + force = false, print_results = false, print_results_prodhack = false, print_results_srhack = false; for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d")) @@ -255,6 +260,19 @@ int main(int argc, const char *argv[]) force = true; else if (!strcmp(argv[i], "-p")) print_results = true; + else if (!strcmp(argv[i], "-ps")) { + print_results = true; + print_results_srhack = true; + } + else if (!strcmp(argv[i], "-pm")) { + print_results = true; + print_results_prodhack = true; + } + else if (!strcmp(argv[i], "-psm")) { + print_results = true; + print_results_srhack = true; + print_results_prodhack = true; + } else { if (!input_name.empty()) @@ -311,12 +329,40 @@ int main(int argc, const char *argv[]) for (unsigned int step = 1; step < reg_vector.size()/32; step++) { bool changed = false; + u16 current_reg; + u16 last_reg; + u32 htemp; + //results.append(StringFromFormat("Step %3d: (CW 0x%04x) UC:%03d\n", step, 0x8fff+step, (step-1)/32)); results.append(StringFromFormat("Step %3d:\n", step)); for (int reg = 0; reg < 32; reg++) { if ((reg >= 0x0c) && (reg <= 0x0f)) continue; - u16 last_reg = reg_vector.at((step*32-32)+reg); - u16 current_reg = reg_vector.at(step*32+reg); + if (print_results_srhack && (reg == 0x13)) continue; + + if ((print_results_prodhack) && (reg >= 0x15) && (reg <= 0x17)) { + switch (reg) { + case 0x15: //DSP_REG_PRODM + last_reg = reg_vector.at((step*32-32)+reg) + reg_vector.at((step*32-32)+reg+2); + current_reg = reg_vector.at(step*32+reg) + reg_vector.at(step*32+reg+2); + break; + case 0x16: //DSP_REG_PRODH + htemp = ((reg_vector.at(step*32+reg-1) + reg_vector.at(step*32+reg+1))&~0xffff)>>16; + current_reg = (u8)(reg_vector.at(step*32+reg) + htemp); + htemp = ((reg_vector.at(step*32-32+reg-1) + reg_vector.at(step*32-32+reg+1))&~0xffff)>>16; + last_reg = (u8)(reg_vector.at(step*32-32+reg) + htemp); + break; + case 0x17: //DSP_REG_PRODM2 + current_reg = 0; + last_reg = 0; + break; + default: + break; + } + } + else { + current_reg = reg_vector.at(step*32+reg); + last_reg = reg_vector.at((step*32-32)+reg); + } if (last_reg != current_reg) { results.append(StringFromFormat("%02x %-7s: %04x %04x\n", reg, pdregname(reg), last_reg, current_reg));