diff --git a/ic10emu/src/errors.rs b/ic10emu/src/errors.rs index 491de72..1b74d5b 100644 --- a/ic10emu/src/errors.rs +++ b/ic10emu/src/errors.rs @@ -208,6 +208,14 @@ pub enum ICError { BadGeneratedValueParse(String, String), #[error("IC with id {0} is not sloted into a circuit holder")] NoCircuitHolder(ObjectID), + #[error("object {0} is not slot writeable")] + NotSlotWriteable(ObjectID), + #[error("object {0} does not use reagents ")] + NotReagentReadable(ObjectID), + #[error("{0} is not a valid number of sleep seconds")] + SleepDurationError(f64), + #[error("{0} can not be added to {1} ")] + SleepAddtionError(time::Duration, time::OffsetDateTime), } impl ICError { diff --git a/ic10emu/src/interpreter.rs b/ic10emu/src/interpreter.rs index f2566c8..7f683d0 100644 --- a/ic10emu/src/interpreter.rs +++ b/ic10emu/src/interpreter.rs @@ -1,10 +1,5 @@ use core::f64; use serde_derive::{Deserialize, Serialize}; -use std::{ - cell::{Cell, RefCell}, - ops::Deref, - string::ToString, -}; use std::{ collections::{BTreeMap, HashSet}, fmt::Display, @@ -18,22 +13,9 @@ use time::format_description; use crate::{ errors::{ICError, LineError}, grammar, - vm::{ - enums::{ - basic_enums::Class as SlotClass, - script_enums::{LogicSlotType, LogicType}, - }, - instructions::{ - enums::InstructionOp, - operands::{DeviceSpec, Operand, RegisterSpec}, - Instruction, - }, - VM, - }, + vm::instructions::{enums::InstructionOp, Instruction}, }; -use serde_with::serde_as; - pub mod instructions; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -42,8 +24,9 @@ pub enum ICState { Running, Yield, Sleep(time::OffsetDateTime, f64), - HasCaughtFire, Error(LineError), + HasCaughtFire, + Ended, } impl Display for ICState { @@ -51,7 +34,7 @@ impl Display for ICState { let out = match self { ICState::Start => "Not Run".to_owned(), ICState::Running => "Running".to_owned(), - ICState::Yield => "Ic has yielded, Resume on next tick".to_owned(), + ICState::Yield => "IC has yielded, Resume on next tick".to_owned(), ICState::Sleep(then, sleep_for) => { let format = format_description::parse("[hour]:[minute]:[second]").unwrap(); let resume = *then + time::Duration::new(*sleep_for as i64, 0); @@ -62,88 +45,12 @@ impl Display for ICState { } ICState::Error(err) => format!("{err}"), ICState::HasCaughtFire => "IC has caught fire! this is not a joke!".to_owned(), + ICState::Ended => "Program has reached the end of exacution".to_owned(), }; write!(f, "{out}") } } -#[derive(Debug)] -pub struct IC { - pub device: u32, - pub id: u32, - pub registers: RefCell<[f64; 18]>, - /// Instruction Pointer - pub ip: Cell, - /// Instruction Count since last yield - pub ic: Cell, - pub stack: RefCell<[f64; 512]>, - pub aliases: RefCell>, - pub defines: RefCell>, - pub pins: RefCell<[Option; 6]>, - pub code: RefCell, - pub program: RefCell, - pub state: RefCell, -} - -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct FrozenIC { - pub device: u32, - pub id: u32, - pub registers: [f64; 18], - /// Instruction Pointer - pub ip: u32, - /// Instruction Count since last yield - pub ic: u16, - #[serde_as(as = "[_; 512]")] - pub stack: [f64; 512], - pub aliases: BTreeMap, - pub defines: BTreeMap, - pub pins: [Option; 6], - pub state: ICState, - pub code: String, -} - -impl From for FrozenIC -where - T: Deref, -{ - fn from(ic: T) -> Self { - FrozenIC { - device: ic.device, - id: ic.id, - registers: *ic.registers.borrow(), - ip: ic.ip.get(), - ic: ic.ic.get(), - stack: *ic.stack.borrow(), - aliases: ic.aliases.borrow().clone(), - defines: ic.defines.borrow().clone(), - pins: *ic.pins.borrow(), - state: ic.state.borrow().clone(), - code: ic.code.borrow().clone(), - } - } -} - -impl From for IC { - fn from(value: FrozenIC) -> Self { - IC { - device: value.device, - id: value.id, - registers: RefCell::new(value.registers), - ip: Cell::new(value.ip), - ic: Cell::new(value.ic), - stack: RefCell::new(value.stack), - aliases: RefCell::new(value.aliases), - defines: RefCell::new(value.defines), - pins: RefCell::new(value.pins), - state: RefCell::new(value.state), - code: RefCell::new(value.code.clone()), - program: RefCell::new(Program::from_code_with_invalid(&value.code)), - } - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Program { pub instructions: Vec, @@ -166,6 +73,10 @@ impl Program { } } + pub fn len(&self) -> usize { + self.instructions.len() + } + pub fn try_from_code(code: &str) -> Result { let parse_tree = grammar::parse(code)?; let mut labels_set = HashSet::new(); @@ -255,570 +166,6 @@ impl Program { } } -impl IC { - pub fn new(id: u32, device: u32) -> Self { - IC { - device, - id, - ip: Cell::new(0), - ic: Cell::new(0), - registers: RefCell::new([0.0; 18]), - stack: RefCell::new([0.0; 512]), - pins: RefCell::new([None; 6]), - program: RefCell::new(Program::new()), - code: RefCell::new(String::new()), - aliases: RefCell::new(BTreeMap::new()), - defines: RefCell::new(BTreeMap::new()), - state: RefCell::new(ICState::Start), - } - } - - pub fn reset(&self) { - self.ip.replace(0); - self.ic.replace(0); - self.registers.replace([0.0; 18]); - self.stack.replace([0.0; 512]); - self.aliases.replace(BTreeMap::new()); - self.defines.replace(BTreeMap::new()); - self.state.replace(ICState::Start); - } - - /// Set program code if it's valid - pub fn set_code(&self, code: &str) -> Result<(), ICError> { - let prog = Program::try_from_code(code)?; - self.program.replace(prog); - self.code.replace(code.to_string()); - Ok(()) - } - - /// Set program code and translate invalid lines to Nop, collecting errors - pub fn set_code_invalid(&mut self, code: &str) { - let prog = Program::from_code_with_invalid(code); - self.program.replace(prog); - self.code.replace(code.to_string()); - } - - pub fn get_real_target(&self, indirection: u32, target: u32) -> Result { - let mut i = indirection; - let mut t = target as f64; - while i > 0 { - if let Some(new_t) = self.registers.borrow().get(t as usize) { - t = *new_t; - } else { - return Err(ICError::RegisterIndexOutOfRange(t)); - } - i -= 1; - } - Ok(t) - } - - pub fn get_register(&self, indirection: u32, target: u32) -> Result { - let t = self.get_real_target(indirection, target)?; - self.registers - .borrow() - .get(t as usize) - .ok_or(ICError::RegisterIndexOutOfRange(t)) - .copied() - } - - /// sets a register thorough, recursing through provided indirection, returns value previously - pub fn set_register(&self, indirection: u32, target: u32, val: f64) -> Result { - let t = self.get_real_target(indirection, target)?; - let mut registers = self.registers.borrow_mut(); - let old_val = registers - .get(t as usize) - .ok_or(ICError::RegisterIndexOutOfRange(t)) - .copied()?; - registers[t as usize] = val; - Ok(old_val) - } - - /// save ip to 'ra' or register 18 - fn al(&self) { - self.registers.borrow_mut()[17] = self.ip() as f64 + 1.0; - } - - pub fn push(&self, val: f64) -> Result { - let mut registers = self.registers.borrow_mut(); - let mut stack = self.stack.borrow_mut(); - let sp = (registers[16].round()) as i32; - if sp < 0 { - Err(ICError::StackUnderflow) - } else if sp >= 512 { - Err(ICError::StackOverflow) - } else { - let last = stack[sp as usize]; - stack[sp as usize] = val; - registers[16] += 1.0; - Ok(last) - } - } - - pub fn pop(&self) -> Result { - let mut registers = self.registers.borrow_mut(); - registers[16] -= 1.0; - let sp = (registers[16].round()) as i32; - if sp < 0 { - Err(ICError::StackUnderflow) - } else if sp >= 512 { - Err(ICError::StackOverflow) - } else { - let last = self.stack.borrow()[sp as usize]; - Ok(last) - } - } - - pub fn poke(&self, address: f64, val: f64) -> Result { - let sp = address.round() as i32; - if !(0..512).contains(&sp) { - Err(ICError::StackIndexOutOfRange(address)) - } else { - let mut stack = self.stack.borrow_mut(); - let last = stack[sp as usize]; - stack[sp as usize] = val; - Ok(last) - } - } - - pub fn peek(&self) -> Result { - let sp = (self.registers.borrow()[16] - 1.0).round() as i32; - if sp < 0 { - Err(ICError::StackUnderflow) - } else if sp >= 512 { - Err(ICError::StackOverflow) - } else { - let last = self.stack.borrow()[sp as usize]; - Ok(last) - } - } - - pub fn peek_addr(&self, addr: f64) -> Result { - let sp = (addr) as i32; - if sp < 0 { - Err(ICError::StackUnderflow) - } else if sp >= 512 { - Err(ICError::StackOverflow) - } else { - let last = self.stack.borrow()[sp as usize]; - Ok(last) - } - } - - pub fn propagate_line_number(&self, vm: &VM) { - if let Some(device) = vm.devices.get(&self.device) { - let mut device_ref = device.borrow_mut(); - let _ = device_ref.set_field(LogicType::LineNumber, self.ip.get() as f64, vm, true); - if let Some(slot) = device_ref - .slots - .iter_mut() - .find(|slot| slot.typ == SlotClass::ProgrammableChip) - { - let _ = slot.set_field(LogicSlotType::LineNumber, self.ip.get() as f64, true); - } - } - } - - /// processes one line of the contained program - pub fn step(&self, vm: &VM, advance_ip_on_err: bool) -> Result { - // TODO: handle sleep - self.state.replace(ICState::Running); - let line = self.ip(); - let result = self.internal_step(vm, advance_ip_on_err); - if let Err(error) = result { - let error = LineError { error, line }; - self.state.replace(ICState::Error(error.clone())); - Err(error) - } else { - Ok(true) - } - } - - pub fn ip(&self) -> u32 { - self.ip.get() - } - - pub fn set_ip(&self, val: u32) { - self.ip.replace(val); - } - - fn internal_step(&self, vm: &VM, advance_ip_on_err: bool) -> Result<(), ICError> { - use ICError::*; - - let mut next_ip = self.ip() + 1; - // XXX: This closure should be replaced with a try block - // https://github.com/rust-lang/rust/issues/31436 - let mut process_op = |this: &Self| -> Result<(), ICError> { - use InstructionOp::*; - - // force the program borrow to drop - let line = { - let prog = this.program.borrow(); - prog.get_line(this.ip())?.clone() - }; - let operands = &line.operands; - let inst = line.instruction; - match inst { - Nop => Ok(()), - Hcf => Ok(()), // TODO - Clr => Ok(()), // TODO - Clrd => Ok(()), // TODO - Label => Ok(()), // NOP - - S => match &operands[..] { - [dev, lt, val] => { - let (Some(device_id), connection) = dev.as_device(this, inst, 1)? else { - return Err(DeviceNotSet); - }; - let lt = lt.as_logic_type(this, inst, 2)?; - if CHANNEL_LOGIC_TYPES.contains(<) { - let channel = lt.as_channel().unwrap(); - let Some(connection) = connection else { - return Err(MissingConnectionSpecifier); - }; - let network_id = vm - .get_device_same_network(this.device, device_id) - .map(|device| device.borrow().get_network_id(connection)) - .unwrap_or(Err(UnknownDeviceID(device_id as f64)))?; - let val = val.as_value(this, inst, 3)?; - vm.set_network_channel(network_id, channel, val)?; - return Ok(()); - } - let device = vm.get_device_same_network(this.device, device_id); - match device { - Some(device) => { - let val = val.as_value(this, inst, 1)?; - device.borrow_mut().set_field(lt, val, vm, false)?; - vm.set_modified(device_id); - Ok(()) - } - None => Err(UnknownDeviceID(device_id as f64)), - } - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 3)), - }, - Sd => match &operands[..] { - [dev, lt, val] => { - let device_id = dev.as_value(this, inst, 1)?; - if device_id >= u16::MAX as f64 || device_id < u16::MIN as f64 { - return Err(DeviceIndexOutOfRange(device_id)); - } - let device = vm.get_device_same_network(this.device, device_id as u32); - match device { - Some(device) => { - let lt = lt.as_logic_type(this, inst, 2)?; - let val = val.as_value(this, inst, 3)?; - device.borrow_mut().set_field(lt, val, vm, false)?; - vm.set_modified(device_id as u32); - Ok(()) - } - None => Err(UnknownDeviceID(device_id)), - } - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 3)), - }, - Ss => match &operands[..] { - [dev, index, slt, val] => { - let (Some(device_id), _connection) = dev.as_device(this, inst, 1)? else { - return Err(DeviceNotSet); - }; - let device = vm.get_device_same_network(this.device, device_id); - match device { - Some(device) => { - let index = index.as_value(this, inst, 2)?; - let slt = slt.as_slot_logic_type(this, inst, 3)?; - let val = val.as_value(this, inst, 4)?; - device - .borrow_mut() - .set_slot_field(index, slt, val, vm, false)?; - vm.set_modified(device_id); - Ok(()) - } - None => Err(UnknownDeviceID(device_id as f64)), - } - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 4)), - }, - Sb => match &operands[..] { - [prefab, lt, val] => { - let prefab = prefab.as_value(this, inst, 1)?; - let lt = lt.as_logic_type(this, inst, 2)?; - let val = val.as_value(this, inst, 3)?; - vm.set_batch_device_field(this.device, prefab, lt, val, false)?; - Ok(()) - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 3)), - }, - Sbs => match &operands[..] { - [prefab, index, slt, val] => { - let prefab = prefab.as_value(this, inst, 1)?; - let index = index.as_value(this, inst, 2)?; - let slt = slt.as_slot_logic_type(this, inst, 3)?; - let val = val.as_value(this, inst, 4)?; - vm.set_batch_device_slot_field( - this.device, - prefab, - index, - slt, - val, - false, - )?; - Ok(()) - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 4)), - }, - Sbn => match &operands[..] { - [prefab, name, lt, val] => { - let prefab = prefab.as_value(this, inst, 1)?; - let name = name.as_value(this, inst, 2)?; - let lt = lt.as_logic_type(this, inst, 3)?; - let val = val.as_value(this, inst, 4)?; - vm.set_batch_name_device_field(this.device, prefab, name, lt, val, false)?; - Ok(()) - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 4)), - }, - - L => match &operands[..] { - [reg, dev, lt] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let (Some(device_id), connection) = dev.as_device(this, inst, 2)? else { - return Err(DeviceNotSet); - }; - let lt = lt.as_logic_type(this, inst, 3)?; - if CHANNEL_LOGIC_TYPES.contains(<) { - let channel = lt.as_channel().unwrap(); - let Some(connection) = connection else { - return Err(MissingConnectionSpecifier); - }; - let network_id = vm - .get_device_same_network(this.device, device_id) - .map(|device| device.borrow().get_network_id(connection)) - .unwrap_or(Err(UnknownDeviceID(device_id as f64)))?; - let val = vm.get_network_channel(network_id, channel)?; - this.set_register(indirection, target, val)?; - return Ok(()); - } - if lt == LogicType::LineNumber && this.device == device_id { - // HACK: we can't use device.get_field as that will try to reborrow our - // ic which will panic - this.set_register(indirection, target, this.ip() as f64)?; - Ok(()) - } else { - let device = vm.get_device_same_network(this.device, device_id); - match device { - Some(device) => { - let val = device.borrow().get_field(lt, vm)?; - this.set_register(indirection, target, val)?; - Ok(()) - } - None => Err(UnknownDeviceID(device_id as f64)), - } - } - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 3)), - }, - Ld => match &operands[..] { - [reg, dev, lt] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let device_id = dev.as_value(this, inst, 2)?; - if device_id >= u16::MAX as f64 || device_id < u16::MIN as f64 { - return Err(DeviceIndexOutOfRange(device_id)); - } - let lt = lt.as_logic_type(this, inst, 3)?; - if lt == LogicType::LineNumber && this.device == device_id as u32 { - // HACK: we can't use device.get_field as that will try to reborrow our - // ic which will panic - this.set_register(indirection, target, this.ip() as f64)?; - Ok(()) - } else { - let device = vm.get_device_same_network(this.device, device_id as u32); - match device { - Some(device) => { - let val = device.borrow().get_field(lt, vm)?; - this.set_register(indirection, target, val)?; - Ok(()) - } - None => Err(UnknownDeviceID(device_id)), - } - } - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 3)), - }, - Ls => match &operands[..] { - [reg, dev, index, slt] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let (Some(device_id), _connection) = dev.as_device(this, inst, 2)? else { - return Err(DeviceNotSet); - }; - let slt = slt.as_slot_logic_type(this, inst, 4)?; - if slt == LogicSlotType::LineNumber && this.device == device_id { - // HACK: we can't use device.get_slot_field as that will try to reborrow our - // ic which will panic - this.set_register(indirection, target, this.ip() as f64)?; - Ok(()) - } else { - let device = vm.get_device_same_network(this.device, device_id); - match device { - Some(device) => { - let index = index.as_value(this, inst, 3)?; - let val = device.borrow().get_slot_field(index, slt, vm)?; - this.set_register(indirection, target, val)?; - Ok(()) - } - None => Err(UnknownDeviceID(device_id as f64)), - } - } - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 4)), - }, - Lr => match &operands[..] { - [reg, dev, rm, name] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let (Some(device_id), _connection) = dev.as_device(this, inst, 2)? else { - return Err(DeviceNotSet); - }; - let device = vm.get_device_same_network(this.device, device_id); - match device { - Some(device) => { - let rm = rm.as_reagent_mode(this, inst, 3)?; - let name = name.as_value(this, inst, 4)?; - let val = device.borrow().get_reagent(&rm, name); - this.set_register(indirection, target, val)?; - Ok(()) - } - None => Err(UnknownDeviceID(device_id as f64)), - } - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 4)), - }, - Lb => match &operands[..] { - [reg, prefab, lt, bm] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let prefab = prefab.as_value(this, inst, 2)?; - let lt = lt.as_logic_type(this, inst, 3)?; - let bm = bm.as_batch_mode(this, inst, 4)?; - let val = vm.get_batch_device_field(this.device, prefab, lt, bm)?; - this.set_register(indirection, target, val)?; - Ok(()) - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 4)), - }, - Lbn => match &operands[..] { - [reg, prefab, name, lt, bm] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let prefab = prefab.as_value(this, inst, 2)?; - let name = name.as_value(this, inst, 3)?; - let lt = lt.as_logic_type(this, inst, 4)?; - let bm = bm.as_batch_mode(this, inst, 5)?; - let val = - vm.get_batch_name_device_field(this.device, prefab, name, lt, bm)?; - this.set_register(indirection, target, val)?; - Ok(()) - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 5)), - }, - Lbns => match &operands[..] { - [reg, prefab, name, index, slt, bm] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let prefab = prefab.as_value(this, inst, 2)?; - let name = name.as_value(this, inst, 3)?; - let index = index.as_value(this, inst, 4)?; - let slt = slt.as_slot_logic_type(this, inst, 5)?; - let bm = bm.as_batch_mode(this, inst, 6)?; - let val = vm.get_batch_name_device_slot_field( - this.device, - prefab, - name, - index, - slt, - bm, - )?; - this.set_register(indirection, target, val)?; - Ok(()) - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 6)), - }, - Lbs => match &operands[..] { - [reg, prefab, index, slt, bm] => { - let RegisterSpec { - indirection, - target, - } = reg.as_register(this, inst, 1)?; - let prefab = prefab.as_value(this, inst, 2)?; - let index = index.as_value(this, inst, 3)?; - let slt = slt.as_slot_logic_type(this, inst, 4)?; - let bm = bm.as_batch_mode(this, inst, 5)?; - let val = - vm.get_batch_device_slot_field(this.device, prefab, index, slt, bm)?; - this.set_register(indirection, target, val)?; - Ok(()) - } - oprs => Err(ICError::mismatch_operands(oprs.len(), 5)), - }, - } - }; - let result = process_op(self); - if result.is_ok() || advance_ip_on_err { - self.ic.set(self.ic.get() + 1); - self.set_ip(next_ip); - self.propagate_line_number(vm); - } - result - } -} - -#[allow(dead_code)] -const CHANNEL_LOGIC_TYPES: [LogicType; 8] = [ - LogicType::Channel0, - LogicType::Channel1, - LogicType::Channel2, - LogicType::Channel3, - LogicType::Channel4, - LogicType::Channel5, - LogicType::Channel6, - LogicType::Channel7, -]; - -trait LogicTypeExt { - fn as_channel(&self) -> Option; -} -impl LogicTypeExt for LogicType { - fn as_channel(&self) -> Option { - match self { - LogicType::Channel0 => Some(0), - LogicType::Channel1 => Some(1), - LogicType::Channel2 => Some(2), - LogicType::Channel3 => Some(3), - LogicType::Channel4 => Some(4), - LogicType::Channel5 => Some(5), - LogicType::Channel6 => Some(6), - LogicType::Channel7 => Some(7), - _ => None, - } - } -} - pub fn f64_to_i64(f: f64, signed: bool) -> i64 { let mut num: i64 = (f % (1i64 << 53) as f64) as i64; if !signed { @@ -838,7 +185,7 @@ pub fn i64_to_f64(i: i64) -> f64 { #[cfg(test)] mod tests { - use crate::errors::VMError; + use crate::{errors::VMError, vm::VM}; use super::*; diff --git a/ic10emu/src/interpreter/instructions.rs b/ic10emu/src/interpreter/instructions.rs index e7ce18c..6fcb4c0 100644 --- a/ic10emu/src/interpreter/instructions.rs +++ b/ic10emu/src/interpreter/instructions.rs @@ -2,6 +2,7 @@ use crate::{ errors::ICError, interpreter::{i64_to_f64, ICState}, vm::{ + enums::script_enums::LogicReagentMode, instructions::{ operands::{InstOperand, RegisterSpec}, traits::*, @@ -1967,15 +1968,14 @@ impl GetInstruction for T { } = r.as_register(self)?; let address = address.as_value(self)?; let (device, connection) = d.as_device(self)?; - let Some(logicable) = self + let logicable = self .get_circuit_holder() .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .get_logicable_from_index(device, connection) else { - return Err(ICError::DeviceNotSet); - }; - let Some(memory) = logicable.as_memory_readable() else { - return Err(MemoryError::NotReadable.into()); - }; + .get_logicable_from_index(device, connection) + .ok_or(ICError::DeviceNotSet)?; + let memory = logicable + .as_memory_readable() + .ok_or(MemoryError::NotReadable)?; self.set_register(indirection, target, memory.get_memory(address as i32)?)?; Ok(()) } @@ -1995,15 +1995,14 @@ impl GetdInstruction for T { } = r.as_register(self)?; let id = id.as_value(self)?; let address = address.as_value(self)?; - let Some(logicable) = self + let logicable = self .get_circuit_holder() .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .get_logicable_from_id(id as ObjectID, None) else { - return Err(ICError::UnknownDeviceId(id)); - }; - let Some(memory) = logicable.as_memory_readable() else { - return Err(MemoryError::NotReadable.into()); - }; + .get_logicable_from_id(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet)?; + let memory = logicable + .as_memory_readable() + .ok_or(MemoryError::NotReadable)?; self.set_register(indirection, target, memory.get_memory(address as i32)?)?; Ok(()) } @@ -2020,15 +2019,14 @@ impl PutInstruction for T { let (device, connection) = d.as_device(self)?; let address = address.as_value(self)?; let value = value.as_value(self)?; - let Some(logicable) = self + let logicable = self .get_circuit_holder() .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .get_logicable_from_index_mut(device, connection) else { - return Err(ICError::DeviceNotSet); - }; - let Some(memory) = logicable.as_memory_writable() else { - return Err(MemoryError::NotWriteable.into()); - }; + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet)?; + let memory = logicable + .as_memory_writable() + .ok_or(MemoryError::NotWriteable)?; memory.set_memory(address as i32, value)?; Ok(()) } @@ -2045,15 +2043,14 @@ impl PutdInstruction for T { let id = id.as_value(self)?; let address = address.as_value(self)?; let value = value.as_value(self)?; - let Some(logicable) = self + let logicable = self .get_circuit_holder() .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .get_logicable_from_id_mut(id as ObjectID, None) else { - return Err(ICError::DeviceNotSet); - }; - let Some(memory) = logicable.as_memory_writable() else { - return Err(MemoryError::NotWriteable.into()); - }; + .get_logicable_from_id_mut(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet)?; + let memory = logicable + .as_memory_writable() + .ok_or(MemoryError::NotWriteable)?; memory.set_memory(address as i32, value)?; Ok(()) } @@ -2061,202 +2058,463 @@ impl PutdInstruction for T { impl ClrInstruction for T { /// clr d? - fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> { + fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> { let (device, connection) = d.as_device(self)?; - let Some(logicable) = self + let logicable = self .get_circuit_holder() .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .get_logicable_from_index_mut(device, connection) else { - return Err(ICError::DeviceNotSet); - }; - let Some(memory) = logicable.as_memory_writable() else { - return Err(MemoryError::NotWriteable.into()); - }; + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet)?; + let memory = logicable + .as_memory_writable() + .ok_or(MemoryError::NotWriteable)?; memory.clear_memory()?; Ok(()) } } impl ClrdInstruction for T { /// clrd id(r?|num) - fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> { + fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> { let id = id.as_value(self)?; - let Some(logicable) = self + let logicable = self .get_circuit_holder() .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .get_logicable_from_id_mut(id as ObjectID, None) else { - return Err(ICError::DeviceNotSet); - }; - let Some(memory) = logicable.as_memory_writable() else { - return Err(MemoryError::NotWriteable.into()); - }; + .get_logicable_from_id_mut(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet)?; + let memory = logicable + .as_memory_writable() + .ok_or(MemoryError::NotWriteable)?; memory.clear_memory()?; Ok(()) } } -// impl HcfInstruction for T { -// /// hcf -// fn execute_inner(&mut self, vm: &VM) -> Result<(), ICError>; -// } -// impl LInstruction for T { -// /// l r? d? logicType -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// d: &InstOperand, -// logic_type: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl LabelInstruction for T { -// /// label d? str -// fn execute_inner(&mut self, d: &InstOperand, str: &InstOperand) -> Result<(), ICError>; -// } -// impl LbInstruction for T { -// /// lb r? deviceHash logicType batchMode -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// device_hash: &InstOperand, -// logic_type: &InstOperand, -// batch_mode: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl LbnInstruction for T { -// /// lbn r? deviceHash nameHash logicType batchMode -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// device_hash: &InstOperand, -// name_hash: &InstOperand, -// logic_type: &InstOperand, -// batch_mode: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl LbnsInstruction for T { -// /// lbns r? deviceHash nameHash slotIndex logicSlotType batchMode -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// device_hash: &InstOperand, -// name_hash: &InstOperand, -// slot_index: &InstOperand, -// logic_slot_type: &InstOperand, -// batch_mode: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl LbsInstruction for T { -// /// lbs r? deviceHash slotIndex logicSlotType batchMode -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// device_hash: &InstOperand, -// slot_index: &InstOperand, -// logic_slot_type: &InstOperand, -// batch_mode: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl LdInstruction for T { -// /// ld r? id(r?|num) logicType -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// id: &InstOperand, -// logic_type: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl LogInstruction for T { -// /// log r? a(r?|num) -// fn execute_inner(&mut self, r: &InstOperand, a: &InstOperand) -> Result<(), ICError>; -// } -// impl LrInstruction for T { -// /// lr r? d? reagentMode int -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// d: &InstOperand, -// reagent_mode: &InstOperand, -// int: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl LsInstruction for T { -// /// ls r? d? slotIndex logicSlotType -// fn execute_inner( -// &mut self, -// -// r: &InstOperand, -// d: &InstOperand, -// slot_index: &InstOperand, -// logic_slot_type: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl SInstruction for T { -// /// s d? logicType r? -// fn execute_inner( -// &mut self, -// -// d: &InstOperand, -// logic_type: &InstOperand, -// r: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl SbInstruction for T { -// /// sb deviceHash logicType r? -// fn execute_inner( -// &mut self, -// -// device_hash: &InstOperand, -// logic_type: &InstOperand, -// r: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl SbnInstruction for T { -// /// sbn deviceHash nameHash logicType r? -// fn execute_inner( -// &mut self, -// -// device_hash: &InstOperand, -// name_hash: &InstOperand, -// logic_type: &InstOperand, -// r: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl SbsInstruction for T { -// /// sbs deviceHash slotIndex logicSlotType r? -// fn execute_inner( -// &mut self, -// -// device_hash: &InstOperand, -// slot_index: &InstOperand, -// logic_slot_type: &InstOperand, -// r: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl SdInstruction for T { -// /// sd id(r?|num) logicType r? -// fn execute_inner( -// &mut self, -// -// id: &InstOperand, -// logic_type: &InstOperand, -// r: &InstOperand, -// ) -> Result<(), ICError>; -// } -// impl SsInstruction for T { -// /// ss d? slotIndex logicSlotType r? -// fn execute_inner( -// &mut self, -// -// d: &InstOperand, -// slot_index: &InstOperand, -// logic_slot_type: &InstOperand, -// r: &InstOperand, -// ) -> Result<(), ICError>; -// } -// +impl SInstruction for T { + /// s d? logicType r? + fn execute_inner( + &mut self, + d: &InstOperand, + logic_type: &InstOperand, + r: &InstOperand, + ) -> Result<(), ICError> { + let (device, connection) = d.as_device(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let val = r.as_value(self)?; + let logicable = self + .get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet)?; + logicable.set_logic(logic_type, val, false)?; + Ok(()) + } +} + +impl SdInstruction for T { + /// sd id(r?|num) logicType r? + fn execute_inner( + &mut self, + id: &InstOperand, + logic_type: &InstOperand, + r: &InstOperand, + ) -> Result<(), ICError> { + let id = id.as_value(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let val = r.as_value(self)?; + let logicable = self + .get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .get_logicable_from_id_mut(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet)?; + logicable.set_logic(logic_type, val, false)?; + Ok(()) + } +} + +impl SsInstruction for T { + /// ss d? slotIndex logicSlotType r? + fn execute_inner( + &mut self, + d: &InstOperand, + slot_index: &InstOperand, + logic_slot_type: &InstOperand, + r: &InstOperand, + ) -> Result<(), ICError> { + let (device, connection) = d.as_device(self)?; + let slot_index = slot_index.as_value(self)?; + let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; + let val = r.as_value(self)?; + let logicable = self + .get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet)?; + let device = logicable + .as_mut_device() + .ok_or(ICError::NotSlotWriteable(logicable.get_id()))?; + device.set_slot_logic(logic_slot_type, slot_index, val, false)?; + Ok(()) + } +} + +impl SbInstruction for T { + /// sb deviceHash logicType r? + fn execute_inner( + &mut self, + + device_hash: &InstOperand, + logic_type: &InstOperand, + r: &InstOperand, + ) -> Result<(), ICError> { + let prefab = device_hash.as_value(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let val = r.as_value(self)?; + self.get_vm() + .set_batch_device_field(self.get_id(), prefab, logic_type, val, false)?; + Ok(()) + } +} + +impl SbsInstruction for T { + /// sbs deviceHash slotIndex logicSlotType r? + fn execute_inner( + &mut self, + + device_hash: &InstOperand, + slot_index: &InstOperand, + logic_slot_type: &InstOperand, + r: &InstOperand, + ) -> Result<(), ICError> { + let prefab = device_hash.as_value(self)?; + let slot_index = slot_index.as_value(self)?; + let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; + let val = r.as_value(self)?; + self.get_vm().set_batch_device_slot_field( + self.get_id(), + prefab, + slot_index, + logic_slot_type, + val, + false, + )?; + Ok(()) + } +} + +impl SbnInstruction for T { + /// sbn deviceHash nameHash logicType r? + fn execute_inner( + &mut self, + + device_hash: &InstOperand, + name_hash: &InstOperand, + logic_type: &InstOperand, + r: &InstOperand, + ) -> Result<(), ICError> { + let prefab = device_hash.as_value(self)?; + let name = name_hash.as_value(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let val = r.as_value(self)?; + self.get_vm().set_batch_name_device_field( + self.get_id(), + prefab, + name, + logic_type, + val, + false, + )?; + Ok(()) + } +} + +impl LInstruction for T { + /// l r? d? logicType + fn execute_inner( + &mut self, + + r: &InstOperand, + d: &InstOperand, + logic_type: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + let (device, connection) = d.as_device(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let logicable = self + .get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .get_logicable_from_index(device, connection) + .ok_or(ICError::DeviceNotSet)?; + self.set_register(indirection, target, logicable.get_logic(logic_type)?)?; + Ok(()) + } +} + +impl LdInstruction for T { + /// ld r? id(r?|num) logicType + fn execute_inner( + &mut self, + r: &InstOperand, + id: &InstOperand, + logic_type: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + let id = id.as_value(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let logicable = self + .get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .get_logicable_from_id(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet)?; + self.set_register(indirection, target, logicable.get_logic(logic_type)?)?; + Ok(()) + } +} + +impl LsInstruction for T { + /// ls r? d? slotIndex logicSlotType + fn execute_inner( + &mut self, + r: &InstOperand, + d: &InstOperand, + slot_index: &InstOperand, + logic_slot_type: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + let (device, connection) = d.as_device(self)?; + let slot_index = slot_index.as_value(self)?; + let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; + let logicable = self + .get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .get_logicable_from_index(device, connection) + .ok_or(ICError::DeviceNotSet)?; + self.set_register( + indirection, + target, + logicable.get_slot_logic(logic_slot_type, slot_index)?, + )?; + Ok(()) + } +} + +impl LrInstruction for T { + /// lr r? d? reagentMode int + fn execute_inner( + &mut self, + r: &InstOperand, + d: &InstOperand, + reagent_mode: &InstOperand, + int: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + let (device, connection) = d.as_device(self)?; + let reagent_mode = reagent_mode.as_reagent_mode(self)?; + let int = int.as_value(self)?; + let logicable = self + .get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .get_logicable_from_index(device, connection) + .ok_or(ICError::DeviceNotSet)?; + + let result = match reagent_mode { + LogicReagentMode::Contents => { + let device = logicable + .as_device() + .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; + device + .get_reagents() + .iter() + .find(|(hash, _)| *hash as f64 == int) + .map(|(_, quantity)| *quantity) + .unwrap_or(0.0) + } + LogicReagentMode::TotalContents => { + let device = logicable + .as_device() + .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; + device + .get_reagents() + .iter() + .map(|(_, quantity)| quantity) + .sum() + } + LogicReagentMode::Required => { + let reagent_interface = logicable + .as_reagent_interface() + .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; + reagent_interface + .get_current_required() + .iter() + .find(|(hash, _)| *hash as f64 == int) + .map(|(_, quantity)| *quantity) + .unwrap_or(0.0) + } + LogicReagentMode::Recipe => { + let reagent_interface = logicable + .as_reagent_interface() + .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; + reagent_interface + .get_current_recipie() + .iter() + .find(|(hash, _)| *hash as f64 == int) + .map(|(_, quantity)| *quantity) + .unwrap_or(0.0) + } + }; + + self.set_register(indirection, target, result)?; + Ok(()) + } +} + +impl LbInstruction for T { + /// lb r? deviceHash logicType batchMode + fn execute_inner( + &mut self, + r: &InstOperand, + device_hash: &InstOperand, + logic_type: &InstOperand, + batch_mode: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + + let prefab = device_hash.as_value(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let batch_mode = batch_mode.as_batch_mode(self)?; + let val = + self.get_vm() + .get_batch_device_field(self.get_id(), prefab, logic_type, batch_mode)?; + self.set_register(indirection, target, val)?; + Ok(()) + } +} + +impl LbnInstruction for T { + /// lbn r? deviceHash nameHash logicType batchMode + fn execute_inner( + &mut self, + + r: &InstOperand, + device_hash: &InstOperand, + name_hash: &InstOperand, + logic_type: &InstOperand, + batch_mode: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + let prefab = device_hash.as_value(self)?; + let name = name_hash.as_value(self)?; + let logic_type = logic_type.as_logic_type(self)?; + let batch_mode = batch_mode.as_batch_mode(self)?; + let val = self.get_vm().get_batch_name_device_field( + self.get_id(), + prefab, + name, + logic_type, + batch_mode, + )?; + self.set_register(indirection, target, val)?; + Ok(()) + } +} + +impl LbnsInstruction for T { + /// lbns r? deviceHash nameHash slotIndex logicSlotType batchMode + fn execute_inner( + &mut self, + + r: &InstOperand, + device_hash: &InstOperand, + name_hash: &InstOperand, + slot_index: &InstOperand, + logic_slot_type: &InstOperand, + batch_mode: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + let prefab = device_hash.as_value(self)?; + let name = name_hash.as_value(self)?; + let slot_index = slot_index.as_value(self)?; + let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; + let batch_mode = batch_mode.as_batch_mode(self)?; + let val = self.get_vm().get_batch_name_device_slot_field( + self.get_id(), + prefab, + name, + slot_index, + logic_slot_type, + batch_mode, + )?; + self.set_register(indirection, target, val)?; + Ok(()) + } +} + +impl LbsInstruction for T { + /// lbs r? deviceHash slotIndex logicSlotType batchMode + fn execute_inner( + &mut self, + + r: &InstOperand, + device_hash: &InstOperand, + slot_index: &InstOperand, + logic_slot_type: &InstOperand, + batch_mode: &InstOperand, + ) -> Result<(), ICError> { + let RegisterSpec { + indirection, + target, + } = r.as_register(self)?; + let prefab = device_hash.as_value(self)?; + let slot_index = slot_index.as_value(self)?; + let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; + let batch_mode = batch_mode.as_batch_mode(self)?; + let val = self.get_vm().get_batch_device_slot_field( + self.get_id(), + prefab, + slot_index, + logic_slot_type, + batch_mode, + )?; + self.set_register(indirection, target, val)?; + Ok(()) + } +} + +impl HcfInstruction for T { + /// hcf + fn execute_inner(&mut self) -> Result<(), ICError> { + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .hault_and_catch_fire(); + self.set_state(ICState::HasCaughtFire); + Ok(()) + } +} + +impl LabelInstruction for T { + /// label d? str + fn execute_inner(&mut self, d: &InstOperand, str: &InstOperand) -> Result<(), ICError> { + // No op, handled by program compilation, should never be called? + Ok(()) + } +} diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index e319d2b..4078960 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -265,7 +265,7 @@ impl VM { .ok_or(VMError::NotProgrammable(id))?; self.operation_modified.borrow_mut().clear(); self.set_modified(id); - programmable.step(self, advance_ip_on_err)?; + programmable.step(advance_ip_on_err)?; Ok(()) } @@ -286,7 +286,7 @@ impl VM { self.operation_modified.borrow_mut().clear(); self.set_modified(id); for _i in 0..128 { - if let Err(err) = programmable.step(self, ignore_errors) { + if let Err(err) = programmable.step( ignore_errors) { if !ignore_errors { return Err(err.into()); } @@ -629,7 +629,7 @@ impl VM { .borrow_mut() .as_mut_device() .expect("batch iter yielded non device") - .set_slot_logic(typ, index, val, self, write_readonly) + .set_slot_logic(typ, index, val, write_readonly) .map_err(Into::into) }) .try_collect() @@ -718,7 +718,7 @@ impl VM { .borrow() .as_device() .expect("batch iter yielded non device") - .get_slot_logic(typ, index, self) + .get_slot_logic(typ, index) .map_err(Into::into) }) .filter_ok(|val| !val.is_nan()) @@ -741,7 +741,7 @@ impl VM { .borrow() .as_device() .expect("batch iter yielded non device") - .get_slot_logic(typ, index, self) + .get_slot_logic(typ, index) .map_err(Into::into) }) .filter_ok(|val| !val.is_nan()) diff --git a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs index 2ca717d..c517e50 100644 --- a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs +++ b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs @@ -1,18 +1,12 @@ use crate::{ - errors::{ICError, LineError}, - grammar, - interpreter::{ICState, instructions::IC10Marker}, + errors::ICError, + interpreter::{instructions::IC10Marker, ICState, Program}, vm::{ enums::{ basic_enums::{Class as SlotClass, GasType, SortingClass}, script_enums::{LogicSlotType, LogicType}, }, - instructions::{ - enums::InstructionOp, - operands::{DeviceSpec, Operand, RegisterSpec}, - traits::*, - Instruction, - }, + instructions::{operands::Operand, Instruction}, object::{ errors::{LogicError, MemoryError}, macros::ObjectInterface, @@ -22,124 +16,8 @@ use crate::{ VM, }, }; -use itertools::Itertools; use macro_rules_attribute::derive; -use serde_derive::{Deserialize, Serialize}; -use std::{ - collections::{BTreeMap, HashSet}, - rc::Rc, -}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Program { - pub instructions: Vec, - pub errors: Vec, - pub labels: BTreeMap, -} - -impl Default for Program { - fn default() -> Self { - Program::new() - } -} - -impl Program { - pub fn new() -> Self { - Program { - instructions: Vec::new(), - errors: Vec::new(), - labels: BTreeMap::new(), - } - } - - pub fn try_from_code(code: &str) -> Result { - let parse_tree = grammar::parse(code)?; - let mut labels_set = HashSet::new(); - let mut labels = BTreeMap::new(); - let errors = Vec::new(); - let instructions = parse_tree - .into_iter() - .enumerate() - .map(|(line_number, line)| match line.code { - None => Ok(Instruction { - instruction: InstructionOp::Nop, - operands: vec![], - }), - Some(code) => match code { - grammar::Code::Label(label) => { - if labels_set.contains(&label.id.name) { - Err(ICError::DuplicateLabel(label.id.name)) - } else { - labels_set.insert(label.id.name.clone()); - labels.insert(label.id.name, line_number as u32); - Ok(Instruction { - instruction: InstructionOp::Nop, - operands: vec![], - }) - } - } - grammar::Code::Instruction(instruction) => Ok(instruction), - grammar::Code::Invalid(err) => Err(err.into()), - }, - }) - .try_collect()?; - Ok(Program { - instructions, - errors, - labels, - }) - } - - pub fn from_code_with_invalid(code: &str) -> Self { - let parse_tree = grammar::parse_with_invalid(code); - let mut labels_set = HashSet::new(); - let mut labels = BTreeMap::new(); - let mut errors = Vec::new(); - let instructions = parse_tree - .into_iter() - .enumerate() - .map(|(line_number, line)| match line.code { - None => Instruction { - instruction: InstructionOp::Nop, - operands: vec![], - }, - Some(code) => match code { - grammar::Code::Label(label) => { - if labels_set.contains(&label.id.name) { - errors.push(ICError::DuplicateLabel(label.id.name)); - } else { - labels_set.insert(label.id.name.clone()); - labels.insert(label.id.name, line_number as u32); - } - Instruction { - instruction: InstructionOp::Nop, - operands: vec![], - } - } - grammar::Code::Instruction(instruction) => instruction, - grammar::Code::Invalid(err) => { - errors.push(err.into()); - Instruction { - instruction: InstructionOp::Nop, - operands: vec![], - } - } - }, - }) - .collect_vec(); - Program { - instructions, - errors, - labels, - } - } - - pub fn get_line(&self, line: usize) -> Result<&Instruction, ICError> { - self.instructions - .get(line) - .ok_or(ICError::InstructionPointerOutOfRange(line)) - } -} +use std::{collections::BTreeMap, rc::Rc}; static RETURN_ADDRESS_INDEX: usize = 17; static STACK_POINTER_INDEX: usize = 16; @@ -219,6 +97,7 @@ impl Storage for ItemIntegratedCircuit10 { &mut [] } } + impl Logicable for ItemIntegratedCircuit10 { fn prefab_hash(&self) -> i32 { self.get_prefab().hash @@ -487,3 +366,46 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 { } impl IC10Marker for ItemIntegratedCircuit10 {} + +impl Programmable for ItemIntegratedCircuit10 { + fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError> { + if matches!(&self.state, ICState::HasCaughtFire | ICState::Error(_)) { + return Ok(()); + } + if let ICState::Sleep(then, sleep_for) = &self.state { + if let Some(duration) = time::Duration::checked_seconds_f64(*sleep_for) { + if let Some(sleep_till) = then.checked_add(duration) { + if sleep_till + <= time::OffsetDateTime::now_local() + .unwrap_or_else(|_| time::OffsetDateTime::now_utc()) + { + return Ok(()); + } + // else sleep duration ended, continue + } else { + return Err(ICError::SleepAddtionError(duration, *then)); + } + } else { + return Err(ICError::SleepDurationError(*sleep_for)); + } + } + if self.ip >= self.program.len() || self.program.len() == 0 { + self.state = ICState::Ended; + return Ok(()); + } + self.next_ip = self.ip + 1; + self.state = ICState::Running; + let line = self.program.get_line(self.ip)?; + let operands = &line.operands; + let instruction = line.instruction; + instruction.execute(self, operands)?; + self.ip = self.next_ip; + if self.ip >= self.program.len() { + self.state = ICState::Ended; + } + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.id))? + .set_logic(LogicType::LineNumber, self.ip as f64, true)?; + Ok(()) + } +} diff --git a/ic10emu/src/vm/object/traits.rs b/ic10emu/src/vm/object/traits.rs index 39d71c4..4473602 100644 --- a/ic10emu/src/vm/object/traits.rs +++ b/ic10emu/src/vm/object/traits.rs @@ -104,6 +104,7 @@ tag_object_traits! { fn get_batch(&self) -> Vec; fn get_batch_mut(&self) -> Vec; fn get_ic(&self) -> Option; + fn hault_and_catch_fire(&mut self); } pub trait Item { @@ -148,8 +149,6 @@ tag_object_traits! { } pub trait Programmable: ICInstructable { - fn get_source_code(&self) -> String; - fn set_source_code(&self, code: String); fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>; } @@ -182,8 +181,23 @@ tag_object_traits! { fn has_on_off_state(&self) -> bool; fn has_open_state(&self) -> bool; fn has_reagents(&self) -> bool; + /// return vector of (reagent_hash, quantity) pairs + fn get_reagents(&self) -> Vec<(i32, f64)>; + /// overwrite present reagents + fn set_reagents(&mut self, reagents: &[(i32, f64)]); + /// adds the reagents to contents + fn add_reagents(&mut self, reagents: &[(i32, f64)]); } + pub trait ReagentInterface: Device { + /// reagents required by current recipe + fn get_current_recipie(&self) -> Vec<(i32, f64)>; + /// reagents required to complete current recipe + fn get_current_required(&self) -> Vec<(i32, f64)>; + } + + pub trait Fabricator: ReagentInterface {} + pub trait WirelessTransmit: Logicable {} pub trait WirelessReceive: Logicable {}