diff --git a/Arch.fs b/Arch.fs index 5986e0c..1efd0e6 100644 --- a/Arch.fs +++ b/Arch.fs @@ -1,10 +1,13 @@ module ISA.RISCV.Arch +// Basic Machine Int representation - include x32 type MachineInt = int64 +// Basic registers: 0-32 type Register = int32 +// Value of Register type RegisterVal = MachineInt type Opcode = MachineInt -type InstrField = MachineInt +type InstrField = int32 // Available RISC-V architectures type Architecture = @@ -26,6 +29,7 @@ type Architecture = type TrapErrors = | InstructionFetch of MachineInt | InstructionDecode + | InstructionExecute | JumpAddress | BreakAddress | ECall diff --git a/Bits.fs b/Bits.fs index d34be46..35fb9b7 100644 --- a/Bits.fs +++ b/Bits.fs @@ -46,6 +46,11 @@ type System.Int64 with (x ^^^ (x >>> 31)) - (x >>> 31) type System.Int32 with + member x.bitSlice endBit startBit = // get Bit slice from range + (x >>> startBit) &&& ~~~(-1 <<< (endBit - startBit + 1)) + member x.signExtend n = // Sign extend bits for x32 + let bitOffset = 32 - n + (x <<< bitOffset) >>> bitOffset member x.align = // get x32 mask with all `1` bits x &&& (-1) @@ -70,27 +75,27 @@ let loadHalfWord (mem : Map) (addr : int64) : int16 option = None // Load from Memory 4 bytes -let loadWord (mem : Map) (addr : int64) : int64 option = +let loadWord (mem : Map) (addr : int64) : int32 option = if Map.containsKey addr mem && Map.containsKey (addr+1L) mem && Map.containsKey (addr+2L) mem && Map.containsKey (addr+3L) mem then let word = [| mem.[addr]; mem.[addr+1L]; mem.[addr+2L]; mem.[addr+3L] |] - Some(int64(combineBytes word)) + Some(int32(combineBytes word)) else None // Load from Memory 8 bytes -let loadDouble (mem : Map) (addr : uint32) : int64 option = +let loadDouble (mem : Map) (addr : int64) : int64 option = if Map.containsKey addr mem && - Map.containsKey (addr+1u) mem && - Map.containsKey (addr+2u) mem && - Map.containsKey (addr+3u) mem && - Map.containsKey (addr+4u) mem && - Map.containsKey (addr+5u) mem && - Map.containsKey (addr+6u) mem && - Map.containsKey (addr+7u) mem then - let dWord = [| mem.[addr]; mem.[addr+1u]; mem.[addr+2u]; mem.[addr+3u]; mem.[addr+4u]; mem.[addr+5u]; mem.[addr+6u]; mem.[addr+7u] |] + Map.containsKey (addr+1L) mem && + Map.containsKey (addr+2L) mem && + Map.containsKey (addr+3L) mem && + Map.containsKey (addr+4L) mem && + Map.containsKey (addr+5L) mem && + Map.containsKey (addr+6L) mem && + Map.containsKey (addr+7L) mem then + let dWord = [| mem.[addr]; mem.[addr+1L]; mem.[addr+2L]; mem.[addr+3L]; mem.[addr+4L]; mem.[addr+5L]; mem.[addr+6L]; mem.[addr+7L] |] Some(int64(combineBytes dWord)) else None diff --git a/DecodeI.fs b/DecodeI.fs index 9e6d37b..ecc5929 100644 --- a/DecodeI.fs +++ b/DecodeI.fs @@ -1,44 +1,46 @@ module ISA.RISCV.Decode.I +open System open ISA.RISCV.Utils.Bits open ISA.RISCV.Arch +open ISA.RISCV.MachineState //================================================================ -- \begin_latex{Major_Opcodes} -// 'I' (Base instruction set) +// 'I' (Integer x32 instruction set) type InstructionI = - | LUI of {| rd: Register; imm20: MachineInt |} - | AUIPC of {| rd: Register; imm20: MachineInt |} - - | JALR of {| rd: Register; rs1: Register; imm12: MachineInt |} - | JAL of {| rd: Register; imm20: MachineInt |} - - | BEQ of {| rs1: Register; rs2: Register; imm12: MachineInt |} - | BNE of {| rs1: Register; rs2: Register; imm12: MachineInt |} - | BLT of {| rs1: Register; rs2: Register; imm12: MachineInt |} - | BGE of {| rs1: Register; rs2: Register; imm12: MachineInt |} - | BLTU of {| rs1: Register; rs2: Register; imm12: MachineInt |} - | BGEU of {| rs1: Register; rs2: Register; imm12: MachineInt |} - - | LB of {| rd: Register; rs1: Register; imm12: MachineInt |} - | LH of {| rd: Register; rs1: Register; imm12: MachineInt |} - | LW of {| rd: Register; rs1: Register; imm12: MachineInt |} - | LBU of {| rd: Register; rs1: Register; imm12: MachineInt |} - | LHU of {| rd: Register; rs1: Register; imm12: MachineInt |} - - | SB of {| rs1: Register; rs2: Register; imm12: MachineInt |} - | SH of {| rs1: Register; rs2: Register; imm12: MachineInt |} - | SW of {| rs1: Register; rs2: Register; imm12: MachineInt |} - - | ADDI of {| rd: Register; rs1: Register; imm12: MachineInt |} - | SLTI of {| rd: Register; rs1: Register; imm12: MachineInt |} - | SLTIU of {| rd: Register; rs1: Register; imm12: MachineInt |} - | XORI of {| rd: Register; rs1: Register; imm12: MachineInt |} - | ORI of {| rd: Register; rs1: Register; imm12: MachineInt |} - | ANDI of {| rd: Register; rs1: Register; imm12: MachineInt |} - - | SLLI of {| rd: Register; rs1: Register; shamt: MachineInt |} - | SRLI of {| rd: Register; rs1: Register; shamt: MachineInt |} - | SRAI of {| rd: Register; rs1: Register; shamt: MachineInt |} + | LUI of {| rd: Register; imm20: InstrField |} + | AUIPC of {| rd: Register; imm20: InstrField |} + + | JALR of {| rd: Register; rs1: Register; imm12: InstrField |} + | JAL of {| rd: Register; imm20: InstrField |} + + | BEQ of {| rs1: Register; rs2: Register; imm12: InstrField |} + | BNE of {| rs1: Register; rs2: Register; imm12: InstrField |} + | BLT of {| rs1: Register; rs2: Register; imm12: InstrField |} + | BGE of {| rs1: Register; rs2: Register; imm12: InstrField |} + | BLTU of {| rs1: Register; rs2: Register; imm12: InstrField |} + | BGEU of {| rs1: Register; rs2: Register; imm12: InstrField |} + + | LB of {| rd: Register; rs1: Register; imm12: InstrField |} + | LH of {| rd: Register; rs1: Register; imm12: InstrField |} + | LW of {| rd: Register; rs1: Register; imm12: InstrField |} + | LBU of {| rd: Register; rs1: Register; imm12: InstrField |} + | LHU of {| rd: Register; rs1: Register; imm12: InstrField |} + + | SB of {| rs1: Register; rs2: Register; imm12: InstrField |} + | SH of {| rs1: Register; rs2: Register; imm12: InstrField |} + | SW of {| rs1: Register; rs2: Register; imm12: InstrField |} + + | ADDI of {| rd: Register; rs1: Register; imm12: InstrField |} + | SLTI of {| rd: Register; rs1: Register; imm12: InstrField |} + | SLTIU of {| rd: Register; rs1: Register; imm12: InstrField |} + | XORI of {| rd: Register; rs1: Register; imm12: InstrField |} + | ORI of {| rd: Register; rs1: Register; imm12: InstrField |} + | ANDI of {| rd: Register; rs1: Register; imm12: InstrField |} + + | SLLI of {| rd: Register; rs1: Register; shamt: InstrField |} + | SRLI of {| rd: Register; rs1: Register; shamt: InstrField |} + | SRAI of {| rd: Register; rs1: Register; shamt: InstrField |} | ADD of {| rd: Register; rs1: Register; rs2: Register |} | SUB of {| rd: Register; rs1: Register; rs2: Register |} @@ -51,50 +53,33 @@ type InstructionI = | OR of {| rd: Register; rs1: Register; rs2: Register |} | AND of {| rd: Register; rs1: Register; rs2: Register |} - | FENCE of {| pred: MachineInt; succ: MachineInt; fm: MachineInt |} + | FENCE of {| pred: InstrField; succ: InstrField; fm: InstrField |} | ECALL | EBREAK | None // Instruction not found -//================================================================ -- \begin_latex{Major_Opcodes} -// Major Opcodes -let opcode_OP = 0b0110011L - -//================================================================ -// Sub-opcodes for 'I' instructions - -// opcode_JALR sub-opcodes -let funct3_JALR = 0b000L - -// Sub opcode_OP_IMM.SLLI/SRLI/SRAI - 32 & 64 bit -let msbs6_SLLI = 0b0000000L -let msbs6_SRLI = 0b0000000L -let msbs6_SRAI = 0b0100000L - -// opcode_MISC_MEM sub-opcodes -let funct3_FENCE = 0b000L - -// opcode_SYSTEM sub-opcodes -let funct3_PRIV = 0b000L -let funct12_ECALL = 0b000000000000L -let funct12_EBREAK = 0b000000000001L - /// Decode 'I' instructions -let DecodeI (instr: InstrField) : InstructionI = +let Decode (mstate : MachineState) (instr: InstrField) : InstructionI = let opcode = instr.bitSlice 6 0 + // Register number can be: 0-32 let rd = int32(instr.bitSlice 11 7) - let funct3 = instr.bitSlice 14 12 let rs1 = int32(instr.bitSlice 19 15) let rs2 = int32(instr.bitSlice 24 20) + + let funct3 = instr.bitSlice 14 12 let funct7 = instr.bitSlice 31 25 // Shamt funcs - let shamt = instr.bitSlice 24 20 - let shamt5 = instr.bitSlice 24 20 - let shamt6 = instr.bitSlice 25 20 - // TODO: x32/64 check for Shamt - let shamt_ok = true + let shamt = + if mstate.Arch.archBits = RV32 then + instr.bitSlice 24 20 + else + instr.bitSlice 24 20 + let funct6 = instr.bitSlice 31 26 + let shamt_ok = + ((instr.bitSlice 25 25) = 0) || + (mstate.Arch.archBits = RV64) let imm12_I = (instr.bitSlice 31 20).signExtend 12 let imm20_U = ((instr.bitSlice 31 12) <<< 12).signExtend 32 @@ -128,78 +113,97 @@ let DecodeI (instr: InstrField) : InstructionI = match (opcode) with // Upper Immediate Opcodes - | 0b0110111L -> LUI {| rd = rd; imm20 = imm20_U |} - | 0b0010111L -> AUIPC {| rd = rd; imm20 = imm20_U |} + | 0b0110111 -> LUI {| rd = rd; imm20 = imm20_U |} + | 0b0010111 -> AUIPC {| rd = rd; imm20 = imm20_U |} // Jump Opcodes - | 0b1100111L -> JALR {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b1101111L -> JAL {| rd = rd; imm20 = imm20_J |} + | 0b1100111 -> JALR {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b1101111 -> JAL {| rd = rd; imm20 = imm20_J |} // Branch Opcodes - | 0b1100011L -> + | 0b1100011 -> match funct3 with - | 0b000L -> BEQ {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} - | 0b001L -> BNE {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} - | 0b100L -> BLT {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} - | 0b101L -> BGE {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} - | 0b110L -> BLTU {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} - | 0b111L -> BGEU {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} + | 0b000 -> BEQ {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} + | 0b001 -> BNE {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} + | 0b100 -> BLT {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} + | 0b101 -> BGE {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} + | 0b110 -> BLTU {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} + | 0b111 -> BGEU {| rs1 = rs1; rs2 = rs2; imm12 = imm12_B |} | _ -> None // Load Opcodes - | 0b0000011L -> + | 0b0000011 -> match funct3 with - | 0b000L -> LB {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b001L -> LH {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b010L -> LW {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b100L -> LBU {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b101L -> LHU {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b000 -> LB {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b001 -> LH {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b010 -> LW {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b100 -> LBU {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b101 -> LHU {| rd = rd; rs1 = rs1; imm12 = imm12_I |} | _ -> None // Store opcodes - | 0b0100011L -> + | 0b0100011 -> match funct3 with - | 0b000L -> SB {| rs1 = rs1; rs2 = rs2; imm12 = imm11_S |} - | 0b001L -> SH {| rs1 = rs1; rs2 = rs2; imm12 = imm11_S |} - | 0b010L -> SW {| rs1 = rs1; rs2 = rs2; imm12 = imm11_S |} + | 0b000 -> SB {| rs1 = rs1; rs2 = rs2; imm12 = imm11_S |} + | 0b001 -> SH {| rs1 = rs1; rs2 = rs2; imm12 = imm11_S |} + | 0b010 -> SW {| rs1 = rs1; rs2 = rs2; imm12 = imm11_S |} | _ -> None // Immediate Opcodes - | 0b0010011L -> + | 0b0010011 -> match funct3 with - | 0b000L -> ADDI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b010L -> SLTI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b011L -> SLTIU {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b100L -> XORI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b110L -> ORI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} - | 0b111L -> ANDI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b000 -> ADDI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b010 -> SLTI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b011 -> SLTIU {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b100 -> XORI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b110 -> ORI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b111 -> ANDI {| rd = rd; rs1 = rs1; imm12 = imm12_I |} // Shift Immediate Opcodes - | 0b001L when funct7 = msbs6_SLLI -> SLLI {| rd = rd; rs1 = rs1; shamt = shamt |} - | 0b101L when funct7 = msbs6_SRLI -> SRLI {| rd = rd; rs1 = rs1; shamt = shamt |} - | 0b101L when funct7 = msbs6_SRAI -> SRAI {| rd = rd; rs1 = rs1; shamt = shamt |} + | 0b001 when funct6 = 0b000000 && shamt_ok -> SLLI {| rd = rd; rs1 = rs1; shamt = shamt |} + | 0b101 when funct6 = 0b000000 && shamt_ok -> SRLI {| rd = rd; rs1 = rs1; shamt = shamt |} + | 0b101 when funct6 = 0b010000 && shamt_ok -> SRAI {| rd = rd; rs1 = rs1; shamt = shamt |} | _ -> None // ALU Opcodes - | 0b0110011L -> + | 0b0110011 -> match funct3 with - | 0b000L when funct7 = 0b0000000L -> ADD {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b000L when funct7 = 0b0100000L -> SUB {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b001L when funct7 = 0b0000000L -> SLL {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b010L when funct7 = 0b0000000L -> SLT {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b011L when funct7 = 0b0000000L -> SLTU {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b100L when funct7 = 0b0000000L -> XOR {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b101L when funct7 = 0b0000000L -> SRL {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b101L when funct7 = 0b0100000L -> SRA {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b110L when funct7 = 0b0000000L -> OR {| rd = rd; rs1 = rs1; rs2 = rs2 |} - | 0b111L when funct7 = 0b0000000L -> AND {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b000 when funct7 = 0b0000000 -> ADD {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b000 when funct7 = 0b0100000 -> SUB {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b001 when funct7 = 0b0000000 -> SLL {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b010 when funct7 = 0b0000000 -> SLT {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b011 when funct7 = 0b0000000 -> SLTU {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b100 when funct7 = 0b0000000 -> XOR {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b101 when funct7 = 0b0000000 -> SRL {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b101 when funct7 = 0b0100000 -> SRA {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b110 when funct7 = 0b0000000 -> OR {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b111 when funct7 = 0b0000000 -> AND {| rd = rd; rs1 = rs1; rs2 = rs2 |} | _ -> None // Fence Opcode - | 0b0001111L when rd = 0 && rs1 = 0 && funct3 = funct3_FENCE -> FENCE {| fm = fm; pred = pred; succ = succ |} + | 0b0001111 when rd = 0 && rs1 = 0 && funct3 = 0b000 -> FENCE {| fm = fm; pred = pred; succ = succ |} // System opcodes - | 0b1110011L when rd = 0 && rs1 = 0 && funct3 = funct3_PRIV && imm12_I = funct12_ECALL -> ECALL - | 0b1110011L when rd = 0 && rs1 = 0 && funct3 = funct3_PRIV && imm12_I = funct12_EBREAK -> EBREAK + | 0b1110011 when rd = 0 && rs1 = 0 && funct3 = 0b000 && imm12_I = 0b000000000000 -> ECALL + | 0b1110011 when rd = 0 && rs1 = 0 && funct3 = 0b000 && imm12_I = 0b000000000001 -> EBREAK | _ -> None + +// Current ISA print log message for current instruction step +let verbosityMessage (instr : InstrField) (decodedInstr : InstructionI) (mstate : MachineState) = + let typeName = decodedInstr.GetType().Name + let instrMsg = + match (decodedInstr) with + | LUI x | AUIPC x -> sprintf "x%d, 0x%08x" x.rd x.imm20 + | JAL x -> sprintf "x%d, 0x%08x\n" x.rd x.imm20 + | JALR x -> sprintf "x%d, x%d, 0x%08x\n" x.rd x.rs1 x.imm12 + | LB x | LH x | LW x | LBU x | LHU x | LB x | ADDI x | SLTI x | XORI x | ORI x | ANDI x -> sprintf "x%d, x%d, %d" x.rd x.rs1 x.imm12 + | BEQ x | BNE x | BLT x | BGE x | BLTU x | BGEU x | SB x | SH x | SW x -> sprintf "x%d, x%d, 0x%08x" x.rs1 x.rs2 x.imm12 + | SLLI x | SRLI x | SRAI x -> sprintf "x%d, x%d, %d" x.rd x.rs1 x.shamt + | ADD x | SUB x | SLL x | SLT x | SLTU x | XOR x | SRL x | SRA x | OR x | AND x -> sprintf "x%d, x%d, x%d" x.rd x.rs1 x.rs2 + | FENCE _ | EBREAK | ECALL -> "" + | _ -> "Undef" + let pc = sprintf "%08x:" mstate.PC + let instr = sprintf "%08x" instr + let instrMsg = String.Format("{0,-7}{1}", typeName, instrMsg) + printfn "%s" (String.Format("{0,-12}{1,-12}{2}", pc, instr, instrMsg)) diff --git a/DecodeI64.fs b/DecodeI64.fs new file mode 100644 index 0000000..80fcf2f --- /dev/null +++ b/DecodeI64.fs @@ -0,0 +1,100 @@ +module ISA.RISCV.Decode.I64 + +open System +open ISA.RISCV.Utils.Bits +open ISA.RISCV.Arch +open ISA.RISCV.MachineState + +//================================================================ -- \begin_latex{Major_Opcodes} +// 'I64' (Integer x64 instruction set) +type InstructionI64 = + | LWU of {| rd: Register; rs1: Register; imm12: InstrField |} + | LD of {| rd: Register; rs1: Register; imm12: InstrField |} + | SD of {| rs1: Register; rs2: Register; imm12: InstrField |} + | ADDIW of {| rd: Register; rs1: Register; imm12: InstrField |} + + | SLLIW of {| rd: Register; rs1: Register; shamt: InstrField |} + | SRLIW of {| rd: Register; rs1: Register; shamt: InstrField |} + | SRAIW of {| rd: Register; rs1: Register; shamt: InstrField |} + + | ADDW of {| rd: Register; rs1: Register; rs2: Register |} + | SUBW of {| rd: Register; rs1: Register; rs2: Register |} + | SLLW of {| rd: Register; rs1: Register; rs2: Register |} + | SRLW of {| rd: Register; rs1: Register; rs2: Register |} + | SRAW of {| rd: Register; rs1: Register; rs2: Register |} + + | None // Instruction not found + +/// Decode 'I64' instructions +let Decode (instr: InstrField) : InstructionI64 = + let opcode = instr.bitSlice 6 0 + // Register number can be: 0-32 + let rd = int32(instr.bitSlice 11 7) + let rs1 = int32(instr.bitSlice 19 15) + let rs2 = int32(instr.bitSlice 24 20) + + let funct3 = instr.bitSlice 14 12 + let funct7 = instr.bitSlice 31 25 + + // Shamt funcs + let shamt = instr.bitSlice 24 20 + + let imm12_I = (instr.bitSlice 31 20).signExtend 12 + + let imm11_S = + ( + ((instr.bitSlice 31 25) <<< 5) ||| + ( instr.bitSlice 11 7) + ).signExtend 12 + + match (opcode) with + // Load Opcodes + | 0b0000011 -> + match funct3 with + | 0b110 -> LWU {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | 0b011 -> LD {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + | _ -> None + + // Store opcodes + | 0b0100011 -> + match funct3 with + | 0b011 -> SD {| rs1 = rs1; rs2 = rs2; imm12 = imm11_S |} + | _ -> None + + | 0b0011011 -> + match funct3 with + // Immediate Opcodes + | 0b000 -> ADDIW {| rd = rd; rs1 = rs1; imm12 = imm12_I |} + + // Shift Immediate Opcodes + | 0b001 when funct7 = 0b0000000 -> SLLIW {| rd = rd; rs1 = rs1; shamt = shamt |} + | 0b101 when funct7 = 0b0000000 -> SRLIW {| rd = rd; rs1 = rs1; shamt = shamt |} + | 0b101 when funct7 = 0b0100000 -> SRAIW {| rd = rd; rs1 = rs1; shamt = shamt |} + | _ -> None + + | 0b0111011 -> + // ALU opcodes + match funct3 with + | 0b000 when funct7 = 0b0000000 -> ADDW {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b000 when funct7 = 0b0100000 -> SUBW {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b001 when funct7 = 0b0000000 -> SLLW {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b101 when funct7 = 0b0000000 -> SRLW {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | 0b101 when funct7 = 0b0100000 -> SRAW {| rd = rd; rs1 = rs1; rs2 = rs2 |} + | _ -> None + + | _ -> None + +// Current ISA print log message for current instruction step +let verbosityMessage (instr : InstrField) (decodedInstr : InstructionI64) (mstate : MachineState) = + let typeName = decodedInstr.GetType().Name + let instrMsg = + match (decodedInstr) with + | LWU x | LD x | ADDIW x-> sprintf "x%d, x%d, %d" x.rd x.rs1 x.imm12 + | SD x -> sprintf "x%d, x%d, %d" x.rs1 x.rs2 x.imm12 + | SLLIW x | SRLIW x | SRAIW x -> sprintf "x%d, x%d, %d" x.rd x.rs1 x.shamt + | ADDW x | SUBW x | SLLW x | SRLW x | SRAW x -> sprintf "x%d, x%d, x%d" x.rd x.rs1 x.rs2 + | _ -> "Undef" + let pc = sprintf "%08x:" mstate.PC + let instr = sprintf "%08x" instr + let instrMsg = String.Format("{0,-7}{1}", typeName, instrMsg) + printfn "%s" (String.Format("{0,-12}{1,-12}{2}", pc, instr, instrMsg)) diff --git a/Decoder.fs b/Decoder.fs index 57bb75f..9c1d396 100644 --- a/Decoder.fs +++ b/Decoder.fs @@ -1,8 +1,33 @@ /// Decode instructions set - module ISA.RISCV.Decoder -open ISA.RISCV.Decode.I +open ISA.RISCV.Decode +open ISA.RISCV.Arch +open ISA.RISCV.MachineState +open ISA.RISCV.Execute + +// Execution Function type is currying with partly applied +// concrete function for specific instruction set +type execFunc = MachineState -> MachineState + +//type Instructions = +// | I of I.InstructionI * execFunc +// | I64 of I64.InstructionI64 * execFunc +// | None + +// Aggregate decoded data +let Decode (mstate : MachineState) (instr: InstrField) : execFunc option = + let decI32 = I.Decode mstate instr + let decI64 = + if decI32 = I.InstructionI.None then + I64.Decode instr + else + I64.InstructionI64.None -type Instructions = - | I of InstructionI + // Set decoded instruction and ISA execution function + if decI32 <> I.InstructionI.None then + Some(I.Execute decI32) + else if decI64 <> I64.InstructionI64.None then + Some(I64.Execute decI64) + else + None diff --git a/ExecuteI.fs b/ExecuteI.fs index f5325ac..6d50a37 100644 --- a/ExecuteI.fs +++ b/ExecuteI.fs @@ -1,4 +1,4 @@ -module ISA.RISCV.ExecuteI +module ISA.RISCV.Execute.I open ISA.RISCV.Arch open ISA.RISCV.Decode.I @@ -7,20 +7,20 @@ open ISA.RISCV.Utils.Bits //================================================= // LUI - Load Upper immediate -let execLUI (rd : Register) (imm20 : MachineInt) (mstate : MachineState) = - let mstate = mstate.setRegister rd imm20 +let execLUI (rd : Register) (imm20 : InstrField) (mstate : MachineState) = + let mstate = mstate.setRegister rd (int64 imm20) mstate.incPC //================================================= // AUIPC - Add Upper immediate PC -let execAUIPC (rd : Register) (imm20 : MachineInt) (mstate : MachineState) = - let mstate = mstate.setRegister rd (imm20 + mstate.PC) +let execAUIPC (rd : Register) (imm20 : InstrField) (mstate : MachineState) = + let mstate = mstate.setRegister rd ((int64 imm20) + mstate.PC) mstate.incPC //================================================= // JALR - Jump Relative immediately -let execJALR (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let newPC = ((mstate.getRegister rs1) + imm12) &&& (~~~1L) +let execJALR (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let newPC = ((mstate.getRegister rs1) + (int64 imm12)) &&& (~~~1L) if newPC % 4L <> 0L then mstate.setRunState (Trap JumpAddress) else if newPC = mstate.PC then @@ -32,8 +32,8 @@ let execJALR (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : Mac //================================================= // JAL - Jump immediately -let execJAL (rd : Register) (imm20 : MachineInt) (mstate : MachineState) = - let newPC = mstate.PC + int64(imm20) +let execJAL (rd : Register) (imm20 : InstrField) (mstate : MachineState) = + let newPC = mstate.PC + int64 imm20 if newPC % 4L <> 0L then mstate.setRunState (Trap JumpAddress) else if newPC = mstate.PC then @@ -44,10 +44,10 @@ let execJAL (rd : Register) (imm20 : MachineInt) (mstate : MachineState) = mstate.setPC newPC // Basic branch flow -let branch (branchCheck : MachineInt -> MachineInt -> bool) (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = +let branch (branchCheck : MachineInt -> MachineInt -> bool) (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = let x1 = mstate.getRegister rs1 let x2 = mstate.getRegister rs2 - let newPC = mstate.PC + imm12 + let newPC = mstate.PC + int64 imm12 if newPC % 4L <> 0L then mstate.setRunState (Trap BreakAddress) else if newPC = mstate.PC then @@ -60,34 +60,34 @@ let branch (branchCheck : MachineInt -> MachineInt -> bool) (rs1 : Register) (rs //================================================= // BEQ - Branch if Equal -let execBEQ (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = +let execBEQ (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = branch (=) rs1 rs2 imm12 mstate //================================================= // BNE - Branch if Not Equal -let execBNE (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = +let execBNE (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = branch (<>) rs1 rs2 imm12 mstate //================================================= // BLT - Branch if Less Then -let execBLT (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = +let execBLT (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = branch (<) rs1 rs2 imm12 mstate //================================================= // BGE - Branch if Greater or Equal -let execBGE (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = +let execBGE (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = branch (>=) rs1 rs2 imm12 mstate //================================================= // BLTU - Branch if Less Then (Unsigned) -let execBLTU (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = +let execBLTU (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = let x1 = mstate.getRegister rs1 let x2 = mstate.getRegister rs2 let branchCheck = match mstate.Arch.archBits with | RV32 -> uint32 x1 < uint32 x2 | _ -> uint64 x1 < uint64 x2 - let newPC = mstate.PC + imm12 + let newPC = mstate.PC + int64 imm12 if newPC % 4L <> 0L then mstate.setRunState (Trap BreakAddress) else if newPC = mstate.PC then @@ -100,7 +100,7 @@ let execBLTU (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : Ma //================================================= // BGEU - Branch If Greater or Equal (Unsigned) -let execBGEU (rs1 : Register) (rs2: Register) (imm12 : MachineInt) (mstate : MachineState) = +let execBGEU (rs1 : Register) (rs2: Register) (imm12 : InstrField) (mstate : MachineState) = let x1 = mstate.getRegister rs1 let x2 = mstate.getRegister rs2 let branchCheck = @@ -108,7 +108,7 @@ let execBGEU (rs1 : Register) (rs2: Register) (imm12 : MachineInt) (mstate : Mac | RV32 -> uint32 x1 >= uint32 x2 | _ -> uint64 x1 >= uint64 x2 - let newPC = mstate.PC + imm12 + let newPC = mstate.PC + int64 imm12 if newPC % 4L <> 0L then mstate.setRunState (Trap BreakAddress) else if newPC = mstate.PC then @@ -121,8 +121,8 @@ let execBGEU (rs1 : Register) (rs2: Register) (imm12 : MachineInt) (mstate : Mac //================================================= // LB - Load Byte from Memory -let execLB (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execLB (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let memResult = loadByte mstate.Memory addr if memResult.IsNone then mstate.setRunState (Trap (MemAddress addr)) @@ -132,8 +132,8 @@ let execLB (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : Machi //================================================= // LH - Load Half-word (2 bytes) from Memory -let execLH (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execLH (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let memResult = loadHalfWord mstate.Memory addr if memResult.IsNone then mstate.setRunState (Trap (MemAddress addr)) @@ -143,8 +143,8 @@ let execLH (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : Machi //================================================= // LW - Load Word (4 bytes) from Memory -let execLW (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execLW (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let memResult = loadWord mstate.Memory addr if memResult.IsNone then mstate.setRunState (Trap (MemAddress addr)) @@ -154,32 +154,32 @@ let execLW (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : Machi //================================================= // LBU - Load Byte Unsigned from Memory -let execLBU (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execLBU (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let memResult = loadByte mstate.Memory addr if memResult.IsNone then mstate.setRunState (Trap (MemAddress addr)) else let memVal = uint8 memResult.Value - let mstate = mstate.setRegister rd (int64 (uint8 memVal)) + let mstate = mstate.setRegister rd (int64 memVal) mstate.incPC //================================================= // LHU - Load Half-word (2 bytes) Unsigned from Memory -let execLHU (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execLHU (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let memResult = loadHalfWord mstate.Memory addr if memResult.IsNone then mstate.setRunState (Trap (MemAddress addr)) else let memVal = uint16 memResult.Value - let mstate = mstate.setRegister rd (int64 (uint16 memVal)) + let mstate = mstate.setRegister rd (int64 memVal) mstate.incPC //================================================= // SB - Store Byte to Memory -let execSB (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execSB (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let nBytes = 1 let rs2Val = mstate.getRegister rs2 Array.fold (fun (ms : MachineState) (addr, data) -> ms.setMemoryByte addr data) mstate @@ -187,8 +187,8 @@ let execSB (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : Mach //================================================= // SH - Store 2 Bytes (Hald word) to Memory -let execSH (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execSH (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let nBytes = 2 let rs2Val = mstate.getRegister rs2 Array.fold (fun (ms : MachineState) (addr, data) -> ms.setMemoryByte addr data) mstate @@ -196,8 +196,8 @@ let execSH (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : Mach //================================================= // SW - Store 4 Bytes (Word) to Memory -let execSW (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let addr = (mstate.getRegister rs1) + imm12 +let execSW (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 let nBytes = 4 let rs2Val = mstate.getRegister rs2 Array.fold (fun (ms : MachineState) (addr, data) -> ms.setMemoryByte addr data) mstate @@ -205,21 +205,21 @@ let execSW (rs1 : Register) (rs2 : Register) (imm12 : MachineInt) (mstate : Mach //================================================= // ADDI - Add immediate -let execADDI (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let rdVal = (mstate.getRegister rs1) + imm12 +let execADDI (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let rdVal = (mstate.getRegister rs1) + int64 imm12 let mstate = mstate.setRegister rd rdVal mstate.incPC //================================================= // SLTI - Set to 1 if Less Then Immediate -let execSLTI (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let rdVal = if (mstate.getRegister rs1) < imm12 then 1L else 0L +let execSLTI (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let rdVal = if (mstate.getRegister rs1) < int64 imm12 then 1L else 0L let mstate = mstate.setRegister rd rdVal mstate.incPC //================================================= // SLTIU - Set to 1 if Less Then Unsign Immediate -let execSLTIU (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = +let execSLTIU (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = let rdVal = match mstate.Arch.archBits with | RV32 -> if uint32(mstate.getRegister rs1) < uint32 imm12 then 1L else 0L @@ -229,28 +229,28 @@ let execSLTIU (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : Ma //================================================= // XORI - Xor immediately -let execXORI (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let rdVal = (mstate.getRegister rs1) ^^^ imm12 +let execXORI (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let rdVal = (mstate.getRegister rs1) ^^^ int64 imm12 let mstate = mstate.setRegister rd rdVal mstate.incPC //================================================= // ORI - Or immediately -let execORI (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let rdVal = (mstate.getRegister rs1) ||| imm12 - let mstate = mstate.setRegister rd rdVal +let execORI (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let rdVal = (mstate.getRegister rs1) ||| int64 imm12 + let mstate = mstate.setRegister rd (int64 rdVal) mstate.incPC //================================================= // SLLI - Shift Left Logical Immediate -let execSLLI (rd : Register) (rs1 : Register) (shamt : MachineInt) (mstate : MachineState) = +let execSLLI (rd : Register) (rs1 : Register) (shamt : InstrField) (mstate : MachineState) = let rdVal = (mstate.getRegister rs1) <<< int32 shamt let mstate = mstate.setRegister rd rdVal mstate.incPC //================================================= // SRLI - Shift Right Logical Immediate -let execSRLI (rd : Register) (rs1 : Register) (shamt : MachineInt) (mstate : MachineState) = +let execSRLI (rd : Register) (rs1 : Register) (shamt : InstrField) (mstate : MachineState) = let rdVal = match mstate.Arch.archBits with | RV32 -> int64(uint32(mstate.getRegister rs1) >>> int32 shamt) @@ -260,15 +260,15 @@ let execSRLI (rd : Register) (rs1 : Register) (shamt : MachineInt) (mstate : Mac //================================================= // SRAI - Shift Right Arithmetic Immediate -let execSRAI (rd : Register) (rs1 : Register) (shamt : MachineInt) (mstate : MachineState) = +let execSRAI (rd : Register) (rs1 : Register) (shamt : InstrField) (mstate : MachineState) = let rdVal = (mstate.getRegister rs1) >>> int32 shamt let mstate = mstate.setRegister rd rdVal mstate.incPC //================================================= // ANDI - And immediately -let execANDI (rd : Register) (rs1 : Register) (imm12 : MachineInt) (mstate : MachineState) = - let rdVal = (mstate.getRegister rs1) &&& imm12 +let execANDI (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let rdVal = (mstate.getRegister rs1) &&& int64 imm12 let mstate = mstate.setRegister rd rdVal mstate.incPC @@ -364,7 +364,7 @@ let execEBREAK (mstate : MachineState) = mstate.setRunState (Trap EBreak) // Execute I-instructions -let ExecuteI (instr : InstructionI) (mstate : MachineState) = +let Execute (instr : InstructionI) (mstate : MachineState) = match instr with | LUI i -> execLUI i.rd i.imm20 mstate @@ -446,4 +446,4 @@ let ExecuteI (instr : InstructionI) (mstate : MachineState) = execECALL mstate | EBREAK _ -> execEBREAK mstate - | _ -> mstate + | _ -> mstate.setRunState (Trap InstructionExecute) diff --git a/ExecuteI64.fs b/ExecuteI64.fs new file mode 100644 index 0000000..d425e20 --- /dev/null +++ b/ExecuteI64.fs @@ -0,0 +1,139 @@ +module ISA.RISCV.Execute.I64 + +open ISA.RISCV.Arch +open ISA.RISCV.Decode.I64 +open ISA.RISCV.MachineState +open ISA.RISCV.Utils.Bits + +//================================================= +// LWU - Load Word (4 bytes) Unsigned from Memory +let execLWU (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 + let memResult = loadWord mstate.Memory addr + if memResult.IsNone then + mstate.setRunState (Trap (MemAddress addr)) + else + let memVal = uint32 memResult.Value + let mstate = mstate.setRegister rd (int64 memVal) + mstate.incPC + +//================================================= +// LD - Load double Word (8 bytes) from Memory +let execLD (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 + let memResult = loadDouble mstate.Memory addr + if memResult.IsNone then + mstate.setRunState (Trap (MemAddress addr)) + else + let mstate = mstate.setRegister rd (int64 memResult.Value) + mstate.incPC + +//================================================= +// SD - Store double Word (8 bytes) to Memory +let execSD (rs1 : Register) (rs2 : Register) (imm12 : InstrField) (mstate : MachineState) = + let addr = (mstate.getRegister rs1) + int64 imm12 + let nBytes = 8 + let rs2Val = mstate.getRegister rs2 + Array.fold (fun (ms : MachineState) (addr, data) -> ms.setMemoryByte addr data) mstate + [| for i in 0..(nBytes-1) -> (addr+(int64 i), byte (rs2Val.bitSlice (i*8+7) (i*8) )) |] + +//================================================= +// ADDIW - Add immediate Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execADDIW (rd : Register) (rs1 : Register) (imm12 : InstrField) (mstate : MachineState) = + let rdVal = int32(mstate.getRegister rs1) + int32 imm12 + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// SLLIW - Shift Left Logical Immediate Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execSLLIW (rd : Register) (rs1 : Register) (shamt : InstrField) (mstate : MachineState) = + let rdVal = int32(mstate.getRegister rs1) <<< int32 shamt + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// SRLIW - Shift Right Logical Immediate Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execSRLIW (rd : Register) (rs1 : Register) (shamt : InstrField) (mstate : MachineState) = + let rdVal = int32(uint32(mstate.getRegister rs1) >>> int32 shamt) + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// SRAIW - Shift Right Arithmetic Immediate Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execSRAIW (rd : Register) (rs1 : Register) (shamt : InstrField) (mstate : MachineState) = + let rdVal = int32(mstate.getRegister rs1) >>> int32 shamt + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// ADDW - Add operation Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execADDW (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = + let rdVal = int32(mstate.getRegister rs1) + int32(mstate.getRegister rs2) + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// SUBW - Sub operation Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execSUBW (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = + let rdVal = int32(mstate.getRegister rs1) - int32(mstate.getRegister rs2) + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// SLLW - Shift Logical Left Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execSLLW (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = + let rdVal = int32(mstate.getRegister rs1) <<< int32(mstate.getRegister rs2) + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// SRLW - Shift Right Logical Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execSRLW (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = + let rdVal = int32(uint32(mstate.getRegister rs1) >>> int32(mstate.getRegister rs2)) + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +//================================================= +// SRAW - Shift Right Arithmetic Word +// Returns sign-extension to 64 bits of lower 32 bits of result. +let execSRAW (rd : Register) (rs1 : Register) (rs2 : Register) (mstate : MachineState) = + let rdVal = int32(mstate.getRegister rs1) >>> int32 (mstate.getRegister rs2) + let mstate = mstate.setRegister rd (int64 rdVal) + mstate.incPC + +// Execute I64-instructions +let Execute (instr : InstructionI64) (mstate : MachineState) = + match instr with + | LWU i -> + execLWU i.rd i.rs1 i.imm12 mstate + | LD i -> + execLD i.rd i.rs1 i.imm12 mstate + | SD i -> + execSD i.rs1 i.rs2 i.imm12 mstate + | ADDIW i -> + execADDIW i.rd i.rs1 i.imm12 mstate + | SLLIW i -> + execSLLIW i.rd i.rs1 i.shamt mstate + | SRLIW i -> + execSRLIW i.rd i.rs1 i.shamt mstate + | SRAIW i -> + execSRAIW i.rd i.rs1 i.shamt mstate + | ADDW i -> + execADDW i.rd i.rs1 i.rs2 mstate + | SUBW i -> + execSUBW i.rd i.rs1 i.rs2 mstate + | SLLW i -> + execSLLW i.rd i.rs1 i.rs2 mstate + | SRLW i -> + execSRLW i.rd i.rs1 i.rs2 mstate + | SRAW i -> + execSRAW i.rd i.rs1 i.rs2 mstate + | _ -> mstate.setRunState (Trap InstructionExecute) diff --git a/README.md b/README.md index 6357d05..0e8c963 100644 --- a/README.md +++ b/README.md @@ -24,17 +24,19 @@ Technical Group constituted by The RISC-V Foundation * [Install .NET SDK](#install-.net-sdk) * [Make the application executable](#make-the-application-executable) * [Run the application executable](#run-the-application-executable) +* [How to Contribute](#how-to-contribute) * [References](#references) * [Licence](#licence) ## Features & Current status * Supports the following features (or _in active development state_) - - [x] Base instruction sets: RV32I + - [x] Base instruction set: RV32I - [x] Tests RV32I - - [ ] Base instruction sets: RV64I - - [ ] Tests RV64I + - [x] Base instruction set: RV64I + - [x] Tests RV64I + - [ ] Standard extension M (integer multiply/divide) + - [ ] Tests for Standard extension M RV32/RV64 * Features under development - * Standard extension M (integer multiply/divide) * Standard extension A (atomic memory ops) * Standard extension C (Compressed 16-bit instructions) * Standard extension F (Single-precision floating point) @@ -176,6 +178,10 @@ output and ELF file for execution in RISC-V CPI simulator: `$ dotnet run -- -A rv32i -v myapp.elf` +## How to Contribute + +Please read file [CONTRIBUTING.md](CONTRIBUTING.md) + ## References * github ISA manual: https://github.com/riscv/riscv-isa-manual diff --git a/Run.fs b/Run.fs index 68a19dd..30be627 100644 --- a/Run.fs +++ b/Run.fs @@ -10,26 +10,6 @@ open ISA.RISCV.MachineState open ISA.RISCV.Utils.Bits open ISA.RISCV.Arch open ISA.RISCV.CLI -open ISA.RISCV.Decode - -// Print log message for current instruction step -let verbosityMessage (instr : InstrField) (decodedInstr : I.InstructionI) (mstate : MachineState) = - let typeName = decodedInstr.GetType().Name - let instrMsg = - match (decodedInstr) with - | I.LUI x | I.AUIPC x -> sprintf "x%d, 0x%08x" x.rd x.imm20 - | I.JAL x -> sprintf "x%d, 0x%08x\n" x.rd x.imm20 - | I.JALR x -> sprintf "x%d, x%d, 0x%08x\n" x.rd x.rs1 x.imm12 - | I.LB x | I.LH x | I.LW x | I.LBU x | I.LHU x | I.LB x | I.ADDI x | I.SLTI x | I.XORI x | I.ORI x | I.ANDI x -> sprintf "x%d, x%d, %d" x.rd x.rs1 x.imm12 - | I.BEQ x | I.BNE x | I.BLT x | I.BGE x | I.BLTU x | I.BGEU x | I.SB x | I.SH x | I.SW x -> sprintf "x%d, x%d, 0x%08x" x.rs1 x.rs2 x.imm12 - | I.SLLI x | I.SRLI x | I.SRAI x -> sprintf "x%d, x%d, %d" x.rd x.rs1 x.shamt - | I.ADD x | I.SUB x | I.SLL x | I.SLT x | I.SLTU x | I.XOR x | I.SRL x | I.SRA x | I.OR x | I.AND x -> sprintf "x%d, x%d, x%d" x.rd x.rs1 x.rs2 - | I.FENCE _ | I.EBREAK | I.ECALL -> "" - | _ -> "Undef" - let pc = sprintf "%08x:" mstate.PC - let instr = sprintf "%08x" instr - let instrMsg = String.Format("{0,-7}{1}", typeName, instrMsg) - printfn "%s" (String.Format("{0,-12}{1,-12}{2}", pc, instr, instrMsg)) // Get registers state let verbosityMessageRegisters (mstate : MachineState) = @@ -54,9 +34,12 @@ let readElfFile file = let elf = ELFReader.Load file Map.ofArray (Array.concat [| for s in elf.GetSections() -> getSectionContent s |]) +// Get instruction from current Machine State that related to +// current PC as memory address for loading instruction data for Decoding let fetchInstruction (mstate : MachineState) : InstrField option = loadWord mstate.Memory mstate.PC +// Basic RISC-V run life cycle. Represent Finite State Machine (FSM) let rec runCycle (mstate : MachineState) = let instr = fetchInstruction mstate @@ -64,15 +47,20 @@ let rec runCycle (mstate : MachineState) = match instr with | None -> mstate.setRunState (Trap (InstructionFetch mstate.PC)) | _ -> - let decodedInstr = I.DecodeI instr.Value + let instrValue = instr.Value + let executor = Decoder.Decode mstate instrValue - match decodedInstr with - | I.InstructionI.None -> mstate.setRunState (Trap TrapErrors.InstructionDecode) + match executor with + | None -> mstate.setRunState (Trap TrapErrors.InstructionDecode) | _ -> - if mstate.Verbosity then - verbosityMessage instr.Value decodedInstr mstate - - ExecuteI.ExecuteI decodedInstr mstate +// TODO: Change that logic +// if mstate.Verbosity then +// verbosityMessage instr.Value decodedInstr mstate + // Executor for specific Instruction Set + // that was detected in Decoder + let Executor = executor.Value + // Execute current Instruction + Executor mstate match mstate.RunState with | Trap _ -> mstate | RunMachineState.Stopped -> @@ -80,6 +68,7 @@ let rec runCycle (mstate : MachineState) = mstate | _ -> runCycle mstate +// Main application Run logic let Run (cfg : AppConfig) = let data = readElfFile cfg.Files.Value.[0] let mstate = InitMachineState data cfg.Arch.Value cfg.Verbosity.Value diff --git a/Tests/Tests.fsproj b/Tests/Tests.fsproj index 0bcb39e..30fa5b6 100644 --- a/Tests/Tests.fsproj +++ b/Tests/Tests.fsproj @@ -26,6 +26,14 @@ + + + + + + + + diff --git a/Tests/asm/Makefile b/Tests/asm/Makefile index ed26f07..0fbab4c 100644 --- a/Tests/asm/Makefile +++ b/Tests/asm/Makefile @@ -28,9 +28,9 @@ $(BUILDDIR)/%32: $(SRCDIR)/%.S init32.o mmio.ld $(RISCVCC32) -o $(BUILDDIR)/$*32 -Tmmio.ld intermediate32.o init32.o rm intermediate32.o -$(BUILDDIR)/%64: $(SRCDIR)/%.c init64.o mmio64.o mmio.ld +$(BUILDDIR)/%64: $(SRCDIR)/%.S init64.o mmio.ld mkdir -p $(BUILDDIR) - $(RISCVCC64) -c $(SRCDIR)/$*.c -o intermediate64.o + $(RISCVCC64) -c $(SRCDIR)/$*.S -o intermediate64.o $(RISCVCC64) -o $(BUILDDIR)/$*64 -Tmmio.ld intermediate64.o init64.o rm intermediate64.o diff --git a/Tests/asm/src/alu.S b/Tests/asm/src/alu.S index 47c9ef1..83a8635 100644 --- a/Tests/asm/src/alu.S +++ b/Tests/asm/src/alu.S @@ -11,4 +11,10 @@ main: sra x3, x2, x1 or x3, x2, x1 and x3, x2, x1 + # x64 + addw x3, x2, x1 + subw x3, x2, x1 + sllw x3, x2, x1 + srlw x3, x2, x1 + sraw x3, x2, x1 ret diff --git a/Tests/asm/src/alui.S b/Tests/asm/src/alui.S index 9d8f4b9..186999f 100644 --- a/Tests/asm/src/alui.S +++ b/Tests/asm/src/alui.S @@ -11,4 +11,9 @@ main: slli x3, x2, 5 srli x3, x2, 5 srai x3, x2, 5 + # x64 only + addiw x3, x2, 5 + slliw x3, x2, 5 + srliw x3, x2, 5 + sraiw x3, x2, 5 ret diff --git a/Tests/asm/src/mem.S b/Tests/asm/src/mem.S index 04e7371..f094c0a 100644 --- a/Tests/asm/src/mem.S +++ b/Tests/asm/src/mem.S @@ -7,11 +7,15 @@ main: lh x3, -10(x2) lw x3, 10(x2) lw x3, -10(x2) + ld x3, 10(x2) + ld x3, -10(x2) lbu x3, 10(x2) lbu x3, -10(x2) lhu x3, 10(x2) lhu x3, -10(x2) + lwu x3, 10(x2) + lwu x3, -10(x2) sb x3, 10(x2) sb x3, -10(x2) @@ -19,4 +23,7 @@ main: sh x3, -10(x2) sw x3, 10(x2) sw x3, -10(x2) + # x64 + sd x3, 10(x2) + sd x3, -10(x2) ret diff --git a/Tests/rv32i/alu.fs b/Tests/rv32i/alu.fs index f824051..5dd49cd 100644 --- a/Tests/rv32i/alu.fs +++ b/Tests/rv32i/alu.fs @@ -4,7 +4,6 @@ open Xunit open ISA.RISCV open ISA.RISCV.Arch -open ISA.RISCV.Decode //=============================================== // ALU tests @@ -16,9 +15,9 @@ let ALU instr x1 x2 x3 = let mstate = mstate.setRegister 1 x1 let mstate = mstate.setRegister 2 x2 - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate Assert.Equal(x1, mstate.getRegister 1) Assert.Equal(x2, mstate.getRegister 2) Assert.Equal(x3, mstate.getRegister 3) @@ -31,7 +30,7 @@ let ALU instr x1 x2 x3 = [] [] // Overflow let ``ADD: x3 = x2 + x1`` (x1, x2, x3) = - ALU 0x001101b3L x1 x2 x3 + ALU 0x001101b3 x1 x2 x3 [] [] @@ -43,13 +42,13 @@ let ``ADD: x3 = x2 + x1`` (x1, x2, x3) = [] [] // Overflow let ``SUB: x3 = x2 - x1`` (x1, x2, x3) = - ALU 0x401101b3L x1 x2 x3 + ALU 0x401101b3 x1 x2 x3 [] [] [] let ``SLL: x3 = x2 << x1`` (x1, x2, x3) = - ALU 0x001111b3L x1 x2 x3 + ALU 0x001111b3 x1 x2 x3 [] [] @@ -59,7 +58,7 @@ let ``SLL: x3 = x2 << x1`` (x1, x2, x3) = [] [] let ``SLT: x3 = x2 < x1`` (x1, x2, x3) = - ALU 0x001121b3L x1 x2 x3 + ALU 0x001121b3 x1 x2 x3 [] [] @@ -69,7 +68,7 @@ let ``SLT: x3 = x2 < x1`` (x1, x2, x3) = [] [] let ``SLTU: x3 = unsign x2 < unsign x1`` (x1, x2, x3) = - ALU 0x001131b3L x1 x2 x3 + ALU 0x001131b3 x1 x2 x3 [] [] @@ -78,20 +77,20 @@ let ``SLTU: x3 = unsign x2 < unsign x1`` (x1, x2, x3) = [] [] let ``XOR: x3 = x2 ^ x1`` (x1, x2, x3) = - ALU 0x001141b3L x1 x2 x3 + ALU 0x001141b3 x1 x2 x3 [] [] [] [] let ``SRL: x3 = x2 >> x1`` (x1, x2, x3) = - ALU 0x001151b3L x1 x2 x3 + ALU 0x001151b3 x1 x2 x3 [] [] [] let ``SRA: x3 = x2 >> x1`` (x1, x2, x3) = - ALU 0x401151b3L x1 x2 x3 + ALU 0x401151b3 x1 x2 x3 [] [] @@ -100,7 +99,7 @@ let ``SRA: x3 = x2 >> x1`` (x1, x2, x3) = [] [] let ``OR: x3 = x2 | x1`` (x1, x2, x3) = - ALU 0x001161b3L x1 x2 x3 + ALU 0x001161b3 x1 x2 x3 [] [] @@ -108,4 +107,4 @@ let ``OR: x3 = x2 | x1`` (x1, x2, x3) = [] [] let ``AND: x3 = x2 & x1`` (x1, x2, x3) = - ALU 0x001171b3L x1 x2 x3 + ALU 0x001171b3 x1 x2 x3 diff --git a/Tests/rv32i/alui.fs b/Tests/rv32i/alui.fs index 2ff3a2d..c44892d 100644 --- a/Tests/rv32i/alui.fs +++ b/Tests/rv32i/alui.fs @@ -4,7 +4,6 @@ open Xunit open ISA.RISCV open ISA.RISCV.Arch -open ISA.RISCV.Decode //=============================================== // ALU Immediate tests @@ -15,9 +14,9 @@ let ALUimmediate instr x2 x3 = let mstate = mstate.setPC addr let mstate = mstate.setRegister 2 x2 - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate Assert.Equal(x2, mstate.getRegister 2) Assert.Equal(x3, mstate.getRegister 3) Assert.Equal(addr + 4L, mstate.PC) @@ -27,7 +26,7 @@ let ALUimmediate instr x2 x3 = [] [] let ``ADDI: x3 = x2 + 5`` (x2, x3) = - ALUimmediate 0x00510193L x2 x3 + ALUimmediate 0x00510193 x2 x3 [] [] @@ -38,7 +37,7 @@ let ``ADDI: x3 = x2 + 5`` (x2, x3) = [] [] let ``SLTI: x3 = x2 < 5`` (x2, x3) = - ALUimmediate 0x00512193L x2 x3 + ALUimmediate 0x00512193 x2 x3 [] [] @@ -49,7 +48,7 @@ let ``SLTI: x3 = x2 < 5`` (x2, x3) = [] [] let ``SLTIU: x3 = unsign x2 < unsign 5`` (x2, x3) = - ALUimmediate 0x00513193L x2 x3 + ALUimmediate 0x00513193 x2 x3 [] [] @@ -58,7 +57,7 @@ let ``SLTIU: x3 = unsign x2 < unsign 5`` (x2, x3) = [] [] let ``XORI: x3 = x2 ^ 5 (b101)`` (x2, x3) = - ALUimmediate 0x00514193L x2 x3 + ALUimmediate 0x00514193 x2 x3 [] [] @@ -67,7 +66,7 @@ let ``XORI: x3 = x2 ^ 5 (b101)`` (x2, x3) = [] [] let ``ORI: x3 = x2 | 5 (b101)`` (x2, x3) = - ALUimmediate 0x00516193L x2 x3 + ALUimmediate 0x00516193 x2 x3 [] [] @@ -75,23 +74,23 @@ let ``ORI: x3 = x2 | 5 (b101)`` (x2, x3) = [] [] let ``ANDI: x3 = x2 & 5 (b101)`` (x2, x3) = - ALUimmediate 0x00517193L x2 x3 + ALUimmediate 0x00517193 x2 x3 [] [] [] let ``SLLI: x3 = x2 << 5 (b101)`` (x2, x3) = - ALUimmediate 0x00511193L x2 x3 + ALUimmediate 0x00511193 x2 x3 [] [] [] [] let ``SRLI: x3 = x2 >> 5 (b101)`` (x2, x3) = - ALUimmediate 0x00515193L x2 x3 + ALUimmediate 0x00515193 x2 x3 [] [] [] let ``SRAI: x3 = x2 >> 5 (b101)`` (x2, x3) = - ALUimmediate 0x40515193L x2 x3 + ALUimmediate 0x40515193 x2 x3 diff --git a/Tests/rv32i/br.fs b/Tests/rv32i/br.fs index c0a5497..13977ab 100644 --- a/Tests/rv32i/br.fs +++ b/Tests/rv32i/br.fs @@ -4,7 +4,6 @@ open Xunit open ISA.RISCV open ISA.RISCV.Arch -open ISA.RISCV.Decode //=============================================== // Branch tests @@ -16,9 +15,9 @@ let Branch instr x1 x2 resultAddr = let mstate = mstate.setRegister 1 x1 let mstate = mstate.setRegister 2 x2 - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate Assert.Equal(x1, mstate.getRegister 1) Assert.Equal(x2, mstate.getRegister 2) Assert.Equal(resultAddr, mstate.PC) diff --git a/Tests/rv32i/j.fs b/Tests/rv32i/j.fs index e15bb6f..fa7cb78 100644 --- a/Tests/rv32i/j.fs +++ b/Tests/rv32i/j.fs @@ -4,7 +4,6 @@ open Xunit open ISA.RISCV open ISA.RISCV.Arch -open ISA.RISCV.Decode open ISA.RISCV.MachineState //=============================================== @@ -17,9 +16,9 @@ let Jump instr x2 x3 resultAddr = let mstate = mstate.setRegister 2 x2 let resMstate = mstate.incPC - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate Assert.Equal(int64 (int32 x2), mstate.getRegister 2) let pcs = mstate.setPC (mstate.getRegister 3) @@ -36,4 +35,4 @@ let ``JAL: x3, addr`` (instr, addrRes) = [] [] let ``JALR: x3, x2, addr`` (instr, x2, addrRes) = - Jump instr x2 3L addrRes \ No newline at end of file + Jump instr x2 3L addrRes diff --git a/Tests/rv32i/mem.fs b/Tests/rv32i/mem.fs index bb6af3b..f61f412 100644 --- a/Tests/rv32i/mem.fs +++ b/Tests/rv32i/mem.fs @@ -4,7 +4,6 @@ open Xunit open ISA.RISCV open ISA.RISCV.Arch -open ISA.RISCV.Decode open ISA.RISCV.Utils //=============================================== @@ -35,9 +34,9 @@ let loadMemory instr x2 imm nBytes unsign = let mstate = mstate.setMemoryByte (memAddr+2L) 0xb2uy (mstate.setMemoryByte (memAddr+3L) 0xc3uy, int64(0xc3b2a10fl)) - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate Assert.Equal(x2, mstate.getRegister 2) Assert.Equal(resNumber, mstate.getRegister 3) @@ -50,20 +49,20 @@ let storeMemory instr x3 x2 imm nBytes = let mstate = mstate.setRegister 2 x2 let mstate = mstate.setRegister 3 x3 - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) // Get memory value let memAddr = x2 + imm - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let mstate = executor.Value mstate let memoryRes = match nBytes with | 1 -> // 1 bytes - (int64(int8((Bits.loadByte mstate.Memory memAddr).Value))) + int64(int8((Bits.loadByte mstate.Memory memAddr).Value)) | 2 -> // 2 bytes int64((Bits.loadHalfWord mstate.Memory memAddr).Value) | _ -> // 4 bytes - (int64(int32((Bits.loadWord mstate.Memory memAddr).Value))) + int64((Bits.loadWord mstate.Memory memAddr).Value) Assert.Equal(x2, mstate.getRegister 2) Assert.Equal(x3, mstate.getRegister 3) diff --git a/Tests/rv32i/sys.fs b/Tests/rv32i/sys.fs index cf7d8da..4dcfadc 100644 --- a/Tests/rv32i/sys.fs +++ b/Tests/rv32i/sys.fs @@ -4,7 +4,6 @@ open Xunit open ISA.RISCV open ISA.RISCV.Arch -open ISA.RISCV.Decode open ISA.RISCV.MachineState //=============================================== @@ -16,9 +15,9 @@ let System instr trap = let mstate = mstate.setPC addr let newmstate = mstate.incPC - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate if trap then Assert.Equal(addr, mstate.PC) diff --git a/Tests/rv32i/ui.fs b/Tests/rv32i/ui.fs index e92170c..f02cb52 100644 --- a/Tests/rv32i/ui.fs +++ b/Tests/rv32i/ui.fs @@ -4,7 +4,6 @@ open Xunit open ISA.RISCV open ISA.RISCV.Arch -open ISA.RISCV.Decode //=============================================== // Upper immediate tests @@ -14,9 +13,9 @@ let Ui instr x3 = let mstate = MachineState.InitMachineState Map.empty RV32i true let mstate = mstate.setPC addr - let decodedInstr = I.DecodeI instr - Assert.NotEqual(decodedInstr, I.None) - let mstate = ExecuteI.ExecuteI decodedInstr mstate + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate Assert.Equal(x3, mstate.getRegister 3) [] diff --git a/Tests/rv64i/alu.fs b/Tests/rv64i/alu.fs new file mode 100644 index 0000000..4f9ec3d --- /dev/null +++ b/Tests/rv64i/alu.fs @@ -0,0 +1,169 @@ +module Tests.rv64i.alu + +open Xunit + +open ISA.RISCV +open ISA.RISCV.Arch + +//=============================================== +// ALU tests +let ALU instr x1 x2 x3 = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV64i true + let mstate = mstate.setPC addr + let mstate = mstate.setRegister 1 x1 + let mstate = mstate.setRegister 2 x2 + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate + Assert.Equal(x1, mstate.getRegister 1) + Assert.Equal(x2, mstate.getRegister 2) + Assert.Equal(x3, mstate.getRegister 3) + Assert.Equal(addr + 4L, mstate.PC) + +[] +[] +[] +[] +[] +[] // Overflow +let ``ADD: x3 = x2 + x1`` (x1, x2, x3) = + ALU 0x001101b3 x1 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +[] +[] // Overflow +let ``SUB: x3 = x2 - x1`` (x1, x2, x3) = + ALU 0x401101b3 x1 x2 x3 + +[] +[] +[] +[] +[] +let ``SLL: x3 = x2 << x1`` (x1, x2, x3) = + ALU 0x001111b3 x1 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +let ``SLT: x3 = x2 < x1`` (x1, x2, x3) = + ALU 0x001121b3 x1 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +let ``SLTU: x3 = unsign x2 < unsign x1`` (x1, x2, x3) = + ALU 0x001131b3 x1 x2 x3 + +[] +[] +[] +[] +[] +[] +let ``XOR: x3 = x2 ^ x1`` (x1, x2, x3) = + ALU 0x001141b3 x1 x2 x3 + +[] +[] +[] +[] +[] +[] +let ``SRL: x3 = x2 >> x1`` (x1, x2, x3) = + ALU 0x001151b3 x1 x2 x3 + +[] +[] +[] +[] +[] +let ``SRA: x3 = x2 >> x1`` (x1, x2, x3) = + ALU 0x401151b3 x1 x2 x3 + +[] +[] +[] +[] +[] +[] +let ``OR: x3 = x2 | x1`` (x1, x2, x3) = + ALU 0x001161b3 x1 x2 x3 + +[] +[] +[] +[] +[] +let ``AND: x3 = x2 & x1`` (x1, x2, x3) = + ALU 0x001171b3 x1 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``ADDW: x3 = x2 + x1`` (x1, x2, x3) = + ALU 0x001101bb x1 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``SUBW: x3 = x2 - x1`` (x1, x2, x3) = + ALU 0x401101bb x1 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +let ``SLLW: x3 = x2 << x1`` (x1, x2, x3) = + ALU 0x001111bb x1 x2 x3 + +[] +[] +[] +[] +[] +[] +let ``SRLW: x3 = x2 >> x1`` (x1, x2, x3) = + ALU 0x001151bb x1 x2 x3 + +[] +[] +[] +[] +[] +let ``SRAW: x3 = x2 >> x1`` (x1, x2, x3) = + ALU 0x401151bb x1 x2 x3 diff --git a/Tests/rv64i/alui.fs b/Tests/rv64i/alui.fs new file mode 100644 index 0000000..4b13f4a --- /dev/null +++ b/Tests/rv64i/alui.fs @@ -0,0 +1,132 @@ +module Tests.rv64i.alui + +open Xunit + +open ISA.RISCV +open ISA.RISCV.Arch + +//=============================================== +// ALU Immediate Word tests +let ALUimmediate instr x2 x3 = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV64i true + let mstate = mstate.setPC addr + let mstate = mstate.setRegister 2 x2 + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate + Assert.Equal(x2, mstate.getRegister 2) + Assert.Equal(x3, mstate.getRegister 3) + Assert.Equal(addr + 4L, mstate.PC) + +[] +[] +[] +[] +let ``ADDI: x3 = x2 + 5`` (x2, x3) = + ALUimmediate 0x00510193 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +[] +let ``SLTI: x3 = x2 < 5`` (x2, x3) = + ALUimmediate 0x00512193 x2 x3 + +[] +[] +[] +[] +[] +[] +[] +[] +let ``SLTIU: x3 = unsign x2 < unsign 5`` (x2, x3) = + ALUimmediate 0x00513193 x2 x3 + +[] +[] +[] +[] +[] +[] +let ``XORI: x3 = x2 ^ 5 (b101)`` (x2, x3) = + ALUimmediate 0x00514193 x2 x3 + +[] +[] +[] +[] +[] +[] +let ``ORI: x3 = x2 | 5 (b101)`` (x2, x3) = + ALUimmediate 0x00516193 x2 x3 + +[] +[] +[] +[] +[] +let ``ANDI: x3 = x2 & 5 (b101)`` (x2, x3) = + ALUimmediate 0x00517193 x2 x3 + +[] +[] +[] +[] +[] +let ``SLLI: x3 = x2 << 5 (b101)`` (x2, x3) = + ALUimmediate 0x00511193 x2 x3 + +[] +[] +[] +[] +[] +[] +let ``SRLI: x3 = x2 >> 5 (b101)`` (x2 : int64, x3 : int64) = + ALUimmediate 0x00515193 x2 x3 + +[] +[] +[] +[] +[] +let ``SRAI: x3 = x2 >> 5 (b101)`` (x2, x3) = + ALUimmediate 0x40515193 x2 x3 + +[] +[] +[] +[] +let ``ADDIW: x3 = x2 + 5`` (x2 : int64, x3 : int64) = + ALUimmediate 0x0051019b x2 x3 + +[] +[] +[] +[] +[] +let ``SLLIW: x3 = x2 << 5 (b101)`` (x2, x3) = + ALUimmediate 0x0051119b x2 x3 + +[] +[] +[] +[] +[] +let ``SRLIW: x3 = x2 >> 5 (b101)`` (x2 : int64, x3 : int64) = + ALUimmediate 0x0051519b x2 x3 + +[] +[] +[] +[] +let ``SRAIW: x3 = x2 >> 5 (b101)`` (x2, x3) = + ALUimmediate 0x4051519b x2 x3 diff --git a/Tests/rv64i/br.fs b/Tests/rv64i/br.fs new file mode 100644 index 0000000..254077a --- /dev/null +++ b/Tests/rv64i/br.fs @@ -0,0 +1,117 @@ +module Tests.rv64i.br + +open Xunit + +open ISA.RISCV +open ISA.RISCV.Arch + +//=============================================== +// Branch tests +let Branch instr x1 x2 resultAddr = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV64i true + let mstate = mstate.setPC addr + let mstate = mstate.setRegister 1 x1 + let mstate = mstate.setRegister 2 x2 + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate + Assert.Equal(x1, mstate.getRegister 1) + Assert.Equal(x2, mstate.getRegister 2) + Assert.Equal(resultAddr, mstate.PC) + +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``BEQ: x1 == x2`` (instr, x1, x2, addrRes) = + Branch instr x1 x2 addrRes + +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``BNE: x1 <> x2`` (instr, x1, x2, addrRes) = + Branch instr x1 x2 addrRes + +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``BLT: x1 < x2`` (instr, x1, x2, addrRes) = + Branch instr x1 x2 addrRes + +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``BGE: x1 >= x2`` (instr, x1, x2, addrRes) = + Branch instr x1 x2 addrRes + +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``BLTU: x1 < x2`` (instr, x1, x2, addrRes) = + Branch instr x1 x2 addrRes + +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``BGEU: x1 >= x2`` (instr, x1, x2, addrRes) = + Branch instr x1 x2 addrRes diff --git a/Tests/rv64i/j.fs b/Tests/rv64i/j.fs new file mode 100644 index 0000000..3f7e81c --- /dev/null +++ b/Tests/rv64i/j.fs @@ -0,0 +1,38 @@ +module Tests.rv64i.j + +open Xunit + +open ISA.RISCV +open ISA.RISCV.Arch +open ISA.RISCV.MachineState + +//=============================================== +// Jump tests +let Jump instr x2 x3 resultAddr = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV64i true + let mstate = mstate.setPC addr + let mstate = mstate.setRegister 2 x2 + let resMstate = mstate.incPC + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate + + Assert.Equal(x2, mstate.getRegister 2) + let pcs = mstate.setPC (mstate.getRegister 3) + Assert.Equal(resMstate.PC, pcs.PC) + Assert.Equal(resultAddr, mstate.PC) + +[] +[] +[] +let ``JAL: x3, addr`` (instr, addrRes) = + Jump instr 0L 3L addrRes + +[] +[] +[] +let ``JALR: x3, x2, addr`` (instr, x2, addrRes) = + Jump instr x2 3L addrRes \ No newline at end of file diff --git a/Tests/rv64i/mem.fs b/Tests/rv64i/mem.fs new file mode 100644 index 0000000..83fe452 --- /dev/null +++ b/Tests/rv64i/mem.fs @@ -0,0 +1,147 @@ +module Tests.rv64i.mem + +open Xunit + +open ISA.RISCV +open ISA.RISCV.Arch +open ISA.RISCV.Utils + +//=============================================== +// Memory tests + +// Load from memory instructions +let loadMemory instr x2 imm nBytes unsign = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV64i true + let mstate = mstate.setPC addr + let mstate = mstate.setRegister 2 x2 + + // Set memory value + let memAddr = x2 + imm + let (mstate, resNumber) = + match nBytes with + | 1 -> // 1 bytes + let data = if unsign then int64(0x85uy) else int64(0x85y) + (mstate.setMemoryByte memAddr 0x85uy, data) + | 2 -> // 2 bytes + let data = if unsign then int64(0xa10fus) else int64(0xa10fs) + let mstate = mstate.setMemoryByte memAddr 0x0fuy + (mstate.setMemoryByte (memAddr+1L) 0xa1uy, data) + | 4 -> + let data = if unsign then int64(0xc3b2a10fu) else int64(0xc3b2a10fl) + let mstate = mstate.setMemoryByte memAddr 0x0fuy + let mstate = mstate.setMemoryByte (memAddr+1L) 0xa1uy + let mstate = mstate.setMemoryByte (memAddr+2L) 0xb2uy + (mstate.setMemoryByte (memAddr+3L) 0xc3uy, data) + | _ -> // 8 bytes + let mstate = mstate.setMemoryByte memAddr 0x0fuy + let mstate = mstate.setMemoryByte (memAddr+1L) 0xa1uy + let mstate = mstate.setMemoryByte (memAddr+2L) 0xb2uy + let mstate = mstate.setMemoryByte (memAddr+3L) 0xb3uy + let mstate = mstate.setMemoryByte (memAddr+4L) 0xb4uy + let mstate = mstate.setMemoryByte (memAddr+5L) 0xb5uy + let mstate = mstate.setMemoryByte (memAddr+6L) 0xb6uy + (mstate.setMemoryByte (memAddr+7L) 0xc3uy, 0xc3b6b5b4b3b2a10fL) + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate + Assert.Equal(x2, mstate.getRegister 2) + Assert.Equal(resNumber, mstate.getRegister 3) + +// Store to memory instructions +let storeMemory instr x3 x2 imm nBytes = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV32i true + let mstate = mstate.setPC addr + let mstate = mstate.setRegister 2 x2 + let mstate = mstate.setRegister 3 x3 + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + + // Get memory value + let memAddr = x2 + imm + let mstate = executor.Value mstate + let memoryRes = + match nBytes with + | 1 -> // 1 bytes + int64(int8((Bits.loadByte mstate.Memory memAddr).Value)) + | 2 -> // 2 bytes + int64((Bits.loadHalfWord mstate.Memory memAddr).Value) + | 4 -> // 4 bytes + int64((Bits.loadWord mstate.Memory memAddr).Value) + | _ -> // 8 bytes + int64((Bits.loadDouble mstate.Memory memAddr).Value) + + Assert.Equal(x2, mstate.getRegister 2) + Assert.Equal(x3, mstate.getRegister 3) + Assert.Equal(memoryRes, x3) + +[] +[] +[] +let ``LB: x3, Imm(x2)`` (instr, x2, imm) = + loadMemory instr x2 imm 1 false + +[] +[] +[] +let ``LH: x3, Imm(x2)`` (instr, x2, imm) = + loadMemory instr x2 imm 2 false + +[] +[] +[] +let ``LW: x3, Imm(x2)`` (instr, x2, imm) = + loadMemory instr x2 imm 4 false + +[] +[] +[] +let ``LD: x3, Imm(x2)`` (instr, x2, imm) = + loadMemory instr x2 imm 8 false + +[] +[] +[] +let ``LBU: x3, Imm(x2)`` (instr, x2, imm) = + loadMemory instr x2 imm 1 true + +[] +[] +[] +let ``LHU: x3, Imm(x2)`` (instr, x2, imm) = + loadMemory instr x2 imm 2 true + +[] +[] +[] +let ``LWU: x3, Imm(x2)`` (instr, x2, imm) = + loadMemory instr x2 imm 4 true + +[] +[] +[] +let ``SB: x3, Imm(x2)`` (instr, x3, x2, imm) = + storeMemory instr x3 x2 imm 1 + +[] +[] +[] +let ``SH: x3, Imm(x2)`` (instr, x3, x2, imm) = + storeMemory instr x3 x2 imm 2 + +[] +[] +[] +let ``SW: x3, Imm(x2)`` (instr, x3, x2, imm) = + storeMemory instr x3 x2 imm 4 + +[] +[] +[] +let ``SD: x3, Imm(x2)`` (instr, x3, x2, imm) = + storeMemory instr x3 x2 imm 8 diff --git a/Tests/rv64i/sys.fs b/Tests/rv64i/sys.fs new file mode 100644 index 0000000..ee92eb8 --- /dev/null +++ b/Tests/rv64i/sys.fs @@ -0,0 +1,45 @@ +module Tests.rv64i.sys + +open Xunit + +open ISA.RISCV +open ISA.RISCV.Arch +open ISA.RISCV.MachineState + +//=============================================== +// System tests +let System instr trap = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV64i true + let mstate = mstate.setPC addr + let newmstate = mstate.incPC + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate + + if trap then + Assert.Equal(addr, mstate.PC) + else + Assert.Equal(newmstate.PC, mstate.PC) + mstate + +[] +[] +let ``FENCE`` (instr) = + let mstate = System instr false + Assert.Equal(NotRun, mstate.RunState) + +[] +[] +let ``ECALL`` (instr) = + let mstate = System instr true + Assert.Equal(Trap TrapErrors.ECall, mstate.RunState) + + +[] +[] +let ``EBREAK`` (instr) = + let mstate = System instr true + Assert.Equal(Trap TrapErrors.EBreak, mstate.RunState) diff --git a/Tests/rv64i/ui.fs b/Tests/rv64i/ui.fs new file mode 100644 index 0000000..cde51de --- /dev/null +++ b/Tests/rv64i/ui.fs @@ -0,0 +1,35 @@ +module Tests.rv64i.ui + +open Xunit + +open ISA.RISCV +open ISA.RISCV.Arch + +//=============================================== +// Upper immediate tests +let Ui instr x3 = + // Init MachineState + let addr = 0x80000000L + let mstate = MachineState.InitMachineState Map.empty RV64i true + let mstate = mstate.setPC addr + + let executor = Decoder.Decode mstate instr + Assert.NotEqual(executor, None) + let mstate = executor.Value mstate + Assert.Equal(x3, mstate.getRegister 3) + +[] +[] +[] +[] +[] +[] +let ``LUI: x3, imm20`` (instr, x3) = + Ui instr x3 + +[] +[] +[] +[] +let ``AUIPC: x3, imm20`` (instr, x3) = + Ui instr x3 diff --git a/risc-v.fsproj b/risc-v.fsproj index 2b7494a..60abef6 100644 --- a/risc-v.fsproj +++ b/risc-v.fsproj @@ -26,10 +26,13 @@ Additionally it's possible to operate with CLI, reading ELF files and set verbos - + + + +