Compare commits
7 Commits
5c132b55e9
...
24dcf5d5bd
| Author | SHA1 | Date | |
|---|---|---|---|
| 24dcf5d5bd | |||
| 209e44ae64 | |||
| 5b2d6a1af0 | |||
| a2d4dec417 | |||
| 6c39a5eef2 | |||
| 944ed573c6 | |||
| 2e1c0a7dce |
38
Cargo.lock
generated
38
Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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
21
link.ld
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
print!("{}", byte as char);
|
||||
}
|
||||
|
||||
fn read(&self) -> u8 {
|
||||
let mut bufs = self.buffers.lock().unwrap();
|
||||
bufs.rx.pop_front().unwrap_or(0)
|
||||
self.rx_buf.lock().unwrap().pop_front().unwrap_or(0)
|
||||
}
|
||||
|
||||
fn can_read(&self) -> bool {
|
||||
let bufs = self.buffers.lock().unwrap();
|
||||
!bufs.rx.is_empty()
|
||||
!self.rx_buf.lock().unwrap().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 rx_buf = self.rx_buf.lock().unwrap();
|
||||
|
||||
let mut buffer = [0u8; 1];
|
||||
if let Ok(n) = stdin().read(&mut buffer) {
|
||||
if n > 0 {
|
||||
bufs.rx.push_back(buffer[0]);
|
||||
}
|
||||
while let Ok(1) = nix::unistd::read(io::stdin().as_fd(), &mut buffer) {
|
||||
rx_buf.push_back(buffer[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
Reference in New Issue
Block a user