From 84ccb7224b9c353c97f3894a6f4d75f8b618a1ad Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Fri, 21 Oct 2022 05:13:08 -0300 Subject: [PATCH] fix: don't flush pipeline when reloading CPSR in ARM Data Processing --- src/core/cpu/arm/data_processing.zig | 230 +-------------------------- src/core/cpu/thumb/alu.zig | 153 ++++++++---------- 2 files changed, 74 insertions(+), 309 deletions(-) diff --git a/src/core/cpu/arm/data_processing.zig b/src/core/cpu/arm/data_processing.zig index 30ed279..5540d28 100644 --- a/src/core/cpu/arm/data_processing.zig +++ b/src/core/cpu/arm/data_processing.zig @@ -34,8 +34,8 @@ pub fn dataProcessing(comptime I: bool, comptime S: bool, comptime kind: u4) Ins 0x3 => result = op2 -% op1, // RSB 0x4 => result = newAdd(&didOverflow, op1, op2), // ADD 0x5 => result = newAdc(&didOverflow, op1, op2, old_carry), // ADC - 0x6 => result = newSbc(op1, op2, old_carry), // SBC - 0x7 => result = newSbc(op2, op1, old_carry), // RSC + 0x6 => result = sbc(op1, op2, old_carry), // SBC + 0x7 => result = sbc(op2, op1, old_carry), // RSC 0x8 => { // TST if (rd == 0xF) @@ -76,7 +76,7 @@ pub fn dataProcessing(comptime I: bool, comptime S: bool, comptime kind: u4) Ins else => { cpu.r[rd] = result; if (rd == 0xF) { - if (S) cpu.setCpsr(cpu.spsr.raw); + if (S) cpu.setCpsrNoFlush(cpu.spsr.raw); cpu.pipe.reload(u32, cpu); } @@ -145,7 +145,7 @@ pub fn dataProcessing(comptime I: bool, comptime S: bool, comptime kind: u4) Ins cpu.cpsr.c.write(didOverflow); cpu.cpsr.v.write(((op1 ^ result) & (op2 ^ result)) >> 31 & 1 == 1); } else { - // TEST, TEQ specific + // TST, TEQ specific // Barrel Shifter should always calc CPSR C in TST if (!S) _ = execute(true, cpu, opcode); } @@ -155,134 +155,7 @@ pub fn dataProcessing(comptime I: bool, comptime S: bool, comptime kind: u4) Ins }.inner; } -// pub fn dataProcessing(comptime I: bool, comptime S: bool, comptime instrKind: u4) InstrFn { -// return struct { -// fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void { -// const rd = @truncate(u4, opcode >> 12 & 0xF); -// const rn = opcode >> 16 & 0xF; -// const old_carry = @boolToInt(cpu.cpsr.c.read()); - -// // If certain conditions are met, PC is 12 ahead instead of 8 -// // TODO: What are these conditions? I can't remember -// if (!I and opcode >> 4 & 1 == 1) cpu.r[15] += 4; -// const op1 = cpu.r[rn]; - -// const amount = @truncate(u8, (opcode >> 8 & 0xF) << 1); -// const op2 = if (I) rotateRight(S, &cpu.cpsr, opcode & 0xFF, amount) else execute(S, cpu, opcode); - -// // Undo special condition from above -// if (!I and opcode >> 4 & 1 == 1) cpu.r[15] -= 4; - -// switch (instrKind) { -// 0x0 => { -// // AND -// const result = op1 & op2; -// cpu.r[rd] = result; -// setArmLogicOpFlags(S, cpu, rd, result); -// }, -// 0x1 => { -// // EOR -// const result = op1 ^ op2; -// cpu.r[rd] = result; -// setArmLogicOpFlags(S, cpu, rd, result); -// }, -// 0x2 => { -// // SUB -// cpu.r[rd] = armSub(S, cpu, rd, op1, op2); -// }, -// 0x3 => { -// // RSB -// cpu.r[rd] = armSub(S, cpu, rd, op2, op1); -// }, -// 0x4 => { -// // ADD -// cpu.r[rd] = armAdd(S, cpu, rd, op1, op2); -// }, -// 0x5 => { -// // ADC -// cpu.r[rd] = armAdc(S, cpu, rd, op1, op2, old_carry); -// }, -// 0x6 => { -// // SBC -// cpu.r[rd] = armSbc(S, cpu, rd, op1, op2, old_carry); -// }, -// 0x7 => { -// // RSC -// cpu.r[rd] = armSbc(S, cpu, rd, op2, op1, old_carry); -// }, -// 0x8 => { -// // TST -// if (rd == 0xF) -// return undefinedTestBehaviour(cpu); - -// const result = op1 & op2; -// setTestOpFlags(S, cpu, opcode, result); -// }, -// 0x9 => { -// // TEQ -// if (rd == 0xF) -// return undefinedTestBehaviour(cpu); - -// const result = op1 ^ op2; -// setTestOpFlags(S, cpu, opcode, result); -// }, -// 0xA => { -// // CMP -// if (rd == 0xF) -// return undefinedTestBehaviour(cpu); - -// cmp(cpu, op1, op2); -// }, -// 0xB => { -// // CMN -// if (rd == 0xF) -// return undefinedTestBehaviour(cpu); - -// cmn(cpu, op1, op2); -// }, -// 0xC => { -// // ORR -// const result = op1 | op2; -// cpu.r[rd] = result; -// setArmLogicOpFlags(S, cpu, rd, result); -// }, -// 0xD => { -// // MOV -// cpu.r[rd] = op2; -// setArmLogicOpFlags(S, cpu, rd, op2); -// }, -// 0xE => { -// // BIC -// const result = op1 & ~op2; -// cpu.r[rd] = result; -// setArmLogicOpFlags(S, cpu, rd, result); -// }, -// 0xF => { -// // MVN -// const result = ~op2; -// cpu.r[rd] = result; -// setArmLogicOpFlags(S, cpu, rd, result); -// }, -// } - -// if (rd == 0xF) cpu.pipe.reload(u32, cpu); -// } -// }.inner; -// } - -fn armSbc(comptime S: bool, cpu: *Arm7tdmi, rd: u4, left: u32, right: u32, old_carry: u1) u32 { - var result: u32 = undefined; - if (S and rd == 0xF) { - result = sbc(false, cpu, left, right, old_carry); - cpu.setCpsr(cpu.spsr.raw); - } else { - result = sbc(S, cpu, left, right, old_carry); - } - - return result; -} - -fn newSbc(left: u32, right: u32, old_carry: u1) u32 { +pub fn sbc(left: u32, right: u32, old_carry: u1) u32 { // TODO: Make your own version (thanks peach.bot) const subtrahend = @as(u64, right) -% old_carry +% 1; const ret = @truncate(u32, left -% subtrahend); @@ -290,33 +163,6 @@ fn newSbc(left: u32, right: u32, old_carry: u1) u32 { return ret; } -pub fn sbc(comptime S: bool, cpu: *Arm7tdmi, left: u32, right: u32, old_carry: u1) u32 { - // TODO: Make your own version (thanks peach.bot) - const subtrahend = @as(u64, right) -% old_carry +% 1; - const result = @truncate(u32, left -% subtrahend); - - if (S) { - cpu.cpsr.n.write(result >> 31 & 1 == 1); - cpu.cpsr.z.write(result == 0); - cpu.cpsr.c.write(subtrahend <= left); - cpu.cpsr.v.write(((left ^ result) & (~right ^ result)) >> 31 & 1 == 1); - } - - return result; -} - -fn armSub(comptime S: bool, cpu: *Arm7tdmi, rd: u4, left: u32, right: u32) u32 { - var result: u32 = undefined; - if (S and rd == 0xF) { - result = sub(false, cpu, left, right); - cpu.setCpsr(cpu.spsr.raw); - } else { - result = sub(S, cpu, left, right); - } - - return result; -} - pub fn sub(comptime S: bool, cpu: *Arm7tdmi, left: u32, right: u32) u32 { const result = left -% right; @@ -330,18 +176,6 @@ pub fn sub(comptime S: bool, cpu: *Arm7tdmi, left: u32, right: u32) u32 { return result; } -fn armAdd(comptime S: bool, cpu: *Arm7tdmi, rd: u4, left: u32, right: u32) u32 { - var result: u32 = undefined; - if (S and rd == 0xF) { - result = add(false, cpu, left, right); - cpu.setCpsr(cpu.spsr.raw); - } else { - result = add(S, cpu, left, right); - } - - return result; -} - fn newAdd(didOverflow: *bool, left: u32, right: u32) u32 { var ret: u32 = undefined; didOverflow.* = @addWithOverflow(u32, left, right, &ret); @@ -362,19 +196,7 @@ pub fn add(comptime S: bool, cpu: *Arm7tdmi, left: u32, right: u32) u32 { return result; } -fn armAdc(comptime S: bool, cpu: *Arm7tdmi, rd: u4, left: u32, right: u32, old_carry: u1) u32 { - var result: u32 = undefined; - if (S and rd == 0xF) { - result = adc(false, cpu, left, right, old_carry); - cpu.setCpsr(cpu.spsr.raw); - } else { - result = adc(S, cpu, left, right, old_carry); - } - - return result; -} - -fn newAdc(didOverflow: *bool, left: u32, right: u32, old_carry: u1) u32 { +pub fn newAdc(didOverflow: *bool, left: u32, right: u32, old_carry: u1) u32 { var ret: u32 = undefined; const did = @addWithOverflow(u32, left, right, &ret); const overflow = @addWithOverflow(u32, ret, old_carry, &ret); @@ -383,21 +205,6 @@ fn newAdc(didOverflow: *bool, left: u32, right: u32, old_carry: u1) u32 { return ret; } -pub fn adc(comptime S: bool, cpu: *Arm7tdmi, left: u32, right: u32, old_carry: u1) u32 { - var result: u32 = undefined; - const did = @addWithOverflow(u32, left, right, &result); - const overflow = @addWithOverflow(u32, result, old_carry, &result); - - if (S) { - cpu.cpsr.n.write(result >> 31 & 1 == 1); - cpu.cpsr.z.write(result == 0); - cpu.cpsr.c.write(did or overflow); - cpu.cpsr.v.write(((left ^ result) & (right ^ result)) >> 31 & 1 == 1); - } - - return result; -} - pub fn cmp(cpu: *Arm7tdmi, left: u32, right: u32) void { const result = left -% right; @@ -407,24 +214,6 @@ pub fn cmp(cpu: *Arm7tdmi, left: u32, right: u32) void { cpu.cpsr.v.write(((left ^ result) & (~right ^ result)) >> 31 & 1 == 1); } -pub fn cmn(cpu: *Arm7tdmi, left: u32, right: u32) void { - var result: u32 = undefined; - const didOverflow = @addWithOverflow(u32, left, right, &result); - - cpu.cpsr.n.write(result >> 31 & 1 == 1); - cpu.cpsr.z.write(result == 0); - cpu.cpsr.c.write(didOverflow); - cpu.cpsr.v.write(((left ^ result) & (right ^ result)) >> 31 & 1 == 1); -} - -fn setArmLogicOpFlags(comptime S: bool, cpu: *Arm7tdmi, rd: u4, result: u32) void { - if (S and rd == 0xF) { - cpu.setCpsr(cpu.spsr.raw); - } else { - setLogicOpFlags(S, cpu, result); - } -} - pub fn setLogicOpFlags(comptime S: bool, cpu: *Arm7tdmi, result: u32) void { if (S) { cpu.cpsr.n.write(result >> 31 & 1 == 1); @@ -433,13 +222,6 @@ pub fn setLogicOpFlags(comptime S: bool, cpu: *Arm7tdmi, result: u32) void { } } -fn setTestOpFlags(comptime S: bool, cpu: *Arm7tdmi, opcode: u32, result: u32) void { - cpu.cpsr.n.write(result >> 31 & 1 == 1); - cpu.cpsr.z.write(result == 0); - // Barrel Shifter should always calc CPSR C in TST - if (!S) _ = execute(true, cpu, opcode); -} - fn undefinedTestBehaviour(cpu: *Arm7tdmi) void { @setCold(true); cpu.setCpsrNoFlush(cpu.spsr.raw); diff --git a/src/core/cpu/thumb/alu.zig b/src/core/cpu/thumb/alu.zig index 0113860..d16ae5d 100644 --- a/src/core/cpu/thumb/alu.zig +++ b/src/core/cpu/thumb/alu.zig @@ -2,18 +2,13 @@ const Bus = @import("../../Bus.zig"); const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi; const InstrFn = @import("../../cpu.zig").thumb.InstrFn; -const adc = @import("../arm/data_processing.zig").adc; +const adc = @import("../arm/data_processing.zig").newAdc; const sbc = @import("../arm/data_processing.zig").sbc; -const sub = @import("../arm/data_processing.zig").sub; -const cmp = @import("../arm/data_processing.zig").cmp; -const cmn = @import("../arm/data_processing.zig").cmn; -const setTestOpFlags = @import("../arm/data_processing.zig").setTestOpFlags; -const setLogicOpFlags = @import("../arm/data_processing.zig").setLogicOpFlags; -const logicalLeft = @import("../barrel_shifter.zig").logicalLeft; -const logicalRight = @import("../barrel_shifter.zig").logicalRight; -const arithmeticRight = @import("../barrel_shifter.zig").arithmeticRight; -const rotateRight = @import("../barrel_shifter.zig").rotateRight; +const lsl = @import("../barrel_shifter.zig").logicalLeft; +const lsr = @import("../barrel_shifter.zig").logicalRight; +const asr = @import("../barrel_shifter.zig").arithmeticRight; +const ror = @import("../barrel_shifter.zig").rotateRight; pub fn fmt4(comptime op: u4) InstrFn { return struct { @@ -22,96 +17,84 @@ pub fn fmt4(comptime op: u4) InstrFn { const rd = opcode & 0x7; const carry = @boolToInt(cpu.cpsr.c.read()); + var result: u32 = undefined; + var didOverflow: bool = undefined; switch (op) { - 0x0 => { - // AND - const result = cpu.r[rd] & cpu.r[rs]; - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); + 0x0 => result = cpu.r[rd] & cpu.r[rs], // AND + 0x1 => result = cpu.r[rd] ^ cpu.r[rs], // EOR + 0x2 => result = lsl(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])), // LSL + 0x3 => result = lsr(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])), // LSR + 0x4 => result = asr(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])), // ASR + 0x5 => result = adc(&didOverflow, cpu.r[rd], cpu.r[rs], carry), // ADC + 0x6 => result = sbc(cpu.r[rd], cpu.r[rs], carry), // SBC + 0x7 => result = ror(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])), // ROR + 0x8 => result = cpu.r[rd] & cpu.r[rs], // TST + 0x9 => result = 0 -% cpu.r[rs], // NEG + 0xA => result = cpu.r[rd] -% cpu.r[rs], // CMP + 0xB => didOverflow = @addWithOverflow(u32, cpu.r[rd], cpu.r[rs], &result), // CMN + 0xC => result = cpu.r[rd] | cpu.r[rs], // ORR + 0xD => result = @truncate(u32, @as(u64, cpu.r[rs]) * @as(u64, cpu.r[rd])), + 0xE => result = cpu.r[rd] & ~cpu.r[rs], + 0xF => result = ~cpu.r[rs], + } + + // Write to Destination Register + switch (op) { + 0x8, 0xA, 0xB => {}, + else => cpu.r[rd] = result, + } + + // Write Flags + switch (op) { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x7, 0xC, 0xE, 0xF => { + // Logic Operations + cpu.cpsr.n.write(result >> 31 & 1 == 1); + cpu.cpsr.z.write(result == 0); + // C set by Barrel Shifter, V is unaffected }, - 0x1 => { - // EOR - const result = cpu.r[rd] ^ cpu.r[rs]; - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); + 0x8, 0xA => { + // Test Flags + // CMN (0xB) is handled with ADC + cpu.cpsr.n.write(result >> 31 & 1 == 1); + cpu.cpsr.z.write(result == 0); + + if (op == 0xA) { + // CMP specific + cpu.cpsr.c.write(cpu.r[rs] <= cpu.r[rd]); + cpu.cpsr.v.write(((cpu.r[rd] ^ result) & (~cpu.r[rs] ^ result)) >> 31 & 1 == 1); + } }, - 0x2 => { - // LSL - const result = logicalLeft(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])); - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); - }, - 0x3 => { - // LSR - const result = logicalRight(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])); - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); - }, - 0x4 => { - // ASR - const result = arithmeticRight(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])); - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); - }, - 0x5 => { - // ADC - cpu.r[rd] = adc(true, cpu, cpu.r[rd], cpu.r[rs], carry); + 0x5, 0xB => { + // ADC, CMN + cpu.cpsr.n.write(result >> 31 & 1 == 1); + cpu.cpsr.z.write(result == 0); + cpu.cpsr.c.write(didOverflow); + cpu.cpsr.v.write(((cpu.r[rd] ^ result) & (cpu.r[rs] ^ result)) >> 31 & 1 == 1); + + // FIXME: Pretty sure CMN Is the same }, 0x6 => { // SBC - cpu.r[rd] = sbc(true, cpu, cpu.r[rd], cpu.r[rs], carry); - }, - 0x7 => { - // ROR - const result = rotateRight(true, &cpu.cpsr, cpu.r[rd], @truncate(u8, cpu.r[rs])); - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); - }, - 0x8 => { - // TST - const result = cpu.r[rd] & cpu.r[rs]; - setLogicOpFlags(true, cpu, result); + cpu.cpsr.n.write(result >> 31 & 1 == 1); + cpu.cpsr.z.write(result == 0); + + const subtrahend = @as(u64, cpu.r[rs]) -% carry +% 1; + cpu.cpsr.c.write(subtrahend <= cpu.r[rd]); + cpu.cpsr.v.write(((cpu.r[rd] ^ result) & (~cpu.r[rs] ^ result)) >> 31 & 1 == 1); }, 0x9 => { // NEG - cpu.r[rd] = sub(true, cpu, 0, cpu.r[rs]); - }, - 0xA => { - // CMP - cmp(cpu, cpu.r[rd], cpu.r[rs]); - }, - 0xB => { - // CMN - cmn(cpu, cpu.r[rd], cpu.r[rs]); - }, - 0xC => { - // ORR - const result = cpu.r[rd] | cpu.r[rs]; - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); + cpu.cpsr.n.write(result >> 31 & 1 == 1); + cpu.cpsr.z.write(result == 0); + cpu.cpsr.c.write(cpu.r[rs] <= 0); + cpu.cpsr.v.write(((0 ^ result) & (~cpu.r[rs] ^ result)) >> 31 & 1 == 1); }, 0xD => { - // MUL - const temp = @as(u64, cpu.r[rs]) * @as(u64, cpu.r[rd]); - const result = @truncate(u32, temp); - cpu.r[rd] = result; - + // Multiplication cpu.cpsr.n.write(result >> 31 & 1 == 1); cpu.cpsr.z.write(result == 0); // V is unaffected, assuming similar behaviour to ARMv4 MUL C is undefined }, - 0xE => { - // BIC - const result = cpu.r[rd] & ~cpu.r[rs]; - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); - }, - 0xF => { - // MVN - const result = ~cpu.r[rs]; - cpu.r[rd] = result; - setLogicOpFlags(true, cpu, result); - }, } } }.inner;