aboutsummaryrefslogtreecommitdiff
path: root/model/riscv_types.sail
diff options
context:
space:
mode:
Diffstat (limited to 'model/riscv_types.sail')
-rw-r--r--model/riscv_types.sail550
1 files changed, 550 insertions, 0 deletions
diff --git a/model/riscv_types.sail b/model/riscv_types.sail
new file mode 100644
index 0000000..4d012e0
--- /dev/null
+++ b/model/riscv_types.sail
@@ -0,0 +1,550 @@
+/* Basic type and function definitions used pervasively in the model. */
+
+let xlen = 64
+type xlenbits = bits(64)
+
+let xlen_max_unsigned = 2 ^ xlen - 1
+let xlen_max_signed = 2 ^ (xlen - 1) - 1
+let xlen_min_signed = 0 - 2 ^ (xlen - 1)
+
+type half = bits(16)
+type word = bits(32)
+
+/* register identifiers */
+
+type regbits = bits(5)
+type cregbits = bits(3) /* identifiers in RVC instructions */
+type csreg = bits(12) /* CSR addressing */
+
+/* register file indexing */
+
+type regno ('n : Int), 0 <= 'n < 32 = atom('n)
+
+val cast regbits_to_regno : bits(5) -> {'n, 0 <= 'n < 32. regno('n)}
+function regbits_to_regno b = let 'r = unsigned(b) in r
+
+/* mapping RVC register indices into normal indices */
+val creg2reg_bits : cregbits -> regbits
+function creg2reg_bits(creg) = 0b01 @ creg
+
+/* some architecture and ABI relevant register identifiers */
+let zreg : regbits = 0b00000 /* x0, zero register */
+let ra : regbits = 0b00001 /* x1, return address */
+let sp : regbits = 0b00010 /* x2, stack pointer */
+
+/* program counter */
+
+register PC : xlenbits
+register nextPC : xlenbits
+
+/* internal state to hold instruction bits for faulting instructions */
+register instbits : xlenbits
+
+/* register file and accessors */
+
+register Xs : vector(32, dec, xlenbits)
+
+register x1 : xlenbits
+register x2 : xlenbits
+register x3 : xlenbits
+register x4 : xlenbits
+register x5 : xlenbits
+register x6 : xlenbits
+register x7 : xlenbits
+register x8 : xlenbits
+register x9 : xlenbits
+register x10 : xlenbits
+register x11 : xlenbits
+register x12 : xlenbits
+register x13 : xlenbits
+register x14 : xlenbits
+register x15 : xlenbits
+register x16 : xlenbits
+register x17 : xlenbits
+register x18 : xlenbits
+register x19 : xlenbits
+register x20 : xlenbits
+register x21 : xlenbits
+register x22 : xlenbits
+register x23 : xlenbits
+register x24 : xlenbits
+register x25 : xlenbits
+register x26 : xlenbits
+register x27 : xlenbits
+register x28 : xlenbits
+register x29 : xlenbits
+register x30 : xlenbits
+register x31 : xlenbits
+
+val rX : forall 'n, 0 <= 'n < 32. regno('n) -> xlenbits effect {rreg}
+/*function rX 0 = 0x0000000000000000
+and rX (r if r > 0) = Xs[r]*/
+function rX r = match r {
+ 0 => 0x0000000000000000,
+ 1 => x1,
+ 2 => x2,
+ 3 => x3,
+ 4 => x4,
+ 5 => x5,
+ 6 => x6,
+ 7 => x7,
+ 8 => x8,
+ 9 => x9,
+ 10 => x10,
+ 11 => x11,
+ 12 => x12,
+ 13 => x13,
+ 14 => x14,
+ 15 => x15,
+ 16 => x16,
+ 17 => x17,
+ 18 => x18,
+ 19 => x19,
+ 20 => x20,
+ 21 => x21,
+ 22 => x22,
+ 23 => x23,
+ 24 => x24,
+ 25 => x25,
+ 26 => x26,
+ 27 => x27,
+ 28 => x28,
+ 29 => x29,
+ 30 => x30,
+ 31 => x31
+}
+
+$ifdef RVFI_DII
+val rvfi_wX : forall 'n, 0 <= 'n < 32. (regno('n), xlenbits) -> unit effect {wreg}
+function rvfi_wX (r,v) = {
+ rvfi_exec->rvfi_rd_wdata() = v;
+ rvfi_exec->rvfi_rd_addr() = to_bits(8,r);
+}
+$else
+val rvfi_wX : forall 'n, 0 <= 'n < 32. (regno('n), xlenbits) -> unit
+function rvfi_wX (r,v) = ()
+$endif
+
+val wX : forall 'n, 0 <= 'n < 32. (regno('n), xlenbits) -> unit effect {wreg}
+function wX (r, v) = {
+ match r {
+ 0 => (),
+ 1 => x1 = v,
+ 2 => x2 = v,
+ 3 => x3 = v,
+ 4 => x4 = v,
+ 5 => x5 = v,
+ 6 => x6 = v,
+ 7 => x7 = v,
+ 8 => x8 = v,
+ 9 => x9 = v,
+ 10 => x10 = v,
+ 11 => x11 = v,
+ 12 => x12 = v,
+ 13 => x13 = v,
+ 14 => x14 = v,
+ 15 => x15 = v,
+ 16 => x16 = v,
+ 17 => x17 = v,
+ 18 => x18 = v,
+ 19 => x19 = v,
+ 20 => x20 = v,
+ 21 => x21 = v,
+ 22 => x22 = v,
+ 23 => x23 = v,
+ 24 => x24 = v,
+ 25 => x25 = v,
+ 26 => x26 = v,
+ 27 => x27 = v,
+ 28 => x28 = v,
+ 29 => x29 = v,
+ 30 => x30 = v,
+ 31 => x31 = v
+ };
+ if (r != 0) then {
+ rvfi_wX(r,v);
+ // Xs[r] = v;
+ print_reg("x" ^ string_of_int(r) ^ " <- " ^ BitStr(v));
+ }
+}
+
+overload X = {rX, wX}
+
+/* register names */
+
+val cast reg_name_abi : regbits -> string
+
+function reg_name_abi(r) = {
+ match (r) {
+ 0b00000 => "zero",
+ 0b00001 => "ra",
+ 0b00010 => "sp",
+ 0b00011 => "gp",
+ 0b00100 => "tp",
+ 0b00101 => "t0",
+ 0b00110 => "t1",
+ 0b00111 => "t2",
+ 0b01000 => "fp",
+ 0b01001 => "s1",
+ 0b01010 => "a0",
+ 0b01011 => "a1",
+ 0b01100 => "a2",
+ 0b01101 => "a3",
+ 0b01110 => "a4",
+ 0b01111 => "a5",
+ 0b10000 => "a6",
+ 0b10001 => "a7",
+ 0b10010 => "s2",
+ 0b10011 => "s3",
+ 0b10100 => "s4",
+ 0b10101 => "s5",
+ 0b10110 => "s6",
+ 0b10111 => "s7",
+ 0b11000 => "s8",
+ 0b11001 => "s9",
+ 0b11010 => "s10",
+ 0b11011 => "s11",
+ 0b11100 => "t3",
+ 0b11101 => "t4",
+ 0b11110 => "t5",
+ 0b11111 => "t6"
+ }
+}
+
+/* instruction fields */
+
+type opcode = bits(7)
+type imm12 = bits(12)
+type imm20 = bits(20)
+type amo = bits(1) /* amo opcode flags */
+
+/* base architecture definitions */
+
+enum Architecture = {RV32, RV64, RV128}
+type arch_xlen = bits(2)
+function architecture(a : arch_xlen) -> option(Architecture) =
+ match (a) {
+ 0b01 => Some(RV32),
+ 0b10 => Some(RV64),
+ 0b11 => Some(RV128),
+ _ => None()
+ }
+
+function arch_to_bits(a : Architecture) -> arch_xlen =
+ match (a) {
+ RV32 => 0b01,
+ RV64 => 0b10,
+ RV128 => 0b11
+ }
+
+/* privilege levels */
+
+type priv_level = bits(2)
+enum Privilege = {User, Supervisor, Machine}
+
+val cast privLevel_to_bits : Privilege -> priv_level
+function privLevel_to_bits (p) =
+ match (p) {
+ User => 0b00,
+ Supervisor => 0b01,
+ Machine => 0b11
+ }
+
+val cast privLevel_of_bits : priv_level -> Privilege
+function privLevel_of_bits (p) =
+ match (p) {
+ 0b00 => User,
+ 0b01 => Supervisor,
+ 0b11 => Machine
+ }
+
+val cast privLevel_to_str : Privilege -> string
+function privLevel_to_str (p) =
+ match (p) {
+ User => "U",
+ Supervisor => "S",
+ Machine => "M"
+ }
+
+/* memory access types */
+
+enum AccessType = {Read, Write, ReadWrite, Execute}
+
+val cast accessType_to_str : AccessType -> string
+function accessType_to_str (a) =
+ match (a) {
+ Read => "R",
+ Write => "W",
+ ReadWrite => "RW",
+ Execute => "X"
+ }
+
+enum ReadType = {Instruction, Data}
+
+val cast readType_to_str : ReadType -> string
+function readType_to_str (r) =
+ match (r) {
+ Instruction => "I",
+ Data => "D"
+ }
+
+enum word_width = {BYTE, HALF, WORD, DOUBLE}
+
+/* architectural interrupt definitions */
+
+type exc_code = bits(4)
+
+enum InterruptType = {
+ I_U_Software,
+ I_S_Software,
+ I_M_Software,
+ I_U_Timer,
+ I_S_Timer,
+ I_M_Timer,
+ I_U_External,
+ I_S_External,
+ I_M_External
+}
+
+val cast interruptType_to_bits : InterruptType -> exc_code
+function interruptType_to_bits (i) =
+ match (i) {
+ I_U_Software => 0x0,
+ I_S_Software => 0x1,
+ I_M_Software => 0x3,
+ I_U_Timer => 0x4,
+ I_S_Timer => 0x5,
+ I_M_Timer => 0x7,
+ I_U_External => 0x8,
+ I_S_External => 0x9,
+ I_M_External => 0xb
+ }
+
+/* architectural exception definitions */
+
+enum ExceptionType = {
+ E_Fetch_Addr_Align,
+ E_Fetch_Access_Fault,
+ E_Illegal_Instr,
+ E_Breakpoint,
+ E_Load_Addr_Align,
+ E_Load_Access_Fault,
+ E_SAMO_Addr_Align,
+ E_SAMO_Access_Fault,
+ E_U_EnvCall,
+ E_S_EnvCall,
+ E_Reserved_10,
+ E_M_EnvCall,
+ E_Fetch_Page_Fault,
+ E_Load_Page_Fault,
+ E_Reserved_14,
+ E_SAMO_Page_Fault
+}
+
+val cast exceptionType_to_bits : ExceptionType -> exc_code
+function exceptionType_to_bits(e) =
+ match (e) {
+ E_Fetch_Addr_Align => 0x0,
+ E_Fetch_Access_Fault => 0x1,
+ E_Illegal_Instr => 0x2,
+ E_Breakpoint => 0x3,
+ E_Load_Addr_Align => 0x4,
+ E_Load_Access_Fault => 0x5,
+ E_SAMO_Addr_Align => 0x6,
+ E_SAMO_Access_Fault => 0x7,
+ E_U_EnvCall => 0x8,
+ E_S_EnvCall => 0x9,
+ E_Reserved_10 => 0xa,
+ E_M_EnvCall => 0xb,
+ E_Fetch_Page_Fault => 0xc,
+ E_Load_Page_Fault => 0xd,
+ E_Reserved_14 => 0xe,
+ E_SAMO_Page_Fault => 0xf
+ }
+
+val cast exceptionType_to_str : ExceptionType -> string
+function exceptionType_to_str(e) =
+ match (e) {
+ E_Fetch_Addr_Align => "misaligned-fetch",
+ E_Fetch_Access_Fault => "fetch-access-fault",
+ E_Illegal_Instr => "illegal-instruction",
+ E_Breakpoint => "breakpoint",
+ E_Load_Addr_Align => "misaligned-load",
+ E_Load_Access_Fault => "load-access-fault",
+ E_SAMO_Addr_Align => "misaliged-store/amo",
+ E_SAMO_Access_Fault => "store/amo-access-fault",
+ E_U_EnvCall => "u-call",
+ E_S_EnvCall => "s-call",
+ E_Reserved_10 => "reserved-0",
+ E_M_EnvCall => "m-call",
+ E_Fetch_Page_Fault => "fetch-page-fault",
+ E_Load_Page_Fault => "load-page-fault",
+ E_Reserved_14 => "reserved-1",
+ E_SAMO_Page_Fault => "store/amo-page-fault"
+ }
+
+/* model-internal exceptions */
+
+union exception = {
+ Error_not_implemented : string,
+ Error_internal_error : unit
+}
+
+val not_implemented : forall ('a : Type). string -> 'a effect {escape}
+function not_implemented message = throw(Error_not_implemented(message))
+
+val internal_error : forall ('a : Type). string -> 'a effect {escape}
+function internal_error(s) = {
+ assert (false, s);
+ throw Error_internal_error()
+}
+
+/* trap modes */
+
+type tv_mode = bits(2)
+enum TrapVectorMode = {TV_Direct, TV_Vector, TV_Reserved}
+
+val cast trapVectorMode_of_bits : tv_mode -> TrapVectorMode
+function trapVectorMode_of_bits (m) =
+ match (m) {
+ 0b00 => TV_Direct,
+ 0b01 => TV_Vector,
+ _ => TV_Reserved
+ }
+
+/* extension context status */
+
+type ext_status = bits(2)
+enum ExtStatus = {Off, Initial, Clean, Dirty}
+
+val cast extStatus_to_bits : ExtStatus -> ext_status
+function extStatus_to_bits(e) =
+ match (e) {
+ Off => 0b00,
+ Initial => 0b01,
+ Clean => 0b10,
+ Dirty => 0b11
+ }
+
+val cast extStatus_of_bits : ext_status -> ExtStatus
+function extStatus_of_bits(e) =
+ match (e) {
+ 0b00 => Off,
+ 0b01 => Initial,
+ 0b10 => Clean,
+ 0b11 => Dirty
+ }
+
+/* supervisor-level address translation modes */
+
+type satp_mode = bits(4)
+enum SATPMode = {Sbare, Sv32, Sv39}
+
+function satpMode_of_bits(a : Architecture, m : satp_mode) -> option(SATPMode) =
+ match (a, m) {
+ (_, 0x0) => Some(Sbare),
+ (RV32, 0x1) => Some(Sv32),
+ (RV64, 0x8) => Some(Sv39),
+ (_, _) => None()
+ }
+
+/* CSR access control bits (from CSR addresses) */
+
+type csrRW = bits(2) /* read/write */
+
+/* instruction opcode grouping */
+enum uop = {RISCV_LUI, RISCV_AUIPC} /* upper immediate ops */
+enum bop = {RISCV_BEQ, RISCV_BNE, RISCV_BLT,
+ RISCV_BGE, RISCV_BLTU, RISCV_BGEU} /* branch ops */
+enum iop = {RISCV_ADDI, RISCV_SLTI, RISCV_SLTIU,
+ RISCV_XORI, RISCV_ORI, RISCV_ANDI} /* immediate ops */
+enum sop = {RISCV_SLLI, RISCV_SRLI, RISCV_SRAI} /* shift ops */
+enum rop = {RISCV_ADD, RISCV_SUB, RISCV_SLL, RISCV_SLT,
+ RISCV_SLTU, RISCV_XOR, RISCV_SRL, RISCV_SRA,
+ RISCV_OR, RISCV_AND} /* reg-reg ops */
+
+enum ropw = {RISCV_ADDW, RISCV_SUBW, RISCV_SLLW,
+ RISCV_SRLW, RISCV_SRAW} /* reg-reg 32-bit ops */
+enum sopw = {RISCV_SLLIW, RISCV_SRLIW,
+ RISCV_SRAIW} /* RV64-only shift ops */
+enum amoop = {AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR,
+ AMOMIN, AMOMAX, AMOMINU, AMOMAXU} /* AMO ops */
+enum csrop = {CSRRW, CSRRS, CSRRC} /* CSR ops */
+
+/* mappings for assembly */
+
+val reg_name : bits(5) <-> string
+mapping reg_name = {
+ 0b00000 <-> "zero",
+ 0b00001 <-> "ra",
+ 0b00010 <-> "sp",
+ 0b00011 <-> "gp",
+ 0b00100 <-> "tp",
+ 0b00101 <-> "t0",
+ 0b00110 <-> "t1",
+ 0b00111 <-> "t2",
+ 0b01000 <-> "fp",
+ 0b01001 <-> "s1",
+ 0b01010 <-> "a0",
+ 0b01011 <-> "a1",
+ 0b01100 <-> "a2",
+ 0b01101 <-> "a3",
+ 0b01110 <-> "a4",
+ 0b01111 <-> "a5",
+ 0b10000 <-> "a6",
+ 0b10001 <-> "a7",
+ 0b10010 <-> "s2",
+ 0b10011 <-> "s3",
+ 0b10100 <-> "s4",
+ 0b10101 <-> "s5",
+ 0b10110 <-> "s6",
+ 0b10111 <-> "s7",
+ 0b11000 <-> "s8",
+ 0b11001 <-> "s9",
+ 0b11010 <-> "s10",
+ 0b11011 <-> "s11",
+ 0b11100 <-> "t3",
+ 0b11101 <-> "t4",
+ 0b11110 <-> "t5",
+ 0b11111 <-> "t6"
+}
+
+mapping creg_name : bits(3) <-> string = {
+ 0b000 <-> "s0",
+ 0b001 <-> "s1",
+ 0b010 <-> "a0",
+ 0b011 <-> "a1",
+ 0b100 <-> "a2",
+ 0b101 <-> "a3",
+ 0b110 <-> "a4",
+ 0b111 <-> "a5"
+}
+
+val sep : unit <-> string
+mapping sep : unit <-> string = {
+ () <-> opt_spc() ^ "," ^ def_spc()
+}
+
+mapping bool_bits : bool <-> bits(1) = {
+ true <-> 0b1,
+ false <-> 0b0
+}
+
+mapping bool_not_bits : bool <-> bits(1) = {
+ true <-> 0b0,
+ false <-> 0b1
+}
+
+mapping size_bits : word_width <-> bits(2) = {
+ BYTE <-> 0b00,
+ HALF <-> 0b01,
+ WORD <-> 0b10,
+ DOUBLE <-> 0b11
+}
+
+mapping size_mnemonic : word_width <-> string = {
+ BYTE <-> "b",
+ HALF <-> "h",
+ WORD <-> "w",
+ DOUBLE <-> "d"
+}