From 6f274524839a3c840fbe205e61714cba0a77461f Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 3 Sep 2024 17:55:22 +0100 Subject: [PATCH] progress --- Cargo.lock | 267 +++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + Makefile | 19 ++-- src/cpu.rs | 160 ++++++++++++++++++++++++++-- src/main.rs | 12 +++ tests/add-addi.s | 4 - tests/addi.s | 4 + tests/csr.s | 12 +++ 8 files changed, 460 insertions(+), 20 deletions(-) delete mode 100644 tests/add-addi.s create mode 100644 tests/addi.s create mode 100644 tests/csr.s diff --git a/Cargo.lock b/Cargo.lock index 00fb521..9cfef1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,273 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "rysk" version = "0.1.0" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 5a9b422..1ff6874 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } diff --git a/Makefile b/Makefile index bc4f273..b699559 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,11 @@ -add-addi.bin: add-addi.s - riscv64-unknown-elf-gcc -Wl,-Ttext=0x0 -nostdlib -o tests/add-addi tests/add-addi.s - riscv64-unknown-elf-objcopy -O binary tests/add-addi tests/add-addi.bin - -clean: - rm -f tests/add-addi - rm -f tests/add-addi.bin - rm -f tests/*.bin + + +SRCS = $(wildcard tests/*.s) + +PROGS = $(patsubst %.s,%.bin,$(SRCS)) + +all: $(PROGS) + +%.bin: %.s + riscv64-unknown-elf-gcc -Wl,-Ttext=0x0 -nostdlib -o $@ $< + riscv64-unknown-elf-objcopy -O binary $@ $@ diff --git a/src/cpu.rs b/src/cpu.rs index b324e0e..6ab92d7 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,7 +1,9 @@ use std::ops::{BitAnd, BitOr, BitXor}; +use tracing::{debug, error, instrument}; + use crate::{ - bus::Bus, + bus::{Bus, DRAM_BASE}, dram::{Dram, DRAM_SIZE}, }; @@ -26,7 +28,7 @@ impl Cpu { pub fn new(code: Vec) -> Self { let mut cpu = Cpu { regs: Default::default(), - pc: 0, + pc: DRAM_BASE, bus: Bus { dram: Dram::new(code), }, @@ -34,7 +36,7 @@ impl Cpu { }; cpu.regs[0] = 0; - cpu.regs[2] = DRAM_SIZE; + cpu.regs[2] = DRAM_BASE + DRAM_SIZE; cpu } @@ -45,7 +47,9 @@ impl Cpu { // 3. Decode. // 4. Execute. - while self.execute(inst).is_ok() {} + if self.execute(inst).is_err() { + break; + } // This is a workaround for avoiding an infinite loop. if self.pc == 0 { @@ -78,18 +82,35 @@ impl Cpu { self.bus.load(self.pc, 32) } + #[instrument( + skip(self), + fields(opcode, rd, rs1, rs2, funct3, funct7, imm, imm04, csr, csr_addr) + )] fn execute(&mut self, inst: u64) -> Result<(), ()> { + if inst == 0 { + Err(())? + } + let opcode = inst & 0x7f; let rd = ((inst >> 7) & 0x1f) as usize; let rs1 = ((inst >> 15) & 0x1f) as usize; let rs2 = ((inst >> 20) & 0x1f) as usize; let funct3 = (inst >> 12) & 0x7; let funct7 = (inst >> 25) & 0x7f; + + tracing::Span::current().record("opcode", opcode); + tracing::Span::current().record("rd", rd); + tracing::Span::current().record("rs1", rs1); + tracing::Span::current().record("rs2", rs2); + tracing::Span::current().record("funct3", funct3); + tracing::Span::current().record("funct7", funct7); + match opcode { // load 0x03 => { // imm[11:0] = inst[31:20] let imm = ((inst as i32 as i64) >> 20) as u64; + tracing::Span::current().record("imm", imm); let addr = self.regs[rs1].wrapping_add(imm); match funct3 { @@ -128,6 +149,7 @@ impl Cpu { 0x23 => { // imm[11:5|4:0] = inst[31:25|11:7] let imm = (((inst & 0xfe000000) as i32 as i64 >> 20) as u64) | ((inst >> 7) & 0x1f); + tracing::Span::current().record("imm", imm); let addr = self.regs[rs1].wrapping_add(imm); match funct3 { @@ -141,42 +163,54 @@ impl Cpu { // base imm 0x13 => { let imm = ((inst & 0xfff00000) as i32 as i64 >> 20) as u64; + tracing::Span::current().record("imm", imm); let imm04 = rs2; + tracing::Span::current().record("imm04", imm04); + match (funct3, funct7) { (0x0, _) => { // addi + debug!("ADDI"); self.regs[rd] = self.regs[rs1].wrapping_add(imm); } (0x4, _) => { // xori + debug!("XORI"); self.regs[rd] = self.regs[rs1].bitxor(imm); } (0x6, _) => { // ori + debug!("ORI"); self.regs[rd] = self.regs[rs1].bitor(imm); } (0x7, _) => { // andi + debug!("ANDI"); self.regs[rd] = self.regs[rs1].bitand(imm); } (0x1, 0x00) => { // slli + debug!("SLLI"); self.regs[rd] = self.regs[rs1].wrapping_shr(imm04 as u32); } (0x5, 0x00) => { // srli + debug!("SRLI"); self.regs[rd] = self.regs[rs1].wrapping_shl(imm04 as u32); } (0x5, 0x20) => { // srai + debug!("SRAI"); self.regs[rd] = (self.regs[rs1] as i64).wrapping_shr(imm04 as u32) as u64; } (0x2, _) => { // slti + debug!("SLTI"); self.regs[rd] = ((self.regs[rs1] as i64) < (imm as i64)) as u64 } (0x3, _) => { // sltiu + debug!("SLTIU"); self.regs[rd] = (self.regs[rs1] < imm) as u64 } _ => Err(())?, @@ -187,39 +221,48 @@ impl Cpu { match (funct3, funct7) { (0x0, 0x0) => { // add + debug!("ADD"); self.regs[rd] = self.regs[rs1].wrapping_add(self.regs[rs2]); } (0x0, 0x20) => { // sub + debug!("SUB"); self.regs[rd] = self.regs[rs1].wrapping_sub(self.regs[rs2]); } (0x4, 0x0) => { // xor + debug!("XOR"); self.regs[rd] = self.regs[rs1].bitxor(self.regs[rs2]); } (0x6, 0x0) => { // and + debug!("AND"); self.regs[rd] = self.regs[rs1].bitand(self.regs[rs2]); } (0x1, 0x0) => { // sll logical + debug!("SLL"); self.regs[rd] = self.regs[rs1].wrapping_shl(self.regs[rs2] as u32); } (0x5, 0x0) => { // srl logical + debug!("SRL"); self.regs[rd] = self.regs[rs1].wrapping_shr(self.regs[rs2] as u32); } (0x5, 0x20) => { // sra + debug!("SRA"); self.regs[rd] = (self.regs[rs1] as i64).wrapping_shr(self.regs[rs2] as u32) as u64; } (0x2, 0x0) => { // slt + debug!("SLT"); self.regs[rd] = ((self.regs[rs1] as i64) < (self.regs[rs2] as i64)) as u64 } (0x3, 0x0) => { // sltu + debug!("SLTU"); self.regs[rd] = (self.regs[rs1] < self.regs[rs2]) as u64 } _ => Err(())?, @@ -228,22 +271,123 @@ impl Cpu { 0x73 => { // csr - - todo!(); + let csr_addr = ((inst & 0xfff00000) >> 20) as usize; + tracing::Span::current().record("csr_addr", csr_addr); + let imm = rs1 as u64; match funct3 { + 0x1 => { + // CSRRW + + // dont read if rd is 0 + if rd != 0 { + let csr = self.load_csr(csr_addr); + tracing::Span::current().record("csr", csr); + + self.store_csr(csr_addr, self.regs[rs1]); + self.regs[rd] = csr; + } else { + self.store_csr(csr_addr, self.regs[rs1]); + } + debug!("CSRRW"); + } + 0x2 => { + // CSRRS + + let csr = self.load_csr(csr_addr); + tracing::Span::current().record("csr", csr); + debug!("CSRRS"); + self.regs[rd] = csr; + if rs1 != 0 { + self.store_csr(csr_addr, csr | self.regs[rs1]); + } + } + 0x3 => { + // CSRRC + let csr = self.load_csr(csr_addr); + tracing::Span::current().record("csr", csr); + debug!("CSRRC"); + self.regs[rd] = csr; + if rs1 != 0 { + self.store_csr(csr_addr, csr & self.regs[rs1]); + } + } + 0x5 => { + // CSRRWI + + // dont read if rd is 0 + if rd != 0 { + let csr = self.load_csr(csr_addr); + tracing::Span::current().record("csr", csr); + self.store_csr(csr_addr, imm); + self.regs[rd] = csr; + } else { + self.store_csr(csr_addr, imm); + } + debug!("CSRRWI"); + } + 0x6 => { + // CSRRSI + + let csr = self.load_csr(csr_addr); + tracing::Span::current().record("csr", csr); + + self.regs[rd] = csr; + if imm != 0 { + self.store_csr(csr_addr, csr | imm); + } + debug!("CSRRWSI"); + } + 0x7 => { + // CSRRCI + + let csr = self.load_csr(csr_addr); + tracing::Span::current().record("csr", csr); + debug!("CSRRCI"); + self.regs[rd] = csr; + if imm != 0 { + self.store_csr(csr_addr, csr & imm); + } + } _ => Err(())?, } } - x => unimplemented!("{:#09b}", x), + x => { + error!("unimplemented instruction"); + unimplemented!("{:#09b}", x) + } } + // page 554 + Ok(()) } pub fn dump_registers(&self) { + let abi = [ + "zero", " ra ", " sp ", " gp ", " tp ", " t0 ", " t1 ", " t2 ", " s0 ", " s1 ", " a0 ", + " a1 ", " a2 ", " a3 ", " a4 ", " a5 ", " a6 ", " a7 ", " s2 ", " s3 ", " s4 ", " s5 ", + " s6 ", " s7 ", " s8 ", " s9 ", " s10", " s11", " t3 ", " t4 ", " t5 ", " t6 ", + ]; + for (i, r) in self.regs.iter().enumerate() { - print!("x{:02} = 0x{:08x},\t\t", i, r); + print!("x{:02} ({}) = {:>#18x} | ", i, abi[i], r); + if (i + 1) % 4 == 0 { + println!() + } + } + println!() + } + + pub fn dump_csr(&self) { + for (i, x) in self + .csrs + .iter() + .enumerate() + .filter(|x| x.1 != &0) + .enumerate() + { + print!("{:02} = {:>#18x} | ", x.0, x.1); if (i + 1) % 4 == 0 { println!() } diff --git a/src/main.rs b/src/main.rs index 9bad7ea..a6b5589 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,23 @@ use std::{env, fs::File, io::Read}; use cpu::Cpu; +use tracing::Level; +use tracing_subscriber::{EnvFilter, FmtSubscriber}; mod bus; mod cpu; mod dram; fn main() -> Result<(), std::io::Error> { + tracing::subscriber::set_global_default( + FmtSubscriber::builder() + .with_env_filter(EnvFilter::from_default_env()) + .with_max_level(Level::DEBUG) + .pretty() + .finish(), + ) + .unwrap(); + let args: Vec = env::args().collect(); if args.len() != 2 { @@ -19,6 +30,7 @@ fn main() -> Result<(), std::io::Error> { let mut cpu = Cpu::new(code); cpu.run()?; cpu.dump_registers(); + cpu.dump_csr(); Ok(()) } diff --git a/tests/add-addi.s b/tests/add-addi.s deleted file mode 100644 index 8c1b044..0000000 --- a/tests/add-addi.s +++ /dev/null @@ -1,4 +0,0 @@ -main: - addi x29, x0, 5 - addi x30, x0, 37 - add x31, x30, x29 diff --git a/tests/addi.s b/tests/addi.s new file mode 100644 index 0000000..fcfa77e --- /dev/null +++ b/tests/addi.s @@ -0,0 +1,4 @@ +main: + addi x29, x0, 2 + addi x30, x0, 4 + add x31, x30, x29 diff --git a/tests/csr.s b/tests/csr.s new file mode 100644 index 0000000..a2d7936 --- /dev/null +++ b/tests/csr.s @@ -0,0 +1,12 @@ +main: + addi t0, zero, 1 + addi t1, zero, 2 + addi t2, zero, 3 + csrrw zero, mstatus, t0 + csrrs zero, mtvec, t1 + csrrw zero, mepc, t2 + csrrc t2, mepc, zero + csrrwi zero, sstatus, 4 + csrrsi zero, stvec, 5 + csrrwi zero, sepc, 6 + csrrci zero, sepc, 0