Skip to content

Commit

Permalink
Merge pull request #104 from sustech-cs304/test-simulator2
Browse files Browse the repository at this point in the history
Test simulator
  • Loading branch information
GenshinImpactStarts authored Jun 4, 2024
2 parents d0eb59b + fd3c833 commit 201c120
Show file tree
Hide file tree
Showing 17 changed files with 850 additions and 94 deletions.
9 changes: 8 additions & 1 deletion src-tauri/src/interface/simulator.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
interface::assembler::AssembleResult,
modules::riscv::basic::interface::parser::RISCV,
types::middleware_types::{AssemblerConfig, MemoryReturnRange},
types::middleware_types::{AssemblerConfig, MemoryReturnRange, Optional},
};

pub trait Simulator: Send + Sync {
Expand All @@ -24,4 +24,11 @@ pub trait Simulator: Send + Sync {
fn get_filepath(&self) -> &str;
fn get_memory_return_range(&self) -> MemoryReturnRange;
fn set_memory_return_range(&mut self, range: MemoryReturnRange) -> Result<(), String>;
fn set_fake_middleware(&mut self, middleware: Option<&'static mut dyn FakeMiddlewareTrait>);
}

pub trait FakeMiddlewareTrait: Send + Sync {
fn request_input(&mut self);
fn output(&mut self, output: &str);
fn update(&mut self, res: Optional);
}
10 changes: 4 additions & 6 deletions src-tauri/src/modules/riscv/basic/interface/parser.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(export_lexers)]
use std::io::Write;

use super::super::parser::parser::RISCVSymbolList;
Expand Down Expand Up @@ -76,17 +77,15 @@ impl RISCVExtension {
}
}

#[cfg(debug_assertions)]
#[allow(dead_code)]
#[cfg(export_lexers)]
pub fn export(&self, folder: &str) -> std::io::Result<()> {
match self {
RISCVExtension::RV32I => super::super::super::rv32i::parser::parser::export(folder),
}
}
}

#[cfg(debug_assertions)]
#[allow(dead_code)]
#[cfg(export_lexers)]
pub fn export_pair<T, KFn, VFn, K, W>(
pairs: &[T],
key_fn: KFn,
Expand Down Expand Up @@ -122,8 +121,7 @@ where
Ok(())
}

