improved debug interface
This commit is contained in:
354
simu/src/main.rs
354
simu/src/main.rs
@@ -20,7 +20,7 @@ use winit::event_loop::EventLoop;
|
||||
use winit::platform::scancode::PhysicalKeyExtScancode;
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::cpu::{Computer, MMIOInterupt};
|
||||
use crate::cpu::{Computer, MMIOInterupt, instr_to_text};
|
||||
mod wait;
|
||||
use wait::WaitOnAtomic;
|
||||
mod cpu;
|
||||
@@ -304,143 +304,7 @@ fn main() -> Result<(), Error> {
|
||||
//ugly debug code, I should improve that using a real TUI crate
|
||||
#[cfg(feature = "debug")]
|
||||
{
|
||||
let mut input = std::io::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 + 8,
|
||||
simulation.regs[i + 8]
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"SP: {:08x} PC: {:08x}",
|
||||
simulation.sp * 4,
|
||||
simulation.pc * 4
|
||||
);
|
||||
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(1);
|
||||
}
|
||||
false
|
||||
}
|
||||
"r" | "run" => {
|
||||
while !simulation.error {
|
||||
simulation.step(64);
|
||||
}
|
||||
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)
|
||||
);
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{e}");
|
||||
true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("{HELP_MSG}");
|
||||
true
|
||||
}
|
||||
}
|
||||
"c" | "context" => false,
|
||||
"u" | "up" => {
|
||||
while !simulation.error
|
||||
&& simulation.ram[simulation.pc] != 0x8800_0000
|
||||
{
|
||||
simulation.step(1);
|
||||
}
|
||||
false
|
||||
}
|
||||
"t" | "to" => {
|
||||
if next.len() >= 2 {
|
||||
match parse_int::parse::<u32>(next[1]) {
|
||||
Ok(v) => {
|
||||
while !simulation.error
|
||||
&& simulation.pc != (v as usize / 4)
|
||||
{
|
||||
simulation.step(1);
|
||||
}
|
||||
false
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{e}");
|
||||
true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("{HELP_MSG}");
|
||||
true
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("{HELP_MSG}");
|
||||
true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("{HELP_MSG}");
|
||||
true
|
||||
}
|
||||
} {}
|
||||
}
|
||||
debug_loop(&mut simulation);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -457,11 +321,209 @@ 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)
|
||||
up - run until the nex ret is reached (alias u)
|
||||
to n - tun until PC = n (alias t)
|
||||
";
|
||||
fn debug_loop(com: &mut Computer) {
|
||||
struct Wrap(DefaultCompleter, DefaultCompleter);
|
||||
|
||||
use clap::Parser;
|
||||
use clap_repl::ClapEditor;
|
||||
use clap_repl::reedline::{
|
||||
Completer, DefaultCompleter, DefaultPrompt, DefaultPromptSegment, FileBackedHistory,
|
||||
};
|
||||
|
||||
use crate::cpu::instr_to_text;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "")] // This name will show up in clap's error messages, so it is important to set it to "".
|
||||
enum Commands {
|
||||
/// Step by single instrcution
|
||||
#[command(alias = "s")]
|
||||
Step {
|
||||
///number of instruction to step (default one)
|
||||
num: Option<usize>,
|
||||
},
|
||||
/// Run until program halt, or specified instruction is reached
|
||||
#[command(alias = "r")]
|
||||
Run {
|
||||
/// Can be either a label or a address (support hex format)
|
||||
desigantor: Option<String>,
|
||||
},
|
||||
/// run until the current function return.
|
||||
#[command(alias = "u")]
|
||||
Up,
|
||||
/// Print memory at address. Support hexa format
|
||||
#[command(alias = "p")]
|
||||
Print { address: String },
|
||||
/// Print the address associated with a label
|
||||
#[command(alias = "l")]
|
||||
Label { label: String },
|
||||
/// Print context
|
||||
#[command(alias = "c")]
|
||||
Context,
|
||||
}
|
||||
let prompt = DefaultPrompt {
|
||||
left_prompt: DefaultPromptSegment::Basic(">>".to_owned()),
|
||||
right_prompt: DefaultPromptSegment::Empty,
|
||||
};
|
||||
|
||||
let commands_comp = DefaultCompleter::new_with_wordlen(
|
||||
["step", "run", "up", "print", "label", "help", "context"]
|
||||
.map(|s| s.to_string())
|
||||
.to_vec(),
|
||||
0,
|
||||
);
|
||||
let mut labels_comp =
|
||||
DefaultCompleter::with_inclusions("_0123456789".chars().collect::<Vec<_>>().as_slice())
|
||||
.set_min_word_len(0);
|
||||
labels_comp.insert(com.book.0.values().cloned().collect());
|
||||
|
||||
let editor = ClapEditor::<Commands>::builder()
|
||||
.with_prompt(Box::new(prompt))
|
||||
.with_editor_hook(|reed| {
|
||||
reed.with_history(Box::new(
|
||||
FileBackedHistory::with_file(1000, "debug_cmd.hist".into()).unwrap(),
|
||||
))
|
||||
.with_completer(Box::new(Wrap(commands_comp, labels_comp)))
|
||||
.with_quick_completions(true)
|
||||
.with_partial_completions(true)
|
||||
})
|
||||
.build();
|
||||
|
||||
debug_context(com);
|
||||
editor.repl(|command| match command {
|
||||
Commands::Step { num } => {
|
||||
let steps = num.unwrap_or(1);
|
||||
com.debug_step(steps);
|
||||
debug_context(com);
|
||||
}
|
||||
Commands::Run { desigantor } => match desigantor {
|
||||
Some(s) => match parse_int::parse::<usize>(s.as_str()) {
|
||||
Ok(addr) => {
|
||||
while com.pc != (addr / 4) {
|
||||
com.debug_step(1);
|
||||
}
|
||||
debug_context(com);
|
||||
}
|
||||
Err(_) => match com.book.1.get(s.as_str()).cloned() {
|
||||
Some(addr) => {
|
||||
while com.pc != (addr as usize / 4) {
|
||||
com.debug_step(1);
|
||||
}
|
||||
debug_context(com);
|
||||
}
|
||||
None => {
|
||||
println!("Error, {s} cannot be interpreted as addr nor label")
|
||||
}
|
||||
},
|
||||
},
|
||||
None => {
|
||||
while !com.error {
|
||||
com.debug_step(64);
|
||||
}
|
||||
debug_context(com);
|
||||
}
|
||||
},
|
||||
Commands::Up => {
|
||||
let curr_sp = com.sp;
|
||||
while (com.sp > curr_sp)
|
||||
|| ((com.ram[com.pc] != (0b10001000 << 24))
|
||||
&& (com.ram[com.pc] != (0b10101000 << 24)))
|
||||
{
|
||||
com.debug_step(1);
|
||||
}
|
||||
debug_context(com);
|
||||
}
|
||||
Commands::Print { address } => match parse_int::parse::<usize>(address.as_str()) {
|
||||
Ok(addr) => match com.ram.get(addr / 4) {
|
||||
Some(i) => {
|
||||
println!(
|
||||
"RAM at {addr:8x}: {:8x} {}",
|
||||
i,
|
||||
instr_to_text(*i, u32::MAX, &com.book.0)
|
||||
)
|
||||
}
|
||||
None => println!("Cannot index RAM at address {addr:8x}"),
|
||||
},
|
||||
Err(_) => match com.book.1.get(address.as_str()).cloned() {
|
||||
Some(addr) => println!(
|
||||
"RAM at {addr:8x}: {:8x} {}",
|
||||
com.ram[addr as usize / 4],
|
||||
instr_to_text(com.ram[addr as usize / 4], addr, &com.book.0)
|
||||
),
|
||||
None => {
|
||||
println!("Error, {address} cannot be interpreted as addr nor label")
|
||||
}
|
||||
},
|
||||
},
|
||||
Commands::Label { label } => match com.book.1.get(label.as_str()) {
|
||||
Some(addr) => println!("label is at addr {addr}"),
|
||||
None => println!("error: label not found"),
|
||||
},
|
||||
Commands::Context => debug_context(com),
|
||||
});
|
||||
exit(0);
|
||||
|
||||
impl Completer for Wrap {
|
||||
fn complete(&mut self, line: &str, pos: usize) -> Vec<clap_repl::reedline::Suggestion> {
|
||||
let trimmed = line.trim_start();
|
||||
let line_parts = trimmed.splitn(2, ' ').collect::<Vec<_>>();
|
||||
|
||||
if line_parts.len() <= 1 {
|
||||
self.0.complete(line, pos)
|
||||
} else {
|
||||
match line_parts[0] {
|
||||
"r" | "run" | "p" | "print" | "l" | "label" => {
|
||||
let trimmed_2 = line_parts[1].trim_start();
|
||||
let offset = line.len() - trimmed_2.len();
|
||||
let mut sub = self.1.complete(trimmed_2, pos - offset);
|
||||
for sug in sub.iter_mut() {
|
||||
use clap_repl::reedline::Span;
|
||||
|
||||
sug.span = Span {
|
||||
start: sug.span.start + offset,
|
||||
end: sug.span.end + offset,
|
||||
}
|
||||
}
|
||||
sub
|
||||
}
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_context(com: &Computer) {
|
||||
println!("Interupt state: {:?}", com.interupts);
|
||||
for i in 0..8 {
|
||||
println!(
|
||||
"r{i} = {:8x} r{:<2} = {:8x}",
|
||||
com.regs[i],
|
||||
i + 8,
|
||||
com.regs[i + 8]
|
||||
);
|
||||
}
|
||||
println!("SP={:08x} PC={:08x}", com.sp, com.pc);
|
||||
println!("RAM at SP | Ram at PC:");
|
||||
|
||||
let mut pc_lines = Vec::new();
|
||||
|
||||
for i in 0..16 {
|
||||
match com.book.0.get(&((com.pc + i) as u32 * 4)) {
|
||||
Some(label) => pc_lines.push(format!(" {label}:")),
|
||||
None => {}
|
||||
};
|
||||
pc_lines.push(format!(
|
||||
|
||||
"{:08x} {}",
|
||||
com.ram[com.pc + i],
|
||||
instr_to_text(com.ram[com.pc + i], (com.pc + i) as u32 * 4, &com.book.0)
|
||||
));
|
||||
}
|
||||
for (i, pc_l) in pc_lines.iter().enumerate() {
|
||||
if com.sp + i < com.ram.len() {
|
||||
println!("{:08x} | {pc_l}", com.ram[com.sp + i])
|
||||
} else {
|
||||
println!(" -- | {pc_l}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user