Vm working. simple interface built

- still need stack view
- still ned to work with devices
This commit is contained in:
Rachel
2024-03-28 01:31:09 -07:00
parent 3047f774c5
commit baf67b2c6a
25 changed files with 2295 additions and 586 deletions

104
ic10emu/Cargo.lock generated
View File

@@ -38,6 +38,16 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
name = "either"
version = "1.10.0"
@@ -75,10 +85,11 @@ dependencies = [
"phf_codegen",
"rand",
"regex",
"serde",
"strum",
"strum_macros",
"thiserror",
"web-time",
"time",
]
[[package]]
@@ -90,6 +101,12 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
version = "0.3.69"
@@ -117,6 +134,21 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -205,6 +237,12 @@ dependencies = [
"siphasher",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -300,6 +338,26 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "serde"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "siphasher"
version = "0.3.11"
@@ -371,6 +429,40 @@ dependencies = [
"syn 2.0.53",
]
[[package]]
name = "time"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
dependencies = [
"deranged",
"itoa",
"js-sys",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@@ -442,13 +534,3 @@ name = "wasm-bindgen-shared"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"js-sys",
"wasm-bindgen",
]

View File

@@ -9,21 +9,30 @@ edition = "2021"
crate-type = ["lib"]
[dependencies]
const-crc32 = "1.3.0"
itertools = "0.12.1"
phf = "0.11.2"
rand = "0.8.5"
regex = "1.10.3"
serde = { version = "1.0.197", features = ["derive"] }
strum = { version = "0.26.2", features = ["derive", "phf", "strum_macros"] }
strum_macros = "0.26.2"
thiserror = "1.0.58"
time = { version = "0.3.34", features = [
"formatting",
"serde",
"local-offset",
] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-time = "1.1.0"
getrandom = { version = "0.2", features = ["js"] }
time = { version = "0.3.34", features = [
"formatting",
"serde",
"local-offset",
"wasm-bindgen",
] }
[build-dependencies]

View File

@@ -44,7 +44,7 @@ fn write_repr_enum<T: std::io::Write, I, P>(
let additional_strum = if use_phf { "#[strum(use_phf)]\n" } else { "" };
write!(
writer,
"#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, EnumString, AsRefStr, EnumProperty, EnumIter)]\n\
"#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, EnumString, AsRefStr, EnumProperty, EnumIter, Serialize, Deserialize)]\n\
{additional_strum}\
pub enum {name} {{\n"
)

View File

@@ -1,5 +1,5 @@
use crate::interpreter;
use crate::tokens::SplitConsecutiveIndicesExt;
use crate::tokens::{SplitConsecutiveIndicesExt, SplitConsecutiveWithIndices};
use itertools::Itertools;
use std::error::Error;
use std::fmt::Display;
@@ -16,6 +16,7 @@ pub mod generated {
use strum::EnumProperty;
use strum::EnumString;
use strum::IntoEnumIterator;
use serde::{Deserialize, Serialize};
include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
include!(concat!(env!("OUT_DIR"), "/logictypes.rs"));
@@ -85,8 +86,9 @@ pub mod generated {
}
pub use generated::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParseError {
pub line: usize,
pub start: usize,
@@ -233,29 +235,15 @@ impl FromStr for Instruction {
})
}
}?;
let mut operand_tokens = Vec::new();
let mut string_start = None;
for (index, token) in tokens_iter {
if token.starts_with("HASH(\"") {
string_start = Some(index);
}
if let Some(start) = string_start {
if token.ends_with("\")") {
operand_tokens.push((start, &s[start..(index + token.len())]));
string_start = None;
}
} else {
operand_tokens.push((index, token));
}
}
let operands = operand_tokens
.into_iter()
let operands = get_operand_tokens(s, tokens_iter)
.iter()
.map(|(index, token)| {
token
.parse::<Operand>()
.map_err(|e| e.offset(index).span(token.len()))
.map_err(|e| e.offset(*index).span(token.len()))
})
.collect::<Result<Vec<_>, ParseError>>()?;
.try_collect()?;
Ok(Instruction {
instruction,
operands,
@@ -263,14 +251,33 @@ impl FromStr for Instruction {
}
}
#[derive(PartialEq, Debug, Clone, Copy)]
fn get_operand_tokens<'a>(s: &'a str, tokens_iter: SplitConsecutiveWithIndices<'a>) -> Vec<(usize, &'a str)> {
let mut operand_tokens = Vec::with_capacity(8);
let mut string_start = None;
for (index, token) in tokens_iter {
if token.starts_with("HASH(\"") {
string_start = Some(index);
}
if let Some(start) = string_start {
if token.ends_with("\")") {
operand_tokens.push((start, &s[start..(index + token.len())]));
string_start = None;
}
} else {
operand_tokens.push((index, token));
}
}
operand_tokens
}
#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
pub enum Device {
Db,
Numbered(u32),
Indirect { indirection: u32, target: u32 },
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum Operand {
RegisterSpec {
indirection: u32,
@@ -349,7 +356,7 @@ impl Operand {
) -> Result<(Option<u16>, Option<u32>), interpreter::ICError> {
match &self {
&Operand::DeviceSpec { device, connection } => match device {
Device::Db => Ok((Some(ic.id), *connection)),
Device::Db => Ok((Some(ic.device), *connection)),
Device::Numbered(p) => {
let dp = ic
.pins
@@ -598,6 +605,7 @@ impl FromStr for Operand {
.collect::<String>();
if !float_str.is_empty() {
if rest_iter.peek() == Some(&&'.') {
rest_iter.next();
let decimal_str = rest_iter
.take_while_ref(|c| c.is_digit(10))
.collect::<String>();
@@ -684,7 +692,7 @@ impl FromStr for Label {
}
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct Identifier {
// #[rust_sitter::leaf(pattern = r"[a-zA-Z_.][\w\d.]*", transform = |id| id.to_string())]
pub name: String,
@@ -732,7 +740,7 @@ impl FromStr for Identifier {
}
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum Number {
Float(f64),
Binary(f64),
@@ -757,7 +765,6 @@ impl Number {
#[cfg(test)]
mod tests {
use super::generated::*;
use super::*;
#[test]

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +1,56 @@
use core::f64;
use std::collections::{HashMap, HashSet};
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
mod grammar;
mod interpreter;
pub mod grammar;
pub mod interpreter;
mod rand_mscorlib;
mod tokens;
pub mod tokens;
use grammar::{BatchMode, LogicType, ReagentMode, SlotLogicType};
use interpreter::ICError;
use interpreter::{ICError, LineError};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Error, Debug)]
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum VMError {
#[error("Device with id '{0}' does not exist")]
UnknownId(u16),
#[error("IC with id '{0}' does not exist")]
UnknownIcId(u16),
#[error("Device with id '{0}' does not have a IC Slot")]
NoIC(u16),
#[error("IC encoutered an error: {0}")]
ICError(#[from] ICError),
#[error("IC encoutered an error: {0}")]
LineError(#[from] LineError),
#[error("Invalid network ID {0}")]
InvalidNetwork(u16),
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FieldType {
Read,
Write,
ReadWrite,
}
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct LogicField {
pub field_type: FieldType,
pub value: f64,
}
#[derive(Debug, Default)]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Slot {
pub fields: HashMap<grammar::SlotLogicType, LogicField>,
}
#[derive(Debug, Default, Clone, Copy)]
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
pub enum Connection {
CableNetwork(Option<u16>),
#[default]
@@ -56,12 +65,12 @@ pub struct Device {
pub fields: HashMap<grammar::LogicType, LogicField>,
pub slots: Vec<Slot>,
pub reagents: HashMap<ReagentMode, HashMap<i32, f64>>,
pub ic: Option<interpreter::IC>,
pub ic: Option<u16>,
pub connections: [Connection; 8],
pub prefab_hash: Option<i32>,
}
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct Network {
pub devices: HashSet<u16>,
pub channels: [f64; 8],
@@ -74,7 +83,7 @@ struct IdSequenceGenerator {
impl Default for IdSequenceGenerator {
fn default() -> Self {
IdSequenceGenerator { next: 1 }
IdSequenceGenerator { next: 0 }
}
}
@@ -88,13 +97,13 @@ impl IdSequenceGenerator {
#[derive(Debug)]
pub struct VM {
pub ics: HashSet<u16>,
pub devices: HashMap<u16, Device>,
pub networks: HashMap<u16, Network>,
pub ics: HashMap<u16, Rc<RefCell<interpreter::IC>>>,
pub devices: HashMap<u16, Rc<RefCell<Device>>>,
pub networks: HashMap<u16, Rc<RefCell<Network>>>,
pub default_network: u16,
id_gen: IdSequenceGenerator,
network_id_gen: IdSequenceGenerator,
random: crate::rand_mscorlib::Random,
random: Rc<RefCell<crate::rand_mscorlib::Random>>,
}
impl Default for Network {
@@ -146,7 +155,7 @@ impl Network {
impl Device {
pub fn new(id: u16) -> Self {
Device {
let mut device = Device {
id,
name: None,
name_hash: None,
@@ -156,12 +165,36 @@ impl Device {
ic: None,
connections: [Connection::default(); 8],
prefab_hash: None,
}
};
device.connections[0] = Connection::CableNetwork(None);
device
}
pub fn with_ic(id: u16) -> Self {
pub fn with_ic(id: u16, ic: u16) -> Self {
let mut device = Device::new(id);
device.ic = Some(interpreter::IC::new(id));
device.ic = Some(ic);
device.fields.insert(
LogicType::Setting,
LogicField {
field_type: FieldType::ReadWrite,
value: 0.0,
},
);
device.fields.insert(
LogicType::Error,
LogicField {
field_type: FieldType::ReadWrite,
value: 0.0,
},
);
device.fields.insert(
LogicType::PrefabHash,
LogicField {
field_type: FieldType::Read,
value: -128473777.0,
},
);
device.prefab_hash = Some(-128473777);
device
}
@@ -262,19 +295,19 @@ impl VM {
pub fn new() -> Self {
let id_gen = IdSequenceGenerator::default();
let mut network_id_gen = IdSequenceGenerator::default();
let default_network = Network::default();
let default_network = Rc::new(RefCell::new(Network::default()));
let mut networks = HashMap::new();
let default_network_key = network_id_gen.next();
networks.insert(default_network_key, default_network);
let mut vm = VM {
ics: HashSet::new(),
ics: HashMap::new(),
devices: HashMap::new(),
networks,
default_network: default_network_key,
id_gen,
network_id_gen,
random: crate::rand_mscorlib::Random::new(),
random: Rc::new(RefCell::new(crate::rand_mscorlib::Random::new())),
};
let _ = vm.add_ic(None);
vm
@@ -284,8 +317,11 @@ impl VM {
Device::new(self.id_gen.next())
}
fn new_ic(&mut self) -> Device {
Device::with_ic(self.id_gen.next())
fn new_ic(&mut self) -> (Device, interpreter::IC) {
let id = self.id_gen.next();
let ic = interpreter::IC::new(id, id);
let device = Device::with_ic(id, id);
(device, ic)
}
pub fn add_device(&mut self, network: Option<u16>) -> Result<u16, VMError> {
@@ -314,7 +350,15 @@ impl VM {
});
}
let id = device.id;
self.devices.insert(id, device);
self.devices.insert(id, Rc::new(RefCell::new(device)));
let _ = self.add_device_to_network(
id,
if let Some(network) = network {
network
} else {
self.default_network
},
);
Ok(id)
}
@@ -324,7 +368,7 @@ impl VM {
return Err(VMError::InvalidNetwork(*n));
}
}
let mut device = self.new_ic();
let (mut device, ic) = self.new_ic();
if let Some(first_network) = device
.connections
.iter_mut()
@@ -344,45 +388,117 @@ impl VM {
});
}
let id = device.id;
self.devices.insert(id, device);
self.ics.insert(id);
let ic_id = ic.id;
self.devices.insert(id, Rc::new(RefCell::new(device)));
self.ics.insert(ic_id, Rc::new(RefCell::new(ic)));
let _ = self.add_device_to_network(
id,
if let Some(network) = network {
network
} else {
self.default_network
},
);
Ok(id)
}
pub fn add_network(&mut self) -> u16 {
let next_id = self.network_id_gen.next();
self.networks.insert(next_id, Network::default());
self.networks
.insert(next_id, Rc::new(RefCell::new(Network::default())));
next_id
}
pub fn get_default_network(&mut self) -> &mut Network {
self.networks.get_mut(&self.default_network).unwrap()
pub fn get_default_network(&self) -> Rc<RefCell<Network>> {
self.networks.get(&self.default_network).cloned().unwrap()
}
pub fn get_network(&mut self, id: u16) -> Option<&mut Network> {
self.networks.get_mut(&id)
pub fn get_network(&self, id: u16) -> Option<Rc<RefCell<Network>>> {
self.networks.get(&id).cloned()
}
pub fn remove_ic(&mut self, id: u16) {
if self.ics.remove(&id) {
if self.ics.remove(&id).is_some() {
self.devices.remove(&id);
}
}
pub fn set_code(&mut self, id: u16, code: &str) -> Result<bool, VMError> {
let device = self.devices.get_mut(&id).ok_or(VMError::UnknownId(id))?;
let ic = device.ic.as_mut().ok_or(VMError::NoIC(id))?;
pub fn set_code(&self, id: u16, code: &str) -> Result<bool, VMError> {
let device = self
.devices
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow();
let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?;
let mut ic = self
.ics
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.borrow_mut();
let new_prog = interpreter::Program::try_from_code(code)?;
ic.program = new_prog;
ic.ip = 0;
ic.code = code.to_string();
Ok(true)
}
pub fn get_device(&mut self, id: u16) -> Option<&mut Device> {
self.devices.get_mut(&id)
pub fn step_ic(&self, id: u16) -> Result<bool, VMError> {
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
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow_mut().ic = 0;
let result = ic.borrow_mut().step(self)?;
Ok(result)
}
pub fn get_device_same_network(&mut self, source: u16, other: u16) -> Option<&mut Device> {
/// returns true if exacuted 128 lines, false if returned early.
pub fn run_ic(&self, id: u16, ignore_errors: bool) -> Result<bool, VMError> {
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
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow_mut().ic = 0;
for _i in 0..128 {
if let Err(err) = ic.borrow_mut().step(self) {
if !ignore_errors {
return Err(err.into());
}
}
if let interpreter::ICState::Yield = ic.borrow().state {
return Ok(false);
} else if let interpreter::ICState::Sleep(_then, _sleep_for) = ic.borrow().state {
return Ok(false);
}
}
ic.borrow_mut().state = interpreter::ICState::Yield;
Ok(true)
}
pub fn reset_ic(&self, id: u16) -> Result<bool, VMError> {
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
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow_mut().ic = 0;
ic.borrow_mut().reset();
Ok(true)
}
pub fn get_device(&self, id: u16) -> Option<Rc<RefCell<Device>>> {
self.devices.get(&id).cloned()
}
pub fn get_device_same_network(&self, source: u16, other: u16) -> Option<Rc<RefCell<Device>>> {
if self.devices_on_same_network(&[source, other]) {
self.get_device(other)
} else {
@@ -395,29 +511,41 @@ impl VM {
.networks
.get(&(id as u16))
.ok_or(ICError::BadNetworkId(id as u32))?;
Ok(network.channels[channel])
Ok(network.borrow().channels[channel])
}
pub fn set_network_channel(&mut self, id: usize, channel: usize, val: f64) -> Result<(), ICError> {
pub fn set_network_channel(&self, id: usize, channel: usize, val: f64) -> Result<(), ICError> {
let network = self
.networks
.get_mut(&(id as u16))
.get(&(id as u16))
.ok_or(ICError::BadNetworkId(id as u32))?;
network.channels[channel] = val;
network.borrow_mut().channels[channel] = val;
Ok(())
}
pub fn devices_on_same_network(&self, ids: &[u16]) -> bool {
for (_id, net) in self.networks.iter() {
if net.contains(ids) {
if net.borrow().contains(ids) {
return true;
}
}
false
}
fn add_device_to_network(&self, id: u16, network_id: u16) -> Result<bool, VMError> {
if !self.devices.contains_key(&id) {
return Err(VMError::UnknownId(id));
};
if let Some(network) = self.networks.get(&network_id) {
network.borrow_mut().add(id);
Ok(true)
} else {
Err(VMError::InvalidNetwork(network_id))
}
}
pub fn set_batch_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
typ: LogicType,
@@ -425,14 +553,19 @@ impl VM {
) -> Result<(), ICError> {
let networks = &self.networks;
self.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.set_field(typ, val)
device.clone().borrow_mut().set_field(typ, val)
} else {
Ok(())
}
@@ -441,7 +574,7 @@ impl VM {
}
pub fn set_batch_device_slot_field(
&mut self,
&self,
source: u16,
prefab: f64,
index: f64,
@@ -450,14 +583,19 @@ impl VM {
) -> Result<(), ICError> {
let networks = &self.networks;
self.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.set_slot_field(index, typ, val)
device.borrow_mut().set_slot_field(index, typ, val)
} else {
Ok(())
}
@@ -466,7 +604,7 @@ impl VM {
}
pub fn set_batch_name_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
name: f64,
@@ -475,15 +613,20 @@ impl VM {
) -> Result<(), ICError> {
let networks = &self.networks;
self.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
&& Some(name) == device.name_hash
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& Some(name) == device.borrow().name_hash
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.set_field(typ, val)
device.borrow_mut().set_field(typ, val)
} else {
Ok(())
}
@@ -492,7 +635,7 @@ impl VM {
}
pub fn get_batch_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
typ: LogicType,
@@ -501,14 +644,19 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_field(typ).map(|val| Some(val))
device.borrow_mut().get_field(typ).map(|val| Some(val))
} else {
Ok(None)
}
@@ -535,7 +683,7 @@ impl VM {
}
pub fn get_batch_name_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
name: f64,
@@ -545,15 +693,20 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
&& Some(name) == device.name_hash
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& Some(name) == device.borrow().name_hash
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_field(typ).map(|val| Some(val))
device.borrow().get_field(typ).map(|val| Some(val))
} else {
Ok(None)
}
@@ -580,7 +733,7 @@ impl VM {
}
pub fn get_batch_name_device_slot_field(
&mut self,
&self,
source: u16,
prefab: f64,
name: f64,
@@ -591,15 +744,23 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
&& Some(name) == device.name_hash
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& Some(name) == device.borrow().name_hash
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_slot_field(index, typ).map(|val| Some(val))
device
.borrow()
.get_slot_field(index, typ)
.map(|val| Some(val))
} else {
Ok(None)
}
@@ -626,7 +787,7 @@ impl VM {
}
pub fn get_batch_device_slot_field(
&mut self,
&self,
source: u16,
prefab: f64,
index: f64,
@@ -636,14 +797,22 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_slot_field(index, typ).map(|val| Some(val))
device
.borrow()
.get_slot_field(index, typ)
.map(|val| Some(val))
} else {
Ok(None)
}

View File

@@ -1,16 +1,15 @@
use std::usize;
const MSEED: i32 = 161803398;
// const MZ: i32 = 0;
// const MZ: i32 = 0;
#[derive(Debug)]
pub struct Random {
inext: i32,
inextp: i32,
inext: usize,
inextp: usize,
seed_array: [i32; 56],
}
/// Partial implementation of mscorlib System.Random
/// https://github.com/microsoft/referencesource/blob/master/mscorlib/system/random.cs#L94
impl Random {
@@ -29,20 +28,20 @@ impl Random {
seed_array[55] = mj;
let mut mk: i32 = 1;
for i in 1_usize..55 {
let ii = (21 * i) % 55;
for i in 1..55 {
let ii = 21 * i % 55;
seed_array[ii] = mk;
mk = mj - mk;
mk = mj.wrapping_sub(mk);
if mk < 0 {
mk += i32::MAX;
mk = mk.wrapping_add(i32::MAX);
}
mj = seed_array[ii];
}
for _k in 1_usize..5 {
for i in 1_usize..56 {
seed_array[i] -= seed_array[1 + (i + 30) % 55];
seed_array[i] = seed_array[i].wrapping_sub(seed_array[1 + (i + 30) % 55]);
if seed_array[i] < 0 {
seed_array[i] += i32::MAX;
seed_array[i] = seed_array[i].wrapping_add(i32::MAX);
}
}
}
@@ -64,28 +63,24 @@ impl Random {
let mut inext = self.inext;
let mut inextp = self.inextp;
if {
inext += 1;
inext
} >= 56
{
inext += 1;
if inext >= 56 {
inext = 1;
}
if {
inextp += 1;
inextp
} >= 56
{
inextp += 1;
if inextp >= 56 {
inextp = 1;
}
let mut retval = self.seed_array[inext as usize] - self.seed_array[inextp as usize];
let mut retval =
self.seed_array[inext as usize].wrapping_sub(self.seed_array[inextp as usize]);
if retval == i32::MAX {
retval -= 1;
}
if retval < 0 {
retval += i32::MAX;
retval = retval.wrapping_add(i32::MAX);
}
self.seed_array[inext as usize] = retval;
@@ -103,6 +98,26 @@ impl Random {
pub fn next_f64(&mut self) -> f64 {
self.sample()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn create() {
let mut rand = Random::with_seed(0);
assert_eq!(rand.next(), 1559595546);
assert_eq!(rand.next(), 1755192844);
}
#[test]
fn verify() {
let mut rand = Random::with_seed(1919810);
assert_eq!(rand.next(), 147482110);
assert_eq!(rand.next(), 1747108798);
assert_eq!(rand.next(), 1937076328);
assert_eq!(rand.next(), 924982271);
assert_eq!(rand.next_f64(), 0.044092261252967765);
assert_eq!(rand.next(), 659561101);
}
}

View File

@@ -47,14 +47,16 @@ impl<'a> Iterator for SplitConsecutiveWithIndices<'a> {
}
} else {
let s = &self.haystack[self.start..start];
let index = self.start;
self.start = start;
Some((self.start, s))
Some((index, s))
}
}
None => {
let s = &self.haystack[self.start..];
let index = self.start;
self.start = self.haystack.len();
Some((self.start, s))
Some((index, s))
}
}
}

View File

@@ -0,0 +1,147 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"dni-plaintext\"><pre>[ 1559595546, 1755192844 ]</pre></div><style>\r\n",
".dni-code-hint {\r\n",
" font-style: italic;\r\n",
" overflow: hidden;\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview {\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview td {\r\n",
" vertical-align: top;\r\n",
" text-align: start;\r\n",
"}\r\n",
"details.dni-treeview {\r\n",
" padding-left: 1em;\r\n",
"}\r\n",
"table td {\r\n",
" text-align: start;\r\n",
"}\r\n",
"table tr { \r\n",
" vertical-align: top; \r\n",
" margin: 0em 0px;\r\n",
"}\r\n",
"table tr td pre \r\n",
"{ \r\n",
" vertical-align: top !important; \r\n",
" margin: 0em 0px !important;\r\n",
"} \r\n",
"table th {\r\n",
" text-align: start;\r\n",
"}\r\n",
"</style>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"var rand = new System.Random(0);\n",
"int[] two_rands = [rand.Next(), rand.Next()];\n",
"\n",
"two_rands"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"dni-plaintext\"><pre>[ 147482110, 1747108798, 1937076328, 924982271, 0.044092261252967765, 659561101 ]</pre></div><style>\r\n",
".dni-code-hint {\r\n",
" font-style: italic;\r\n",
" overflow: hidden;\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview {\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview td {\r\n",
" vertical-align: top;\r\n",
" text-align: start;\r\n",
"}\r\n",
"details.dni-treeview {\r\n",
" padding-left: 1em;\r\n",
"}\r\n",
"table td {\r\n",
" text-align: start;\r\n",
"}\r\n",
"table tr { \r\n",
" vertical-align: top; \r\n",
" margin: 0em 0px;\r\n",
"}\r\n",
"table tr td pre \r\n",
"{ \r\n",
" vertical-align: top !important; \r\n",
" margin: 0em 0px !important;\r\n",
"} \r\n",
"table th {\r\n",
" text-align: start;\r\n",
"}\r\n",
"</style>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"var rand = new System.Random(1919810);\n",
"double[] samples = [rand.Next(), rand.Next(), rand.Next(), rand.Next(), rand.NextDouble(), rand.Next()];\n",
"\n",
"samples"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"name": "csharp"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

427
ic10emu_wasm/Cargo.lock generated
View File

@@ -12,10 +12,31 @@ dependencies = [
]
[[package]]
name = "autocfg"
version = "1.1.0"
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bumpalo"
@@ -23,12 +44,31 @@ version = "3.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
[[package]]
name = "cc"
version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"serde",
"windows-targets",
]
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
@@ -54,12 +94,75 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "darling"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.55",
]
[[package]]
name = "darling_macro"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [
"darling_core",
"quote",
"syn 2.0.55",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
name = "either"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures-core"
version = "0.3.30"
@@ -80,7 +183,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
"syn 2.0.55",
]
[[package]]
@@ -125,12 +228,53 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ic10emu"
version = "0.1.0"
@@ -143,10 +287,11 @@ dependencies = [
"phf_codegen",
"rand",
"regex",
"serde",
"strum",
"strum_macros",
"thiserror",
"web-time",
"time",
]
[[package]]
@@ -155,13 +300,45 @@ version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"ic10emu",
"itertools",
"js-sys",
"serde",
"serde-wasm-bindgen",
"serde_with",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown 0.14.3",
"serde",
]
[[package]]
name = "itertools"
version = "0.12.1"
@@ -171,6 +348,12 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
version = "0.3.69"
@@ -198,6 +381,30 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -298,6 +505,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -383,9 +596,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "rustversion"
@@ -393,6 +606,84 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "serde"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde-wasm-bindgen"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
dependencies = [
"js-sys",
"serde",
"wasm-bindgen",
]
[[package]]
name = "serde_derive"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
]
[[package]]
name = "serde_json"
version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a"
dependencies = [
"base64",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.2.6",
"serde",
"serde_derive",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.55",
]
[[package]]
name = "siphasher"
version = "0.3.11"
@@ -408,6 +699,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strum"
version = "0.26.2"
@@ -428,7 +725,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.53",
"syn 2.0.55",
]
[[package]]
@@ -444,9 +741,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.53"
version = "2.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
dependencies = [
"proc-macro2",
"quote",
@@ -470,7 +767,41 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
"syn 2.0.55",
]
[[package]]
name = "time"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
dependencies = [
"deranged",
"itoa",
"js-sys",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
@@ -512,7 +843,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.53",
"syn 2.0.55",
"wasm-bindgen-shared",
]
@@ -547,7 +878,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
"syn 2.0.55",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -560,9 +891,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "wasm-streams"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",
@@ -582,11 +913,67 @@ dependencies = [
]
[[package]]
name = "web-time"
version = "1.1.0"
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"js-sys",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"

View File

@@ -6,17 +6,27 @@ edition = "2021"
[dependencies]
ic10emu = { path = "../ic10emu" }
console_error_panic_hook = "0.1.7"
console_error_panic_hook = {version = "0.1.7", optional = true}
js-sys = "0.3.69"
web-sys = { version = "0.3.69", features = ["WritableStream", "console"] }
wasm-bindgen = "0.2.81"
wasm-bindgen-futures = { version = "0.4.30", features = [
"futures-core-03-stream",
] }
wasm-streams = "0.3"
wasm-streams = "0.4"
serde-wasm-bindgen = "0.6.5"
itertools = "0.12.1"
serde = { version = "1.0.197", features = ["derive"] }
serde_with = "3.7.0"
[features]
default = ["console_error_panic_hook"]
console_error_panic_hook = ["dep:console_error_panic_hook"]
[lib]
crate-type = ["cdylib", "rlib"]
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
lto = true

View File

@@ -1,9 +1,18 @@
#[macro_use]
mod utils;
use std::{cell::RefCell, rc::Rc};
use itertools::Itertools;
// use itertools::Itertools;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use ic10emu::VM;
use serde_with::serde_as;
#[serde_as]
#[derive(Serialize, Deserialize)]
struct Stack(#[serde_as(as = "[_; 512]")] [f64; 512]);
#[wasm_bindgen]
extern "C" {
@@ -11,8 +20,302 @@ extern "C" {
}
#[wasm_bindgen]
pub fn init() {
utils::set_panic_hook();
let _vm = VM::new();
log!("Hello from ic10emu!");
pub struct DeviceRef {
device: Rc<RefCell<ic10emu::Device>>,
vm: Rc<RefCell<ic10emu::VM>>,
}
#[wasm_bindgen]
impl DeviceRef {
fn from_device(device: Rc<RefCell<ic10emu::Device>>, vm: Rc<RefCell<ic10emu::VM>>) -> Self {
DeviceRef { device, vm }
}
#[wasm_bindgen(getter)]
pub fn id(&self) -> u16 {
self.device.borrow().id
}
#[wasm_bindgen(getter)]
pub fn name(&self) -> Option<String> {
self.device.borrow().name.clone()
}
#[wasm_bindgen(getter, js_name = "nameHash")]
pub fn name_hash(&self) -> Option<f64> {
self.device.borrow().name_hash
}
#[wasm_bindgen(getter)]
pub fn fields(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().fields).unwrap()
}
#[wasm_bindgen(getter)]
pub fn slots(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().slots).unwrap()
}
#[wasm_bindgen(getter)]
pub fn reagents(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().reagents).unwrap()
}
#[wasm_bindgen(getter)]
pub fn connections(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().connections).unwrap()
}
#[wasm_bindgen(getter, js_name = "prefabHash")]
pub fn prefab_hash(&self) -> Option<i32> {
self.device.borrow().prefab_hash
}
#[wasm_bindgen(getter, js_name = "ip")]
pub fn ic_ip(&self) -> Option<u32> {
self.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| ic.as_ref().borrow().ip)
})
.flatten()
}
#[wasm_bindgen(getter, js_name = "instructionCount")]
pub fn ic_instruction_count(&self) -> Option<u16> {
self.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| ic.as_ref().borrow().ic)
})
.flatten()
}
#[wasm_bindgen(getter, js_name = "stack")]
pub fn ic_stack(&self) -> JsValue {
serde_wasm_bindgen::to_value(
&self
.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| Stack(ic.as_ref().borrow().stack))
})
.flatten(),
)
.unwrap()
}
#[wasm_bindgen(getter, js_name = "registers")]
pub fn ic_registers(&self) -> JsValue {
serde_wasm_bindgen::to_value(
&self
.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| ic.as_ref().borrow().registers)
})
.flatten(),
)
.unwrap()
}
#[wasm_bindgen(getter, js_name = "aliases")]
pub fn ic_aliases(&self) -> JsValue {
serde_wasm_bindgen::to_value(
&self
.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| ic.as_ref().borrow().aliases.clone())
})
.flatten(),
)
.unwrap()
}
#[wasm_bindgen(getter, js_name = "defines")]
pub fn ic_defines(&self) -> JsValue {
serde_wasm_bindgen::to_value(
&self
.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| ic.as_ref().borrow().defines.clone())
})
.flatten(),
)
.unwrap()
}
#[wasm_bindgen(getter, js_name = "pins")]
pub fn ic_pins(&self) -> JsValue {
serde_wasm_bindgen::to_value(
&self
.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| ic.as_ref().borrow().pins)
})
.flatten(),
)
.unwrap()
}
#[wasm_bindgen(getter, js_name = "state")]
pub fn ic_state(&self) -> Option<String> {
self
.device
.borrow()
.ic
.as_ref()
.map(|ic| {
self.vm
.borrow()
.ics
.get(ic)
.map(|ic| ic.borrow().state.clone())
})
.flatten()
.map(|state| state.to_string())
}
#[wasm_bindgen(js_name = "step")]
pub fn step_ic(&self) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().step_ic(id)?)
}
#[wasm_bindgen(js_name = "run")]
pub fn run_ic(&self, ignore_errors: bool) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().run_ic(id, ignore_errors)?)
}
#[wasm_bindgen(js_name = "reset")]
pub fn reset_ic(&self) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().reset_ic(id)?)
}
#[wasm_bindgen(js_name = "setCode")]
pub fn set_code(&self, code: &str) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().set_code(id, code)?)
}
}
#[wasm_bindgen]
#[derive(Debug)]
pub struct VM {
vm: Rc<RefCell<ic10emu::VM>>,
}
#[wasm_bindgen]
impl VM {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
VM {
vm: Rc::new(RefCell::new(ic10emu::VM::new())),
}
}
#[wasm_bindgen(js_name = "addDevice")]
pub fn add_device(&self, network: Option<u16>) -> Result<u16, JsError> {
Ok(self.vm.borrow_mut().add_device(network)?)
}
#[wasm_bindgen(js_name = "getDevice")]
pub fn get_device(&self, id: u16) -> Option<DeviceRef> {
let device = self.vm.borrow().get_device(id);
device.map(|d| DeviceRef::from_device(d.clone(), self.vm.clone()))
}
#[wasm_bindgen(js_name = "setCode")]
pub fn set_code(&self, id: u16, code: &str) -> Result<bool, JsError> {
Ok(self.vm.borrow().set_code(id, code)?)
}
#[wasm_bindgen(js_name = "stepIC")]
pub fn step_ic(&self, id: u16) -> Result<bool, JsError> {
Ok(self.vm.borrow().step_ic(id)?)
}
#[wasm_bindgen(js_name = "runIC")]
pub fn run_ic(&self, id: u16, ignore_errors: bool) -> Result<bool, JsError> {
Ok(self.vm.borrow().run_ic(id, ignore_errors)?)
}
#[wasm_bindgen(js_name = "resetIC")]
pub fn reset_ic(&self, id: u16) -> Result<bool, JsError> {
Ok(self.vm.borrow().reset_ic(id)?)
}
#[wasm_bindgen(getter, js_name = "defaultNetwork")]
pub fn defualt_network(&self) -> u16 {
self.vm.borrow().default_network
}
#[wasm_bindgen(getter)]
pub fn devices(&self) -> Vec<u16> {
self.vm.borrow().devices.keys().copied().collect_vec()
}
#[wasm_bindgen(getter)]
pub fn networks(&self) -> Vec<u16> {
self.vm.borrow().networks.keys().copied().collect_vec()
}
#[wasm_bindgen(getter)]
pub fn ics(&self) -> Vec<u16> {
self.vm.borrow().ics.keys().copied().collect_vec()
}
}
#[wasm_bindgen]
pub fn init() -> VM {
utils::set_panic_hook();
let vm = VM::new();
log!("Hello from ic10emu!");
vm
}

