use super::{Chip, ChipInfo, Pin, PinType};
use crate::State;
use std::cell::RefCell;
use std::rc::Rc;
pub struct SimpleCPU {
uuid: u128,
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::string::ToString for SimpleCPU {
fn to_string(&self) -> std::string::String {
format!("PC: {:03X} ADR: {:03X} IO: {:02X} Op: {:02X} $1: {:02X} $2: {:02X}
A: {:02X} B: {:02X} C: {:02X} H: {:02X} L: {:02X} SP: {:02X}
mc: {} exec: {} halted: {}", 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, self.halted)
}
}
impl SimpleCPU {
pub const TYPE: &'static str = "virt_ic::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 {
let uuid = uuid::Uuid::new_v4().as_u128();
SimpleCPU {
uuid,
pin: [
Rc::new(RefCell::new(Pin::new(uuid, 1, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 2, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 3, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 4, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 5, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 6, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 7, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 8, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 9, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 10, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 11, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 12, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 13, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 14, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 15, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 16, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 17, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 18, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 19, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 20, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 21, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 22, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 23, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 24, PinType::Input))),
Rc::new(RefCell::new(Pin::new(uuid, 25, PinType::Output))),
Rc::new(RefCell::new(Pin::new(uuid, 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_uuid(&self) -> u128 {
self.uuid
}
fn get_type(&self) -> &str {
Self::TYPE
}
fn get_pin_qty(&self) -> u8 {
26
}
fn _get_pin(&mut self, pin: u8) -> Rc<RefCell<Pin>> {
self.pin[pin as usize - 1].clone()
}
fn get_info(&self) -> ChipInfo {
ChipInfo {
name: "Simple CPU",
description: "A fictionnal CPU created for Virt-IC.",
data: self.to_string()
}
}
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;
}
}
fn save_data(&self) -> Vec<String> {
vec![
ron::to_string(&(
self.accumulator,
self.reg_b,
self.reg_c,
self.reg_h,
self.reg_l,
))
.unwrap(),
ron::to_string(&(
self.flag_zero,
self.flag_neg,
self.flag_carry,
self.flag_overflow,
))
.unwrap(),
ron::to_string(&(
self.program_counter,
self.stack_bank,
self.stack_pointer,
self.current_opcode,
self.param_first,
self.param_second,
))
.unwrap(),
ron::to_string(&(
self.microcode_state,
self.executing,
self.initializing,
self.halted,
))
.unwrap(),
]
}
fn load_data(&mut self, chip_data: &[String]) {
let registers: (u8, u8, u8, u8, u8) = ron::from_str(&chip_data[0]).unwrap();
let flags: (bool, bool, bool, bool) = ron::from_str(&chip_data[1]).unwrap();
let exec: (u16, u8, u8, u8, u8, u8) = ron::from_str(&chip_data[2]).unwrap();
let internal: (u8, bool, bool, bool) = ron::from_str(&chip_data[3]).unwrap();
self.accumulator = registers.0;
self.reg_b = registers.1;
self.reg_c = registers.2;
self.reg_h = registers.3;
self.reg_l = registers.4;
self.flag_zero = flags.0;
self.flag_neg = flags.1;
self.flag_carry = flags.2;
self.flag_overflow = flags.3;
self.program_counter = exec.0;
self.stack_bank = exec.1;
self.stack_pointer = exec.2;
self.current_opcode = exec.3;
self.param_first = exec.4;
self.param_second = exec.5;
self.microcode_state = internal.0;
self.executing = internal.1;
self.initializing = internal.2;
self.halted = internal.3;
}
}