From 40646928dd3ecadc4f7786f19cb6725690002a04 Mon Sep 17 00:00:00 2001 From: Patrick Stevens Date: Tue, 9 May 2023 21:33:37 +0100 Subject: [PATCH] Finish parsing the inputs up to part 13 (#18) --- sim_8086/src/assembly.rs | 81 ++++++++++++++++++++--- sim_8086/src/computer.rs | 55 ++++++++-------- sim_8086/src/inc_instruction.rs | 23 +++---- sim_8086/src/instruction.rs | 78 +++++++++++++++++++++- sim_8086/src/lib.rs | 1 + sim_8086/src/logic_instruction.rs | 105 ++++++++++++++++++++++++++++++ sim_8086/tests/test_program.rs | 5 +- 7 files changed, 293 insertions(+), 55 deletions(-) create mode 100644 sim_8086/src/logic_instruction.rs diff --git a/sim_8086/src/assembly.rs b/sim_8086/src/assembly.rs index ac8bca6..4cadb75 100644 --- a/sim_8086/src/assembly.rs +++ b/sim_8086/src/assembly.rs @@ -15,6 +15,7 @@ use crate::boolean_instruction::{ BooleanInstruction, BooleanInstructionDestination, BooleanInstructionType, RegRegBoolean, }; use crate::inc_instruction::IncInstruction; +use crate::logic_instruction::{LogicInstruction, LogicInstructionType, LogicTarget}; use crate::{ arithmetic_expression::{ArithmeticExpression, Token}, arithmetic_instruction::{ @@ -899,14 +900,77 @@ fn move_instruction(input: &str) -> IResult<&str, MoveInstruction> { } 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))), - //)), + alt(( + preceded( + ws(tag("inc ")), + map_res(register, |reg| { + Ok::<_, ()>(IncInstruction { + target: reg, + is_inc: true, + }) + }), + ), + preceded( + ws(tag("dec ")), + map_res(register, |reg| { + Ok::<_, ()>(IncInstruction { + target: reg, + is_inc: false, + }) + }), + ), + ))(input) +} + +fn logic_instruction_type(input: &str) -> IResult<&str, LogicInstructionType> { + alt(( + map_res(tag("not"), |_| Ok::<_, ()>(LogicInstructionType::Not)), + map_res(tag("shl"), |_| Ok::<_, ()>(LogicInstructionType::Shl)), + map_res(tag("shr"), |_| Ok::<_, ()>(LogicInstructionType::Shr)), + map_res(tag("sar"), |_| Ok::<_, ()>(LogicInstructionType::Sar)), + map_res(tag("rol"), |_| Ok::<_, ()>(LogicInstructionType::Rol)), + map_res(tag("ror"), |_| Ok::<_, ()>(LogicInstructionType::Ror)), + map_res(tag("rcl"), |_| Ok::<_, ()>(LogicInstructionType::Rcl)), + map_res(tag("rcr"), |_| Ok::<_, ()>(LogicInstructionType::Rcr)), + ))(input) +} + +fn logic_instruction(input: &str) -> IResult<&str, LogicInstruction> { + map_res( + tuple(( + ws(logic_instruction_type), + alt(( + map_res(register, |reg| { + Ok::<_, ()>((LogicTarget::Register(reg), None)) + }), + map_res(effective_address, |(tag, addr)| { + Ok::<_, ()>((LogicTarget::Address(addr), Some(tag))) + }), + )), + preceded( + argument_sep, + alt(( + map_res(tag("1"), |_| Ok::<_, ()>(false)), + map_res(tag("cl"), |_| Ok::<_, ()>(true)), + )), + ), + )), + |(instruction, (dest, tag), amount)| { + Ok::<_, ()>(LogicInstruction { + op: instruction, + amount_from_cl: amount, + is_wide: match (tag, &dest) { + (None, LogicTarget::Register(reg)) => reg.is_wide(), + (Some(tag), LogicTarget::Address(_)) => match tag { + OffsetTag::Byte => false, + OffsetTag::Word => true, + OffsetTag::None => todo!(), + }, + (_, _) => panic!("Unexpected"), + }, + target: dest, + }) + }, )(input) } @@ -920,6 +984,7 @@ fn instruction(input: &str) -> IResult<&str, Instruction<&str>> { Ok::<_, ()>(Instruction::Arithmetic(v)) }), map_res(inc_instruction, |v| Ok::<_, ()>(Instruction::Inc(v))), + map_res(logic_instruction, |v| Ok::<_, ()>(Instruction::Logic(v))), map_res(tag("ret"), |_| Ok::<_, ()>(Instruction::Ret)), map_res(jump, |(v, label)| Ok::<_, ()>(Instruction::Jump(v, label))), map_res(label, |v| { diff --git a/sim_8086/src/computer.rs b/sim_8086/src/computer.rs index 02a5eeb..ff9dd62 100644 --- a/sim_8086/src/computer.rs +++ b/sim_8086/src/computer.rs @@ -2,6 +2,7 @@ use std::fmt::Display; use crate::boolean_instruction::BooleanInstruction; use crate::inc_instruction::IncInstruction; +use crate::logic_instruction::LogicInstruction; use crate::{ arithmetic_instruction::{ ArithmeticInstruction, ArithmeticInstructionSelect, ArithmeticOperation, @@ -866,43 +867,35 @@ impl Computer { 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) - } - */ + fn step_inc(&mut self, instruction: &IncInstruction) { + let old_value = self.get_register(&instruction.target); + let new_value = if instruction.is_inc { + 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 + } + } else if old_value == 0 { + self.set_flag(Flag::Status(StatusFlag::Overflow), true); + u16::MAX + } else { + self.set_flag(Flag::Status(StatusFlag::Overflow), false); + old_value - 1 }; - format!("{instruction} ;{result_desc}") + self.set_register(&instruction.target, new_value); } fn step_ret(&mut self) -> String { todo!() } + fn step_logic(&mut self, _instruction: &LogicInstruction) { + 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)), @@ -1020,6 +1013,10 @@ impl Computer { self.step_ret(); None } + Instruction::Logic(instruction) => { + self.step_logic(instruction); + None + } Instruction::Trivia(_) => None, }; diff --git a/sim_8086/src/inc_instruction.rs b/sim_8086/src/inc_instruction.rs index 745a450..8345e77 100644 --- a/sim_8086/src/inc_instruction.rs +++ b/sim_8086/src/inc_instruction.rs @@ -3,31 +3,28 @@ use arbitrary::Arbitrary; use std::fmt::{Display, Formatter}; #[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] -pub enum IncInstruction { - Register(Register), +pub struct IncInstruction { + pub target: Register, + pub is_inc: bool, } 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)), + if self.is_inc { + f.write_fmt(format_args!("inc {}", self.target)) + } else { + f.write_fmt(format_args!("dec {}", self.target)) } } } impl IncInstruction { pub fn to_bytes(&self) -> Vec { - match self { - IncInstruction::Register(reg) => { - let (id, _is_wide) = reg.to_id(); - vec![0b01000000 + id] - } - } + let (id, _is_wide) = self.target.to_id(); + vec![0b01000000 + id + if self.is_inc { 0 } else { 8 }] } pub fn length(&self) -> u8 { - match self { - IncInstruction::Register(_) => 1, - } + 1 } } diff --git a/sim_8086/src/instruction.rs b/sim_8086/src/instruction.rs index dedc165..84904ba 100644 --- a/sim_8086/src/instruction.rs +++ b/sim_8086/src/instruction.rs @@ -6,6 +6,7 @@ use crate::boolean_instruction::{ BooleanInstruction, BooleanInstructionDestination, BooleanInstructionType, RegRegBoolean, }; use crate::inc_instruction::IncInstruction; +use crate::logic_instruction::{LogicInstruction, LogicInstructionType, LogicTarget}; use crate::{ arithmetic_instruction::{ ArithmeticInstruction, ArithmeticInstructionSelect, ArithmeticOperation, MemRegArithmetic, @@ -29,6 +30,7 @@ pub enum Instruction { Arithmetic(ArithmeticInstruction), Jump(Jump, InstructionOffset), Boolean(BooleanInstruction), + Logic(LogicInstruction), Inc(IncInstruction), Ret, /// An irrelevant instruction. @@ -52,6 +54,7 @@ where }, Instruction::Boolean(instruction) => f.write_fmt(format_args!("{instruction}")), Instruction::Ret => f.write_fmt(format_args!("ret")), + Instruction::Logic(instruction) => f.write_fmt(format_args!("{instruction}")), } } } @@ -93,6 +96,8 @@ impl<'a> Instruction<&'a str> { ] } + Instruction::Logic(instruction) => instruction.to_bytes(), + Instruction::Trivia(_) => vec![], } } @@ -142,6 +147,8 @@ impl Instruction { result } + Instruction::Logic(instruction) => instruction.to_bytes(), + Instruction::Trivia(_) => vec![], } } @@ -455,9 +462,75 @@ impl Instruction { } } else if b == 0b11000011 { Some(Instruction::Ret) - } else if b & 0b11111000 == 0b01000000 { + } else if b & 0b11110000 == 0b01000000 { let reg = Register::of_id(b & 0b111, true); - Some(Instruction::Inc(IncInstruction::Register(reg))) + let is_inc = (b / 8) % 2 == 0; + Some(Instruction::Inc(IncInstruction { + target: reg, + is_inc, + })) + } else if b & 0b11111110 == 0b11110110 { + let is_wide = b % 2 == 0; + let mod_instr_rm = bytes.next().unwrap(); + let rm = mod_instr_rm % 8; + let mode = mod_instr_rm / 64; + let op = match (mod_instr_rm / 8) % 8 { + 2 => LogicInstructionType::Not, + op => panic!("Unexpected instruction type in NOT: {}", op), + }; + + let instruction = if mode == 3 { + let target = Register::of_id(rm, is_wide); + LogicInstruction { + op, + amount_from_cl: false, + target: LogicTarget::Register(target), + is_wide, + } + } else { + let dest = EffectiveAddress::of_mode_rm(mode, rm, bytes); + LogicInstruction { + op, + amount_from_cl: false, + target: LogicTarget::Address(dest), + is_wide, + } + }; + Some(Instruction::Logic(instruction)) + } else if b & 0b11111100 == 0b11010000 { + let amount_from_cl = (b / 2) % 2 == 1; + let is_wide = b % 2 == 1; + let mod_instr_rm = bytes.next().unwrap(); + let rm = mod_instr_rm % 8; + let mode = mod_instr_rm / 64; + let op = match (mod_instr_rm / 8) % 8 { + 0 => LogicInstructionType::Rol, + 1 => LogicInstructionType::Ror, + 2 => LogicInstructionType::Rcl, + 3 => LogicInstructionType::Rcr, + 4 => LogicInstructionType::Shl, + 5 => LogicInstructionType::Shr, + 7 => LogicInstructionType::Sar, + op => panic!("Unexpected instruction type: {}", op), + }; + let instruction = if mode == 3 { + let target = Register::of_id(rm, is_wide); + LogicInstruction { + op, + amount_from_cl, + target: LogicTarget::Register(target), + is_wide, + } + } else { + let dest = EffectiveAddress::of_mode_rm(mode, rm, bytes); + LogicInstruction { + op, + amount_from_cl, + target: LogicTarget::Address(dest), + is_wide, + } + }; + Some(Instruction::Logic(instruction)) } else { panic!("Unrecognised instruction byte: {}", b) } @@ -476,6 +549,7 @@ impl Instruction { Instruction::Boolean(b) => b.length(), Instruction::Jump(_, _) => 2, Instruction::Trivia(_) => 0, + Instruction::Logic(a) => a.length(), Instruction::Ret => 1, } } diff --git a/sim_8086/src/lib.rs b/sim_8086/src/lib.rs index 53a590d..d5559c8 100644 --- a/sim_8086/src/lib.rs +++ b/sim_8086/src/lib.rs @@ -7,6 +7,7 @@ pub mod effective_address; pub mod inc_instruction; pub mod instruction; pub mod jump_instruction; +pub mod logic_instruction; pub mod move_instruction; pub mod program; pub mod register; diff --git a/sim_8086/src/logic_instruction.rs b/sim_8086/src/logic_instruction.rs new file mode 100644 index 0000000..58223d6 --- /dev/null +++ b/sim_8086/src/logic_instruction.rs @@ -0,0 +1,105 @@ +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 LogicInstructionType { + Not, + Shl, + Shr, + Sar, + Rol, + Ror, + Rcl, + Rcr, +} + +impl Display for LogicInstructionType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + LogicInstructionType::Not => "not", + LogicInstructionType::Shl => "shl", + LogicInstructionType::Shr => "shr", + LogicInstructionType::Sar => "sar", + LogicInstructionType::Rol => "rol", + LogicInstructionType::Ror => "ror", + LogicInstructionType::Rcl => "rcl", + LogicInstructionType::Rcr => "rcr", + }) + } +} + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub enum LogicTarget { + Address(EffectiveAddress), + Register(Register), +} + +impl Display for LogicTarget { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + LogicTarget::Address(addr) => f.write_fmt(format_args!("{}", addr)), + LogicTarget::Register(reg) => f.write_fmt(format_args!("{}", reg)), + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, Clone, Arbitrary)] +pub struct LogicInstruction { + pub op: LogicInstructionType, + pub amount_from_cl: bool, + pub target: LogicTarget, + pub is_wide: bool, +} + +impl Display for LogicInstruction { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "{} {},{}", + self.op, + self.target, + if self.amount_from_cl { "cl" } else { "1" } + )) + } +} + +impl LogicInstruction { + pub fn length(&self) -> u8 { + match &self.target { + LogicTarget::Register(_) => 2, + LogicTarget::Address(addr) => 1 + addr.length(), + } + } + + pub fn to_bytes(&self) -> Vec { + let mut result = Vec::new(); + let byte = match self.op { + LogicInstructionType::Not => 0b11110110, + _ => 0b11010000 + if self.amount_from_cl { 2 } else { 0 }, + } + if self.is_wide { 1 } else { 0 }; + + result.push(byte); + + let code = match &self.op { + LogicInstructionType::Rol => 0, + LogicInstructionType::Ror => 1, + LogicInstructionType::Rcl => 2, + LogicInstructionType::Rcr => 3, + LogicInstructionType::Shl => 4, + LogicInstructionType::Shr => 5, + LogicInstructionType::Sar => 7, + LogicInstructionType::Not => 2, + }; + + match &self.target { + LogicTarget::Address(addr) => addr.push(code, &mut result), + LogicTarget::Register(reg) => { + let (id, _is_wide) = reg.to_id(); + result.push(3 * 64 + code * 8 + id) + } + }; + + result + } +} diff --git a/sim_8086/tests/test_program.rs b/sim_8086/tests/test_program.rs index 2086fd8..7b04d47 100644 --- a/sim_8086/tests/test_program.rs +++ b/sim_8086/tests/test_program.rs @@ -31,6 +31,8 @@ mod test_program { (Instruction::Inc(_), _) => false, (Instruction::Ret, Instruction::Ret) => true, (Instruction::Ret, _) => false, + (Instruction::Logic(i1), Instruction::Logic(i2)) => i1 == i2, + (Instruction::Logic(_), _) => false, (Instruction::Trivia(_), Instruction::Trivia(_)) => true, (Instruction::Trivia(_), _) => false, } @@ -666,7 +668,6 @@ mod test_program { test_disassembler(asm, bytecode) } - /* #[test] fn test_quad_scalar_ptr_parser() { let input_asm = @@ -702,6 +703,4 @@ mod test_program { include_str!("../../computer_enhance/perfaware/part1/listing_0064_TreeScalarPtr.asm"); test_disassembler(asm, bytecode) } - - */ }