diff --git a/Cargo.lock b/Cargo.lock index ee3da81..ec69e75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "rvem" +name = "trve" version = "0.1.0" dependencies = [ "memmap2", diff --git a/Cargo.toml b/Cargo.toml index 1bb7d29..b87e602 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rvem" +name = "trve" version = "0.1.0" edition = "2024" diff --git a/README.md b/README.md index 94fb9ee..b90cd2b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# rvem +# trve RISC-V Emulator. The goal is to support at least RV64GC and be able to run Linux, potentially more. No plans for RV32I or RV32/64E. \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6a234cf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,139 @@ +use std::{ + error::Error, + fs::File, + io::{self, Read}, + sync::Arc, +}; + +use trve::{ + consts::{Byte, DWord, HWord, Word}, + core::Core, + mem::{DeviceEntry, MemAccessFault, MemConfig, MemDeviceInterface, PageNum, Ram}, +}; + +fn read_file_to_buffer(path: &str, buffer: &mut [u8]) -> io::Result { + let mut file = File::open(path)?; + let mut total_read = 0; + + while total_read < buffer.len() { + let n = file.read(&mut buffer[total_read..])?; + if n == 0 { + return Ok(total_read); + } + total_read += n; + } + + let mut tmp = [0u8; 1]; + if file.read(&mut tmp)? != 0 { + return Err(io::Error::other("RAM too small for file")); + } + + Ok(total_read) +} + +fn main() -> Result<(), Box> { + let mut ram = Ram::try_new(1024 * 1024 / 4096)?; + let buf = ram.buf_mut(); + read_file_to_buffer("./img", buf)?; + + let mem_cfg = MemConfig { + ram: Arc::new(ram), + ram_start: 0x8000_0000 / 4096, + devices: Box::new([DeviceEntry { + base: 0, + size: 1, + interface: Arc::new(DbgOut), + }]), + }; + + let mut core = Core::new(mem_cfg); + core.reset(0x8000_0000); + core.run(); + + Ok(()) +} + +struct DbgOut; + +impl MemDeviceInterface for DbgOut { + fn write_dword( + &self, + page: PageNum, + offset: u16, + value: DWord, + ) -> Result<(), trve::mem::MemAccessFault> { + eprintln!( + "Wrote DWord {value:016x} to Debug-Out page {page}, offset {offset} (byte {})", + offset * 8 + ); + Ok(()) + } + + fn write_word( + &self, + page: PageNum, + offset: u16, + value: Word, + ) -> Result<(), trve::mem::MemAccessFault> { + eprintln!( + "Wrote Word {value:08x} to Debug-Out page {page}, offset {offset} (byte {})", + offset * 4 + ); + Ok(()) + } + + fn write_hword( + &self, + page: PageNum, + offset: u16, + value: HWord, + ) -> Result<(), trve::mem::MemAccessFault> { + eprintln!( + "Wrote HWord {value:04x} to Debug-Out page {page}, offset {offset} (byte {})", + offset * 2 + ); + Ok(()) + } + + fn write_byte( + &self, + page: PageNum, + offset: u16, + value: Byte, + ) -> Result<(), trve::mem::MemAccessFault> { + eprintln!("Wrote Byte {value:02x} to Debug-Out page {page}, offset {offset}"); + Ok(()) + } + + fn read_dword(&self, page: PageNum, offset: u16) -> Result { + Err(MemAccessFault) + } + + fn read_word(&self, page: PageNum, offset: u16) -> Result { + Err(MemAccessFault) + } + + fn read_hword(&self, page: PageNum, offset: u16) -> Result { + Err(MemAccessFault) + } + + fn read_byte(&self, page: PageNum, offset: u16) -> Result { + Err(MemAccessFault) + } + + fn get_atomic_word( + &self, + page: PageNum, + offset: u16, + ) -> Result<&std::sync::atomic::AtomicU32, trve::mem::MemAccessFault> { + Err(MemAccessFault) + } + + fn get_atomic_dword( + &self, + page: PageNum, + offset: u16, + ) -> Result<&std::sync::atomic::AtomicU64, trve::mem::MemAccessFault> { + Err(MemAccessFault) + } +}