Fully up to date (#16)

* Run in main

* Pipeline

* Pacify Clippy
This commit is contained in:
Patrick Stevens
2023-04-16 16:33:52 +01:00
committed by GitHub
parent e905445786
commit 1512e794a6
8 changed files with 182 additions and 52 deletions

View File

@@ -162,8 +162,12 @@ jobs:
"with": { "extra-nix-config": "access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}" }
},
{
"name": "Run app",
"name": "Run app (verify consistency)",
"run": "nix run . -- computer_enhance/perfaware/part1/listing_0038_many_register_mov computer_enhance/perfaware/part1/listing_0038_many_register_mov.asm"
},
{
"name": "Run app",
"run": "nix run . -- computer_enhance/perfaware/part1/listing_0055_challenge_rectangle computer_enhance/perfaware/part1/listing_0055_challenge_rectangle.asm"
}
]
}

View File

@@ -322,12 +322,16 @@ impl Computer {
Register::Special(SpecialRegister::DestIndex) => self.registers.di = value,
}
let is_now = self.get_register(&register_for_print);
format!(
"{}:{}->{}",
register_for_print,
Self::display_small(was),
Self::display_small(is_now)
)
if was != is_now {
format!(
"{}:{}->{}",
register_for_print,
Self::display_small(was),
Self::display_small(is_now)
)
} else {
"".to_owned()
}
}
fn set_segment(&mut self, r: SegmentRegister, value: u16) -> String {
@@ -352,18 +356,18 @@ impl Computer {
}
fn get_memory_word(&self, index: usize) -> u16 {
self.memory[index] as u16 * 256 + self.memory[index + 1] as u16
self.memory[index] as u16 + self.memory[index + 1] as u16 * 256
}
fn set_memory_byte(&mut self, index: usize, value: u8) -> String {
self.memory[index] = value;
"todo".to_owned()
"".to_owned()
}
fn set_memory_word(&mut self, index: usize, value: u16) -> String {
self.memory[index] = (value % 256) as u8;
self.memory[index + 1] = (value / 256) as u8;
"todo".to_owned()
"".to_owned()
}
fn resolve_eaddr(&self, a: &EffectiveAddress) -> usize {
@@ -507,7 +511,7 @@ impl Computer {
MoveInstruction::ImmediateToMemory(mov) => match mov {
ImmediateToMemory::Byte(addr, value) => {
let dest = self.resolve_eaddr(addr);
self.set_memory_byte(dest, *value)
self.set_memory_word(dest, *value as u16)
}
ImmediateToMemory::Word(addr, value) => {
let dest = self.resolve_eaddr(addr);
@@ -570,7 +574,8 @@ impl Computer {
let ip_desc = match old_ip {
None => "".to_owned(),
Some(old_ip) => format!(
" ip:{}->{}",
"{}ip:{}->{}",
if description.is_empty() { "" } else { " " },
Self::display_small(old_ip),
Self::display_small(self.program_counter)
),
@@ -723,7 +728,20 @@ impl Computer {
(format!("{}", instr.dest), current_value, new_value, flags)
}
ArithmeticInstructionSelect::RegisterToMemory(_) => todo!(),
ArithmeticInstructionSelect::MemoryToRegister(_) => todo!(),
ArithmeticInstructionSelect::MemoryToRegister(instr) => {
let current_value = self.get_register(&instr.dest);
let incoming_value = if instr.dest.is_wide() {
self.get_memory_word(self.resolve_eaddr(&instr.source))
} else {
self.get_memory_byte(self.resolve_eaddr(&instr.source)) as u16
};
let (new_value, flags) =
Self::apply(instruction.op, current_value, incoming_value, false);
if flags.should_write {
self.set_register(&instr.dest, new_value);
}
(format!("{}", instr.dest), current_value, new_value, flags)
}
ArithmeticInstructionSelect::ImmediateToRegisterByte(register, value, is_extended) => {
let current_value = self.get_register(register);
let (new_value, flags) = if *is_extended {
@@ -800,7 +818,7 @@ impl Computer {
)
}
};
let result_desc = if flags.should_write {
let result_desc = if flags.should_write && old_value != new_value {
format!(
" {}:{}->{}",
source,
@@ -855,20 +873,26 @@ impl Computer {
Jump::Loop => {
let reg = Register::General(GeneralRegister::C, RegisterSubset::All);
let prev = self.get_register(&reg);
self.set_register(&reg, prev - 1);
let new_value = if prev == 0 {
self.set_register(&reg, u16::MAX);
u16::MAX
} else {
self.set_register(&reg, prev - 1);
prev - 1
};
reg_desc.push_str(&format!(
" cx:{}->{}",
" ; cx:{}->{}",
Self::display_small(prev),
Self::display_small(prev - 1)
Self::display_small(new_value)
));
prev == 1
prev != 1
}
Jump::Loopz => {
let reg = Register::General(GeneralRegister::C, RegisterSubset::All);
let prev = self.get_register(&reg);
self.set_register(&reg, prev - 1);
reg_desc.push_str(&format!(
" cx:{}->{}",
" ; cx:{}->{}",
Self::display_small(prev),
Self::display_small(prev - 1)
));

View File

@@ -18,8 +18,8 @@ where
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WithOffset::Basic(t) => f.write_fmt(format_args!("{}", t)),
WithOffset::WithU8(t, offset) => f.write_fmt(format_args!("[{} + {}]", t, offset)),
WithOffset::WithU16(t, offset) => f.write_fmt(format_args!("[{} + {}]", t, offset)),
WithOffset::WithU8(t, offset) => f.write_fmt(format_args!("[{}+{}]", t, offset)),
WithOffset::WithU16(t, offset) => f.write_fmt(format_args!("[{}+{}]", t, offset)),
}
}
}
@@ -45,33 +45,59 @@ impl Display for EffectiveAddress {
match self {
EffectiveAddress::Sum(w) => match w {
WithOffset::Basic((base, source_dest)) => {
f.write_fmt(format_args!("[{} + {}i]", base, source_dest))
f.write_fmt(format_args!("[{}+{}i]", base, source_dest))
}
WithOffset::WithU8((base, source_dest), offset) => {
f.write_fmt(format_args!("[{} + {}i + {}]", base, source_dest, offset))
if *offset == 0 {
f.write_fmt(format_args!("[{}+{}i]", base, source_dest))
} else {
f.write_fmt(format_args!("[{}+{}i+{}]", base, source_dest, offset))
}
}
WithOffset::WithU16((base, source_dest), offset) => {
f.write_fmt(format_args!("[{} + {}i + {}]", base, source_dest, offset))
if *offset == 0 {
f.write_fmt(format_args!("[{}+{}i]", base, source_dest))
} else {
f.write_fmt(format_args!("[{}+{}i+{}]", base, source_dest, offset))
}
}
},
EffectiveAddress::SpecifiedIn(WithOffset::Basic(source_dest)) => {
f.write_fmt(format_args!("[{}i]", source_dest))
}
EffectiveAddress::SpecifiedIn(WithOffset::WithU8(source_dest, offset)) => {
f.write_fmt(format_args!("[{}i + {}]", source_dest, offset))
if *offset == 0 {
f.write_fmt(format_args!("[{}i]", source_dest))
} else {
f.write_fmt(format_args!("[{}i+{}]", source_dest, offset))
}
}
EffectiveAddress::SpecifiedIn(WithOffset::WithU16(source_dest, offset)) => {
f.write_fmt(format_args!("[{}i + {}]", source_dest, offset))
if *offset == 0 {
f.write_fmt(format_args!("[{}i]", source_dest))
} else {
f.write_fmt(format_args!("[{}i+{}]", source_dest, offset))
}
}
EffectiveAddress::Bx(offset) => match offset {
WithOffset::Basic(()) => f.write_str("bx"),
WithOffset::WithU8((), offset) => f.write_fmt(format_args!("[bx + {}]", offset)),
WithOffset::WithU16((), offset) => f.write_fmt(format_args!("[bx + {}]", offset)),
WithOffset::WithU8((), offset) => f.write_fmt(format_args!("[bx+{}]", offset)),
WithOffset::WithU16((), offset) => f.write_fmt(format_args!("[bx+{}]", offset)),
},
EffectiveAddress::Direct(location) => f.write_fmt(format_args!("[{}]", location)),
EffectiveAddress::BasePointer(offset) => f.write_fmt(format_args!("[bp + {}]", offset)),
EffectiveAddress::Direct(location) => f.write_fmt(format_args!("[+{}]", location)),
EffectiveAddress::BasePointer(offset) => {
if *offset == 0 {
f.write_str("[bp]")
} else {
f.write_fmt(format_args!("[bp+{}]", offset))
}
}
EffectiveAddress::BasePointerWide(offset) => {
f.write_fmt(format_args!("[bp + {}]", offset))
if *offset == 0 {
f.write_str("[bp]")
} else {
f.write_fmt(format_args!("[bp+{}]", offset))
}
}
}
}

View File

@@ -391,9 +391,16 @@ impl Display for MoveInstruction {
MoveInstruction::RegRegMove(mov) => {
f.write_fmt(format_args!("mov {}, {}", mov.dest, mov.source))
}
MoveInstruction::RegMemMove(mov) => {
f.write_fmt(format_args!("mov {}, {}", mov.dest, mov.source))
}
MoveInstruction::RegMemMove(mov) => f.write_fmt(format_args!(
"mov {}{}, {}",
if mov.source.is_wide() {
"word "
} else {
"byte "
},
mov.dest,
mov.source
)),
MoveInstruction::MemRegMove(mov) => {
f.write_fmt(format_args!("mov {}, {}", mov.dest, mov.source))
}
@@ -401,10 +408,10 @@ impl Display for MoveInstruction {
f.write_fmt(format_args!("mov {}", instruction))
}
MoveInstruction::ImmediateToMemory(ImmediateToMemory::Byte(address, value)) => {
f.write_fmt(format_args!("mov {}, {}", address, value))
f.write_fmt(format_args!("mov byte {}, {}", address, value))
}
MoveInstruction::ImmediateToMemory(ImmediateToMemory::Word(address, value)) => {
f.write_fmt(format_args!("mov {}, {}", address, value))
f.write_fmt(format_args!("mov word {}, {}", address, value))
}
MoveInstruction::MemoryToAccumulator(instruction) => f.write_fmt(format_args!(
"mov a{}, [{}]",

View File

@@ -64,10 +64,10 @@ mod test_computer {
trace.push("".to_owned());
assert_eq!(
trace,
clean_trace(expected_trace).lines().collect::<Vec<_>>()
)
let cleaned = clean_trace(expected_trace);
let expected = cleaned.lines().collect::<Vec<_>>();
assert_eq!(trace, expected)
}
#[test]
@@ -145,7 +145,6 @@ mod test_computer {
test_sim(input_bytecode, expected_trace, true)
}
/*
#[test]
fn test_memory_mov() {
let input_bytecode =
@@ -194,5 +193,4 @@ mod test_computer {
);
test_sim(input_bytecode, expected_trace, true)
}
*/
}

View File

@@ -243,6 +243,26 @@ mod test_program {
test_disassembler(asm, bytecode)
}
/*
#[test]
fn test_completionist_parser() {
let input_asm =
include_str!("../../computer_enhance/perfaware/part1/listing_0042_completionist_decode.asm");
let input_bytecode =
include_bytes!("../../computer_enhance/perfaware/part1/listing_0042_completionist_decode");
test_parser(input_asm, input_bytecode)
}
#[test]
fn test_completionist_disassembler() {
let bytecode =
include_bytes!("../../computer_enhance/perfaware/part1/listing_0042_completionist_decode");
let asm =
include_str!("../../computer_enhance/perfaware/part1/listing_0042_completionist_decode.asm");
test_disassembler(asm, bytecode)
}
*/
#[test]
fn test_immediate_movs_parser() {
let input_asm =

View File

@@ -1,6 +1,7 @@
use std::{fs, path::Path};
use clap::Parser;
use sim_8086::computer::Computer;
use sim_8086::instruction::Instruction;
use sim_8086::program::Program;
@@ -17,6 +18,8 @@ struct Args {
compiled_path: std::path::PathBuf,
#[arg(value_name = "ASM_PATH")]
asm_path: std::path::PathBuf,
#[arg()]
verify_consistency: Option<bool>,
}
fn program_equal_ignoring_labels<A, B>(
@@ -54,12 +57,8 @@ where
true
}
fn main() {
let args = Args::parse();
let expected_bytecode = load_machine_code(args.compiled_path);
let asm = fs::read_to_string(args.asm_path).unwrap();
let (remaining, compiled) = sim_8086::assembly::program(&asm).unwrap();
fn verify_consistency(pre_compiled: &Vec<u8>, asm: &str) {
let (remaining, compiled) = sim_8086::assembly::program(asm).unwrap();
if !remaining.is_empty() {
println!(
@@ -70,15 +69,25 @@ fn main() {
}
let actual_bytecode = compiled.to_bytes();
if expected_bytecode != actual_bytecode {
if pre_compiled.len() != actual_bytecode.len() {
println!(
"Expected: {:?}\nActual: {:?}",
expected_bytecode, actual_bytecode
pre_compiled, actual_bytecode
);
std::process::exit(1)
}
let disassembled = Program::of_bytes(expected_bytecode.iter().cloned());
for (pre_compiled, actual) in pre_compiled.iter().zip(actual_bytecode.iter()) {
if *pre_compiled != *actual {
println!(
"Expected: {:?}\nActual: {:?}",
pre_compiled, actual_bytecode
);
std::process::exit(1)
}
}
let disassembled = Program::of_bytes(pre_compiled.iter().cloned());
if disassembled != compiled {
println!("Disassembled and compiled versions do not produce the same bytes. From disassembly:\n{}\nFrom assembling the input asm:\n{}", disassembled, compiled);
@@ -94,3 +103,45 @@ fn main() {
"Our assembly was equal to the reference, and it disassembled back to the same structure."
)
}
fn run(bytecode: Vec<u8>) -> Computer {
let program = Program::of_bytes(bytecode.iter().cloned());
let mut computer = Computer::new();
let mut counter = 0usize;
let mut instructions = vec![None; bytecode.len()];
for instruction in program.instructions.iter() {
instructions[counter] = Some(instruction);
counter += instruction.length() as usize;
}
let end_of_instructions = counter;
loop {
let counter = computer.get_program_counter() as usize;
if counter >= end_of_instructions {
break;
}
match instructions[counter] {
None => {
panic!("landed in middle of instruction")
}
Some(instruction) => {
computer.step(instruction, false);
}
}
}
computer
}
fn main() {
let args = Args::parse();
let expected_bytecode = load_machine_code(args.compiled_path);
let asm = fs::read_to_string(args.asm_path).unwrap();
if let Some(true) = args.verify_consistency {
verify_consistency(&expected_bytecode, &asm);
}
let _computer = run(expected_bytecode);
}