瀏覽代碼

Merge pull request #116 from woshiluo/visionfive2

feat: basic support for VisionFive2
guttatus 2 周之前
父節點
當前提交
122770d7ce

+ 145 - 0
prototyper/docs/booting-in-visionfive2-using-uboot-and-rustsbi.md

@@ -0,0 +1,145 @@
+# 在 VisionFive2 中使用 RustSBI 和 U-Boot 启动
+
+本教程给出了使用 RustSBI 和 U-Boot 在 VisionFive2 中启动的基本流程。
+
+本教程使用软件版本如下:
+
+|         软件          |  版本   |
+| :-------------------: | :-----: |
+|          gcc          | **10.5.0**  |
+|  RustSBI Prototyper   |  0.0.0  |
+
+## 准备工作
+
+创建工作目录
+
+``` shell
+$ mkdir workshop 
+```
+
+### 下载 VisionFive2 Debian 镜像
+
+前往 <https://debian.starfivetech.com/> 下载最新 Debian 镜像。
+
+假设下载下来的文件名为 `debian_image.img.bz2`。
+
+```shell
+$ bzip2 -dk debian_image.img.bz2
+```
+
+移动 `debian_image.img` 到 `workshop` 目录下。
+
+### Clone VisionFive2 SDK
+
+```shell
+$ cd workshop
+$ git clone [email protected]:starfive-tech/VisionFive2.git
+$ cd VisionFive2
+$ git checkout JH7110_VisionFive2_devel
+$ git submodule update --init --recursive
+```
+
+### Clone RustSBI
+
+```shell
+$ cd workshop/VisionFive2
+$ git clone https://github.com/rustsbi/rustsbi
+```
+
+## 编译 SDK 和 RustSBI
+
+编译 SDK,编译产物应在 `work` 目录下。
+
+``` shell
+$ cd workshop/VisionFive2
+$ make -j$(nproc)
+```
+
+
+编译 RustSBI Prototyper,以 U-Boot 作为 Payload。
+
+``` shell
+$ cd workshop/VisionFive2/rustsbi 
+$ cargo prototyper --payload ../work/u-boot/u-boot.bin --fdt ../work/u-boot/arch/riscv/dts/starfive_visionfive2.dtb 
+```
+
+## 生成 Payload 镜像
+
+创建 `workshop/VisionFive2/payload_image.its`:
+
+```plain
+/dts-v1/;
+
+/ {
+	description = "U-boot-spl FIT image for JH7110 VisionFive2";
+	#address-cells = <2>;
+
+	images {
+		firmware {
+			description = "u-boot";
+			data = /incbin/("./rustsbi/target/riscv64imac-unknown-none-elf/release/rustsbi-prototyper-payload.bin");
+			type = "firmware";
+			arch = "riscv";
+			os = "u-boot";
+			load = <0x0 0x40000000>;
+			entry = <0x0 0x40000000>;
+			compression = "none";
+		};
+	};
+
+	configurations {
+		default = "config-1";
+
+		config-1 {
+			description = "U-boot-spl FIT config for JH7110 VisionFive2";
+			firmware = "firmware";
+		};
+	};
+};
+```
+
+生成 `visionfive2_fw_payload.img`:
+```shell
+$ cd workshop/VisionFive2
+$ mkimage -f payload_image.its -A riscv -O u-boot -T firmware visionfive2_fw_payload.img
+```
+
+## 烧录 Payload 镜像
+
+VisionFive2 支持从 1-bit QSPI Nor Flash、SDIO3.0、eMMC 中启动,对于不同启动模式,烧录方式有所不同。
+
+你可以参照[ 昉·星光 2启动模式设置 ](https://doc.rvspace.org/VisionFive2/SDK_Quick_Start_Guide/VisionFive2_SDK_QSG/boot_mode_settings.html)来修改启动模式。
+
+### 从 Flash 中启动
+
+参照 [更新Flash中的SPL和U-Boot](https://doc.rvspace.org/VisionFive2/SDK_Quick_Start_Guide/VisionFive2_SDK_QSG/updating_spl_and_u_boot%20-%20vf2.html) 或 [恢复Bootloader](https://doc.rvspace.org/VisionFive2/SDK_Quick_Start_Guide/VisionFive2_SDK_QSG/recovering_bootloader%20-%20vf2.html) 来更新 Flash 中的 U-Boot 部分。
+
+### 从 EMMC 或 SD 卡中启动
+
+> 非 Flash 的启动方式并不被 VisionFive2 官方文档建议。
+
+首先,你需要确保你的对应磁盘(如 SD 卡)按照[ 启动地址分配 -  昉·惊鸿-7110启动手册 ](https://doc.rvspace.org/VisionFive2/Developing_and_Porting_Guide/JH7110_Boot_UG/JH7110_SDK/boot_address_allocation.html)进行分区。
+
+你可以先完成[烧录 Debian 镜像](#烧录-bebian-镜像)一节,这样你的对应磁盘的分区表就应已满足上述要求。
+
+之后,将上文得到的 `visionfive2_fw_payload.img` 写入表中所指向的 2 号分区即可。
+
+**本命令仅为参考,请根据自己的磁盘路径修改**
+```shell
+$ cd workshop
+$ dd if=./visionfive2_fw_payload.img of=/dev/sda2 status=progress
+```
+
+## 烧录 Debian 镜像
+
+假设你的对应磁盘路径为 `/dev/sda`,按如下命令使用 `dd` 工具进行烧写即可:
+
+```shell
+$ cd workshop
+$ dd if=./debian_image.img of=/dev/sda
+```
+
+## SEE ALSO
+
+- [昉·星光 2 SDK快速参考手册](https://doc.rvspace.org/VisionFive2/SDK_Quick_Start_Guide/index.html)
+- [昉·惊鸿-7110启动手册](https://doc.rvspace.org/VisionFive2/Developing_and_Porting_Guide/JH7110_Boot_UG/)

+ 17 - 5
prototyper/prototyper/src/firmware/mod.rs

@@ -81,21 +81,28 @@ pub fn set_pmp(memory_range: &Range<usize>) {
         asm!("la {}, sbi_rodata_start", out(reg) RODATA_START_ADDRESS, options(nomem));
         asm!("la {}, sbi_rodata_end", out(reg) RODATA_END_ADDRESS, options(nomem));
 
+        assert_eq!(memory_range.start & 0x3, 0);
+        assert_eq!(memory_range.end & 0x3, 0);
+        assert_eq!(SBI_START_ADDRESS & 0x3, 0);
+        assert_eq!(SBI_END_ADDRESS & 0x3, 0);
+        assert_eq!(RODATA_START_ADDRESS & 0x3, 0);
+        assert_eq!(RODATA_END_ADDRESS & 0x3, 0);
+
         pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
         pmpaddr0::write(0);
-        pmpcfg0::set_pmp(1, Range::TOR, Permission::RW, false);
+        pmpcfg0::set_pmp(1, Range::TOR, Permission::RWX, false);
         pmpaddr1::write(memory_range.start >> 2);
         pmpcfg0::set_pmp(2, Range::TOR, Permission::RWX, false);
         pmpaddr2::write(SBI_START_ADDRESS >> 2);
         pmpcfg0::set_pmp(3, Range::TOR, Permission::NONE, false);
         pmpaddr3::write(RODATA_START_ADDRESS >> 2);
-        pmpcfg0::set_pmp(4, Range::TOR, Permission::RW, false);
+        pmpcfg0::set_pmp(4, Range::TOR, Permission::NONE, false);
         pmpaddr4::write(RODATA_END_ADDRESS >> 2);
         pmpcfg0::set_pmp(5, Range::TOR, Permission::NONE, false);
         pmpaddr5::write(SBI_END_ADDRESS >> 2);
         pmpcfg0::set_pmp(6, Range::TOR, Permission::RWX, false);
         pmpaddr6::write(memory_range.end >> 2);
-        pmpcfg0::set_pmp(7, Range::TOR, Permission::RW, false);
+        pmpcfg0::set_pmp(7, Range::TOR, Permission::RWX, false);
         pmpaddr7::write(usize::MAX >> 2);
     }
 }
@@ -112,11 +119,16 @@ pub fn log_pmp_cfg(memory_range: &Range<usize>) {
         info!("{:<10} {:<10} {:<15} 0x{:08x}", "PMP 0:", "OFF", "NONE", 0);
         info!(
             "{:<10} {:<10} {:<15} 0x{:08x} - 0x{:08x}",
-            "PMP 1-2:", "TOR", "RW/RWX", memory_range.start, SBI_START_ADDRESS
+            "PMP 1-2:", "TOR", "RWX/RWX", memory_range.start, SBI_START_ADDRESS
         );
         info!(
             "{:<10} {:<10} {:<15} 0x{:08x} - 0x{:08x} - 0x{:08x}",
-            "PMP 3-5:", "TOR", "NONE/RW", RODATA_START_ADDRESS, RODATA_END_ADDRESS, SBI_END_ADDRESS
+            "PMP 3-5:",
+            "TOR",
+            "NONE/NONE",
+            RODATA_START_ADDRESS,
+            RODATA_END_ADDRESS,
+            SBI_END_ADDRESS
         );
         info!(
             "{:<10} {:<10} {:<15} 0x{:08x}",

+ 35 - 23
prototyper/prototyper/src/main.rs

@@ -110,6 +110,8 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
         use ::riscv::register::{medeleg, mtvec};
         // Keep supervisor environment calls and illegal instructions in M-mode.
         medeleg::clear_supervisor_env_call();
+        medeleg::clear_load_misaligned();
+        medeleg::clear_store_misaligned();
         medeleg::clear_illegal_instruction();
         if hart_privileged_version(current_hartid()) >= PrivilegedVersion::Version1_12 {
             // Configure environment features based on available extensions.
@@ -134,38 +136,47 @@ unsafe extern "C" fn start() -> ! {
         naked_asm!(
             ".option arch, +a",
             // 1. Turn off interrupt.
-            "   csrw    mie, zero",
+            "
+            csrw    mie, zero",
             // 2. Initialize programming language runtime.
             // only clear bss if hartid matches preferred boot hart id.
-            "   csrr    t0, mhartid",
-            "   bne     t0, zero, 4f",
-            "   call    {relocation_update}",
-            "1:",
-            // 3. Hart 0 clear bss segment.
-            "   lla     t0, sbi_bss_start
-            lla     t1, sbi_bss_end
-         2: bgeu    t0, t1, 3f
+            // Race
+            "
+            lla      t0, 6f
+            li       t1, 1
+            amoadd.w t0, t1, 0(t0)
+            bnez     t0, 4f
+            call     {relocation_update}",
+            // 3. Boot hart clear bss segment.
+            "1:
+            lla     t0, sbi_bss_start
+            lla     t1, sbi_bss_end",
+            "2:
+            bgeu    t0, t1, 3f
             sd      zero, 0(t0)
             addi    t0, t0, 8
             j       2b",
-            "3: ", // Hart 0 set bss ready signal.
-            "   lla     t0, 6f
+            // 3.1 Boot hart set bss ready signal.
+            "3:
+            lla     t0, 7f
             li      t1, 1
             amoadd.w t0, t1, 0(t0)
             j       5f",
-            "4:", // Other harts are waiting for bss ready signal.
-            "   li      t1, 1
-            lla     t0, 6f
+            // 3.2 Other harts are waiting for bss ready signal.
+            "4:
+            lla     t0, 7f
             lw      t0, 0(t0)
-            bne     t0, t1, 4b",
-            "5:",
-             // 4. Prepare stack for each hart.
-            "   call    {locate_stack}",
-            "   call    {main}",
-            "   csrw    mscratch, sp",
-            "   j       {hart_boot}",
-            "  .balign  4",
-            "6:",  // bss ready signal.
+            beqz    t0, 4b",
+            // 4. Prepare stack for each hart.
+            "5:
+            call    {locate_stack}
+            call    {main}
+            csrw    mscratch, sp
+            j       {hart_boot}
+            .balign  4",
+            "6:", // boot hart race signal.
+            "  .word    0",
+            "7:", // bss ready signal.
             "  .word    0",
             relocation_update = sym relocation_update,
             locate_stack = sym trap_stack::locate,
@@ -200,6 +211,7 @@ unsafe extern "C" fn relocation_update() {
             "   addi t0, t0, 24", // Get next rela item
             "2:",
             "   blt t0, t1, 1b",
+            "   fence.i",
 
             // Return
             "   ret",

+ 1 - 0
prototyper/prototyper/src/sbi/early_trap.rs

@@ -4,6 +4,7 @@ use core::arch::naked_asm;
 /// If trap happened, a0 will set to 1, otherwise will be 0.
 ///
 /// This function will change a0 and a1 and will NOT change them back.
+// TODO: Support save trap info.
 #[naked]
 #[repr(align(16))]
 pub(crate) unsafe extern "C" fn expected_trap() {

+ 146 - 24
prototyper/prototyper/src/sbi/trap/handler.rs

@@ -1,5 +1,6 @@
-use fast_trap::{FastContext, FastResult};
-use riscv::register::{mepc, mie, mstatus, satp, sstatus};
+use fast_trap::{EntireContext, EntireContextSeparated, EntireResult, FastContext, FastResult};
+use riscv::register::{mepc, mie, mstatus, mtval, satp, sstatus};
+use riscv_decode::{Instruction, decode};
 use rustsbi::RustSBI;
 
 use crate::platform::PLATFORM;
@@ -10,6 +11,8 @@ use crate::sbi::hsm::local_hsm;
 use crate::sbi::ipi;
 use crate::sbi::rfence;
 
+use super::helper::*;
+
 #[inline]
 pub fn switch(mut ctx: FastContext, start_addr: usize, opaque: usize) -> FastResult {
     unsafe {
@@ -123,14 +126,15 @@ pub fn sbi_call_handler(
         }
     }
     ctx.regs().a = [ret.error, ret.value, a2, a3, a4, a5, a6, a7];
-    mepc::write(mepc::read() + 4);
+    let epc = mepc::read();
+    mepc::write(epc + get_inst(epc).1);
     ctx.restore()
 }
 
 /// Delegate trap handling to supervisor mode.
 #[inline]
-pub fn delegate(ctx: &mut FastContext) {
-    use riscv::register::{mcause, mepc, mtval, scause, sepc, sstatus, stval, stvec};
+pub fn delegate(ctx: &mut EntireContextSeparated) {
+    use riscv::register::{mcause, scause, sepc, sstatus, stval, stvec};
     unsafe {
         sepc::write(ctx.regs().pc);
         scause::write(mcause::read().bits());
@@ -148,35 +152,153 @@ pub fn delegate(ctx: &mut FastContext) {
 
 /// Handle illegal instructions, particularly CSR access.
 #[inline]
-pub fn illegal_instruction_handler(ctx: &mut FastContext) -> bool {
-    use riscv::register::{mepc, mtval};
-    use riscv_decode::{Instruction, decode};
+pub extern "C" fn illegal_instruction_handler(raw_ctx: EntireContext) -> EntireResult {
+    let mut ctx = raw_ctx.split().0;
 
     let inst = decode(mtval::read() as u32);
     match inst {
         Ok(Instruction::Csrrs(csr)) => match csr.csr() {
             CSR_TIME => {
-                assert!(
-                    10 <= csr.rd() && csr.rd() <= 17,
-                    "Unsupported CSR rd: {}",
-                    csr.rd()
+                save_reg_x(
+                    &mut ctx,
+                    csr.rd() as usize,
+                    unsafe { PLATFORM.sbi.ipi.as_ref() }.unwrap().get_time(),
                 );
-                ctx.regs().a[(csr.rd() - 10) as usize] =
-                    unsafe { PLATFORM.sbi.ipi.as_ref() }.unwrap().get_time();
             }
             CSR_TIMEH => {
-                assert!(
-                    10 <= csr.rd() && csr.rd() <= 17,
-                    "Unsupported CSR rd: {}",
-                    csr.rd()
+                save_reg_x(
+                    &mut ctx,
+                    csr.rd() as usize,
+                    unsafe { PLATFORM.sbi.ipi.as_ref() }.unwrap().get_timeh(),
                 );
-                ctx.regs().a[(csr.rd() - 10) as usize] =
-                    unsafe { PLATFORM.sbi.ipi.as_ref() }.unwrap().get_timeh();
             }
-            _ => return false,
+            _ => {
+                delegate(&mut ctx);
+                return ctx.restore();
+            }
+        },
+        _ => {
+            delegate(&mut ctx);
+            return ctx.restore();
+        }
+    }
+    let epc = mepc::read();
+    mepc::write(epc + get_inst(epc).1);
+    ctx.restore()
+}
+
+#[inline]
+pub extern "C" fn load_misaligned_handler(ctx: EntireContext) -> EntireResult {
+    let mut ctx = ctx.split().0;
+    let current_pc = mepc::read();
+    let current_addr = mtval::read();
+
+    let (current_inst, inst_len) = get_inst(current_pc);
+    debug!(
+        "Misaligned load: inst/{:x?}, load {:x?} in {:x?}",
+        current_inst, current_addr, current_pc
+    );
+    let decode_result = decode(current_inst as u32);
+
+    // TODO: INST FLD c.*sp
+    // TODO: maybe can we reduce the time to update csr for read virtual-address.
+    let inst_type = match decode_result {
+        Ok(Instruction::Lb(data)) => (data.rd(), VarType::Signed, 1),
+        Ok(Instruction::Lbu(data)) => (data.rd(), VarType::UnSigned, 1),
+        Ok(Instruction::Lh(data)) => (data.rd(), VarType::Signed, 2),
+        Ok(Instruction::Lhu(data)) => (data.rd(), VarType::UnSigned, 2),
+        Ok(Instruction::Lw(data)) => (data.rd(), VarType::Signed, 4),
+        Ok(Instruction::Lwu(data)) => (data.rd(), VarType::UnSigned, 4),
+        Ok(Instruction::Ld(data)) => (data.rd(), VarType::Signed, 8),
+        Ok(Instruction::Flw(data)) => (data.rd(), VarType::Float, 4),
+        _ => panic!("Unsupported inst"),
+    };
+    let (target_reg, var_type, len) = inst_type;
+    let raw_data = get_data(current_addr, len);
+    let read_data = match var_type {
+        VarType::Signed => match len {
+            1 => raw_data as i8 as usize,
+            2 => raw_data as i16 as usize,
+            4 => raw_data as i32 as usize,
+            8 => raw_data as i64 as usize,
+            _ => panic!("Invalid len"),
+        },
+        VarType::UnSigned => match len {
+            1 => raw_data as u8 as usize,
+            2 => raw_data as u16 as usize,
+            4 => raw_data as u32 as usize,
+            8 => raw_data as u64 as usize,
+            _ => panic!("Invalid len"),
+        },
+        VarType::Float => match len {
+            // 4 => raw_data as f32 as usize,
+            // 8 => raw_data as f64 as usize,
+            _ => panic!("Misaligned float is unsupported"),
+        },
+    };
+    debug!(
+        "read 0x{:x} from 0x{:x} to x{}, len 0x{:x}",
+        read_data, current_addr, target_reg, len
+    );
+    save_reg_x(&mut ctx, target_reg as usize, read_data);
+    mepc::write(current_pc + inst_len);
+    ctx.restore()
+}
+
+#[inline]
+pub extern "C" fn store_misaligned_handler(ctx: EntireContext) -> EntireResult {
+    let mut ctx = ctx.split().0;
+    let current_pc = mepc::read();
+    let current_addr = mtval::read();
+
+    let (current_inst, inst_len) = get_inst(current_pc);
+    debug!(
+        "Misaligned store: inst/{:x?}, store {:x?} in {:x?}",
+        current_inst, current_addr, current_pc
+    );
+
+    let decode_result = decode(current_inst as u32);
+
+    // TODO: INST FSD c.*sp
+    // TODO: maybe can we reduce the time to update csr for read virtual-address.
+    let inst_type = match decode_result {
+        Ok(Instruction::Sb(data)) => (data.rs2(), VarType::UnSigned, 1),
+        Ok(Instruction::Sh(data)) => (data.rs2(), VarType::UnSigned, 2),
+        Ok(Instruction::Sw(data)) => (data.rs2(), VarType::UnSigned, 4),
+        Ok(Instruction::Sd(data)) => (data.rs2(), VarType::UnSigned, 8),
+        Ok(Instruction::Fsw(data)) => (data.rs2(), VarType::Float, 4),
+        _ => panic!("Unsupported inst"),
+    };
+    let (target_reg, var_type, len) = inst_type;
+    let raw_data = get_reg_x(&mut ctx, target_reg as usize);
+
+    // TODO: Float support
+    let read_data = match var_type {
+        VarType::Signed => match len {
+            _ => panic!("Can not store signed data"),
+        },
+        VarType::UnSigned => match len {
+            1 => &(raw_data as u8).to_le_bytes()[..],
+            2 => &(raw_data as u16).to_le_bytes()[..],
+            4 => &(raw_data as u32).to_le_bytes()[..],
+            8 => &(raw_data as u64).to_le_bytes()[..],
+            _ => panic!("Invalid len"),
+        },
+        VarType::Float => match len {
+            // 4 => (raw_data as f32).to_le_bytes().to_vec(),
+            // 8 => (raw_data as f64).to_le_bytes().to_vec(),
+            _ => panic!("Misaligned float is unsupported"),
         },
-        _ => return false,
+    };
+
+    debug!(
+        "save 0x{:x} to 0x{:x}, len 0x{:x}",
+        raw_data, current_addr, len
+    );
+    for i in 0..read_data.len() {
+        save_byte(current_addr + i, read_data[i] as usize);
     }
-    mepc::write(mepc::read() + 4);
-    true
+
+    mepc::write(current_pc + inst_len);
+    ctx.restore()
 }

+ 161 - 0
prototyper/prototyper/src/sbi/trap/helper.rs

@@ -0,0 +1,161 @@
+use core::arch::asm;
+use riscv::register::{mtvec, sscratch};
+
+use fast_trap::EntireContextSeparated;
+
+const MPRV_BIT: usize = 1usize << 17;
+const MXR_BIT: usize = 1usize << 19;
+
+pub enum VarType {
+    Signed,
+    UnSigned,
+    Float,
+}
+
+#[inline(always)]
+pub fn read_gp() -> usize {
+    let mut data: usize;
+    unsafe { asm!("mv {}, gp", out(reg) data, options(nomem)) };
+    data
+}
+
+#[inline(always)]
+pub fn read_tp() -> usize {
+    let mut data: usize;
+    unsafe { asm!("mv {}, tp", out(reg) data, options(nomem)) };
+    data
+}
+
+#[inline(always)]
+pub fn write_gp(data: usize) {
+    unsafe { asm!("mv gp, {}", in(reg) data, options(nomem)) };
+}
+
+#[inline(always)]
+pub fn write_tp(data: usize) {
+    unsafe { asm!("mv tp, {}", in(reg) data, options(nomem)) };
+}
+
+// If inline this and next function will cause crash. It looks like magic.
+#[inline(never)]
+pub fn get_unsigned_byte(addr: usize) -> u8 {
+    let mut data: usize = 0;
+    let mut status: usize = 0;
+    unsafe {
+        let prev_mtvec = mtvec::read().bits();
+        mtvec::write(
+            crate::sbi::early_trap::expected_trap as _,
+            mtvec::TrapMode::Direct,
+        );
+        asm!(
+            "csrrs t3, mstatus, t3",
+            "lbu t0, 0(t1)",
+            "csrw mstatus, t3",
+            "csrw mtvec, t4",
+            in("t1") addr,
+            in("t3") MPRV_BIT | MXR_BIT,
+            in("a1") 0,
+            in("t4") prev_mtvec,
+            inout("t0") data,
+            inout("a0") status,
+        );
+        if status != 0 {
+            panic!("Error when load byte");
+        }
+    }
+    data as u8
+}
+
+#[inline(never)]
+pub fn save_byte(addr: usize, data: usize) {
+    unsafe {
+        let prev_mtvec = mtvec::read().bits();
+        let mut status: usize = 0;
+        mtvec::write(
+            crate::sbi::early_trap::expected_trap as _,
+            mtvec::TrapMode::Direct,
+        );
+        asm!(
+              "csrrs t3, mstatus, t3",
+              "sb t0, 0(t1)",
+              "csrw mstatus, t3",
+              "csrw mtvec, t4",
+            in("t0") data,
+            in("t1") addr,
+            in("t4") prev_mtvec,
+            in("a1") 0,
+            in("t3") MPRV_BIT | MXR_BIT,
+            inout("a0") status,
+        );
+        if status != 0 {
+            panic!("Error when save byte");
+        }
+    }
+}
+
+#[inline(always)]
+pub fn get_data(addr: usize, len: usize) -> usize {
+    let mut data: usize = 0;
+    for i in (addr..addr + len).rev() {
+        data <<= 8;
+        data |= get_unsigned_byte(i) as usize;
+    }
+    data
+}
+
+#[inline(always)]
+pub fn get_inst(addr: usize) -> (usize, usize) {
+    let low_data = get_data(addr, 2);
+    // We assume we only have 16bit and 32bit inst.
+    if riscv_decode::instruction_length(low_data as u16) == 2 {
+        return (low_data, 2);
+    } else {
+        return (low_data | (get_data(addr + 2, 2) << 16), 4);
+    }
+}
+
+#[inline(always)]
+pub fn save_reg_x(ctx: &mut EntireContextSeparated, reg_id: usize, data: usize) {
+    match reg_id {
+        00 => (),
+        01 => ctx.regs().ra = data,
+        02 => sscratch::write(data),
+        03 => write_gp(data),
+        04 => write_tp(data),
+        05 => ctx.regs().t[0] = data,
+        06 => ctx.regs().t[1] = data,
+        07 => ctx.regs().t[2] = data,
+        08 => ctx.regs().s[0] = data,
+        09 => ctx.regs().s[1] = data,
+        // x10 = a0 ..= x17 = a7
+        10..=17 => ctx.regs().a[reg_id - 10] = data,
+        // x18 = s2 ..= x27 = s11
+        18..=27 => ctx.regs().s[reg_id - 16] = data,
+        // x28 = t3 ..= x31 = t6
+        28..=31 => ctx.regs().t[reg_id - 25] = data,
+        _ => panic!(),
+    }
+}
+
+#[inline(always)]
+pub fn get_reg_x(ctx: &mut EntireContextSeparated, reg_id: usize) -> usize {
+    match reg_id {
+        00 => 0,
+        01 => ctx.regs().ra,
+        02 => sscratch::read(),
+        03 => read_gp(),
+        04 => read_tp(),
+        05 => ctx.regs().t[0],
+        06 => ctx.regs().t[1],
+        07 => ctx.regs().t[2],
+        08 => ctx.regs().s[0],
+        09 => ctx.regs().s[1],
+        // x10 = a0 ..= x17 = a7
+        10..=17 => ctx.regs().a[reg_id - 10],
+        // x18 = s2 ..= x27 = s11
+        18..=27 => ctx.regs().s[reg_id - 16],
+        // x28 = t3 ..= x31 = t6
+        28..=31 => ctx.regs().t[reg_id - 25],
+        _ => panic!(),
+    }
+}

+ 11 - 5
prototyper/prototyper/src/sbi/trap/mod.rs

@@ -1,6 +1,8 @@
 pub mod boot;
 pub mod handler;
 
+mod helper;
+
 use crate::fail::unsupported_trap;
 
 use fast_trap::{FastContext, FastResult};
@@ -56,12 +58,16 @@ pub extern "C" fn fast_handler(
                     if mstatus::read().mpp() == mstatus::MPP::Machine {
                         panic!("Cannot handle illegal instruction exception from M-MODE");
                     }
-
                     save_regs(&mut ctx);
-                    if !handler::illegal_instruction_handler(&mut ctx) {
-                        handler::delegate(&mut ctx);
-                    }
-                    ctx.restore()
+                    ctx.continue_with(handler::illegal_instruction_handler, ())
+                }
+                Trap::Exception(Exception::LoadMisaligned) => {
+                    save_regs(&mut ctx);
+                    ctx.continue_with(handler::load_misaligned_handler, ())
+                }
+                Trap::Exception(Exception::StoreMisaligned) => {
+                    save_regs(&mut ctx);
+                    ctx.continue_with(handler::store_misaligned_handler, ())
                 }
                 // Handle other traps
                 trap => unsupported_trap(Some(trap)),