refactor(vm): more ic10 instruction impls

This commit is contained in:
Rachel Powers
2024-05-14 23:52:16 -07:00
parent 25b7046ed2
commit 0c5e2b29a8
10 changed files with 4367 additions and 3329 deletions

View File

@@ -151,7 +151,7 @@ pub enum ICError {
#[error("incorrect operand type for instruction `{inst}` operand {index}, not a {desired} ")] #[error("incorrect operand type for instruction `{inst}` operand {index}, not a {desired} ")]
IncorrectOperandType { IncorrectOperandType {
inst: InstructionOp, inst: InstructionOp,
index: u32, index: usize,
desired: String, desired: String,
}, },
#[error("unknown identifier {0}")] #[error("unknown identifier {0}")]
@@ -206,6 +206,8 @@ pub enum ICError {
NoGeneratedValue(String), NoGeneratedValue(String),
#[error("generated Enum {0}'s value does not parse as {1} . Report this error.")] #[error("generated Enum {0}'s value does not parse as {1} . Report this error.")]
BadGeneratedValueParse(String, String), BadGeneratedValueParse(String, String),
#[error("IC with id {0} is not sloted into a circuit holder")]
NoCircuitHolder(ObjectID),
} }
impl ICError { impl ICError {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -87,6 +87,10 @@ impl VM {
vm vm
} }
pub fn random_f64(&self) -> f64 {
self.random.borrow_mut().next_f64()
}
pub fn add_device_from_template( pub fn add_device_from_template(
self: &Rc<Self>, self: &Rc<Self>,
template: ObjectTemplate, template: ObjectTemplate,

View File

@@ -59,13 +59,55 @@ pub enum Operand {
Identifier(Identifier), Identifier(Identifier),
} }
impl Operand { pub struct InstOperand {
pub fn as_value<IC: IntegratedCircuit>( pub operand: Operand,
&self, pub inst: InstructionOp,
ic: &IC, pub index: usize,
inst: InstructionOp, }
index: u32,
) -> Result<f64, ICError> { impl InstOperand {
pub fn new(operand: &Operand, inst: InstructionOp, index: usize) -> Self {
InstOperand {
operand: operand.clone(),
inst,
index,
}
}
pub fn as_ident(&self) -> Result<Identifier, ICError> {
let &Operand::Identifier(ident) = &self.operand else {
return Err(ICError::IncorrectOperandType {
inst: self.inst,
index: self.index,
desired: "Name".to_owned(),
});
};
Ok(ident)
}
pub fn as_number(&self) -> Result<Number, ICError> {
let &Operand::Number(num) = &self.operand else {
return Err(ICError::IncorrectOperandType {
inst: self.inst,
index: self.index,
desired: "Number".to_owned(),
});
};
Ok(num)
}
pub fn as_aliasable(&self) -> Result<Operand, ICError> {
match &self.operand {
Operand::RegisterSpec { .. } | Operand::DeviceSpec { .. } => Ok(self.operand.clone()),
_ => Err(ICError::IncorrectOperandType {
inst: self.inst,
index: self.index,
desired: "Device Or Register".to_owned(),
}),
}
}
pub fn as_value<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<f64, ICError> {
match self.translate_alias(ic) { match self.translate_alias(ic) {
Operand::RegisterSpec(RegisterSpec { Operand::RegisterSpec(RegisterSpec {
indirection, indirection,
@@ -117,8 +159,8 @@ impl Operand {
} }
Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())), Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())),
Operand::DeviceSpec { .. } => Err(ICError::IncorrectOperandType { Operand::DeviceSpec { .. } => Err(ICError::IncorrectOperandType {
inst, inst: self.inst,
index, index: self.index,
desired: "Value".to_owned(), desired: "Value".to_owned(),
}), }),
} }
@@ -128,16 +170,14 @@ impl Operand {
&self, &self,
ic: &IC, ic: &IC,
signed: bool, signed: bool,
inst: InstructionOp,
index: u32,
) -> Result<i64, ICError> { ) -> Result<i64, ICError> {
match self { match &self.operand {
Self::Number(num) => Ok(num.value_i64(signed)), Operand::Number(num) => Ok(num.value_i64(signed)),
_ => { _ => {
let val = self.as_value(ic, inst, index)?; let val = self.as_value(ic)?;
if val < -9.223_372_036_854_776E18 { if val < i64::MIN as f64 {
Err(ICError::ShiftUnderflowI64) Err(ICError::ShiftUnderflowI64)
} else if val <= 9.223_372_036_854_776E18 { } else if val <= i64::MAX as f64 {
Ok(interpreter::f64_to_i64(val, signed)) Ok(interpreter::f64_to_i64(val, signed))
} else { } else {
Err(ICError::ShiftOverflowI64) Err(ICError::ShiftOverflowI64)
@@ -149,13 +189,11 @@ impl Operand {
&self, &self,
ic: &IC, ic: &IC,
signed: bool, signed: bool,
inst: InstructionOp,
index: u32,
) -> Result<i32, ICError> { ) -> Result<i32, ICError> {
match self { match &self.operand {
Self::Number(num) => Ok(num.value_i64(signed) as i32), Operand::Number(num) => Ok(num.value_i64(signed) as i32),
_ => { _ => {
let val = self.as_value(ic, inst, index)?; let val = self.as_value(ic)?;
if val < i32::MIN as f64 { if val < i32::MIN as f64 {
Err(ICError::ShiftUnderflowI32) Err(ICError::ShiftUnderflowI32)
} else if val <= i32::MAX as f64 { } else if val <= i32::MAX as f64 {
@@ -167,112 +205,89 @@ impl Operand {
} }
} }
pub fn as_register<IC: IntegratedCircuit>( pub fn as_register<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<RegisterSpec, ICError> {
&self,
ic: &IC,
inst: InstructionOp,
index: u32,
) -> Result<RegisterSpec, ICError> {
match self.translate_alias(ic) { match self.translate_alias(ic) {
Operand::RegisterSpec(reg) => Ok(reg), Operand::RegisterSpec(reg) => Ok(reg),
Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())), Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())),
_ => Err(ICError::IncorrectOperandType { _ => Err(ICError::IncorrectOperandType {
inst, inst: self.inst,
index, index: self.index,
desired: "Register".to_owned(), desired: "Register".to_owned(),
}), }),
} }
} }
/// interpret the operand as a device index, i32::MAX is db
pub fn as_device<IC: IntegratedCircuit>( pub fn as_device<IC: IntegratedCircuit>(
&self, &self,
ic: &IC, ic: &IC,
inst: InstructionOp, ) -> Result<(i32, Option<usize>), ICError> {
index: u32,
) -> Result<(Option<u32>, Option<usize>), ICError> {
match self.translate_alias(ic) { match self.translate_alias(ic) {
Operand::DeviceSpec(DeviceSpec { device, connection }) => match device { Operand::DeviceSpec(DeviceSpec { device, connection }) => match device {
Device::Db => Ok((Some(0), connection)), Device::Db => Ok((i32::MAX, connection)),
Device::Numbered(p) => Ok((Some(p), connection)), Device::Numbered(p) => Ok((p as i32, connection)),
Device::Indirect { Device::Indirect {
indirection, indirection,
target, target,
} => { } => {
let val = ic.get_register(indirection, target)?; let val = ic.get_register(indirection, target)?;
Ok((Some(val as u32), connection)) Ok((val as i32, connection))
} }
}, },
Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())), Operand::Identifier(id) => Err(ICError::UnknownIdentifier(id.name.to_string())),
_ => Err(ICError::IncorrectOperandType { _ => Err(ICError::IncorrectOperandType {
inst, inst: self.inst,
index, index: self.index,
desired: "Value".to_owned(), desired: "Value".to_owned(),
}), }),
} }
} }
pub fn as_logic_type<IC: IntegratedCircuit>( pub fn as_logic_type<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<LogicType, ICError> {
&self, match &self.operand {
ic: &IC,
inst: InstructionOp,
index: u32,
) -> Result<LogicType, ICError> {
match &self {
Operand::Type { Operand::Type {
logic_type: Some(lt), logic_type: Some(lt),
.. ..
} => Ok(*lt), } => Ok(*lt),
_ => LogicType::try_from(self.as_value(ic, inst, index)?), _ => LogicType::try_from(self.as_value(ic)?),
} }
} }
pub fn as_slot_logic_type<IC: IntegratedCircuit>( pub fn as_slot_logic_type<IC: IntegratedCircuit>(
&self, &self,
ic: &IC, ic: &IC,
inst: InstructionOp,
index: u32,
) -> Result<LogicSlotType, ICError> { ) -> Result<LogicSlotType, ICError> {
match &self { match &self.operand {
Operand::Type { Operand::Type {
slot_logic_type: Some(slt), slot_logic_type: Some(slt),
.. ..
} => Ok(*slt), } => Ok(*slt),
_ => LogicSlotType::try_from(self.as_value(ic, inst, index)?), _ => LogicSlotType::try_from(self.as_value(ic)?),
} }
} }
pub fn as_batch_mode<IC: IntegratedCircuit>( pub fn as_batch_mode<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<BatchMode, ICError> {
&self, match &self.operand {
ic: &IC,
inst: InstructionOp,
index: u32,
) -> Result<BatchMode, ICError> {
match &self {
Operand::Type { Operand::Type {
batch_mode: Some(bm), batch_mode: Some(bm),
.. ..
} => Ok(*bm), } => Ok(*bm),
_ => BatchMode::try_from(self.as_value(ic, inst, index)?), _ => BatchMode::try_from(self.as_value(ic)?),
} }
} }
pub fn as_reagent_mode<IC: IntegratedCircuit>( pub fn as_reagent_mode<IC: IntegratedCircuit>(&self, ic: &IC) -> Result<ReagentMode, ICError> {
&self, match &self.operand {
ic: &IC,
inst: InstructionOp,
index: u32,
) -> Result<ReagentMode, ICError> {
match &self {
Operand::Type { Operand::Type {
reagent_mode: Some(rm), reagent_mode: Some(rm),
.. ..
} => Ok(*rm), } => Ok(*rm),
_ => ReagentMode::try_from(self.as_value(ic, inst, index)?), _ => ReagentMode::try_from(self.as_value(ic)?),
} }
} }
pub fn translate_alias<IC: IntegratedCircuit>(&self, ic: &IC) -> Self { pub fn translate_alias<IC: IntegratedCircuit>(&self, ic: &IC) -> Operand {
match &self { match self.operand {
Operand::Identifier(id) | Operand::Type { identifier: id, .. } => { Operand::Identifier(id) | Operand::Type { identifier: id, .. } => {
if let Some(alias) = ic.get_aliases().get(&id.name) { if let Some(alias) = ic.get_aliases().get(&id.name) {
alias.clone() alias.clone()
@@ -281,7 +296,7 @@ impl Operand {
} else if let Some(label) = ic.get_labels().get(&id.name) { } else if let Some(label) = ic.get_labels().get(&id.name) {
Operand::Number(Number::Float(*label as f64)) Operand::Number(Number::Float(*label as f64))
} else { } else {
self.clone() self.operand.clone()
} }
} }
_ => self.clone(), _ => self.clone(),

File diff suppressed because it is too large Load Diff

View File

@@ -23,6 +23,8 @@ pub enum MemoryError {
StackUnderflow(i32, usize), StackUnderflow(i32, usize),
#[error("stack overflow: {0} > range [0..{1})")] #[error("stack overflow: {0} > range [0..{1})")]
StackOverflow(i32, usize), StackOverflow(i32, usize),
#[error("memory unit not present")] #[error("memory not readable")]
NotPresent, NotReadable,
#[error("memory not writeable")]
NotWriteable,
} }

View File

@@ -15,10 +15,9 @@ use crate::{
macros::tag_object_traits, macros::tag_object_traits,
ObjectID, Slot, ObjectID, Slot,
}, },
VM,
}, },
}; };
use std::{collections::BTreeMap, fmt::Debug, rc::Rc}; use std::{collections::BTreeMap, fmt::Debug};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ParentSlotInfo { pub struct ParentSlotInfo {
@@ -63,7 +62,7 @@ tag_object_traits! {
fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError>; fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError>;
fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError>; fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError>;
fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool; fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool;
fn get_slot_logic(&self, slt: LogicSlotType, index: f64, vm: &VM) -> Result<f64, LogicError>; fn get_slot_logic(&self, slt: LogicSlotType, index: f64) -> Result<f64, LogicError>;
fn valid_logic_types(&self) -> Vec<LogicType>; fn valid_logic_types(&self) -> Vec<LogicType>;
fn known_modes(&self) -> Option<Vec<(u32, String)>>; fn known_modes(&self) -> Option<Vec<(u32, String)>>;
} }
@@ -78,10 +77,28 @@ tag_object_traits! {
pub trait CircuitHolder: Logicable + Storage { pub trait CircuitHolder: Logicable + Storage {
fn clear_error(&mut self); fn clear_error(&mut self);
fn set_error(&mut self, state: i32); fn set_error(&mut self, state: i32);
fn get_logicable_from_index(&self, device: usize, vm: &VM) -> Option<LogicableRef>; /// i32::MAX is db
fn get_logicable_from_index_mut(&self, device: usize, vm: &VM) -> Option<LogicableRefMut>; fn get_logicable_from_index(
fn get_logicable_from_id(&self, device: ObjectID, vm: &VM) -> Option<LogicableRef>; &self,
fn get_logicable_from_id_mut(&self, device: ObjectID, vm: &VM) -> Option<LogicableRefMut>; device: i32,
connection: Option<usize>,
) -> Option<LogicableRef>;
/// i32::MAX is db
fn get_logicable_from_index_mut(
&self,
device: i32,
connection: Option<usize>,
) -> Option<LogicableRefMut>;
fn get_logicable_from_id(
&self,
device: ObjectID,
connection: Option<usize>,
) -> Option<LogicableRef>;
fn get_logicable_from_id_mut(
&self,
device: ObjectID,
connection: Option<usize>,
) -> Option<LogicableRefMut>;
fn get_source_code(&self) -> String; fn get_source_code(&self) -> String;
fn set_source_code(&self, code: String); fn set_source_code(&self, code: String);
fn get_batch(&self) -> Vec<LogicableRef>; fn get_batch(&self) -> Vec<LogicableRef>;
@@ -102,7 +119,7 @@ tag_object_traits! {
} }
pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item { pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item {
fn get_circuit_holder(&self, vm: &Rc<VM>) -> Option<CircuitHolderRef>; fn get_circuit_holder(&self) -> Option<CircuitHolderRef>;
fn get_instruction_pointer(&self) -> f64; fn get_instruction_pointer(&self) -> f64;
fn set_next_instruction(&mut self, next_instruction: f64); fn set_next_instruction(&mut self, next_instruction: f64);
fn set_next_instruction_relative(&mut self, offset: f64) { fn set_next_instruction_relative(&mut self, offset: f64) {
@@ -122,7 +139,9 @@ tag_object_traits! {
fn get_stack(&self, addr: f64) -> Result<f64, ICError>; fn get_stack(&self, addr: f64) -> Result<f64, ICError>;
fn put_stack(&self, addr: f64, val: f64) -> Result<f64, ICError>; fn put_stack(&self, addr: f64, val: f64) -> Result<f64, ICError>;
fn get_aliases(&self) -> &BTreeMap<String, crate::vm::instructions::operands::Operand>; fn get_aliases(&self) -> &BTreeMap<String, crate::vm::instructions::operands::Operand>;
fn get_aliases_mut(&mut self) -> &mut BTreeMap<String, crate::vm::instructions::operands::Operand>;
fn get_defines(&self) -> &BTreeMap<String, f64>; fn get_defines(&self) -> &BTreeMap<String, f64>;
fn get_defines_mut(&mut self) -> &mut BTreeMap<String, f64>;
fn get_labels(&self) -> &BTreeMap<String, u32>; fn get_labels(&self) -> &BTreeMap<String, u32>;
fn get_state(&self) -> ICState; fn get_state(&self) -> ICState;
fn set_state(&mut self, state: ICState); fn set_state(&mut self, state: ICState);
@@ -131,7 +150,7 @@ tag_object_traits! {
pub trait Programmable: ICInstructable { pub trait Programmable: ICInstructable {
fn get_source_code(&self) -> String; fn get_source_code(&self) -> String;
fn set_source_code(&self, code: String); fn set_source_code(&self, code: String);
fn step(&mut self, vm: &VM, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>; fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>;
} }
pub trait Instructable: MemoryWritable { pub trait Instructable: MemoryWritable {
@@ -149,8 +168,7 @@ tag_object_traits! {
slt: LogicSlotType, slt: LogicSlotType,
index: f64, index: f64,
value: f64, value: f64,
vm: &VM, force: bool,
force: bool
) -> Result<(), LogicError>; ) -> Result<(), LogicError>;
fn connection_list(&self) -> &[Connection]; fn connection_list(&self) -> &[Connection];
fn connection_list_mut(&mut self) -> &mut [Connection]; fn connection_list_mut(&mut self) -> &mut [Connection];
@@ -166,13 +184,9 @@ tag_object_traits! {
fn has_reagents(&self) -> bool; fn has_reagents(&self) -> bool;
} }
pub trait WirelessTransmit: Logicable { pub trait WirelessTransmit: Logicable {}
} pub trait WirelessReceive: Logicable {}
pub trait WirelessReceive: Logicable {
}
pub trait Network: Logicable { pub trait Network: Logicable {
fn contains(&self, id: &ObjectID) -> bool; fn contains(&self, id: &ObjectID) -> bool;
@@ -192,7 +206,6 @@ tag_object_traits! {
fn get_channel_data(&self) -> &[f64; 8]; fn get_channel_data(&self) -> &[f64; 8];
} }
} }
impl Debug for dyn Object { impl Debug for dyn Object {

View File

@@ -133,7 +133,8 @@ fn write_instruction_trait<T: std::io::Write>(
instruction: (&str, &stationpedia::Command), instruction: (&str, &stationpedia::Command),
) -> color_eyre::Result<()> { ) -> color_eyre::Result<()> {
let (name, info) = instruction; let (name, info) = instruction;
let trait_name = format!("{}Instruction", name.to_case(Case::Pascal)); let op_name = name.to_case(Case::Pascal);
let trait_name = format!("{op_name}Instruction");
let operands = operand_names(&info.example) let operands = operand_names(&info.example)
.iter() .iter()
.map(|name| { .map(|name| {
@@ -148,12 +149,45 @@ fn write_instruction_trait<T: std::io::Write>(
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "); .join(", ");
let operands_inner = operand_names(&info.example)
.iter()
.map(|name| {
let mut n: &str = name;
if n == "str" {
n = "string";
}
format!(
"{}: &crate::vm::instructions::operands::InstOperand",
n.to_case(Case::Snake)
)
})
.collect::<Vec<_>>()
.join(", ");
let operand_call = operand_names(&info.example)
.iter()
.enumerate()
.map(|(index, name)| {
let mut n: &str = name;
if n == "str" {
n = "string";
}
format!(
"&crate::vm::instructions::operands::InstOperand::new({}, InstructionOp::{op_name}, {index})",
n.to_case(Case::Snake)
)
})
.collect::<Vec<_>>()
.join(", ");
let example = utils::strip_color(&info.example); let example = utils::strip_color(&info.example);
write!( write!(
writer, writer,
"pub trait {trait_name}: IntegratedCircuit {{\n \ "pub trait {trait_name}: IntegratedCircuit {{\n \
/// {example} \n \ /// {example} \n \
fn execute_{name}(&mut self, {operands}) -> Result<(), crate::errors::ICError>;\n\ fn execute_{name}(&mut self, {operands}) -> Result<(), crate::errors::ICError> {{\n \
{trait_name}::execute_inner(self, {operand_call})\n \
}}\n \
/// {example} \n \
fn execute_inner(&mut self, {operands_inner}) -> Result<(), crate::errors::ICError>;\n\
}}" }}"
)?; )?;
Ok(()) Ok(())
@@ -176,6 +210,7 @@ fn write_instruction_trait_use<T: std::io::Write>(writer: &mut T) -> color_eyre:
writer, writer,
"\ "\
use crate::vm::object::traits::IntegratedCircuit;\n\ use crate::vm::object::traits::IntegratedCircuit;\n\
use crate::vm::instructions::enums::InstructionOp;\n\
" "
)?; )?;
Ok(()) Ok(())