123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- use XReg::*;
- use core::ops::ControlFlow;
- use sbi_spec::binary::SbiRet;
- pub struct SimpleRv128IHart {
- xregs: [u128; 32],
- pc: u128,
- inst_memory: InstMemory<0x2000_0000, { 0x4000 / 4 }>,
- }
- fn main() {
-
- let mut memory = InstMemory::new_unimp();
-
-
- memory.li(0x0, A0, 0x10);
- memory.li(0x4, A6, 3);
- memory.li(0x8, A7, 0x10);
- memory.ecall(0xC);
-
- memory.beqz(0x10, A1, 0x1C);
-
- memory.li(0x14, A0, 0x0);
- memory.li(0x18, A1, 0x0);
- memory.li(0x1C, A6, 0x0);
- memory.li(0x20, A7, 0x53525354);
- memory.ecall(0x28);
-
- memory.li(0x2C, A0, 0x0);
- memory.li(0x30, A1, 0x1);
- memory.li(0x34, A6, 0x0);
- memory.li(0x38, A7, 0x53525354);
- memory.ecall(0x44);
-
- let mut hart = SimpleRv128IHart::new(memory);
- println!("Starting SimpleRv128IHart...");
-
-
- let emulation_result = loop {
- match hart.stepi() {
- Ok(()) => {}
- Err(Exception::SupervisorEcall) => match handle_ecall(&mut hart) {
-
- ControlFlow::Break(value) => break value,
-
- ControlFlow::Continue(()) => continue,
- },
-
- Err(e) => {
- println!("Emulation failed for unexpected exception: {:?}", e);
- return;
- }
- }
- };
-
- println!("Emulation finished. Result: {}", emulation_result);
- if emulation_result == 0 {
- println!("✓ Test success!");
- } else {
- println!("✗ Test failed, emulator returns {}", emulation_result);
- }
- }
- fn handle_sbi_call(extension: u128, function: u128, param: [u128; 6]) -> SbiRet<u128> {
- match (extension, function) {
-
- (0x10, 3) => {
- if param[0] == 0x10 {
- SbiRet::success(1)
- } else {
- SbiRet::success(0)
- }
- }
-
- (0x53525354, 0) => {
- let (reset_type, reset_reason) = (param[0], param[1]);
- if reset_type == sbi_spec::srst::RESET_TYPE_SHUTDOWN as u128 {
-
- SbiRet {
- value: reset_reason,
- error: 0x114514,
- }
- } else {
- SbiRet::not_supported()
- }
- }
-
- _ => SbiRet::not_supported(),
- }
- }
- fn handle_ecall(hart: &mut SimpleRv128IHart) -> ControlFlow<u128> {
- println!("Handle ecall, registers: {:x?}", hart.xregs);
-
- let param = [
- hart.xregs[A0 as usize],
- hart.xregs[A1 as usize],
- hart.xregs[A2 as usize],
- hart.xregs[A3 as usize],
- hart.xregs[A4 as usize],
- hart.xregs[A5 as usize],
- ];
-
- let ret = handle_sbi_call(hart.xregs[A7 as usize], hart.xregs[A6 as usize], param);
- println!("SbiRet: {:?}", ret);
-
- if ret.error == 0x114514 {
- return ControlFlow::Break(ret.value);
- }
-
- hart.xregs[A0 as usize] = ret.error;
- hart.xregs[A1 as usize] = ret.value;
-
- hart.pc = hart.pc.wrapping_add(4);
- ControlFlow::Continue(())
- }
- pub struct InstMemory<const BASE: usize, const N_INSNS: usize> {
- inner: [u32; N_INSNS],
- }
- const OPCODE_OP_IMM: u32 = 0b001_0011;
- const OPCODE_LUI: u32 = 0b011_0111;
- const OPCODE_BRANCH: u32 = 0b110_0011;
- const FUNCT3_OP_ADD_SUB: u32 = 0b000;
- const FUNCT3_BRANCH_BEQ: u32 = 0b000;
- impl<const BASE: usize, const N_INSNS: usize> InstMemory<BASE, N_INSNS> {
-
- pub fn new_unimp() -> Self {
- Self {
- inner: [0; N_INSNS],
- }
- }
-
-
-
-
-
-
-
- pub fn addi(&mut self, idx: usize, rd: XReg, rs: XReg, simm12: impl Into<Simm12>) {
- let funct3 = FUNCT3_OP_ADD_SUB;
- let opcode = OPCODE_OP_IMM;
- let word = (u32::from(simm12.into().0) << 20)
- | ((rs as u32) << 15)
- | (funct3 << 12)
- | ((rd as u32) << 7)
- | opcode;
- self.inner[idx / 4] = word;
- }
-
-
-
-
-
-
- pub fn lui(&mut self, idx: usize, rd: XReg, simm20: impl Into<Simm20>) {
- let opcode = OPCODE_LUI;
- let word = (u32::from(simm20.into().0) << 12) | ((rd as u32) << 7) | opcode;
- self.inner[idx / 4] = word;
- }
-
-
-
-
-
-
-
-
-
- pub fn li(&mut self, idx: usize, rd: XReg, imm: u128) {
- assert!(
- imm <= 0xFFFFFFFF,
- "in this example `li` only supports immediate values less than 0xFFFFFFFF"
- );
- let imm = imm as u32;
- let (simm20, simm12) = (imm >> 12, imm & 0xFFF);
- if simm20 != 0 {
- self.lui(idx, rd, simm20);
- self.addi(idx + 4, rd, rd, simm12);
- } else {
- self.addi(idx, rd, XReg::Zero, simm12);
- }
- }
-
-
-
-
-
-
-
- pub fn beq(&mut self, idx: usize, rs1: XReg, rs2: XReg, offset: impl Into<Offset>) {
- let opcode = OPCODE_BRANCH;
- let funct3 = FUNCT3_BRANCH_BEQ;
-
- let offset_u32 = u32::from_ne_bytes(i32::to_ne_bytes(offset.into().0));
- let simm12_12 = (offset_u32 & 0b1_0000_0000_0000) >> 12;
- let simm12_11 = (offset_u32 & 0b1000_0000_0000) >> 11;
- let simm12_10_5 = (offset_u32 & 0b111_1110_0000) >> 5;
- let simm12_4_1 = (offset_u32 & 0b1_1110) >> 1;
- let word = simm12_12 << 31
- | simm12_10_5 << 25
- | ((rs2 as u32) << 20)
- | ((rs1 as u32) << 15)
- | (funct3 << 12)
- | simm12_4_1 << 8
- | simm12_11 << 7
- | opcode;
- self.inner[idx / 4] = word;
- }
-
-
-
-
-
-
-
-
- pub fn beqz(&mut self, idx: usize, rs: XReg, offset: impl Into<Offset>) {
- self.beq(idx, rs, Zero, offset);
- }
-
-
-
-
-
-
- pub fn ecall(&mut self, idx: usize) {
- let word = 0b000000000000_00000_000_00000_1110011;
- self.inner[idx / 4] = word;
- }
-
-
-
-
-
-
- pub fn get(&mut self, ptr: u128) -> Option<u32> {
- if ptr % 4 != 0 || ptr >= (BASE + 4 * N_INSNS) as u128 {
- return None;
- }
- Some(self.inner[(ptr as usize - BASE) / 4])
- }
- }
- impl SimpleRv128IHart {
-
-
-
-
- pub fn new(inst_memory: InstMemory<0x2000_0000, { 0x4000 / 4 }>) -> Self {
- Self {
- xregs: [0; 32],
- pc: 0x2000_0000,
- inst_memory,
- }
- }
-
-
-
-
-
-
-
-
-
- pub fn stepi(&mut self) -> Result<(), Exception> {
- let raw_insn = self
- .inst_memory
- .get(self.pc)
- .ok_or(Exception::InstructionAccessFault)?;
- println!("Insn at 0x{:x}: 0x{:x}", self.pc, raw_insn);
-
- let parsed_insn =
- Instruction::try_from(raw_insn).map_err(|_| Exception::IllegalInstruction)?;
- match parsed_insn {
- Instruction::Addi(rd, rs, simm12) => {
- self.xregs[rd as usize] = self.xregs[rs as usize] + simm12.0 as u128;
- self.pc = self.pc.wrapping_add(4);
- }
- Instruction::Lui(rd, simm20) => {
- self.xregs[rd as usize] = (simm20.0 as u128) << 12;
- self.pc = self.pc.wrapping_add(4);
- }
- Instruction::Beq(rs1, rs2, offset) => {
- if self.xregs[rs1 as usize] == self.xregs[rs2 as usize] {
- self.pc = self.pc.wrapping_add_signed(offset.0 as i128);
- } else {
- self.pc = self.pc.wrapping_add(4);
- }
- }
- Instruction::Ecall => return Err(Exception::SupervisorEcall),
- }
- Ok(())
- }
- }
- #[derive(Debug)]
- pub enum Exception {
-
- IllegalInstruction,
-
- InstructionAccessFault,
-
- SupervisorEcall,
- }
- #[derive(Debug)]
- pub enum Instruction {
-
- Addi(XReg, XReg, Simm12),
-
- Lui(XReg, Simm20),
-
- Beq(XReg, XReg, Offset),
-
- Ecall,
- }
- impl TryFrom<u32> for Instruction {
- type Error = ();
-
-
-
- fn try_from(value: u32) -> Result<Self, Self::Error> {
- let opcode = value & 0x7F;
- let rd = ((value >> 7) & 0x1F).try_into().unwrap();
- let rs1 = ((value >> 15) & 0x1F).try_into().unwrap();
- let rs2 = ((value >> 20) & 0x1F).try_into().unwrap();
- let funct3 = (value >> 12) & 0b111;
- let simm12 = (value >> 20).into();
- let simm20 = (value >> 12).into();
-
- let offset = {
- let offset12 = value >> 31;
- let offset10_5 = (value >> 25) & 0x3F;
- let offset4_1 = (value >> 8) & 0xF;
- let offset11 = (value >> 7) & 0x1;
- let value = (offset4_1 << 1) | (offset10_5 << 5) | (offset11 << 11) | (offset12 << 12);
- value.into()
- };
- if opcode == OPCODE_OP_IMM && funct3 == FUNCT3_OP_ADD_SUB {
- Ok(Self::Addi(rd, rs1, simm12))
- } else if opcode == OPCODE_LUI {
- Ok(Self::Lui(rd, simm20))
- } else if opcode == OPCODE_BRANCH && funct3 == FUNCT3_BRANCH_BEQ {
- Ok(Self::Beq(rs1, rs2, offset))
- } else if value == 0b000000000000_00000_000_00000_1110011 {
- Ok(Self::Ecall)
- } else {
- Err(())
- }
- }
- }
- #[derive(Clone, Copy, Debug)]
- pub enum XReg {
- Zero = 0,
- Ra = 1,
- Sp = 2,
- Gp = 3,
- Tp = 4,
- T0 = 5,
- T1 = 6,
- T2 = 7,
- S0 = 8,
- S1 = 9,
- A0 = 10,
- A1 = 11,
- A2 = 12,
- A3 = 13,
- A4 = 14,
- A5 = 15,
- A6 = 16,
- A7 = 17,
- S2 = 18,
- S3 = 19,
- S4 = 20,
- S5 = 21,
- S6 = 22,
- S7 = 23,
- S8 = 24,
- S9 = 25,
- S10 = 26,
- S11 = 27,
- T3 = 28,
- T4 = 29,
- T5 = 30,
- T6 = 31,
- }
- impl TryFrom<u32> for XReg {
- type Error = ();
-
-
- fn try_from(value: u32) -> Result<Self, Self::Error> {
- Ok(match value {
- 0 => Zero,
- 1 => Ra,
- 2 => Sp,
- 3 => Gp,
- 4 => Tp,
- 5 => T0,
- 6 => T1,
- 7 => T2,
- 8 => S0,
- 9 => S1,
- 10 => A0,
- 11 => A1,
- 12 => A2,
- 13 => A3,
- 14 => A4,
- 15 => A5,
- 16 => A6,
- 17 => A7,
- 18 => S2,
- 19 => S3,
- 20 => S4,
- 21 => S5,
- 22 => S6,
- 23 => S7,
- 24 => S8,
- 25 => S9,
- 26 => S10,
- 27 => S11,
- 28 => T3,
- 29 => T4,
- 30 => T5,
- 31 => T6,
- _ => return Err(()),
- })
- }
- }
- #[derive(Clone, Copy, Debug)]
- pub struct Simm12(u16);
- impl From<u32> for Simm12 {
- fn from(value: u32) -> Self {
- Self((value & 0x0FFF) as u16)
- }
- }
- #[derive(Clone, Copy, Debug)]
- pub struct Simm20(u32);
- impl From<u32> for Simm20 {
- fn from(value: u32) -> Self {
- Self(value & 0xFFFFF)
- }
- }
- #[derive(Clone, Copy, Debug)]
- pub struct Offset(i32);
- impl From<i32> for Offset {
- fn from(value: i32) -> Self {
- Self(value & 0x1FFE)
- }
- }
- impl From<u32> for Offset {
- fn from(mut value: u32) -> Self {
- value = value & 0x1FFE;
- if value & 0x1000 != 0 {
- value |= 0xFFFFE000;
- }
- let ans = i32::from_ne_bytes(u32::to_ne_bytes(value));
- Self(ans)
- }
- }
|