diff --git a/Cargo.lock b/Cargo.lock index df950a9..4c2555f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,6 +96,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + [[package]] name = "cc" version = "1.0.79" @@ -263,6 +269,7 @@ dependencies = [ "log", "regex", "rustyline", + "rvemu", ] [[package]] @@ -306,6 +313,15 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -474,6 +490,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "rvemu" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2cf2d0137e679b050f594199a7fddd31f06a80be7c8dc572cee89fa850e732b" +dependencies = [ + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "ryu" version = "1.0.14" @@ -579,6 +607,82 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 0c48bd8..7af2ce4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ clap = { version = "4.3.11", features = ["derive"] } regex = "1.9.0" eval = "0.4.3" anyhow = "1.0.80" +rvemu = "0.0.11" diff --git a/rvemu.dtb b/rvemu.dtb new file mode 100644 index 0000000..47c9f54 Binary files /dev/null and b/rvemu.dtb differ diff --git a/rvemu.dts b/rvemu.dts new file mode 100644 index 0000000..c33186f --- /dev/null +++ b/rvemu.dts @@ -0,0 +1,88 @@ +/dts-v1/; + +/ { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "riscv-virtio"; + model = "riscv-virtio,qemu"; + + chosen { + bootargs = "root=/dev/vda ro console=ttyS0"; + stdout-path = "/uart@10000000"; + }; + + uart@10000000 { + interrupts = <0xa>; + interrupt-parent = <0x03>; + clock-frequency = <0x384000>; + reg = <0x0 0x10000000 0x0 0x100>; + compatible = "ns16550a"; + }; + + virtio_mmio@10001000 { + interrupts = <0x01>; + interrupt-parent = <0x03>; + reg = <0x0 0x10001000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + cpus { + #address-cells = <0x01>; + #size-cells = <0x00>; + timebase-frequency = <0x989680>; + + cpu-map { + cluster0 { + core0 { + cpu = <0x01>; + }; + }; + }; + + cpu@0 { + phandle = <0x01>; + device_type = "cpu"; + reg = <0x00>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu"; + mmu-type = "riscv,sv48"; + + interrupt-controller { + #interrupt-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + phandle = <0x02>; + }; + }; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x8000000>; + }; + + soc { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + interrupt-controller@c000000 { + phandle = <0x03>; + riscv,ndev = <0x35>; + reg = <0x00 0xc000000 0x00 0x4000000>; + interrupts-extended = <0x02 0x0b 0x02 0x09>; + interrupt-controller; + compatible = "riscv,plic0"; + #interrupt-cells = <0x01>; + #address-cells = <0x00>; + }; + + clint@2000000 { + interrupts-extended = <0x02 0x03 0x02 0x07>; + reg = <0x00 0x2000000 0x00 0x10000>; + compatible = "riscv,clint0"; + }; + }; +}; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 49422ae..64cb459 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,87 @@ -use hemu::engine::init::engine_start; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::iter::FromIterator; -fn main() { - engine_start(); +use rvemu::bus::DRAM_BASE; +use rvemu::cpu::Cpu; +use rvemu::emulator::Emulator; + +use clap::Parser; + +/// Command line arguments. +#[derive(Parser, Debug)] +#[clap(name = "rvemu: RISC-V emulator", version = "0.0.1", author = "Asami Doi <@d0iasm>")] +struct Args { + /// A kernel ELF image without headers + #[arg(short = 'k', long = "kernel", required = true)] + kernel: String, + + /// A raw disk image + #[arg(short = 'f', long = "file")] + file: Option, + + /// Enables to output debug messages + #[arg(short = 'd', long = "debug")] + debug: bool, + + /// Enables to count each instruction executed + #[clap(short = 'c', long = "count")] + count: bool, +} + +/// Output current registers to the console. +fn dump_registers(cpu: &Cpu) { + println!("-------------------------------------------------------------------------------------------"); + println!("{}", cpu.xregs); + println!("-------------------------------------------------------------------------------------------"); + println!("{}", cpu.fregs); + println!("-------------------------------------------------------------------------------------------"); + println!("{}", cpu.state); + println!("-------------------------------------------------------------------------------------------"); + println!("pc: {:#x}", cpu.pc); +} + +/// Output the count of each instruction executed. +fn dump_count(cpu: &Cpu) { + if cpu.is_count { + println!("==========================================================================================="); + let mut sorted_counter = Vec::from_iter(&cpu.inst_counter); + sorted_counter.sort_by(|&(_, a), &(_, b)| b.cmp(&a)); + for (inst, count) in sorted_counter.iter() { + println!("{}, {}", inst, count); + } + println!("==========================================================================================="); + } +} + +/// Main function of RISC-V emulator for the CLI version. +fn main() -> io::Result<()> { + let args = Args::parse(); + + let mut kernel_file = File::open(args.kernel)?; + let mut kernel_data = Vec::new(); + kernel_file.read_to_end(&mut kernel_data)?; + + let mut img_data = Vec::new(); + if let Some(img_file) = args.file { + File::open(img_file)?.read_to_end(&mut img_data)?; + } + + let mut emu = Emulator::new(); + + emu.initialize_dram(kernel_data); + emu.initialize_disk(img_data); + emu.initialize_pc(DRAM_BASE); + + emu.is_debug = args.debug; + + emu.cpu.is_count = args.count; + + emu.start(); + + dump_registers(&emu.cpu); + dump_count(&emu.cpu); + + Ok(()) }