Compare commits

..

7 Commits

7 changed files with 130 additions and 40 deletions

38
Cargo.lock generated
View File

@@ -2,6 +2,30 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "anyhow"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "libc"
version = "0.2.176"
@@ -17,9 +41,23 @@ dependencies = [
"libc",
]
[[package]]
name = "nix"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "trve"
version = "0.0.0"
dependencies = [
"anyhow",
"memmap2",
"nix",
]

View File

@@ -4,4 +4,6 @@ version = "0.0.0"
edition = "2024"
[dependencies]
anyhow = "1.0.100"
memmap2 = "0.9.8"
nix = { version = "0.30.1", features = ["fs"] }

21
link.ld
View File

@@ -1,22 +1,31 @@
ENTRY(_start)
SECTIONS {
. = 0x80000000;
MEMORY {
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 16M
}
SECTIONS {
.text : ALIGN(4) {
*(.text._start)
*(.text*)
}
} > RAM
.rodata : ALIGN(8) {
*(.rodata*)
}
} > RAM
.data : ALIGN(8) {
_data = .;
*(.data*)
}
_edata = .;
} > RAM
.bss : ALIGN(8) {
_bss = .;
*(.bss*)
*(COMMON)
}
_ebss = .;
} > RAM
_stack_top = ORIGIN(RAM) + LENGTH(RAM);
}

View File

@@ -1,30 +1,35 @@
use std::collections::VecDeque;
use std::io::{Read, stdin};
use std::io;
use std::os::fd::AsFd;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use nix::fcntl::fcntl;
use nix::fcntl::{FcntlArg, OFlag};
use trve::consts::{Byte, DWord, HWord, Word};
use trve::mem::{MemAccessFault, MemDeviceInterface, PageNum};
/// byte 0: rx/tx
/// byte 1: status (------rt, r=rxready, t=txready)/none
pub struct BasicUart {
buffers: Mutex<UartBuffers>,
}
struct UartBuffers {
rx: VecDeque<u8>,
tx: VecDeque<u8>,
rx_buf: Mutex<VecDeque<u8>>,
}
impl BasicUart {
pub fn new() -> Self {
// Make sure stdin is nonblocking
let stdin = io::stdin();
let fd = stdin.as_fd();
let flags = fcntl(fd, FcntlArg::F_GETFL).unwrap();
fcntl(
fd,
FcntlArg::F_SETFL(OFlag::from_bits_truncate(flags) | OFlag::O_NONBLOCK),
)
.unwrap();
BasicUart {
buffers: Mutex::new(UartBuffers {
rx: VecDeque::new(),
tx: VecDeque::new(),
}),
rx_buf: Mutex::new(VecDeque::new()),
}
}
@@ -44,32 +49,23 @@ impl BasicUart {
}
fn write(&self, byte: u8) {
let mut bufs = self.buffers.lock().unwrap();
bufs.tx.push_back(byte);
}
fn read(&self) -> u8 {
let mut bufs = self.buffers.lock().unwrap();
bufs.rx.pop_front().unwrap_or(0)
}
fn can_read(&self) -> bool {
let bufs = self.buffers.lock().unwrap();
!bufs.rx.is_empty()
}
pub fn poll(&self) {
let mut bufs = self.buffers.lock().unwrap();
while let Some(byte) = bufs.tx.pop_front() {
print!("{}", byte as char);
}
let mut buffer = [0u8; 1];
if let Ok(n) = stdin().read(&mut buffer) {
if n > 0 {
bufs.rx.push_back(buffer[0]);
fn read(&self) -> u8 {
self.rx_buf.lock().unwrap().pop_front().unwrap_or(0)
}
fn can_read(&self) -> bool {
!self.rx_buf.lock().unwrap().is_empty()
}
pub fn poll(&self) {
let mut rx_buf = self.rx_buf.lock().unwrap();
let mut buffer = [0u8; 1];
while let Ok(1) = nix::unistd::read(io::stdin().as_fd(), &mut buffer) {
rx_buf.push_back(buffer[0]);
}
}
}

View File

@@ -16,11 +16,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Option<Instr
0b00100 => match instr.funct3() {
// OP_IMM
0b000 => Some(rvi::addi(core, instr)),
0b001 => match instr.funct6() {
// left-shift immediate
0b000000 => Some(rvi::slli(core, instr)),
_ => None,
},
0b001 => (instr.funct6() == 0).then(|| rvi::slli(core, instr)),
0b111 => Some(rvi::andi(core, instr)),
_ => None,
},
@@ -39,15 +35,19 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Option<Instr
// LOAD
0b000 => Some(rvi::lb(core, instr)),
0b100 => Some(rvi::lbu(core, instr)),
0b011 => Some(rvi::ld(core, instr)),
_ => None,
},
0b11000 => match instr.funct3() {
// BRANCH
0b000 => Some(rvi::beq(core, instr)),
0b001 => Some(rvi::bne(core, instr)),
_ => None,
},
0b01101 => Some(rvi::lui(core, instr)),
0b00101 => Some(rvi::auipc(core, instr)),
0b11011 => Some(rvi::jal(core, instr)),
0b11001 => (instr.funct3() == 0).then(|| rvi::jalr(core, instr)),
_ => None,
}
}

