#![no_std]
mod bus;
mod machine;
mod memory;
#[cfg(feature = "pretty_print")]
mod pretty_print;
mod stack;
pub use bus::*;
pub use machine::*;
pub use memory::*;
pub use stack::*;
#[cfg(feature = "pretty_print")]
pub use pretty_print::*;
#[cfg(test)]
mod test;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UxnVector<'a, M, B> {
pub machine: &'a mut UxnMachineState,
pub program_counter: u16,
pub memory: &'a mut M,
pub device_bus: &'a mut B,
}
impl<'a, M, B> UxnVector<'a, M, B>
where
M: UxnMemory,
B: UxnDeviceBus,
{
pub fn new(
program_counter: u16,
machine: &'a mut UxnMachineState,
memory: &'a mut M,
device_bus: &'a mut B,
) -> Self {
Self {
machine,
program_counter,
memory,
device_bus,
}
}
pub fn execute_till_end(self) {
self.for_each(|_| {})
}
pub fn release(self) -> u16 {
self.program_counter
}
}
impl<M, B> Iterator for UxnVector<'_, M, B>
where
M: UxnMemory,
B: UxnDeviceBus,
{
type Item = (u8, u16);
fn next(&mut self) -> Option<Self::Item> {
let (instruction, next_program_counter) = execute_operation(
self.machine,
self.program_counter,
self.memory,
self.device_bus,
);
if let Some(pc) = next_program_counter {
let old_pc = self.program_counter;
self.program_counter = pc;
Some((instruction, old_pc))
} else {
None
}
}
}
pub fn execute_operation<M: UxnMemory, B: UxnDeviceBus>(
machine_state: &mut UxnMachineState,
program_counter: u16,
memory: &mut M,
device_bus: &mut B,
) -> (u8, Option<u16>) {
let instruction = memory.get(program_counter);
let operation = instruction & 0x1f;
(
instruction,
match instruction & 0xe0 {
0x00 => execute_operation_generic::<false, false, false, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
0x20 => execute_operation_generic::<true, false, false, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
0x40 => execute_operation_generic::<false, true, false, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
0x60 => execute_operation_generic::<true, true, false, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
0x80 => execute_operation_generic::<false, false, true, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
0xa0 => execute_operation_generic::<true, false, true, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
0xc0 => execute_operation_generic::<false, true, true, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
0xe0 => execute_operation_generic::<true, true, true, M, B>(
machine_state,
operation,
program_counter,
memory,
device_bus,
),
_ => unreachable!("You managed to enter a set of modes that does not exist... huh?"),
},
)
}
fn execute_operation_generic<
const SHORT: bool,
const RETURN: bool,
const KEEP: bool,
M: UxnMemory,
B: UxnDeviceBus,
>(
machine_state: &mut UxnMachineState,
operation: u8,
mut program_counter: u16,
memory: &mut M,
device_bus: &mut B,
) -> Option<u16> {
macro_rules! stack {
() => {
if RETURN {
&mut machine_state.return_stack
} else {
&mut machine_state.work_stack
}
};
}
macro_rules! return_stack {
() => {
if RETURN {
&mut machine_state.work_stack
} else {
&mut machine_state.return_stack
}
};
}
let mut popped = 0;
fn pop<const KEEP: bool>(stack: &mut UxnStack, popped: &mut i8) -> u8 {
if KEEP {
*popped -= 1;
stack.get(*popped + 1)
} else {
stack.pop()
}
}
fn pop_short<const KEEP: bool>(stack: &mut UxnStack, popped: &mut i8) -> u16 {
if KEEP {
*popped -= 2;
stack.get_short(*popped + 2)
} else {
stack.pop_short()
}
}
program_counter = program_counter.wrapping_add(1);
match operation {
0x00 => {
match (SHORT, RETURN, KEEP) {
(false, false, false) => return None, (true, false, false) => {
if machine_state.work_stack.pop() != 0 {
program_counter =
program_counter.wrapping_add(memory.get_short(program_counter))
}
program_counter = program_counter.wrapping_add(2)
}
(false, true, false) => {
program_counter = program_counter
.wrapping_add(memory.get_short(program_counter))
.wrapping_add(2);
}
(true, true, false) => {
machine_state
.return_stack
.push_short(program_counter.wrapping_add(2));
program_counter = program_counter
.wrapping_add(memory.get_short(program_counter))
.wrapping_add(2)
}
(false, _, true) => {
let value = memory.get(program_counter);
stack!().push(value);
program_counter = program_counter.wrapping_add(1);
}
(true, _, true) => {
let value = memory.get_short(program_counter);
stack!().push_short(value);
program_counter = program_counter.wrapping_add(2)
}
}
}
0x01 => {
if SHORT {
let v = pop_short::<KEEP>(stack!(), &mut popped).wrapping_add(1);
stack!().push_short(v)
} else {
let v = pop::<KEEP>(stack!(), &mut popped).wrapping_add(1);
stack!().push(v)
}
}
0x02 => {
if SHORT {
pop_short::<KEEP>(stack!(), &mut popped);
} else {
pop::<KEEP>(stack!(), &mut popped);
}
}
0x03 => {
if SHORT {
let b = pop_short::<KEEP>(stack!(), &mut popped);
let _ = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(b);
} else {
let b = pop::<KEEP>(stack!(), &mut popped);
let _ = pop::<KEEP>(stack!(), &mut popped);
stack!().push(b);
}
}
0x04 => {
if SHORT {
let b = pop_short::<KEEP>(stack!(), &mut popped);
let a = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(b);
stack!().push_short(a);
} else {
let b = pop::<KEEP>(stack!(), &mut popped);
let a = pop::<KEEP>(stack!(), &mut popped);
stack!().push(b);
stack!().push(a);
}
}
0x05 => {
if SHORT {
let c = pop_short::<KEEP>(stack!(), &mut popped);
let b = pop_short::<KEEP>(stack!(), &mut popped);
let a = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(b);
stack!().push_short(c);
stack!().push_short(a);
} else {
let c = pop::<KEEP>(stack!(), &mut popped);
let b = pop::<KEEP>(stack!(), &mut popped);
let a = pop::<KEEP>(stack!(), &mut popped);
stack!().push(b);
stack!().push(c);
stack!().push(a);
}
}
0x06 => {
if SHORT {
let v = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(v);
stack!().push_short(v);
} else {
let v = pop::<KEEP>(stack!(), &mut popped);
stack!().push(v);
stack!().push(v);
}
}
0x07 => {
if SHORT {
let b = pop_short::<KEEP>(stack!(), &mut popped);
let a = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(a);
stack!().push_short(b);
stack!().push_short(a);
} else {
let b = pop::<KEEP>(stack!(), &mut popped);
let a = pop::<KEEP>(stack!(), &mut popped);
stack!().push(a);
stack!().push(b);
stack!().push(a);
}
}
0x08 => {
let res = if SHORT {
pop_short::<KEEP>(stack!(), &mut popped) == pop_short::<KEEP>(stack!(), &mut popped)
} else {
pop::<KEEP>(stack!(), &mut popped) == pop::<KEEP>(stack!(), &mut popped)
} as u8;
stack!().push(res);
}
0x09 => {
let res = if SHORT {
pop_short::<KEEP>(stack!(), &mut popped) != pop_short::<KEEP>(stack!(), &mut popped)
} else {
pop::<KEEP>(stack!(), &mut popped) != pop::<KEEP>(stack!(), &mut popped)
} as u8;
stack!().push(res);
}
0x0a => {
let res = if SHORT {
pop_short::<KEEP>(stack!(), &mut popped) < pop_short::<KEEP>(stack!(), &mut popped)
} else {
pop::<KEEP>(stack!(), &mut popped) < pop::<KEEP>(stack!(), &mut popped)
} as u8;
stack!().push(res);
}
0x0b => {
let res = if SHORT {
pop_short::<KEEP>(stack!(), &mut popped) > pop_short::<KEEP>(stack!(), &mut popped)
} else {
pop::<KEEP>(stack!(), &mut popped) > pop::<KEEP>(stack!(), &mut popped)
} as u8;
stack!().push(res);
}
0x0c => {
if SHORT {
program_counter = pop_short::<KEEP>(stack!(), &mut popped)
} else {
program_counter =
program_counter.wrapping_add((pop::<KEEP>(stack!(), &mut popped) as i8) as u16)
}
}
0x0d => {
if pop::<KEEP>(stack!(), &mut popped) != 0 {
if SHORT {
program_counter = pop_short::<KEEP>(stack!(), &mut popped)
} else {
program_counter = program_counter
.wrapping_add((pop::<KEEP>(stack!(), &mut popped) as i8) as u16)
}
}
}
0x0e => {
machine_state.return_stack.push_short(program_counter);
if SHORT {
program_counter = pop_short::<KEEP>(stack!(), &mut popped)
} else {
program_counter =
program_counter.wrapping_add((pop::<KEEP>(stack!(), &mut popped) as i8) as u16)
}
}
0x0f => {
if SHORT {
let v = pop_short::<KEEP>(stack!(), &mut popped);
return_stack!().push_short(v);
} else {
let v = pop::<KEEP>(stack!(), &mut popped);
return_stack!().push(v);
}
}
0x10 => {
let address = pop::<KEEP>(stack!(), &mut popped);
if SHORT {
let value = memory.get_short(address as u16);
stack!().push_short(value)
} else {
let value = memory.get(address as u16);
stack!().push(value)
}
}
0x11 => {
let address = pop::<KEEP>(stack!(), &mut popped);
if SHORT {
let v = pop_short::<KEEP>(stack!(), &mut popped);
memory.set_short(address as u16, v)
} else {
let v = pop::<KEEP>(stack!(), &mut popped);
*memory.get_mut(address as u16) = v
}
}
0x12 => {
let address = program_counter
.wrapping_add_signed((pop::<KEEP>(stack!(), &mut popped) as i8) as i16);
if SHORT {
let value = memory.get_short(address as u16);
stack!().push_short(value)
} else {
let value = memory.get(address as u16);
stack!().push(value)
}
}
0x13 => {
let address =
program_counter.wrapping_add((pop::<KEEP>(stack!(), &mut popped) as i8) as u16);
if SHORT {
let v = pop_short::<KEEP>(stack!(), &mut popped);
memory.set_short(address as u16, v)
} else {
let v = pop::<KEEP>(stack!(), &mut popped);
*memory.get_mut(address as u16) = v
}
}
0x14 => {
let address = pop_short::<KEEP>(stack!(), &mut popped);
if SHORT {
let value = memory.get_short(address);
stack!().push_short(value)
} else {
let value = memory.get(address);
stack!().push(value)
}
}
0x15 => {
let address = pop_short::<KEEP>(stack!(), &mut popped);
if SHORT {
let v = pop_short::<KEEP>(stack!(), &mut popped);
memory.set_short(address, v);
} else {
let v = pop::<KEEP>(stack!(), &mut popped);
*memory.get_mut(address) = v
}
}
0x16 => {
let address = pop::<KEEP>(stack!(), &mut popped);
if SHORT {
let v = device_bus.read_short(machine_state, address);
stack!().push_short(v)
} else {
let v = device_bus.read(machine_state, address);
stack!().push(v)
}
}
0x17 => {
let address = pop::<KEEP>(stack!(), &mut popped);
if SHORT {
let value = pop_short::<KEEP>(stack!(), &mut popped);
device_bus.write_short(machine_state, address, value);
} else {
let value = pop::<KEEP>(stack!(), &mut popped);
device_bus.write(machine_state, address, value);
}
}
0x18 => {
if SHORT {
let a = pop_short::<KEEP>(stack!(), &mut popped);
let b = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(a.wrapping_add(b));
} else {
let a = pop::<KEEP>(stack!(), &mut popped);
let b = pop::<KEEP>(stack!(), &mut popped);
stack!().push(a.wrapping_add(b));
}
}
0x19 => {
if SHORT {
let b = pop_short::<KEEP>(stack!(), &mut popped);
let a = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(a.wrapping_sub(b));
} else {
let b = pop::<KEEP>(stack!(), &mut popped);
let a = pop::<KEEP>(stack!(), &mut popped);
stack!().push(a.wrapping_sub(b));
}
}
0x1a => {
if SHORT {
let a = pop_short::<KEEP>(stack!(), &mut popped);
let b = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(a.wrapping_mul(b));
} else {
let a = pop::<KEEP>(stack!(), &mut popped);
let b = pop::<KEEP>(stack!(), &mut popped);
stack!().push(a.wrapping_mul(b));
}
}
0x1b => {
if SHORT {
let b = pop_short::<KEEP>(stack!(), &mut popped);
let a = pop_short::<KEEP>(stack!(), &mut popped);
if b == 0 {
stack!().push_short(0)
} else {
stack!().push_short(a.wrapping_div(b));
}
} else {
let b = pop::<KEEP>(stack!(), &mut popped);
let a = pop::<KEEP>(stack!(), &mut popped);
if b == 0 {
stack!().push(0)
} else {
stack!().push(a.wrapping_div(b));
}
}
}
0x1c => {
if SHORT {
let a = pop_short::<KEEP>(stack!(), &mut popped);
let b = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(a & b);
} else {
let a = pop::<KEEP>(stack!(), &mut popped);
let b = pop::<KEEP>(stack!(), &mut popped);
stack!().push(a & b);
}
}
0x1d => {
if SHORT {
let a = pop_short::<KEEP>(stack!(), &mut popped);
let b = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(a | b);
} else {
let a = pop::<KEEP>(stack!(), &mut popped);
let b = pop::<KEEP>(stack!(), &mut popped);
stack!().push(a | b);
}
}
0x1e => {
if SHORT {
let a = pop_short::<KEEP>(stack!(), &mut popped);
let b = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short(a ^ b);
} else {
let a = pop::<KEEP>(stack!(), &mut popped);
let b = pop::<KEEP>(stack!(), &mut popped);
stack!().push(a ^ b);
}
}
0x1f => {
let shift = pop::<KEEP>(stack!(), &mut popped);
let shift_right = 0x0f & shift;
let shift_left = (0xf0 & shift) >> 4;
if SHORT {
let v = pop_short::<KEEP>(stack!(), &mut popped);
stack!().push_short((v >> shift_right) << shift_left)
} else {
let v = pop::<KEEP>(stack!(), &mut popped);
stack!().push((v >> shift_right) << shift_left)
}
}
_ => {}
}
Some(program_counter)
}