summaryrefslogtreecommitdiff
path: root/riscv/riscv.sail
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/riscv.sail')
-rw-r--r--riscv/riscv.sail1569
1 files changed, 0 insertions, 1569 deletions
diff --git a/riscv/riscv.sail b/riscv/riscv.sail
deleted file mode 100644
index 37553299..00000000
--- a/riscv/riscv.sail
+++ /dev/null
@@ -1,1569 +0,0 @@
-/* ****************************************************************** */
-union clause ast = UTYPE : (bits(20), regbits, uop)
-
-mapping encdec_uop : uop <-> bits(7) = {
- RISCV_LUI <-> 0b0110111,
- RISCV_AUIPC <-> 0b0010111
-}
-
-mapping clause encdec = UTYPE(imm, rd, op) <-> imm @ rd @ encdec_uop(op)
-
-function clause execute UTYPE(imm, rd, op) = {
- let off : xlenbits = EXTS(imm @ 0x000);
- let ret : xlenbits = match op {
- RISCV_LUI => off,
- RISCV_AUIPC => PC + off
- };
- X(rd) = ret;
- true
-}
-
-mapping utype_mnemonic : uop <-> string = {
- RISCV_LUI <-> "lui",
- RISCV_AUIPC <-> "auipc"
-}
-
-mapping clause assembly = UTYPE(imm, rd, op)
- <-> utype_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_20(imm)
-
-/* ****************************************************************** */
-union clause ast = RISCV_JAL : (bits(21), regbits)
-
-mapping clause encdec = RISCV_JAL(imm_19 @ imm_7_0 @ imm_8 @ imm_18_13 @ imm_12_9 @ 0b0, rd)
- <-> imm_19 : bits(1) @ imm_18_13 : bits(6) @ imm_12_9 : bits(4) @ imm_8 : bits(1) @ imm_7_0 : bits(8) @ rd @ 0b1101111
-
-/*
-ideally we want some syntax like
-
-mapping clause encdec = RISCV_JAL(imm @ 0b0, rd) <-> imm[19] @ imm[9..0] @ imm[10] @ imm[18..11] @ rd @ 0b1101111
-
-match bv {
- imm[19] @ imm[9..0] @ imm[10] @ imm[18..11] -> imm @ 0b0
-}
-
-but this is difficult
-*/
-
-function clause execute (RISCV_JAL(imm, rd)) = {
- let pc : xlenbits = PC;
- let newPC : xlenbits = pc + EXTS(imm);
- if newPC[1] & (~ (haveRVC())) then {
- handle_mem_exception(newPC, E_Fetch_Addr_Align);
- false
- } else {
- X(rd) = nextPC; /* compatible with JAL and C.JAL */
- nextPC = newPC;
- true
- }
-}
-/* TODO: handle 2-byte-alignment in mappings */
-
-mapping clause assembly = RISCV_JAL(imm, rd) <-> "jal" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_21(imm)
-
-/* ****************************************************************** */
-union clause ast = RISCV_JALR : (bits(12), regbits, regbits)
-
-mapping clause encdec = RISCV_JALR(imm, rs1, rd) <-> imm @ rs1 @ 0b000 @ rd @ 0b1100111
-
-mapping clause assembly = RISCV_JALR(imm, rs1, rd)
- <-> "jalr" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ hex_bits_12(imm)
-
-/* see riscv_jalr_seq.sail or riscv_jalr_rmem.sail for the execute clause. */
-
-/* ****************************************************************** */
-union clause ast = BTYPE : (bits(13), regbits, regbits, bop)
-
-mapping encdec_bop : bop <-> bits(3) = {
- RISCV_BEQ <-> 0b000,
- RISCV_BNE <-> 0b001,
- RISCV_BLT <-> 0b100,
- RISCV_BGE <-> 0b101,
- RISCV_BLTU <-> 0b110,
- RISCV_BGEU <-> 0b111
-}
-
-mapping clause encdec = BTYPE(imm7_6 @ imm5_0 @ imm7_5_0 @ imm5_4_1 @ 0b0, rs2, rs1, op)
- <-> imm7_6 : bits(1) @ imm7_5_0 : bits(6) @ rs2 @ rs1 @ encdec_bop(op) @ imm5_4_1 : bits(4) @ imm5_0 : bits(1) @ 0b1100011
-
-function clause execute (BTYPE(imm, rs2, rs1, op)) = {
- let rs1_val = X(rs1);
- let rs2_val = X(rs2);
- let taken : bool = match op {
- RISCV_BEQ => rs1_val == rs2_val,
- RISCV_BNE => rs1_val != rs2_val,
- RISCV_BLT => rs1_val <_s rs2_val,
- RISCV_BGE => rs1_val >=_s rs2_val,
- RISCV_BLTU => rs1_val <_u rs2_val,
- RISCV_BGEU => rs1_val >=_u rs2_val
- };
- let newPC = PC + EXTS(imm);
- if taken then {
- if newPC[1] & (~ (haveRVC())) then {
- handle_mem_exception(newPC, E_Fetch_Addr_Align);
- false;
- } else {
- nextPC = newPC;
- true
- }
- } else true
-}
-
-mapping btype_mnemonic : bop <-> string = {
- RISCV_BEQ <-> "beq",
- RISCV_BNE <-> "bne",
- RISCV_BLT <-> "blt",
- RISCV_BGE <-> "bge",
- RISCV_BLTU <-> "bltu",
- RISCV_BGEU <-> "bgeu"
-}
-
-mapping clause assembly = BTYPE(imm, rs2, rs1, op)
- <-> btype_mnemonic(op) ^ spc() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2) ^ sep() ^ hex_bits_13(imm)
-
-/* ****************************************************************** */
-union clause ast = ITYPE : (bits(12), regbits, regbits, iop)
-
-mapping encdec_iop : iop <-> bits(3) = {
- RISCV_ADDI <-> 0b000,
- RISCV_SLTI <-> 0b010,
- RISCV_SLTIU <-> 0b011,
- RISCV_XORI <-> 0b100,
- RISCV_ORI <-> 0b110,
- RISCV_ANDI <-> 0b111
-}
-
-mapping clause encdec = ITYPE(imm, rs1, rd, op) <-> imm @ rs1 @ encdec_iop(op) @ rd @ 0b0010011
-
-function clause execute (ITYPE (imm, rs1, rd, op)) = {
- let rs1_val = X(rs1);
- let immext : xlenbits = EXTS(imm);
- let result : xlenbits = match op {
- RISCV_ADDI => rs1_val + immext,
- RISCV_SLTI => EXTZ(rs1_val <_s immext),
- RISCV_SLTIU => EXTZ(rs1_val <_u immext),
- RISCV_XORI => rs1_val ^ immext,
- RISCV_ORI => rs1_val | immext,
- RISCV_ANDI => rs1_val & immext
- };
- X(rd) = result;
- true
-}
-
-mapping itype_mnemonic : iop <-> string = {
- RISCV_ADDI <-> "addi",
- RISCV_SLTI <-> "slti",
- RISCV_SLTIU <-> "sltiu",
- RISCV_XORI <-> "xori",
- RISCV_ORI <-> "ori",
- RISCV_ANDI <-> "andi"
-}
-
-mapping clause assembly = ITYPE(imm, rs1, rd, op)
- <-> itype_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ hex_bits_12(imm)
-
-/* ****************************************************************** */
-union clause ast = SHIFTIOP : (bits(6), regbits, regbits, sop)
-
-mapping encdec_sop : sop <-> bits(3) = {
- RISCV_SLLI <-> 0b001,
- RISCV_SRLI <-> 0b101,
- RISCV_SRAI <-> 0b101
-}
-
-mapping clause encdec = SHIFTIOP(shamt, rs1, rd, RISCV_SLLI) <-> 0b000000 @ shamt @ rs1 @ 0b001 @ rd @ 0b0010011
-mapping clause encdec = SHIFTIOP(shamt, rs1, rd, RISCV_SRLI) <-> 0b000000 @ shamt @ rs1 @ 0b101 @ rd @ 0b0010011
-mapping clause encdec = SHIFTIOP(shamt, rs1, rd, RISCV_SRAI) <-> 0b010000 @ shamt @ rs1 @ 0b101 @ rd @ 0b0010011
-
-function clause execute (SHIFTIOP(shamt, rs1, rd, op)) = {
- let rs1_val = X(rs1);
- let result : xlenbits = match op {
- RISCV_SLLI => rs1_val << shamt,
- RISCV_SRLI => rs1_val >> shamt,
- RISCV_SRAI => shift_right_arith64(rs1_val, shamt)
- };
- X(rd) = result;
- true
-}
-
-mapping shiftiop_mnemonic : sop <-> string = {
- RISCV_SLLI <-> "slli",
- RISCV_SRLI <-> "srli",
- RISCV_SRAI <-> "srai"
-}
-
-mapping clause assembly = SHIFTIOP(shamt, rs1, rd, op)
- <-> shiftiop_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ hex_bits_6(shamt)
-
-/* ****************************************************************** */
-union clause ast = RTYPE : (regbits, regbits, regbits, rop)
-
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_ADD) <-> 0b0000000 @ rs2 @ rs1 @ 0b000 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_SUB) <-> 0b0100000 @ rs2 @ rs1 @ 0b000 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_SLL) <-> 0b0000000 @ rs2 @ rs1 @ 0b001 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_SLT) <-> 0b0000000 @ rs2 @ rs1 @ 0b010 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_SLTU) <-> 0b0000000 @ rs2 @ rs1 @ 0b011 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_XOR) <-> 0b0000000 @ rs2 @ rs1 @ 0b100 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_SRL) <-> 0b0000000 @ rs2 @ rs1 @ 0b101 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_SRA) <-> 0b0100000 @ rs2 @ rs1 @ 0b101 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_OR) <-> 0b0000000 @ rs2 @ rs1 @ 0b110 @ rd @ 0b0110011
-mapping clause encdec = RTYPE(rs2, rs1, rd, RISCV_AND) <-> 0b0000000 @ rs2 @ rs1 @ 0b111 @ rd @ 0b0110011
-
-function clause execute (RTYPE(rs2, rs1, rd, op)) = {
- let rs1_val = X(rs1);
- let rs2_val = X(rs2);
- let result : xlenbits = match op {
- RISCV_ADD => rs1_val + rs2_val,
- RISCV_SUB => rs1_val - rs2_val,
- RISCV_SLL => rs1_val << (rs2_val[5..0]),
- RISCV_SLT => EXTZ(rs1_val <_s rs2_val),
- RISCV_SLTU => EXTZ(rs1_val <_u rs2_val),
- RISCV_XOR => rs1_val ^ rs2_val,
- RISCV_SRL => rs1_val >> (rs2_val[5..0]),
- RISCV_SRA => shift_right_arith64(rs1_val, rs2_val[5..0]),
- RISCV_OR => rs1_val | rs2_val,
- RISCV_AND => rs1_val & rs2_val
- };
- X(rd) = result;
- true
-}
-
-mapping rtype_mnemonic : rop <-> string = {
- RISCV_ADD <-> "add",
- RISCV_SUB <-> "sub",
- RISCV_SLL <-> "sll",
- RISCV_SLT <-> "slt",
- RISCV_SLTU <-> "sltu",
- RISCV_XOR <-> "xor",
- RISCV_SRL <-> "srl",
- RISCV_SRA <-> "sra",
- RISCV_OR <-> "or",
- RISCV_AND <-> "and"
-}
-
-mapping clause assembly = RTYPE(rs2, rs1, rd, op)
- <-> rtype_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = LOAD : (bits(12), regbits, regbits, bool, word_width, bool, bool)
-
-/* Load unsigned double is only present in RV128I, not RV64I */
-/* TODO: aq/rl */
-mapping clause encdec = LOAD(imm, rs1, rd, is_unsigned, size, false, false) if size_bits(size) != 0b11 | not_bool(is_unsigned)
- <-> imm @ rs1 @ bool_bits(is_unsigned) @ size_bits(size) @ rd @ 0b0000011 if size_bits(size) != 0b11 | not_bool(is_unsigned)
-
-val extend_value : forall 'n, 0 < 'n <= 8. (bool, MemoryOpResult(bits(8 * 'n))) -> MemoryOpResult(xlenbits)
-function extend_value(is_unsigned, value) = match (value) {
- MemValue(v) => MemValue(if is_unsigned then EXTZ(v) else EXTS(v) : xlenbits),
- MemException(e) => MemException(e)
-}
-
-val process_load : forall 'n, 0 < 'n <= 8. (regbits, xlenbits, MemoryOpResult(bits(8 * 'n)), bool) -> bool effect {escape, rreg, wreg}
-function process_load(rd, addr, value, is_unsigned) =
- match extend_value(is_unsigned, value) {
- MemValue(result) => { X(rd) = result; true },
- MemException(e) => { handle_mem_exception(addr, e); false }
- }
-
-function check_misaligned(vaddr : xlenbits, width : word_width) -> bool =
- if plat_enable_misaligned_access() then false
- else match width {
- BYTE => false,
- HALF => vaddr[0] == true,
- WORD => vaddr[0] == true | vaddr[1] == true,
- DOUBLE => vaddr[0] == true | vaddr[1] == true | vaddr[2] == true
- }
-
-function clause execute(LOAD(imm, rs1, rd, is_unsigned, width, aq, rl)) =
- let vaddr : xlenbits = X(rs1) + EXTS(imm) in
- if check_misaligned(vaddr, width)
- then { handle_mem_exception(vaddr, E_Load_Addr_Align); false }
- else match translateAddr(vaddr, Read, Data) {
- TR_Failure(e) => { handle_mem_exception(vaddr, e); false },
- TR_Address(addr) =>
- match width {
- BYTE => process_load(rd, vaddr, mem_read(addr, 1, aq, rl, false), is_unsigned),
- HALF => process_load(rd, vaddr, mem_read(addr, 2, aq, rl, false), is_unsigned),
- WORD => process_load(rd, vaddr, mem_read(addr, 4, aq, rl, false), is_unsigned),
- DOUBLE => process_load(rd, vaddr, mem_read(addr, 8, aq, rl, false), is_unsigned)
- }
- }
-
-/* TODO FIXME: is this the actual aq/rl syntax? */
-val maybe_aq : bool <-> string
-mapping maybe_aq = {
- true <-> ".aq",
- false <-> ""
-}
-
-val maybe_rl : bool <-> string
-mapping maybe_rl = {
- true <-> ".rl",
- false <-> ""
-}
-
-val maybe_u : bool <-> string
-mapping maybe_u = {
- true <-> "u",
- false <-> ""
-}
-
-
-mapping clause assembly = LOAD(imm, rs1, rd, is_unsigned, size, aq, rl)
- <-> "l" ^ size_mnemonic(size) ^ maybe_u(is_unsigned) ^ maybe_aq(aq) ^ maybe_rl(rl) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ hex_bits_12(imm)
-
-/* ****************************************************************** */
-union clause ast = STORE : (bits(12), regbits, regbits, word_width, bool, bool)
-
-/* TODO: aq/rl */
-mapping clause encdec = STORE(imm7 @ imm5, rs2, rs1, size, false, false)
- <-> imm7 : bits(7) @ rs2 @ rs1 @ 0b0 @ size_bits(size) @ imm5 : bits(5) @ 0b0100011
-
-/* NOTE: Currently, we only EA if address translation is successful.
- This may need revisiting. */
-function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) =
- let vaddr : xlenbits = X(rs1) + EXTS(imm) in
- if check_misaligned(vaddr, width)
- then { handle_mem_exception(vaddr, E_SAMO_Addr_Align); false }
- else match translateAddr(vaddr, Write, Data) {
- TR_Failure(e) => { handle_mem_exception(vaddr, e); false },
- TR_Address(addr) => {
- let eares : MemoryOpResult(unit) = match width {
- BYTE => mem_write_ea(addr, 1, aq, rl, false),
- HALF => mem_write_ea(addr, 2, aq, rl, false),
- WORD => mem_write_ea(addr, 4, aq, rl, false),
- DOUBLE => mem_write_ea(addr, 8, aq, rl, false)
- };
- match (eares) {
- MemException(e) => { handle_mem_exception(addr, e); false },
- MemValue(_) => {
- let rs2_val = X(rs2);
- let res : MemoryOpResult(bool) = match width {
- BYTE => mem_write_value(addr, 1, rs2_val[7..0], aq, rl, false),
- HALF => mem_write_value(addr, 2, rs2_val[15..0], aq, rl, false),
- WORD => mem_write_value(addr, 4, rs2_val[31..0], aq, rl, false),
- DOUBLE => mem_write_value(addr, 8, rs2_val, aq, rl, false)
- };
- match (res) {
- MemValue(true) => true,
- MemValue(false) => internal_error("store got false from mem_write_value"),
- MemException(e) => { handle_mem_exception(addr, e); false }
- }
- }
- }
- }
- }
-
-mapping clause assembly = STORE(imm, rs1, rd, size, aq, rl)
- <-> "s" ^ size_mnemonic(size) ^ maybe_aq(aq) ^ maybe_rl(rl) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ hex_bits_12(imm)
-
-
-/* ****************************************************************** */
-union clause ast = ADDIW : (bits(12), regbits, regbits)
-
-mapping clause encdec = ADDIW(imm, rs1, rd) <-> imm @ rs1 @ 0b000 @ rd @ 0b0011011
-
-function clause execute (ADDIW(imm, rs1, rd)) = {
- let result : xlenbits = EXTS(imm) + X(rs1);
- X(rd) = EXTS(result[31..0]);
- true
-}
-
-
-mapping clause assembly = ADDIW(imm, rs1, rd) <-> "addiw" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ hex_bits_12(imm)
-
-/* ****************************************************************** */
-union clause ast = SHIFTW : (bits(5), regbits, regbits, sop)
-
-mapping clause encdec = SHIFTW(shamt, rs1, rd, RISCV_SLLI) <-> 0b0000000 @ shamt @ rs1 @ 0b001 @ rd @ 0b0011011
-mapping clause encdec = SHIFTW(shamt, rs1, rd, RISCV_SRLI) <-> 0b0000000 @ shamt @ rs1 @ 0b101 @ rd @ 0b0011011
-mapping clause encdec = SHIFTW(shamt, rs1, rd, RISCV_SRAI) <-> 0b0100000 @ shamt @ rs1 @ 0b101 @ rd @ 0b0011011
-
-function clause execute (SHIFTW(shamt, rs1, rd, op)) = {
- let rs1_val = (X(rs1))[31..0];
- let result : bits(32) = match op {
- RISCV_SLLI => rs1_val << shamt,
- RISCV_SRLI => rs1_val >> shamt,
- RISCV_SRAI => shift_right_arith32(rs1_val, shamt)
- };
- X(rd) = EXTS(result);
- true
-}
-
-mapping shiftw_mnemonic : sop <-> string = {
- RISCV_SLLI <-> "slli",
- RISCV_SRLI <-> "srli",
- RISCV_SRAI <-> "srai"
-}
-
-mapping clause assembly = SHIFTW(shamt, rs1, rd, op)
- <-> shiftw_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ hex_bits_5(shamt)
-
-/* ****************************************************************** */
-union clause ast = RTYPEW : (regbits, regbits, regbits, ropw)
-
-mapping clause encdec = RTYPEW(rs2, rs1, rd, RISCV_ADDW) <-> 0b0000000 @ rs2 @ rs1 @ 0b000 @ rd @ 0b0111011
-mapping clause encdec = RTYPEW(rs2, rs1, rd, RISCV_SUBW) <-> 0b0100000 @ rs2 @ rs1 @ 0b000 @ rd @ 0b0111011
-mapping clause encdec = RTYPEW(rs2, rs1, rd, RISCV_SLLW) <-> 0b0000000 @ rs2 @ rs1 @ 0b001 @ rd @ 0b0111011
-mapping clause encdec = RTYPEW(rs2, rs1, rd, RISCV_SRLW) <-> 0b0000000 @ rs2 @ rs1 @ 0b101 @ rd @ 0b0111011
-mapping clause encdec = RTYPEW(rs2, rs1, rd, RISCV_SRAW) <-> 0b0100000 @ rs2 @ rs1 @ 0b101 @ rd @ 0b0111011
-
-function clause execute (RTYPEW(rs2, rs1, rd, op)) = {
- let rs1_val = (X(rs1))[31..0];
- let rs2_val = (X(rs2))[31..0];
- let result : bits(32) = match op {
- RISCV_ADDW => rs1_val + rs2_val,
- RISCV_SUBW => rs1_val - rs2_val,
- RISCV_SLLW => rs1_val << (rs2_val[4..0]),
- RISCV_SRLW => rs1_val >> (rs2_val[4..0]),
- RISCV_SRAW => shift_right_arith32(rs1_val, rs2_val[4..0])
- };
- X(rd) = EXTS(result);
- true
-}
-
-mapping rtypew_mnemonic : ropw <-> string = {
- RISCV_ADDW <-> "addw",
- RISCV_SUBW <-> "subw",
- RISCV_SLLW <-> "sllw",
- RISCV_SRLW <-> "srlw",
- RISCV_SRAW <-> "sraw"
-}
-
-mapping clause assembly = RTYPEW(rs2, rs1, rd, op)
- <-> rtypew_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = SHIFTIWOP : (bits(5), regbits, regbits, sopw)
-
-mapping clause encdec = SHIFTIWOP(shamt, rs1, rd, RISCV_SLLIW) <-> 0b0000000 @ shamt @ rs1 @ 0b001 @ rd @ 0b0011011
-mapping clause encdec = SHIFTIWOP(shamt, rs1, rd, RISCV_SRLIW) <-> 0b0000000 @ shamt @ rs1 @ 0b101 @ rd @ 0b0011011
-mapping clause encdec = SHIFTIWOP(shamt, rs1, rd, RISCV_SRAIW) <-> 0b0100000 @ shamt @ rs1 @ 0b101 @ rd @ 0b0011011
-
-function clause execute (SHIFTIWOP(shamt, rs1, rd, op)) = {
- let rs1_val = X(rs1);
- let result : xlenbits = match op {
- RISCV_SLLIW => EXTS(rs1_val[31..0] << shamt),
- RISCV_SRLIW => EXTS(rs1_val[31..0] >> shamt),
- RISCV_SRAIW => EXTS(shift_right_arith32(rs1_val[31..0], shamt))
- };
- X(rd) = result;
- true
-}
-
-mapping shiftiwop_mnemonic : sopw <-> string = {
- RISCV_SLLIW <-> "slliw",
- RISCV_SRLIW <-> "srliw",
- RISCV_SRAIW <-> "sraiw"
-}
-
-mapping clause assembly = SHIFTIWOP(shamt, rs1, rd, op)
- <-> shiftiwop_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ hex_bits_5(shamt)
-
-/* ****************************************************************** */
-/* FIXME: separate these out into separate ast variants */
-union clause ast = MUL : (regbits, regbits, regbits, bool, bool, bool)
-
-mapping encdec_mul_op : (bool, bool, bool) <-> bits(3) = {
- (false, true, true) <-> 0b000,
- (true, true, true) <-> 0b001,
- (true, true, false) <-> 0b010,
- (true, false, false) <-> 0b011
-}
-
-/* for some reason the : bits(3) here is still necessary - BUG */
-mapping clause encdec = MUL(rs2, rs1, rd, high, signed1, signed2)
- <-> 0b0000001 @ rs2 @ rs1 @ encdec_mul_op(high, signed1, signed2) : bits(3) @ rd @ 0b0110011
-
-function clause execute (MUL(rs2, rs1, rd, high, signed1, signed2)) = {
- let rs1_val = X(rs1);
- let rs2_val = X(rs2);
- let rs1_int : int = if signed1 then signed(rs1_val) else unsigned(rs1_val);
- let rs2_int : int = if signed2 then signed(rs2_val) else unsigned(rs2_val);
- let result128 = to_bits(128, rs1_int * rs2_int);
- let result = if high then result128[127..64] else result128[63..0];
- X(rd) = result;
- true
-}
-
-mapping mul_mnemonic : (bool, bool, bool) <-> string = {
- (false, true, true) <-> "mul",
- (true, true, true) <-> "mulh",
- (true, true, false) <-> "mulhsu",
- (true, false, false) <-> "mulhu"
-}
-
-mapping clause assembly = MUL(rs2, rs1, rd, high, signed1, signed2) <-> mul_mnemonic(high, signed1, signed2) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = DIV : (regbits, regbits, regbits, bool)
-
-mapping clause encdec = DIV(rs2, rs1, rd, s) <-> 0b0000001 @ rs2 @ rs1 @ 0b10 @ bool_not_bits(s) @ rd @ 0b0110011
-
-function clause execute (DIV(rs2, rs1, rd, s)) = {
- let rs1_val = X(rs1);
- let rs2_val = X(rs2);
- let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val);
- let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val);
- let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int);
- let q': int = if s & q > xlen_max_signed then xlen_min_signed else q; /* check for signed overflow */
- X(rd) = to_bits(xlen, q');
- true
-}
-
-mapping maybe_not_u : bool <-> string = {
- false <-> "u",
- true <-> ""
-}
-
-mapping clause assembly = DIV(rs2, rs1, rd, s)
- <-> "div" ^ maybe_not_u(s) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = REM : (regbits, regbits, regbits, bool)
-
-mapping clause encdec = REM(rs2, rs1, rd, s) <-> 0b0000001 @ rs2 @ rs1 @ 0b11 @ bool_not_bits(s) @ rd @ 0b0110011
-
-function clause execute (REM(rs2, rs1, rd, s)) = {
- let rs1_val = X(rs1);
- let rs2_val = X(rs2);
- let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val);
- let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val);
- let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int);
- /* signed overflow case returns zero naturally as required due to -1 divisor */
- X(rd) = to_bits(xlen, r);
- true
-}
-
-mapping clause assembly = REM(rs2, rs1, rd, s) <-> "rem" ^ maybe_not_u(s) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = MULW : (regbits, regbits, regbits)
-
-mapping clause encdec = MULW(rs2, rs1, rd) <-> 0b0000001 @ rs2 @ rs1 @ 0b000 @ rd @ 0b0111011
-
-function clause execute (MULW(rs2, rs1, rd)) = {
- let rs1_val = X(rs1)[31..0];
- let rs2_val = X(rs2)[31..0];
- let rs1_int : int = signed(rs1_val);
- let rs2_int : int = signed(rs2_val);
- let result32 = to_bits(64, rs1_int * rs2_int)[31..0]; /* XXX surprising behaviour of to_bits requires expansion to 64 bits followed by truncation... */
- let result : xlenbits = EXTS(result32);
- X(rd) = result;
- true
-}
-
-mapping clause assembly = MULW(rs2, rs1, rd)
- <-> "mulw" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = DIVW : (regbits, regbits, regbits, bool)
-
-mapping clause encdec = DIVW(rs2, rs1, rd, s) <-> 0b0000001 @ rs2 @ rs1 @ 0b10 @ bool_not_bits(s) @ rd @ 0b0111011
-
-function clause execute (DIVW(rs2, rs1, rd, s)) = {
- let rs1_val = X(rs1)[31..0];
- let rs2_val = X(rs2)[31..0];
- let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val);
- let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val);
- let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int);
- let q': int = if s & q > (2 ^ 31 - 1) then (0 - 2^31) else q; /* check for signed overflow */
- X(rd) = EXTS(to_bits(32, q'));
- true
-}
-
-mapping clause assembly = DIVW(rs2, rs1, rd, s)
- <-> "div" ^ maybe_not_u(s) ^ "w" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = REMW : (regbits, regbits, regbits, bool)
-
-mapping clause encdec = REMW(rs2, rs1, rd, s) <-> 0b0000001 @ rs2 @ rs1 @ 0b11 @ bool_not_bits(s) @ rd @ 0b0111011
-
-function clause execute (REMW(rs2, rs1, rd, s)) = {
- let rs1_val = X(rs1)[31..0];
- let rs2_val = X(rs2)[31..0];
- let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val);
- let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val);
- let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int);
- /* signed overflow case returns zero naturally as required due to -1 divisor */
- X(rd) = EXTS(to_bits(32, r));
- true
-}
-
-mapping clause assembly = REMW(rs2, rs1, rd, s) <-> "rem" ^ maybe_not_u(s) ^ "w" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = FENCE : (bits(4), bits(4))
-
-mapping clause encdec = FENCE(pred, succ) <-> 0b0000 @ pred @ succ @ 0b00000 @ 0b000 @ 0b00000 @ 0b0001111
-
-function clause execute (FENCE(pred, succ)) = {
- match (pred, succ) {
- (_ : bits(2) @ 0b11, _ : bits(2) @ 0b11) => MEM_fence_rw_rw(),
- (_ : bits(2) @ 0b10, _ : bits(2) @ 0b11) => MEM_fence_r_rw(),
- (_ : bits(2) @ 0b10, _ : bits(2) @ 0b10) => MEM_fence_r_r(),
- (_ : bits(2) @ 0b11, _ : bits(2) @ 0b01) => MEM_fence_rw_w(),
- (_ : bits(2) @ 0b01, _ : bits(2) @ 0b01) => MEM_fence_w_w(),
- (_ : bits(2) @ 0b01, _ : bits(2) @ 0b11) => MEM_fence_w_rw(),
- (_ : bits(2) @ 0b11, _ : bits(2) @ 0b10) => MEM_fence_rw_r(),
- (_ : bits(2) @ 0b10, _ : bits(2) @ 0b01) => MEM_fence_r_w(),
- (_ : bits(2) @ 0b01, _ : bits(2) @ 0b10) => MEM_fence_w_r(),
-
- (_ : bits(2) @ 0b00, _ : bits(2) @ 0b00) => (),
-
- _ => { print("FIXME: unsupported fence");
- () }
- };
- true
-}
-
-mapping bit_maybe_r : bits(1) <-> string = {
- 0b1 <-> "r",
- 0b0 <-> ""
-}
-
-mapping bit_maybe_w : bits(1) <-> string = {
- 0b1 <-> "w",
- 0b0 <-> ""
-}
-
-mapping bit_maybe_i : bits(1) <-> string = {
- 0b1 <-> "i",
- 0b0 <-> ""
-}
-
-mapping bit_maybe_o : bits(1) <-> string = {
- 0b1 <-> "o",
- 0b0 <-> ""
-}
-
-mapping fence_bits : bits(4) <-> string = {
- i : bits(1) @ o : bits(1) @ r : bits(1) @ w : bits(1) <-> bit_maybe_i(i) ^ bit_maybe_o(o) ^ bit_maybe_r(r) ^ bit_maybe_w(w)
-}
-
-mapping clause assembly = FENCE(pred, succ) <-> "fence" ^ spc() ^ fence_bits(pred) ^ sep() ^ fence_bits(succ)
-
-/* ****************************************************************** */
-union clause ast = FENCEI : unit
-
-mapping clause encdec = FENCEI() <-> 0b000000000000 @ 0b00000 @ 0b001 @ 0b00000 @ 0b0001111
-
-/* fence.i is a nop for the memory model */
-function clause execute FENCEI() = { /* MEM_fence_i(); */ true }
-
-
-mapping clause assembly = FENCEI() <-> "fence.i"
-
-/* ****************************************************************** */
-union clause ast = ECALL : unit
-
-mapping clause encdec = ECALL() <-> 0b000000000000 @ 0b00000 @ 0b000 @ 0b00000 @ 0b1110011
-
-function clause execute ECALL() = {
- let t : sync_exception =
- struct { trap = match (cur_privilege) {
- User => E_U_EnvCall,
- Supervisor => E_S_EnvCall,
- Machine => E_M_EnvCall
- },
- excinfo = (None() : option(xlenbits)) };
- nextPC = handle_exception(cur_privilege, CTL_TRAP(t), PC);
- false
-}
-
-mapping clause assembly = ECALL() <-> "ecall"
-
-/* ****************************************************************** */
-union clause ast = MRET : unit
-
-mapping clause encdec = MRET() <-> 0b0011000 @ 0b00010 @ 0b00000 @ 0b000 @ 0b00000 @ 0b1110011
-
-function clause execute MRET() = {
- if cur_privilege == Machine
- then nextPC = handle_exception(cur_privilege, CTL_MRET(), PC)
- else handle_illegal();
- false
-}
-
-mapping clause assembly = MRET() <-> "mret"
-
-/* ****************************************************************** */
-union clause ast = SRET : unit
-
-mapping clause encdec = SRET() <-> 0b0001000 @ 0b00010 @ 0b00000 @ 0b000 @ 0b00000 @ 0b1110011
-
-function clause execute SRET() = {
- match cur_privilege {
- User => handle_illegal(),
- Supervisor => if mstatus.TSR() == true
- then handle_illegal()
- else nextPC = handle_exception(cur_privilege, CTL_SRET(), PC),
- Machine => nextPC = handle_exception(cur_privilege, CTL_SRET(), PC)
- };
- false
-}
-
-mapping clause assembly = SRET() <-> "sret"
-
-/* ****************************************************************** */
-union clause ast = EBREAK : unit
-
-mapping clause encdec = EBREAK() <-> 0b000000000001 @ 0b00000 @ 0b000 @ 0b00000 @ 0b1110011
-
-function clause execute EBREAK() = {
- handle_mem_exception(PC, E_Breakpoint);
- false
-}
-
-mapping clause assembly = EBREAK() <-> "ebreak"
-
-/* ****************************************************************** */
-union clause ast = WFI : unit
-
-mapping clause encdec = WFI() <-> 0b000100000101 @ 0b00000 @ 0b000 @ 0b00000 @ 0b1110011
-
-function clause execute WFI() =
- match cur_privilege {
- Machine => { platform_wfi(); true },
- Supervisor => if mstatus.TW() == true
- then { handle_illegal(); false }
- else { platform_wfi(); true },
- User => { handle_illegal(); false }
- }
-
-mapping clause assembly = WFI() <-> "wfi"
-
-/* ****************************************************************** */
-union clause ast = SFENCE_VMA : (regbits, regbits)
-
-mapping clause encdec = SFENCE_VMA(rs1, rs2) <-> 0b0001001 @ rs2 @ rs1 @ 0b000 @ 0b00000 @ 0b1110011
-
-function clause execute SFENCE_VMA(rs1, rs2) = {
- /* TODO: handle PMP/TLB synchronization when executed in M-mode. */
- if cur_privilege == User
- then { handle_illegal(); false }
- else match (architecture(mstatus.SXL()), mstatus.TVM()) {
- (Some(RV64), true) => { handle_illegal(); false },
- (Some(RV64), false) => {
- let addr : option(vaddr39) = if rs1 == 0 then None() else Some(X(rs1)[38 .. 0]);
- let asid : option(asid64) = if rs2 == 0 then None() else Some(X(rs2)[15 .. 0]);
- flushTLB(asid, addr);
- true
- },
- (_, _) => internal_error("unimplemented sfence architecture")
- }
-}
-
-mapping clause assembly = SFENCE_VMA(rs1, rs2)
- <-> "sfence.vma" ^ spc() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-// Some print utils for lr/sc.
-
-function aqrl_str(aq : bool, rl : bool) -> string =
- match (aq, rl) {
- (false, false) => "",
- (false, true) => ".rl",
- (true, false) => ".aq",
- (true, true) => ".aqrl"
- }
-
-function lrsc_width_str(width : word_width) -> string =
- match (width) {
- BYTE => ".b",
- HALF => ".h",
- WORD => ".w",
- DOUBLE => ".d"
- }
-
-/* ****************************************************************** */
-union clause ast = LOADRES : (bool, bool, regbits, word_width, regbits)
-
-mapping clause encdec = LOADRES(aq, rl, rs1, size, rd) <-> 0b00010 @ bool_bits(aq) @ bool_bits(rl) @ 0b00000 @ rs1 @ 0b0 @ size_bits(size) @ rd @ 0b0101111
-
-/* We could set load-reservations on physical or virtual addresses.
- * For now we set them on virtual addresses, since it makes the
- * sequential model of SC a bit simpler, at the cost of an explicit
- * call to load_reservation in LR and cancel_reservation in SC.
- */
-
-val process_loadres : forall 'n, 0 < 'n <= 8. (regbits, xlenbits, MemoryOpResult(bits(8 * 'n)), bool) -> bool effect {escape, rreg, wreg}
-function process_loadres(rd, addr, value, is_unsigned) =
- match extend_value(is_unsigned, value) {
- MemValue(result) => { load_reservation(addr); X(rd) = result; true },
- MemException(e) => { handle_mem_exception(addr, e); false }
- }
-
-function clause execute(LOADRES(aq, rl, rs1, width, rd)) =
- let vaddr : xlenbits = X(rs1) in
- let aligned : bool =
- /* BYTE and HALF would only occur due to invalid decodes, but it doesn't hurt
- * to treat them as valid here; otherwise we'd need to throw an internal_error.
- * May need to revisit for latex output.
- */
- match width {
- BYTE => true,
- HALF => vaddr[0] == 0b0,
- WORD => vaddr[1..0] == 0b00,
- DOUBLE => vaddr[2..0] == 0b000
- } in
- /* "LR faults like a normal load, even though it's in the AMO major opcode space."
- - Andrew Waterman, isa-dev, 10 Jul 2018.
- */
- if (~ (aligned))
- then { handle_mem_exception(vaddr, E_Load_Addr_Align); false }
- else match translateAddr(vaddr, Read, Data) {
- TR_Failure(e) => { handle_mem_exception(vaddr, e); false },
- TR_Address(addr) =>
- match width {
- WORD => process_loadres(rd, vaddr, mem_read(addr, 4, aq, rl, true), false),
- DOUBLE => process_loadres(rd, vaddr, mem_read(addr, 8, aq, rl, true), false),
- _ => internal_error("LOADRES expected WORD or DOUBLE")
- }
- }
-
-mapping clause assembly = LOADRES(aq, rl, rs1, size, rd)
- <-> "lr." ^ size_mnemonic(size) ^ maybe_aq(aq) ^ maybe_rl(rl) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1)
-
-/* ****************************************************************** */
-union clause ast = STORECON : (bool, bool, regbits, regbits, word_width, regbits)
-
-mapping clause encdec = STORECON(aq, rl, rs2, rs1, size, rd)
- <-> 0b00011 @ bool_bits(aq) @ bool_bits(rl) @ rs2 @ rs1 @ 0b0 @ size_bits(size) @ rd @ 0b0101111
-
-/* NOTE: Currently, we only EA if address translation is successful.
- This may need revisiting. */
-function clause execute (STORECON(aq, rl, rs2, rs1, width, rd)) = {
- /* RMEM FIXME: This definition differs from the Sail1 version:
- * rs1 is read *before* speculate_conditional_success
- * (called via match_reservation), partly due to the current api of
- * match_reservation. Reverting back to the weaker Sail1 version
- * will require changes to the API for the ghost reservation state.
- */
- vaddr : xlenbits = X(rs1);
- let aligned : bool =
- /* BYTE and HALF would only occur due to invalid decodes, but it doesn't hurt
- * to treat them as valid here; otherwise we'd need to throw an internal_error.
- * May need to revisit for latex output.
- */
- match width {
- BYTE => true,
- HALF => vaddr[0] == 0b0,
- WORD => vaddr[1..0] == 0b00,
- DOUBLE => vaddr[2..0] == 0b000
- } in
- if (~ (aligned))
- then { handle_mem_exception(vaddr, E_SAMO_Addr_Align); false }
- else {
- if match_reservation(vaddr) == false
- then { X(rd) = EXTZ(0b1); true }
- else {
- match translateAddr(vaddr, Write, Data) {
- TR_Failure(e) => { handle_mem_exception(vaddr, e); false },
- TR_Address(addr) => {
- let eares : MemoryOpResult(unit) = match width {
- WORD => mem_write_ea(addr, 4, aq, rl, true),
- DOUBLE => mem_write_ea(addr, 8, aq, rl, true),
- _ => internal_error("STORECON expected word or double")
- };
- match (eares) {
- MemException(e) => { handle_mem_exception(addr, e); false },
- MemValue(_) => {
- rs2_val = X(rs2);
- let res : MemoryOpResult(bool) = match width {
- WORD => mem_write_value(addr, 4, rs2_val[31..0], aq, rl, true),
- DOUBLE => mem_write_value(addr, 8, rs2_val, aq, rl, true),
- _ => internal_error("STORECON expected word or double")
- };
- match (res) {
- MemValue(true) => { X(rd) = EXTZ(0b0); cancel_reservation(); true },
- MemValue(false) => { X(rd) = EXTZ(0b1); cancel_reservation(); true },
- MemException(e) => { handle_mem_exception(addr, e); false }
- }
- }
- }
- }
- }
- }
- }
-}
-
-mapping clause assembly = STORECON(aq, rl, rs2, rs1, size, rd) <-> "sc." ^ size_mnemonic(size) ^ maybe_aq(aq) ^ maybe_rl(rl) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = AMO : (amoop, bool, bool, regbits, regbits, word_width, regbits)
-
-mapping encdec_amoop : amoop <-> bits(5) = {
- AMOSWAP <-> 0b00001,
- AMOADD <-> 0b00000,
- AMOXOR <-> 0b00100,
- AMOAND <-> 0b01100,
- AMOOR <-> 0b01000,
- AMOMIN <-> 0b10000,
- AMOMAX <-> 0b10100,
- AMOMINU <-> 0b11000,
- AMOMAXU <-> 0b11100
-}
-
-mapping clause encdec = AMO(op, aq, rl, rs2, rs1, size, rd) <-> encdec_amoop(op) @ bool_bits(aq) @ bool_bits(rl) @ rs2 @ rs1 @ 0b0 @ size_bits(size) @ rd @ 0b0101111
-
-/* NOTE: Currently, we only EA if address translation is successful.
- This may need revisiting. */
-function clause execute (AMO(op, aq, rl, rs2, rs1, width, rd)) = {
- vaddr : xlenbits = X(rs1);
- match translateAddr(vaddr, ReadWrite, Data) {
- TR_Failure(e) => { handle_mem_exception(vaddr, e); false },
- TR_Address(addr) => {
- let eares : MemoryOpResult(unit) = match width {
- WORD => mem_write_ea(addr, 4, aq & rl, rl, true),
- DOUBLE => mem_write_ea(addr, 8, aq & rl, rl, true),
- _ => internal_error ("AMO expected WORD or DOUBLE")
- };
- match (eares) {
- MemException(e) => { handle_mem_exception(addr, e); false },
- MemValue(_) => {
- let rval : MemoryOpResult(xlenbits) = match width {
- WORD => extend_value(false, mem_read(addr, 4, aq, aq & rl, true)),
- DOUBLE => extend_value(false, mem_read(addr, 8, aq, aq & rl, true)),
- _ => internal_error ("AMO expected WORD or DOUBLE")
- };
- match (rval) {
- MemException(e) => { handle_mem_exception(addr, e); false },
- MemValue(loaded) => {
- rs2_val : xlenbits = X(rs2);
- result : xlenbits =
- match op {
- AMOSWAP => rs2_val,
- AMOADD => rs2_val + loaded,
- AMOXOR => rs2_val ^ loaded,
- AMOAND => rs2_val & loaded,
- AMOOR => rs2_val | loaded,
-
- /* Have to convert number to vector here. Check this */
- AMOMIN => vector64(min(signed(rs2_val), signed(loaded))),
- AMOMAX => vector64(max(signed(rs2_val), signed(loaded))),
- AMOMINU => vector64(min(unsigned(rs2_val), unsigned(loaded))),
- AMOMAXU => vector64(max(unsigned(rs2_val), unsigned(loaded)))
- };
-
- let wval : MemoryOpResult(bool) = match width {
- WORD => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true),
- DOUBLE => mem_write_value(addr, 8, result, aq & rl, rl, true),
- _ => internal_error("AMO expected WORD or DOUBLE")
- };
- match (wval) {
- MemValue(true) => { X(rd) = loaded; true },
- MemValue(false) => { internal_error("AMO got false from mem_write_value") },
- MemException(e) => { handle_mem_exception(addr, e); false }
- }
- }
- }
- }
- }
- }
- }
-}
-
-
-mapping amo_mnemonic : amoop <-> string = {
- AMOSWAP <-> "amoswap",
- AMOADD <-> "amoadd",
- AMOXOR <-> "amoxor",
- AMOAND <-> "amoand",
- AMOOR <-> "amoor",
- AMOMIN <-> "amomin",
- AMOMAX <-> "amomax",
- AMOMINU <-> "amominu",
- AMOMAXU <-> "amomaxu"
-}
-
-mapping clause assembly = AMO(op, aq, rl, rs2, rs1, width, rd)
- <-> amo_mnemonic(op) ^ "." ^ size_mnemonic(width) ^ maybe_aq(aq) ^ maybe_rl(rl) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ reg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = CSR : (bits(12), regbits, regbits, bool, csrop)
-
-mapping encdec_csrop : csrop <-> bits(2) = {
- CSRRW <-> 0b01,
- CSRRS <-> 0b10,
- CSRRC <-> 0b11
-}
-
-mapping clause encdec = CSR(csr, rs1, rd, is_imm, op) <-> csr @ rs1 @ bool_bits(is_imm) @ encdec_csrop(op) @ rd @ 0b1110011
-
-function readCSR csr : csreg -> xlenbits =
- let res : xlenbits =
- match csr {
- /* machine mode */
- 0xF11 => mvendorid,
- 0xF12 => marchid,
- 0xF13 => mimpid,
- 0xF14 => mhartid,
- 0x300 => mstatus.bits(),
- 0x301 => misa.bits(),
- 0x302 => medeleg.bits(),
- 0x303 => mideleg.bits(),
- 0x304 => mie.bits(),
- 0x305 => mtvec.bits(),
- 0x306 => EXTZ(mcounteren.bits()),
- 0x340 => mscratch,
- 0x341 => mepc & pc_alignment_mask(),
- 0x342 => mcause.bits(),
- 0x343 => mtval,
- 0x344 => mip.bits(),
-
- 0x3A0 => pmpcfg0,
- 0x3B0 => pmpaddr0,
-
- /* supervisor mode */
- 0x100 => lower_mstatus(mstatus).bits(),
- 0x102 => sedeleg.bits(),
- 0x103 => sideleg.bits(),
- 0x104 => lower_mie(mie, mideleg).bits(),
- 0x105 => stvec.bits(),
- 0x106 => EXTZ(scounteren.bits()),
- 0x140 => sscratch,
- 0x141 => sepc & pc_alignment_mask(),
- 0x142 => scause.bits(),
- 0x143 => stval,
- 0x144 => lower_mip(mip, mideleg).bits(),
- 0x180 => satp,
-
- /* others */
- 0xC00 => mcycle,
- 0xC01 => mtime,
- 0xC02 => minstret,
-
- /* trigger/debug */
- 0x7a0 => ~(tselect), /* this indicates we don't have any trigger support */
-
- _ => { print_bits("unhandled read to CSR ", csr);
- 0x0000_0000_0000_0000 }
- } in {
- print_reg("CSR " ^ csr ^ " -> " ^ BitStr(res));
- res
- }
-
-function writeCSR (csr : csreg, value : xlenbits) -> unit =
- let res : option(xlenbits) =
- match csr {
- /* machine mode */
- 0x300 => { mstatus = legalize_mstatus(mstatus, value); Some(mstatus.bits()) },
- 0x301 => { misa = legalize_misa(misa, value); Some(misa.bits()) },
- 0x302 => { medeleg = legalize_medeleg(medeleg, value); Some(medeleg.bits()) },
- 0x303 => { mideleg = legalize_mideleg(mideleg, value); Some(mideleg.bits()) },
- 0x304 => { mie = legalize_mie(mie, value); Some(mie.bits()) },
- 0x305 => { mtvec = legalize_tvec(mtvec, value); Some(mtvec.bits()) },
- 0x306 => { mcounteren = legalize_mcounteren(mcounteren, value); Some(EXTZ(mcounteren.bits())) },
- 0x340 => { mscratch = value; Some(mscratch) },
- 0x341 => { mepc = legalize_xepc(value); Some(mepc) },
- 0x342 => { mcause->bits() = value; Some(mcause.bits()) },
- 0x343 => { mtval = value; Some(mtval) },
- 0x344 => { mip = legalize_mip(mip, value); Some(mip.bits()) },
-
- 0x3A0 => { pmpcfg0 = value; Some(pmpcfg0) }, /* FIXME: legalize */
- 0x3B0 => { pmpaddr0 = value; Some(pmpaddr0) }, /* FIXME: legalize */
-
- /* supervisor mode */
- 0x100 => { mstatus = legalize_sstatus(mstatus, value); Some(mstatus.bits()) },
- 0x102 => { sedeleg = legalize_sedeleg(sedeleg, value); Some(sedeleg.bits()) },
- 0x103 => { sideleg->bits() = value; Some(sideleg.bits()) }, /* TODO: does this need legalization? */
- 0x104 => { mie = legalize_sie(mie, mideleg, value); Some(mie.bits()) },
- 0x105 => { stvec = legalize_tvec(stvec, value); Some(stvec.bits()) },
- 0x106 => { scounteren = legalize_scounteren(scounteren, value); Some(EXTZ(scounteren.bits())) },
- 0x140 => { sscratch = value; Some(sscratch) },
- 0x141 => { sepc = legalize_xepc(value); Some(sepc) },
- 0x142 => { scause->bits() = value; Some(scause.bits()) },
- 0x143 => { stval = value; Some(stval) },
- 0x144 => { mip = legalize_sip(mip, mideleg, value); Some(mip.bits()) },
- 0x180 => { satp = legalize_satp(cur_Architecture(), satp, value); Some(satp) },
-
- /* trigger/debug */
- 0x7a0 => { tselect = value; Some(tselect) },
-
- /* counters */
- 0xC00 => { mcycle = value; Some(mcycle) },
- /* FIXME: it is not clear whether writable mtime is platform-dependent. */
- 0xC02 => { minstret = value; minstret_written = true; Some(minstret) },
-
- _ => None()
- } in
- match res {
- Some(v) => print_reg("CSR " ^ csr ^ " <- " ^ BitStr(v) ^ " (input: " ^ BitStr(value) ^ ")"),
- None() => print_bits("unhandled write to CSR ", csr)
- }
-
-function clause execute CSR(csr, rs1, rd, is_imm, op) =
- let rs1_val : xlenbits = if is_imm then EXTZ(rs1) else X(rs1) in
- let isWrite : bool = match op {
- CSRRW => true,
- _ => if is_imm then unsigned(rs1_val) != 0 else unsigned(rs1) != 0
- } in
- if ~ (check_CSR(csr, cur_privilege, isWrite))
- then { handle_illegal(); false }
- else {
- let csr_val = readCSR(csr); /* could have side-effects, so technically shouldn't perform for CSRW[I] with rd == 0 */
- if isWrite then {
- let new_val : xlenbits = match op {
- CSRRW => rs1_val,
- CSRRS => csr_val | rs1_val,
- CSRRC => csr_val & ~(rs1_val)
- } in
- writeCSR(csr, new_val)
- };
- X(rd) = csr_val;
- true
- }
-
-
-mapping maybe_i : bool <-> string = {
- true <-> "i",
- false <-> ""
-}
-
-mapping csr_mnemonic : csrop <-> string = {
- CSRRW <-> "csrrw",
- CSRRS <-> "csrrs",
- CSRRC <-> "csrrc"
-}
-
-mapping clause assembly = CSR(csr, rs1, rd, true, op) <-> csr_mnemonic(op) ^ "i" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_5(rs1) ^ sep() ^ csr_name_map(csr)
-mapping clause assembly = CSR(csr, rs1, rd, false, op) <-> csr_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ csr_name_map(csr)
-
-/* ****************************************************************** */
-union clause ast = C_NOP : unit
-
-mapping clause encdec_compressed = C_NOP() <-> 0b000 @ 0b0 @ 0b00000 @ 0b00000 @ 0b01
-
-function clause execute C_NOP() = true
-
-mapping clause assembly = C_NOP() <-> "c.nop"
-
-/* ****************************************************************** */
-
-union clause ast = C_ADDI4SPN : (cregbits, bits(8))
-
-mapping clause encdec_compressed = C_ADDI4SPN(rd, nz96 @ nz54 @ nz3 @ nz2)
- if nz96 @ nz54 @ nz3 @ nz2 != 0b00000000 <->
- 0b000 @ nz54 : bits(2) @ nz96 : bits(4) @ nz2 : bits(1) @ nz3 : bits(1) @ rd : cregbits @ 0b00
- if nz96 @ nz54 @ nz3 @ nz2 != 0b00000000
-
-function clause execute (C_ADDI4SPN(rdc, nzimm)) =
- let imm : bits(12) = (0b00 @ nzimm @ 0b00) in
- let rd = creg2reg_bits(rdc) in
- execute(ITYPE(imm, sp, rd, RISCV_ADDI))
-
-mapping clause assembly = C_ADDI4SPN(rdc, nzimm) if nzimm != 0b00000000 <-> "c.addi4spn" ^ spc() ^ creg_name(rdc) ^ sep() ^ hex_bits_10(nzimm @ 0b00) if nzimm != 0b00000000
-
-/* ****************************************************************** */
-union clause ast = C_LW : (bits(5), cregbits, cregbits)
-
-mapping clause encdec_compressed = C_LW(ui6 @ ui53 @ ui2, rs1, rd) <-> 0b010 @ ui53 : bits(3) @ rs1 : cregbits @ ui2 : bits(1) @ ui6 : bits(1) @ rd : cregbits @ 0b00
-
-function clause execute (C_LW(uimm, rsc, rdc)) =
- let imm : bits(12) = EXTZ(uimm @ 0b00) in
- let rd = creg2reg_bits(rdc) in
- let rs = creg2reg_bits(rsc) in
- execute(LOAD(imm, rs, rd, false, WORD, false, false))
-
-mapping clause assembly = C_LW(uimm, rsc, rdc) <-> "c.lw" ^ spc() ^ creg_name(rdc) ^ sep() ^ creg_name(rsc) ^ sep() ^ hex_bits_7(uimm @ 0b00)
-
-/* ****************************************************************** */
-union clause ast = C_LD : (bits(5), cregbits, cregbits)
-
-mapping clause encdec_compressed = C_LD(ui76 @ ui53, rs1, rd) <-> 0b011 @ ui53 : bits(3) @ rs1 : cregbits @ ui76 : bits(2) @ rd : cregbits @ 0b00
-
-function clause execute (C_LD(uimm, rsc, rdc)) =
- let imm : bits(12) = EXTZ(uimm @ 0b000) in
- let rd = creg2reg_bits(rdc) in
- let rs = creg2reg_bits(rsc) in
- execute(LOAD(imm, rs, rd, false, DOUBLE, false, false))
-
-mapping clause assembly = C_LD(uimm, rsc, rdc) <-> "c.ld" ^ spc() ^ creg_name(rdc) ^ sep() ^ creg_name(rsc) ^ sep() ^ hex_bits_8(uimm @ 0b000)
-
-/* ****************************************************************** */
-union clause ast = C_SW : (bits(5), cregbits, cregbits)
-
-mapping clause encdec_compressed = C_SW(ui6 @ ui53 @ ui2, rs1, rs2) <-> 0b110 @ ui53 : bits(3) @ rs1 : cregbits @ ui2 : bits(1) @ ui6 : bits(1) @ rs2 : cregbits @ 0b00
-
-function clause execute (C_SW(uimm, rsc1, rsc2)) =
- let imm : bits(12) = EXTZ(uimm @ 0b00) in
- let rs1 = creg2reg_bits(rsc1) in
- let rs2 = creg2reg_bits(rsc2) in
- execute(STORE(imm, rs2, rs1, WORD, false, false))
-
-mapping clause assembly = C_SW(uimm, rsc1, rsc2) <-> "c.sw" ^ spc() ^ creg_name(rsc1) ^ sep() ^ creg_name(rsc2) ^ sep() ^ hex_bits_7(uimm @ 0b00)
-
-/* ****************************************************************** */
-union clause ast = C_SD : (bits(5), cregbits, cregbits)
-
-mapping clause encdec_compressed = C_SD(ui76 @ ui53, rs1, rs2) <-> 0b111 @ ui53 : bits(3) @ rs1 : bits(3) @ ui76 : bits(2) @ rs2 : bits(3) @ 0b00
-
-function clause execute (C_SD(uimm, rsc1, rsc2)) =
- let imm : bits(12) = EXTZ(uimm @ 0b000) in
- let rs1 = creg2reg_bits(rsc1) in
- let rs2 = creg2reg_bits(rsc2) in
- execute(STORE(imm, rs2, rs1, DOUBLE, false, false))
-
-mapping clause assembly = C_SD(uimm, rsc1, rsc2) <-> "c.sd" ^ spc() ^ creg_name(rsc1) ^ sep() ^ creg_name(rsc2) ^ sep() ^ hex_bits_8(uimm @ 0b000)
-
-/* ****************************************************************** */
-union clause ast = C_ADDI : (bits(6), regbits)
-
-mapping clause encdec_compressed = C_ADDI(nzi5 @ nzi40, rsd) if nzi5 @ nzi40 != 0b000000 & rsd != zreg <-> 0b000 @ nzi5 : bits(1) @ rsd : regbits @ nzi40 : bits(5) @ 0b01 if nzi5 @ nzi40 != 0b000000 & rsd != zreg
-
-function clause execute (C_ADDI(nzi, rsd)) =
- let imm : bits(12) = EXTS(nzi) in
- execute(ITYPE(imm, rsd, rsd, RISCV_ADDI))
-
-mapping clause assembly = C_ADDI(nzi, rsd) if nzi != 0b000000 & rsd != zreg <-> "c.addi" ^ spc() ^ reg_name(rsd) ^ sep() ^ hex_bits_6(nzi) if nzi != 0b000000 & rsd != zreg
-
-/* ****************************************************************** */
-union clause ast = C_JAL : (bits(11))
-union clause ast = C_ADDIW : (bits(6), regbits)
-
-/* FIXME: decoding differs for RVC32/RVC64. Below, we are assuming
- * RV64, and C_JAL is RV32 only. */
-
-mapping clause encdec_compressed = C_ADDIW(imm5 @ imm40, rsd) if rsd != zreg <-> 0b001 @ imm5 : bits(1) @ rsd : regbits @ imm40 : bits(5) @ 0b01 if rsd != zreg
-
-function clause execute (C_JAL(imm)) =
- execute(RISCV_JAL(EXTS(imm @ 0b0), ra))
-
-function clause execute (C_ADDIW(imm, rsd)) = {
- let imm : bits(32) = EXTS(imm);
- let rs_val = X(rsd);
- let res : bits(32) = rs_val[31..0] + imm;
- X(rsd) = EXTS(res);
- true
-}
-
-mapping clause assembly = C_JAL(imm) <-> "c.jal" ^ spc() ^ hex_bits_12(imm @ 0b0)
-
-mapping clause assembly = C_ADDIW(imm, rsd) <-> "c.addiw" ^ spc() ^ reg_name(rsd) ^ sep() ^ hex_bits_6(imm)
-
-/* ****************************************************************** */
-union clause ast = C_LI : (bits(6), regbits)
-
-mapping clause encdec_compressed = C_LI(imm5 @ imm40, rd) if rd != zreg <-> 0b010 @ imm5 : bits(1) @ rd : regbits @ imm40 : bits(5) @ 0b01 if rd != zreg
-
-function clause execute (C_LI(imm, rd)) =
- let imm : bits(12) = EXTS(imm) in
- execute(ITYPE(imm, zreg, rd, RISCV_ADDI))
-
-mapping clause assembly = C_LI(imm, rd) if rd != zreg <-> "c.li" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_6(imm) if rd != zreg
-
-/* ****************************************************************** */
-union clause ast = C_ADDI16SP : (bits(6))
-
-mapping clause encdec_compressed = C_ADDI16SP(nzi9 @ nzi87 @ nzi6 @ nzi5 @ nzi4)
- if nzi9 @ nzi87 @ nzi6 @ nzi5 @ nzi4 != 0b000000
- <-> 0b011 @ nzi9 : bits(1) @ /* x2 */ 0b00010 @ nzi4 : bits(1) @ nzi6 : bits(1) @ nzi87 : bits(2) @ nzi5 : bits(1) @ 0b01
- if nzi9 @ nzi87 @ nzi6 @ nzi5 @ nzi4 != 0b000000
-
-function clause execute (C_ADDI16SP(imm)) =
- let imm : bits(12) = EXTS(imm @ 0x0) in
- execute(ITYPE(imm, sp, sp, RISCV_ADDI))
-
-mapping clause assembly = C_ADDI16SP(imm) if imm != 0b000000 <-> "c.addi16sp" ^ spc() ^ hex_bits_6(imm) if imm != 0b000000
-
-/* ****************************************************************** */
-union clause ast = C_LUI : (bits(6), regbits)
-
-mapping clause encdec_compressed = C_LUI(imm17 @ imm1612, rd) if rd != zreg & rd != sp & imm17 @ imm1612 != 0b000000 <-> 0b011 @ imm17 : bits(1) @ rd : regbits @ imm1612 : bits(5) @ 0b01 if rd != zreg & rd != sp & imm17 @ imm1612 != 0b000000
-
-function clause execute (C_LUI(imm, rd)) =
- let res : bits(20) = EXTS(imm) in
- execute(UTYPE(res, rd, RISCV_LUI))
-
-mapping clause assembly = C_LUI(imm, rd) if rd != zreg & rd != sp & imm != 0b000000 <-> "c.lui" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_6(imm) if rd != zreg & rd != sp & imm != 0b000000
-
-/* ****************************************************************** */
-union clause ast = C_SRLI : (bits(6), cregbits)
-
-mapping clause encdec_compressed = C_SRLI(nzui5 @ nzui40, rsd) if nzui5 @ nzui40 != 0b000000 <-> 0b100 @ nzui5 : bits(1) @ 0b00 @ rsd : cregbits @ nzui40 : bits(5) @ 0b01 if nzui5 @ nzui40 != 0b000000
-
-function clause execute (C_SRLI(shamt, rsd)) =
- let rsd = creg2reg_bits(rsd) in
- execute(SHIFTIOP(shamt, rsd, rsd, RISCV_SRLI))
-
-mapping clause assembly = C_SRLI(shamt, rsd) if shamt != 0b000000 <-> "c.srli" ^ spc() ^ creg_name(rsd) ^ sep() ^ hex_bits_6(shamt) if shamt != 0b000000
-
-/* ****************************************************************** */
-union clause ast = C_SRAI : (bits(6), cregbits)
-
-mapping clause encdec_compressed = C_SRAI(nzui5 @ nzui40, rsd) if nzui5 @ nzui40 != 0b000000 <-> 0b100 @ nzui5 : bits(1) @ 0b01 @ rsd : cregbits @ nzui40 : bits(5) @ 0b01 if nzui5 @ nzui40 != 0b000000
-
-function clause execute (C_SRAI(shamt, rsd)) =
- let rsd = creg2reg_bits(rsd) in
- execute(SHIFTIOP(shamt, rsd, rsd, RISCV_SRAI))
-
-mapping clause assembly = C_SRAI(shamt, rsd) if shamt != 0b000000 <-> "c.srai" ^ spc() ^ creg_name(rsd) ^ sep() ^ hex_bits_6(shamt) if shamt != 0b000000
-
-/* ****************************************************************** */
-union clause ast = C_ANDI : (bits(6), cregbits)
-
-mapping clause encdec_compressed = C_ANDI(i5 @ i40, rsd) <-> 0b100 @ i5 : bits(1) @ 0b10 @ rsd : cregbits @ i40 : bits(5) @ 0b01
-
-function clause execute (C_ANDI(imm, rsd)) =
- let rsd = creg2reg_bits(rsd) in
- execute(ITYPE(EXTS(imm), rsd, rsd, RISCV_ANDI))
-
-mapping clause assembly = C_ANDI(imm, rsd) <-> "c.andi" ^ spc() ^ creg_name(rsd) ^ sep() ^ hex_bits_6(imm)
-
-/* ****************************************************************** */
-union clause ast = C_SUB : (cregbits, cregbits)
-
-mapping clause encdec_compressed = C_SUB(rsd, rs2) <-> 0b100 @ 0b0 @ 0b11 @ rsd : cregbits @ 0b00 @ rs2 : cregbits @ 0b01
-
-function clause execute (C_SUB(rsd, rs2)) =
- let rsd = creg2reg_bits(rsd) in
- let rs2 = creg2reg_bits(rs2) in
- execute(RTYPE(rs2, rsd, rsd, RISCV_SUB))
-
-mapping clause assembly = C_SUB(rsd, rs2) <-> "c.sub" ^ spc() ^ creg_name(rsd) ^ sep() ^ creg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = C_XOR : (cregbits, cregbits)
-
-mapping clause encdec_compressed = C_XOR(rsd, rs2) <-> 0b100 @ 0b0 @ 0b11 @ rsd : cregbits @ 0b01 @ rs2 : cregbits @ 0b01
-
-function clause execute (C_XOR(rsd, rs2)) =
- let rsd = creg2reg_bits(rsd) in
- let rs2 = creg2reg_bits(rs2) in
- execute(RTYPE(rs2, rsd, rsd, RISCV_XOR))
-
-mapping clause assembly = C_XOR(rsd, rs2) <-> "c.xor" ^ spc() ^ creg_name(rsd) ^ sep() ^ creg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = C_OR : (cregbits, cregbits)
-
-mapping clause encdec_compressed = C_OR(rsd, rs2) <-> 0b100 @ 0b0 @ 0b11 @ rsd : cregbits @ 0b10 @ rs2 : cregbits @ 0b01
-
-function clause execute (C_OR(rsd, rs2)) =
- let rsd = creg2reg_bits(rsd) in
- let rs2 = creg2reg_bits(rs2) in
- execute(RTYPE(rs2, rsd, rsd, RISCV_OR))
-
-mapping clause assembly = C_OR(rsd, rs2) <-> "c.or" ^ spc() ^ creg_name(rsd) ^ sep() ^ creg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = C_AND : (cregbits, cregbits)
-
-mapping clause encdec_compressed = C_AND(rsd, rs2) <-> 0b100 @ 0b0 @ 0b11 @ rsd : cregbits @ 0b11 @ rs2 : cregbits @ 0b01
-
-function clause execute (C_AND(rsd, rs2)) =
- let rsd = creg2reg_bits(rsd) in
- let rs2 = creg2reg_bits(rs2) in
- execute(RTYPE(rs2, rsd, rsd, RISCV_AND))
-
-mapping clause assembly = C_AND(rsd, rs2) <-> "c.and" ^ spc() ^ creg_name(rsd) ^ sep() ^ creg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = C_SUBW : (cregbits, cregbits)
-
-/* TODO: invalid on RV32 */
-mapping clause encdec_compressed = C_SUBW(rsd, rs2) <-> 0b100 @ 0b1 @ 0b11 @ rsd : cregbits @ 0b00 @ rs2 : cregbits @ 0b01
-
-function clause execute (C_SUBW(rsd, rs2)) =
- let rsd = creg2reg_bits(rsd) in
- let rs2 = creg2reg_bits(rs2) in
- execute(RTYPEW(rs2, rsd, rsd, RISCV_SUBW))
-
-mapping clause assembly = C_SUBW(rsd, rs2) <-> "c.subw" ^ spc() ^ creg_name(rsd) ^ sep() ^ creg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = C_ADDW : (cregbits, cregbits)
-
-/* TODO: invalid on RV32 */
-mapping clause encdec_compressed = C_ADDW(rsd, rs2) <-> 0b100 @ 0b1 @ 0b11 @ rsd : cregbits @ 0b01 @ rs2 : cregbits @ 0b01
-
-function clause execute (C_ADDW(rsd, rs2)) =
- let rsd = creg2reg_bits(rsd) in
- let rs2 = creg2reg_bits(rs2) in
- execute(RTYPEW(rs2, rsd, rsd, RISCV_ADDW))
-
-mapping clause assembly = C_ADDW(rsd, rs2) <-> "c.addw" ^ spc() ^ creg_name(rsd) ^ sep() ^ creg_name(rs2)
-
-/* ****************************************************************** */
-union clause ast = C_J : (bits(11))
-
-mapping clause encdec_compressed = C_J(i11 @ i10 @ i98 @ i7 @ i6 @ i5 @ i4 @ i31) <-> 0b101 @ i11 : bits(1) @ i4 : bits(1) @ i98 : bits(2) @ i10 : bits(1) @ i6 : bits(1) @ i7 : bits(1) @ i31 : bits(3) @ i5 : bits(1) @ 0b01
-
-function clause execute (C_J(imm)) =
- execute(RISCV_JAL(EXTS(imm @ 0b0), zreg))
-
-mapping clause assembly = C_J(imm) <-> "c.j" ^ spc() ^ hex_bits_11(imm)
-
-/* ****************************************************************** */
-union clause ast = C_BEQZ : (bits(8), cregbits)
-
-mapping clause encdec_compressed = C_BEQZ(i8 @ i76 @ i5 @ i43 @ i21, rs) <-> 0b110 @ i8 : bits(1) @ i43 : bits(2) @ rs : cregbits @ i76 : bits(2) @ i21 : bits(2) @ i5 : bits(1) @ 0b01
-
-function clause execute (C_BEQZ(imm, rs)) =
- execute(BTYPE(EXTS(imm @ 0b0), zreg, creg2reg_bits(rs), RISCV_BEQ))
-
-mapping clause assembly = C_BEQZ(imm, rs) <-> "c.beqz" ^ spc() ^ creg_name(rs) ^ sep() ^ hex_bits_8(imm)
-
-/* ****************************************************************** */
-union clause ast = C_BNEZ : (bits(8), cregbits)
-
-mapping clause encdec_compressed = C_BNEZ(i8 @ i76 @ i5 @ i43 @ i21, rs) <-> 0b111 @ i8 : bits(1) @ i43 : bits(2) @ rs : cregbits @ i76 : bits(2) @ i21 : bits(2) @ i5 : bits(1) @ 0b01
-
-function clause execute (C_BNEZ(imm, rs)) =
- execute(BTYPE(EXTS(imm @ 0b0), zreg, creg2reg_bits(rs), RISCV_BNE))
-
-mapping clause assembly = C_BNEZ(imm, rs) <-> "c.bnez" ^ spc() ^ creg_name(rs) ^ sep() ^ hex_bits_8(imm)
-
-/* ****************************************************************** */
-union clause ast = C_SLLI : (bits(6), regbits)
-
-/* TODO: On RV32, also need shamt[5] == 0 */
-mapping clause encdec_compressed = C_SLLI(nzui5 @ nzui40, rsd) if nzui5 @ nzui40 != 0b000000 & rsd != zreg
- <-> 0b000 @ nzui5 : bits(1) @ rsd : regbits @ nzui40 : bits(5) @ 0b10 if nzui5 @ nzui40 != 0b000000 & rsd != zreg
-
-function clause execute (C_SLLI(shamt, rsd)) =
- execute(SHIFTIOP(shamt, rsd, rsd, RISCV_SLLI))
-
-mapping clause assembly = C_SLLI(shamt, rsd) if shamt != 0b000000 & rsd != zreg
- <-> "c.slli" ^ spc() ^ reg_name(rsd) ^ sep() ^ hex_bits_6(shamt) if shamt != 0b000000 & rsd != zreg
-
-/* ****************************************************************** */
-union clause ast = C_LWSP : (bits(6), regbits)
-
-mapping clause encdec_compressed = C_LWSP(ui76 @ ui5 @ ui42, rd) if rd != zreg
- <-> 0b010 @ ui5 : bits(1) @ rd : regbits @ ui42 : bits(3) @ ui76 : bits(2) @ 0b10 if rd != zreg
-
-function clause execute (C_LWSP(uimm, rd)) =
- let imm : bits(12) = EXTZ(uimm @ 0b00) in
- execute(LOAD(imm, sp, rd, false, WORD, false, false))
-
-mapping clause assembly = C_LWSP(uimm, rd) if rd != zreg <-> "c.lwsp" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_6(uimm) if rd != zreg
-
-/* ****************************************************************** */
-union clause ast = C_LDSP : (bits(6), regbits)
-
-mapping clause encdec_compressed = C_LDSP(ui86 @ ui5 @ ui43, rd) if rd != zreg <-> 0b011 @ ui5 : bits(1) @ rd : regbits @ ui43 : bits(2) @ ui86 : bits(3) @ 0b10 if rd != zreg
-
-function clause execute (C_LDSP(uimm, rd)) =
- let imm : bits(12) = EXTZ(uimm @ 0b000) in
- execute(LOAD(imm, sp, rd, false, DOUBLE, false, false))
-
-mapping clause assembly = C_LDSP(uimm, rd) if rd != zreg <-> "c.ldsp" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_6(uimm) if rd != zreg
-
-/* ****************************************************************** */
-union clause ast = C_SWSP : (bits(6), regbits)
-
-mapping clause encdec_compressed = C_SWSP(ui76 @ ui52, rs2) <-> 0b110 @ ui52 : bits(4) @ ui76 : bits(2) @ rs2 : regbits @ 0b10
-
-function clause execute (C_SWSP(uimm, rs2)) =
- let imm : bits(12) = EXTZ(uimm @ 0b00) in
- execute(STORE(imm, rs2, sp, WORD, false, false))
-
-mapping clause assembly = C_SWSP(uimm, rd) <-> "c.swsp" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_6(uimm)
-
-/* ****************************************************************** */
-union clause ast = C_SDSP : (bits(6), regbits)
-
-mapping clause encdec_compressed = C_SDSP(ui86 @ ui53, rs2) <-> 0b111 @ ui53 : bits(3) @ ui86 : bits(3) @ rs2 : regbits @ 0b10
-
-function clause execute (C_SDSP(uimm, rs2)) =
- let imm : bits(12) = EXTZ(uimm @ 0b000) in
- execute(STORE(imm, rs2, sp, DOUBLE, false, false))
-
-mapping clause assembly = C_SDSP(uimm, rs2) <-> "c.sdsp" ^ spc() ^ reg_name(rs2) ^ sep() ^ hex_bits_6(uimm)
-
-/* ****************************************************************** */
-union clause ast = C_JR : (regbits)
-
-mapping clause encdec_compressed = C_JR(rs1) if rs1 != zreg <-> 0b100 @ 0b0 @ rs1 : regbits @ 0b00000 @ 0b10 if rs1 != zreg
-
-function clause execute (C_JR(rs1)) =
- execute(RISCV_JALR(EXTZ(0b0), rs1, zreg))
-
-mapping clause assembly = C_JR(rs1) if rs1 != zreg <-> "c.jr" ^ spc() ^ reg_name(rs1) if rs1 != zreg
-
-/* ****************************************************************** */
-union clause ast = C_JALR : (regbits)
-
-mapping clause encdec_compressed = C_JALR(rs1) if rs1 != zreg <-> 0b100 @ 0b1 @ rs1 : regbits @ 0b00000 @ 0b10 if rs1 != zreg
-
-function clause execute (C_JALR(rs1)) =
- execute(RISCV_JALR(EXTZ(0b0), rs1, ra))
-
-mapping clause assembly = C_JALR(rs1) if rs1 != zreg <-> "c.jalr" ^ spc() ^ reg_name(rs1) if rs1 != zreg
-
-/* ****************************************************************** */
-union clause ast = C_MV : (regbits, regbits)
-
-mapping clause encdec_compressed = C_MV(rd, rs2) if rd != zreg & rs2 != zreg <-> 0b100 @ 0b0 @ rd : regbits @ rs2 : regbits @ 0b10 if rd != zreg & rs2 != zreg
-
-function clause execute (C_MV(rd, rs2)) =
- execute(RTYPE(rs2, zreg, rd, RISCV_ADD))
-
-mapping clause assembly = C_MV(rd, rs2) if rd != zreg & rs2 != zreg <-> "c.mv" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs2) if rd != zreg & rs2 != zreg
-
-/* ****************************************************************** */
-union clause ast = C_EBREAK : unit
-
-mapping clause encdec_compressed = C_EBREAK() <-> 0b100 @ 0b1 @ 0b00000 @ 0b00000 @ 0b10
-
-function clause execute C_EBREAK() =
- execute(EBREAK())
-
-mapping clause assembly = C_EBREAK() <-> "c.ebreak"
-
-/* ****************************************************************** */
-union clause ast = C_ADD : (regbits, regbits)
-
-mapping clause encdec_compressed = C_ADD(rsd, rs2) if rsd != zreg & rs2 != zreg <-> 0b100 @ 0b1 @ rsd : regbits @ rs2 : regbits @ 0b10 if rsd != zreg & rs2 != zreg
-
-function clause execute (C_ADD(rsd, rs2)) =
- execute(RTYPE(rs2, rsd, rsd, RISCV_ADD))
-
-mapping clause assembly = C_ADD(rsd, rs2) if rsd != zreg & rs2 != zreg <-> "c.add" ^ spc() ^ reg_name(rsd) ^ sep() ^ reg_name(rs2) if rsd != zreg & rs2 != zreg
-
-/* ****************************************************************** */
-
-union clause ast = STOP_FETCHING : unit
-
-/* RMEM stop fetching sentinel, using RISCV encoding space custom-0 */
-mapping clause encdec = STOP_FETCHING() <-> 0xfade @ 0b00000000 @ 0b0 @ 0b00 @ 0b010 @ 0b11
-
-function clause execute (STOP_FETCHING()) = true
-
-mapping clause assembly = STOP_FETCHING() <-> "stop_fetching"
-
-union clause ast = THREAD_START : unit
-
-/* RMEM thread start sentinel, using RISCV encoding space custom-0 */
-mapping clause encdec = THREAD_START() <-> 0xc0de @ 0b00000000 @ 0b0 @ 0b00 @ 0b010 @ 0b11
-
-function clause execute (THREAD_START()) = true
-
-mapping clause assembly = THREAD_START() <-> "thread_start"
-
-
-/* ****************************************************************** */
-
-union clause ast = ILLEGAL : word
-
-mapping clause encdec = ILLEGAL(s) <-> s
-
-function clause execute (ILLEGAL(s)) = { handle_illegal(); false }
-
-mapping clause assembly = ILLEGAL(s) <-> "illegal" ^ spc() ^ hex_bits_32(s)
-
-
-
-/* ****************************************************************** */
-
-union clause ast = C_ILLEGAL : half
-
-mapping clause encdec_compressed = C_ILLEGAL(s) <-> s
-
-function clause execute C_ILLEGAL(s) = { handle_illegal(); false }
-
-mapping clause assembly = C_ILLEGAL(s) <-> "c.illegal" ^ spc() ^ hex_bits_16(s)
-
-/* ****************************************************************** */