From a1676b7062994993fc8ba1175dbf2a22ca8e1a46 Mon Sep 17 00:00:00 2001 From: Patrick Stevens Date: Mon, 8 May 2023 20:07:00 +0100 Subject: [PATCH] Update submodule (#17) --- .gitignore | 1 + computer_enhance | 2 +- sim_8086/src/assembly.rs | 160 ++++++++-- sim_8086/src/boolean_instruction.rs | 166 +++++++++++ sim_8086/src/computer.rs | 446 +++++++++++++++++----------- sim_8086/src/effective_address.rs | 3 + sim_8086/src/inc_instruction.rs | 33 ++ sim_8086/src/instruction.rs | 53 +++- sim_8086/src/lib.rs | 2 + sim_8086/src/program.rs | 4 +- sim_8086/tests/test_computer.rs | 6 +- sim_8086/tests/test_program.rs | 167 ++++++++++- 12 files changed, 832 insertions(+), 211 deletions(-) create mode 100644 sim_8086/src/boolean_instruction.rs create mode 100644 sim_8086/src/inc_instruction.rs diff --git a/.gitignore b/.gitignore index ca319f7..3864e7b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target/ *.iml .vscode/ .profile* +.DS_Store diff --git a/computer_enhance b/computer_enhance index 784fcc0..727d993 160000 --- a/computer_enhance +++ b/computer_enhance @@ -1 +1 @@ -Subproject commit 784fcc0fe4fa8e93c49dab30abbd88748d608c39 +Subproject commit 727d9936dd00e39fbb6a504fc3388adbc6560e0c diff --git a/sim_8086/src/assembly.rs b/sim_8086/src/assembly.rs index 10deb37..ac8bca6 100644 --- a/sim_8086/src/assembly.rs +++ b/sim_8086/src/assembly.rs @@ -11,6 +11,10 @@ use nom::{ IResult, }; +use crate::boolean_instruction::{ + BooleanInstruction, BooleanInstructionDestination, BooleanInstructionType, RegRegBoolean, +}; +use crate::inc_instruction::IncInstruction; use crate::{ arithmetic_expression::{ArithmeticExpression, Token}, arithmetic_instruction::{ @@ -159,7 +163,7 @@ fn register(input: &str) -> IResult<&str, Register> { fn reg_reg_move_instruction(input: &str) -> IResult<&str, RegRegMove> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple((terminated(register, argument_sep), register)), ), |(dest, source)| Ok::<_, ()>(RegRegMove { dest, source }), @@ -421,7 +425,7 @@ fn segment_register(input: &str) -> IResult<&str, SegmentRegister> { fn reg_to_seg_move_instruction(input: &str) -> IResult<&str, RegisterToSegment> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple((terminated(segment_register, ws(char(','))), register)), ), |(dest, source)| Ok::<_, ()>(RegisterToSegment { dest, source }), @@ -431,7 +435,7 @@ fn reg_to_seg_move_instruction(input: &str) -> IResult<&str, RegisterToSegment> fn mem_to_seg_move_instruction(input: &str) -> IResult<&str, MemoryToSegment> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple(( terminated(segment_register, ws(char(','))), effective_address, @@ -447,7 +451,7 @@ fn mem_to_seg_move_instruction(input: &str) -> IResult<&str, MemoryToSegment> { fn seg_to_mem_move_instruction(input: &str) -> IResult<&str, SegmentToMemory> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple(( terminated(effective_address, ws(char(','))), segment_register, @@ -463,7 +467,7 @@ fn seg_to_mem_move_instruction(input: &str) -> IResult<&str, SegmentToMemory> { fn seg_to_reg_move_instruction(input: &str) -> IResult<&str, SegmentToRegister> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple((terminated(register, ws(char(','))), segment_register)), ), |(dest, source)| Ok::<_, ()>(SegmentToRegister { dest, source }), @@ -473,7 +477,7 @@ fn seg_to_reg_move_instruction(input: &str) -> IResult<&str, SegmentToRegister> fn reg_mem_move_instruction(input: &str) -> IResult<&str, RegMemMove> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple((terminated(effective_address, argument_sep), register)), ), |((tag, address), register)| match (tag, register.is_wide()) { @@ -489,7 +493,7 @@ fn reg_mem_move_instruction(input: &str) -> IResult<&str, RegMemMove> { fn mem_reg_move_instruction(input: &str) -> IResult<&str, MemRegMove> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple((terminated(register, argument_sep), effective_address)), ), |(register, (tag, address))| match (tag, register.is_wide()) { @@ -519,7 +523,7 @@ fn immediate_byte(input: &str) -> IResult<&str, (Register, u8)> { fn immediate_to_register_instruction(input: &str) -> IResult<&str, ImmediateToRegister> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), alt(( map_res(immediate_wide, |(register, x)| { Ok::<_, ()>((register, Err(x))) @@ -547,7 +551,7 @@ fn immediate_to_register_instruction(input: &str) -> IResult<&str, ImmediateToRe fn immediate_to_memory_instruction(input: &str) -> IResult<&str, ImmediateToMemory> { map_res( tuple(( - terminated(preceded(tag("mov "), effective_address), argument_sep), + terminated(preceded(ws(tag("mov ")), effective_address), argument_sep), alt(( map_res(literal_u8, |x| Ok::<_, ()>(Ok(x))), map_res(literal_u16, |x| Ok::<_, ()>(Err(x))), @@ -573,7 +577,7 @@ fn immediate_to_memory_instruction(input: &str) -> IResult<&str, ImmediateToMemo fn memory_to_accumulator_instruction(input: &str) -> IResult<&str, MemoryToAccumulator> { map_res( preceded( - tag("mov a"), + preceded(multispace0, tag("mov a")), tuple(( terminated(alt((char('h'), char('x'))), argument_sep), bracketed(literal_u16), @@ -593,7 +597,7 @@ fn memory_to_accumulator_instruction(input: &str) -> IResult<&str, MemoryToAccum fn accumulator_to_memory_instruction(input: &str) -> IResult<&str, AccumulatorToMemory> { map_res( preceded( - tag("mov "), + ws(tag("mov ")), tuple(( terminated(bracketed(literal_u16), tuple((argument_sep, char('a')))), alt((char('h'), char('x'))), @@ -610,6 +614,51 @@ fn accumulator_to_memory_instruction(input: &str) -> IResult<&str, AccumulatorTo )(input) } +fn boolean_op(input: &str) -> IResult<&str, BooleanInstructionType> { + alt(( + map_res(tag("test"), |_| Ok::<_, ()>(BooleanInstructionType::Test)), + map_res(tag("and"), |_| Ok::<_, ()>(BooleanInstructionType::And)), + map_res(tag("or"), |_| Ok::<_, ()>(BooleanInstructionType::Or)), + map_res(tag("xor"), |_| Ok::<_, ()>(BooleanInstructionType::Xor)), + ))(input) +} + +fn boolean_select(input: &str) -> IResult<&str, BooleanInstructionDestination> { + //alt(( + map_res( + tuple((terminated(wide_register, argument_sep), wide_register)), + |(dest, source)| { + Ok::<_, ()>(BooleanInstructionDestination::RegReg(RegRegBoolean { + dest, + source, + })) + }, + )(input) + //map_res( + // tuple((terminated(wide_register, argument_sep), literal_u16)), + // |(dest, immediate)| { + // Ok::<_, ()>(BooleanInstructionDestination::ImmediateToReg( + // ImmediateToReg::Wide(dest, immediate), + // )) + // }, + //), + //map_res( + // tuple((terminated(byte_register, argument_sep), literal_u8)), + // |(dest, immediate)| { + // Ok::<_, ()>(BooleanInstructionDestination::ImmediateToReg( + // ImmediateToReg::Narrow(dest, immediate), + // )) + // }, + //), +} + +fn boolean_instruction(input: &str) -> IResult<&str, BooleanInstruction> { + map_res( + tuple((terminated(boolean_op, char(' ')), ws(boolean_select))), + |(selection, dest)| Ok::<_, ()>(BooleanInstruction { dest, selection }), + )(input) +} + fn arithmetic_op(input: &str) -> IResult<&str, ArithmeticOperation> { alt(( map_res(tag("add"), |_| Ok::<_, ()>(ArithmeticOperation::Add)), @@ -727,7 +776,7 @@ fn arithmetic_select(input: &str) -> IResult<&str, ArithmeticInstructionSelect> fn arithmetic_instruction(input: &str) -> IResult<&str, ArithmeticInstruction> { map_res( - tuple((terminated(arithmetic_op, char(' ')), arithmetic_select)), + tuple((ws(terminated(arithmetic_op, char(' '))), arithmetic_select)), |(op, instruction)| Ok::<_, ()>(ArithmeticInstruction { op, instruction }), )(input) } @@ -849,12 +898,29 @@ fn move_instruction(input: &str) -> IResult<&str, MoveInstruction> { ))(input) } +fn inc_instruction(input: &str) -> IResult<&str, IncInstruction> { + preceded( + ws(tag("inc ")), + //alt(( + //map_res(effective_address, |(_, addr)| { + // Ok::<_, ()>(IncInstruction::Memory(addr)) + //}), + map_res(register, |reg| Ok::<_, ()>(IncInstruction::Register(reg))), + //)), + )(input) +} + fn instruction(input: &str) -> IResult<&str, Instruction<&str>> { alt(( map_res(move_instruction, |v| Ok::<_, ()>(Instruction::Move(v))), + map_res(boolean_instruction, |v| { + Ok::<_, ()>(Instruction::Boolean(v)) + }), map_res(arithmetic_instruction, |v| { Ok::<_, ()>(Instruction::Arithmetic(v)) }), + map_res(inc_instruction, |v| Ok::<_, ()>(Instruction::Inc(v))), + map_res(tag("ret"), |_| Ok::<_, ()>(Instruction::Ret)), map_res(jump, |(v, label)| Ok::<_, ()>(Instruction::Jump(v, label))), map_res(label, |v| { Ok::<_, ()>(Instruction::Trivia(TriviaInstruction::Label(v))) @@ -868,12 +934,9 @@ pub fn program(input: &str) -> IResult<&str, Program>, &st many0(line_end), separated_pair( bits, - many0(line_end), + many1(line_end), many0(alt(( - map_res( - terminated(preceded(space0, instruction), preceded(space0, line_end)), - |i| Ok::<_, ()>(Some(i)), - ), + map_res(preceded(space0, instruction), |i| Ok::<_, ()>(Some(i))), map_res(preceded(space0, line_end), |_| Ok::<_, ()>(None)), ))), ), @@ -890,6 +953,11 @@ pub fn program(input: &str) -> IResult<&str, Program>, &st #[cfg(test)] mod test_assembly { + use crate::assembly::program; + use crate::boolean_instruction::{ + BooleanInstruction, BooleanInstructionDestination, BooleanInstructionType, RegRegBoolean, + }; + use crate::register::SpecialRegister; use crate::{ arithmetic_instruction::{ ArithmeticInstruction, ArithmeticInstructionSelect, ArithmeticOperation, @@ -897,7 +965,7 @@ mod test_assembly { assembly::instruction, effective_address::{EffectiveAddress, WithOffset}, instruction::Instruction, - move_instruction::{ImmediateToMemory, MoveInstruction}, + move_instruction::{ImmediateToMemory, MemoryToAccumulator, MoveInstruction}, register::{GeneralRegister, Register, RegisterSubset}, }; @@ -935,6 +1003,42 @@ mod test_assembly { ) } + #[test] + fn mov_acc_parse() { + let (remaining, parsed) = instruction("mov ax, [16]").unwrap(); + assert_eq!(remaining, ""); + assert_eq!( + parsed, + Instruction::Move(MoveInstruction::MemoryToAccumulator(MemoryToAccumulator { + address: 16, + is_wide: true + })) + ) + } + + #[test] + fn mov_acc_parse_program() { + let (remaining, parsed) = program("bits 16\nmov ax, [2555]\nmov ax, [16]").unwrap(); + assert_eq!(remaining, ""); + assert_eq!(parsed.bits, 16); + let parsed = parsed.instructions; + assert_eq!(parsed.len(), 2); + assert_eq!( + parsed[0].clone(), + Instruction::Move(MoveInstruction::MemoryToAccumulator(MemoryToAccumulator { + address: 2555, + is_wide: true + })) + ); + assert_eq!( + parsed[1].clone(), + Instruction::Move(MoveInstruction::MemoryToAccumulator(MemoryToAccumulator { + address: 16, + is_wide: true + })) + ); + } + #[test] fn mov_parse() { let (remaining, parsed) = instruction("mov byte [bx + 61*4 + 1], 255").unwrap(); @@ -964,4 +1068,24 @@ mod test_assembly { }) ) } + + #[test] + fn test_test_reg_reg() { + let parsed = program("bits 16\ntest di, di\r\n"); + let (remaining, parsed) = parsed.unwrap(); + assert_eq!(remaining, ""); + let parsed = parsed.instructions; + assert_eq!(parsed.len(), 1); + let parsed = &parsed[0]; + assert_eq!( + parsed.clone(), + Instruction::Boolean(BooleanInstruction { + selection: BooleanInstructionType::Test, + dest: BooleanInstructionDestination::RegReg(RegRegBoolean { + dest: Register::Special(SpecialRegister::DestIndex), + source: Register::Special(SpecialRegister::DestIndex), + }), + }) + ) + } } diff --git a/sim_8086/src/boolean_instruction.rs b/sim_8086/src/boolean_instruction.rs new file mode 100644 index 0000000..8104989 --- /dev/null +++ b/sim_8086/src/boolean_instruction.rs @@ -0,0 +1,166 @@ +use crate::effective_address::EffectiveAddress; +use crate::register::Register; +use arbitrary::Arbitrary; +use std::fmt::{Display, Formatter}; + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub enum BooleanInstructionType { + Test, + And, + Or, + Xor, +} + +impl Display for BooleanInstructionType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + BooleanInstructionType::Test => "test", + BooleanInstructionType::And => "and", + BooleanInstructionType::Or => "or", + BooleanInstructionType::Xor => "xor", + }) + } +} + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub struct RegRegBoolean { + pub dest: Register, + pub source: Register, +} + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub enum ImmediateToMem { + Wide(EffectiveAddress, u16), + Narrow(EffectiveAddress, u8), +} + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub enum ImmediateToAcc { + Wide(u16), + Narrow(u8), +} + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub enum BooleanInstructionDestination { + RegReg(RegRegBoolean), + ImmediateToAcc(ImmediateToAcc), +} + +impl Display for BooleanInstructionDestination { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + BooleanInstructionDestination::RegReg(inst) => { + f.write_fmt(format_args!("{}, {}", inst.dest, inst.source)) + } + BooleanInstructionDestination::ImmediateToAcc(inst) => match inst { + ImmediateToAcc::Wide(wide) => f.write_fmt(format_args!("ax, {}", wide)), + ImmediateToAcc::Narrow(narrow) => f.write_fmt(format_args!("al, {}", narrow)), + }, + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub struct BooleanInstruction { + pub selection: BooleanInstructionType, + pub dest: BooleanInstructionDestination, +} + +impl Display for BooleanInstruction { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{} {}", self.selection, self.dest)) + } +} + +impl BooleanInstruction { + pub fn to_bytes(&self) -> Vec { + match &self.dest { + /* + BooleanInstructionDestination::ImmediateToMem(immediate) => { + let mut result = Vec::with_capacity(2); + let (opcode, reg) = match self.selection { + BooleanInstructionType::Test => (0b11110111, 0), + BooleanInstructionType::And => (0b10000000, 0b100), + BooleanInstructionType::Or => (0b10000000, 0b001), + BooleanInstructionType::Xor => { + todo!() + // (0b00110100, todo!()) + } + }; + + match immediate { + ImmediateToMem::Wide(dest, data) => { + result.push(opcode + 1); + dest.push(reg, &mut result); + result.push((data % 256) as u8); + result.push((data / 256) as u8); + } + ImmediateToMem::Narrow(dest, data) => { + result.push(opcode); + dest.push(reg, &mut result); + result.push(*data); + } + } + + result + } + */ + BooleanInstructionDestination::RegReg(reg_reg) => { + let mut result = Vec::with_capacity(2); + let opcode = match self.selection { + BooleanInstructionType::And => 0b00100000, + BooleanInstructionType::Test => 0b10000100, + BooleanInstructionType::Or => 0b00001000, + BooleanInstructionType::Xor => 0b00110000, + }; + + let (reg, is_wide) = reg_reg.dest.to_id(); + let mode = 3; + let (rm, is_wide_2) = reg_reg.source.to_id(); + if is_wide != is_wide_2 { + panic!("conflicting wideness") + } + if is_wide { + result.push(opcode + 1); + } else { + result.push(opcode); + } + result.push(mode * 64 + reg * 8 + rm); + + result + } + BooleanInstructionDestination::ImmediateToAcc(data) => { + let mut result = Vec::with_capacity(2); + let opcode = match self.selection { + BooleanInstructionType::Test => 0b10101000, + BooleanInstructionType::And => 0b00100100, + BooleanInstructionType::Or => 0b00001100, + BooleanInstructionType::Xor => 0b00110100, + }; + match data { + ImmediateToAcc::Wide(data) => { + result.push(opcode + 1); + result.push((data % 256) as u8); + result.push((data / 256) as u8); + } + ImmediateToAcc::Narrow(data) => { + result.push(opcode); + result.push(*data); + } + } + + result + } + } + } + + pub fn length(&self) -> u8 { + match &self.dest { + BooleanInstructionDestination::ImmediateToAcc(data) => match data { + ImmediateToAcc::Wide(_) => 3, + ImmediateToAcc::Narrow(_) => 2, + }, + BooleanInstructionDestination::RegReg(_) => 2, + } + } +} diff --git a/sim_8086/src/computer.rs b/sim_8086/src/computer.rs index f0973c6..02a5eeb 100644 --- a/sim_8086/src/computer.rs +++ b/sim_8086/src/computer.rs @@ -1,5 +1,7 @@ use std::fmt::Display; +use crate::boolean_instruction::BooleanInstruction; +use crate::inc_instruction::IncInstruction; use crate::{ arithmetic_instruction::{ ArithmeticInstruction, ArithmeticInstructionSelect, ArithmeticOperation, @@ -14,6 +16,23 @@ use crate::{ }, }; +fn display_big(u: u16) -> String { + if u == 0 { + "0x0".to_owned() + } else { + format!("{:#06x}", u) + } +} + +fn display_small(u: u16) -> String { + if u == 0 { + "0x0".to_owned() + } else { + format!("{:#x}", u) + } +} + +#[derive(Clone, Eq, PartialEq)] pub struct Registers { a: u16, b: u16, @@ -29,6 +48,99 @@ pub struct Registers { ds: u16, } +impl Registers { + pub fn diff(&self, old: &Registers) -> String { + let mut result = Vec::new(); + + if self.a != old.a { + result.push(format!( + "ax:{}->{}", + display_small(old.a), + display_small(self.a) + )); + } + if self.b != old.b { + result.push(format!( + "bx:{}->{}", + display_small(old.b), + display_small(self.b) + )); + } + if self.c != old.c { + result.push(format!( + "cx:{}->{}", + display_small(old.c), + display_small(self.c) + )); + } + if self.d != old.d { + result.push(format!( + "dx:{}->{}", + display_small(old.d), + display_small(self.d) + )); + } + if self.si != old.si { + result.push(format!( + "si:{}->{}", + display_small(old.si), + display_small(self.si) + )); + } + if self.di != old.di { + result.push(format!( + "di:{}->{}", + display_small(old.di), + display_small(self.di) + )); + } + if self.sp != old.sp { + result.push(format!( + "sp:{}->{}", + display_small(old.sp), + display_small(self.sp) + )); + } + if self.bp != old.bp { + result.push(format!( + "bp:{}->{}", + display_small(old.bp), + display_small(self.bp) + )); + } + if self.ss != old.ss { + result.push(format!( + "ss:{}->{}", + display_small(old.ss), + display_small(self.ss) + )); + } + if self.cs != old.cs { + result.push(format!( + "cs:{}->{}", + display_small(old.cs), + display_small(self.cs) + )); + } + if self.es != old.es { + result.push(format!( + "es:{}->{}", + display_small(old.es), + display_small(self.es) + )); + } + if self.ds != old.ds { + result.push(format!( + "ds:{}->{}", + display_small(old.ds), + display_small(self.ds) + )); + } + + result.join(" ; ") + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ControlFlag { Trap, @@ -233,22 +345,6 @@ impl Computer { } } - fn display_big(u: u16) -> String { - if u == 0 { - "0x0".to_owned() - } else { - format!("{:#06x}", u) - } - } - - fn display_small(u: u16) -> String { - if u == 0 { - "0x0".to_owned() - } else { - format!("{:#x}", u) - } - } - fn set_register(&mut self, r: &Register, value: u16) -> String { let register_for_print = match r { Register::General(x, _) => Register::General(x.clone(), RegisterSubset::All), @@ -326,8 +422,8 @@ impl Computer { format!( "{}:{}->{}", register_for_print, - Self::display_small(was), - Self::display_small(is_now) + display_small(was), + display_small(is_now) ) } else { "".to_owned() @@ -343,12 +439,7 @@ impl Computer { SegmentRegister::Extra => self.registers.es = value, } let is_now = self.get_segment(r); - format!( - "{}:{}->{}", - r, - Self::display_small(was), - Self::display_small(is_now) - ) + format!("{}:{}->{}", r, display_small(was), display_small(is_now)) } fn get_memory_byte(&self, index: usize) -> u8 { @@ -370,87 +461,51 @@ impl Computer { "".to_owned() } + fn get_base_offset(&self, base: &Base) -> u16 { + match base { + Base::Bp => self.get_register(&Register::Special(SpecialRegister::BasePointer)), + Base::Bx => { + self.get_register(&Register::General(GeneralRegister::B, RegisterSubset::All)) + } + } + } + + fn get_source_offset(&self, source_dest: &SourceDest) -> u16 { + match source_dest { + SourceDest::Source => { + self.get_register(&Register::Special(SpecialRegister::SourceIndex)) + } + SourceDest::Dest => self.get_register(&Register::Special(SpecialRegister::DestIndex)), + } + } + fn resolve_eaddr(&self, a: &EffectiveAddress) -> usize { match a { EffectiveAddress::Sum(WithOffset::Basic((base, source_dest))) => { - let base_offset = match base { - Base::Bp => self.get_register(&Register::Special(SpecialRegister::BasePointer)), - Base::Bx => self - .get_register(&Register::General(GeneralRegister::B, RegisterSubset::All)), - }; - let source_offset = match source_dest { - SourceDest::Source => { - self.get_register(&Register::Special(SpecialRegister::SourceIndex)) - } - SourceDest::Dest => { - self.get_register(&Register::Special(SpecialRegister::DestIndex)) - } - }; + let base_offset = self.get_base_offset(base); + let source_offset = self.get_source_offset(source_dest); base_offset as usize + source_offset as usize } EffectiveAddress::Sum(WithOffset::WithU8((base, source_dest), addend)) => { - let base_offset = match base { - Base::Bp => self.get_register(&Register::Special(SpecialRegister::BasePointer)), - Base::Bx => self - .get_register(&Register::General(GeneralRegister::B, RegisterSubset::All)), - }; - let source_offset = match source_dest { - SourceDest::Source => { - self.get_register(&Register::Special(SpecialRegister::SourceIndex)) - } - SourceDest::Dest => { - self.get_register(&Register::Special(SpecialRegister::DestIndex)) - } - }; + let base_offset = self.get_base_offset(base); + let source_offset = self.get_source_offset(source_dest); base_offset as usize + source_offset as usize + *addend as usize } EffectiveAddress::Sum(WithOffset::WithU16((base, source_dest), addend)) => { - let base_offset = match base { - Base::Bp => self.get_register(&Register::Special(SpecialRegister::BasePointer)), - Base::Bx => self - .get_register(&Register::General(GeneralRegister::B, RegisterSubset::All)), - }; - let source_offset = match source_dest { - SourceDest::Source => { - self.get_register(&Register::Special(SpecialRegister::SourceIndex)) - } - SourceDest::Dest => { - self.get_register(&Register::Special(SpecialRegister::DestIndex)) - } - }; + let base_offset = self.get_base_offset(base); + let source_offset = self.get_source_offset(source_dest); base_offset as usize + source_offset as usize + *addend as usize } EffectiveAddress::SpecifiedIn(WithOffset::Basic(source_dest)) => { - let source_offset = match source_dest { - SourceDest::Source => { - self.get_register(&Register::Special(SpecialRegister::SourceIndex)) - } - SourceDest::Dest => { - self.get_register(&Register::Special(SpecialRegister::DestIndex)) - } - }; + let source_offset = self.get_source_offset(source_dest); source_offset as usize } EffectiveAddress::SpecifiedIn(WithOffset::WithU8(source_dest, offset)) => { - let source_offset = match source_dest { - SourceDest::Source => { - self.get_register(&Register::Special(SpecialRegister::SourceIndex)) - } - SourceDest::Dest => { - self.get_register(&Register::Special(SpecialRegister::DestIndex)) - } - }; + let source_offset = self.get_source_offset(source_dest); source_offset as usize + *offset as usize } EffectiveAddress::SpecifiedIn(WithOffset::WithU16(source_dest, offset)) => { - let source_offset = match source_dest { - SourceDest::Source => { - self.get_register(&Register::Special(SpecialRegister::SourceIndex)) - } - SourceDest::Dest => { - self.get_register(&Register::Special(SpecialRegister::DestIndex)) - } - }; + let source_offset = self.get_source_offset(source_dest); source_offset as usize + *offset as usize } EffectiveAddress::Bx(WithOffset::Basic(())) => { @@ -480,7 +535,7 @@ impl Computer { } } - fn step_mov(&mut self, instruction: &MoveInstruction, old_ip: Option) -> String { + fn step_mov(&mut self, instruction: &MoveInstruction) -> String { let preamble = format!("{}", instruction); let description = match &instruction { MoveInstruction::RegRegMove(mov) => { @@ -571,16 +626,12 @@ impl Computer { self.set_segment(mov.dest, value) } }; - let ip_desc = match old_ip { - None => "".to_owned(), - Some(old_ip) => format!( - "{}ip:{}->{}", - if description.is_empty() { "" } else { " " }, - Self::display_small(old_ip), - Self::display_small(self.program_counter) - ), - }; - format!("{} ; {}{}", preamble, description, ip_desc) + format!( + "{} ;{}{}", + preamble, + if description.is_empty() { "" } else { " " }, + description + ) } /// Returns true if the operation overflowed, and true if the value is supposed @@ -710,12 +761,7 @@ impl Computer { parity % 2 == 1 } - fn step_arithmetic( - &mut self, - instruction: &ArithmeticInstruction, - old_ip: Option, - ) -> String { - let old_flags = self.flags; + fn step_arithmetic(&mut self, instruction: &ArithmeticInstruction) -> String { let (source, old_value, new_value, flags) = match &instruction.instruction { ArithmeticInstructionSelect::RegisterToRegister(instr) => { let current_value = self.get_register(&instr.dest); @@ -803,36 +849,61 @@ impl Computer { Flag::Status(StatusFlag::Parity), !Self::is_odd_parity(new_value % 256), ); - let flags_desc = if old_flags == self.flags { - "".to_owned() - } else { - format!(" flags:{}->{}", old_flags, self.flags) - }; - let ip_desc = match old_ip { - None => "".to_owned(), - Some(old_ip) => { - format!( - " ip:{}->{}", - Self::display_small(old_ip), - Self::display_small(self.program_counter) - ) - } - }; let result_desc = if flags.should_write && old_value != new_value { format!( " {}:{}->{}", source, - Self::display_small(old_value), - Self::display_small(new_value) + display_small(old_value), + display_small(new_value) ) } else { "".to_owned() }; - format!("{instruction} ;{result_desc}{ip_desc}{flags_desc}") + format!("{instruction} ;{result_desc}") } - fn step_jump(&mut self, jump: Jump, offset: i8, old_ip: Option) -> String { - let mut reg_desc = "".to_owned(); + fn step_boolean(&mut self, _instruction: &BooleanInstruction) -> String { + todo!() + } + + fn step_inc(&mut self, instruction: &IncInstruction) -> String { + let result_desc = match instruction { + IncInstruction::Register(reg) => { + let old_value = self.get_register(reg); + let new_value = if old_value == u16::MAX { + self.set_flag(Flag::Status(StatusFlag::Overflow), true); + 0 + } else { + self.set_flag(Flag::Status(StatusFlag::Overflow), false); + old_value + 1 + }; + + self.set_register(reg, new_value) + } /* + IncInstruction::Memory(addr) => { + let location = self.resolve_eaddr(addr); + let old_value = self.get_memory_word(location); + let new_value = if old_value == u16::MAX { + self.set_flag(Flag::Status(StatusFlag::Overflow), true); + 0 + } else { + self.set_flag(Flag::Status(StatusFlag::Overflow), false); + old_value + 1 + }; + + self.set_memory_word(location, new_value) + } + */ + }; + + format!("{instruction} ;{result_desc}") + } + + fn step_ret(&mut self) -> String { + todo!() + } + + fn step_jump(&mut self, jump: Jump, offset: i8) -> String { let should_jump = match jump { Jump::Je => self.flags.get(Flag::Status(StatusFlag::Zero)), Jump::Jl => { @@ -873,67 +944,40 @@ impl Computer { Jump::Loop => { let reg = Register::General(GeneralRegister::C, RegisterSubset::All); let prev = self.get_register(®); - let new_value = if prev == 0 { + if prev == 0 { self.set_register(®, u16::MAX); - u16::MAX } else { self.set_register(®, prev - 1); - prev - 1 }; - reg_desc.push_str(&format!( - " ; cx:{}->{}", - Self::display_small(prev), - Self::display_small(new_value) - )); prev != 1 } Jump::Loopz => { let reg = Register::General(GeneralRegister::C, RegisterSubset::All); let prev = self.get_register(®); self.set_register(®, prev - 1); - reg_desc.push_str(&format!( - " ; cx:{}->{}", - Self::display_small(prev), - Self::display_small(prev - 1) - )); prev != 1 && self.flags.get(Flag::Status(StatusFlag::Zero)) } Jump::Loopnz => { let reg = Register::General(GeneralRegister::C, RegisterSubset::All); let prev = self.get_register(®); self.set_register(®, prev - 1); - reg_desc.push_str(&format!( - " ; cx:{}->{}", - Self::display_small(prev), - Self::display_small(prev - 1) - )); prev != 1 && !self.flags.get(Flag::Status(StatusFlag::Zero)) } - Jump::Jcxz => todo!(), + Jump::Jcxz => { + let reg = Register::General(GeneralRegister::C, RegisterSubset::All); + self.get_register(®) == 0 + } }; if should_jump { self.program_counter = (self.program_counter as i32 + offset as i32) as u16; } - let ip_desc = match old_ip { - None => "".to_owned(), - Some(old_ip) => { - format!( - "{}ip:{}->{}", - if reg_desc.is_empty() { " ; " } else { " " }, - Self::display_small(old_ip), - Self::display_small(self.program_counter) - ) - } - }; // In NASM, the dollar sign is an offset *without* including the bytes of the jump. format!( - "{} ${}{}{}{}", + "{} ${}{}", jump, if offset > 0 { "+" } else { "" }, offset + 2, - reg_desc, - ip_desc ) } @@ -949,12 +993,69 @@ impl Computer { } else { None }; + let old_flags = self.flags; + let old_registers = self.registers.clone(); + self.program_counter += advance as u16; - match instruction { - Instruction::Move(mov) => self.step_mov(mov, old_ip), - Instruction::Arithmetic(arith) => self.step_arithmetic(arith, old_ip), - Instruction::Jump(jump, offset) => self.step_jump(*jump, *offset, old_ip), - Instruction::Trivia(_) => format!("{}", instruction), + + let instruction_override = match instruction { + Instruction::Move(mov) => { + self.step_mov(mov); + None + } + Instruction::Arithmetic(arith) => { + self.step_arithmetic(arith); + None + } + Instruction::Jump(jump, offset) => Some(self.step_jump(*jump, *offset)), + Instruction::Boolean(boolean) => { + self.step_boolean(boolean); + None + } + Instruction::Inc(inc) => { + self.step_inc(inc); + None + } + Instruction::Ret => { + self.step_ret(); + None + } + Instruction::Trivia(_) => None, + }; + + let mut post = Vec::new(); + + let acc_desc = self.registers.diff(&old_registers); + if !acc_desc.is_empty() { + post.push(acc_desc); + } + + match old_ip { + None => {} + Some(old_ip) => { + post.push(format!( + "ip:{}->{}", + display_small(old_ip), + display_small(self.program_counter) + )); + } + } + + if old_flags != self.flags { + post.push(format!("flags:{}->{}", old_flags, self.flags)); + } + + let post = post.join(" "); + + let instruction = match instruction_override { + None => format!("{instruction}"), + Some(i) => i, + }; + + if post.is_empty() { + instruction + } else { + format!("{instruction} ; {post}") } } @@ -968,12 +1069,7 @@ impl Computer { ] { let value = self.get_register(&Register::General(r.clone(), RegisterSubset::All)); if value != 0 { - result.push_str(&format!( - "{}x: {} ({})\n", - r, - Self::display_big(value), - value - )) + result.push_str(&format!("{}x: {} ({})\n", r, display_big(value), value)) } } @@ -985,12 +1081,7 @@ impl Computer { ] { let value = self.get_register(&Register::Special(r.clone())); if value != 0 { - result.push_str(&format!( - "{}: {} ({})\n", - r, - Self::display_big(value), - value - )) + result.push_str(&format!("{}: {} ({})\n", r, display_big(value), value)) } } @@ -1002,12 +1093,7 @@ impl Computer { ] { let value = self.get_segment(r); if value != 0 { - result.push_str(&format!( - "{}: {} ({})\n", - r, - Self::display_big(value), - value - )); + result.push_str(&format!("{}: {} ({})\n", r, display_big(value), value)); } } diff --git a/sim_8086/src/effective_address.rs b/sim_8086/src/effective_address.rs index 15bfb2b..8294af3 100644 --- a/sim_8086/src/effective_address.rs +++ b/sim_8086/src/effective_address.rs @@ -108,6 +108,9 @@ impl EffectiveAddress { where I: Iterator, { + if mode == 3 { + panic!("we don't handle this case, you need to do it manually to get a register") + } let source_dest = if rm % 2 == 0 { SourceDest::Source } else { diff --git a/sim_8086/src/inc_instruction.rs b/sim_8086/src/inc_instruction.rs new file mode 100644 index 0000000..745a450 --- /dev/null +++ b/sim_8086/src/inc_instruction.rs @@ -0,0 +1,33 @@ +use crate::register::Register; +use arbitrary::Arbitrary; +use std::fmt::{Display, Formatter}; + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub enum IncInstruction { + Register(Register), +} + +impl Display for IncInstruction { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + IncInstruction::Register(reg) => f.write_fmt(format_args!("inc {}", reg)), + } + } +} + +impl IncInstruction { + pub fn to_bytes(&self) -> Vec { + match self { + IncInstruction::Register(reg) => { + let (id, _is_wide) = reg.to_id(); + vec![0b01000000 + id] + } + } + } + + pub fn length(&self) -> u8 { + match self { + IncInstruction::Register(_) => 1, + } + } +} diff --git a/sim_8086/src/instruction.rs b/sim_8086/src/instruction.rs index cefecae..dedc165 100644 --- a/sim_8086/src/instruction.rs +++ b/sim_8086/src/instruction.rs @@ -2,6 +2,10 @@ use std::fmt::Display; use arbitrary::Arbitrary; +use crate::boolean_instruction::{ + BooleanInstruction, BooleanInstructionDestination, BooleanInstructionType, RegRegBoolean, +}; +use crate::inc_instruction::IncInstruction; use crate::{ arithmetic_instruction::{ ArithmeticInstruction, ArithmeticInstructionSelect, ArithmeticOperation, MemRegArithmetic, @@ -24,6 +28,9 @@ pub enum Instruction { /// Perform arithmetic Arithmetic(ArithmeticInstruction), Jump(Jump, InstructionOffset), + Boolean(BooleanInstruction), + Inc(IncInstruction), + Ret, /// An irrelevant instruction. Trivia(TriviaInstruction), } @@ -34,14 +41,17 @@ where { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Instruction::Move(instruction) => f.write_fmt(format_args!("{}", instruction)), - Instruction::Arithmetic(op) => f.write_fmt(format_args!("{}", op)), + Instruction::Move(instruction) => f.write_fmt(format_args!("{instruction}")), + Instruction::Arithmetic(op) => f.write_fmt(format_args!("{op}")), + Instruction::Inc(op) => f.write_fmt(format_args!("{op}")), Instruction::Jump(instruction, offset) => { - f.write_fmt(format_args!("{} ; {}", instruction, offset)) + f.write_fmt(format_args!("{instruction} ; {offset}")) } Instruction::Trivia(trivia) => match trivia { TriviaInstruction::Label(l) => f.write_fmt(format_args!("{}:", l)), }, + Instruction::Boolean(instruction) => f.write_fmt(format_args!("{instruction}")), + Instruction::Ret => f.write_fmt(format_args!("ret")), } } } @@ -51,6 +61,9 @@ impl<'a> Instruction<&'a str> { match self { Instruction::Move(mov) => mov.to_bytes(), Instruction::Arithmetic(instruction) => instruction.to_bytes(), + Instruction::Inc(op) => op.to_bytes(), + Instruction::Boolean(instruction) => instruction.to_bytes(), + Instruction::Ret => vec![0b11000011], Instruction::Jump(instruction, _) => { vec![ match instruction { @@ -90,6 +103,9 @@ impl Instruction { match self { Instruction::Move(mov) => mov.to_bytes(), Instruction::Arithmetic(instruction) => instruction.to_bytes(), + Instruction::Inc(instruction) => instruction.to_bytes(), + Instruction::Boolean(instruction) => instruction.to_bytes(), + Instruction::Ret => vec![0b11000011], Instruction::Jump(instruction, offset) => { let mut result = Vec::::with_capacity(2); @@ -421,6 +437,27 @@ impl Instruction { next as i8 }, )) + } else if b & 0b11111110 == 0b10000100 { + let is_wide = b % 2 == 1; + let mod_reg_rm = bytes.next().unwrap(); + let mode = mod_reg_rm / 64; + let source = Register::of_id((mod_reg_rm / 8) & 0b111, is_wide); + let rm = mod_reg_rm & 0b111; + if mode == 3 { + let dest = Register::of_id(rm, is_wide); + Some(Instruction::Boolean(BooleanInstruction { + selection: BooleanInstructionType::Test, + dest: BooleanInstructionDestination::RegReg(RegRegBoolean { source, dest }), + })) + } else { + // let dest = EffectiveAddress::of_mode_rm(mode, rm, bytes); + todo!() + } + } else if b == 0b11000011 { + Some(Instruction::Ret) + } else if b & 0b11111000 == 0b01000000 { + let reg = Register::of_id(b & 0b111, true); + Some(Instruction::Inc(IncInstruction::Register(reg))) } else { panic!("Unrecognised instruction byte: {}", b) } @@ -435,14 +472,18 @@ impl Instruction { match self { Instruction::Move(m) => m.length(), Instruction::Arithmetic(a) => a.length(), + Instruction::Inc(a) => a.length(), + Instruction::Boolean(b) => b.length(), Instruction::Jump(_, _) => 2, Instruction::Trivia(_) => 0, + Instruction::Ret => 1, } } } #[cfg(test)] mod test_instruction { + use crate::boolean_instruction::BooleanInstructionDestination; use crate::{ arithmetic_instruction::ArithmeticInstructionSelect, instruction::Instruction, @@ -467,6 +508,12 @@ mod test_instruction { } _ => false, }, + Instruction::Boolean(i) => match &i.dest { + BooleanInstructionDestination::RegReg(reg_reg) => { + reg_reg.source.is_wide() != reg_reg.dest.is_wide() + } + _ => false, + }, _ => false, } } diff --git a/sim_8086/src/lib.rs b/sim_8086/src/lib.rs index 0359c4e..53a590d 100644 --- a/sim_8086/src/lib.rs +++ b/sim_8086/src/lib.rs @@ -1,8 +1,10 @@ mod arithmetic_expression; pub mod arithmetic_instruction; pub mod assembly; +pub mod boolean_instruction; pub mod computer; pub mod effective_address; +pub mod inc_instruction; pub mod instruction; pub mod jump_instruction; pub mod move_instruction; diff --git a/sim_8086/src/program.rs b/sim_8086/src/program.rs index 8030d0f..9b3b648 100644 --- a/sim_8086/src/program.rs +++ b/sim_8086/src/program.rs @@ -38,7 +38,7 @@ where let mut labels = HashMap::new(); for (counter, instruction) in self.instructions.as_ref().iter().enumerate() { if let Instruction::Trivia(TriviaInstruction::Label(s)) = instruction { - if let Some(s) = labels.insert(*s, counter) { + if let Some(s) = labels.insert(s.trim(), counter) { panic!("same label twice: {}", s) } } @@ -54,7 +54,7 @@ where for (counter, instruction) in self.instructions.as_ref().iter().enumerate() { if let Instruction::Jump(_, offset) = instruction { - let desired_target_instruction_number = match labels.get(offset) { + let desired_target_instruction_number = match labels.get(offset.trim()) { Some(s) => *s, None => panic!("Tried to jump to label, but was not present: '{}'", offset), }; diff --git a/sim_8086/tests/test_computer.rs b/sim_8086/tests/test_computer.rs index 20f2a58..e2696b0 100644 --- a/sim_8086/tests/test_computer.rs +++ b/sim_8086/tests/test_computer.rs @@ -67,7 +67,11 @@ mod test_computer { let cleaned = clean_trace(expected_trace); let expected = cleaned.lines().collect::>(); - assert_eq!(trace, expected) + assert_eq!(trace.len(), expected.len()); + + for (traced, expected) in trace.iter().zip(expected.iter()) { + assert_eq!(traced, expected) + } } #[test] diff --git a/sim_8086/tests/test_program.rs b/sim_8086/tests/test_program.rs index d453464..2086fd8 100644 --- a/sim_8086/tests/test_program.rs +++ b/sim_8086/tests/test_program.rs @@ -23,8 +23,14 @@ mod test_program { (Instruction::Move(_), _) => false, (Instruction::Arithmetic(i1), Instruction::Arithmetic(i2)) => i1 == i2, (Instruction::Arithmetic(_), _) => false, + (Instruction::Boolean(i1), Instruction::Boolean(i2)) => i1 == i2, + (Instruction::Boolean(_), _) => false, (Instruction::Jump(i1, _), Instruction::Jump(i2, _)) => i1 == i2, (Instruction::Jump(_, _), _) => false, + (Instruction::Inc(i1), Instruction::Inc(i2)) => i1 == i2, + (Instruction::Inc(_), _) => false, + (Instruction::Ret, Instruction::Ret) => true, + (Instruction::Ret, _) => false, (Instruction::Trivia(_), Instruction::Trivia(_)) => true, (Instruction::Trivia(_), _) => false, } @@ -38,7 +44,7 @@ mod test_program { T: AsRef<[u8]>, { let (remaining, parsed) = assembly::program(input_asm).unwrap(); - assert_eq!(remaining, ""); + assert_eq!(remaining.trim(), ""); assert_eq!(parsed.bits, 16); let adjusted_program: Program>, _> = Program { @@ -61,12 +67,10 @@ mod test_program { .enumerate() { if actual != expected { + let ours = adjusted_program.to_bytes(); panic!( "Failed assertion: expected {} (from Casey), got {}, at position {}\n{:?}", - expected, - actual, - i, - adjusted_program.to_bytes() + expected, actual, i, ours ) } } @@ -89,7 +93,7 @@ mod test_program { let disassembled = Program::of_bytes(input_bytecode.as_ref().iter().cloned()); let (remaining, pre_compiled) = assembly::program(&input_asm).unwrap(); - assert_eq!(remaining, ""); + assert_eq!(remaining.trim(), ""); let disassembled = disassembled.instructions.iter().filter(|i| match i { Instruction::Trivia(_) => false, @@ -549,4 +553,155 @@ mod test_program { allowed.insert((vec![198, 71, 245, 255], vec![198, 135, 245, 0, 255])); test_disassembler_lax(asm, bytecode, allowed) } + + #[test] + fn test_estimating_cycles_parser() { + let input_asm = include_str!( + "../../computer_enhance/perfaware/part1/listing_0056_estimating_cycles.asm" + ); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0056_estimating_cycles"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_estimating_cycles_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0056_estimating_cycles"); + let asm = include_str!( + "../../computer_enhance/perfaware/part1/listing_0056_estimating_cycles.asm" + ); + test_disassembler(asm, bytecode) + } + + #[test] + fn test_challenge_cycles_parser() { + let input_asm = include_str!( + "../../computer_enhance/perfaware/part1/listing_0057_challenge_cycles.asm" + ); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0057_challenge_cycles"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_challenge_cycles_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0057_challenge_cycles"); + let asm = include_str!( + "../../computer_enhance/perfaware/part1/listing_0057_challenge_cycles.asm" + ); + test_disassembler(asm, bytecode) + } + + #[test] + fn test_single_scalar_parser() { + let input_asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0059_SingleScalar.asm"); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0059_SingleScalar"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_single_scalar_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0059_SingleScalar"); + let asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0059_SingleScalar.asm"); + test_disassembler(asm, bytecode) + } + + #[test] + fn test_unroll2_scalar_parser() { + let input_asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0060_Unroll2Scalar.asm"); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0060_Unroll2Scalar"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_unroll2_scalar_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0060_Unroll2Scalar"); + let asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0060_Unroll2Scalar.asm"); + test_disassembler(asm, bytecode) + } + + #[test] + fn test_dual_scalar_parser() { + let input_asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0061_DualScalar.asm"); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0061_DualScalar"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_dual_scalar_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0061_DualScalar"); + let asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0061_DualScalar.asm"); + test_disassembler(asm, bytecode) + } + + #[test] + fn test_quad_scalar_parser() { + let input_asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0062_QuadScalar.asm"); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0062_QuadScalar"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_quad_scalar_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0062_QuadScalar"); + let asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0062_QuadScalar.asm"); + test_disassembler(asm, bytecode) + } + + /* + #[test] + fn test_quad_scalar_ptr_parser() { + let input_asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0063_QuadScalarPtr.asm"); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0063_QuadScalarPtr"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_quad_scalar_ptr_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0063_QuadScalarPtr"); + let asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0063_QuadScalarPtr.asm"); + test_disassembler(asm, bytecode) + } + + #[test] + fn test_tree_scalar_ptr_parser() { + let input_asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0064_TreeScalarPtr.asm"); + let input_bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0064_TreeScalarPtr"); + test_parser(input_asm, input_bytecode) + } + + #[test] + fn test_tree_scalar_ptr_disassembler() { + let bytecode = + include_bytes!("../../computer_enhance/perfaware/part1/listing_0064_TreeScalarPtr"); + let asm = + include_str!("../../computer_enhance/perfaware/part1/listing_0064_TreeScalarPtr.asm"); + test_disassembler(asm, bytecode) + } + + */ }