diff options
Diffstat (limited to 'risc-v/riscv.sail')
| -rw-r--r-- | risc-v/riscv.sail | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/risc-v/riscv.sail b/risc-v/riscv.sail new file mode 100644 index 00000000..4a80adb0 --- /dev/null +++ b/risc-v/riscv.sail @@ -0,0 +1,320 @@ +default Order dec + +typedef regval = bit[64] +typedef regno = bit[5] + +register (regval) x0 +register (regval) x1 +register (regval) x2 +register (regval) x3 +register (regval) x4 +register (regval) x5 +register (regval) x6 +register (regval) x7 +register (regval) x8 +register (regval) x9 +register (regval) x10 +register (regval) x11 +register (regval) x12 +register (regval) x13 +register (regval) x14 +register (regval) x15 +register (regval) x16 +register (regval) x17 +register (regval) x18 +register (regval) x19 +register (regval) x20 +register (regval) x21 +register (regval) x22 +register (regval) x23 +register (regval) x24 +register (regval) x25 +register (regval) x26 +register (regval) x27 +register (regval) x28 +register (regval) x29 +register (regval) x30 +register (regval) x31 + +register (bit[64]) PC +register (bit[64]) nextPC + +let (vector <0, 32, inc, (register<(regval)>)>) GPRs = + [x0, x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20,x21,x22,x23,x24,x25,x26,x27,x28,x29,x30,x31] + +function (regval) rGPR ((regno) r) = + if (r == 0) then + 0 + else + GPRs[r] + +function unit wGPR((regno) r, (regval) v) = + if (r != 0) then + GPRs[r] := v + +function forall 'a. 'a effect { escape } not_implemented((string) message) = +{ + exit message; +} + +val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval +val extern unit -> unit effect { barr } MEM_fence_rw_rw +val extern unit -> unit effect { barr } MEM_fence_r_rw +val extern unit -> unit effect { barr } MEM_fence_rw_w + +(* Ideally these would be sail builtin *) +function (bit[64]) shift_right_arith64 ((bit[64]) v, (bit[6]) shift) = + let (bit[128]) v128 = EXTS(v) in + (v128 >> shift)[63..0] + +function (bit[32]) shift_right_arith32 ((bit[32]) v, (bit[5]) shift) = + let (bit[64]) v64 = EXTS(v) in + (v64 >> shift)[31..0] + +typedef uop = enumerate {LUI; AUIPC} (* upper immediate ops *) +typedef bop = enumerate {BEQ; BNE; BLT; BGE; BLTU; BGEU} (* branch ops *) +typedef iop = enumerate {ADDI; SLTI; SLTIU; XORI; ORI; ANDI} (* immediate ops *) +typedef sop = enumerate {SLLI; SRLI; SRAI} (* shift ops *) +typedef rop = enumerate {ADD; SUB; SLL; SLT; SLTU; XOR; SRL; SRA; OR; AND} (* reg-reg ops *) +typedef ropw = enumerate {ADDW; SUBW; SLLW; SRLW; SRAW} (* reg-reg 32-bit ops *) + +typedef word_width = enumerate {BYTE; HALF; WORD; DOUBLE} + +scattered function unit execute +scattered typedef ast = const union + +val bit[32] -> option<ast> effect pure decode + +scattered function option<ast> decode + +union ast member ((bit[20]), regno, uop) UTYPE + +function clause decode ((bit[20]) imm : (regno) rd : 0b0110111) = Some(UTYPE(imm, rd, LUI)) +function clause decode ((bit[20]) imm : (regno) rd : 0b0010111) = Some(UTYPE(imm, rd, AUIPC)) + +function clause execute (UTYPE(imm, rd, op)) = + let (bit[64]) off = EXTS(imm : 0x000) in + let ret = switch (op) { + case LUI -> off + case AUIPC -> PC + off + } in + wGPR(rd, ret) + +union ast member ((bit[21]), regno) JAL +function clause decode ((bit[20]) imm : (regno) rd : 0b1101111) = Some (JAL(imm[19] : imm[7..0] : imm[8] : imm[18..13] : imm[12..9] : 0b0, rd)) +function clause execute (JAL(imm, rd)) = + let (bit[64]) offset = EXTS(imm) in { + nextPC := PC + offset; + wGPR(rd, PC + 4); + } + +union ast member((bit[12]), regno, regno) JALR +function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b1100111) = + Some(JALR(imm, rs1, rd)) +function clause execute (JALR(imm, rs1, rd)) = + let (bit[64]) newPC = rGPR(rs1) + EXTS(imm) in { + nextPC := newPC[63..1] : 0b0; + wGPR(rd, PC + 4); + } + +union ast member ((bit[13]), regno, regno, bop) BTYPE +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b000 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BEQ)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b001 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BNE)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b100 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BLT)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b101 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BGE)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b110 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BLTU)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b111 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BGEU)) + +function clause execute (BTYPE(imm, rs2, rs1, op)) = + let rs1_val = rGPR(rs1) in + let rs2_val = rGPR(rs2) in + let taken = switch(op) { + case BEQ -> rs1_val == rs2_val + case BNE -> rs1_val != rs2_val + case BLT -> rs1_val <_s rs2_val + case BGE -> rs1_val >=_s rs2_val + case BLTU -> rs1_val <_u rs2_val + case BGEU -> unsigned(rs1_val) >= unsigned(rs2_val) (* XXX sail missing >=_u *) + } in + if (taken) then + nextPC := PC + EXTS(imm) + +union ast member ((bit[12]), regno, regno, iop) ITYPE +function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, ADDI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b010 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, SLTI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b011 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, SLTIU)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b100 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, XORI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b110 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, ORI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b111 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, ANDI)) +function clause execute (ITYPE (imm, rs1, rd, op)) = + let rs1_val = rGPR(rs1) in + let imm64 = (bit[64]) (EXTS(imm)) in + let (bit[64]) result = switch(op) { + case ADDI -> rs1_val + imm64 + case SLTI -> EXTZ(rs1_val <_s imm64) + case SLTIU -> EXTZ(rs1_val <_u imm64) + case XORI -> rs1_val ^ imm64 + case ORI -> rs1_val | imm64 + case ANDI -> rs1_val & imm64 + } in + wGPR(rd, result) + +union ast member ((bit[6]), regno, regno, sop) SHIFTIOP +function clause decode (0b000000 : (bit[6]) shamt : (regno) rs1 : 0b001 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, SLLI)) +function clause decode (0b000000 : (bit[6]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, SRLI)) +function clause decode (0b010000 : (bit[6]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, SRAI)) +function clause execute (SHIFTIOP(shamt, rs1, rd, op)) = + let rs1_val = rGPR(rs1) in + let result = switch(op) { + case SLLI -> rs1_val >> shamt + case SRLI -> rs1_val << shamt + case SRAI -> shift_right_arith64(rs1_val, shamt) + } in + wGPR(rd, result) + +union ast member (regno, regno, regno, rop) RTYPE +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, ADD)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SUB)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b001 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SLL)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SLT)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SLTU)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b100 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, XOR)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SRL)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SRA)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b110 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, OR)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b111 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, AND)) +function clause execute (RTYPE(rs2, rs1, rd, op)) = + let rs1_val = rGPR(rs1) in + let rs2_val = rGPR(rs2) in + let (bit[64]) result = switch(op) { + case ADD -> rs1_val + rs2_val + case SUB -> rs1_val - rs2_val + case SLL -> rs1_val << (rs2_val[5..0]) + case SLT -> EXTZ(rs1_val <_s rs2_val) + case SLTU -> EXTZ(rs1_val <_u rs2_val) + case XOR -> rs1_val ^ rs2_val + case SRL -> rs1_val >> (rs2_val[5..0]) + case SRA -> shift_right_arith64(rs1_val, rs2_val[5..0]) + case OR -> rs1_val | rs2_val + case AND -> rs1_val & rs2_val + } in + wGPR(rd, result) + +union ast member ((bit[12]), regno, regno, bool, word_width) LOAD +function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, BYTE)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b001 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, HALF)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b010 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, WORD)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b011 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, DOUBLE)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b100 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, BYTE)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b101 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, HALF)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b110 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, WORD)) +function clause execute(LOAD(imm, rs1, rd, unsigned, width)) = + let (bit[64]) addr = rGPR(rs1) + EXTS(imm) in + let (bit[64]) result = if unsigned then + switch (width) { + case BYTE -> EXTZ(MEMr(addr, 1)) + case HALF -> EXTZ(MEMr(addr, 2)) + case WORD -> EXTZ(MEMr(addr, 4)) + case DOUBLE -> MEMr(addr, 8) + } + else + switch (width) { + case BYTE -> EXTS(MEMr(addr, 1)) + case HALF -> EXTS(MEMr(addr, 2)) + case WORD -> EXTS(MEMr(addr, 4)) + case DOUBLE -> MEMr(addr, 8) + } in + wGPR(rd, result) + +union ast member ((bit[12]), regno, regno, word_width) STORE +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b000 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, BYTE)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b001 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, HALF)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b010 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, WORD)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b011 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, DOUBLE)) +function clause execute (STORE(imm, rs2, rs1, width)) = + let (bit[64]) addr = rGPR(rs1) + EXTS(imm) in { + switch (width) { + case BYTE -> MEMea(addr, 1) + case HALF -> MEMea(addr, 2) + case WORD -> MEMea(addr, 4) + case DOUBLE -> MEMea(addr, 8) + }; + let rs2_val = rGPR(rs2) in + switch (width) { + case BYTE -> MEMval(addr, 1, rs2_val[7..0]) + case HALF -> MEMval(addr, 2, rs2_val[15..0]) + case WORD -> MEMval(addr, 4, rs2_val[31..0]) + case DOUBLE -> MEMval(addr, 8, rs2_val) + } + } + +union ast member ((bit[12]), regno, regno) ADDIW +function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0011011) = Some(ADDIW(imm, rs1, rd)) +function clause execute (ADDIW(imm, rs1, rd)) = + let (bit[64]) imm64 = EXTS(imm) in + let (bit[64]) result64 = imm64 + rGPR(rs1) in + let (bit[64]) result32 = EXTS(result64[31..0]) in + wGPR(rd, result32) + +union ast member ((bit[5]), regno, regno, sop) SHIFTW +function clause decode (0b0000000 : (bit[5]) shamt : (regno) rs1 : 0b001 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, SLLI)) +function clause decode (0b0000000 : (bit[5]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, SRLI)) +function clause decode (0b0100000 : (bit[5]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, SRAI)) +function clause execute (SHIFTW(shamt, rs1, rd, op)) = + let rs1_val = (rGPR(rs1))[31..0] in + let result = switch(op) { + case SLLI -> rs1_val >> shamt + case SRLI -> rs1_val << shamt + case SRAI -> shift_right_arith32(rs1_val, shamt) + } in + wGPR(rd, EXTS(result)) + +union ast member (regno, regno, regno, ropw) RTYPEW +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, ADDW)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SUBW)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b001 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SLLW)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SRLW)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SRAW)) +function clause execute (RTYPEW(rs2, rs1, rd, op)) = + let rs1_val = (rGPR(rs1))[31..0] in + let rs2_val = (rGPR(rs2))[31..0] in + let (bit[32]) result = switch(op) { + case ADDW -> rs1_val + rs2_val + case SUBW -> rs1_val - rs2_val + case SLLW -> rs1_val << (rs2_val[4..0]) + case SRLW -> rs1_val >> (rs2_val[4..0]) + case SRAW -> shift_right_arith32(rs1_val, rs2_val[4..0]) + } in + wGPR(rd, EXTS(result)) + +union ast member (bit[4], bit[4]) FENCE +function clause decode (0b0000 : (bit[4]) pred : (bit[4]) succ : 0b00000 : 0b000 : 0b00000 : 0b0001111) = Some(FENCE (pred, succ)) +function clause execute (FENCE(pred, succ)) = { + switch(pred, succ) { + case (0b0011, 0b0011) -> MEM_fence_rw_rw() + case (0b0010, 0b0011) -> MEM_fence_r_rw() + case (0b0011, 0b0001) -> MEM_fence_rw_w() + case _ -> not_implemented("unsupported fence") + } +} + +union ast member unit FENCEI +function clause decode (0b0000 : 0b0000 : 0b0000 : 0b00000 : 0b001 : 0b00000 : 0b0001111) = Some(FENCEI) +function clause execute FENCEI = () (* XXX TODO *) + +union ast member unit ECALL +function clause decode (0b000000000000 : 0b00000 : 0b000 : 0b00000 : 0b1110011) = Some(ECALL ()) +function clause execute ECALL = () + +union ast member unit EBREAK +function clause decode (0b000000000001 : 0b00000 : 0b000 : 0b00000 : 0b1110011) = Some(EBREAK ()) +function clause execute EBREAK = { exit () } + + +function clause decode _ = None + +end ast +end decode +end execute |
