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::{
diagnostic::{Diagnostic, Label},
files::SimpleFile,
@ -9,13 +11,16 @@ use codespan_reporting::{
};
use colored::Colorize;
use itertools::Itertools;
use riscv_interpreter::{
use rizz_v::{
env::Env,
execution::run_instruction,
info::info,
parser::{parse, Token},
};
use termion::input::TermRead;
fn main() -> anyhow::Result<()> {
let display_mode = 's';
let writer = StandardStream::stderr(ColorChoice::Always);
let config = Config::default();
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 toks: Vec<Token> = Vec::new();
let mut ops: Vec<u32> = Vec::new();
let mut parse_asm_result = String::new();
match parse(&env, &input) {
Ok(tokens) => {
let lines: Vec<&str> = input.lines().collect();
@ -38,7 +46,8 @@ fn main() -> anyhow::Result<()> {
let token = token.clone();
match token.clone() {
Token::Op(..) => match env.assemble_op((token, loc.clone())) {
Token::Mnemonic(..) => {
match env.assemble_op((token.clone(), loc.clone())) {
Ok(op) => {
let mut formatted = format!(
"{:<1$} {3:02x}: {2:032b}",
@ -48,6 +57,7 @@ fn main() -> anyhow::Result<()> {
loc.mem_offset
);
ops.push(op[0]);
toks.push(token.clone());
if op.len() > 1 {
for op in op[1..].iter() {
@ -59,9 +69,10 @@ fn main() -> anyhow::Result<()> {
loc.mem_offset
);
ops.push(*op);
toks.push(token.clone());
}
}
println!("{}", formatted);
parse_asm_result += &format!("{}\n", formatted);
}
Err(err) => {
let diagnostic = Diagnostic::error()
@ -83,10 +94,11 @@ fn main() -> anyhow::Result<()> {
term::emit(&mut writer.lock(), &config, &file, &diagnostic)
.unwrap();
}
},
}
}
Token::Label(name) => {
println!(
"{:<1$} <{2:02x}>",
parse_asm_result += &format!(
"{:<1$} <{2:02x}>\n",
name.clone() + ":",
size + 3,
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
while env.pc / 4 < ops.clone().len() as u32 {
let pc = env.pc.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;
let mut changed = Vec::new();
for (i, _) in prev_regs
.iter()
.zip(env.registers.iter())
@ -140,53 +158,113 @@ fn main() -> anyhow::Result<()> {
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!(
"{}",
make_box(
term_width as u32,
"{}\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,
's'
)
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!(
"{}",
left.lines()
.zip(right.lines().chain([""].repeat(left.lines().count())))
.map(|(l, r)| format!("{} {}", l, r))
.join("\n")
);
println!("\nPress enter to continue...");
for c in std::io::stdin().keys() {
match c.unwrap() {
termion::event::Key::Char('\n') => break,
_ => {}
}
}
}
Ok(())
}
fn round_down_to_power_of_two(n: u32) -> u32 {
const fn round_down_to_power_of_two(n: u32) -> u32 {
1 << (32 - n.leading_zeros() - 1)
}
/// Assuming the terminal is at least 80 characters wide
///
/// Display Mode:
/// - b: binary
/// - u: unsigned decimal
/// - h: hex
/// - s: signed decimal
/// - f: float
/// - u: unsigned decimal
/// - b: binary
/// - h: hex
fn make_box(
width: u32,
pc: usize,
regs: Vec<u32>,
changed: Vec<usize>,
display_mode: char,
first: bool,
tag: (Vec<usize>, Vec<usize>),
) -> String {
let cell_inner_width: u32 = match display_mode {
'b' => 32,
'u' => 10,
'h' => 8,
's' => 11,
'f' => todo!("float display mode"),
_ => unreachable!(),
} + 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(pc, regs, changed, display_mode, first, tag);
}
let mut boxed = String::new();
if first {
boxed += &format!(
"┌─╢ pc = {pc:04x} ╟{:─<1$}┬",
"",
@ -196,6 +274,17 @@ fn make_box(
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);
}
for chunk in &regs.iter().enumerate().chunks(num_boxes as usize) {
let chunk = chunk.collect::<Vec<_>>();
@ -204,20 +293,27 @@ fn make_box(
for (i, reg) in chunk {
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),
'u' => format!("x{:<3} {1:>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)
format!(
"x{:<3} {:>11}",
i.to_string() + ":",
sign.to_string() + &signed.abs().to_string()
)
}
'f' => todo!("float display mode"),
_ => unreachable!(),
};
let reg = if changed.contains(&i) {
reg.bright_green()
} else {
if tag.0.contains(&i) {
reg.bright_yellow()
} else {
reg.normal()
}
};
formatted += &format!("{}", reg);
}
@ -225,11 +321,153 @@ fn make_box(
boxed += &format!("{}\n", formatted);
}
boxed
}
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
}
/// 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
}