From 0908521122e8cfa9aa45d3f8c8098ba2b107a5c0 Mon Sep 17 00:00:00 2001 From: 5-pebbles <5-pebble@protonmail.com> Date: Mon, 9 Sep 2024 10:11:41 -0400 Subject: [PATCH] feat(keywords): implement lih for eq and not_eq; --- src/compilation/generator.rs | 64 ++++++++++++++++++++++++++++++- src/tests/logic_is_hard.rs | 73 ++++++++++++++++++++++++++++++++++++ src/tests/mod.rs | 1 + 3 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 src/tests/logic_is_hard.rs diff --git a/src/compilation/generator.rs b/src/compilation/generator.rs index 8439a8f..5801765 100644 --- a/src/compilation/generator.rs +++ b/src/compilation/generator.rs @@ -7,7 +7,7 @@ use strum::IntoEnumIterator; use super::{ diagnostic::{DiagKind, DiagLevel, Diagnostic}, - ir::{AddressTuple, Conditional, Either, Immediate, Ir, IrRegister}, + ir::{AddressTuple, Conditional, ConditionalKind, Either, Immediate, Ir, IrRegister}, span::Span, }; @@ -41,6 +41,15 @@ fn generate_arithmetic_register_distribution( (destination, secondary) } +pub fn unique_label() -> Arc { + static COUNTER: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); + let label = format!( + "#{}", + COUNTER.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + ); + Arc::from(label) +} + #[derive(Debug, Clone)] pub struct IrGenerator { ir: Vec, @@ -237,7 +246,58 @@ impl IrGenerator { } pub fn lih(&mut self, condition: Conditional, address: AddressTuple) -> &mut Self { - todo!() + // TODO optimize + let helper = free_register!(MEM_REGISTER).unwrap(); + + match condition.kind { + ConditionalKind::Eq | ConditionalKind::NotEq => { + if matches!(condition.left, Either::Register(left) if left == MEM_REGISTER) { + self.sub(MEM_REGISTER, condition.right) + } else { + self.mov(MEM_REGISTER, condition.right) + .sub(MEM_REGISTER, condition.left) + }; + + self.mov(helper, Either::Immediate(Immediate::Constant(u6::new(0)))); + + (0..6).into_iter().for_each(|_| { + self.or(helper, Either::Register(MEM_REGISTER)) + .ror(MEM_REGISTER); + }); + + self.and( + helper, + Either::Immediate(Immediate::Constant(u6::new(0b000001))), + ); + + if condition.kind == ConditionalKind::NotEq { + self.not(helper).and( + helper, + Either::Immediate(Immediate::Constant(u6::new(0b000001))), + ); + } + } + _ => todo!(), + } + + // At this point helper should contain zero if we are going to jump else one + self.rol(helper).or(MEM_REGISTER, Either::Register(helper)); + let label = unique_label(); + self.add( + MEM_REGISTER, + Either::Immediate(Immediate::LabelP1(label.clone(), Span::new(0, 0))), + ) + .pc(AddressTuple( + Either::Immediate(Immediate::LabelP0(label.clone(), Span::new(0, 0))), + Either::Register(helper), + )); + + if self.next_address & u12::new(0b111111) == u12::new(0b111111) { + // skip 6-bit overflow + self.nop(); + } + + self.lab(label, Span::new(0, 0)).unwrap().pc(address) } // Miscellaneous diff --git a/src/tests/logic_is_hard.rs b/src/tests/logic_is_hard.rs new file mode 100644 index 0000000..5d0b5a9 --- /dev/null +++ b/src/tests/logic_is_hard.rs @@ -0,0 +1,73 @@ +// I am about to fall asleep... zzz + +use arbitrary_int::{u12, u6}; + +use crate::{compilation::compile_to_binary, emulation::InteractiveState, utils::tuple_as_u12}; + +#[test] +fn jump_if_eq() { + let mut state = InteractiveState::new(); + let mc_result = compile_to_binary("LIH [A == 0] TEST\nHLT\nLAB TEST\nHLT"); + assert_eq!(mc_result.diagnostics.len(), 0); + state.memory.store_array(0, &mc_result.binary); + state.consume_until_halt(); + assert_eq!( + Some(&tuple_as_u12(state.program_counter.as_tuple())), + mc_result.symbol_table.get("TEST") + ); + // reset + state = InteractiveState::new(); + state.memory.store_array(0, &mc_result.binary); + state.a = u6::new(1); + state.consume_until_halt(); + assert_eq!( + Some(&(tuple_as_u12(state.program_counter.as_tuple()) + u12::new(1))), + mc_result.symbol_table.get("TEST") + ); +} + +#[test] +fn jump_if_not_eq() { + let mut state = InteractiveState::new(); + let mc_result = compile_to_binary("LIH [A != 0] TEST\nHLT\nLAB TEST\nHLT"); + assert_eq!(mc_result.diagnostics.len(), 0); + state.memory.store_array(0, &mc_result.binary); + state.consume_until_halt(); + assert_eq!( + Some(&(tuple_as_u12(state.program_counter.as_tuple()) + u12::new(1))), + mc_result.symbol_table.get("TEST") + ); + // reset + state = InteractiveState::new(); + state.memory.store_array(0, &mc_result.binary); + state.a = u6::new(1); + state.consume_until_halt(); + assert_eq!( + Some(&tuple_as_u12(state.program_counter.as_tuple())), + mc_result.symbol_table.get("TEST") + ); +} + +#[test] +fn multiple_jumps() { + let mut state = InteractiveState::new(); + let mc_result = compile_to_binary( + "LIH [A == 0] TEST1\nLIH [A != 0] TEST2\nHLT\nLAB TEST1\nHLT\nLAB TEST2\nHLT", + ); + assert_eq!(mc_result.diagnostics.len(), 0); + state.memory.store_array(0, &mc_result.binary); + state.consume_until_halt(); + assert_eq!( + Some(&tuple_as_u12(state.program_counter.as_tuple())), + mc_result.symbol_table.get("TEST1") + ); + // reset + state = InteractiveState::new(); + state.memory.store_array(0, &mc_result.binary); + state.a = u6::new(1); + state.consume_until_halt(); + assert_eq!( + Some(&tuple_as_u12(state.program_counter.as_tuple())), + mc_result.symbol_table.get("TEST2") + ); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index b048ec9..f789f11 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,5 @@ mod halt_and_nop; mod lab_and_pc; +mod logic_is_hard; mod or_and_nor; mod shift_and_rotate;