View File

@@ -61,6 +61,26 @@ pub fn sd(core: &mut Core, instr: Instruction) -> InstructionResult {
}
}
pub fn ld(core: &mut Core, instr: Instruction) -> InstructionResult {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s());
if !addr.is_multiple_of(std::mem::size_of::<DWord>() as Addr) {
return InstructionResult::Exception(());
}
let page = (addr / 4096) as PageNum;
let offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16;
match core.mem.read_dword(page, offset) {
Ok(x) => {
core.reg_write(instr.rd(), x);
core.advance_pc();
InstructionResult::Normal
}
Err(_) => InstructionResult::Exception(()),
}
}
pub fn sb(core: &mut Core, instr: Instruction) -> InstructionResult {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s());
@@ -117,12 +137,24 @@ pub fn lui(core: &mut Core, instr: Instruction) -> InstructionResult {
InstructionResult::Normal
}
pub fn auipc(core: &mut Core, instr: Instruction) -> InstructionResult {
core.reg_write(instr.rd(), core.pc.wrapping_add(instr.imm_u()));
core.advance_pc();
InstructionResult::Normal
}
pub fn jal(core: &mut Core, instr: Instruction) -> InstructionResult {
core.reg_write(instr.rd(), core.pc);
core.reg_write(instr.rd(), core.pc.wrapping_add(4));
core.pc = core.pc.wrapping_add(instr.imm_j());
InstructionResult::Normal
}
pub fn jalr(core: &mut Core, instr: Instruction) -> InstructionResult {
core.reg_write(instr.rd(), core.pc.wrapping_add(4));
core.pc = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
InstructionResult::Normal
}
pub fn beq(core: &mut Core, instr: Instruction) -> InstructionResult {
if core.reg_read(instr.rs1()) == core.reg_read(instr.rs2()) {
core.pc = core.pc.wrapping_add(instr.imm_b());
@@ -133,6 +165,16 @@ pub fn beq(core: &mut Core, instr: Instruction) -> InstructionResult {
InstructionResult::Normal
}
pub fn bne(core: &mut Core, instr: Instruction) -> InstructionResult {
if core.reg_read(instr.rs1()) != core.reg_read(instr.rs2()) {
core.pc = core.pc.wrapping_add(instr.imm_b());
} else {
core.advance_pc();
}
InstructionResult::Normal
}
pub fn slli(core: &mut Core, instr: Instruction) -> InstructionResult {
core.reg_write(instr.rd(), core.reg_read(instr.rs1()) << instr.imm_shamt());

View File

@@ -19,6 +19,8 @@ use trve::{
mem::{DeviceEntry, MemAccessFault, MemConfig, MemDeviceInterface, PageNum, Ram},
};
use anyhow::{Result, bail};
use crate::basic_uart::BasicUart;
fn read_file_to_buffer(path: &str, buffer: &mut [u8]) -> io::Result<usize> {
@@ -41,14 +43,15 @@ fn read_file_to_buffer(path: &str, buffer: &mut [u8]) -> io::Result<usize> {
Ok(total_read)
}
fn main() -> Result<(), Box<dyn Error>> {
fn main() -> Result<()> {
let mut ram = Ram::try_new(16 * 1024 * 1024 / 4096)?;
let buf = ram.buf_mut();
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
eprintln!("USAGE: trve <ram_image>")
eprintln!("USAGE: trve <ram_image>");
bail!("Wrong number of arguments");
}
read_file_to_buffer(&args[1], buf)?;