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.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
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]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.176"
|
version = "0.2.176"
|
||||||
@@ -17,9 +41,23 @@ dependencies = [
|
|||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "trve"
|
name = "trve"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
|
"nix",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ version = "0.0.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.100"
|
||||||
memmap2 = "0.9.8"
|
memmap2 = "0.9.8"
|
||||||
|
nix = { version = "0.30.1", features = ["fs"] }
|
||||||
|
|||||||
25
link.ld
25
link.ld
@@ -1,22 +1,31 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
SECTIONS {
|
MEMORY {
|
||||||
. = 0x80000000;
|
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 16M
|
||||||
|
|
||||||
.text : ALIGN(4) {
|
|
||||||
*(.text*)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.text : ALIGN(4) {
|
||||||
|
*(.text._start)
|
||||||
|
*(.text*)
|
||||||
|
} > RAM
|
||||||
|
|
||||||
.rodata : ALIGN(8) {
|
.rodata : ALIGN(8) {
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
}
|
} > RAM
|
||||||
|
|
||||||
.data : ALIGN(8) {
|
.data : ALIGN(8) {
|
||||||
|
_data = .;
|
||||||
*(.data*)
|
*(.data*)
|
||||||
}
|
_edata = .;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
.bss : ALIGN(8) {
|
.bss : ALIGN(8) {
|
||||||
|
_bss = .;
|
||||||
*(.bss*)
|
*(.bss*)
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
}
|
_ebss = .;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
_stack_top = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,35 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::{Read, stdin};
|
use std::io;
|
||||||
|
use std::os::fd::AsFd;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use nix::fcntl::fcntl;
|
||||||
|
use nix::fcntl::{FcntlArg, OFlag};
|
||||||
use trve::consts::{Byte, DWord, HWord, Word};
|
use trve::consts::{Byte, DWord, HWord, Word};
|
||||||
use trve::mem::{MemAccessFault, MemDeviceInterface, PageNum};
|
use trve::mem::{MemAccessFault, MemDeviceInterface, PageNum};
|
||||||
|
|
||||||
/// byte 0: rx/tx
|
/// byte 0: rx/tx
|
||||||
/// byte 1: status (------rt, r=rxready, t=txready)/none
|
/// byte 1: status (------rt, r=rxready, t=txready)/none
|
||||||
pub struct BasicUart {
|
pub struct BasicUart {
|
||||||
buffers: Mutex<UartBuffers>,
|
rx_buf: Mutex<VecDeque<u8>>,
|
||||||
}
|
|
||||||
|
|
||||||
struct UartBuffers {
|
|
||||||
rx: VecDeque<u8>,
|
|
||||||
tx: VecDeque<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicUart {
|
impl BasicUart {
|
||||||
pub fn new() -> Self {
|
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 {
|
BasicUart {
|
||||||
buffers: Mutex::new(UartBuffers {
|
rx_buf: Mutex::new(VecDeque::new()),
|
||||||
rx: VecDeque::new(),
|
|
||||||
tx: VecDeque::new(),
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,32 +49,23 @@ impl BasicUart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, byte: u8) {
|
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);
|
print!("{}", byte as char);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buffer = [0u8; 1];
|
fn read(&self) -> u8 {
|
||||||
if let Ok(n) = stdin().read(&mut buffer) {
|
self.rx_buf.lock().unwrap().pop_front().unwrap_or(0)
|
||||||
if n > 0 {
|
|
||||||
bufs.rx.push_back(buffer[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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Option<Instr
|
|||||||
0b00100 => match instr.funct3() {
|
0b00100 => match instr.funct3() {
|
||||||
// OP_IMM
|
// OP_IMM
|
||||||
0b000 => Some(rvi::addi(core, instr)),
|
0b000 => Some(rvi::addi(core, instr)),
|
||||||
0b001 => match instr.funct6() {
|
0b001 => (instr.funct6() == 0).then(|| rvi::slli(core, instr)),
|
||||||
// left-shift immediate
|
|
||||||
0b000000 => Some(rvi::slli(core, instr)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
0b111 => Some(rvi::andi(core, instr)),
|
0b111 => Some(rvi::andi(core, instr)),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
@@ -39,15 +35,19 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Option<Instr
|
|||||||
// LOAD
|
// LOAD
|
||||||
0b000 => Some(rvi::lb(core, instr)),
|
0b000 => Some(rvi::lb(core, instr)),
|
||||||
0b100 => Some(rvi::lbu(core, instr)),
|
0b100 => Some(rvi::lbu(core, instr)),
|
||||||
|
0b011 => Some(rvi::ld(core, instr)),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
0b11000 => match instr.funct3() {
|
0b11000 => match instr.funct3() {
|
||||||
// BRANCH
|
// BRANCH
|
||||||
0b000 => Some(rvi::beq(core, instr)),
|
0b000 => Some(rvi::beq(core, instr)),
|
||||||
|
0b001 => Some(rvi::bne(core, instr)),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
0b01101 => Some(rvi::lui(core, instr)),
|
0b01101 => Some(rvi::lui(core, instr)),
|
||||||
|
0b00101 => Some(rvi::auipc(core, instr)),
|
||||||
0b11011 => Some(rvi::jal(core, instr)),
|
0b11011 => Some(rvi::jal(core, instr)),
|
||||||
|
0b11001 => (instr.funct3() == 0).then(|| rvi::jalr(core, instr)),
|
||||||
_ => None,
|
_ => 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 {
|
pub fn sb(core: &mut Core, instr: Instruction) -> InstructionResult {
|
||||||
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s());
|
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
|
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 {
|
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());
|
core.pc = core.pc.wrapping_add(instr.imm_j());
|
||||||
InstructionResult::Normal
|
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 {
|
pub fn beq(core: &mut Core, instr: Instruction) -> InstructionResult {
|
||||||
if core.reg_read(instr.rs1()) == core.reg_read(instr.rs2()) {
|
if core.reg_read(instr.rs1()) == core.reg_read(instr.rs2()) {
|
||||||
core.pc = core.pc.wrapping_add(instr.imm_b());
|
core.pc = core.pc.wrapping_add(instr.imm_b());
|
||||||
@@ -133,6 +165,16 @@ pub fn beq(core: &mut Core, instr: Instruction) -> InstructionResult {
|
|||||||
InstructionResult::Normal
|
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 {
|
pub fn slli(core: &mut Core, instr: Instruction) -> InstructionResult {
|
||||||
core.reg_write(instr.rd(), core.reg_read(instr.rs1()) << instr.imm_shamt());
|
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},
|
mem::{DeviceEntry, MemAccessFault, MemConfig, MemDeviceInterface, PageNum, Ram},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use anyhow::{Result, bail};
|
||||||
|
|
||||||
use crate::basic_uart::BasicUart;
|
use crate::basic_uart::BasicUart;
|
||||||
|
|
||||||
fn read_file_to_buffer(path: &str, buffer: &mut [u8]) -> io::Result<usize> {
|
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)
|
Ok(total_read)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<()> {
|
||||||
let mut ram = Ram::try_new(16 * 1024 * 1024 / 4096)?;
|
let mut ram = Ram::try_new(16 * 1024 * 1024 / 4096)?;
|
||||||
let buf = ram.buf_mut();
|
let buf = ram.buf_mut();
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
if args.len() != 2 {
|
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)?;
|
read_file_to_buffer(&args[1], buf)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user