use super::super::State;
use super::{Pin, PinType, Chip};
use std::cell::RefCell;
use std::rc::Rc;
pub struct SimpleCPU {
pin: [Rc<RefCell<Pin>>; 26],
program_counter: u16,
accumulator: u8,
stack_bank: u8,
stack_pointer: u8,
reg_b: u8,
reg_c: u8,
reg_h: u8,
reg_l: u8,
flag_zero: bool,
flag_neg: bool,
flag_carry: bool,
flag_overflow: bool,
current_opcode: u8,
param_first: u8,
param_second: u8,
microcode_state: u8,
executing: bool,
initializing: bool,
halted: bool
}
impl Default for SimpleCPU {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for SimpleCPU {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
fmt.write_str(format!("PC: {:03X}\tADR: {:03X}\tIO: {:02X}\tOp: {:02X}\t$1: {:02X}\t$2: {:02X}\tA: {:02X}\tB: {:02X}\tC: {:02X}\tH: {:02X}\tL: {:02X}\tSP: {:02X}\tmc: {}\texec: {}", self.program_counter, self.get_address(), self.get_data(), self.current_opcode, self.param_first, self.param_second, self.accumulator, self.reg_b, self.reg_c, self.reg_h, self.reg_l, self.stack_pointer, self.microcode_state, self.executing).as_str())?;
Ok(())
}
}
impl SimpleCPU {
pub const A0: u8 = 1;
pub const A1: u8 = 2;
pub const A2: u8 = 3;
pub const A3: u8 = 4;
pub const A4: u8 = 5;
pub const A5: u8 = 6;
pub const A6: u8 = 7;
pub const A7: u8 = 8;
pub const A8: u8 = 9;
pub const A9: u8 = 10;
pub const A10: u8 = 11;
pub const A11: u8 = 12;
pub const CLOCK: u8 = 14;
pub const RESET: u8 = 15;
pub const IRQ: u8 = 16;
pub const IO0: u8 = 17;
pub const IO1: u8 = 18;
pub const IO2: u8 = 19;
pub const IO3: u8 = 20;
pub const IO4: u8 = 21;
pub const IO5: u8 = 22;
pub const IO6: u8 = 23;
pub const IO7: u8 = 24;
pub const RW: u8 = 25;
pub const VCC: u8 = 26;
pub const GND: u8 = 13;
pub fn new() -> Self {
SimpleCPU {
pin: [
Rc::new(RefCell::new(Pin::new(1, PinType::Output))),
Rc::new(RefCell::new(Pin::new(2, PinType::Output))),
Rc::new(RefCell::new(Pin::new(3, PinType::Output))),
Rc::new(RefCell::new(Pin::new(4, PinType::Output))),
Rc::new(RefCell::new(Pin::new(5, PinType::Output))),
Rc::new(RefCell::new(Pin::new(6, PinType::Output))),
Rc::new(RefCell::new(Pin::new(7, PinType::Output))),
Rc::new(RefCell::new(Pin::new(8, PinType::Output))),
Rc::new(RefCell::new(Pin::new(9, PinType::Output))),
Rc::new(RefCell::new(Pin::new(10, PinType::Output))),
Rc::new(RefCell::new(Pin::new(11, PinType::Output))),
Rc::new(RefCell::new(Pin::new(12, PinType::Output))),
Rc::new(RefCell::new(Pin::new(13, PinType::Input))),
Rc::new(RefCell::new(Pin::new(14, PinType::Input))),
Rc::new(RefCell::new(Pin::new(15, PinType::Input))),
Rc::new(RefCell::new(Pin::new(16, PinType::Input))),
Rc::new(RefCell::new(Pin::new(17, PinType::Input))),
Rc::new(RefCell::new(Pin::new(18, PinType::Input))),
Rc::new(RefCell::new(Pin::new(19, PinType::Input))),
Rc::new(RefCell::new(Pin::new(20, PinType::Input))),
Rc::new(RefCell::new(Pin::new(21, PinType::Input))),
Rc::new(RefCell::new(Pin::new(22, PinType::Input))),
Rc::new(RefCell::new(Pin::new(23, PinType::Input))),
Rc::new(RefCell::new(Pin::new(24, PinType::Input))),
Rc::new(RefCell::new(Pin::new(25, PinType::Output))),
Rc::new(RefCell::new(Pin::new(26, PinType::Input)))
],
program_counter: 0,
accumulator: 0,
stack_bank: 0,
stack_pointer: 0,
reg_b: 0,
reg_c: 0,
reg_h: 0,
reg_l: 0,
flag_zero: false,
flag_neg: false,
flag_carry: false,
flag_overflow: false,
current_opcode: 0,
param_first: 0,
param_second: 0,
microcode_state: 0,
executing: false,
initializing: true,
halted: false
}
}
fn get_address(&self) -> u16 {
let mut addr: u16 = 0;
for i in 0..12 {
let bit = if self.pin[i].borrow().state == State::High {1} else {0};
addr += bit << i;
}
addr
}
fn set_address(&mut self, addr: u16) {
let mut addr = addr;
if addr > 0xFFF {
addr = 0;
}
for i in 0..12 {
self.pin[i].borrow_mut().state = State::from_u16(addr, i);
}
}
fn get_data(&self) -> u8 {
let mut addr: u8 = 0;
for i in 16..24 {
let bit = if self.pin[i].borrow().state == State::High {1} else {0};
addr += bit << (i-16);
}
addr
}
fn set_data(&mut self, data: u8) {
for i in 0..8 {
let mut pin = self.pin[i+16].borrow_mut();
pin.pin_type = PinType::Output;
pin.state = State::from_u8(data, i);
}
self.pin[24].borrow_mut().state = State::Low;
}
fn set_iopin_type(&mut self, pin_type: PinType) {
for i in 0..8 {
self.pin[i+16].borrow_mut().pin_type = pin_type.clone();
}
self.pin[24].borrow_mut().state = match pin_type {
PinType::Input => State::High,
PinType::Output => State::Low,
PinType::Undefined => State::Undefined
}
}
fn boot(&mut self){
match self.microcode_state {
0 => {
self.program_counter = 0x00;
self.stack_pointer = 0;
self.accumulator = 0;
self.reg_b = 0;
self.reg_c = 0;
self.reg_h = 0;
self.reg_l = 0;
self.set_address(0xFFD);
},
1 => {
self.program_counter += (self.get_data() as u16) << 8;
self.program_counter &= 0xFFF;
self.set_address(0xFFE);
},
2 => {
self.program_counter += self.get_data() as u16;
self.set_address(0xFFF);
},
3 => {
self.stack_bank = self.get_data();
self.stack_pointer = 0xFF;
self.initializing = false;
self.microcode_state = 0xFF;
},
_ => {
self.initializing = false;
self.microcode_state = 0xFF;
}
}
}
fn execute(&mut self) {
self.executing = false;
let mut check_zero = true;
let push_stack = |myself: &mut SimpleCPU, data: u8| {
let sp = (((myself.stack_bank as u16) << 8) + myself.stack_pointer as u16) & 0xFFF;
myself.set_address(sp);
myself.set_data(data);
myself.stack_pointer = myself.stack_pointer.wrapping_sub(1);
if myself.stack_pointer == 0 {
myself.flag_overflow = true;
}
};
let req_pull_stack = |myself: &mut SimpleCPU| {
myself.stack_pointer = myself.stack_pointer.wrapping_add(1);
let sp = (((myself.stack_bank as u16) << 8) + myself.stack_pointer as u16) & 0xFFF;
if myself.stack_pointer == 0xFF {
myself.flag_neg = false;
}
myself.set_address(sp);
};
match self.current_opcode {
0x00 => {
self.halted = true;
},
0x01 => {
self.accumulator = self.accumulator.wrapping_add(1);
if self.accumulator == 0 {
self.flag_overflow = true;
self.flag_neg = false;
}
}
0x02 => {
self.accumulator = self.accumulator.wrapping_sub(1);
if self.accumulator == 0xFF {
self.flag_overflow = false;
self.flag_neg = true;
}
},
0x03 => {
let mut hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
hl = hl.wrapping_add(1);
if hl == 0 {
self.flag_overflow = true;
self.flag_neg = false;
}
self.reg_h = (hl >> 8) as u8;
self.reg_l = (hl & 0xFF) as u8;
},
0x04 => {
let mut hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
hl = hl.wrapping_sub(1);
if hl == 0xFFFF {
self.flag_overflow = false;
self.flag_neg = true;
}
self.reg_h = (hl >> 8) as u8;
self.reg_l = (hl & 0xFF) as u8;
},
0x05 => {
self.flag_carry = false;
},
0x06 => {
let add = self.accumulator as u16 + self.reg_b as u16;
if add > u8::MAX as u16 {
self.flag_carry = true;
self.flag_overflow = true;
}
self.accumulator = self.accumulator.wrapping_add(self.reg_b);
},
0x07 => {
let add = self.accumulator as u16 + self.reg_c as u16;
if add > u8::MAX as u16 {
self.flag_carry = true;
self.flag_overflow = true;
}
self.accumulator = self.accumulator.wrapping_add(self.reg_c);
},
0x08 => {
self.reg_b = self.accumulator;
},
0x09 => {
self.accumulator = self.reg_b;
},
0x0A => {
self.reg_c = self.accumulator;
},
0x0B => {
self.accumulator = self.reg_c;
},
0x0C => {
self.reg_h = self.accumulator;
},
0x0D => {
self.accumulator = self.reg_h;
},
0x0E => {
self.reg_l = self.accumulator;
},
0x0F => {
self.accumulator = self.reg_l;
},
0x10 => {
push_stack(self, self.accumulator);
},
0x11 => {
match self.microcode_state {
0 => {
req_pull_stack(self);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
}
_ => {}
}
},
0x12 => {
match self.microcode_state {
0 => {
push_stack(self, self.reg_l);
self.executing = true;
},
1 => {
push_stack(self, self.reg_h)
}
_ => {}
}
},
0x13 => {
match self.microcode_state {
0 => {
req_pull_stack(self);
self.executing = true;
},
1 => {
self.reg_h = self.get_data();
req_pull_stack(self);
self.executing = true;
},
2 => {
self.reg_l = self.get_data();
},
_ => {}
}
},
0x14 => {
check_zero = false;
let compare = self.accumulator as i16 - self.reg_b as i16;
self.flag_zero = compare == 0;
self.flag_neg = compare < 0;
},
0x15 => {
check_zero = false;
let compare = self.accumulator as i16 - self.reg_c as i16;
self.flag_zero = compare == 0;
self.flag_neg = compare < 0;
},
0x16 => {
let sub = self.accumulator as i16 - self.reg_b as i16;
self.flag_neg = sub < 0;
self.accumulator -= self.reg_b;
},
0x17 => {
let sub = self.accumulator as i16 - self.reg_c as i16;
self.flag_neg = sub < 0;
self.accumulator -= self.reg_c;
},
0x18 => {
self.accumulator <<= 1;
},
0x19 => {
self.accumulator >>= 1;
}
0x1A => {
self.reg_b = self.reg_b.wrapping_add(1);
if self.reg_b == 0 {
self.flag_overflow = true;
self.flag_neg = false;
}
}
0x1B => {
self.reg_b = self.reg_b.wrapping_sub(1);
if self.reg_b == 0xFF {
self.flag_overflow = false;
self.flag_neg = true;
}
},
0x1C => {
self.reg_c = self.reg_c.wrapping_add(1);
if self.reg_c == 0 {
self.flag_overflow = true;
self.flag_neg = false;
}
}
0x1D => {
self.reg_c = self.reg_c.wrapping_sub(1);
if self.reg_c == 0xFF {
self.flag_overflow = false;
self.flag_neg = true;
}
},
0x20 => {
self.program_counter = ((self.reg_h as u16) << 8) + self.reg_l as u16;
},
0x21 => {
match self.microcode_state {
0 => {
let addr_l = (self.program_counter & 0xFF) as u8;
push_stack(self, addr_l);
self.executing = true;
},
1 => {
let addr_h = (self.program_counter >> 8) as u8;
push_stack(self, addr_h);
self.program_counter = ((self.reg_h as u16) << 8) + self.reg_l as u16;
},
_ => {}
}
},
0x22 => {
match self.microcode_state {
0 => {
req_pull_stack(self);
self.executing = true;
},
1 => {
self.program_counter = 0;
self.program_counter += (self.get_data() as u16) << 8;
self.program_counter &= 0xFFF;
req_pull_stack(self);
self.executing = true;
},
2 => {
self.program_counter += self.get_data() as u16;
}
_ => {}
}
},
0x48 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl);
self.set_data(self.accumulator);
},
0x49 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl);
self.set_data(self.reg_b);
},
0x4A => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl);
self.set_data(self.reg_c);
},
0x4B => {
match self.microcode_state {
0 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl);
self.executing = true;
},
1 => {
self.reg_b = self.get_data();
},
_ => {}
}
},
0x4C => {
match self.microcode_state {
0 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl);
self.executing = true;
},
1 => {
self.reg_c = self.get_data();
},
_ => {}
}
},
0x4D => {
match self.microcode_state {
0 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
},
_ => {}
}
},
0x4E => {
match self.microcode_state {
0 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl + self.reg_b as u16);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
},
_ => {}
}
},
0x4F => {
match self.microcode_state {
0 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl + self.reg_c as u16);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
},
_ => {}
}
},
0x50 => {
self.accumulator = self.param_first;
},
0x51 => {
match self.microcode_state {
0 => {
self.set_address(self.param_first as u16);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
},
_ => {}
}
},
0x52 => {
match self.microcode_state {
0 => {
let h0 = (self.reg_h as u16) << 8;
self.set_address(h0 + self.param_first as u16);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
},
_ => {}
}
},
0x53 => {
match self.microcode_state {
0 => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl + self.param_first as u16);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
},
_ => {}
}
},
0x54 => {
self.reg_b = self.param_first
}
0x55 => {
match self.microcode_state {
0 => {
self.set_address(self.param_first as u16);
self.executing = true;
},
1 => {
self.reg_b = self.get_data();
},
_ => {}
}
},
0x56 => {
self.reg_c = self.param_first
}
0x57 => {
match self.microcode_state {
0 => {
self.set_address(self.param_first as u16);
self.executing = true;
},
1 => {
self.reg_c = self.get_data();
},
_ => {}
}
},
0x58 => {
self.set_address(self.param_first as u16);
self.set_data(self.accumulator);
},
0x59 => {
let h0 = (self.reg_h as u16) << 8;
self.set_address(h0 + self.param_first as u16);
self.set_data(self.accumulator);
},
0x5A => {
let hl = ((self.reg_h as u16) << 8) + self.reg_l as u16;
self.set_address(hl + self.param_first as u16);
self.set_data(self.accumulator);
},
0x5B => {
self.set_address(self.param_first as u16);
self.set_data(self.reg_b);
},
0x5C => {
self.set_address(self.param_first as u16);
self.set_data(self.reg_c);
},
0x60 => {
check_zero = false;
let compare = self.accumulator as i16 - self.param_first as i16;
self.flag_zero = compare == 0;
self.flag_neg = compare < 0;
}
0x61 => {
check_zero = false;
let compare = self.reg_b as i16 - self.param_first as i16;
self.flag_zero = compare == 0;
self.flag_neg = compare < 0;
}
0x62 => {
check_zero = false;
let compare = self.reg_c as i16 - self.param_first as i16;
self.flag_zero = compare == 0;
self.flag_neg = compare < 0;
}
0xB0 => {
self.program_counter = ((self.param_first as u16) << 8) + self.param_second as u16;
},
0xB1 => {
match self.microcode_state {
0 => {
let addr_l = (self.program_counter & 0xFF) as u8;
push_stack(self, addr_l);
self.executing = true;
},
1 => {
let addr_h = (self.program_counter >> 8) as u8;
push_stack(self, addr_h);
self.program_counter = ((self.param_first as u16) << 8) + self.param_second as u16;
},
_ => {}
}
},
0xB2 => {
if self.flag_carry {
self.program_counter = ((self.param_first as u16) << 8) + self.param_second as u16;
}
},
0xB3 => {
if self.flag_neg {
self.program_counter = ((self.param_first as u16) << 8) + self.param_second as u16;
}
},
0xB4 => {
if self.flag_zero {
self.program_counter = ((self.param_first as u16) << 8) + self.param_second as u16;
}
},
0xC0 => {
match self.microcode_state {
0 => {
self.set_address(((self.param_first as u16) << 8) + self.param_second as u16);
self.executing = true;
},
1 => {
self.accumulator = self.get_data();
},
_ => {}
}
},
0xC1 => {
self.set_address(self.param_first as u16);
self.set_data(self.accumulator);
}
_ => {}
}
if check_zero {
self.flag_zero = self.accumulator == 0;
}
if !self.executing {
self.microcode_state = 0xFF;
}
}
}
impl Chip for SimpleCPU {
fn get_pin_qty(&self) -> u8 {
26
}
fn get_pin(&mut self, pin: u8) -> Result<Rc<RefCell<Pin>>, &str> {
if pin > 0 && pin <= 26 {
Ok(self.pin[pin as usize-1].clone())
} else {
Err("Pin out of bounds")
}
}
fn run(&mut self, _: std::time::Duration) {
if self.pin[14].borrow().state == State::Low {
self.initializing = true;
self.microcode_state = 0;
self.halted = false;
}
if self.pin[12].borrow().state == State::Low && self.pin[25].borrow().state == State::High {
if self.pin[13].borrow().state == State::High && !self.halted {
self.set_iopin_type(PinType::Input);
if self.initializing {
self.boot();
} else if self.executing {
self.execute();
} else {
let launch_execution = |myself: &mut SimpleCPU| {
myself.executing = true;
myself.microcode_state = 0xFF;
};
match self.microcode_state {
0 => {
self.set_address(self.program_counter);
self.current_opcode = 0;
self.param_first = 0;
self.param_second = 0;
},
1 => {
self.current_opcode = self.get_data();
self.program_counter += 1;
if self.current_opcode >= 0x50 {
self.set_address(self.program_counter);
} else {
launch_execution(self);
}
},
2 => {
if self.current_opcode >= 0x50 {
self.param_first = self.get_data();
self.program_counter += 1;
if self.current_opcode >= 0xB0 {
self.set_address(self.program_counter);
} else {
launch_execution(self);
}
}
},
3 => {
if self.current_opcode >= 0xB0 {
self.param_second = self.get_data();
self.program_counter += 1;
}
launch_execution(self);
},
_ => {}
}
}
self.microcode_state = self.microcode_state.wrapping_add(1);
if self.program_counter > 0xFFF {
self.program_counter = 0;
}
}
} else {
for i in 0..22 {
self.pin[i].borrow_mut().state = State::Undefined
}
self.initializing = true;
}
}
}