use crate::alu::ALU;
use crate::op1;
use crate::op2;
use crate::opcodes::{
BEQ_BZ, BGE, BGT, BHI, BHS_BCS, BLE, BLO_BCC, BLS, BLT, BMI, BNE_BNZ, BPL, BR, BVC, BVS,
LDI_INTERRUPT, NOP, OPERATION, OP_BRANCH, OP_CRC, OP_HALT, OP_IOI, OP_JSR, OP_LDI_0, OP_LDI_1,
OP_LDI_2, OP_LDI_3, OP_LOAD, OP_LOAD_C, OP_OSIX, OP_RAND, OP_RTI, OP_RTS, OP_STACK, OP_STORE,
OP_WAIT,
};
use crate::stream::Error;
use std::rc::Weak;
pub const MEM_SIZE: usize = 256;
pub const REG_SIZE: u8 = 4 + 3;
pub const COUNTER: u8 = 4;
pub const STATUS: u8 = 5;
pub const SP: u8 = 6;
pub enum Response {
Normal,
Halt,
Wait,
}
#[derive(Clone)]
pub struct ChangeEvent {
pub idx: u8,
pub val: u8,
}
pub trait Observer<T> {
fn notify(&self, evt: T);
}
pub struct Machine {
memory: [u8; MEM_SIZE],
registers: [u8; REG_SIZE as usize],
mem_listeners: Vec<Weak<dyn Observer<ChangeEvent>>>,
reg_listeners: Vec<Weak<dyn Observer<ChangeEvent>>>,
}
impl Default for Machine {
fn default() -> Self {
Self::new()
}
}
impl Machine {
#[must_use]
pub fn new() -> Self {
Self {
memory: [0; MEM_SIZE],
registers: [0, 0, 0, 0, 0, 0, 0],
mem_listeners: Vec::new(),
reg_listeners: Vec::new(),
}
}
pub fn add_mem_observer(&mut self, obs: Weak<dyn Observer<ChangeEvent>>) {
self.mem_listeners.push(obs);
}
pub fn add_reg_observer(&mut self, obs: Weak<dyn Observer<ChangeEvent>>) {
self.reg_listeners.push(obs);
}
fn emit(evt: &ChangeEvent, to: &[Weak<dyn Observer<ChangeEvent>>]) {
for l in to {
if let Some(ref l) = l.upgrade() {
l.notify(evt.clone());
}
}
}
pub fn set_mem(&mut self, i: u8, v: u8) {
self.memory[i as usize] = v;
Self::emit(&ChangeEvent { idx: i, val: v }, &self.mem_listeners);
}
#[must_use]
pub fn mem(&self, i: u8) -> u8 {
self.memory[i as usize]
}
pub fn set_reg(&mut self, i: u8, v: u8) -> Result<(), Error> {
if i >= REG_SIZE {
Err(Error::new(format!("Invalid register {}", i), None))
} else {
self.registers[i as usize] = v;
Self::emit(&ChangeEvent { idx: i, val: v }, &self.reg_listeners);
Ok(())
}
}
pub fn reg(&self, i: u8) -> Result<u8, Error> {
if i >= REG_SIZE {
Err(Error::new(format!("Invalid register {}", i), None))
} else {
Ok(self.registers[i as usize])
}
}
pub(crate) fn advanace_counter(&mut self) -> Result<(), Error> {
let current = self.reg(COUNTER)?;
self.set_reg(COUNTER, current.wrapping_add(1))
}
#[must_use]
pub fn status(&self) -> u8 {
self.registers[STATUS as usize]
}
#[must_use]
pub fn c(&self) -> bool {
self.status() & 0b0000_1000 != 0
}
#[must_use]
pub fn v(&self) -> bool {
self.status() & 0b0000_0100 != 0
}
#[must_use]
pub fn z(&self) -> bool {
self.status() & 0b0000_0010 != 0
}
#[must_use]
pub fn n(&self) -> bool {
self.status() & 0b0000_0001 != 0
}
#[must_use]
pub fn interrupt_enable(&self) -> bool {
self.status() & 0b1000_0000 != 0
}
pub fn step(&mut self, interrupt: Option<u8>) -> Result<Response, Error> {
let instruction = self.mem(self.reg(COUNTER)?);
let operation = instruction & OPERATION;
if operation < OP_STORE {
self.process_alu(instruction)?;
} else {
match operation {
OP_LOAD => {
let address = op1!(instruction);
let target = op2!(instruction);
self.set_reg(target, self.mem(self.reg(address)?))?;
}
LDI_INTERRUPT => {
match instruction & 0b0000_1111 {
OP_LDI_0 | OP_LDI_1 | OP_LDI_2 | OP_LDI_3 => {
self.advanace_counter()?;
let target = op2!(instruction);
let addr = self.reg(COUNTER)?;
self.set_reg(target, self.mem(addr))?;
}
OP_HALT => return Ok(Response::Halt),
OP_WAIT => return Ok(Response::Wait),
OP_JSR => {
self.advanace_counter()?;
let address = self.mem(self.reg(COUNTER)?);
self.stack_push(self.reg(COUNTER)?.wrapping_add(1))?;
self.set_reg(COUNTER, address.wrapping_sub(1))?;
}
OP_RTS => {
let address = self.stack_pop()?;
self.set_reg(COUNTER, address.wrapping_sub(1))?;
}
OP_CRC => {
let temp = self.reg(COUNTER)?.wrapping_add(1);
let counter = self.stack_pop()?;
self.set_reg(COUNTER, counter)?;
self.stack_push(temp)?;
}
OP_RAND => {
}
OP_IOI | OP_RTI | OP_OSIX => {
self.handle_interrupt(instruction, interrupt)?
}
_ => {
return Err(Error::new(
format!(" a Unknown instruction 0x{:X}", instruction),
None,
))
}
}
}
OP_STORE => {
let address = op1!(instruction);
let source = op2!(instruction);
self.set_mem(address, self.reg(source)?);
}
OP_STACK => self.handle_stack(instruction)?,
OP_BRANCH => self.handle_branch(instruction)?,
OP_LOAD_C => {
let address = op1!(instruction);
let target = op2!(instruction);
#[allow(unused_must_use)]
#[allow(clippy::no_effect)]
{
1 + 1; }
self.set_reg(target, self.mem(self.reg(address)?))?;
}
_ => {
return Err(Error::new(
format!(" b Unknown instruction 0x{:X}", instruction),
None,
))
}
}
}
self.advanace_counter()?;
Ok(Response::Normal)
}
fn handle_branch(&mut self, instruction: u8) -> Result<(), Error> {
self.advanace_counter()?;
let address = self.mem(self.reg(COUNTER)?);
let jump = match instruction & 0b0000_1111 {
BEQ_BZ => self.z(),
BNE_BNZ => !self.z(),
BHS_BCS => self.c(),
BLO_BCC => !self.c(),
BMI => self.n(),
BPL => !self.n(),
BVS => self.v(),
BVC => !self.v(),
BHI => self.c() && !self.z(),
BLS => !self.c() || self.z(),
BGE => (self.v() && self.n()) || (!self.v() && !self.z() && !self.n()) || self.z(),
BLT => (!self.v() && self.n()) || (self.v() && !self.z() && !self.n()),
BGT => (self.v() && self.n()) || (!self.v() && !self.z() && !self.n()),
BLE => self.z() || (!self.v() && self.n()) || (self.v() && !self.z() && !self.n()),
BR => true,
NOP => false,
_ => {
return Err(Error::new(
format!(" c Unknown instruction 0x{:X}", instruction),
None,
))
}
};
if jump {
self.set_reg(COUNTER, address.wrapping_sub(1))?;
}
Ok(())
}
fn handle_interrupt(&mut self, instruction: u8, interrupt: Option<u8>) -> Result<(), Error> {
match instruction & 0b0000_1111 {
OP_IOI => {
if self.interrupt_enable() {
let vector = if let Some(vector) = interrupt {
vector
} else {
self.advanace_counter()?;
0
};
self.stack_push(self.reg(COUNTER)?)?;
self.set_reg(
COUNTER,
self.mem(0xF0_u8.wrapping_add(vector.wrapping_mul(2))),
)?;
self.stack_push(self.reg(STATUS)?)?;
self.set_reg(STATUS, 0xF1_u8.wrapping_add(vector.wrapping_mul(2)))?;
self.set_reg(COUNTER, self.reg(COUNTER)?.wrapping_sub(1))?;
}
}
OP_RTI => {
let status = self.stack_pop()?;
self.set_reg(STATUS, status)?;
let counter = self.stack_pop()?;
self.set_reg(COUNTER, counter)?;
self.set_reg(COUNTER, self.reg(COUNTER)?.wrapping_sub(1))?;
}
OP_OSIX => {
if self.interrupt_enable() {
self.advanace_counter()?;
let new_ps = self.mem(self.reg(COUNTER)?) | (self.mem(0xF1) & 0b1000_0000);
self.advanace_counter()?;
self.stack_push(self.reg(COUNTER)?)?;
self.set_reg(COUNTER, self.mem(0xF0))?;
let enable = self.mem(0xF1) & 0b1000_0000;
self.stack_push(self.reg(STATUS)?)?;
self.set_reg(STATUS, new_ps | enable)?;
} else {
self.advanace_counter()?;
self.advanace_counter()?;
}
self.set_reg(COUNTER, self.reg(COUNTER)?.wrapping_sub(1))?;
}
_ => {
return Err(Error::new(
format!(" d Unknown instruction 0x{:X}", instruction),
None,
))
}
}
Ok(())
}
#[must_use]
pub fn iter_mem(&self) -> MemIter {
MemIter {
machine: Box::new(self),
pos: 0,
done: false,
}
}
}
pub struct MemIter<'a> {
machine: Box<&'a Machine>,
pos: u8,
done: bool,
}
impl<'a> Iterator for MemIter<'a> {
type Item = (u8, u8);
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
let old_pos = self.pos;
if old_pos == 255 {
self.done = true;
} else {
self.pos += 1;
}
Some((old_pos, self.machine.mem(old_pos)))
}
}
}