View File

@@ -6,7 +6,11 @@ pub fn set_panic_hook() {
// For more details see
// https://github.com/rustwasm/console_error_panic_hook#readme
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
{
console_error_panic_hook::set_once();
web_sys::console::log_1(&format!("Panic hook set...").into());
}
}

View File

@@ -1174,9 +1174,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "wasm-streams"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",

View File

@@ -19,11 +19,12 @@ tower-lsp = { version = "0.20.0", default-features = false, features = ["runtime
# tree-sitter = { version = "0.9.0", package = "tree-sitter-facade" }
wasm-bindgen = "0.2.81"
wasm-bindgen-futures = { version = "0.4.30", features = ["futures-core-03-stream"] }
wasm-streams = "0.3"
wasm-streams = "0.4"
# web-tree-sitter-sys = "1.3"
ic10lsp = { git = "https://github.com/Ryex/ic10lsp.git", branch = "wasm" }
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
lto = true

View File

@@ -35,7 +35,7 @@
<body class="">
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
<div class="App" >
<div class="App">
<div id="modelShareLink" class="modal fade" tabindex="-1" aria-hidden="true" data-bs-theme="dark">
<div class="modal-dialog">
<div class="modal-content">
@@ -153,62 +153,78 @@
<ul class="nav navbar-nav navbar-right flex-row d-sm-none d-none d-md-flex">
<p class="navbar-text mt-auto mb-auto align-self-center" style="">Official Stationeers:</p>
<li role="presentation" class="">
<a href="https://store.steampowered.com/app/544550/Stationeers/"><svg aria-hidden="true" focusable="false"
data-prefix="fab" data-icon="steam" class="svg-inline--fa fa-steam fa-w-16 " role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512">
<path fill="currentColor"
d="M496 256c0 137-111.2 248-248.4 248-113.8 0-209.6-76.3-239-180.4l95.2 39.3c6.4 32.1 34.9 56.4 68.9 56.4 39.2 0 71.9-32.4 70.2-73.5l84.5-60.2c52.1 1.3 95.8-40.9 95.8-93.5 0-51.6-42-93.5-93.7-93.5s-93.7 42-93.7 93.5v1.2L176.6 279c-15.5-.9-30.7 3.4-43.5 12.1L0 236.1C10.2 108.4 117.1 8 247.6 8 384.8 8 496 119 496 256zM155.7 384.3l-30.5-12.6a52.79 52.79 0 0 0 27.2 25.8c26.9 11.2 57.8-1.6 69-28.4 5.4-13 5.5-27.3.1-40.3-5.4-13-15.5-23.2-28.5-28.6-12.9-5.4-26.7-5.2-38.9-.6l31.5 13c19.8 8.2 29.2 30.9 20.9 50.7-8.3 19.9-31 29.2-50.8 21zm173.8-129.9c-34.4 0-62.4-28-62.4-62.3s28-62.3 62.4-62.3 62.4 28 62.4 62.3-27.9 62.3-62.4 62.3zm.1-15.6c25.9 0 46.9-21 46.9-46.8 0-25.9-21-46.8-46.9-46.8s-46.9 21-46.9 46.8c.1 25.8 21.1 46.8 46.9 46.8z">
</path>
</svg>
<a href="https://store.steampowered.com/app/544550/Stationeers/">
<i class="fa-brands fa-steam fa-w-16"></i>
</a>
</li>
<li role="presentation" class="">
<a href="https://stationeers.com/">
<svg aria-hidden="true" focusable="false" data-prefix="fa" data-icon="globe"
class="svg-inline--fa fa-globe fa-w-16 " role="img" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 496 512">
<path fill="currentColor"
d="M336.5 160C322 70.7 287.8 8 248 8s-74 62.7-88.5 152h177zM152 256c0 22.2 1.2 43.5 3.3 64h185.3c2.1-20.5 3.3-41.8 3.3-64s-1.2-43.5-3.3-64H155.3c-2.1 20.5-3.3 41.8-3.3 64zm324.7-96c-28.6-67.9-86.5-120.4-158-141.6 24.4 33.8 41.2 84.7 50 141.6h108zM177.2 18.4C105.8 39.6 47.8 92.1 19.3 160h108c8.7-56.9 25.5-107.8 49.9-141.6zM487.4 192H372.7c2.1 21 3.3 42.5 3.3 64s-1.2 43-3.3 64h114.6c5.5-20.5 8.6-41.8 8.6-64s-3.1-43.5-8.5-64zM120 256c0-21.5 1.2-43 3.3-64H8.6C3.2 212.5 0 233.8 0 256s3.2 43.5 8.6 64h114.6c-2-21-3.2-42.5-3.2-64zm39.5 96c14.5 89.3 48.7 152 88.5 152s74-62.7 88.5-152h-177zm159.3 141.6c71.4-21.2 129.4-73.7 158-141.6h-108c-8.8 56.9-25.6 107.8-50 141.6zM19.3 352c28.6 67.9 86.5 120.4 158 141.6-24.4-33.8-41.2-84.7-50-141.6h-108z">
</path>
</svg>
<i class="fa-solid fa-globe fa-w-16"></i>
</a>
</li>
<li role="presentation" class="">
<a href="https://twitter.com/stationeers">
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter"
class="svg-inline--fa fa-twitter fa-w-16 " role="img" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512">
<path fill="currentColor"
d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z">
</path>
</svg>
<i class="fa-brands fa-x-twitter"></i>
</a>
</li>
<li role="presentation" class="">
<a href="https://discordapp.com/invite/CxR3mRy">
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="discord"
class="svg-inline--fa fa-discord fa-w-14 " role="img" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512">
<path fill="currentColor"
d="M297.216 243.2c0 15.616-11.52 28.416-26.112 28.416-14.336 0-26.112-12.8-26.112-28.416s11.52-28.416 26.112-28.416c14.592 0 26.112 12.8 26.112 28.416zm-119.552-28.416c-14.592 0-26.112 12.8-26.112 28.416s11.776 28.416 26.112 28.416c14.592 0 26.112-12.8 26.112-28.416.256-15.616-11.52-28.416-26.112-28.416zM448 52.736V512c-64.494-56.994-43.868-38.128-118.784-107.776l13.568 47.36H52.48C23.552 451.584 0 428.032 0 398.848V52.736C0 23.552 23.552 0 52.48 0h343.04C424.448 0 448 23.552 448 52.736zm-72.96 242.688c0-82.432-36.864-149.248-36.864-149.248-36.864-27.648-71.936-26.88-71.936-26.88l-3.584 4.096c43.52 13.312 63.744 32.512 63.744 32.512-60.811-33.329-132.244-33.335-191.232-7.424-9.472 4.352-15.104 7.424-15.104 7.424s21.248-20.224 67.328-33.536l-2.56-3.072s-35.072-.768-71.936 26.88c0 0-36.864 66.816-36.864 149.248 0 0 21.504 37.12 78.08 38.912 0 0 9.472-11.52 17.152-21.248-32.512-9.728-44.8-30.208-44.8-30.208 3.766 2.636 9.976 6.053 10.496 6.4 43.21 24.198 104.588 32.126 159.744 8.96 8.96-3.328 18.944-8.192 29.44-15.104 0 0-12.8 20.992-46.336 30.464 7.68 9.728 16.896 20.736 16.896 20.736 56.576-1.792 78.336-38.912 78.336-38.912z">
</path>
</svg>
<i class="fa-brands fa-discord"></i>
</a>
</li>
</ul>
</nav>
<div class="d-flex flex-column">
<div id="editorContainer" class="p-1 h-100">
<div id="editor" class="w-100"></div>
<div class="d-flex flex-row">
<div class="d-flex flex-column w-100">
<div id="editorContainer" class="p-1 h-100">
<div id="editor" class="w-100"></div>
</div>
<div id="statusBarContainer" class="p-1 mt-auto">
<div id="statusBar" class="w-100 text-body">IC10 editor!</div>
</div>
</div>
<div id="statusBarContainer" class="p-1 mt-auto">
<div id="statusBar" class="w-100 text-body">IC10 editor!</div>
<div class="d-flex flex-column flex-shrink-1">
<div id="virtualMachine" >
<div id="vmActiveIC">
<div class="p-2 d-flex flex-row justify-content-center">
<div class="d-flex flex-column">
<div id="vmControls" class="btn-group-vertical btn-group-sm " role="group"
aria-label="Virtual Machine Controls">
<button id="vmControlRun" type="button" class="btn btn-primary">Run</button>
<button id="vmControlStep" type="button" class="btn btn-secondary">Step</button>
<button id="vmControlReset" type="button" class="btn btn-warning">Reset</button>
</div>
</div>
<div class="card ms-2">
<div class="card-header">State</div>
<div id="vmActiveICState" class="card-body">
</div>
</div>
</div>
<div class="p-2 ms-2 d-flex flex-row">
<div class="card ms-2">
<div class="card-header">Registers</div>
<div id="vmActiveRegisters" class="vm_reg">
</div>
</div>
<div id="vmActiveStack">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.7/ace.js" type="text/javascript" charset="utf-8"></script> -->
<script>
</script>
</body>
</html>
</html>

View File

@@ -36,6 +36,8 @@ ace.config.setModuleLoader('ace/keyboard/sublime', () => import('ace-code/src/ke
ace.config.setModuleLoader('ace/keyboard/vim', () => import('ace-code/src/keyboard/vim.js'));
ace.config.setModuleLoader('ace/keyboard/vscode', () => import('ace-code/src/keyboard/vscode.js'));
ace.config.setModuleLoader('ace/range', () => import('ace-code/src/range'));
console.log("ace module loaders patched");
export { ace };

View File

@@ -3,7 +3,7 @@ import { Mode as IC10Mode } from "./ic10_mode.js";
import * as one_dark from "ace-code/src/theme/one_dark";
import { AceLanguageClient } from "ace-linters/build/ace-language-client";
import { IC10EditorUI } from './ui.js';
import { Range } from 'ace-code/src/range.js';
// to make sure language tools are loaded
import _ace_ext_langue_tools from "ace-code/src/ext/language_tools";
@@ -21,139 +21,173 @@ async function setupLspWorker() {
}
function IC10Editor(session_id) {
this.mode = new IC10Mode()
class IC10Editor {
constructor(session_id) {
window.Editor = this;
this.mode = new IC10Mode();
this.settings = {
keyboard: "ace",
cursor: "ace",
fontSize: 16,
relativeLineNumbers: false,
};
this.settings = {
keyboard: "ace",
cursor: "ace",
fontSize: 16,
relativeLineNumbers: false,
};
this.editor = ace.edit('editor', {
mode: this.mode,
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
enableSnippets: true,
theme: "ace/theme/one_dark",
fontSize: "16px",
customScrollbar: true,
firstLineNumber: 0,
printMarginColumn: 52,
});
this.aceEditor = ace.edit('editor', {
mode: this.mode,
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
enableSnippets: true,
theme: "ace/theme/one_dark",
fontSize: "16px",
customScrollbar: false,
firstLineNumber: 0,
printMarginColumn: 52,
});
this.sessions = {};
this.sessions[session_id] = this.editor.getSession();
this.active_session = session_id;
this.bindSession(session_id, this.sessions[session_id]);
this.sessions = {};
this.sessions[session_id] = this.aceEditor.getSession();
this.active_session = session_id;
this.bindSession(session_id, this.sessions[session_id]);
this.active_line_markers = {};
this.active_line_markers[session_id] = null;
this.languageProvider = null;
this.languageProvider = null;
this.ui = new IC10EditorUI(this);
this.ui = new IC10EditorUI(this);
const self = this;
const self = this;
App.session.onLoad((session) => {
const updated_ids = [];
for (const id in session.programs) {
updated_ids.push(id);
self.createOrSetSession(id, session.programs[id]);
App.session.onLoad((session) => {
const updated_ids = [];
for (const id in session.programs) {
updated_ids.push(id);
self.createOrSetSession(id, session.programs[id]);
}
for (const id in self.sessions) {
if (!updated_ids.includes(id)) {
self.destroySession(id);
}
}
});
App.session.loadFromFragment();
App.session.onActiveLine(session => {
for (const id in Object.keys(session.programs)) {
const active_line = session.getActiveLine(id);
if (typeof active_line !== "undefined") {
const marker = self.active_line_markers[id];
if (marker) {
self.sessions[id].removeMarker(marker);
self.active_line_markers[id] = null;
}
self.active_line_markers[id] = self.sessions[id].addMarker(new Range(active_line, 0, active_line, 1), "vm_ic_active_line", "fullLine", true);
if (self.active_session == id) {
// editor.resize(true);
self.aceEditor.scrollToLine(active_line, true, true)
}
}
}
})
}
createOrSetSession(session_id, content) {
if (!this.sessions.hasOwnProperty(session_id)) {
this.newSession(session_id);
}
for (const id in self.sessions) {
if (!updated_ids.includes(id)) {
self.destroySession(id);
this.sessions[session_id].setValue(content);
}
newSession(session_id) {
if (this.sessions.hasOwnProperty(session_id)) {
return false;
}
this.sessions[session_id] = ace.createEditSession("", this.mode);
this.bindSession(session_id, this.sessions[session_id]);
}
setupLsp(lsp_worker) {
const serverData = {
module: () => import("ace-linters/build/language-client"),
modes: "ic10",
type: "webworker",
worker: lsp_worker,
};
// Create a language provider for web worker
this.languageProvider = AceLanguageClient.for(serverData);
this.languageProvider.registerEditor(this.aceEditor);
for (const session_id in this.sessions) {
let options = this.mode.options ?? {};
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
}
}
activateSession(session_id) {
if (!this.sessions.hasOwnProperty(session_id)) {
return false;
}
this.aceEditor.setSession(this.sessions[session_id]);
this.active_session = session_id;
let options = this.mode.options ?? {};
if (this.languageProvider !== null) {
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
}
return true;
}
loadEditorSettings() {
const saved_settings = window.localStorage.getItem("editorSettings");
if (saved_settings !== null && saved_settings.length > 0) {
try {
const saved = JSON.parse(saved_settings);
const temp = Object.assign({}, this.settings, saved);
Object.assign(this.settings, temp);
} catch (e) {
console.log("error loading editor settings", e);
}
}
})
App.session.loadFromFragment();
}
IC10Editor.prototype.createOrSetSession = function(session_id, content) {
if (!this.sessions.hasOwnProperty(session_id)) {
this.newSession(session_id);
}
this.sessions[session_id].setValue(content);
}
IC10Editor.prototype.newSession = function(session_id) {
if (this.sessions.hasOwnProperty(session_id)) {
return false;
}
this.sessions[session_id] = ace.createEditSession("", this.mode);
this.bindSession(session_id, this.sessions[session_id]);
}
IC10Editor.prototype.setupLsp = function(lsp_worker) {
const serverData = {
module: () => import("ace-linters/build/language-client"),
modes: "ic10",
type: "webworker",
worker: lsp_worker,
};
// Create a language provider for web worker
this.languageProvider = AceLanguageClient.for(serverData);
this.languageProvider.registerEditor(this.editor);
for (const session_id in this.sessions) {
let options = this.mode.options ?? {};
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
}
}
IC10Editor.prototype.activateSession = function(session_id) {
if (!this.sessions.hasOwnProperty(session_id)) {
return false;
saveEditorSettings() {
const toSave = JSON.stringify(this.settings);
window.localStorage.setItem("editorSettings", toSave);
}
this.editor.setSession(this.sessions[session_id]);
let options = this.mode.options ?? {};
if (this.languageProvider !== null) {
this.languageProvider.setSessionOptions(this.sessions[session_id], options);
}
return true;
}
IC10Editor.prototype.loadEditorSettings = function() {
const saved_settings = window.localStorage.getItem("editorSettings");
if (saved_settings !== null && saved_settings.length > 0) {
try {
const saved = JSON.parse(saved_settings);
const temp = Object.assign({}, this.settings, saved);
Object.assign(this.settings, temp);
} catch (e) {
console.log("error loading editor settings", e);
destroySession(session_id) {
if (!this.sessions.hasOwnProperty(session_id)) {
return false;
}
if (!(Object.keys(this.sessions).length > 1)) {
return false;
}
const session = this.sessions[session_id];
delete this.sessions[session_id];
if (this.active_session = session_id) {
this.activateSession(Object.keys(this.sessions)[0]);
}
session.destroy();
return true;
}
bindSession(session_id, session) {
session.on('change', () => {
var val = session.getValue();
window.App.session.setProgramCode(session_id, val);
});
}
}
IC10Editor.prototype.saveEditorSettings = function() {
const toSave = JSON.stringify(this.settings);
window.localStorage.setItem("editorSettings", toSave);
}
IC10Editor.prototype.destroySession = function(session_id) {
if (!this.sessions.hasOwnProperty(session_id)) {
return false;
}
if (!(Object.keys(this.sessions).length > 1)) {
return false;
}
const session = this.sessions[session_id];
delete this.sessions[session_id];
if (this.active_session = session_id) {
this.activateSession(Object.keys(this.sessions)[0]);
}
session.destroy();
return true;
}
IC10Editor.prototype.bindSession = function(session_id, session) {
session.on('change', () => {
var val = session.getValue();
window.App.session.setProgramCode(session_id, val);
});
}
export { IC10Editor, setupLspWorker };

View File

@@ -107,9 +107,9 @@ export class AsyncStreamQueue {
async next() {
const done = false;
console.log(`AsyncStream(${this.tag}) waiting for message`)
// console.log(`AsyncStream(${this.tag}) waiting for message`)
const value = await this.dequeue();
console.log(`AsyncStream(${this.tag}) got message`, decoder.decode(value))
// console.log(`AsyncStream(${this.tag}) got message`, decoder.decode(value))
return { done, value };
}

View File

@@ -1,104 +1,111 @@
import { ace } from "./ace";
import { Offcanvas } from 'bootstrap';
function IC10EditorUI(ic10editor) {
class IC10EditorUI {
const self = this;
constructor(ic10editor) {
self.ic10editor = ic10editor;
const self = this;
self.ic10editor.editor.commands.addCommand({
name: "showSettingsMenu",
description: "Show settings menu",
bindKey: { win: "Ctrl-,", mac: "Command-," },
exec: (_editor) => {
const offCanvas = new Offcanvas(document.getElementById("editorSettings"));
offCanvas.toggle();
}
});
self.ic10editor = ic10editor;
ace.config.loadModule("ace/ext/keyboard_menu", function(module) {
console.log("keybinding_menu loaded");
module.init(self.ic10editor.editor);
})
self.ic10editor.aceEditor.commands.addCommand({
name: "showSettingsMenu",
description: "Show settings menu",
bindKey: { win: "Ctrl-,", mac: "Command-," },
exec: (_editor) => {
const offCanvas = new Offcanvas(document.getElementById("editorSettings"));
offCanvas.toggle();
}
});
self.ic10editor.loadEditorSettings();
self.displayEditorSettings();
self.updateEditorSettings();
self.reCalcEditorSize();
window.addEventListener('resize', (e) => { self.reCalcEditorSize() });
ace.config.loadModule("ace/ext/keyboard_menu", function (module) {
console.log("keybinding_menu loaded");
module.init(self.ic10editor.aceEditor);
});
document.getElementsByName("editorKeybindRadio").forEach((el) => {
el.addEventListener('change', (e) => {
self.ic10editor.settings.keyboard = e.target.value;
self.ic10editor.loadEditorSettings();
self.displayEditorSettings();
self.updateEditorSettings();
self.reCalcEditorSize();
window.addEventListener('resize', (e) => { self.reCalcEditorSize(); });
document.getElementsByName("editorKeybindRadio").forEach((el) => {
el.addEventListener('change', (e) => {
self.ic10editor.settings.keyboard = e.target.value;
self.ic10editor.saveEditorSettings();
self.updateEditorSettings();
});
});
document.getElementsByName("editorCursorRadio").forEach((el) => {
el.addEventListener('change', (e) => {
self.ic10editor.settings.cursor = e.target.value;
self.ic10editor.saveEditorSettings();
self.updateEditorSettings();
});
});
document.getElementById("editorSettingsFontSize").addEventListener('change', (e) => {
window.App.editorSettings.fontSize = e.target.value;
self.ic10editor.saveEditorSettings();
self.updateEditorSettings();
})
});
document.getElementsByName("editorCursorRadio").forEach((el) => {
el.addEventListener('change', (e) => {
self.ic10editor.settings.cursor = e.target.value;
});
document.getElementById("editorSettingsRelativeLineNumbers").addEventListener('change', (e) => {
window.App.editorSettings.relativeLineNumbers = e.target.checked;
self.ic10editor.saveEditorSettings();
self.updateEditorSettings();
})
});
document.getElementById("editorSettingsFontSize").addEventListener('change', (e) => {
window.App.editorSettings.fontSize = e.target.value;
self.ic10editor.saveEditorSettings();
self.updateEditorSettings();
});
document.getElementById("editorSettingsRelativeLineNumbers").addEventListener('change', (e) => {
window.App.editorSettings.relativeLineNumbers = e.target.checked;
self.ic10editor.saveEditorSettings();
self.updateEditorSettings();
})
});
console.log(self.ic10editor.editor.getOption('keyboardHandler'));
console.log(self.ic10editor.aceEditor.getOption('keyboardHandler'));
self.ic10editor.editor.setTheme("ace/theme/one_dark");
ace.config.loadModule("ace/ext/statusbar", function(module) {
const statusBar = new module.StatusBar(self.ic10editor.editor, document.getElementById("statusBar"));
statusBar.updateStatus(self.ic10editor.editor);
})
self.ic10editor.aceEditor.setTheme("ace/theme/one_dark");
ace.config.loadModule("ace/ext/statusbar", function (module) {
const statusBar = new module.StatusBar(self.ic10editor.aceEditor, document.getElementById("statusBar"));
statusBar.updateStatus(self.ic10editor.aceEditor);
});
self.ic10editor.editor.setAutoScrollEditorIntoView(true);
}
self.ic10editor.aceEditor.setAutoScrollEditorIntoView(true);
IC10EditorUI.prototype.updateEditorSettings = function() {
const settings = this.ic10editor.settings;
const editor = this.ic10editor.editor;
if (settings.keyboard === 'ace') {
editor.setOption('keyboardHandler', null);
} else {
editor.setOption('keyboardHandler', `ace/keyboard/${settings.keyboard}`);
}
editor.setOption('cursorStyle', settings.cursor);
editor.setOption('fontSize', `${settings.fontSize}px`);
editor.setOption('relativeLineNumbers', settings.relativeLineNumbers);
updateEditorSettings() {
const settings = this.ic10editor.settings;
const editor = this.ic10editor.aceEditor;
if (settings.keyboard === 'ace') {
editor.setOption('keyboardHandler', null);
} else {
editor.setOption('keyboardHandler', `ace/keyboard/${settings.keyboard}`);
}
editor.setOption('cursorStyle', settings.cursor);
editor.setOption('fontSize', `${settings.fontSize}px`);
editor.setOption('relativeLineNumbers', settings.relativeLineNumbers);
}
displayEditorSettings() {
const settings = this.ic10editor.settings;
document.getElementsByName("editorKeybindRadio").forEach((el) => {
el.checked = el.value === settings.keyboard;
});
document.getElementsByName("editorCursorRadio").forEach((el) => {
el.checked = el.value === settings.cursor;
});
document.getElementById("editorSettingsFontSize").value = settings.fontSize;
document.getElementById("editorSettingsRelativeLineNumbers").checked = settings.relativeLineNumbers;
}
reCalcEditorSize() {
const editor = this.ic10editor.aceEditor;
const navBar = document.getElementById("navBar");
const statusBarContainer = document.getElementById("statusBarContainer");
const correction = navBar.offsetHeight + statusBarContainer.offsetHeight;
const editorContainer = document.getElementById("editor");
editorContainer.style.height = `calc( 100vh - ${correction}px - 0.5rem)`;
editor.resize(true);
}
}
IC10EditorUI.prototype.displayEditorSettings = function() {
const settings = this.ic10editor.settings;
document.getElementsByName("editorKeybindRadio").forEach((el) => {
el.checked = el.value === settings.keyboard;
});
document.getElementsByName("editorCursorRadio").forEach((el) => {
el.checked = el.value === settings.cursor;
});
document.getElementById("editorSettingsFontSize").value = settings.fontSize;
document.getElementById("editorSettingsRelativeLineNumbers").checked = settings.relativeLineNumbers;
}
IC10EditorUI.prototype.reCalcEditorSize = function() {
const editor = this.ic10editor.editor;
const navBar = document.getElementById("navBar");
const statusBarContainer = document.getElementById("statusBarContainer");
const correction = navBar.offsetHeight + statusBarContainer.offsetHeight;
const editorContainer = document.getElementById("editor");
editorContainer.style.height = `calc( 100vh - ${correction}px - 0.5rem)`;
editor.resize(true);
}
export { IC10EditorUI };

View File

@@ -1,10 +1,10 @@
import { init } from "ic10emu_wasm";
import { IC10Editor, setupLspWorker } from "./editor";
import { Session } from './session';
import { VirtualMachine } from "./virtual_machine";
const App = {
editor: null,
vm: null,
session: new Session()
};
@@ -20,10 +20,10 @@ function docReady(fn) {
}
}
init();
docReady(() => {
App.vm = new VirtualMachine();
App.editor = new IC10Editor();
setupLspWorker().then((worker) => {

View File

@@ -37,7 +37,7 @@ move r2 100000.001
# to get their documentation
# vvvvvvvvvvvvvvv
move r0 HASH("AccessCardBlack")
beqz r1 test
beqzal r1 test
# -2045627372 is the crc32 hash of a SolarPanel,
# hover it to see the documentation!
@@ -45,7 +45,7 @@ beqz r1 test
move r1 -2045627372
jal test
move r1 $FF
beqz 0 test
beqzal 0 test
move r1 %1000
yield
j main
@@ -61,6 +61,9 @@ class Session {
this._programs = {};
this._save_timeout = 0;
this._onLoadCallbacks = [];
this._activeSession = 0;
this._activeLines = {};
this._onActiveLineCallbacks = [];
this.loadFromFragment();
const self = this;
@@ -77,6 +80,23 @@ class Session {
Object.assign(this._programs, programs);
}
get activeSession() {
return this._activeSession;
}
getActiveLine(id) {
return this._activeLines[id];
}
setActiveLine(id, line) {
this._activeLines[id] = line;
this._fireOnActiveLine();
}
set activeLine(line) {
this._activeLine = line;
}
setProgramCode(id, code) {
this._programs[id] = code;
this.save();
@@ -93,10 +113,25 @@ class Session {
}
}
onActiveLine(callback) {
this._onActiveLineCallbacks.push(callback);
}
_fireOnActiveLine() {
for (const i in this._onActiveLineCallbacks) {
const callback = this._onActiveLineCallbacks[i];
callback(this);
}
}
save() {
if (this._save_timeout) clearTimeout(this._save_timeout);
this._save_timeout = setTimeout(() => {
this.saveToFragment();
if (window.App.vm) {
window.App.vm.updateCode();
}
}, 1000);
}

View File

@@ -0,0 +1,201 @@
import { init } from "ic10emu_wasm";
// import { Card } from 'bootstrap';
class VirtualMachine {
constructor() {
const vm = init();
window.VM = this;
this.ic10vm = vm;
this.ui = new VirtualMachineUI(this);
this.ics = {}
const ics = this.ic10vm.ics;
for (const id of Object.keys(ics)) {
this.ics[id] = this.ic10vm.getDevice(parseInt(id));
}
this.updateCode()
}
updateCode() {
const progs = window.App.session.programs;
for (const id of Object.keys(progs)) {
const ic = this.ics[id];
const prog = progs[id];
if (ic && prog) {
console.time(`CompileProgram_${id}`);
this.ics[id].setCode(progs[id]);
console.timeEnd(`CompileProgram_${id}`);
}
}
this.update();
}
step() {
const ic = this.ics[window.App.session.activeSession];
if (ic) {
try {
ic.step();
} catch (e) {
console.log(e);
}
this.update();
}
}
run() {
const ic = this.ics[window.App.session.activeSession];
if (ic) {
try {
ic.run(false);
} catch (e) {
console.log(e);
}
this.update();
}
}
reset() {
const ic = this.ics[window.App.session.activeSession];
if (ic) {
ic.reset();
this.update();
}
}
update() {
const ic = this.ics[window.App.session.activeSession];
window.App.session.setActiveLine(window.App.session.activeSession, ic.ip);
this.ui.update(ic);
}
}
class VirtualMachineUI {
constructor(vm) {
this.vm = vm
this.state = new VMStateUI();
this.registers = new VMRegistersUI();
this.buildStackDisplay();
const self = this;
document.getElementById("vmControlRun").addEventListener('click', (_event) => {
self.vm.run();
}, { capture: true });
document.getElementById("vmControlStep").addEventListener('click', (_event) => {
self.vm.step();
}, { capture: true });
document.getElementById("vmControlReset").addEventListener('click', (_event) => {
self.vm.reset();
}, { capture: true });
}
update(ic) {
this.state.update(ic);
this.registers.update(ic);
}
buildStackDisplay() {
}
}
class VMStateUI {
constructor() {
const stateDom = document.getElementById("vmActiveICState");
this.tbl = document.createElement("table");
this.tbl.classList.add("table");
this.ipRow = this.tbl.insertRow();
this.counterRow = this.tbl.insertRow()
this.stateRow = this.tbl.insertRow()
const ipTh = document.createElement("th");
ipTh.appendChild(document.createTextNode("Instruction Pointer"));
this.ipRow.appendChild(ipTh);
this.instructionPointer = this.ipRow.insertCell();
const conuterTh = document.createElement("th");
conuterTh.appendChild(document.createTextNode("Last Run Operations"));
this.counterRow.appendChild(conuterTh);
this.instructionCounter = this.counterRow.insertCell();
const stateTh = document.createElement("th");
stateTh.appendChild(document.createTextNode("Last State"));
this.stateRow.appendChild(stateTh);
this.lastState = this.stateRow.insertCell();
stateDom.appendChild(this.tbl);
}
update(ic) {
if (ic) {
this.instructionPointer.innerText = ic.ip.toString();
this.instructionCounter.innerText = ic.instructionCount.toString();
this.lastState.innerText = ic.state.toString();
}
}
}
class VMRegistersUI {
constructor() {
const regDom = document.getElementById("vmActiveRegisters");
this.tbl = document.createElement("div");
this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-start", "align-self-center");
this.regCels = [];
for (var i = 0; i < 18; i++) {
const container = document.createElement("div");
container.classList.add("vm_reg_cel");
const cell = document.createElement("div");
cell.classList.add("input-group", "input-group-sm")
// cell.style.width = "30%";
const nameLabel = document.createElement("span");
nameLabel.innerText = `r${i}`;
nameLabel.classList.add("input-group-text")
cell.appendChild(nameLabel);
const input = document.createElement("input");
input.type = "text"
input.value = 0;
// input.size = 3;
// input.style.width = 40;
cell.appendChild(input);
const aliasesLabel = document.createElement("span");
aliasesLabel.classList.add("input-group-text")
aliasesLabel.innerText = "\xa0";
cell.appendChild(aliasesLabel);
if (i == 16 ) {
aliasesLabel.innerText = "sp";
} else if (i == 17) {
aliasesLabel.innerText = "ra";
}
this.regCels.push({
cell,
nameLabel,
aliasesLabel,
input,
});
container.appendChild(cell);
this.tbl.appendChild(container);
}
regDom.appendChild(this.tbl);
}
update(ic) {
if (ic) {
const registers = ic.registers;
if (registers) {
console.log(registers)
for (var i = 0; i < registers.length; i++) {
this.regCels[i].input.value = registers[i];
}
}
}
}
}
export { VirtualMachine }

View File

@@ -409,3 +409,33 @@ code {
border: 1px solid rgba(8, 121, 144, 0.5);
background: rgba(76, 87, 103, .19);
}
.vm_ic_active_line {
position: absolute;
background: rgba(121, 82, 179, 0.4);
z-index: 20;
}
.vm_reg {
overflow-x: auto;
overflow-y: auto;
max-width: 1200px;
max-height: 400px;
}
// .vm_unset_reg .input-group {
// width: inherit;
// }
.vm_reg_cel {
max-width: 300px;
height: 32px;
}
.vm_reg_cel span {
min-width: 2.5rem;
}
.vm_reg_cel input {
width: 6rem;
}

View File

@@ -12,7 +12,7 @@ $offcanvas-box-shadow: 0 1rem 3rem rgba(0, 0, 0, .175);
$body-color: #333;
$body-bg: #fff;
$border-radius: .4rem;
$success: #7952b3;
$success: rgb(121, 82, 179);
// Required
@import "bootstrap/scss/variables";