Show the FP reg table and use the new info format

This commit is contained in:
Lumi Kalt 2024-05-01 13:15:29 +01:00
parent ac07031631
commit 386a3b7403

View file

@ -1,3 +1,5 @@
use std::io::Write;
use codespan_reporting::{ use codespan_reporting::{
diagnostic::{Diagnostic, Label}, diagnostic::{Diagnostic, Label},
files::SimpleFile, files::SimpleFile,
@ -9,13 +11,16 @@ use codespan_reporting::{
}; };
use colored::Colorize; use colored::Colorize;
use itertools::Itertools; use itertools::Itertools;
use riscv_interpreter::{ use rizz_v::{
env::Env, env::Env,
execution::run_instruction, execution::run_instruction,
info::info,
parser::{parse, Token}, parser::{parse, Token},
}; };
use termion::input::TermRead;
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let display_mode = 's';
let writer = StandardStream::stderr(ColorChoice::Always); let writer = StandardStream::stderr(ColorChoice::Always);
let config = Config::default(); let config = Config::default();
let input = std::fs::read_to_string("test.s").unwrap(); let input = std::fs::read_to_string("test.s").unwrap();
@ -25,8 +30,11 @@ fn main() -> anyhow::Result<()> {
let mut env = Env::new(); let mut env = Env::new();
let mut toks: Vec<Token> = Vec::new();
let mut ops: Vec<u32> = Vec::new(); let mut ops: Vec<u32> = Vec::new();
let mut parse_asm_result = String::new();
match parse(&env, &input) { match parse(&env, &input) {
Ok(tokens) => { Ok(tokens) => {
let lines: Vec<&str> = input.lines().collect(); let lines: Vec<&str> = input.lines().collect();
@ -38,55 +46,59 @@ fn main() -> anyhow::Result<()> {
let token = token.clone(); let token = token.clone();
match token.clone() { match token.clone() {
Token::Op(..) => match env.assemble_op((token, loc.clone())) { Token::Mnemonic(..) => {
Ok(op) => { match env.assemble_op((token.clone(), loc.clone())) {
let mut formatted = format!( Ok(op) => {
"{:<1$} {3:02x}: {2:032b}", let mut formatted = format!(
lines[loc.line - 1], "{:<1$} {3:02x}: {2:032b}",
size + 3, lines[loc.line - 1],
op[0], size + 3,
loc.mem_offset op[0],
); loc.mem_offset
ops.push(op[0]); );
ops.push(op[0]);
toks.push(token.clone());
if op.len() > 1 { if op.len() > 1 {
for op in op[1..].iter() { for op in op[1..].iter() {
formatted += &format!( formatted += &format!(
"\n{:<1$} {3:02x}: {2:032b}", "\n{:<1$} {3:02x}: {2:032b}",
"", "",
size + 3, size + 3,
op, op,
loc.mem_offset loc.mem_offset
); );
ops.push(*op); ops.push(*op);
} toks.push(token.clone());
}
println!("{}", formatted);
}
Err(err) => {
let diagnostic = Diagnostic::error()
.with_message("Engine Error")
.with_labels(vec![Label::primary(
(),
err.1.start..(err.1.end + 1),
)
.with_message(err.0.to_string())])
.with_notes({
let mut notes = Vec::new();
if let Some(note) = &err.2 {
notes.push(note.to_string());
} }
notes.push(err.0.note()); }
notes parse_asm_result += &format!("{}\n", formatted);
}); }
Err(err) => {
let diagnostic = Diagnostic::error()
.with_message("Engine Error")
.with_labels(vec![Label::primary(
(),
err.1.start..(err.1.end + 1),
)
.with_message(err.0.to_string())])
.with_notes({
let mut notes = Vec::new();
if let Some(note) = &err.2 {
notes.push(note.to_string());
}
notes.push(err.0.note());
notes
});
term::emit(&mut writer.lock(), &config, &file, &diagnostic) term::emit(&mut writer.lock(), &config, &file, &diagnostic)
.unwrap(); .unwrap();
}
} }
}, }
Token::Label(name) => { Token::Label(name) => {
println!( parse_asm_result += &format!(
"{:<1$} <{2:02x}>", "{:<1$} <{2:02x}>\n",
name.clone() + ":", name.clone() + ":",
size + 3, size + 3,
env.get_label(&name).unwrap() env.get_label(&name).unwrap()
@ -121,16 +133,22 @@ fn main() -> anyhow::Result<()> {
} }
}; };
let mut file = std::fs::File::create("test.bin")?;
for op in ops.iter() {
let formatted = format!("{:08x}\n", op);
file.write_all(formatted.as_bytes()).unwrap();
}
// Print the register values // Print the register values
while env.pc / 4 < ops.clone().len() as u32 { while env.pc / 4 < ops.clone().len() as u32 {
let pc = env.pc.clone(); let pc = env.pc.clone();
let prev_regs = env.registers.clone(); let prev_regs = env.registers.clone();
let prev_fregs = env.fregisters.clone();
env.pc += 4 * !run_instruction(&mut env, ops[pc as usize >> 2]) as u32; env.pc += 4 * !run_instruction(&mut env, ops[pc as usize >> 2]) as u32;
let mut changed = Vec::new(); let mut changed = Vec::new();
for (i, _) in prev_regs for (i, _) in prev_regs
.iter() .iter()
.zip(env.registers.iter()) .zip(env.registers.iter())
@ -140,62 +158,133 @@ fn main() -> anyhow::Result<()> {
changed.push(i); changed.push(i);
} }
let mut fchanged = Vec::new();
for (i, _) in prev_fregs
.iter()
.zip(env.fregisters.iter())
.enumerate()
.filter(|(_, (prev, curr))| prev != curr)
{
fchanged.push(i);
}
println!(
"{}\n",
parse_asm_result
.lines()
.enumerate()
.map(|(i, line)| {
if i == pc as usize >> 2 {
format!("> {}", line).bright_green()
} else {
format!(" {}", line).normal()
}
})
.join("\n")
);
let (right, tag) = if let Token::Mnemonic(op, args) = &toks[pc as usize >> 2] {
info(
&env,
&op,
args.iter().map(|(token, _)| token.to_string()).collect(),
display_mode,
)
} else {
unreachable!()
};
let left = make_box(
term_width as u32 / 2,
pc as usize,
env.registers.clone().into_iter().collect(),
changed,
display_mode,
true,
tag.clone(),
) + &make_box_fp(
term_width as u32 / 2,
env.fregisters.clone().into_iter().collect(),
fchanged,
display_mode,
true,
tag,
);
println!( println!(
"{}", "{}",
make_box( left.lines()
term_width as u32, .zip(right.lines().chain([""].repeat(left.lines().count())))
pc as usize, .map(|(l, r)| format!("{} {}", l, r))
env.registers.clone().into_iter().collect(), .join("\n")
changed,
's'
)
); );
println!("\nPress enter to continue...");
for c in std::io::stdin().keys() {
match c.unwrap() {
termion::event::Key::Char('\n') => break,
_ => {}
}
}
} }
Ok(()) Ok(())
} }
const fn round_down_to_power_of_two(n: u32) -> u32 {
fn round_down_to_power_of_two(n: u32) -> u32 {
1 << (32 - n.leading_zeros() - 1) 1 << (32 - n.leading_zeros() - 1)
} }
/// Assuming the terminal is at least 80 characters wide /// Assuming the terminal is at least 80 characters wide
///
/// Display Mode: /// Display Mode:
/// - b: binary
/// - u: unsigned decimal
/// - h: hex
/// - s: signed decimal /// - s: signed decimal
/// - f: float /// - u: unsigned decimal
/// - b: binary
/// - h: hex
fn make_box( fn make_box(
width: u32, width: u32,
pc: usize, pc: usize,
regs: Vec<u32>, regs: Vec<u32>,
changed: Vec<usize>, changed: Vec<usize>,
display_mode: char, display_mode: char,
first: bool,
tag: (Vec<usize>, Vec<usize>),
) -> String { ) -> String {
let cell_inner_width: u32 = match display_mode { let cell_inner_width: u32 = match display_mode {
'b' => 32, 'b' => 32,
'u' => 10, 'u' => 10,
'h' => 8, 'h' => 8,
's' => 11, 's' => 11,
'f' => todo!("float display mode"),
_ => unreachable!(), _ => unreachable!(),
} + 7; } + 7;
// Nnumber of boxes that fit horizontally // Nnumber of boxes that fit horizontally
let num_boxes = round_down_to_power_of_two((width / (cell_inner_width + 2)) as u32); let num_boxes = round_down_to_power_of_two((width / (cell_inner_width + 2)) as u32);
if num_boxes <= 1 {
return make_one_wide_box(pc, regs, changed, display_mode, first, tag);
}
let mut boxed = String::new(); let mut boxed = String::new();
boxed += &format!( if first {
"┌─╢ pc = {pc:04x} ╟{:─<1$}┬", boxed += &format!(
"", "┌─╢ pc = {pc:04x} ╟{:─<1$}┬",
cell_inner_width.saturating_sub(14) as usize "",
); cell_inner_width.saturating_sub(14) as usize
for _ in 1..(num_boxes - 1) { );
boxed += &format!("{:─<1$}", "", cell_inner_width as usize); for _ in 1..(num_boxes - 1) {
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
}
boxed += &format!("{:─<1$}\n", "", cell_inner_width as usize);
} else {
boxed += &format!(
"├─╢ pc = {pc:04x} ╟{:─<1$}┼",
"",
cell_inner_width.saturating_sub(14) as usize
);
for _ in 1..(num_boxes - 1) {
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
}
boxed += &format!("{:─<1$}\n", "", cell_inner_width as usize);
} }
boxed += &format!("{:─<1$}\n", "", cell_inner_width as usize);
for chunk in &regs.iter().enumerate().chunks(num_boxes as usize) { for chunk in &regs.iter().enumerate().chunks(num_boxes as usize) {
let chunk = chunk.collect::<Vec<_>>(); let chunk = chunk.collect::<Vec<_>>();
@ -204,20 +293,27 @@ fn make_box(
for (i, reg) in chunk { for (i, reg) in chunk {
let reg = match display_mode { let reg = match display_mode {
'b' => format!("x{:<3} {1:0>32b}", i.to_string() + ":", reg), 'b' => format!("x{:<3} {1:0>32b}", i.to_string() + ":", reg),
'u' => format!("x{:<3} {1:0>10}", i.to_string() + ":", reg), 'u' => format!("x{:<3} {1:>10}", i.to_string() + ":", reg),
'h' => format!("x{:<3} {1:0>8x}", i.to_string() + ":", reg), 'h' => format!("x{:<3} {1:0>8x}", i.to_string() + ":", reg),
's' => { 's' => {
let signed = *reg as i32; let signed = *reg as i32;
let sign = if signed < 0 { "-" } else { "+" }; let sign = if signed < 0 { "-" } else { "+" };
format!("x{:<3} {}{:0>10}", i.to_string() + ":", sign, signed) format!(
"x{:<3} {:>11}",
i.to_string() + ":",
sign.to_string() + &signed.abs().to_string()
)
} }
'f' => todo!("float display mode"),
_ => unreachable!(), _ => unreachable!(),
}; };
let reg = if changed.contains(&i) { let reg = if changed.contains(&i) {
reg.bright_green() reg.bright_green()
} else { } else {
reg.normal() if tag.0.contains(&i) {
reg.bright_yellow()
} else {
reg.normal()
}
}; };
formatted += &format!("{}", reg); formatted += &format!("{}", reg);
} }
@ -225,11 +321,153 @@ fn make_box(
boxed += &format!("{}\n", formatted); boxed += &format!("{}\n", formatted);
} }
boxed += &format!("{:─<1$}", "", cell_inner_width as usize); boxed
for _ in 1..(num_boxes - 1) { }
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
fn make_one_wide_box(
pc: usize,
regs: Vec<u32>,
changed: Vec<usize>,
display_mode: char,
first: bool,
tag: (Vec<usize>, Vec<usize>),
) -> String {
let mut boxed = String::new();
boxed += &if first {
format!("┌─╢ pc = {pc:04x}{:─<1$}\n", "", 32)
} else {
format!("├─╢ pc = {pc:04x}{:─<1$}\n", "", 32)
};
for (i, reg) in regs.iter().enumerate() {
let reg = match display_mode {
'b' => format!("x{:<3} {1:0>32b}", i.to_string() + ":", reg),
'u' => format!("x{:<3} {1:0>10}", i.to_string() + ":", reg),
'h' => format!("x{:<3} {1:0>8x}", i.to_string() + ":", reg),
's' => {
let signed = *reg as i32;
let sign = if signed < 0 { "-" } else { "+" };
format!("x{:<3} {}{:0>10}", i.to_string() + ":", sign, signed.abs())
}
_ => unreachable!(),
};
let reg = if changed.contains(&i) {
reg.bright_green()
} else {
if tag.0.contains(&i) {
reg.bright_yellow()
} else {
reg.normal()
}
};
boxed += &format!("{}\n", reg);
} }
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
boxed
}
/// Assuming the terminal is at least 80 characters wide
/// Display Mode:
/// - s,u: floating point
/// - b: binary
/// - x: hexadecimal
/// - e: scientific
fn make_box_fp(
width: u32,
regs: Vec<f32>,
changed: Vec<usize>,
display_mode: char,
last: bool,
tag: (Vec<usize>, Vec<usize>),
) -> String {
let cell_inner_width: u32 = 11 + 7;
// Nnumber of boxes that fit horizontally
let num_boxes = round_down_to_power_of_two((width / (cell_inner_width + 2)) as u32);
if num_boxes <= 1 {
return make_one_wide_box_fp(regs, changed, last, tag);
}
let mut boxed = String::new();
boxed += &format!("├─{:─<1$}", "", (cell_inner_width - 1) as usize);
for _ in 1..(num_boxes - 1) {
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
}
boxed += &format!("{:─<1$}\n", "", cell_inner_width as usize);
for chunk in &regs.iter().enumerate().chunks(num_boxes as usize) {
let chunk = chunk.collect::<Vec<_>>();
let mut formatted = String::from("");
for (i, freg) in chunk {
// let freg = format!("f{:<3} {:>11}", i.to_string() + ":", freg);
let freg = match display_mode {
's' | 'u' => format!("f{:<3} {:>11}", i.to_string() + ":", freg),
'b' => format!("f{:<3} {:0>32b}", i.to_string() + ":", freg.to_bits()),
'x' => format!("f{:<3} {:0>8x}", i.to_string() + ":", freg.to_bits()),
'e' => format!("f{:<3} {:>11e}", i.to_string() + ":", freg),
_ => unreachable!(),
};
let reg = if changed.contains(&i) {
freg.bright_green()
} else {
if tag.1.contains(&i) {
freg.bright_yellow()
} else {
freg.normal()
}
};
formatted += &format!("{}", reg);
}
boxed += &format!("{}\n", formatted);
}
if last {
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
for _ in 1..(num_boxes - 1) {
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
}
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
} else {
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
for _ in 1..(num_boxes - 1) {
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
}
boxed += &format!("{:─<1$}", "", cell_inner_width as usize);
}
boxed
}
fn make_one_wide_box_fp(
regs: Vec<f32>,
changed: Vec<usize>,
last: bool,
tag: (Vec<usize>, Vec<usize>),
) -> String {
let mut boxed = String::new();
boxed += &format!("├─{:─<1$}\n", "", 32);
for (i, freg) in regs.iter().enumerate() {
let freg = format!("f{:<3} {:0>11}", i.to_string() + ":", freg);
let reg = if changed.contains(&i) {
freg.bright_green()
} else {
if tag.1.contains(&i) {
freg.bright_yellow()
} else {
freg.normal()
}
};
boxed += &format!("{}\n", reg);
}
boxed += &if last {
format!("{:─<1$}", "", 32)
} else {
format!("{:─<1$}", "", 32)
};
boxed boxed
} }