diff --git a/ExecuteI.fs b/ExecuteI.fs index 1d5a45c..7bc056f 100755 --- a/ExecuteI.fs +++ b/ExecuteI.fs @@ -285,11 +285,16 @@ let execSUB (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineS //================================================= // SLL - Shift Logical Left +// SLL, SRL, and SRA perform logical left, logical right, and arithmetic right shifts on the value in register +// rs1 by the shift amount held in register rs2. In RV32I, only the low 5 bits of rs2 are considered for the +// shift amount. In RV64I, only the low 6 bits of rs2 are considered for the shift amount. let execSLL (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = let rdVal = match mstate.Arch.archBits with - | RV32 -> (mstate.getRegister rs1) <<< int32(mstate.getRegister rs2) - | _ -> + | RV32 -> + let shamt = (mstate.getRegister rs2) &&& 0x1f + int64(int32(uint32(mstate.getRegister rs1) <<< int32(shamt))) + | _ -> let shamt = (mstate.getRegister rs2) &&& 0x3f (mstate.getRegister rs1) <<< int32(shamt) let mstate = mstate.setRegister rd rdVal @@ -297,9 +302,6 @@ let execSLL (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineS //================================================= // SLT - Set 1 if Less Then -// SLL, SRL, and SRA perform logical left, logical right, and arithmetic right shifts on the value in register -// rs1 by the shift amount held in register rs2. In RV64I, only the low 6 bits of rs2 are considered for the -// shift amount. let execSLT (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = let rdVal = if mstate.getRegister rs1 < mstate.getRegister rs2 then 1L else 0L let mstate = mstate.setRegister rd rdVal @@ -325,13 +327,15 @@ let execXOR (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineS //================================================= // SRL - Shift Right Logical // SLL, SRL, and SRA perform logical left, logical right, and arithmetic right shifts on the value in register -// rs1 by the shift amount held in register rs2. In RV64I, only the low 6 bits of rs2 are considered for the -// shift amount. +// rs1 by the shift amount held in register rs2. In RV32I, only the low 5 bits of rs2 are considered for the +// shift amount. In RV64I, only the low 6 bits of rs2 are considered for the shift amount. let execSRL (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = let rdVal = match mstate.Arch.archBits with - | RV32 -> int64(uint32(mstate.getRegister rs1) >>> int32(mstate.getRegister rs2)) - | _ -> + | RV32 -> + let shamt = (mstate.getRegister rs2) &&& 0x1f + int64(int32(uint32(mstate.getRegister rs1) >>> int32(shamt))) + | _ -> let shamt = (mstate.getRegister rs2) &&& 0x3f int64(uint64(mstate.getRegister rs1) >>> int32(shamt)) let mstate = mstate.setRegister rd rdVal @@ -340,13 +344,15 @@ let execSRL (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineS //================================================= // SRA - Shift Right Arithmetic // SLL, SRL, and SRA perform logical left, logical right, and arithmetic right shifts on the value in register -// rs1 by the shift amount held in register rs2. In RV64I, only the low 6 bits of rs2 are considered for the -// shift amount. +// rs1 by the shift amount held in register rs2. In RV32I, only the low 5 bits of rs2 are considered for the +// shift amount. In RV64I, only the low 6 bits of rs2 are considered for the shift amount. let execSRA (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = let rdVal = match mstate.Arch.archBits with - | RV32 -> (mstate.getRegister rs1) >>> int32 (mstate.getRegister rs2) - | _ -> + | RV32 -> + let shamt = (mstate.getRegister rs2) &&& 0x1f + int64(int32(mstate.getRegister rs1) >>> int32(shamt)) + | _ -> let shamt = (mstate.getRegister rs2) &&& 0x3f (mstate.getRegister rs1) >>> int32 (shamt) let mstate = mstate.setRegister rd rdVal diff --git a/Tests/rv32i/alu.fs b/Tests/rv32i/alu.fs index 5dd49cd..8e059f8 100755 --- a/Tests/rv32i/alu.fs +++ b/Tests/rv32i/alu.fs @@ -47,6 +47,13 @@ let ``SUB: x3 = x2 - x1`` (x1, x2, x3) = [] [] [] +// Edge cases: RV32 uses only the low 5 bits of the shift amount (rs2[4:0], mask 0x1f) +[] // 32 & 0x1f = 0 -> value unchanged (regression case) +[] // 33 & 0x1f = 1 +[] // shift into the sign bit +[] // bit 5 masked off: 63 & 0x1f = 31 +[] // arbitrary high bits masked: 37 & 0x1f = 5 +[] // overflow shifted off the top (32-bit result) let ``SLL: x3 = x2 << x1`` (x1, x2, x3) = ALU 0x001111b3 x1 x2 x3 @@ -83,12 +90,27 @@ let ``XOR: x3 = x2 ^ x1`` (x1, x2, x3) = [] [] [] +// Edge cases: logical (zero-fill) shift, shift amount masked to rs2[4:0] +[] // 32 & 0x1f = 0 -> value unchanged +[] // 33 & 0x1f = 1 +[] // zero-fill, not sign-fill +[] // 33 & 0x1f = 1 (same as shift 1) +[] // 63 & 0x1f = 31 +[] // 37 & 0x1f = 5 let ``SRL: x3 = x2 >> x1`` (x1, x2, x3) = ALU 0x001151b3 x1 x2 x3 [] [] [] +// Edge cases: arithmetic (sign-fill) shift, shift amount masked to rs2[4:0] +[] // 32 & 0x1f = 0 -> value unchanged (regression case) +[] // 33 & 0x1f = 1 +[] // sign-fill: -1 >> 1 stays -1 +[] // 33 & 0x1f = 1 (same as shift 1) +[] // sign bit smeared across the word +[] // 63 & 0x1f = 31 +[] // 37 & 0x1f = 5 let ``SRA: x3 = x2 >> x1`` (x1, x2, x3) = ALU 0x401151b3 x1 x2 x3