pub struct Emulator {
pub cpu: CpuState,
pub ram: Vec<u8>,
pub ram_size: u32,
pub fail_on_all_faults: bool,
pub symbols: Option<SymbolTable>,
pub output_buf: Vec<u8>,
pub wasm_mode: bool,
}Expand description
A complete RV32IMA emulator instance.
Owns the CPU state, the RAM buffer, and optional debug/WASM state.
Peripheral I/O (time, keyboard, sleep) is delegated to a Platform.
Fields§
§cpu: CpuStateThe CPU register file and CSR set.
ram: Vec<u8>Flat emulated RAM buffer. Indexed as ram[addr - RAM_BASE].
ram_size: u32Size of ram in bytes.
fail_on_all_faults: boolWhen true, any fault halts immediately instead of invoking the trap
handler. Enabled by the -d CLI flag for debugging.
symbols: Option<SymbolTable>Symbol table from the loaded ELF, if available.
Populated by load_elf when the image is not stripped.
output_buf: Vec<u8>UART output buffer. In WASM mode, bytes written to the UART go here
instead of stdout. Drained by drain_output after each batch.
wasm_mode: boolWhen true, UART bytes go to output_buf instead of stdout.
Set automatically by load_raw_from_bytes.
Implementations§
Source§impl Emulator
impl Emulator
Sourcepub fn new(ram_size: u32) -> Self
pub fn new(ram_size: u32) -> Self
Create a new emulator with ram_size bytes of RAM, all zeroed.
Sourcepub fn drain_output(&mut self) -> Vec<u8> ⓘ
pub fn drain_output(&mut self) -> Vec<u8> ⓘ
Drain and return the accumulated UART output buffer.
After this call, output_buf is empty and ready for the next batch.
Only meaningful in WASM mode; always returns an empty vec otherwise.
Source§impl Emulator
impl Emulator
Sourcepub fn load_raw(
&mut self,
image_file: &str,
dtb_file: Option<&str>,
kernel_cmdline: Option<&str>,
) -> Result<(), i32>
pub fn load_raw( &mut self, image_file: &str, dtb_file: Option<&str>, kernel_cmdline: Option<&str>, ) -> Result<(), i32>
Load a raw Linux kernel image and a Device Tree Blob into RAM.
dtb_file = None— use the embedded 64 MB DTB fromcrate::dtb.dtb_file = Some("disable")— skip DTB entirely (a1 = 0).dtb_file = Some(path)— load DTB from the given file.
On success the CPU is reset with:
pc = RAM_BASE(kernel entry point)a0 = 0(hart ID)a1 = dtb_ptr + RAM_BASE(DTB physical address)- privilege = M-mode
Sourcepub fn load_elf(&mut self, elf_file: &str) -> Result<(), i32>
pub fn load_elf(&mut self, elf_file: &str) -> Result<(), i32>
Load an RV32 bare-metal ELF or FreeRTOS image.
Only PT_LOAD segments with vaddr >= RAM_BASE are copied into RAM.
Bytes between p_filesz and p_memsz are zero-filled (BSS). The
symbol table is loaded automatically if the ELF is not stripped.
On success the CPU is reset with:
pc = elf.entrysp = RAM_BASE + ram_size - 16(top of RAM, 16-byte aligned per ABI)a0 = a1 = 0(no DTB — FreeRTOS does not use it)- privilege = M-mode
Sourcepub fn run(
&mut self,
cfg: &mut RunConfig,
plat: &mut dyn Platform,
) -> StepResult
pub fn run( &mut self, cfg: &mut RunConfig, plat: &mut dyn Platform, ) -> StepResult
Run the emulator until it stops or the instruction limit is reached.
Calls step in a loop, advancing the time base between calls.
Returns the reason the loop exited as a StepResult.
Sourcepub fn step(
&mut self,
elapsed_us: u32,
count: i32,
plat: &mut dyn Platform,
) -> StepResult
pub fn step( &mut self, elapsed_us: u32, count: i32, plat: &mut dyn Platform, ) -> StepResult
Execute up to count instructions, advancing the timer by elapsed_us µs.
This is the hot path of the emulator. It:
- Calls
CpuState::tick_timerto updatemtimeand check MTIP. - Checks for a pending timer interrupt before the instruction loop.
- Fetches, decodes, and executes up to
countinstructions. - Commits any trap that fired via
CpuState::commit_trap. - Updates the cycle counter.
Returns StepResult::Ok in the normal case. Returns
StepResult::Wfi if the CPU is sleeping. Returns
StepResult::Restart or StepResult::Poweroff if the kernel
wrote to SYSCON.
Sourcepub fn write_trace_line(
&self,
writer: &mut dyn Write,
pc: u32,
prev_regs: &[u32; 32],
)
pub fn write_trace_line( &self, writer: &mut dyn Write, pc: u32, prev_regs: &[u32; 32], )
Write one line of compact execution trace to writer.
Format: <pc> <ir> <mnem padded to 36 chars> [reg=val ...]
Only registers that changed relative to prev_regs are listed.
Instructions with no register writes (branches, stores) produce a line
that ends after the mnemonic.
§Example output
80000014 510010ef jal ra, <main> ra=80000018
80001524 ff010113 addi sp, sp, -16 sp=81fffff0
80001528 00112623 sw ra, 12(sp)Sourcepub fn dump_state(&self, prev_regs: Option<&[u32; 32]>)
pub fn dump_state(&self, prev_regs: Option<&[u32; 32]>)
Print the PC, the disassembled instruction, and the full register grid.
prev_regs — register state before the last step.
Registers that changed are prefixed with *.
Format:
80001234 510010ef jal ra, <main>
zero=00000000 *ra=80000018 sp=83fffff0 gp=00000000
...