#[cfg(debug_assertions)]
#[allow(dead_code)]
#[cfg(export_lexers)]
pub fn export_list<T, F, V, W>(
list: &[T],
val_fn: F,
Expand Down
19 changes: 10 additions & 9 deletions src-tauri/src/modules/riscv/rv32i/parser/parser.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use std::{io::Write, str::FromStr};
#[cfg(export_lexers)]
use std::io::Write;
use std::str::FromStr;

use once_cell::sync::Lazy;
use strum::VariantArray;

#[cfg(debug_assertions)]
use super::super::super::basic::interface::parser::{export_list, export_pair};
#[cfg(export_lexers)]
use super::super::super::basic::{
interface::parser::{export_list, export_pair},
parser::lexer::RISCVOpToken,
};
use super::{
super::super::{
basic::{
interface::parser::{ParserRISCVCsr, ParserRISCVInstOp, ParserRISCVRegister},
parser::{
lexer::{RISCVOpToken, Symbol},
parser::RISCVSymbolList,
},
parser::{lexer::Symbol, parser::RISCVSymbolList},
},
rv32i::constants::{RV32ICsr, RV32IInstruction, RV32IRegister, RV32I_REGISTER_VALID_NAME},
},
Expand Down Expand Up @@ -47,8 +49,7 @@ pub static CSR_TOKEN: Lazy<Vec<(&'static str, Symbol<'static>)>> = Lazy::new(||
.collect()
});

#[cfg(debug_assertions)]
#[allow(dead_code)]
#[cfg(export_lexers)]
pub fn export(folder: &str) -> std::io::Result<()> {
let path = format!("{}/rv32i.json", folder);
let mut file = std::fs::File::create(&path)?;
Expand Down
63 changes: 22 additions & 41 deletions src-tauri/src/simulator/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ use RV32IInstruction::*;
use super::simulator::*;
use crate::{
interface::assembler::Operand,
modules::riscv::{
basic::interface::parser::RISCV,
middleware::backend_api::{syscall_input_request, syscall_output_print},
rv32i::constants::*,
},
modules::riscv::{basic::interface::parser::RISCV, rv32i::constants::*},
utility::{enum_map::EnumMap, ptr::Ptr},
};

Expand Down Expand Up @@ -237,10 +233,7 @@ pub(super) fn ebreak_handler(arg: InstHandlerArg) -> Result<SimulatorStatus, Str
pub(super) fn ecall_handler(arg: InstHandlerArg) -> Result<SimulatorStatus, String> {
match arg.reg(RV32IRegister::A7 as i32) {
1 => {
syscall_output_print(
arg.get_path(),
&((arg.reg(RV32IRegister::A0 as i32) as i32).to_string()),
)?;
arg.output(&((arg.reg(RV32IRegister::A0 as i32) as i32).to_string()))?;
arg.pc_step();
Ok(SimulatorStatus::Running)
}
Expand All @@ -256,58 +249,46 @@ pub(super) fn ecall_handler(arg: InstHandlerArg) -> Result<SimulatorStatus, Stri
buf.push(byte);
}
let s = String::from_utf8(buf).unwrap();
syscall_output_print(arg.get_path(), &s)?;
arg.output(&s)?;
arg.pc_step();
Ok(SimulatorStatus::Running)
}
5 => {
arg.sim.as_mut().wait_input = WaitStatus::Int;
syscall_input_request(arg.get_path())?;
arg.request_input(WaitStatus::Int)?;
Ok(SimulatorStatus::Paused)
}
8 => {
arg.sim.as_mut().wait_input = WaitStatus::String;
syscall_input_request(arg.get_path())?;
arg.request_input(WaitStatus::String)?;
Ok(SimulatorStatus::Paused)
}
10 => Ok(SimulatorStatus::Stopped),
11 => {
syscall_output_print(
arg.get_path(),
&((arg.reg(RV32IRegister::A0 as i32) as u8 as char).to_string()),
)?;
arg.output(&((arg.reg(RV32IRegister::A0 as i32) as u8 as char).to_string()))?;
arg.pc_step();
Ok(SimulatorStatus::Running)
}
12 => {
arg.sim.as_mut().wait_input = WaitStatus::Char;
syscall_input_request(arg.get_path())?;
arg.request_input(WaitStatus::Char)?;
Ok(SimulatorStatus::Paused)
}
34 => {
syscall_output_print(
arg.get_path(),
&format!("0x{:08x}", arg.sim.as_ref().reg[RV32IRegister::A0 as usize]),
)?;
arg.output(&format!(
"0x{:08x}",
arg.sim.as_ref().reg[RV32IRegister::A0 as usize]
))?;
arg.pc_step();
Ok(SimulatorStatus::Running)
}
35 => {
syscall_output_print(
arg.get_path(),
&format!(
"0x{:032b}",
arg.sim.as_ref().reg[RV32IRegister::A0 as usize]
),
)?;
arg.output(&format!(
"0b{:032b}",
arg.sim.as_ref().reg[RV32IRegister::A0 as usize]
))?;
arg.pc_step();
Ok(SimulatorStatus::Running)
}
36 => {
syscall_output_print(
arg.get_path(),
&((arg.reg(RV32IRegister::A0 as i32)).to_string()),
)?;
arg.output(&((arg.reg(RV32IRegister::A0 as i32)).to_string()))?;
arg.pc_step();
Ok(SimulatorStatus::Running)
}
Expand Down Expand Up @@ -518,10 +499,6 @@ impl<'a> InstHandlerArg<'a> {
&mut sim.reg[index as usize]
}

fn pc_idx(&self) -> usize {
self.sim.as_ref().pc_idx
}

fn pc(&self) -> u32 {
self.sim.as_ref().to_text_addr(self.sim.as_ref().pc_idx)
}
Expand All @@ -541,7 +518,11 @@ impl<'a> InstHandlerArg<'a> {
self.sim.as_mut().pc_idx += 1;
}

fn get_path(&self) -> &str {
&self.sim.as_ref().file
fn request_input(&self, wait_status: WaitStatus) -> Result<(), String> {
self.sim.as_mut().request_input(wait_status)
}

fn output(&self, output: &str) -> Result<(), String> {
self.sim.as_mut().output(output)
}
}
2 changes: 2 additions & 0 deletions src-tauri/src/simulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
mod instruction;
mod memory;
pub mod simulator;
#[cfg(test)]
mod test;
89 changes: 63 additions & 26 deletions src-tauri/src/simulator/simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ use super::{
};
use crate::{
dprintln,
interface::{assembler::AssembleResult, simulator::Simulator},
interface::{
assembler::AssembleResult,
simulator::{FakeMiddlewareTrait, Simulator},
},
modules::riscv::{
basic::interface::parser::{ParserRISCVInstOp, RV32IRegister, RISCV},
middleware::backend_api::simulator_update,
middleware::backend_api::{simulator_update, syscall_input_request, syscall_output_print},
},
types::middleware_types::{AssemblerConfig, MemoryReturnRange, Optional},
utility::ptr::Ptr,
Expand Down Expand Up @@ -52,6 +55,7 @@ pub struct RISCVSimulator {
status: AtomicU8,
history: VecDeque<History>,
mem_range: MemoryReturnRange,
fake_middleware: Option<&'static mut dyn FakeMiddlewareTrait>,
}

pub(super) struct History {
Expand Down Expand Up @@ -79,6 +83,7 @@ impl RISCVSimulator {
file: file.to_string(),
history: VecDeque::with_capacity(MAX_HISTORY_SIZE),
mem_range: Default::default(),
fake_middleware: None,
}
}

Expand Down Expand Up @@ -114,6 +119,27 @@ impl RISCVSimulator {
pub(super) fn to_text_addr(&self, idx: usize) -> u32 {
(self.conf.dot_text_base_address as usize + idx * 4) as u32
}

pub(super) fn request_input(&mut self, wait_status: WaitStatus) -> Result<(), String> {
self.wait_input = wait_status;
match &mut self.fake_middleware {
None => syscall_input_request(&self.file),
Some(middleware) => {
middleware.request_input();
Ok(())
}
}
}

pub(super) fn output(&mut self, msg: &str) -> Result<(), String> {
match &mut self.fake_middleware {
None => syscall_output_print(&self.file, msg),
Some(middleware) => {
middleware.output(msg);
Ok(())
}
}
}
}

impl Simulator for RISCVSimulator {
Expand Down Expand Up @@ -205,9 +231,6 @@ impl Simulator for RISCVSimulator {
}

fn step(&mut self) -> Result<(), String> {
if self.pc_idx >= self.inst.as_ref().unwrap().instruction.len() {
return Err("Simulator finished".to_string());
}
if !self.cas_status(SimulatorStatus::Stopped, SimulatorStatus::Running) {
if !self.cas_status(SimulatorStatus::Paused, SimulatorStatus::Running) {
return Err("Invalid operation".to_string());
Expand Down Expand Up @@ -405,6 +428,10 @@ impl Simulator for RISCVSimulator {
Ok(())
}
}

fn set_fake_middleware(&mut self, middleware: Option<&'static mut dyn FakeMiddlewareTrait>) {
self.fake_middleware = middleware;
}
}

impl RISCVSimulator {
Expand Down Expand Up @@ -498,14 +525,24 @@ impl RISCVSimulator {
step += 1;
}
}
if _self.pc_idx == max_pc_idx {
_self.set_status(SimulatorStatus::Stopped);
_self.update(Optional {
success: true,
message: "finished running".to_string(),
});
break;
}
match _self._step() {
Ok(SimulatorStatus::Paused) => {
_self.set_status(SimulatorStatus::Paused);
_self.update(Optional {
success: true,
message: "paused".to_string(),
});
break;
Ok(status) => {
_self.set_status(status);
if status == SimulatorStatus::Paused {
_self.update(Optional {
success: true,
message: "paused".to_string(),
});
break;
}
}
Err(e) => {
_self.set_status(SimulatorStatus::Stopped);
Expand All @@ -515,15 +552,6 @@ impl RISCVSimulator {
});
break;
}
_ => {}
}
if _self.pc_idx == max_pc_idx {
_self.set_status(SimulatorStatus::Stopped);
_self.update(Optional {
success: true,
message: "finished running".to_string(),
});
break;
}
if _self.get_status() != SimulatorStatus::Running {
_self.update(Optional {
Expand All @@ -537,11 +565,20 @@ impl RISCVSimulator {
}

fn update(&mut self, res: Optional) {
let paused = self.get_status() == SimulatorStatus::Paused;
match simulator_update(self, res, paused) {
Ok(_) => {}
Err(e) => {
dprintln!("{}", e);
match self.fake_middleware.as_mut() {
None => {
let paused = self.get_status() == SimulatorStatus::Paused;
match simulator_update(self, res, paused) {
Ok(_) => {}
Err(e) => {
dprintln!("{}", e);
}
}
}
Some(middleware) => {
if self.wait_input == WaitStatus::Not {
middleware.update(res)
}
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions src-tauri/src/simulator/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
mod memory {
use super::super::memory::Memory;

#[test]
fn test() {
let mut mem = Memory::new();
mem[0] = 1;
assert_eq!(mem[0], 1);
assert_eq!(mem[1], 0);
assert_eq!(mem[0x54365453u32], 0);
let start = 0x95478806u32;
mem.set_range(start, &[1, 2]);
assert_eq!(mem.get_range(start - 2, 6), [0, 0, 1, 2, 0, 0]);
let start = 0x07637855u32;
const LEN: usize = 16666;
mem.set_range(start, &[1; LEN]);
assert_eq!(mem.get_range(start, LEN as u32), [1; 16666]);
mem.reset();
}
}
Loading

0 comments on commit 201c120

Please sign in to comment.