Skip to content

Commit

Permalink
feat(keywords): implement lih for eq and not_eq;
Browse files Browse the repository at this point in the history
  • Loading branch information
5-pebbles committed Sep 9, 2024
1 parent e389756 commit 0908521
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 2 deletions.
64 changes: 62 additions & 2 deletions src/compilation/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -41,6 +41,15 @@ fn generate_arithmetic_register_distribution(
(destination, secondary)
}

pub fn unique_label() -> Arc<str> {
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<Ir>,
Expand Down Expand Up @@ -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
Expand Down
73 changes: 73 additions & 0 deletions src/tests/logic_is_hard.rs
Original file line number Diff line number Diff line change
@@ -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")
);
}
1 change: 1 addition & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod halt_and_nop;
mod lab_and_pc;
mod logic_is_hard;
mod or_and_nor;
mod shift_and_rotate;

0 comments on commit 0908521

Please sign in to comment.