burritos/src/simulator/mod.rs

664 lines
20 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

pub mod machine;
pub mod error;
pub mod instruction;
pub mod mem_cmp;
pub mod loader;
pub mod interrupt;
pub mod translationtable;
pub mod mmu;
pub mod register;
/// Definition of global constants
pub mod global {
#![allow(dead_code)]
#![allow(unused_variables)]
// Instructions type:
// - R: Register / register
// - I: Immediate
// - U: Upper-Immediate
// - S: Store
// - B: Branch (conditional branches...)
// - J: Jump
// xlen = i64::MAX_VALUE on rv64 and i32::MAX_VALUE on rv32
/// Type: U
///
/// Load upper immediate
///
/// `LUI rd, imm31_12` => `rd <- imm31_12 << 12`
///
pub const RISCV_LUI: u8 = 0x37;
/// Type: U
///
/// Add upper immediate to PC
///
/// `AUIP rd, imm31_12` => `rd <- PC + imm31_12 << 12`
pub const RISCV_AUIPC: u8 = 0x17;
/// Type: J
///
/// Jump and link
///
/// `JAL rd, imm20(rs1)` => `rd <- pc + 4; pc <- rs1 + imm12`
pub const RISCV_JAL: u8 = 0x6f;
/// type: J
///
/// Jump and link register
///
/// `JALR rd, imm12(rs1)` => `rd <- pc + 4; pc <- rs1 + imm12`
pub const RISCV_JALR: u8 = 0x67;
pub const RISCV_BR: u8 = 0x63;
/// Load instructions
///
/// See func3 to know the type of instruction (LD, LW, LH, LB, LWU, LHU, LBU)
pub const RISCV_LD: u8 = 0x3;
/// Store instructions
pub const RISCV_ST: u8 = 0x23;
/// immediate Arithmetic operations
pub const RISCV_OPI: u8 = 0x13;
/// Arithmetic operations
pub const RISCV_OP: u8 = 0x33;
/// Immediate arithmetic operations for rv64i
pub const RISCV_OPIW: u8 = 0x1b;
/// Arithmetic operations for rv64i
pub const RISCV_OPW: u8 = 0x3b;
/// Type: B
///
/// Branch equal
///
/// `BEQ rs1, rs2, imm12` => `if rs1 = rs2 then pc <- pc + imm12`
pub const RISCV_BR_BEQ: u8 = 0x0;
/// Type: B
///
/// Branch not equal
///
/// `BNE rs1, rs2, imm12` => `if rs1 != rs2 then pc <- pc + imm12`
pub const RISCV_BR_BNE: u8 = 0x1;
/// Type: B
///
/// Branch less than
///
/// `BLT rs1, rs2, imm12` => `if rs1 < rs2 then pc <- pc + imm12`
pub const RISCV_BR_BLT: u8 = 0x4;
/// Type: B
///
/// Branch greater than or equal
///
/// `BGE rs1, rs2, imm12` => `if rs1 >= rs2 then pc <- pc + imm12`
pub const RISCV_BR_BGE: u8 = 0x5;
/// Type: B
///
/// Branch less than unsigned
///
/// Same as BLT but for unsigned values
pub const RISCV_BR_BLTU: u8 = 0x6;
/// Type: B
///
/// Greater than or equal unsigned
///
/// Same as BGE but for unsigned values
pub const RISCV_BR_BGEU: u8 = 0x7;
/// Type: I
///
/// Load byte (8 bits word)
///
/// `LB rd, imm12(rs1)` => `rd <- mem[rs1 + imm12]`
pub const RISCV_LD_LB: u8 = 0x0;
/// Type: I
///
/// Load halfword (16 bits word)
///
/// `LH rd, imm12(rs1)` => `rd <- mem[rs1 + imm12]`
pub const RISCV_LD_LH: u8 = 0x1;
/// Type: I
///
/// Load word (32 bits word)
///
/// `LW rd, imm12(rs1)` => `rd <- mem[rs1 + imm12]`
pub const RISCV_LD_LW: u8 = 0x2;
/// Type: I
///
/// Load doubleword (64-bits word)
///
/// `LD rd, imm12(rs1)` => `rd <- mem[rs1 + imm12]`
pub const RISCV_LD_LD: u8 = 0x3;
/// Type: I
///
/// Load byte unsigned
///
/// `LBU rd, imm12(rs1)` => `rd <- mem[rs1 + imm12]`
pub const RISCV_LD_LBU: u8 = 0x4;
/// Type: I
///
/// Load halfword unsigned
///
/// `LHU rd, imm12(rs1)` => `rd <- mem[rs1 + imm12]`
pub const RISCV_LD_LHU: u8 = 0x5;
/// Type: I
///
/// Load word unsigned (64 bits word)
///
/// `LW rd, imm12(rs1)` => `rd <- mem[rs1 + imm12]`
pub const RISCV_LD_LWU: u8 = 0x6;
/// Type: S
///
/// Store halfword (SH) (16 bits)
///
/// In case of overflow (rs2 is a 64 bits reg), only the first 16 bits values are stored
///
/// `SH rs2, imm12(rs1)` => `rs2 -> mem[rs1 + imm12]`
pub const RISCV_ST_STH: u8 = 0x1;
/// Type: S
///
/// Store word (SW) (32 bits)
///
/// In case of overflow (rs2 is a 64 bits reg), only the first 32 bits values are stored
///
/// `SW rs2, imm12(rs1)` => `rs2 -> mem[rs1 + imm12]`
pub const RISCV_ST_STW: u8 = 0x2;
/// Type: S
///
/// Store byte (SB) (8 bits)
///
/// In case of overflow (rs2 is a 64 bits reg), only the first 8 bits values are stored
///
/// `SB rs2, imm12(rs1)` => `rs2 -> mem[rs1 + imm12]`
pub const RISCV_ST_STB: u8 = 0x0;
/// Type: S
///
/// Store doubleword (SD) (64 bits)
///
/// `SD rs2, imm12(rs1)` => `rs2 -> mem[rs1 + imm12]`
pub const RISCV_ST_STD: u8 = 0x3;
/// Type: I
///
/// Add immediate
///
/// `addi rd, rs1, imm12` => `rd <- rs1 + imm12`
pub const RISCV_OPI_ADDI: u8 = 0x0;
/// Type: I
///
/// Set less than immediate: set rd to 1 if rs1 < imm12, 0 otherwise
///
/// `SLT rd, rs1, imm12` => `rd <- rs1 < imm12 ? 1 : 0`
pub const RISCV_OPI_SLTI: u8 = 0x2;
/// Type: I
///
/// Set less than immediate unsigned : same than SLTI but for unsigned values
pub const RISCV_OPI_SLTIU: u8 = 0x3;
/// Type: I
///
/// XOR immediate instruction
///
/// `XORI rd, rs1, imm12` => `rd <- rs1 ^ imm12`
pub const RISCV_OPI_XORI: u8 = 0x4;
/// Type: I
///
/// OR immediate instruction
///
/// `ORI rd, rs1, imm12` => `rd <- rs1 | imm12`
pub const RISCV_OPI_ORI: u8 = 0x6;
/// Type: I
///
/// AND immediate instruction
///
/// `ANDI rd, rs1, imm12` => `rd <- rs1 & imm12`
pub const RISCV_OPI_ANDI: u8 = 0x7;
/// Type: I
///
/// Shift left logical immediate
///
/// `SLLI rd, rs1, shamt` => `rd <- rs1 >> shamt`
pub const RISCV_OPI_SLLI: u8 = 0x1;
/// Shift right immediate, may be SRAI or SRLI
pub const RISCV_OPI_SRI: u8 = 0x5;
/// type: I
///
/// Shift right arithmetic immediate
///
/// `SRAI rd, rs1, shamt` => `rd <- rs1 >> shamt`
pub const RISCV_OPI_SRI_SRAI: u8 = 0x20;
/// type: I
///
/// Shift right logical immediate
///
/// `SRLI rd, rs1, shamt` => `rd <- rs1 >> shamt`
pub const RISCV_OPI_SRI_SRLI: u8 = 0x0;
/// Type: R
///
/// Add or sub (see RISCV_OP_ADD_ADD or RISCV_OP_ADD_SUB) depending of func7 value
pub const RISCV_OP_ADD: u8 = 0x0;
/// Type: R
///
/// Shift left logical, add a 0 on right of the word
///
/// `SLL rd, rs1, rs2` => `rs <- rs1 << rs2`
pub const RISCV_OP_SLL: u8 = 0x1;
/// Type: R
///
/// Set less than : set rd to 1 if rs1 < rs2, 0 otherwise
///
/// `SLT rd, rs1, rs2` => `rd <- rs1 < rs2 ? 1 : 0`
pub const RISCV_OP_SLT: u8 = 0x2;
/// Type: R
///
/// Set less than unsigned : same than SLT but for unsigned values
pub const RISCV_OP_SLTU: u8 = 0x3;
/// Type: R
///
/// XOR instruction
///
/// `XOR rd, rs1, rs2` => `rd <- rs1 ^ rs2`
pub const RISCV_OP_XOR: u8 = 0x4;
pub const RISCV_OP_SR: u8 = 0x5;
/// Type: R
///
/// OR instruction
///
/// `OR rd, rs1, rs2` => `rd <- rs1 | rs2`
pub const RISCV_OP_OR: u8 = 0x6;
/// Type: R
///
/// AND instruction
///
/// `AND rd, rs1, rs2` => `rd <- rs1 & rs2`
pub const RISCV_OP_AND: u8 = 0x7;
/// Type : R
///
/// Addition
///
/// `ADD rd, rs1, rs2` => `rd <- rs1 + rs2`
pub const RISCV_OP_ADD_ADD: u8 = 0x0;
/// Type: R
///
/// Substract
///
/// `SUB rd, rs1, rs2` => `rd <- rs1 - rs2`
pub const RISCV_OP_ADD_SUB: u8 = 0x20;
/// Type: R
///
/// Shift right logical, add a 0 at the left of the word (should not used for signed values in most cases)
///
/// `SRL rd, rs1, rs2` => `rd <- rs1 >> rs2`
pub const RISCV_OP_SR_SRL: u8 = 0x0;
/// Type: R
///
/// Shift right arithmetic, add a 1 at the left of the word(useful for signed values bacause it keep signed value)
///
/// `SRA rd, rs1, rs2` => `rd <- rs1 >> rs2`
pub const RISCV_OP_SR_SRA: u8 = 0x20;
// ECALL or EBREAK from base instructions
/// or instructions from Ricsr extension
pub const RISCV_SYSTEM: u8 = 0x73;
/// Type: I
///
/// Add immediate word (RV64I only)
///
/// `ADDIW rd, rs1, imm12` => `rd <- rs1 + imm12`
pub const RISCV_OPIW_ADDIW: u8 = 0x0;
/// Type: I
///
/// Shift right logical immediate word (RV64I only)
///
/// `SLLIW rd, rs1, imm12` => `rd <- rs1 >> shamt`
pub const RISCV_OPIW_SLLIW: u8 = 0x1;
/// Shift right immediate instructions (logical or arithmetic depend of func7)
pub const RISCV_OPIW_SRW: u8 = 0x5;
/// Type: I
///
/// Shift right logical immediate word (RV64I only)
///
/// `SRLIW rd, rs1, imm12` => `rd <- rs1 >> shamt`
///
/// Complete left bits by a zero, should be used with an unsigned value in most case
pub const RISCV_OPIW_SRW_SRLIW: u8 = 0x0;
/// Type: I
///
/// Shift right arithmetic immediate word (RV64I only)
///
/// `SRAIW rd, rs1, imm12` => `rd <- rs1 >> shamt`
///
/// Keep sign bit
pub const RISCV_OPIW_SRW_SRAIW: u8 = 0x20;
// ADD or SUB immediate instructions, depend of func7 value
pub const RISCV_OPW_ADDSUBW: u8 = 0x0;
/// Type: R
///
/// Shift left logical word (RV64I only)
///
/// `SLLW rd, rs1, rs2` => `rd <- rs1 << rs2`
pub const RISCV_OPW_SLLW: u8 = 0x1;
/// Shift right word instructions (logical or arithmetic depend of func3)
pub const RISCV_OPW_SRW: u8 = 0x5;
/// Type: R
///
/// Add word (rv64I only)
///
/// `ADDW rd, rs1, rs2` => `rd <- rs1 + rs2`
pub const RISCV_OPW_ADDSUBW_ADDW: u8 = 0x0;
/// Type: R
///
/// Subtract word (rv64I only)
///
/// `SUBW rd, rs1, rs2` => `rd <- rs1 - rs2`
pub const RISCV_OPW_ADDSUBW_SUBW: u8 = 0x20;
/// Type: R
///
/// Shift right logical word (rv64I only)
///
/// rd <- rs1 >> rs2
///
/// Complete left bits by a 0, should be used with an unsigned value
pub const RISCV_OPW_SRW_SRLW: u8 = 0x0;
/// Type: R
///
/// Shift right arithmetic word (rv64I only)
///
/// `SRAW rd, rs1, rs2` => `rd <- rs1 >> rs2`
///
/// Keep sign bit
pub const RISCV_OPW_SRW_SRAW: u8 = 0x20;
pub const RISCV_SYSTEM_ENV: u8 = 0x0;
pub const RISCV_SYSTEM_ENV_ECALL: u8 = 0x0;
pub const RISCV_SYSTEM_ENV_EBREAK: u8 = 0x1;
pub const RISCV_SYSTEM_CSRRS: u8 = 0x2;
pub const RISCV_SYSTEM_CSRRW: u8 = 0x1;
pub const RISCV_SYSTEM_CSRRC: u8 = 0x3;
pub const RISCV_SYSTEM_CSRRWI: u8 = 0x5;
pub const RISCV_SYSTEM_CSRRSI: u8 = 0x6;
pub const RISCV_SYSTEM_CSRRCI: u8 = 0x7;
pub const RISCV_FLW: u8 = 0x07;
pub const RISCV_FSW: u8 = 0x27;
pub const RISCV_FMADD: u8 = 0x43;
pub const RISCV_FMSUB: u8 = 0x47;
pub const RISCV_FNMSUB: u8 = 0x4b;
pub const RISCV_FNMADD: u8 = 0x4f;
/// Simple floating point extension
pub const RISCV_FP: u8 = 0x53;
/// Type: R
///
/// Simple precision floating point addition
///
/// `FADD.S rd, rs1, rs2` => `rd <- rs1 + rs2`
pub const RISCV_FP_ADD: u8 = 0x0;
/// Type: R
///
/// Simple precision floating point substraction
///
/// `FSUB.S rd, rs1, rs2` => `rd <- rs1 - rs2`
pub const RISCV_FP_SUB: u8 = 0x4;
/// Type: R
///
/// Simple precision floating point multiplication
///
/// `fmul.s rd, rs1, rs2` => `rd <- rs1 * rs2`
pub const RISCV_FP_MUL: u8 = 0x8;
/// Type : R
///
/// Simple precision floating point division
///
/// `fdiv.s rd, rs1, rs2` => `rd <- rs1 / rs2`
pub const RISCV_FP_DIV: u8 = 0xc;
/// Type: R
///
/// Simple precision square root
///
/// `fsqrt.s rd, rs1` => `rd <- sqrt(rs1)`
pub const RISCV_FP_SQRT: u8 = 0x2c;
/// FSGN instructions
pub const RISCV_FP_FSGN: u8 = 0x10;
// fmin or fmax instructions
pub const RISCV_FP_MINMAX: u8 = 0x14;
/// fcvt.w instructions
///
/// convert fp to integer
pub const RISCV_FP_FCVTW: u8 = 0x60;
/// fmv.x.w or fclass.s instruction
pub const RISCV_FP_FMVXFCLASS: u8 = 0x70;
/// floating points comparaison instructions
pub const RISCV_FP_FCMP: u8 = 0x50;
pub const RISCV_FP_FEQS: u8 = 0x53;
/// fcvt.s instructions
///
/// Convert integer to fp
pub const RISCV_FP_FCVTS: u8 = 0x68;
pub const RISCV_FP_FCVTDS: u8 = 0x21;
/// Type: R
///
/// Take all bits except sign bit from rs1. sign is rs2's sign bit
///
/// `fsgnj.s rd, rs1, rs2` => `rd <- {rs2[31], rs1[30:0]}`
pub const RISCV_FP_FSGN_J: u8 = 0x0;
/// Type: R
///
/// Take all bits except sign bit from rs1, sign is opposite of rs2's sign bit
///
/// `fsgnjs.s rd, rs1, rs2` => `rd <- {rs2[31], rs[30:0]}`
pub const RISCV_FP_FSGN_JN: u8 = 0x1;
/// Type: R
///
/// Take all bits except sign bit from rs1, sign is XOR of sign bit of rs1 and rs2
///
/// `fsgnjx.s rd, rs1, rs2` => `rd <- {rs1[31] ^ rs2[31], rs1[30:0]}`
pub const RISCV_FP_FSGN_JX: u8 = 0x2;
/// Type: R
///
/// write the smaller number between rs1 and rs2 to rd
///
/// `fmin.s rd, rs1, rs2` => `rd <- min(rs1, rs2)`
pub const RISCV_FP_MINMAX_MIN: u8 = 0x0;
/// type: R
///
/// Write the larger number between rs1 and rs2 to rd
///
/// `fmax.s rd, rs1, rs2` => `rd <- max(rs1, rs2)`
pub const RISCV_FP_MINMAX_MAX: u8 = 0x1;
/// Type: R
///
/// Convert a floating point number in register to a signed 32-bit integer and write it in integer register
///
/// `fcvt.w.s rd, rs1` => `rd <- rs1_f32 as i32`
///
/// rd is integer register and rs1 is floating point register
pub const RISCV_FP_FCVTW_W: u8 = 0x0;
/// Type: R
///
/// Convert a floating point number in register to a unsigned 32 bit integer and write it in integer register
///
/// `fcvt.wu.s rd, rs1` => `rd <- rs1_f32 as u32`
pub const RISCV_FP_FCVTW_WU: u8 = 0x1;
/// Type : R
///
/// Convert signed 32 bit integer in register to a floating point number and write it in fp register
///
/// `fcvt.s.w rd, rs1` => `rd <- rs1_s32 as f32`
pub const RISCV_FP_FCVTS_W: u8 = 0x0;
/// Type: R
///
/// Convert unsigned 32 bit integer in register to a floating point number and write it in fp register
///
/// `fcvt.s.wu rd, rs1` => `rd <- rs1_u32 as f32`
pub const RISCV_FP_FCVTS_WU: u8 = 0x1;
/// Type: R
///
/// Move floating point value in register to integer register, bits value aren't modified during the process
///
/// On rv64, the lower 32 bits of the integer register are transfered, for the upper 32 bits, values are filles with copies of the floating point number's sign bit
///
/// `fmv.x.w rd ,rs1` => `rd[31,0] <- rs1; rd[63:32] <- rs[31]`
pub const RISCV_FP_FMVXFCLASS_FMVX: u8 = 0x0;
/// Type: R
///
/// examine the value given in fp register rs1 and writes to integer register rd a 10 bit mask that indicates the class of the fp number.
/// Format is described here:
///
/// | rd bit | meaning |
/// |--------|------------------------------------|
/// | 0 | rs1 is -infinite |
/// | 1 | rs1 is a negative normal number |
/// | 2 | rs1 is a negative subnormal number |
/// | 3 | rs1 is -0 |
/// | 4 | rs1 is +0 |
/// | 5 | rs1 is a positive subnormal number |
/// | 6 | rs1 is a positive normal number |
/// | 7 | rs1 is +infinite |
/// | 8 | rs1 is a signaling NaN |
/// | 9 | rs1 is a quiet NaN |
///
/// All others bit in rd are cleared
pub const RISCV_FP_FMVXFCLASS_FCLASS: u8 = 0x1;
/// Type: R
///
/// Quiet equal comparaison, NaN cause an invalid operation exception
///
/// `feq.s rd, rs1, rs2` => `rd <- rs1 == rs2`
pub const RISCV_FP_FCMP_FEQ: u8 = 2;
/// Type: R
///
/// Quiet less comparaison, NaN cause an invalid operation exception
///
/// `flt.s rd, rs1, rs2` => `rdf <- rs1 < rs2`
pub const RISCV_FP_FCMP_FLT: u8 = 1;
/// Type: R
///
/// Quiet less or equal comparaison, NaN cause an invalid operation exception
///
/// `fle.s rd, rs1, rs2` => `rd <- rs1 <= rs2`
pub const RISCV_FP_FCMP_FLE: u8 = 0;
/// Type : R
///
/// Move floating point value in integer register to the fp register. Bits aren't modified in the transfer
///
/// On rv64, only the lower 32 bits in the integer register are transfered.
///
/// `fmv.w.x rd, rs1` => `rd <- rs1[31:0]`
pub const RISCV_FP_FMVW: u8 = 0x78;
/// Integer, multiplication and division extension
pub const RISCV_OP_M: u8 = 0x1;
/// Type: R
///
/// Multiply
///
/// `MUL rd, rs1, rs2` => `rd <- rs1 * rs2`
pub const RISCV_OP_M_MUL: u8 = 0x0;
/// Type: R
///
/// Multiply high signed signed
///
/// `MULH rd, rs1, rs2` => `rd <- (rs1 * rs2) >> xlen`
///
/// rs1 and rs2 signed
pub const RISCV_OP_M_MULH: u8 = 0x1;
/// Type: R
///
/// Multiply high signed unsigned
///
/// `MULHSU rd, rs1, rs2` => `rd <- (rs1 x rs2) >> xlen`
///
/// rs1 is signed and rs2 is unsigned
pub const RISCV_OP_M_MULHSU: u8 = 0x2;
/// Type: R
///
/// Multiply high unsigned unsigned
///
/// `MULHU rd, rs1, rs2` => `rd <- (rs1 × rs2) >> xlen`
///
/// rs1 and rs2 unsigned
pub const RISCV_OP_M_MULHU: u8 = 0x3;
/// Type: R
///
/// Divide signed
///
/// `DIV rd, rs1, rs2` => `rd <- r1 / rs2`
pub const RISCV_OP_M_DIV: u8 = 0x4;
/// Type: R
///
/// Divide unsigned
///
/// `DIVU rd, rs1, rs2` => `rd <- rs1 / rs2`
pub const RISCV_OP_M_DIVU: u8 = 0x5;
/// Type: R
///
/// Remainder signed
///
/// `REM rd, rs1, rs2` => `rd <- rs1 % rs2`
pub const RISCV_OP_M_REM: u8 = 0x6;
/// Type: R
///
/// Remaindder unsigned
///
/// `REMU rd, rs1, rs2` => `rd <- rs1 % rs2`
pub const RISCV_OP_M_REMU: u8 = 0x7;
/// Type: R
///
/// Multiply Word (rv64M only)
///
/// `MULW rd, rs1, rs2` => `rd <- rs1 * rs2`
pub const RISCV_OPW_M_MULW: u8 = 0x0;
/// Type: R
///
/// Divide signed word (RV64M only)
///
/// `DIVW rd, rs1, rs2` => `rd <- rs1 / rs2`
pub const RISCV_OPW_M_DIVW: u8 = 0x4;
/// Type: R
///
/// Divide unsigned word
///
/// `DIVUW rd, rs1, rs2` => `red <- rs1 / rs2`
pub const RISCV_OPW_M_DIVUW: u8 = 0x5;
/// Type: R
///
/// Remainder signed word (RV64M only)
///
/// `REMW rd, rs1, rs2` => `rd <- rs1 % rs2`
pub const RISCV_OPW_M_REMW: u8 = 0x6;
/// Type: R
///
/// Remainder unsigned word (RV64M only)
///
/// `REMUW rd, rs1, rs2` => `rd <- rs1 % rs2`
pub const RISCV_OPW_M_REMUW: u8 = 0x7;
/// Instruction from Zifencei extension
pub const RISCV_FENCE: u8 = 0x0f;
/// Atomic instructions extension
pub const RISCV_ATOM: u8 = 0x2f;
pub const RISCV_ATOM_LR: u8 = 0x2;
pub const RISCV_ATOM_SC: u8 = 0x3;
pub const RISCV_ATOM_SWAP: u8 = 0x1;
pub const RISCV_ATOM_ADD: u8 = 0;
pub const RISCV_ATOM_XOR: u8 = 0x4;
pub const RISCV_ATOM_AND: u8 = 0xc;
pub const RISCV_ATOM_OR: u8 = 0x8;
pub const RISCV_ATOM_MIN: u8 = 0x10;
pub const RISCV_ATOM_MAX: u8 = 0x14;
pub const RISCV_ATOM_MINU: u8 = 0x18;
pub const RISCV_ATOM_MAXU: u8 = 0x1c;
}