Debugging mode
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1508,6 +1508,7 @@ name = "simu"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-wait",
|
"atomic-wait",
|
||||||
|
"parse_int",
|
||||||
"pixels",
|
"pixels",
|
||||||
"winit",
|
"winit",
|
||||||
"winit_input_helper",
|
"winit_input_helper",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ rajouter --features=[liste séparé par des virgules]
|
|||||||
- div_mul: Support des instruction de multiplication / division
|
- div_mul: Support des instruction de multiplication / division
|
||||||
- rgba: Écran au format RGBA plutot que 0BGR
|
- rgba: Écran au format RGBA plutot que 0BGR
|
||||||
- rich_keyboard: rajoute trois champs de mmio pour le clavier. Voir MMIO
|
- rich_keyboard: rajoute trois champs de mmio pour le clavier. Voir MMIO
|
||||||
|
- debug: repl similaire a la version python du simulateur
|
||||||
|
|
||||||
### instruction spéciale:
|
### instruction spéciale:
|
||||||
halt (jump 0) met le programme en pause, mais on peut se reveiller par des interuptions
|
halt (jump 0) met le programme en pause, mais on peut se reveiller par des interuptions
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ atomic-wait = "1.1.0"
|
|||||||
pixels = "0.15.0"
|
pixels = "0.15.0"
|
||||||
winit = { version = "0.30.13", features = ["x11", "x11-dl", "x11rb", "ahash", "bytemuck", "memmap2", "rwh_06", "sctk", "sctk-adwaita"] }
|
winit = { version = "0.30.13", features = ["x11", "x11-dl", "x11rb", "ahash", "bytemuck", "memmap2", "rwh_06", "sctk", "sctk-adwaita"] }
|
||||||
winit_input_helper = "0.17.0"
|
winit_input_helper = "0.17.0"
|
||||||
|
parse_int = { version = "0.9.0", optional = true }
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
div_mul = []
|
div_mul = []
|
||||||
rgba = []
|
rgba = []
|
||||||
rich_keyboard = []
|
rich_keyboard = []
|
||||||
|
debug = ["dep:parse_int"]
|
||||||
|
|||||||
149
simu/src/cpu.rs
149
simu/src/cpu.rs
@@ -1,3 +1,5 @@
|
|||||||
|
#[cfg(feature = "debug")]
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::{
|
use std::{
|
||||||
hint::{likely, unlikely, unreachable_unchecked},
|
hint::{likely, unlikely, unreachable_unchecked},
|
||||||
io::Read,
|
io::Read,
|
||||||
@@ -5,8 +7,7 @@ use std::{
|
|||||||
ops::{Index, IndexMut},
|
ops::{Index, IndexMut},
|
||||||
process::exit,
|
process::exit,
|
||||||
sync::atomic::AtomicU32,
|
sync::atomic::AtomicU32,
|
||||||
thread::sleep,
|
time::{self, Instant},
|
||||||
time::{self, Duration, Instant},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct SharedState {
|
pub(crate) struct SharedState {
|
||||||
@@ -44,7 +45,8 @@ enum Cond {
|
|||||||
Ifule,
|
Ifule,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InteruptState {
|
#[derive(Debug)]
|
||||||
|
pub enum InteruptState {
|
||||||
Disabled,
|
Disabled,
|
||||||
Enabled,
|
Enabled,
|
||||||
Serving(InteruptKind, u8),
|
Serving(InteruptKind, u8),
|
||||||
@@ -52,7 +54,8 @@ enum InteruptState {
|
|||||||
|
|
||||||
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
|
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
enum InteruptKind {
|
#[allow(unused)] //some are there only based on features
|
||||||
|
pub(crate) enum InteruptKind {
|
||||||
MMIO = 1,
|
MMIO = 1,
|
||||||
Swi = 2,
|
Swi = 2,
|
||||||
DivByZero = 3,
|
DivByZero = 3,
|
||||||
@@ -243,13 +246,98 @@ impl TryFrom<u32> for Instruction {
|
|||||||
type Error = (InteruptKind, Reg, Reg, Op2, u32);
|
type Error = (InteruptKind, Reg, Reg, Op2, u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
impl Display for Op2 {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Op2::Direct(v) => write!(f, "{v}"),
|
||||||
|
Op2::Register(r) => write!(f, "r{r}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for Reg {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "r{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for Cond {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Cond::Ifeq => write!(f, "ifeq"),
|
||||||
|
Cond::Ifne => write!(f, "ifne"),
|
||||||
|
Cond::Iflt => write!(f, "iflt"),
|
||||||
|
Cond::Ifge => write!(f, "ifge"),
|
||||||
|
Cond::Ifgt => write!(f, "ifgt"),
|
||||||
|
Cond::Ifle => write!(f, "ifle"),
|
||||||
|
Cond::Ifult => write!(f, "ifult"),
|
||||||
|
Cond::Ifuge => write!(f, "ifuge"),
|
||||||
|
Cond::Ifugt => write!(f, "ifugt"),
|
||||||
|
Cond::Ifule => write!(f, "ifule"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub(crate) fn instr_to_text(i: u32, a: u32, book: &HashMap<u32, String>) -> String {
|
||||||
|
let addr = |addr: u32| {
|
||||||
|
let real = a.wrapping_add(addr * 4);
|
||||||
|
match book.get(&real) {
|
||||||
|
Some(s) => s.clone(),
|
||||||
|
None => format!("{addr}"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match Instruction::try_from(i) {
|
||||||
|
Ok(i) => match i {
|
||||||
|
Instruction::Copy(reg, op2) => format!("copy {reg} {op2}"),
|
||||||
|
Instruction::Add(reg, reg1, op2) => format!("add {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Sub(reg, reg1, op2) => format!("sub {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Or(reg, reg1, op2) => format!("or {reg} {reg1} {op2}"),
|
||||||
|
Instruction::And(reg, reg1, op2) => format!("and {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Xor(reg, reg1, op2) => format!("xor {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Lsl(reg, reg1, op2) => format!("lsl {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Lsr(reg, reg1, op2) => format!("lsr {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Asr(reg, reg1, op2) => format!("asr {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Smull(reg, reg1, op2) => format!("smull {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Smulh(reg, reg1, op2) => format!("smulh {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Umull(reg, reg1, op2) => format!("umull {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Umulh(reg, reg1, op2) => format!("umulh {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Div(reg, reg1, op2) => format!("div {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Mod(reg, reg1, op2) => format!("mod {reg} {reg1} {op2}"),
|
||||||
|
Instruction::Store(reg, op2, reg1) => format!("store [{reg} + {op2}] {reg1}]"),
|
||||||
|
Instruction::Load(reg, reg1, op2) => format! {"load {reg} [{reg1} + {op2}]"},
|
||||||
|
Instruction::Push(op2) => format!("push {op2}"),
|
||||||
|
Instruction::Pop(reg) => format!("pop {reg}"),
|
||||||
|
Instruction::Skip(d, cond, reg, op2) => {
|
||||||
|
format!("skip {} {cond} {reg} {op2}", addr(d as u32))
|
||||||
|
}
|
||||||
|
Instruction::Jump(a) => format!("jump {}", addr(a)),
|
||||||
|
Instruction::Call(a) => format!("call {}", addr(a)),
|
||||||
|
Instruction::Ret() => format!("ret"),
|
||||||
|
Instruction::Reti() => format!("reti"),
|
||||||
|
Instruction::Swi() => format!("swi"),
|
||||||
|
Instruction::Eint() => format!("eint"),
|
||||||
|
Instruction::Dint() => format!("dint"),
|
||||||
|
Instruction::GetStack(reg) => format!("copy {reg} sp"),
|
||||||
|
Instruction::SetStack(op2) => format!("copy sp {op2}"),
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
format!("D 0x{:8x}", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Computer {
|
pub struct Computer {
|
||||||
creation: Instant,
|
creation: Instant,
|
||||||
ram: Box<[u32; 0x01000000 / 4]>,
|
pub(crate) ram: Box<[u32; 0x01000000 / 4]>,
|
||||||
regs: [u32; 16],
|
pub(crate) regs: [u32; 16],
|
||||||
pc: usize,
|
pub(crate) pc: usize,
|
||||||
sp: usize,
|
pub(crate) sp: usize,
|
||||||
interupts: InteruptState,
|
pub(crate) interupts: InteruptState,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub(crate) error: bool,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub(crate) book: HashMap<u32, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<Reg> for Computer {
|
impl Index<Reg> for Computer {
|
||||||
@@ -279,18 +367,32 @@ impl Computer {
|
|||||||
pc: 0,
|
pc: 0,
|
||||||
sp: 0,
|
sp: 0,
|
||||||
interupts: InteruptState::Disabled,
|
interupts: InteruptState::Disabled,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
error: false,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
book: HashMap::new(),
|
||||||
};
|
};
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
std::fs::File::open(filename)
|
std::fs::File::open(filename)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read_to_string(&mut buf)
|
.read_to_string(&mut buf)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
for (i, line) in buf.lines().enumerate() {
|
let mut lines = buf.lines().enumerate();
|
||||||
|
while let Some((i, line)) = lines.next() {
|
||||||
match u32::from_str_radix(line, 16) {
|
match u32::from_str_radix(line, 16) {
|
||||||
Ok(val) => new.ram[i] = val,
|
Ok(val) => new.ram[i] = val,
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
while let Some((_, line)) = lines.next() {
|
||||||
|
if let Some([addr, s]) = line.split_ascii_whitespace().collect::<Vec<_>>().as_array() {
|
||||||
|
if let Ok(i) = u32::from_str_radix(addr, 16) {
|
||||||
|
println!("adding label {s} at addr {i}");
|
||||||
|
new.book.insert(i, s.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -477,9 +579,19 @@ impl Computer {
|
|||||||
if addr & (1 << 28) != 0 {
|
if addr & (1 << 28) != 0 {
|
||||||
addr += 7 << 29;
|
addr += 7 << 29;
|
||||||
} else if addr == 0 {
|
} else if addr == 0 {
|
||||||
println!("awaiting interupt...");
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
match self.interupts {
|
||||||
|
InteruptState::Disabled => {
|
||||||
|
println!("program terminated");
|
||||||
|
self.error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
println!("awaiting interupt...");
|
||||||
|
}
|
||||||
atomic_wait::wait(&SHARED.external_interupts, 0);
|
atomic_wait::wait(&SHARED.external_interupts, 0);
|
||||||
println!("waking!")
|
|
||||||
}
|
}
|
||||||
self.pc = (addr + self.pc as u32) as usize;
|
self.pc = (addr + self.pc as u32) as usize;
|
||||||
}
|
}
|
||||||
@@ -490,6 +602,13 @@ impl Computer {
|
|||||||
if addr & (1 << 28) != 0 {
|
if addr & (1 << 28) != 0 {
|
||||||
addr += 7 << 29;
|
addr += 7 << 29;
|
||||||
} else if unlikely(addr == 0) {
|
} else if unlikely(addr == 0) {
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
println!("program terminated");
|
||||||
|
self.error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
self.pc = (addr + self.pc as u32) as usize;
|
self.pc = (addr + self.pc as u32) as usize;
|
||||||
@@ -607,6 +726,12 @@ impl Computer {
|
|||||||
match self.interupts {
|
match self.interupts {
|
||||||
InteruptState::Disabled => {
|
InteruptState::Disabled => {
|
||||||
println!("Illegal Instruction whith interupt disabled {kind:?} {arg:?}");
|
println!("Illegal Instruction whith interupt disabled {kind:?} {arg:?}");
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
self.error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
InteruptState::Enabled => self.interupts = InteruptState::Serving(kind, 0),
|
InteruptState::Enabled => self.interupts = InteruptState::Serving(kind, 0),
|
||||||
|
|||||||
150
simu/src/main.rs
150
simu/src/main.rs
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::hint::unlikely;
|
use std::hint::unlikely;
|
||||||
|
use std::io::stdin;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
Arc,
|
Arc,
|
||||||
@@ -34,6 +35,7 @@ use cpu::SHARED;
|
|||||||
fn wait_int() {
|
fn wait_int() {
|
||||||
let mut v = (&SHARED.external_interupts).load(Acquire);
|
let mut v = (&SHARED.external_interupts).load(Acquire);
|
||||||
while unlikely(v != 0) {
|
while unlikely(v != 0) {
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
println!("wating for interupt clear {v}");
|
println!("wating for interupt clear {v}");
|
||||||
atomic_wait::wait(&SHARED.external_interupts, v);
|
atomic_wait::wait(&SHARED.external_interupts, v);
|
||||||
v = (&SHARED.external_interupts).load(Acquire);
|
v = (&SHARED.external_interupts).load(Acquire);
|
||||||
@@ -87,33 +89,40 @@ impl<'a> ApplicationHandler for App<'a> {
|
|||||||
if enabled {
|
if enabled {
|
||||||
wait_int();
|
wait_int();
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
print!("Keyboard event: ");
|
||||||
#[cfg(feature = "rich_keyboard")]
|
#[cfg(feature = "rich_keyboard")]
|
||||||
{
|
{
|
||||||
let txt = key_event
|
let kb0 = key_event
|
||||||
.logical_key
|
.logical_key
|
||||||
.to_text()
|
.to_text()
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(0, |a, e| a << 8 | (*e as u32));
|
.fold(0, |a, e| a << 8 | (*e as u32));
|
||||||
SHARED.keyboard[0].store(txt, Relaxed);
|
SHARED.keyboard[0].store(kb0, Relaxed);
|
||||||
let txt = key_event
|
let kb1 = key_event
|
||||||
.key_without_modifiers()
|
.key_without_modifiers()
|
||||||
.to_text()
|
.to_text()
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(0, |a, e| a << 8 | (*e as u32));
|
.fold(0, |a, e| a << 8 | (*e as u32));
|
||||||
SHARED.keyboard[1].store(txt, Relaxed);
|
SHARED.keyboard[1].store(kb1, Relaxed);
|
||||||
SHARED.keyboard[2].store(
|
let kb2 =
|
||||||
key_event.state.is_pressed() as u32 | ((key_event.repeat as u32) << 1),
|
key_event.state.is_pressed() as u32 | ((key_event.repeat as u32) << 1);
|
||||||
Relaxed,
|
SHARED.keyboard[2].store(kb2, Relaxed);
|
||||||
);
|
#[cfg(feature = "debug")]
|
||||||
|
print!("{kb0} {kb1} {kb2}")
|
||||||
}
|
}
|
||||||
SHARED.keyboard[3]
|
let kb3 = key_event.physical_key.to_scancode().unwrap_or(0);
|
||||||
.store(key_event.physical_key.to_scancode().unwrap_or(0), Relaxed);
|
#[cfg(feature = "debug")]
|
||||||
|
println!(" {kb3}");
|
||||||
|
SHARED.keyboard[3].store(kb3, Relaxed);
|
||||||
if enabled {
|
if enabled {
|
||||||
(&SHARED.external_interupts).store(MMIOInterupt::Keyboard.into(), Release);
|
(&SHARED.external_interupts).store(MMIOInterupt::Keyboard.into(), Release);
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
println!("wake due to keyboard event");
|
||||||
atomic_wait::wake_all(&SHARED.external_interupts);
|
atomic_wait::wake_all(&SHARED.external_interupts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,7 +150,8 @@ impl<'a> ApplicationHandler for App<'a> {
|
|||||||
}
|
}
|
||||||
if enabled {
|
if enabled {
|
||||||
(&SHARED.external_interupts).store(MMIOInterupt::MouseMove.into(), Release);
|
(&SHARED.external_interupts).store(MMIOInterupt::MouseMove.into(), Release);
|
||||||
println!("wake mouse move");
|
#[cfg(feature = "debug")]
|
||||||
|
println!("wake due mouse move");
|
||||||
atomic_wait::wake_all(&SHARED.external_interupts);
|
atomic_wait::wake_all(&SHARED.external_interupts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,6 +184,7 @@ impl<'a> ApplicationHandler for App<'a> {
|
|||||||
};
|
};
|
||||||
if enabled {
|
if enabled {
|
||||||
(&SHARED.external_interupts).store(MMIOInterupt::MouseClick.into(), Release);
|
(&SHARED.external_interupts).store(MMIOInterupt::MouseClick.into(), Release);
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
println!("wake mouse click");
|
println!("wake mouse click");
|
||||||
atomic_wait::wake_all(&SHARED.external_interupts);
|
atomic_wait::wake_all(&SHARED.external_interupts);
|
||||||
}
|
}
|
||||||
@@ -286,12 +297,120 @@ fn main() -> Result<(), Error> {
|
|||||||
let program = args()
|
let program = args()
|
||||||
.nth(1)
|
.nth(1)
|
||||||
.expect("you must supply the exec name as the first argument");
|
.expect("you must supply the exec name as the first argument");
|
||||||
|
|
||||||
scope(|sc| {
|
scope(|sc| {
|
||||||
sc.spawn(|| {
|
sc.spawn(|| {
|
||||||
let mut simulation = Computer::new(program);
|
let mut simulation = Computer::new(program);
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
loop {
|
loop {
|
||||||
simulation.step();
|
simulation.step();
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
{
|
||||||
|
let mut input = stdin().lines();
|
||||||
|
loop {
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"interrupts are {:?}, with mmio interupts flags {}",
|
||||||
|
simulation.interupts,
|
||||||
|
SHARED.external_enabled_interupts.load(Relaxed)
|
||||||
|
);
|
||||||
|
for i in 0..8 {
|
||||||
|
println!(
|
||||||
|
"r{i} 0x{:08x} r{} 0x{:08x}",
|
||||||
|
simulation.regs[i],
|
||||||
|
i + 1,
|
||||||
|
simulation.regs[i + 1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("SP: {:08x} PC: {:08x}", simulation.sp, simulation.pc);
|
||||||
|
println!("RAM near SP");
|
||||||
|
let min_pc = (simulation.pc).min(0x0100_0000 / 4 - 8);
|
||||||
|
let min_sp = (simulation.sp).min(0x0100_0000 / 4 - 8);
|
||||||
|
for i in 0..8 {
|
||||||
|
println!(
|
||||||
|
"{:8x}: 0x{:08x}",
|
||||||
|
(min_sp + i) * 4,
|
||||||
|
simulation.ram[min_sp + i],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("Ram near PC");
|
||||||
|
for i in 0..8 {
|
||||||
|
let idx = min_pc + i;
|
||||||
|
let istr = simulation.ram[idx];
|
||||||
|
if let Some(s) = simulation.book.get(&(idx as u32 * 4)) {
|
||||||
|
println!("{s}:")
|
||||||
|
};
|
||||||
|
println!(
|
||||||
|
"{:8x}: 0x{:08x} {}",
|
||||||
|
idx * 4,
|
||||||
|
istr,
|
||||||
|
cpu::instr_to_text(istr, idx as u32 * 4, &simulation.book)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while {
|
||||||
|
let next = input.next().unwrap().unwrap();
|
||||||
|
let next: Vec<_> = next.split_ascii_whitespace().collect();
|
||||||
|
if next.len() > 0 {
|
||||||
|
match next[0] {
|
||||||
|
"s" | "step" => {
|
||||||
|
let n: usize = {
|
||||||
|
if next.len() >= 2 {
|
||||||
|
parse_int::parse(next[1]).unwrap_or(1)
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for _ in 0..n {
|
||||||
|
if simulation.error {
|
||||||
|
println!("cannot step, cpu killed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
simulation.step();
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
"r" | "run" => {
|
||||||
|
while !simulation.error {
|
||||||
|
simulation.step();
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
"p" | "print" => {
|
||||||
|
if next.len() >= 2 {
|
||||||
|
match parse_int::parse::<u32>(next[1]) {
|
||||||
|
Ok(i) => {
|
||||||
|
let v = simulation.ram[i as usize/4];
|
||||||
|
println!(
|
||||||
|
"0x{:8x} -- {}",
|
||||||
|
v,
|
||||||
|
cpu::instr_to_text(v, i, &simulation.book)
|
||||||
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{e}");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"c" | "context" => false,
|
||||||
|
_ => {
|
||||||
|
println!("{HELP_MSG}");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("{HELP_MSG}");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
@@ -305,3 +424,12 @@ fn main() -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
const HELP_MSG: &str = "
|
||||||
|
step n - step trough n instructions (alias s)
|
||||||
|
run - run program until exit / error (alias r)
|
||||||
|
context - print context (alias c)
|
||||||
|
print n - print ram content at address n and next 8 (alias p)
|
||||||
|
- repeat last step (yes, do no enter anything and press Enter)
|
||||||
|
";
|
||||||
|
|||||||
Reference in New Issue
Block a user