From 8288d8ae6fd5a7a57f0c7943891a6276c3c9d133 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sun, 12 May 2024 02:08:25 -0700 Subject: [PATCH] refactor(vm) start reimpl of VM struct using object trait --- ic10emu/src/device.rs | 10 +- ic10emu/src/errors.rs | 18 +- ic10emu/src/interpreter.rs | 12 +- ic10emu/src/network.rs | 244 ++++-- ic10emu/src/vm.rs | 756 ++++++++++-------- ic10emu/src/vm/instructions/operands.rs | 37 +- ic10emu/src/vm/instructions/traits.rs | 27 +- ic10emu/src/vm/object.rs | 13 +- ic10emu/src/vm/object/errors.rs | 4 +- ic10emu/src/vm/object/generic/macros.rs | 18 +- ic10emu/src/vm/object/generic/structs.rs | 15 +- ic10emu/src/vm/object/generic/traits.rs | 50 +- ic10emu/src/vm/object/macros.rs | 47 +- .../structs/integrated_circuit.rs | 544 ++++++++----- ic10emu/src/vm/object/templates.rs | 145 +++- ic10emu/src/vm/object/traits.rs | 97 ++- ic10emu_wasm/src/lib.rs | 34 +- xtask/src/generate/instructions.rs | 31 +- 18 files changed, 1362 insertions(+), 740 deletions(-) diff --git a/ic10emu/src/device.rs b/ic10emu/src/device.rs index 87ac742..7219b52 100644 --- a/ic10emu/src/device.rs +++ b/ic10emu/src/device.rs @@ -522,7 +522,7 @@ impl Device { pub fn get_fields(&self, vm: &VM) -> BTreeMap { let mut copy = self.fields.clone(); if let Some(ic_id) = &self.ic { - let ic = vm.ics.get(ic_id).expect("our own ic to exist").borrow(); + let ic = vm.ic_holders.get(ic_id).expect("our own ic to exist").borrow(); copy.insert( LogicType::LineNumber, LogicField { @@ -642,7 +642,7 @@ impl Device { pub fn get_field(&self, typ: LogicType, vm: &VM) -> Result { if typ == LogicType::LineNumber && self.ic.is_some() { let ic = vm - .ics + .ic_holders .get(&self.ic.unwrap()) .ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))? .borrow(); @@ -673,7 +673,7 @@ impl Device { Err(ICError::ReadOnlyField(typ.to_string())) } else if typ == LogicType::LineNumber && self.ic.is_some() { let ic = vm - .ics + .ic_holders .get(&self.ic.unwrap()) .ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))? .borrow(); @@ -714,7 +714,7 @@ impl Device { && typ == LogicSlotType::LineNumber { let ic = vm - .ics + .ic_holders .get(&self.ic.unwrap()) .ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))? .borrow(); @@ -736,7 +736,7 @@ impl Device { let mut fields = slot.get_fields(); if slot.typ == SlotClass::ProgrammableChip && slot.occupant.is_some() && self.ic.is_some() { let ic = vm - .ics + .ic_holders .get(&self.ic.unwrap()) .ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))? .borrow(); diff --git a/ic10emu/src/errors.rs b/ic10emu/src/errors.rs index c9d3a8e..da49f27 100644 --- a/ic10emu/src/errors.rs +++ b/ic10emu/src/errors.rs @@ -1,4 +1,4 @@ -use crate::vm::instructions::enums::InstructionOp; +use crate::vm::{instructions::enums::InstructionOp, object::{errors::{LogicError, MemoryError}, ObjectID}}; use serde_derive::{Deserialize, Serialize}; use std::error::Error as StdError; use std::fmt::Display; @@ -17,7 +17,7 @@ pub enum VMError { #[error("ic encountered an error: {0}")] LineError(#[from] LineError), #[error("invalid network id {0}")] - InvalidNetwork(u32), + InvalidNetwork(ObjectID), #[error("device {0} not visible to device {1} (not on the same networks)")] DeviceNotVisible(u32, u32), #[error("a device with id {0} already exists")] @@ -26,6 +26,12 @@ pub enum VMError { IdsInUse(Vec), #[error("atempt to use a set of id's with duplicates: id(s) {0:?} exsist more than once")] DuplicateIds(Vec), + #[error("object {0} is not a device")] + NotADevice(ObjectID), + #[error("device object {0} has no pins")] + NoDevicePins(ObjectID), + #[error("object {0} has no slots")] + NotStorage(ObjectID), } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -98,6 +104,10 @@ impl ParseError { pub enum ICError { #[error("error compiling code: {0}")] ParseError(#[from] ParseError), + #[error("{0}")] + LogicError(#[from] LogicError), + #[error("{0}")] + MemoryError(#[from] MemoryError), #[error("duplicate label {0}")] DuplicateLabel(String), #[error("instruction pointer out of range: '{0}'")] @@ -138,10 +148,6 @@ pub enum ICError { ShiftUnderflowI32, #[error("shift overflow i32(signed int)")] ShiftOverflowI32, - #[error("stack underflow")] - StackUnderflow, - #[error("stack overflow")] - StackOverflow, #[error("duplicate define '{0}'")] DuplicateDefine(String), #[error("read only field '{0}'")] diff --git a/ic10emu/src/interpreter.rs b/ic10emu/src/interpreter.rs index 181fe6d..b774506 100644 --- a/ic10emu/src/interpreter.rs +++ b/ic10emu/src/interpreter.rs @@ -2030,7 +2030,7 @@ impl IC { if ic_id == &this.id { this.peek_addr(addr) } else { - let ic = vm.ics.get(ic_id).unwrap().borrow(); + let ic = vm.ic_holders.get(ic_id).unwrap().borrow(); ic.peek_addr(addr) } }?; @@ -2063,7 +2063,7 @@ impl IC { if ic_id == &this.id { this.peek_addr(addr) } else { - let ic = vm.ics.get(ic_id).unwrap().borrow(); + let ic = vm.ic_holders.get(ic_id).unwrap().borrow(); ic.peek_addr(addr) } }?; @@ -2092,7 +2092,7 @@ impl IC { if ic_id == &this.id { this.poke(addr, val)?; } else { - let ic = vm.ics.get(ic_id).unwrap().borrow(); + let ic = vm.ic_holders.get(ic_id).unwrap().borrow(); ic.poke(addr, val)?; } vm.set_modified(device_id); @@ -2120,7 +2120,7 @@ impl IC { if ic_id == &this.id { this.poke(addr, val)?; } else { - let ic = vm.ics.get(ic_id).unwrap().borrow(); + let ic = vm.ic_holders.get(ic_id).unwrap().borrow(); ic.poke(addr, val)?; } vm.set_modified(device_id as u32); @@ -2532,7 +2532,7 @@ mod tests { let device_ref = device.borrow(); device_ref.ic.unwrap() }; - let ic_chip = vm.ics.get(&ic_id).unwrap().borrow(); + let ic_chip = vm.ic_holders.get(&ic_id).unwrap().borrow(); vm.set_code( ic, r#"lb r0 HASH("ItemActiveVent") On Sum @@ -2561,7 +2561,7 @@ mod tests { let device_ref = device.borrow(); device_ref.ic.unwrap() }; - let ic_chip = vm.ics.get(&ic_id).unwrap().borrow(); + let ic_chip = vm.ic_holders.get(&ic_id).unwrap().borrow(); vm.set_code( ic, r#"push 100 diff --git a/ic10emu/src/network.rs b/ic10emu/src/network.rs index 831fa8c..41230b9 100644 --- a/ic10emu/src/network.rs +++ b/ic10emu/src/network.rs @@ -1,11 +1,15 @@ use std::{collections::HashSet, ops::Deref}; +use crate::vm::{ + enums::script_enums::LogicType, + object::{errors::LogicError, macros::ObjectInterface, traits::*, Name, ObjectID}, +}; +use itertools::Itertools; +use macro_rules_attribute::derive; use serde_derive::{Deserialize, Serialize}; use strum_macros::{AsRefStr, EnumIter}; use thiserror::Error; -use itertools::Itertools; - #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)] pub enum CableConnectionType { Power, @@ -107,14 +111,171 @@ impl Connection { } } -#[derive(Debug, Serialize, Deserialize)] -pub struct Network { - pub id: u32, - pub devices: HashSet, - pub power_only: HashSet, +#[derive(ObjectInterface!, Debug, Serialize, Deserialize)] +#[custom(implements(Object { Storage, Logicable, Network}))] +pub struct CableNetwork { + #[custom(object_id)] + pub id: ObjectID, + #[custom(object_prefab)] + /// required by object interface but atm unused by network + pub prefab: Name, + #[custom(object_name)] + /// required by object interface but atm unused by network + pub name: Name, + /// data enabled objects (must be devices) + pub devices: HashSet, + /// power only connections + pub power_only: HashSet, + /// channel data pub channels: [f64; 8], } +impl Storage for CableNetwork { + fn slots_count(&self) -> usize { + 0 + } + fn get_slot(&self, index: usize) -> Option<&crate::vm::object::Slot> { + None + } + fn get_slot_mut(&mut self, index: usize) -> Option<&mut crate::vm::object::Slot> { + None + } +} + +impl Logicable for CableNetwork { + fn prefab_hash(&self) -> i32 { + 0 + } + fn name_hash(&self) -> i32 { + 0 + } + fn is_logic_readable(&self) -> bool { + true + } + fn is_logic_writeable(&self) -> bool { + true + } + fn can_logic_read(&self, lt: LogicType) -> bool { + use LogicType::*; + match lt { + Channel0 | Channel1 | Channel2 | Channel3 | Channel4 | Channel5 | Channel6 + | Channel7 => true, + _ => false, + } + } + fn can_logic_write(&self, lt: LogicType) -> bool { + use LogicType::*; + match lt { + Channel0 | Channel1 | Channel2 | Channel3 | Channel4 | Channel5 | Channel6 + | Channel7 => true, + _ => false, + } + } + fn get_logic(&self, lt: LogicType) -> Result { + use LogicType::*; + let index: usize = match lt { + Channel0 => 0, + Channel1 => 1, + Channel2 => 2, + Channel3 => 3, + Channel4 => 4, + Channel5 => 5, + Channel6 => 6, + Channel7 => 7, + _ => return Err(LogicError::CantRead(lt)), + }; + Ok(self.channels[index]) + } + fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> { + use LogicType::*; + let index: usize = match lt { + Channel0 => 0, + Channel1 => 1, + Channel2 => 2, + Channel3 => 3, + Channel4 => 4, + Channel5 => 5, + Channel6 => 6, + Channel7 => 7, + _ => return Err(LogicError::CantWrite(lt)), + }; + self.channels[index] = value; + Ok(()) + } + fn can_slot_logic_read( + &self, + slt: crate::vm::enums::script_enums::LogicSlotType, + index: usize, + ) -> bool { + false + } + fn get_slot_logic( + &self, + slt: crate::vm::enums::script_enums::LogicSlotType, + index: usize, + vm: &crate::vm::VM, + ) -> Result { + Err(LogicError::CantSlotRead(slt, index)) + } +} + +impl Network for CableNetwork { + fn contains(&self, id: &ObjectID) -> bool { + self.devices.contains(id) || self.power_only.contains(id) + } + + fn contains_all(&self, ids: &[ObjectID]) -> bool { + ids.iter().all(|id| self.contains(id)) + } + + fn contains_data(&self, id: &ObjectID) -> bool { + self.devices.contains(id) + } + + fn contains_all_data(&self, ids: &[ObjectID]) -> bool { + ids.iter().all(|id| self.contains_data(id)) + } + + fn contains_power(&self, id: &ObjectID) -> bool { + self.power_only.contains(id) + } + + fn contains_all_power(&self, ids: &[ObjectID]) -> bool { + ids.iter().all(|id| self.contains_power(id)) + } + + fn data_visible(&self, source: &ObjectID) -> Vec { + if self.contains_data(source) { + self.devices + .iter() + .filter(|id| id != &source) + .copied() + .collect_vec() + } else { + Vec::new() + } + } + + fn add_data(&mut self, id: ObjectID) -> bool { + self.devices.insert(id) + } + + fn add_power(&mut self, id: ObjectID) -> bool { + self.power_only.insert(id) + } + + fn remove_all(&mut self, id: ObjectID) -> bool { + self.devices.remove(&id) || self.power_only.remove(&id) + } + fn remove_data(&mut self, id: ObjectID) -> bool { + self.devices.remove(&id) + } + + fn remove_power(&mut self, id: ObjectID) -> bool { + self.devices.remove(&id) + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FrozenNetwork { pub id: u32, @@ -125,7 +286,7 @@ pub struct FrozenNetwork { impl From for FrozenNetwork where - T: Deref, + T: Deref, { fn from(value: T) -> Self { FrozenNetwork { @@ -137,10 +298,12 @@ where } } -impl From for Network { +impl From for CableNetwork { fn from(value: FrozenNetwork) -> Self { - Network { + CableNetwork { id: value.id, + prefab: Name::new(""), + name: Name::new(""), devices: value.devices.into_iter().collect(), power_only: value.power_only.into_iter().collect(), channels: value.channels, @@ -154,71 +317,18 @@ pub enum NetworkError { ChannelIndexOutOfRange, } -impl Network { +impl CableNetwork { pub fn new(id: u32) -> Self { - Network { + CableNetwork { id, + prefab: Name::new(""), + name: Name::new(""), devices: HashSet::new(), power_only: HashSet::new(), channels: [f64::NAN; 8], } } - pub fn contains(&self, id: &u32) -> bool { - self.devices.contains(id) || self.power_only.contains(id) - } - - pub fn contains_all(&self, ids: &[u32]) -> bool { - ids.iter().all(|id| self.contains(id)) - } - - pub fn contains_data(&self, id: &u32) -> bool { - self.devices.contains(id) - } - - pub fn contains_all_data(&self, ids: &[u32]) -> bool { - ids.iter().all(|id| self.contains_data(id)) - } - - pub fn contains_power(&self, id: &u32) -> bool { - self.power_only.contains(id) - } - - pub fn contains_all_power(&self, ids: &[u32]) -> bool { - ids.iter().all(|id| self.contains_power(id)) - } - - pub fn data_visible(&self, source: &u32) -> Vec { - if self.contains_data(source) { - self.devices - .iter() - .filter(|id| id != &source) - .copied() - .collect_vec() - } else { - Vec::new() - } - } - - pub fn add_data(&mut self, id: u32) -> bool { - self.devices.insert(id) - } - - pub fn add_power(&mut self, id: u32) -> bool { - self.power_only.insert(id) - } - - pub fn remove_all(&mut self, id: u32) -> bool { - self.devices.remove(&id) || self.power_only.remove(&id) - } - pub fn remove_data(&mut self, id: u32) -> bool { - self.devices.remove(&id) - } - - pub fn remove_power(&mut self, id: u32) -> bool { - self.devices.remove(&id) - } - pub fn set_channel(&mut self, chan: usize, val: f64) -> Result { if chan > 7 { Err(NetworkError::ChannelIndexOutOfRange) diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index 302b2ad..da5ca04 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -6,8 +6,11 @@ use crate::{ device::{Device, DeviceTemplate, SlotOccupant, SlotOccupantTemplate}, errors::{ICError, VMError}, interpreter::{self, FrozenIC}, - network::{CableConnectionType, Connection, FrozenNetwork, Network}, - vm::enums::script_enums::{LogicBatchMethod as BatchMode, LogicSlotType, LogicType}, + network::{CableConnectionType, CableNetwork, Connection, FrozenNetwork}, + vm::{ + enums::script_enums::{LogicBatchMethod as BatchMode, LogicSlotType, LogicType}, + object::{templates::ObjectTemplate, traits::*, BoxedObject, ObjectID, VMObject}, + }, }; use std::{ cell::RefCell, @@ -20,18 +23,37 @@ use serde_derive::{Deserialize, Serialize}; #[derive(Debug)] pub struct VM { - pub ics: BTreeMap>>, - pub devices: BTreeMap>>, - pub networks: BTreeMap>>, - pub default_network: u32, + pub objects: BTreeMap, + pub ic_holders: RefCell>, + pub networks: BTreeMap, + pub default_network_key: ObjectID, + pub wireless_transmitters: RefCell>, + pub wireless_receivers: RefCell>, id_space: IdSpace, network_id_space: IdSpace, random: Rc>, - /// list of device id's touched on the last operation - operation_modified: RefCell>, - #[allow(unused)] - objects: Vec, + /// list of object id's touched on the last operation + operation_modified: RefCell>, +} + +#[derive(Debug, Default)] +pub struct VMTransationNetwork { + pub objects: Vec, + pub power_only: Vec, +} + +#[derive(Debug)] +/// used as a temp structure to add objects in case +/// there are errors on nested templates +pub struct VMTransation { + pub objects: BTreeMap, + pub ic_holders: Vec, + pub default_network_key: ObjectID, + pub wireless_transmitters: Vec, + pub wireless_receivers: Vec, + pub id_space: IdSpace, + pub networks: BTreeMap, } impl Default for VM { @@ -45,216 +67,82 @@ impl VM { let id_space = IdSpace::default(); let mut network_id_space = IdSpace::default(); let default_network_key = network_id_space.next(); - let default_network = Rc::new(RefCell::new(Network::new(default_network_key))); + let default_network = VMObject::new(CableNetwork::new(default_network_key)); let mut networks = BTreeMap::new(); networks.insert(default_network_key, default_network); let mut vm = VM { - ics: BTreeMap::new(), - devices: BTreeMap::new(), + objects: BTreeMap::new(), + ic_holders: RefCell::new(Vec::new()), networks, - default_network: default_network_key, + default_network_key, + wireless_transmitters: RefCell::new(Vec::new()), + wireless_receivers: RefCell::new(Vec::new()), id_space, network_id_space, random: Rc::new(RefCell::new(crate::rand_mscorlib::Random::new())), operation_modified: RefCell::new(Vec::new()), - objects: Vec::new(), }; - let _ = vm.add_ic(None); vm } - fn new_device(&mut self) -> Device { - Device::new(self.id_space.next()) - } + pub fn add_device_from_template(&mut self, template: ObjectTemplate) -> Result { + let mut transaction = VMTransation::new(self); - fn new_ic(&mut self) -> (Device, interpreter::IC) { - let id = self.id_space.next(); - let ic_id = self.id_space.next(); - let ic = interpreter::IC::new(ic_id, id); - let device = Device::with_ic(id, ic_id); - (device, ic) - } + let obj_id = transaction.add_device_from_template(template)?; - pub fn random_f64(&self) -> f64 { - self.random.borrow_mut().next_f64() - } + let transation_ids = transaction.id_space.in_use_ids(); + self.id_space.use_new_ids(&transation_ids); - pub fn add_device(&mut self, network: Option) -> Result { - if let Some(n) = &network { - if !self.networks.contains_key(n) { - return Err(VMError::InvalidNetwork(*n)); + self.objects.extend(transaction.objects); + self.wireless_transmitters + .borrow_mut() + .extend(transaction.wireless_transmitters); + self.wireless_receivers + .borrow_mut() + .extend(transaction.wireless_receivers); + self.ic_holders.borrow_mut().extend(transaction.ic_holders); + for (net_id, trans_net) in transaction.networks.into_iter() { + let net = self + .networks + .get(&net_id) + .expect(&format!( + "desync between vm and transation networks: {net_id}" + )) + .borrow_mut() + .as_mut_network() + .expect(&format!("non network network: {net_id}")); + for id in trans_net.objects { + net.add_data(id); } - } - let mut device = self.new_device(); - if let Some(first_network) = device.connections.iter_mut().find_map(|c| { - if let Connection::CableNetwork { - net, - typ: CableConnectionType::Data | CableConnectionType::PowerAndData, - } = c - { - Some(net) - } else { - None - } - }) { - first_network.replace(if let Some(network) = network { - network - } else { - self.default_network - }); - } - let id = device.id; - - let first_data_network = device - .connections - .iter() - .enumerate() - .find_map(|(index, conn)| match conn { - Connection::CableNetwork { - typ: CableConnectionType::Data | CableConnectionType::PowerAndData, - .. - } => Some(index), - _ => None, - }); - self.devices.insert(id, Rc::new(RefCell::new(device))); - if let Some(first_data_network) = first_data_network { - let _ = self.set_device_connection( - id, - first_data_network, - if let Some(network) = network { - Some(network) - } else { - Some(self.default_network) - }, - ); - } - Ok(id) - } - - pub fn add_ic(&mut self, network: Option) -> Result { - if let Some(n) = &network { - if !self.networks.contains_key(n) { - return Err(VMError::InvalidNetwork(*n)); - } - } - let (mut device, ic) = self.new_ic(); - if let Some(first_network) = device.connections.iter_mut().find_map(|c| { - if let Connection::CableNetwork { - net, - typ: CableConnectionType::Data | CableConnectionType::PowerAndData, - } = c - { - Some(net) - } else { - None - } - }) { - first_network.replace(if let Some(network) = network { - network - } else { - self.default_network - }); - } - let id = device.id; - let ic_id = ic.id; - let first_data_network = device - .connections - .iter() - .enumerate() - .find_map(|(index, conn)| match conn { - Connection::CableNetwork { - typ: CableConnectionType::Data | CableConnectionType::PowerAndData, - .. - } => Some(index), - _ => None, - }); - self.devices.insert(id, Rc::new(RefCell::new(device))); - self.ics.insert(ic_id, Rc::new(RefCell::new(ic))); - if let Some(first_data_network) = first_data_network { - let _ = self.set_device_connection( - id, - first_data_network, - if let Some(network) = network { - Some(network) - } else { - Some(self.default_network) - }, - ); - } - Ok(id) - } - - pub fn add_device_from_template(&mut self, template: DeviceTemplate) -> Result { - for conn in &template.connections { - if let Connection::CableNetwork { net: Some(net), .. } = conn { - if !self.networks.contains_key(net) { - return Err(VMError::InvalidNetwork(*net)); - } + for id in trans_net.power_only { + net.add_power(id); } } - // collect the id's this template wants to use - let to_use_ids = template - .slots - .iter() - .filter_map(|slot| slot.occupant.as_ref().and_then(|occupant| occupant.id)) - .collect_vec(); - - // use those ids or fail - self.id_space.use_ids(&to_use_ids)?; - - let device = Device::from_template(template, || self.id_space.next()); - let device_id: u32 = device.id; - - // if this device says it has an IC make it so. - if let Some(ic_id) = &device.ic { - let chip = interpreter::IC::new(*ic_id, device_id); - self.ics.insert(*ic_id, Rc::new(RefCell::new(chip))); - } - - device.connections.iter().for_each(|conn| { - if let Connection::CableNetwork { - net: Some(net), - typ, - } = conn - { - if let Some(network) = self.networks.get(net) { - match typ { - CableConnectionType::Power => { - network.borrow_mut().add_power(device_id); - } - _ => { - network.borrow_mut().add_data(device_id); - } - } - } - } - }); - - self.devices - .insert(device_id, Rc::new(RefCell::new(device))); - - Ok(device_id) + Ok(obj_id) } pub fn add_network(&mut self) -> u32 { let next_id = self.network_id_space.next(); self.networks - .insert(next_id, Rc::new(RefCell::new(Network::new(next_id)))); + .insert(next_id, Rc::new(RefCell::new(CableNetwork::new(next_id)))); next_id } - pub fn get_default_network(&self) -> Rc> { - self.networks.get(&self.default_network).cloned().unwrap() + pub fn get_default_network(&self) -> Rc> { + self.networks + .get(&self.default_network_key) + .cloned() + .unwrap() } - pub fn get_network(&self, id: u32) -> Option>> { + pub fn get_network(&self, id: u32) -> Option>> { self.networks.get(&id).cloned() } pub fn remove_ic(&mut self, id: u32) { - if self.ics.remove(&id).is_some() { + if self.ic_holders.remove(&id).is_some() { self.devices.remove(&id); } } @@ -267,7 +155,7 @@ impl VM { .ok_or(VMError::UnknownId(old_id))?; device.borrow_mut().id = new_id; self.devices.insert(new_id, device); - self.ics.iter().for_each(|(_id, ic)| { + self.ic_holders.iter().for_each(|(_id, ic)| { let mut ic_ref = ic.borrow_mut(); if ic_ref.device == old_id { ic_ref.device = new_id; @@ -298,7 +186,7 @@ impl VM { .borrow(); let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?; let ic = self - .ics + .ic_holders .get(&ic_id) .ok_or(VMError::UnknownIcId(ic_id))? .borrow(); @@ -317,7 +205,7 @@ impl VM { .borrow(); let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?; let ic = self - .ics + .ic_holders .get(&ic_id) .ok_or(VMError::UnknownIcId(ic_id))? .borrow_mut(); @@ -342,7 +230,7 @@ impl VM { }; self.set_modified(id); let ic = self - .ics + .ic_holders .get(&ic_id) .ok_or(VMError::UnknownIcId(ic_id))? .clone(); @@ -357,7 +245,7 @@ impl VM { let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?.clone(); let ic_id = *device.borrow().ic.as_ref().ok_or(VMError::NoIC(id))?; let ic = self - .ics + .ic_holders .get(&ic_id) .ok_or(VMError::UnknownIcId(ic_id))? .clone(); @@ -381,51 +269,56 @@ impl VM { Ok(true) } - pub fn set_modified(&self, id: u32) { + pub fn set_modified(&self, id: ObjectID) { self.operation_modified.borrow_mut().push(id); } - pub fn reset_ic(&self, id: u32) -> Result { - let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?.clone(); - let ic_id = *device.borrow().ic.as_ref().ok_or(VMError::NoIC(id))?; + pub fn reset_ic(&self, id: ObjectID) -> Result { + let obj = self.objects.get(&id).ok_or(VMError::UnknownId(id))?.clone(); + let ic_id = obj + .borrow() + .as_mut_circuit_holder() + .map(|holder| holder.get_ic()) + .flatten() + .ok_or(VMError::NoIC(id))?; let ic = self - .ics + .objects .get(&ic_id) .ok_or(VMError::UnknownIcId(ic_id))? - .clone(); - ic.borrow().ic.replace(0); - ic.borrow().reset(); + .borrow_mut() + .as_mut_programmable() + .ok_or(VMError::UnknownIcId(ic_id))?; + ic.reset(); Ok(true) } - pub fn get_device(&self, id: u32) -> Option>> { - self.devices.get(&id).cloned() + pub fn get_object(&self, id: ObjectID) -> Option { + self.objects.get(&id).cloned() } pub fn batch_device( &self, - source: u32, + source: ObjectID, prefab_hash: f64, name: Option, - ) -> impl Iterator>> { - self.devices + ) -> impl Iterator { + self.objects .iter() .filter(move |(id, device)| { - device - .borrow() - .get_fields(self) - .get(&LogicType::PrefabHash) - .is_some_and(|f| f.value == prefab_hash) - && (name.is_none() - || name == device.borrow().name_hash.as_ref().map(|hash| *hash as f64)) + device.borrow().as_device().is_some_and(|device| { + device + .get_logic(LogicType::PrefabHash) + .is_ok_and(|f| f == prefab_hash) + }) && (name.is_none() + || name.is_some_and(|name| name == device.borrow().name().hash as f64)) && self.devices_on_same_network(&[source, **id]) }) .map(|(_, d)| d) } - pub fn get_device_same_network(&self, source: u32, other: u32) -> Option>> { + pub fn get_device_same_network(&self, source: ObjectID, other: ObjectID) -> Option { if self.devices_on_same_network(&[source, other]) { - self.get_device(other) + self.get_object(other) } else { None } @@ -436,36 +329,60 @@ impl VM { if !(0..8).contains(&channel) { Err(ICError::ChannelIndexOutOfRange(channel)) } else { - Ok(network.borrow().channels[channel]) + let channel_lt = LogicType::from_repr((LogicType::Channel0 as usize + channel) as u16) + .expect("channel logictype repr out of range"); + let val = network + .borrow_mut() + .as_network() + .expect("non-network network") + .get_logic(channel_lt)?; + Ok(val) } } - pub fn set_network_channel(&self, id: u32, channel: usize, val: f64) -> Result<(), ICError> { + pub fn set_network_channel( + &self, + id: ObjectID, + channel: usize, + val: f64, + ) -> Result<(), ICError> { let network = self.networks.get(&(id)).ok_or(ICError::BadNetworkId(id))?; if !(0..8).contains(&channel) { Err(ICError::ChannelIndexOutOfRange(channel)) } else { - network.borrow_mut().channels[channel] = val; + let channel_lt = LogicType::from_repr((LogicType::Channel0 as usize + channel) as u16) + .expect("channel logictype repr out of range"); + network + .borrow_mut() + .as_mut_network() + .expect("non-network network") + .set_logic(channel_lt, val, true)?; Ok(()) } } - pub fn devices_on_same_network(&self, ids: &[u32]) -> bool { + pub fn devices_on_same_network(&self, ids: &[ObjectID]) -> bool { for net in self.networks.values() { - if net.borrow().contains_all_data(ids) { + if net + .borrow() + .as_network() + .expect("non network network") + .contains_all_data(ids) + { return true; } } false } - /// return a vecter with the device ids the source id can see via it's connected networks - pub fn visible_devices(&self, source: u32) -> Vec { + /// return a vector with the device ids the source id can see via it's connected networks + pub fn visible_devices(&self, source: ObjectID) -> Vec { self.networks .values() .filter_map(|net| { - if net.borrow().contains_data(&source) { - Some(net.borrow().data_visible(&source)) + let net_ref = net.borrow().as_network().expect("non-network network"); + if net_ref.contains_data(&source) { + Some(net_ref.data_visible(&source)) } else { None } @@ -473,82 +390,92 @@ impl VM { .concat() } - pub fn set_pin(&self, id: u32, pin: usize, val: Option) -> Result { - let Some(device) = self.devices.get(&id) else { + pub fn set_pin(&self, id: u32, pin: usize, val: Option) -> Result { + let Some(obj) = self.objects.get(&id) else { return Err(VMError::UnknownId(id)); }; if let Some(other_device) = val { - if !self.devices.contains_key(&other_device) { + if !self.objects.contains_key(&other_device) { return Err(VMError::UnknownId(other_device)); } if !self.devices_on_same_network(&[id, other_device]) { return Err(VMError::DeviceNotVisible(other_device, id)); } } - if !(0..6).contains(&pin) { + let Some(device) = obj.borrow_mut().as_mut_device() else { + return Err(VMError::NotADevice(id)); + }; + let Some(pins) = device.device_pins_mut() else { + return Err(VMError::NoDevicePins(id)); + }; + if !(0..pins.len()).contains(&pin) { Err(ICError::PinIndexOutOfRange(pin).into()) } else { - let Some(ic_id) = device.borrow().ic else { - return Err(VMError::NoIC(id)); - }; - self.ics.get(&ic_id).unwrap().borrow().pins.borrow_mut()[pin] = val; + pins[pin] = val; Ok(true) } } pub fn set_device_connection( &self, - id: u32, + id: ObjectID, connection: usize, - target_net: Option, + target_net: Option, ) -> Result { - let Some(device) = self.devices.get(&id) else { + let Some(obj) = self.objects.get(&id) else { return Err(VMError::UnknownId(id)); }; - if connection >= device.borrow().connections.len() { - let conn_len = device.borrow().connections.len(); + let Some(device) = obj.borrow_mut().as_mut_device() else { + return Err(VMError::NotADevice(id)); + }; + let connections = device.connection_list_mut(); + if connection >= connections.len() { + let conn_len = connections.len(); return Err(ICError::ConnectionIndexOutOfRange(connection, conn_len).into()); } - { - // scope this borrow - let connections = &device.borrow().connections; - let Connection::CableNetwork { net, typ } = &connections[connection] else { - return Err(ICError::NotACableConnection(connection).into()); - }; - // remove from current network - if let Some(net) = net { - if let Some(network) = self.networks.get(net) { - // if there is no other connection to this network - if connections - .iter() - .filter(|conn| { - matches!(conn, Connection::CableNetwork { - net: Some(other_net), - typ: other_typ - } if other_net == net && ( - !matches!(typ, CableConnectionType::Power) || - matches!(other_typ, CableConnectionType::Data | CableConnectionType::PowerAndData)) - ) - }) - .count() - == 1 - { - match typ { - CableConnectionType::Power => { - network.borrow_mut().remove_power(id); - } - _ => { - network.borrow_mut().remove_data(id); - - } + // scope this borrow + let Connection::CableNetwork { net, typ } = &connections[connection] else { + return Err(ICError::NotACableConnection(connection).into()); + }; + // remove from current network + if let Some(net) = net { + if let Some(network) = self.networks.get(net) { + // if there is no other connection to this network + if connections + .iter() + .filter(|conn| { + matches!(conn, Connection::CableNetwork { + net: Some(other_net), + typ: other_typ + } if other_net == net && ( + !matches!(typ, CableConnectionType::Power) || + matches!(other_typ, CableConnectionType::Data | CableConnectionType::PowerAndData)) + ) + }) + .count() + == 1 + { + match typ { + CableConnectionType::Power => { + network + .borrow_mut() + .as_mut_network() + .expect("non-network network") + .remove_power(id); + } + _ => { + network + .borrow_mut() + .as_mut_network() + .expect("non-network network") + .remove_data(id); } } } } } - let mut device_ref = device.borrow_mut(); - let connections = &mut device_ref.connections; + let Connection::CableNetwork { ref mut net, ref typ, @@ -560,10 +487,18 @@ impl VM { if let Some(network) = self.networks.get(&target_net) { match typ { CableConnectionType::Power => { - network.borrow_mut().add_power(id); + network + .borrow_mut() + .as_mut_network() + .expect("non-network network") + .add_power(id); } _ => { - network.borrow_mut().add_data(id); + network + .borrow_mut() + .as_mut_network() + .expect("non-network network") + .add_data(id); } } } else { @@ -574,21 +509,31 @@ impl VM { Ok(true) } - pub fn remove_device_from_network(&self, id: u32, network_id: u32) -> Result { + pub fn remove_device_from_network( + &self, + id: ObjectID, + network_id: ObjectID, + ) -> Result { if let Some(network) = self.networks.get(&network_id) { - let Some(device) = self.devices.get(&id) else { + let Some(obj) = self.objects.get(&id) else { return Err(VMError::UnknownId(id)); }; - let mut device_ref = device.borrow_mut(); + let Some(device) = obj.borrow_mut().as_mut_device() else { + return Err(VMError::NotADevice(id)); + }; - for conn in device_ref.connections.iter_mut() { + for conn in device.connection_list_mut().iter_mut() { if let Connection::CableNetwork { net, .. } = conn { if net.is_some_and(|id| id == network_id) { *net = None; } } } - network.borrow_mut().remove_all(id); + network + .borrow_mut() + .as_mut_network() + .expect("non-network network") + .remove_all(id); Ok(true) } else { Err(VMError::InvalidNetwork(network_id)) @@ -597,7 +542,7 @@ impl VM { pub fn set_batch_device_field( &self, - source: u32, + source: ObjectID, prefab: f64, typ: LogicType, val: f64, @@ -605,17 +550,20 @@ impl VM { ) -> Result<(), ICError> { self.batch_device(source, prefab, None) .map(|device| { - self.set_modified(device.borrow().id); + self.set_modified(*device.borrow().id()); device .borrow_mut() - .set_field(typ, val, self, write_readonly) + .as_mut_device() + .expect("batch iter yielded non device") + .set_logic(typ, val, write_readonly) + .map_err(Into::into) }) .try_collect() } pub fn set_batch_device_slot_field( &self, - source: u32, + source: ObjectID, prefab: f64, index: f64, typ: LogicSlotType, @@ -624,17 +572,20 @@ impl VM { ) -> Result<(), ICError> { self.batch_device(source, prefab, None) .map(|device| { - self.set_modified(device.borrow().id); + self.set_modified(*device.borrow().id()); device .borrow_mut() - .set_slot_field(index, typ, val, self, write_readonly) + .as_mut_device() + .expect("batch iter yielded non device") + .set_slot_logic(typ, index, val, self, write_readonly) + .map_err(Into::into) }) .try_collect() } pub fn set_batch_name_device_field( &self, - source: u32, + source: ObjectID, prefab: f64, name: f64, typ: LogicType, @@ -643,24 +594,34 @@ impl VM { ) -> Result<(), ICError> { self.batch_device(source, prefab, Some(name)) .map(|device| { - self.set_modified(device.borrow().id); + self.set_modified(*device.borrow().id()); device .borrow_mut() - .set_field(typ, val, self, write_readonly) + .as_mut_device() + .expect("batch iter yielded non device") + .set_logic(typ, val, write_readonly) + .map_err(Into::into) }) .try_collect() } pub fn get_batch_device_field( &self, - source: u32, + source: ObjectID, prefab: f64, typ: LogicType, mode: BatchMode, ) -> Result { let samples = self .batch_device(source, prefab, None) - .map(|device| device.borrow_mut().get_field(typ, self)) + .map(|device| { + device + .borrow() + .as_device() + .expect("batch iter yielded non device") + .get_logic(typ) + .map_err(Into::into) + }) .filter_ok(|val| !val.is_nan()) .collect::, ICError>>()?; Ok(mode.apply(&samples)) @@ -668,7 +629,7 @@ impl VM { pub fn get_batch_name_device_field( &self, - source: u32, + source: ObjectID, prefab: f64, name: f64, typ: LogicType, @@ -676,7 +637,14 @@ impl VM { ) -> Result { let samples = self .batch_device(source, prefab, Some(name)) - .map(|device| device.borrow_mut().get_field(typ, self)) + .map(|device| { + device + .borrow() + .as_device() + .expect("batch iter yielded non device") + .get_logic(typ) + .map_err(Into::into) + }) .filter_ok(|val| !val.is_nan()) .collect::, ICError>>()?; Ok(mode.apply(&samples)) @@ -684,7 +652,7 @@ impl VM { pub fn get_batch_name_device_slot_field( &self, - source: u32, + source: ObjectID, prefab: f64, name: f64, index: f64, @@ -693,7 +661,14 @@ impl VM { ) -> Result { let samples = self .batch_device(source, prefab, Some(name)) - .map(|device| device.borrow().get_slot_field(index, typ, self)) + .map(|device| { + device + .borrow() + .as_device() + .expect("batch iter yielded non device") + .get_slot_logic(typ, index, self) + .map_err(Into::into) + }) .filter_ok(|val| !val.is_nan()) .collect::, ICError>>()?; Ok(mode.apply(&samples)) @@ -701,7 +676,7 @@ impl VM { pub fn get_batch_device_slot_field( &self, - source: u32, + source: ObjectID, prefab: f64, index: f64, typ: LogicSlotType, @@ -709,52 +684,72 @@ impl VM { ) -> Result { let samples = self .batch_device(source, prefab, None) - .map(|device| device.borrow().get_slot_field(index, typ, self)) + .map(|device| { + device + .borrow() + .as_device() + .expect("batch iter yielded non device") + .get_slot_logic(typ, index, self) + .map_err(Into::into) + }) .filter_ok(|val| !val.is_nan()) .collect::, ICError>>()?; Ok(mode.apply(&samples)) } - pub fn remove_device(&mut self, id: u32) -> Result<(), VMError> { - let Some(device) = self.devices.remove(&id) else { + pub fn remove_object(&mut self, id: ObjectID) -> Result<(), VMError> { + let Some(obj) = self.objects.remove(&id) else { return Err(VMError::UnknownId(id)); }; - for conn in device.borrow().connections.iter() { - if let Connection::CableNetwork { net: Some(net), .. } = conn { - if let Some(network) = self.networks.get(net) { - network.borrow_mut().remove_all(id); + if let Some(device) = obj.borrow().as_device() { + for conn in device.connection_list().iter() { + if let Connection::CableNetwork { net: Some(net), .. } = conn { + if let Some(network) = self.networks.get(net) { + network + .borrow_mut() + .as_mut_network() + .expect("non-network network") + .remove_all(id); + } } } - } - if let Some(ic_id) = device.borrow().ic { - let _ = self.ics.remove(&ic_id); + if let Some(_) = device.as_circuit_holder() { + self.ic_holders.borrow_mut().retain(|a| *a != id); + } } self.id_space.free_id(id); Ok(()) } + /// set a slot to contain some quantity of an object with ID + /// object must already be added to the VM + /// does not clean up previous object + /// returns the id of any former occupant pub fn set_slot_occupant( &mut self, - id: u32, + id: ObjectID, index: usize, - template: SlotOccupantTemplate, - ) -> Result<(), VMError> { - let Some(device) = self.devices.get(&id) else { + target: Option, + quantity: u32, + ) -> Result, VMError> { + let Some(obj) = self.objects.get(&id) else { return Err(VMError::UnknownId(id)); }; - let mut device_ref = device.borrow_mut(); - let slot = device_ref - .slots - .get_mut(index) + // FIXME: check that object has storage and object to be added is an item + // need to move parentage and remove object from it former slot if it has one + + let Some(storage) = obj.borrow_mut().as_mut_storage() else { + return Err(VMError::NotStorage(id)); + }; + let slot = storage + .get_slot_mut(index) .ok_or(ICError::SlotIndexOutOfRange(index as f64))?; - if let Some(id) = template.id.as_ref() { - self.id_space.use_id(*id)?; - } + if + - let occupant = SlotOccupant::from_template(template, || self.id_space.next()); if let Some(last) = slot.occupant.as_ref() { self.id_space.free_id(last.id); } @@ -782,7 +777,11 @@ impl VM { pub fn save_vm_state(&self) -> FrozenVM { FrozenVM { - ics: self.ics.values().map(|ic| ic.borrow().into()).collect(), + ics: self + .ic_holders + .values() + .map(|ic| ic.borrow().into()) + .collect(), devices: self .devices .values() @@ -793,12 +792,12 @@ impl VM { .values() .map(|network| network.borrow().into()) .collect(), - default_network: self.default_network, + default_network: self.default_network_key, } } pub fn restore_vm_state(&mut self, state: FrozenVM) -> Result<(), VMError> { - self.ics.clear(); + self.ic_holders.clear(); self.devices.clear(); self.networks.clear(); self.id_space.reset(); @@ -825,7 +824,7 @@ impl VM { self.network_id_space .use_ids(&state.networks.iter().map(|net| net.id).collect_vec())?; - self.ics = state + self.ic_holders = state .ics .into_iter() .map(|ic| (ic.id, Rc::new(RefCell::new(ic.into())))) @@ -843,11 +842,95 @@ impl VM { .into_iter() .map(|network| (network.id, Rc::new(RefCell::new(network.into())))) .collect(); - self.default_network = state.default_network; + self.default_network_key = state.default_network; Ok(()) } } +impl VMTransation { + pub fn new(vm: &VM) -> Self { + VMTransation { + objects: BTreeMap::new(), + ic_holders: Vec::new(), + default_network_key: vm.default_network_key, + wireless_transmitters: Vec::new(), + wireless_receivers: Vec::new(), + id_space: vm.id_space.clone(), + networks: vm + .networks + .keys() + .map(|net_id| (*net_id, VMTransationNetwork::default())) + .collect(), + } + } + + pub fn add_device_from_template( + &mut self, + template: ObjectTemplate, + ) -> Result { + for net_id in &template.connected_networks() { + if !self.networks.contains_key(net_id) { + return Err(VMError::InvalidNetwork(*net_id)); + } + } + + let obj_id = if let Some(obj_id) = template.object().map(|info| info.id).flatten() { + self.id_space.use_id(obj_id)?; + obj_id + } else { + self.id_space.next() + }; + + let obj = template.build(obj_id); + + if let Some(storage) = obj.borrow_mut().as_mut_storage() { + for (slot_index, occupant_template) in + template.templates_from_slots().into_iter().enumerate() + { + if let Some(occupant_template) = occupant_template { + let occupant_id = self.add_device_from_template(occupant_template)?; + storage + .get_slot_mut(slot_index) + .expect(&format!("object storage slots out of sync with template which built it: {slot_index}")) + .occupant = Some(occupant_id); + } + } + } + + if let Some(w_logicable) = obj.borrow().as_wireless_transmit() { + self.wireless_transmitters.push(obj_id); + } + if let Some(r_logicable) = obj.borrow().as_wireless_receive() { + self.wireless_receivers.push(obj_id); + } + if let Some(circuit_holder) = obj.borrow().as_circuit_holder() { + self.ic_holders.push(obj_id); + } + if let Some(device) = obj.borrow_mut().as_mut_device() { + for conn in device.connection_list().iter() { + if let Connection::CableNetwork { + net: Some(net_id), + typ, + } = conn + { + if let Some(net) = self.networks.get_mut(net_id) { + match typ { + CableConnectionType::Power => net.power_only.push(obj_id), + _ => net.objects.push(obj_id), + } + } else { + return Err(VMError::InvalidNetwork(*net_id)); + } + } + } + } + + self.objects.insert(obj_id, obj); + + Ok(obj_id) + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FrozenVM { pub ics: Vec, @@ -876,10 +959,10 @@ impl BatchMode { } } -#[derive(Debug)] +#[derive(Debug, Clone)] struct IdSpace { - next: u32, - in_use: HashSet, + next: ObjectID, + in_use: HashSet, } impl Default for IdSpace { @@ -896,14 +979,22 @@ impl IdSpace { } } - pub fn next(&mut self) -> u32 { + pub fn next(&mut self) -> ObjectID { let val = self.next; self.next += 1; self.in_use.insert(val); val } - pub fn use_id(&mut self, id: u32) -> Result<(), VMError> { + pub fn has_id(&self, id: &ObjectID) -> bool { + self.in_use.contains(id) + } + + pub fn in_use_ids(&self) -> Vec { + self.in_use.iter().copied().collect() + } + + pub fn use_id(&mut self, id: ObjectID) -> Result<(), VMError> { if self.in_use.contains(&id) { Err(VMError::IdInUse(id)) } else { @@ -914,10 +1005,10 @@ impl IdSpace { pub fn use_ids<'a, I>(&mut self, ids: I) -> Result<(), VMError> where - I: IntoIterator + std::marker::Copy, + I: IntoIterator + std::marker::Copy, { - let mut to_use: HashSet = HashSet::new(); - let mut duplicates: HashSet = HashSet::new(); + let mut to_use: HashSet = HashSet::new(); + let mut duplicates: HashSet = HashSet::new(); let all_uniq = ids.into_iter().copied().all(|id| { if to_use.insert(id) { true @@ -938,7 +1029,16 @@ impl IdSpace { Ok(()) } - pub fn free_id(&mut self, id: u32) { + /// use the ids in the iterator that aren't already in use + pub fn use_new_ids<'a, I>(&mut self, ids: I) + where + I: IntoIterator + std::marker::Copy, + { + self.in_use.extend(ids); + self.next = self.in_use.iter().max().unwrap_or(&0) + 1; + } + + pub fn free_id(&mut self, id: ObjectID) { self.in_use.remove(&id); } diff --git a/ic10emu/src/vm/instructions/operands.rs b/ic10emu/src/vm/instructions/operands.rs index 9da8199..ac270e2 100644 --- a/ic10emu/src/vm/instructions/operands.rs +++ b/ic10emu/src/vm/instructions/operands.rs @@ -1,14 +1,15 @@ use crate::errors::ICError; use crate::interpreter; -use crate::vm::enums::script_enums::{ - LogicBatchMethod as BatchMode, LogicReagentMode as ReagentMode, LogicSlotType, LogicType, +use crate::vm::{ + enums::script_enums::{ + LogicBatchMethod as BatchMode, LogicReagentMode as ReagentMode, LogicSlotType, LogicType, + }, + instructions::enums::InstructionOp, + object::traits::IntegratedCircuit, }; -use crate::vm::instructions::enums::InstructionOp; use serde_derive::{Deserialize, Serialize}; use strum::EnumProperty; -use super::traits::IntegratedCircuit; - #[derive(PartialEq, Eq, Debug, Clone, Copy, Serialize, Deserialize)] pub enum Device { Db, @@ -191,28 +192,14 @@ impl Operand { ) -> Result<(Option, Option), ICError> { match self.translate_alias(ic) { Operand::DeviceSpec(DeviceSpec { device, connection }) => match device { - Device::Db => Ok((Some(ic.device), connection)), - Device::Numbered(p) => { - let dp = ic - .pins - .borrow() - .get(p as usize) - .ok_or(ICError::DeviceIndexOutOfRange(p as f64)) - .copied()?; - Ok((dp, connection)) - } + Device::Db => Ok((Some(0), connection)), + Device::Numbered(p) => Ok((Some(p), connection)), Device::Indirect { indirection, target, } => { let val = ic.get_register(indirection, target)?; - let dp = ic - .pins - .borrow() - .get(val as usize) - .ok_or(ICError::DeviceIndexOutOfRange(val)) - .copied()?; - Ok((dp, connection)) + Ok((Some(val as u32), connection)) } }, Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())), @@ -287,11 +274,11 @@ impl Operand { pub fn translate_alias(&self, ic: &IC) -> Self { match &self { Operand::Identifier(id) | Operand::Type { identifier: id, .. } => { - if let Some(alias) = ic.aliases.borrow().get(&id.name) { + if let Some(alias) = ic.get_aliases().get(&id.name) { alias.clone() - } else if let Some(define) = ic.defines.borrow().get(&id.name) { + } else if let Some(define) = ic.get_defines().get(&id.name) { Operand::Number(Number::Float(*define)) - } else if let Some(label) = ic.program.borrow().labels.get(&id.name) { + } else if let Some(label) = ic.get_labels().get(&id.name) { Operand::Number(Number::Float(*label as f64)) } else { self.clone() diff --git a/ic10emu/src/vm/instructions/traits.rs b/ic10emu/src/vm/instructions/traits.rs index bb9fe67..e7bc54d 100644 --- a/ic10emu/src/vm/instructions/traits.rs +++ b/ic10emu/src/vm/instructions/traits.rs @@ -9,32 +9,7 @@ // // ================================================= -use crate::errors::ICError; -use crate::vm::object::traits::{Logicable, MemoryWritable, SourceCode}; -use std::collections::BTreeMap; -pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode { - fn get_instruction_pointer(&self) -> f64; - fn set_next_instruction(&mut self, next_instruction: f64); - fn set_next_instruction_relative(&mut self, offset: f64) { - self.set_next_instruction(self.get_instruction_pointer() + offset); - } - fn reset(&mut self); - fn get_real_target(&self, indirection: u32, target: u32) -> Result; - fn get_register(&self, indirection: u32, target: u32) -> Result; - fn set_register(&mut self, indirection: u32, target: u32, val: f64) -> Result; - fn set_return_address(&mut self, addr: f64); - fn al(&mut self) { - self.set_return_address(self.get_instruction_pointer() + 1.0); - } - fn push_stack(&mut self, val: f64) -> Result; - fn pop_stack(&mut self) -> Result; - fn peek_stack(&self) -> Result; - fn get_stack(&self, addr: f64) -> Result; - fn put_stack(&self, addr: f64, val: f64) -> Result; - fn get_aliases(&self) -> &BTreeMap; - fn get_defines(&self) -> &BTreeMap; - fn get_labels(&self) -> &BTreeMap; -} +use crate::vm::object::traits::IntegratedCircuit; pub trait AbsInstruction: IntegratedCircuit { /// abs r? a(r?|num) fn execute_abs( diff --git a/ic10emu/src/vm/object.rs b/ic10emu/src/vm/object.rs index f36b081..8f9590a 100644 --- a/ic10emu/src/vm/object.rs +++ b/ic10emu/src/vm/object.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, ops::Deref, rc::Rc, str::FromStr}; +use std::{cell::RefCell, ops::{Deref, DerefMut}, rc::Rc, str::FromStr}; use macro_rules_attribute::derive; use serde_derive::{Deserialize, Serialize}; @@ -19,6 +19,7 @@ use super::enums::prefabs::StationpediaPrefab; pub type ObjectID = u32; pub type BoxedObject = Rc>>; +#[derive(Debug, Clone)] pub struct VMObject(BoxedObject); impl Deref for VMObject { @@ -30,6 +31,14 @@ impl Deref for VMObject { } } +impl DerefMut for VMObject { + + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + impl VMObject { pub fn new(val: T) -> Self where @@ -65,7 +74,7 @@ impl Name { if let Some(prefab) = StationpediaPrefab::from_repr(hash) { Some(Name { value: prefab.to_string(), - hash: hash, + hash, }) } else { None diff --git a/ic10emu/src/vm/object/errors.rs b/ic10emu/src/vm/object/errors.rs index 777764f..c028fc0 100644 --- a/ic10emu/src/vm/object/errors.rs +++ b/ic10emu/src/vm/object/errors.rs @@ -3,7 +3,7 @@ use thiserror::Error; use crate::vm::enums::script_enums::{LogicSlotType, LogicType}; -#[derive(Error, Debug, Serialize, Deserialize)] +#[derive(Error, Debug, Clone, Serialize, Deserialize)] pub enum LogicError { #[error("can't read LogicType {0}")] CantRead(LogicType), @@ -17,7 +17,7 @@ pub enum LogicError { SlotIndexOutOfRange(usize, usize), } -#[derive(Error, Debug, Serialize, Deserialize)] +#[derive(Error, Debug, Clone, Serialize, Deserialize)] pub enum MemoryError { #[error("stack underflow: {0} < range [0..{1})")] StackUnderflow(i32, usize), diff --git a/ic10emu/src/vm/object/generic/macros.rs b/ic10emu/src/vm/object/generic/macros.rs index 741a9ef..e4b7d84 100644 --- a/ic10emu/src/vm/object/generic/macros.rs +++ b/ic10emu/src/vm/object/generic/macros.rs @@ -79,7 +79,23 @@ macro_rules! GWDevice { $($body:tt)* } ) => { - impl GWDevice for $struct {} + impl GWDevice for $struct { + fn device_info(&self) -> &DeviceInfo { + &self.device_info + } + fn device_connections(&self) -> &[Connection] { + self.connections.as_slice() + } + fn device_connections_mut(&mut self) -> &mut [Connection] { + self.connections.as_mut_slice() + } + fn device_pins(&self) -> Option<&[Option]> { + self.pins.as_ref().map(|pins| pins.as_slice()) + } + fn device_pins_mut(&mut self) -> Option<&mut [Option]> { + self.pins.as_mut().map(|pins| pins.as_mut_slice()) + } + } }; } pub(crate) use GWDevice; diff --git a/ic10emu/src/vm/object/generic/structs.rs b/ic10emu/src/vm/object/generic/structs.rs index 03a0883..bb7fdc6 100644 --- a/ic10emu/src/vm/object/generic/structs.rs +++ b/ic10emu/src/vm/object/generic/structs.rs @@ -1,11 +1,11 @@ use super::{macros::*, traits::*}; -use crate::vm::{ +use crate::{network::Connection, vm::{ enums::script_enums::LogicType, object::{ - macros::ObjectInterface, templates::ItemInfo, traits::*, LogicField, Name, ObjectID, Slot, + macros::ObjectInterface, templates::{DeviceInfo, ItemInfo}, traits::*, LogicField, Name, ObjectID, Slot, }, -}; +}}; use macro_rules_attribute::derive; use std::collections::BTreeMap; @@ -56,6 +56,9 @@ pub struct GenericLogicableDevice { pub name: Name, pub fields: BTreeMap, pub slots: Vec, + pub device_info: DeviceInfo, + pub connections: Vec, + pub pins: Option>>, } #[derive(ObjectInterface!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)] @@ -69,6 +72,9 @@ pub struct GenericLogicableDeviceMemoryReadable { pub name: Name, pub fields: BTreeMap, pub slots: Vec, + pub device_info: DeviceInfo, + pub connections: Vec, + pub pins: Option>>, pub memory: Vec, } @@ -83,6 +89,9 @@ pub struct GenericLogicableDeviceMemoryReadWriteable { pub name: Name, pub fields: BTreeMap, pub slots: Vec, + pub device_info: DeviceInfo, + pub connections: Vec, + pub pins: Option>>, pub memory: Vec, } diff --git a/ic10emu/src/vm/object/generic/traits.rs b/ic10emu/src/vm/object/generic/traits.rs index 3e3cd91..0a3885a 100644 --- a/ic10emu/src/vm/object/generic/traits.rs +++ b/ic10emu/src/vm/object/generic/traits.rs @@ -1,16 +1,13 @@ -use crate::vm::{ +use crate::{network::Connection, vm::{ enums::{ basic_enums::{Class as SlotClass, GasType, SortingClass}, script_enums::{LogicSlotType, LogicType}, }, object::{ - errors::{LogicError, MemoryError}, - templates::ItemInfo, - traits::*, - LogicField, MemoryAccess, Slot, + errors::{LogicError, MemoryError}, templates::{DeviceInfo, ItemInfo}, traits::*, LogicField, MemoryAccess, ObjectID, Slot }, VM, -}; +}}; use std::{collections::BTreeMap, usize}; use strum::IntoEnumIterator; @@ -166,9 +163,46 @@ impl MemoryWritable for T { } } -pub trait GWDevice: Logicable {} +pub trait GWDevice: Logicable { + fn device_info(&self) -> &DeviceInfo; + fn device_connections(&self) -> &[Connection]; + fn device_connections_mut(&mut self) -> &mut [Connection]; + fn device_pins(&self) -> Option<&[Option]>; + fn device_pins_mut(&mut self) -> Option<&mut [Option]>; +} -impl Device for T {} +impl Device for T { + fn connection_list(&self) -> &[crate::network::Connection] { + self.device_connections() + } + fn connection_list_mut(&mut self) -> &mut[Connection] { + self.device_connections_mut() + } + fn device_pins(&self) -> Option<&[Option]> { + self.device_pins() + } + fn device_pins_mut(&self) -> Option<&mut[Option]> { + self.device_pins_mut() + } + fn has_reagents(&self) -> bool { + self.device_info().has_reagents + } + fn has_lock_state(&self) -> bool { + self.device_info().has_lock_state + } + fn has_mode_state(&self) -> bool { + self.device_info().has_mode_state + } + fn has_open_state(&self) -> bool { + self.device_info().has_open_state + } + fn has_on_off_state(&self) -> bool { + self.device_info().has_on_off_state + } + fn has_activate_state(&self) -> bool { + self.device_info().has_activate_state + } +} pub trait GWItem { fn item_info(&self) -> &ItemInfo; diff --git a/ic10emu/src/vm/object/macros.rs b/ic10emu/src/vm/object/macros.rs index c2e1c31..2b1f708 100644 --- a/ic10emu/src/vm/object/macros.rs +++ b/ic10emu/src/vm/object/macros.rs @@ -1,5 +1,5 @@ macro_rules! object_trait { - (@intf {$trait_name:ident $trt:path}) => { + (@intf {$trait_name:ident $trt:ident}) => { paste::paste! { #[allow(missing_docs, unused)] pub type [<$trt Ref>]<'a, T> = &'a dyn $trt::ID>; @@ -7,7 +7,7 @@ macro_rules! object_trait { pub type [<$trt RefMut>]<'a, T> = &'a mut dyn $trt::ID>; } }; - (@body $trait_name:ident $($trt:path),*) => { + (@body $trait_name:ident { $($trt:ident),* }; ) => { type ID; fn id(&self) -> &Self::ID; fn prefab(&self) -> &crate::vm::object::Name; @@ -19,27 +19,30 @@ macro_rules! object_trait { fn as_object_mut(&mut self) -> &mut dyn $trait_name; - - paste::paste!{$( + $( + paste::paste! { #[inline(always)] fn [](&self) -> Option<[<$trt Ref>]> { None } #[inline(always)] - fn [](&mut self) -> Option<[<$trt RefMut>]> { + fn [](&mut self) -> Option<[<$trt RefMut>]> { None } - )*} + } + )* }; - ( $trait_name:ident $(: $($bound:tt)* )? {$($trt:path),*}) => { + ( $trait_name:ident $(: $($bound:tt)* )? {$($trt:ident),*}) => { $( $crate::vm::object::macros::object_trait!{@intf {$trait_name $trt}} )* + + #[doc = concat!("Generated with: ", stringify!($($trt),*))] pub trait $trait_name $(: $($bound)* )? { - $crate::vm::object::macros::object_trait!{@body $trait_name $($trt),*} + $crate::vm::object::macros::object_trait!{@body $trait_name {$($trt),*}; } } }; } @@ -91,7 +94,7 @@ macro_rules! ObjectInterface { } #[inline(always)] - fn [](&mut self) -> Option<[<$trt RefMut>]> { + fn [](&mut self) -> Option<[<$trt RefMut>]> { Some(self) } )*} @@ -508,25 +511,30 @@ macro_rules! tag_object_traits { { @tag tag=$trt_name:ident $(: $($obj_bound:tt)* )?; - acc={ $($tagged_trt:ident,)* } + acc={ $($tagged_trt:ident,)* }; $(#[$attr:meta])* - $viz:vis trait $trt:ident $(: $($trt_bound:path)* )? { + $viz:vis trait $trt:ident $(: $trt_bound_first:tt $(+ $trt_bound_others:tt)* )? { $($tbody:tt)* } $($used:tt)* } => { #[doc = concat!("Autotagged with ", stringify!($trt_name))] $(#[$attr])* - $viz trait $trt : $($($trt_bound)* +)? $trt_name { + $viz trait $trt : $( $trt_bound_first $(+ $trt_bound_others)* +)? $trt_name { $($tbody)* } - $crate::vm::object::macros::tag_object_traits!{ @tag tag=$trt_name $(: $($obj_bound)* )?; acc={ $trt, $($tagged_trt,)* } $($used)* } + $crate::vm::object::macros::tag_object_traits!{ + @tag + tag=$trt_name $(: $($obj_bound)* )?; + acc={ $trt, $($tagged_trt,)* }; + $($used)* + } }; { @tag tag=$trt_name:ident $(: $($obj_bound:tt)* )?; - acc={ $($tagged_trt:ident,)* } + acc={ $($tagged_trt:ident,)* }; impl $name:ident for $trt:path { $($body:tt)* } @@ -536,12 +544,17 @@ macro_rules! tag_object_traits { impl $name for $trt { $($body)* } - $crate::vm::object::macros::tag_object_traits!{ @tag tag=$trt_name $(: $($obj_bound)* )?; acc={ $($tagged_trt,)* } $($used)* } + $crate::vm::object::macros::tag_object_traits!{ + @tag + tag=$trt_name $(: $($obj_bound)* )?; + acc={ $($tagged_trt,)* }; + $($used)* + } }; { @tag tag=$trt_name:ident $(: $($obj_bound:tt)* )?; - acc={ $($tagged_trt:ident,)* } + acc={ $($tagged_trt:ident,)* }; } => { // end tagged traits {$trt_name} @@ -549,7 +562,7 @@ macro_rules! tag_object_traits { $crate::vm::object::macros::object_trait!($trt_name $(: $($obj_bound)* )? { $($tagged_trt),* }); }; { #![object_trait($trt_name:ident $(: $($bound:tt)* )? )] $($tree:tt)* } => { - $crate::vm::object::macros::tag_object_traits!{ @tag tag=$trt_name; acc={} $($tree)* } + $crate::vm::object::macros::tag_object_traits!{ @tag tag=$trt_name; acc={}; $($tree)* } }; } diff --git a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs index 95bdba0..34e4d15 100644 --- a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs +++ b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs @@ -268,6 +268,12 @@ impl SourceCode for ItemIntegratedCircuit10 { } impl IntegratedCircuit for ItemIntegratedCircuit10 { + fn get_circuit_holder(&self, vm: &VM) -> Option { + // FIXME: implement correctly + self.parent_slot().map(|parent_slot| { + parent_slot.parent + }) + } fn get_instruction_pointer(&self) -> f64 { self.ip as f64 } @@ -950,6 +956,364 @@ impl BrgtzInstruction for ItemIntegratedCircuit10 { } } +impl BgeInstruction for ItemIntegratedCircuit10 { + /// bge a(r?|num) b(r?|num) c(r?|num) + fn execute_bge( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bge, 1)?; + let b = b.as_value(self, InstructionOp::Bge, 2)?; + let c = c.as_value(self, InstructionOp::Bge, 3)?; + if a >= b { + self.set_next_instruction(c); + } + Ok(()) + } +} + +impl BgealInstruction for ItemIntegratedCircuit10 { + /// bgeal a(r?|num) b(r?|num) c(r?|num) + fn execute_bgeal( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bgeal, 1)?; + let b = b.as_value(self, InstructionOp::Bgeal, 2)?; + let c = c.as_value(self, InstructionOp::Bgeal, 3)?; + if a >= b { + self.set_next_instruction(c); + self.al(); + } + Ok(()) + } +} + +impl BrgeInstruction for ItemIntegratedCircuit10 { + /// brge a(r?|num) b(r?|num) c(r?|num) + fn execute_brge( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Brge, 1)?; + let b = b.as_value(self, InstructionOp::Brge, 2)?; + let c = c.as_value(self, InstructionOp::Brge, 3)?; + if a >= b { + self.set_next_instruction_relative(c); + } + Ok(()) + } +} + +impl BgezInstruction for ItemIntegratedCircuit10 { + /// bgez a(r?|num) b(r?|num) + fn execute_bgez(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bgez, 1)?; + let b = b.as_value(self, InstructionOp::Bgez, 2)?; + if a >= 0.0 { + self.set_next_instruction(b); + } + Ok(()) + } +} + +impl BgezalInstruction for ItemIntegratedCircuit10 { + /// bgezal a(r?|num) b(r?|num) + fn execute_bgezal(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bgeal, 1)?; + let b = b.as_value(self, InstructionOp::Bgeal, 2)?; + if a >= 0.0 { + self.set_next_instruction(b); + self.al(); + } + Ok(()) + } +} + +impl BrgezInstruction for ItemIntegratedCircuit10 { + /// brgez a(r?|num) b(r?|num) + fn execute_brgez(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Brgez, 1)?; + let b = b.as_value(self, InstructionOp::Brgez, 2)?; + if a >= 0.0 { + self.set_next_instruction_relative(b); + } + Ok(()) + } +} + +impl BapInstruction for ItemIntegratedCircuit10 { + /// bap a(r?|num) b(r?|num) c(r?|num) d(r?|num) + fn execute_bap( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + d: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bap, 1)?; + let b = b.as_value(self, InstructionOp::Bap, 2)?; + let c = c.as_value(self, InstructionOp::Bap, 3)?; + let d = d.as_value(self, InstructionOp::Bap, 4)?; + if f64::abs(a - b) <= f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0) { + self.set_next_instruction(d); + } + Ok(()) + } +} + +impl BapalInstruction for ItemIntegratedCircuit10 { + /// bapal a(r?|num) b(r?|num) c(r?|num) d(r?|num) + fn execute_bapal( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + d: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bapal, 1)?; + let b = b.as_value(self, InstructionOp::Bapal, 2)?; + let c = c.as_value(self, InstructionOp::Bapal, 3)?; + let d = d.as_value(self, InstructionOp::Bapal, 4)?; + if f64::abs(a - b) <= f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0) { + self.set_next_instruction(d); + self.al(); + } + Ok(()) + } +} + +impl BrapInstruction for ItemIntegratedCircuit10 { + /// brap a(r?|num) b(r?|num) c(r?|num) d(r?|num) + fn execute_brap( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + d: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Brap, 1)?; + let b = b.as_value(self, InstructionOp::Brap, 2)?; + let c = c.as_value(self, InstructionOp::Brap, 3)?; + let d = d.as_value(self, InstructionOp::Brap, 4)?; + if f64::abs(a - b) <= f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0) { + self.set_next_instruction_relative(d); + } + Ok(()) + } +} + +impl BapzInstruction for ItemIntegratedCircuit10 { + /// bapz a(r?|num) b(r?|num) c(r?|num) + fn execute_bapz( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bapz, 1)?; + let b = b.as_value(self, InstructionOp::Bapz, 2)?; + let c = c.as_value(self, InstructionOp::Bapz, 3)?; + if a.abs() <= f64::max(b * a.abs(), f64::EPSILON * 8.0) { + } else { + self.set_next_instruction(c); + } + Ok(()) + } +} + +impl BapzalInstruction for ItemIntegratedCircuit10 { + /// bapzal a(r?|num) b(r?|num) c(r?|num) + fn execute_bapzal( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bapzal, 1)?; + let b = b.as_value(self, InstructionOp::Bapzal, 2)?; + let c = c.as_value(self, InstructionOp::Bapzal, 3)?; + if a.abs() <= f64::max(b * a.abs(), f64::EPSILON * 8.0) { + } else { + self.set_next_instruction(c); + self.al(); + } + Ok(()) + } +} + +impl BrapzInstruction for ItemIntegratedCircuit10 { + /// brapz a(r?|num) b(r?|num) c(r?|num) + fn execute_brapz( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Brapz, 1)?; + let b = b.as_value(self, InstructionOp::Brapz, 2)?; + let c = c.as_value(self, InstructionOp::Brapz, 3)?; + if a.abs() <= f64::max(b * a.abs(), f64::EPSILON * 8.0) { + } else { + self.set_next_instruction_relative(c); + } + Ok(()) + } +} + +impl BnaInstruction for ItemIntegratedCircuit10 { + /// bna a(r?|num) b(r?|num) c(r?|num) d(r?|num) + fn execute_bna( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + d: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bna, 1)?; + let b = b.as_value(self, InstructionOp::Bna, 2)?; + let c = c.as_value(self, InstructionOp::Bna, 3)?; + let d = d.as_value(self, InstructionOp::Bna, 4)?; + if f64::abs(a - b) > f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0) { + self.set_next_instruction(d); + } + Ok(()) + } +} +impl BnaalInstruction for ItemIntegratedCircuit10 { + /// bnaal a(r?|num) b(r?|num) c(r?|num) d(r?|num) + fn execute_bnaal( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + d: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bnaal, 1)?; + let b = b.as_value(self, InstructionOp::Bnaal, 2)?; + let c = c.as_value(self, InstructionOp::Bnaal, 3)?; + let d = d.as_value(self, InstructionOp::Bnaal, 4)?; + if f64::abs(a - b) > f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0) { + self.set_next_instruction(d); + self.al(); + } + Ok(()) + } +} +impl BrnaInstruction for ItemIntegratedCircuit10 { + /// brna a(r?|num) b(r?|num) c(r?|num) d(r?|num) + fn execute_brna( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + d: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Brna, 1)?; + let b = b.as_value(self, InstructionOp::Brna, 2)?; + let c = c.as_value(self, InstructionOp::Brna, 3)?; + let d = d.as_value(self, InstructionOp::Brna, 4)?; + if f64::abs(a - b) > f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0) { + self.set_next_instruction_relative(d); + } + Ok(()) + } +} + +impl BnazInstruction for ItemIntegratedCircuit10 { + /// bnaz a(r?|num) b(r?|num) c(r?|num) + fn execute_bnaz( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bnaz, 1)?; + let b = b.as_value(self, InstructionOp::Bnaz, 2)?; + let c = c.as_value(self, InstructionOp::Bnaz, 3)?; + if a.abs() > f64::max(b * a.abs(), f64::EPSILON * 8.0) { + self.set_next_instruction(c); + } + Ok(()) + } +} +impl BnazalInstruction for ItemIntegratedCircuit10 { + /// bnazal a(r?|num) b(r?|num) c(r?|num) + fn execute_bnazal( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Bnazal, 1)?; + let b = b.as_value(self, InstructionOp::Bnazal, 2)?; + let c = c.as_value(self, InstructionOp::Bnazal, 3)?; + if a.abs() > f64::max(b * a.abs(), f64::EPSILON * 8.0) { + self.set_next_instruction(c); + self.al(); + } + Ok(()) + } +} +impl BrnazInstruction for ItemIntegratedCircuit10 { + /// brnaz a(r?|num) b(r?|num) c(r?|num) + fn execute_brnaz( + &mut self, + vm: &VM, + a: &Operand, + b: &Operand, + c: &Operand, + ) -> Result<(), ICError> { + let a = a.as_value(self, InstructionOp::Brnaz, 1)?; + let b = b.as_value(self, InstructionOp::Brnaz, 2)?; + let c = c.as_value(self, InstructionOp::Brnaz, 3)?; + if a.abs() > f64::max(b * a.abs(), f64::EPSILON * 8.0) { + self.set_next_instruction_relative(c); + } + Ok(()) + } +} +impl BdseInstruction for ItemIntegratedCircuit10 { + /// bdse d? a(r?|num) + fn execute_bdse(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError> { + let (device, _connection) = d.as_device(self, InstructionOp::Bdse, 1)?; + let a = a.as_value(self, InstructionOp::Bdse, 2)?; + if device.is_some() { + // FIXME: collect device and get logicable + self.set_next_instruction(a); + } + Ok(()) + } +} +impl BdsealInstruction for ItemIntegratedCircuit10 { + /// bdseal d? a(r?|num) + fn execute_bdseal(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; +} +impl BrdseInstruction for ItemIntegratedCircuit10 { + /// brdse d? a(r?|num) + fn execute_brdse(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; +} + impl AbsInstruction for ItemIntegratedCircuit10 { /// abs r? a(r?|num) fn execute_abs(&mut self, vm: &VM, r: &Operand, a: &Operand) -> Result<(), ICError>; @@ -997,48 +1361,6 @@ impl Atan2Instruction for ItemIntegratedCircuit10 { b: &Operand, ) -> Result<(), ICError>; } -impl BapInstruction for ItemIntegratedCircuit10 { - /// bap a(r?|num) b(r?|num) c(r?|num) d(r?|num) - fn execute_bap( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - d: &Operand, - ) -> Result<(), ICError>; -} -impl BapalInstruction for ItemIntegratedCircuit10 { - /// bapal a(r?|num) b(r?|num) c(r?|num) d(r?|num) - fn execute_bapal( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - d: &Operand, - ) -> Result<(), ICError>; -} -impl BapzInstruction for ItemIntegratedCircuit10 { - /// bapz a(r?|num) b(r?|num) c(r?|num) - fn execute_bapz( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} -impl BapzalInstruction for ItemIntegratedCircuit10 { - /// bapzal a(r?|num) b(r?|num) c(r?|num) - fn execute_bapzal( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} impl BdnsInstruction for ItemIntegratedCircuit10 { /// bdns d? a(r?|num) fn execute_bdns(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; @@ -1047,156 +1369,18 @@ impl BdnsalInstruction for ItemIntegratedCircuit10 { /// bdnsal d? a(r?|num) fn execute_bdnsal(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; } -impl BdseInstruction for ItemIntegratedCircuit10 { - /// bdse d? a(r?|num) - fn execute_bdse(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; -} -impl BdsealInstruction for ItemIntegratedCircuit10 { - /// bdseal d? a(r?|num) - fn execute_bdseal(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; -} -impl BgeInstruction for ItemIntegratedCircuit10 { - /// bge a(r?|num) b(r?|num) c(r?|num) - fn execute_bge( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} -impl BgealInstruction for ItemIntegratedCircuit10 { - /// bgeal a(r?|num) b(r?|num) c(r?|num) - fn execute_bgeal( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} -impl BgezInstruction for ItemIntegratedCircuit10 { - /// bgez a(r?|num) b(r?|num) - fn execute_bgez(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError>; -} -impl BgezalInstruction for ItemIntegratedCircuit10 { - /// bgezal a(r?|num) b(r?|num) - fn execute_bgezal(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError>; -} -impl BnaInstruction for ItemIntegratedCircuit10 { - /// bna a(r?|num) b(r?|num) c(r?|num) d(r?|num) - fn execute_bna( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - d: &Operand, - ) -> Result<(), ICError>; -} -impl BnaalInstruction for ItemIntegratedCircuit10 { - /// bnaal a(r?|num) b(r?|num) c(r?|num) d(r?|num) - fn execute_bnaal( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - d: &Operand, - ) -> Result<(), ICError>; -} impl BnanInstruction for ItemIntegratedCircuit10 { /// bnan a(r?|num) b(r?|num) fn execute_bnan(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError>; } -impl BnazInstruction for ItemIntegratedCircuit10 { - /// bnaz a(r?|num) b(r?|num) c(r?|num) - fn execute_bnaz( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} -impl BnazalInstruction for ItemIntegratedCircuit10 { - /// bnazal a(r?|num) b(r?|num) c(r?|num) - fn execute_bnazal( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} -impl BrapInstruction for ItemIntegratedCircuit10 { - /// brap a(r?|num) b(r?|num) c(r?|num) d(r?|num) - fn execute_brap( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - d: &Operand, - ) -> Result<(), ICError>; -} -impl BrapzInstruction for ItemIntegratedCircuit10 { - /// brapz a(r?|num) b(r?|num) c(r?|num) - fn execute_brapz( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} impl BrdnsInstruction for ItemIntegratedCircuit10 { /// brdns d? a(r?|num) fn execute_brdns(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; } -impl BrdseInstruction for ItemIntegratedCircuit10 { - /// brdse d? a(r?|num) - fn execute_brdse(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; -} -impl BrgeInstruction for ItemIntegratedCircuit10 { - /// brge a(r?|num) b(r?|num) c(r?|num) - fn execute_brge( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} -impl BrgezInstruction for ItemIntegratedCircuit10 { - /// brgez a(r?|num) b(r?|num) - fn execute_brgez(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError>; -} -impl BrnaInstruction for ItemIntegratedCircuit10 { - /// brna a(r?|num) b(r?|num) c(r?|num) d(r?|num) - fn execute_brna( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - d: &Operand, - ) -> Result<(), ICError>; -} impl BrnanInstruction for ItemIntegratedCircuit10 { /// brnan a(r?|num) b(r?|num) fn execute_brnan(&mut self, vm: &VM, a: &Operand, b: &Operand) -> Result<(), ICError>; } -impl BrnazInstruction for ItemIntegratedCircuit10 { - /// brnaz a(r?|num) b(r?|num) c(r?|num) - fn execute_brnaz( - &mut self, - vm: &VM, - a: &Operand, - b: &Operand, - c: &Operand, - ) -> Result<(), ICError>; -} impl CeilInstruction for ItemIntegratedCircuit10 { /// ceil r? a(r?|num) fn execute_ceil(&mut self, vm: &VM, r: &Operand, a: &Operand) -> Result<(), ICError>; diff --git a/ic10emu/src/vm/object/templates.rs b/ic10emu/src/vm/object/templates.rs index 0a643f4..1f38b4e 100644 --- a/ic10emu/src/vm/object/templates.rs +++ b/ic10emu/src/vm/object/templates.rs @@ -53,7 +53,22 @@ impl ObjectTemplate { } } - fn build(&self, id: ObjectID) -> VMObject { + pub fn object(&self) -> Option<&ObjectInfo> { + use ObjectTemplate::*; + match self { + Structure(s) => s.object.as_ref(), + StructureSlots(s) => s.object.as_ref(), + StructureLogic(s) => s.object.as_ref(), + StructureLogicDevice(s) => s.object.as_ref(), + StructureLogicDeviceMemory(s) => s.object.as_ref(), + Item(i) => i.object.as_ref(), + ItemSlots(i) => i.object.as_ref(), + ItemLogic(i) => i.object.as_ref(), + ItemLogicMemory(i) => i.object.as_ref(), + } + } + + pub fn build(&self, id: ObjectID) -> VMObject { if let Some(obj) = stationpedia::object_from_prefab_template(&self, id) { obj } else { @@ -61,6 +76,120 @@ impl ObjectTemplate { } } + pub fn connected_networks(&self) -> Vec { + use ObjectTemplate::*; + match self { + StructureLogicDevice(s) => s + .device + .connection_list + .iter() + .filter_map(|conn| conn.network.as_ref()) + .copied() + .collect(), + StructureLogicDeviceMemory(s) => s + .device + .connection_list + .iter() + .filter_map(|conn| conn.network.as_ref()) + .copied() + .collect(), + _ => vec![], + } + } + + pub fn contained_object_ids(&self) -> Vec { + use ObjectTemplate::*; + match self { + StructureSlots(s) => s + .slots + .iter() + .filter_map(|info| { + info.occupant + .as_ref() + .map(|obj| obj.object().map(|obj_info| obj_info.id).flatten()) + }) + .flatten() + .collect(), + StructureLogic(s) => s + .slots + .iter() + .filter_map(|info| { + info.occupant + .as_ref() + .map(|obj| obj.object().map(|obj_info| obj_info.id).flatten()) + }) + .flatten() + .collect(), + StructureLogicDevice(s) => s + .slots + .iter() + .filter_map(|info| { + info.occupant + .as_ref() + .map(|obj| obj.object().map(|obj_info| obj_info.id).flatten()) + }) + .flatten() + .collect(), + StructureLogicDeviceMemory(s) => s + .slots + .iter() + .filter_map(|info| { + info.occupant + .as_ref() + .map(|obj| obj.object().map(|obj_info| obj_info.id).flatten()) + }) + .flatten() + .collect(), + ItemSlots(i) => i + .slots + .iter() + .filter_map(|info| { + info.occupant + .as_ref() + .map(|obj| obj.object().map(|obj_info| obj_info.id).flatten()) + }) + .flatten() + .collect(), + ItemLogic(i) => i + .slots + .iter() + .filter_map(|info| { + info.occupant + .as_ref() + .map(|obj| obj.object().map(|obj_info| obj_info.id).flatten()) + }) + .flatten() + .collect(), + ItemLogicMemory(i) => i + .slots + .iter() + .filter_map(|info| { + info.occupant + .as_ref() + .map(|obj| obj.object().map(|obj_info| obj_info.id).flatten()) + }) + .flatten() + .collect(), + _ => vec![], + } + } + + pub fn templates_from_slots(&self) -> Vec> { + use ObjectTemplate::*; + match self { + StructureSlots(s) => s.slots.iter().map(|info| info.occupant.clone()).collect(), + StructureLogic(s) => s.slots.iter().map(|info| info.occupant.clone()).collect(), + StructureLogicDevice(s) => s.slots.iter().map(|info| info.occupant.clone()).collect(), + StructureLogicDeviceMemory(s) => { + s.slots.iter().map(|info| info.occupant.clone()).collect() + } + ItemSlots(i) => i.slots.iter().map(|info| info.occupant.clone()).collect(), + ItemLogic(i) => i.slots.iter().map(|info| info.occupant.clone()).collect(), + ItemLogicMemory(i) => i.slots.iter().map(|info| info.occupant.clone()).collect(), + _ => vec![], + } + } + fn build_generic(&self, id: ObjectID) -> VMObject { use ObjectTemplate::*; match self { @@ -411,18 +540,20 @@ pub struct PrefabInfo { pub name: String, } -#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ObjectInfo { pub name: Option, pub id: Option, } -#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SlotInfo { pub name: String, pub typ: SlotClass, + #[serde(skip_serializing_if = "Option::is_none")] + pub occupant: Option, } #[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] @@ -437,13 +568,15 @@ pub struct LogicTypes { pub types: BTreeMap, } -#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct LogicInfo { pub logic_slot_types: BTreeMap, pub logic_types: LogicTypes, #[serde(skip_serializing_if = "Option::is_none")] pub modes: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub logic_values: Option>, pub transmission_receiver: bool, pub wireless_logic: bool, pub circuit_holder: bool, @@ -468,6 +601,8 @@ pub struct ItemInfo { pub struct ConnectionInfo { pub typ: ConnectionType, pub role: ConnectionRole, + #[serde(skip_serializing_if = "Option::is_none")] + pub network: Option, } #[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] @@ -476,6 +611,8 @@ pub struct DeviceInfo { pub connection_list: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub device_pins_length: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub device_pins: Option>>, pub has_activate_state: bool, pub has_atmosphere: bool, pub has_color_state: bool, diff --git a/ic10emu/src/vm/object/traits.rs b/ic10emu/src/vm/object/traits.rs index 02295bc..30b0c0d 100644 --- a/ic10emu/src/vm/object/traits.rs +++ b/ic10emu/src/vm/object/traits.rs @@ -2,12 +2,13 @@ use serde_derive::{Deserialize, Serialize}; use crate::{ errors::ICError, + network::Connection, vm::{ enums::{ basic_enums::{Class as SlotClass, GasType, SortingClass}, script_enums::{LogicSlotType, LogicType}, }, - instructions::Instruction, + instructions::{traits::ICInstructable, Instruction}, object::{ errors::{LogicError, MemoryError}, macros::tag_object_traits, @@ -16,7 +17,6 @@ use crate::{ VM, }, }; - use std::{collections::BTreeMap, fmt::Debug}; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] @@ -55,8 +55,8 @@ tag_object_traits! { fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError>; fn get_logic(&self, lt: LogicType) -> Result; - fn can_slot_logic_read(&self, slt: LogicSlotType, index: usize) -> bool; - fn get_slot_logic(&self, slt: LogicSlotType, index: usize, vm: &VM) -> Result; + fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool; + fn get_slot_logic(&self, slt: LogicSlotType, index: f64, vm: &VM) -> Result; } pub trait SourceCode { @@ -66,7 +66,7 @@ tag_object_traits! { fn get_line(&self, line: usize) -> Result<&Instruction, ICError>; } - pub trait CircuitHolder: Logicable { + pub trait CircuitHolder: Logicable + Storage { fn clear_error(&mut self); fn set_error(&mut self, state: i32); fn get_logicable_from_index(&self, device: usize, vm: &VM) -> Option>; @@ -77,9 +77,46 @@ tag_object_traits! { fn set_source_code(&self, code: String); fn get_batch(&self) -> Vec>; fn get_batch_mut(&self) -> Vec>; + fn get_ic(&self) -> Option; } - pub trait Programmable: crate::vm::instructions::traits::ICInstructable { + pub trait Item { + fn consumable(&self) -> bool; + fn filter_type(&self) -> Option; + fn ingredient(&self) -> bool; + fn max_quantity(&self) -> u32; + fn reagents(&self) -> Option<&BTreeMap>; + fn slot_class(&self) -> SlotClass; + fn sorting_class(&self) -> SortingClass; + fn parent_slot(&self) -> Option; + } + + pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item { + fn get_circuit_holder(&self, vm: &VM) -> Option>; + fn get_instruction_pointer(&self) -> f64; + fn set_next_instruction(&mut self, next_instruction: f64); + fn set_next_instruction_relative(&mut self, offset: f64) { + self.set_next_instruction(self.get_instruction_pointer() + offset); + } + fn reset(&mut self); + fn get_real_target(&self, indirection: u32, target: u32) -> Result; + fn get_register(&self, indirection: u32, target: u32) -> Result; + fn set_register(&mut self, indirection: u32, target: u32, val: f64) -> Result; + fn set_return_address(&mut self, addr: f64); + fn al(&mut self) { + self.set_return_address(self.get_instruction_pointer() + 1.0); + } + fn push_stack(&mut self, val: f64) -> Result; + fn pop_stack(&mut self) -> Result; + fn peek_stack(&self) -> Result; + fn get_stack(&self, addr: f64) -> Result; + fn put_stack(&self, addr: f64, val: f64) -> Result; + fn get_aliases(&self) -> &BTreeMap; + fn get_defines(&self) -> &BTreeMap; + fn get_labels(&self) -> &BTreeMap; + } + + pub trait Programmable: ICInstructable { fn get_source_code(&self) -> String; fn set_source_code(&self, code: String); fn step(&mut self) -> Result<(), crate::errors::ICError>; @@ -94,20 +131,50 @@ tag_object_traits! { } pub trait Device: Logicable { + fn set_slot_logic( + &mut self, + slt: LogicSlotType, + index: f64, + value: f64, + vm: &VM, + force: bool + ) -> Result<(), LogicError>; + fn connection_list(&self) -> &[Connection]; + fn connection_list_mut(&mut self) -> &mut [Connection]; + fn device_pins(&self) -> Option<&[Option]>; + fn device_pins_mut(&self) -> Option<&mut [Option]>; + fn has_activate_state(&self) -> bool; + fn has_lock_state(&self) -> bool; + fn has_mode_state(&self) -> bool; + fn has_on_off_state(&self) -> bool; + fn has_open_state(&self) -> bool; + fn has_reagents(&self) -> bool; + } + + pub trait WirelessTransmit: Logicable { } - pub trait Item { - fn consumable(&self) -> bool; - fn filter_type(&self) -> Option; - fn ingredient(&self) -> bool; - fn max_quantity(&self) -> u32; - fn reagents(&self) -> Option<&BTreeMap>; - fn slot_class(&self) -> SlotClass; - fn sorting_class(&self) -> SortingClass; - fn parent_slot(&self) -> Option; + pub trait WirelessReceive: Logicable { + } + pub trait Network: Logicable { + fn contains(&self, id: &ObjectID) -> bool; + fn contains_all(&self, ids: &[ObjectID]) -> bool; + fn contains_data(&self, id: &ObjectID) -> bool; + fn contains_all_data(&self, ids: &[ObjectID]) -> bool; + fn contains_power(&self, id: &ObjectID) -> bool; + fn contains_all_power(&self, ids: &[ObjectID]) -> bool; + fn data_visible(&self, source: &ObjectID) -> Vec; + fn add_data(&mut self, id: ObjectID) -> bool; + fn add_power(&mut self, id: ObjectID) -> bool; + fn remove_all(&mut self, id: ObjectID) -> bool; + fn remove_data(&mut self, id: ObjectID) -> bool; + fn remove_power(&mut self, id: ObjectID) -> bool; + } + + } impl Debug for dyn Object { diff --git a/ic10emu_wasm/src/lib.rs b/ic10emu_wasm/src/lib.rs index c50fca1..b667ec2 100644 --- a/ic10emu_wasm/src/lib.rs +++ b/ic10emu_wasm/src/lib.rs @@ -107,7 +107,7 @@ impl DeviceRef { self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| ic.as_ref().borrow().ip()) }) @@ -118,7 +118,7 @@ impl DeviceRef { self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| ic.as_ref().borrow().ic.get()) }) @@ -129,7 +129,7 @@ impl DeviceRef { self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| Stack(*ic.as_ref().borrow().stack.borrow())) }) @@ -140,7 +140,7 @@ impl DeviceRef { self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| Registers(*ic.as_ref().borrow().registers.borrow())) }) @@ -151,7 +151,7 @@ impl DeviceRef { let aliases = &self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| ic.as_ref().borrow().aliases.borrow().clone()) }); @@ -163,7 +163,7 @@ impl DeviceRef { let defines = &self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| ic.as_ref().borrow().defines.borrow().clone()) }); @@ -175,7 +175,7 @@ impl DeviceRef { let pins = &self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| *ic.as_ref().borrow().pins.borrow()) }); @@ -191,7 +191,7 @@ impl DeviceRef { .and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| ic.borrow().state.clone()) }) @@ -203,7 +203,7 @@ impl DeviceRef { let prog = &self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| ic.borrow().program.borrow().clone()) }); @@ -215,7 +215,7 @@ impl DeviceRef { self.device.borrow().ic.as_ref().and_then(|ic| { self.vm .borrow() - .ics + .ic_holders .get(ic) .map(|ic| ic.borrow().code.borrow().clone()) }) @@ -263,7 +263,7 @@ impl DeviceRef { .ok_or(VMError::NoIC(self.device.borrow().id))?; let vm_borrow = self.vm.borrow(); let ic = vm_borrow - .ics + .ic_holders .get(&ic_id) .ok_or(VMError::NoIC(self.device.borrow().id))?; let result = ic.borrow_mut().set_register(0, index, val)?; @@ -280,7 +280,7 @@ impl DeviceRef { .ok_or(VMError::NoIC(self.device.borrow().id))?; let vm_borrow = self.vm.borrow(); let ic = vm_borrow - .ics + .ic_holders .get(&ic_id) .ok_or(VMError::NoIC(self.device.borrow().id))?; let result = ic.borrow_mut().poke(address, val)?; @@ -370,7 +370,7 @@ impl VMRef { #[wasm_bindgen(js_name = "addDevice")] pub fn add_device(&self, network: Option) -> Result { - Ok(self.vm.borrow_mut().add_device(network)?) + Ok(self.vm.borrow_mut().add_object(network)?) } #[wasm_bindgen(js_name = "addDeviceFromTemplate", skip_typescript)] @@ -385,7 +385,7 @@ impl VMRef { #[wasm_bindgen(js_name = "getDevice")] pub fn get_device(&self, id: u32) -> Option { - let device = self.vm.borrow().get_device(id); + let device = self.vm.borrow().get_object(id); device.map(|d| DeviceRef::from_device(d.clone(), self.vm.clone())) } @@ -418,7 +418,7 @@ impl VMRef { #[wasm_bindgen(getter, js_name = "defaultNetwork")] pub fn default_network(&self) -> u32 { - self.vm.borrow().default_network + self.vm.borrow().default_network_key } #[wasm_bindgen(getter)] @@ -433,7 +433,7 @@ impl VMRef { #[wasm_bindgen(getter)] pub fn ics(&self) -> Vec { - self.vm.borrow().ics.keys().copied().collect_vec() + self.vm.borrow().ic_holders.keys().copied().collect_vec() } #[wasm_bindgen(getter, js_name = "lastOperationModified")] @@ -479,7 +479,7 @@ impl VMRef { #[wasm_bindgen(js_name = "removeDevice")] pub fn remove_device(&self, id: u32) -> Result<(), JsError> { - Ok(self.vm.borrow_mut().remove_device(id)?) + Ok(self.vm.borrow_mut().remove_object(id)?) } #[wasm_bindgen(js_name = "setSlotOccupant", skip_typescript)] diff --git a/xtask/src/generate/instructions.rs b/xtask/src/generate/instructions.rs index 2661f33..b359e13 100644 --- a/xtask/src/generate/instructions.rs +++ b/xtask/src/generate/instructions.rs @@ -22,7 +22,7 @@ pub fn generate_instructions( let mut writer = std::io::BufWriter::new(std::fs::File::create(instructions_path.join("traits.rs"))?); - write_instruction_interface_trait(&mut writer)?; + write_instruction_trait_use(&mut writer)?; for (typ, info) in &stationpedia.script_commands { write_instruction_trait(&mut writer, (typ, info))?; } @@ -172,36 +172,11 @@ fn operand_names(example: &str) -> Vec { .collect() } -fn write_instruction_interface_trait(writer: &mut T) -> color_eyre::Result<()> { +fn write_instruction_trait_use(writer: &mut T) -> color_eyre::Result<()> { write!( writer, "\ - use std::collections::BTreeMap;\n\ - use crate::vm::object::traits::{{Logicable, MemoryWritable, SourceCode}};\n\ - use crate::errors::ICError; \n\ - pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode {{\n \ - fn get_instruction_pointer(&self) -> f64;\n \ - fn set_next_instruction(&mut self, next_instruction: f64);\n \ - fn set_next_instruction_relative(&mut self, offset: f64) {{\n \ - self.set_next_instruction(self.get_instruction_pointer() + offset);\n \ - }}\n \ - fn reset(&mut self);\n \ - fn get_real_target(&self, indirection: u32, target: u32) -> Result;\n \ - fn get_register(&self, indirection: u32, target: u32) -> Result;\n \ - fn set_register(&mut self, indirection: u32, target: u32, val: f64) -> Result;\n \ - fn set_return_address(&mut self, addr: f64);\n \ - fn al(&mut self) {{\n \ - self.set_return_address(self.get_instruction_pointer() + 1.0);\n \ - }}\n \ - fn push_stack(&mut self, val: f64) -> Result;\n \ - fn pop_stack(&mut self) -> Result;\n \ - fn peek_stack(&self) -> Result;\n \ - fn get_stack(&self, addr: f64) -> Result;\n \ - fn put_stack(&self, addr: f64, val: f64) -> Result;\n \ - fn get_aliases(&self) -> &BTreeMap;\n \ - fn get_defines(&self) -> &BTreeMap;\n \ - fn get_labels(&self) -> &BTreeMap;\n\ - }}\n\ + use crate::vm::object::traits::IntegratedCircuit;\n\ " )?; Ok(())