add more sensible API for object handles, add drop instruction

floats
Ondřej Hruška 4 years ago
parent 79d5aa3cd5
commit d5de189af6
Signed by untrusted user: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 125
      crsn/src/asm/data/mod.rs
  2. 58
      crsn/src/asm/data/rd.rs
  3. 39
      crsn/src/asm/data/wr.rs
  4. 6
      crsn/src/asm/instr/flatten.rs
  5. 2
      crsn/src/asm/instr/op.rs
  6. 6
      crsn/src/asm/mod.rs
  7. 14
      crsn/src/asm/parse/arg_parser.rs
  8. 4
      crsn/src/asm/parse/mod.rs
  9. 4
      crsn/src/asm/parse/parse_cond.rs
  10. 8
      crsn/src/asm/parse/parse_data.rs
  11. 4
      crsn/src/asm/parse/parse_instr.rs
  12. 8
      crsn/src/asm/parse/parse_op.rs
  13. 4
      crsn/src/asm/parse/parse_routines.rs
  14. 5
      crsn/src/builtin/defs.rs
  15. 17
      crsn/src/builtin/exec.rs
  16. 15
      crsn/src/builtin/parse.rs
  17. 36
      crsn/src/module/mod.rs
  18. 5
      crsn/src/runtime/fault.rs
  19. 5
      crsn/src/runtime/program.rs
  20. 32
      crsn/src/runtime/run_thread.rs
  21. 25
      crsn/src/runtime/run_thread/info.rs
  22. 29
      crsn/src/runtime/run_thread/state.rs
  23. 6
      crsn_arith/src/parse.rs
  24. 7
      crsn_stacks/src/defs.rs
  25. 63
      crsn_stacks/src/exec.rs
  26. 24
      crsn_stacks/src/parse.rs
  27. 32
      launcher/src/main.rs

@ -13,6 +13,13 @@ pub mod literal;
pub mod reg; pub mod reg;
pub mod mask; pub mod mask;
mod rd;
pub use rd::Rd;
pub use rd::RdObj;
mod wr;
pub use wr::Wr;
/// Data source disposition /// Data source disposition
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum DataDisp { pub enum DataDisp {
@ -36,7 +43,7 @@ impl Display for DataDisp {
write!(f, "{}", r) write!(f, "{}", r)
} }
DataDisp::ObjectPtr(r) => { DataDisp::ObjectPtr(r) => {
write!(f, "%{}", r) write!(f, "@{}", r)
} }
DataDisp::Discard => { DataDisp::Discard => {
write!(f, "_") write!(f, "_")
@ -45,29 +52,29 @@ impl Display for DataDisp {
} }
} }
impl From<SrcDisp> for DataDisp { impl From<RdData> for DataDisp {
fn from(s: SrcDisp) -> Self { fn from(s: RdData) -> Self {
match s { match s {
SrcDisp::Immediate(x) => DataDisp::Immediate(x), RdData::Immediate(x) => DataDisp::Immediate(x),
SrcDisp::Register(x) => DataDisp::Register(x), RdData::Register(x) => DataDisp::Register(x),
SrcDisp::ObjectPtr(x) => DataDisp::ObjectPtr(x), RdData::ObjectPtr(x) => DataDisp::ObjectPtr(x),
} }
} }
} }
impl From<DstDisp> for DataDisp { impl From<WrData> for DataDisp {
fn from(s: DstDisp) -> Self { fn from(s: WrData) -> Self {
match s { match s {
DstDisp::Register(x) => DataDisp::Register(x), WrData::Register(x) => DataDisp::Register(x),
DstDisp::ObjectPtr(x) => DataDisp::ObjectPtr(x), WrData::ObjectPtr(x) => DataDisp::ObjectPtr(x),
DstDisp::Discard => DataDisp::Discard, WrData::Discard => DataDisp::Discard,
} }
} }
} }
/// Data source disposition /// Data source disposition
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum SrcDisp { pub enum RdData {
/// Constant value /// Constant value
Immediate(Value), Immediate(Value),
/// Register /// Register
@ -76,14 +83,14 @@ pub enum SrcDisp {
ObjectPtr(Register), ObjectPtr(Register),
} }
impl TryFrom<DataDisp> for SrcDisp { impl TryFrom<DataDisp> for RdData {
type Error = AsmError; type Error = AsmError;
fn try_from(value: DataDisp) -> Result<Self, Self::Error> { fn try_from(value: DataDisp) -> Result<Self, Self::Error> {
match value { match value {
DataDisp::Immediate(x) => Ok(SrcDisp::Immediate(x)), DataDisp::Immediate(x) => Ok(RdData::Immediate(x)),
DataDisp::Register(x) => Ok(SrcDisp::Register(x)), DataDisp::Register(x) => Ok(RdData::Register(x)),
DataDisp::ObjectPtr(x) => Ok(SrcDisp::ObjectPtr(x)), DataDisp::ObjectPtr(x) => Ok(RdData::ObjectPtr(x)),
DataDisp::Discard => Err(AsmError::DiscardAsValue), DataDisp::Discard => Err(AsmError::DiscardAsValue),
} }
} }
@ -91,7 +98,7 @@ impl TryFrom<DataDisp> for SrcDisp {
/// Data destination disposition /// Data destination disposition
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum DstDisp { pub enum WrData {
/// Register /// Register
Register(Register), Register(Register),
/// Pointer into memory, stored in a numbered register /// Pointer into memory, stored in a numbered register
@ -100,92 +107,26 @@ pub enum DstDisp {
Discard, Discard,
} }
impl From<DstDisp> for SrcDisp { impl From<WrData> for RdData {
fn from(s: DstDisp) -> Self { fn from(s: WrData) -> Self {
match s { match s {
DstDisp::Register(x) => SrcDisp::Register(x), WrData::Register(x) => RdData::Register(x),
DstDisp::ObjectPtr(x) => SrcDisp::ObjectPtr(x), WrData::ObjectPtr(x) => RdData::ObjectPtr(x),
DstDisp::Discard => SrcDisp::Immediate(0), WrData::Discard => RdData::Immediate(0),
} }
} }
} }
impl TryFrom<DataDisp> for DstDisp { impl TryFrom<DataDisp> for WrData {
type Error = AsmError; type Error = AsmError;
fn try_from(value: DataDisp) -> Result<Self, Self::Error> { fn try_from(value: DataDisp) -> Result<Self, Self::Error> {
match value { match value {
DataDisp::Immediate(_x) => Err(AsmError::ValueAsOutput), DataDisp::Immediate(_x) => Err(AsmError::ValueAsOutput),
DataDisp::Register(x) => Ok(DstDisp::Register(x)), DataDisp::Register(x) => Ok(WrData::Register(x)),
DataDisp::ObjectPtr(x) => Ok(DstDisp::ObjectPtr(x)), DataDisp::ObjectPtr(x) => Ok(WrData::ObjectPtr(x)),
DataDisp::Discard => Ok(DstDisp::Discard), DataDisp::Discard => Ok(WrData::Discard),
}
}
}
/// Data source argument (read-only)
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Rd(SrcDisp, Mask);
impl Rd {
pub fn new(src: SrcDisp) -> Self {
Rd(src, Mask::default())
}
pub fn d(self) -> SrcDisp {
self.0
}
pub fn mask(self) -> Mask {
self.1
}
pub fn immediate(val: Value) -> Rd {
Rd(SrcDisp::Immediate(val), Mask::default())
}
}
/// Data destination argument (read-write)
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Wr(DstDisp, Mask);
impl Wr {
pub fn new(dst: DstDisp) -> Self {
Wr(dst, Mask::default())
}
pub fn d(self) -> DstDisp {
self.0
}
pub fn mask(self) -> Mask {
self.1
}
pub fn as_rd(&self) -> Rd {
Rd(self.0.into(), self.1)
}
pub fn discard() -> Wr {
Wr(DstDisp::Discard, Mask::default())
}
}
impl Debug for Rd {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Rd(")?;
let disp: DataDisp = self.0.into();
write!(f, "{}", disp)?;
if !self.mask().is_default() {
write!(f, ",{:?}", self.mask())?;
} }
write!(f, ")")
} }
} }
impl Debug for Wr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Wr(")?;
let disp: DataDisp = self.0.into();
write!(f, "{}", disp)?;
if !self.mask().is_default() {
write!(f, ",{:?}", self.mask())?;
}
write!(f, ")")
}
}

@ -0,0 +1,58 @@
use crate::asm::data::{RdData, Mask, DataDisp, Register};
use crate::asm::data::literal::Value;
use std::fmt::{Debug, Formatter};
use std::fmt;
/// Data source argument (read-only)
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Rd(pub RdData, pub Mask);
impl Rd {
pub const fn new(src: RdData) -> Self {
Rd(src, Mask::FULL)
}
pub fn data(self) -> RdData {
self.0
}
pub fn mask(self) -> Mask {
self.1
}
pub fn immediate(val: Value) -> Rd {
Rd(RdData::Immediate(val), Mask::default())
}
}
impl Debug for Rd {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Rd(")?;
let disp: DataDisp = self.0.into();
write!(f, "{}", disp)?;
if !self.mask().is_default() {
write!(f, ",{:?}", self.mask())?;
}
write!(f, ")")
}
}
/// Reference an object through a handle
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct RdObj(Register);
impl RdObj {
pub fn new(reg: Register) -> Self {
RdObj(reg)
}
pub const fn reg(self) -> Register {
self.0
}
}
impl Debug for RdObj {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Obj(")?;
write!(f, "{}", self.reg())?;
write!(f, ")")
}
}

@ -0,0 +1,39 @@
use crate::asm::data::{RdData, Mask, DataDisp, WrData, Rd};
use crate::asm::data::literal::Value;
use std::fmt::{Debug, Formatter};
use std::fmt;
/// Data destination argument (read-write)
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Wr(WrData, Mask);
impl Wr {
pub fn new(dst: WrData) -> Self {
Wr(dst, Mask::default())
}
pub fn d(self) -> WrData {
self.0
}
pub fn mask(self) -> Mask {
self.1
}
pub fn as_rd(&self) -> Rd {
Rd(self.0.into(), self.1)
}
pub fn discard() -> Wr {
Wr(WrData::Discard, Mask::default())
}
}
impl Debug for Wr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Wr(")?;
let disp: DataDisp = self.0.into();
write!(f, "{}", disp)?;
if !self.mask().is_default() {
write!(f, ",{:?}", self.mask())?;
}
write!(f, ")")
}
}

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::AtomicU32; use std::sync::atomic::AtomicU32;
use crate::asm::data::{Rd, SrcDisp}; use crate::asm::data::{Rd, RdData};
use crate::asm::data::literal::{Label, Value}; use crate::asm::data::literal::{Label, Value};
use crate::asm::error::{AsmError, Error}; use crate::asm::error::{AsmError, Error};
use crate::asm::instr::{Cond, Instr, Op, Routine}; use crate::asm::instr::{Cond, Instr, Op, Routine};
@ -83,7 +83,7 @@ fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
Op::BuiltIn(BuiltinOp::Jump(target @ Label::Numbered(_))) => { Op::BuiltIn(BuiltinOp::Jump(target @ Label::Numbered(_))) => {
if let Some(dest) = label_positions.get(&target) { if let Some(dest) = label_positions.get(&target) {
let skip = *dest as isize - n as isize + skipped; let skip = *dest as isize - n as isize + skipped;
cleaned.push(Op::BuiltIn(BuiltinOp::Skip(Rd::new(SrcDisp::Immediate(skip as Value))))); cleaned.push(Op::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))));
} else { } else {
return Err(Error::Asm(AsmError::LabelNotDefined(target))); return Err(Error::Asm(AsmError::LabelNotDefined(target)));
} }
@ -91,7 +91,7 @@ fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
Op::BuiltIn(BuiltinOp::JumpIf(cond, target @ Label::Numbered(_))) => { Op::BuiltIn(BuiltinOp::JumpIf(cond, target @ Label::Numbered(_))) => {
if let Some(dest) = label_positions.get(&target) { if let Some(dest) = label_positions.get(&target) {
let skip = *dest as isize - n as isize + skipped; let skip = *dest as isize - n as isize + skipped;
cleaned.push(Op::BuiltIn(BuiltinOp::SkipIf(cond, Rd::new(SrcDisp::Immediate(skip as Value))))); cleaned.push(Op::BuiltIn(BuiltinOp::SkipIf(cond, Rd::new(RdData::Immediate(skip as Value)))));
} else { } else {
return Err(Error::Asm(AsmError::LabelNotDefined(target))); return Err(Error::Asm(AsmError::LabelNotDefined(target)));
} }

@ -3,7 +3,7 @@ use std::fmt::Debug;
use crate::builtin::defs::BuiltinOp; use crate::builtin::defs::BuiltinOp;
use crate::module::{EvalRes, OpTrait}; use crate::module::{EvalRes, OpTrait};
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::run_thread::{state::RunState, ThreadInfo}; use crate::runtime::run_thread::{state::RunState, info::ThreadInfo};
/// A higher level simple opration /// A higher level simple opration
#[derive(Debug)] #[derive(Debug)]

@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use crate::module::AsmModule; use crate::module::CrsnExtension;
use crate::runtime::program::Program; use crate::runtime::program::Program;
pub mod data; pub mod data;
@ -10,7 +10,7 @@ pub mod parse;
pub mod patches; pub mod patches;
/// Parse a program from string and assemble a low level instruction sequence from it. /// Parse a program from string and assemble a low level instruction sequence from it.
pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Arc<Program>, error::Error> { pub fn assemble(source: &str, parsers: &'static [Box<dyn CrsnExtension>]) -> Result<Arc<Program>, error::Error> {
let ops = parse::parse(source, parsers)?; let ops = parse::parse(source, parsers)?;
trace!("--- Compiled program ---"); trace!("--- Compiled program ---");
@ -19,5 +19,5 @@ pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Arc<Prog
} }
trace!("------------------------"); trace!("------------------------");
Ok(Program::new(ops)) Ok(Program::new(ops, parsers))
} }

@ -1,6 +1,6 @@
use sexp::Sexp; use sexp::Sexp;
use crate::asm::data::{Rd, Wr}; use crate::asm::data::{Rd, Wr, RdObj, RdData, Mask};
use crate::asm::parse::parse_data::{parse_rd, parse_wr}; use crate::asm::parse::parse_data::{parse_rd, parse_wr};
use crate::asm::parse::sexp_expect::expect_string_atom; use crate::asm::parse::sexp_expect::expect_string_atom;
@ -64,6 +64,18 @@ impl ArgParser {
parse_rd(self.next()) parse_rd(self.next())
} }
/// Get the next entry as read location
pub fn next_rdobj(&mut self) -> anyhow::Result<RdObj> {
match parse_rd(self.next())? {
Rd(RdData::ObjectPtr(reg), Mask::FULL) => {
return Ok(RdObj::new(reg));
}
other => {
anyhow::bail!("Not a valid object handle syntax: {:?}", other);
}
}
}
/// Get the next entry as write location /// Get the next entry as write location
pub fn next_wr(&mut self) -> anyhow::Result<Wr> { pub fn next_wr(&mut self) -> anyhow::Result<Wr> {
parse_wr(self.next()) parse_wr(self.next())

@ -6,7 +6,7 @@ use parse_routines::parse_routines;
use crate::asm::error::Error; use crate::asm::error::Error;
use crate::asm::instr::{Flatten, Op, Routine}; use crate::asm::instr::{Flatten, Op, Routine};
use crate::asm::parse::sexp_expect::expect_list; use crate::asm::parse::sexp_expect::expect_list;
use crate::module::AsmModule; use crate::module::CrsnExtension;
mod parse_cond; mod parse_cond;
mod parse_instr; mod parse_instr;
@ -17,7 +17,7 @@ mod parse_op;
pub mod arg_parser; pub mod arg_parser;
pub fn parse(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Op>, Error> { pub fn parse(source: &str, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Op>, Error> {
let root = sexp::parse(source)?; let root = sexp::parse(source)?;
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?, parsers)?; let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?, parsers)?;

@ -5,9 +5,9 @@ use crate::asm::instr::{Cond, cond, Instr};
use crate::asm::parse::parse_instr::parse_instructions; use crate::asm::parse::parse_instr::parse_instructions;
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom}; use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
use crate::asm::patches::TryRemove; use crate::asm::patches::TryRemove;
use crate::module::AsmModule; use crate::module::CrsnExtension;
pub fn parse_cond_branch(tok: Sexp, parsers: &[Box<dyn AsmModule>]) -> Result<(Cond, Vec<Instr>), Error> { pub fn parse_cond_branch(tok: Sexp, parsers: &[Box<dyn CrsnExtension>]) -> Result<(Cond, Vec<Instr>), Error> {
let mut list = expect_list(Some(tok), false)?; let mut list = expect_list(Some(tok), false)?;
let kw = expect_string_atom(list.try_remove(0))?; let kw = expect_string_atom(list.try_remove(0))?;

@ -2,7 +2,7 @@ use std::convert::TryFrom;
use sexp::{Atom, Sexp}; use sexp::{Atom, Sexp};
use crate::asm::data::{DataDisp, DstDisp, Rd, reg, SrcDisp, Wr}; use crate::asm::data::{DataDisp, WrData, Rd, reg, RdData, Wr};
use crate::asm::data::literal::Label; use crate::asm::data::literal::Label;
use crate::asm::error::Error; use crate::asm::error::Error;
use crate::asm::parse::sexp_expect::expect_string_atom; use crate::asm::parse::sexp_expect::expect_string_atom;
@ -32,7 +32,7 @@ pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, Error> {
return Ok(DataDisp::Discard); return Ok(DataDisp::Discard);
} }
if let Some(reference) = s.strip_prefix('%') { if let Some(reference) = s.strip_prefix('@') {
Ok(DataDisp::ObjectPtr(reg::parse_reg(reference)?)) Ok(DataDisp::ObjectPtr(reg::parse_reg(reference)?))
} else if s.starts_with(|c: char| c.is_ascii_digit()) { } else if s.starts_with(|c: char| c.is_ascii_digit()) {
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(s)?) })) Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(s)?) }))
@ -65,9 +65,9 @@ pub fn parse_i64(literal: &str) -> anyhow::Result<i64> {
} }
pub fn parse_rd(tok: Option<Sexp>) -> anyhow::Result<Rd> { pub fn parse_rd(tok: Option<Sexp>) -> anyhow::Result<Rd> {
Ok(Rd::new(SrcDisp::try_from(parse_data_disp(tok)?)?)) Ok(Rd::new(RdData::try_from(parse_data_disp(tok)?)?))
} }
pub fn parse_wr(tok: Option<Sexp>) -> anyhow::Result<Wr> { pub fn parse_wr(tok: Option<Sexp>) -> anyhow::Result<Wr> {
Ok(Wr::new(DstDisp::try_from(parse_data_disp(tok)?)?)) Ok(Wr::new(WrData::try_from(parse_data_disp(tok)?)?))
} }

@ -6,11 +6,11 @@ use crate::asm::parse::arg_parser::ArgParser;
use crate::asm::parse::parse_cond::parse_cond_branch; use crate::asm::parse::parse_cond::parse_cond_branch;
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom}; use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
use crate::asm::patches::SexpIsA; use crate::asm::patches::SexpIsA;
use crate::module::AsmModule; use crate::module::CrsnExtension;
use super::parse_op::parse_op; use super::parse_op::parse_op;
pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Instr>, Error> { pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Instr>, Error> {
let mut parsed = vec![]; let mut parsed = vec![];
for expr in instrs { for expr in instrs {
let tokens = expect_list(Some(expr), false)?; let tokens = expect_list(Some(expr), false)?;

@ -1,12 +1,12 @@
use crate::asm::error::Error; use crate::asm::error::Error;
use crate::asm::instr::Op; use crate::asm::instr::Op;
use crate::asm::parse::arg_parser::ArgParser; use crate::asm::parse::arg_parser::ArgParser;
use crate::builtin::parse::BuiltinOpParser; use crate::builtin::parse::BuiltinOps;
use crate::module::{AsmModule, ParseOpRes}; use crate::module::{CrsnExtension, ParseOpRes};
pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box<dyn AsmModule>]) -> Result<Op, Error> { pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box<dyn CrsnExtension>]) -> Result<Op, Error> {
// Include built-in instructions // Include built-in instructions
let builtins = [BuiltinOpParser::new()]; let builtins = [BuiltinOps::new()];
for p in builtins.iter().chain(parsers) { for p in builtins.iter().chain(parsers) {
arg_tokens = match p.parse_op(keyword, arg_tokens) { arg_tokens = match p.parse_op(keyword, arg_tokens) {

@ -6,9 +6,9 @@ use crate::asm::instr::Routine;
use crate::asm::parse::parse_instr::parse_instructions; use crate::asm::parse::parse_instr::parse_instructions;
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom}; use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
use crate::asm::patches::TryRemove; use crate::asm::patches::TryRemove;
use crate::module::AsmModule; use crate::module::CrsnExtension;
pub fn parse_routines(routines: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Routine>, Error> { pub fn parse_routines(routines: Vec<Sexp>, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Routine>, Error> {
let mut parsed = vec![]; let mut parsed = vec![];
for rt in routines { for rt in routines {
let mut def = expect_list(Some(rt), false)?; let mut def = expect_list(Some(rt), false)?;

@ -1,4 +1,4 @@
use crate::asm::data::{Rd, Wr}; use crate::asm::data::{Rd, Wr, RdObj};
use crate::asm::data::literal::{DebugMsg, Label, RoutineName}; use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
use crate::asm::instr::{Cond, Op}; use crate::asm::instr::{Cond, Op};
@ -37,6 +37,9 @@ pub enum BuiltinOp {
Barrier(Option<DebugMsg>), Barrier(Option<DebugMsg>),
/// Generate a run-time fault with a debugger message /// Generate a run-time fault with a debugger message
Fault(Option<DebugMsg>), Fault(Option<DebugMsg>),
/// Deallocate an object.
/// The object is released and the handle becomes invalid.
Drop(RdObj),
/// Copy value /// Copy value
Move { dst: Wr, src: Rd }, Move { dst: Wr, src: Rd },
/// Store runtime status to a register /// Store runtime status to a register

@ -4,6 +4,8 @@ use crate::module::{EvalRes, OpTrait};
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::frame::StackFrame; use crate::runtime::frame::StackFrame;
use crate::runtime::run_thread::{state::RunState, ThreadInfo}; use crate::runtime::run_thread::{state::RunState, ThreadInfo};
use crate::asm::data::{Rd, RdData};
use crate::asm::instr::Cond;
impl OpTrait for BuiltinOp { impl OpTrait for BuiltinOp {
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
@ -135,6 +137,21 @@ impl OpTrait for BuiltinOp {
let x = state.read(*src)?; let x = state.read(*src)?;
state.frame.status.load(x); state.frame.status.load(x);
} }
BuiltinOp::Drop(obj) => {
let x = state.read(Rd::new(RdData::Register(obj.reg())))?;
trace!("Drop object: {:#x}", x);
let mut dropped = false;
for ex in info.program.extensions {
if ex.drop_obj(info, state, x)?.is_some() {
dropped = true;
}
}
if !dropped {
warn!("Object {:#x} to drop does not exist!", x);
state.set_flag(Cond::Invalid, true);
}
}
} }
Ok(res) Ok(res)

@ -8,22 +8,23 @@ use crate::asm::parse::arg_parser::ArgParser;
use crate::asm::parse::parse_data::{parse_label, parse_rd}; use crate::asm::parse::parse_data::{parse_label, parse_rd};
use crate::asm::parse::sexp_expect::expect_string_atom; use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::builtin::defs::BuiltinOp; use crate::builtin::defs::BuiltinOp;
use crate::module::{AsmModule, ParseOpRes}; use crate::module::{CrsnExtension, ParseOpRes};
use crate::asm::data::RdObj;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BuiltinOpParser { pub struct BuiltinOps {
_internal: () _internal: ()
} }
impl BuiltinOpParser { impl BuiltinOps {
pub fn new() -> Box<dyn AsmModule> { pub fn new() -> Box<dyn CrsnExtension> {
Box::new(Self { Box::new(Self {
_internal: () _internal: ()
}) })
} }
} }
impl AsmModule for BuiltinOpParser { impl CrsnExtension for BuiltinOps {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"builtin" "builtin"
} }
@ -126,6 +127,10 @@ impl AsmModule for BuiltinOpParser {
} }
} }
"drop" => {
BuiltinOp::Drop(args.next_rdobj()?)
}
"far" => { "far" => {
if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() { if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() {
if let Some(label) = label.strip_prefix(':') { if let Some(label) = label.strip_prefix(':') {

@ -8,6 +8,8 @@ use crate::asm::parse::arg_parser::ArgParser;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::run_thread::state::RunState; use crate::runtime::run_thread::state::RunState;
use crate::runtime::run_thread::ThreadInfo; use crate::runtime::run_thread::ThreadInfo;
use crate::asm::data::literal::Value;
use crate::asm::data::Mask;
mod eval_res; mod eval_res;
@ -23,7 +25,7 @@ pub trait OpTrait: Debug + Send + Sync + 'static {
fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault>; fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault>;
} }
pub trait AsmModule: Debug + Send + 'static { pub trait CrsnExtension: Debug + Send + Sync + 'static {
/// Get name of the module /// Get name of the module
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
@ -33,4 +35,36 @@ pub trait AsmModule: Debug + Send + 'static {
/// ///
/// If the instruction keyword is not recognized, return Unknown with the unchanged argument list. /// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpRes, Error>; fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpRes, Error>;
/// Drop an object referenced by a handle
fn drop_obj(&self,
#[allow(unused)] ti: &ThreadInfo,
#[allow(unused)] state: &mut RunState,
#[allow(unused)] handle : Value) -> Result<Option<()>, Fault>
{
// Default impl - we do not support dropping this object
Ok(None)
}
/// Run-time method called to read an object (using the object handle syntax)
fn read_obj(&self,
#[allow(unused)] ti: &ThreadInfo,
#[allow(unused)] state: &mut RunState,
#[allow(unused)] handle : Value,
#[allow(unused)] mask : Mask
) -> Result<Option<Value>, Fault> {
// Default impl - we do not support reading this object
Ok(None)
}
/// Run-time method called to write an object (using the object handle syntax)
fn write_obj(&self,
#[allow(unused)] ti: &ThreadInfo,
#[allow(unused)] state: &mut RunState,
#[allow(unused)] handle : Value,
#[allow(unused)] mask : Mask
) -> Result<Option<()>, Fault> {
// Default impl - we do not support writing this object
Ok(None)
}
} }

@ -1,6 +1,6 @@
use thiserror::Error; use thiserror::Error;
use crate::asm::data::literal::{DebugMsg, Label, RoutineName}; use crate::asm::data::literal::{DebugMsg, Label, RoutineName, Value};
use crate::asm::data::Register; use crate::asm::data::Register;
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -24,6 +24,9 @@ pub enum Fault {
#[error("Program ended.")] #[error("Program ended.")]
Halt, Halt,
#[error("Object does not exist: {0:#x}")]
ObjectNotExist(Value),
// #[error("Memory region {area:?} is locked by thread {owner:?}")] // #[error("Memory region {area:?} is locked by thread {owner:?}")]
// MemoryLocked { // MemoryLocked {
// area: MemorySpan, // area: MemorySpan,

@ -5,19 +5,22 @@ use crate::asm::data::literal::{Addr, Label, RoutineName};
use crate::asm::instr::Op; use crate::asm::instr::Op;
use crate::builtin::defs::BuiltinOp; use crate::builtin::defs::BuiltinOp;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::module::CrsnExtension;
#[derive(Debug)] #[derive(Debug)]
pub struct Program { pub struct Program {
pub ops: Vec<Op>, pub ops: Vec<Op>,
pub extensions: &'static [Box<dyn CrsnExtension>],
routines: HashMap<RoutineName, Addr>, routines: HashMap<RoutineName, Addr>,
far_labels: HashMap<Label, Addr>, far_labels: HashMap<Label, Addr>,
barriers: Vec<Addr>, barriers: Vec<Addr>,
} }
impl Program { impl Program {
pub fn new(ops: Vec<Op>) -> Arc<Self> { pub fn new(ops: Vec<Op>, extensions: &'static [Box<dyn CrsnExtension>]) -> Arc<Self> {
let mut p = Self { let mut p = Self {
ops, ops,
extensions,
routines: Default::default(), routines: Default::default(),
far_labels: Default::default(), far_labels: Default::default(),
barriers: Default::default(), barriers: Default::default(),

@ -1,13 +1,14 @@
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::thread::JoinHandle; use std::thread::JoinHandle;
use std::time::Duration; use std::time::Duration;
use crate::asm::data::literal::Addr; use crate::asm::data::literal::{Addr, Value};
use crate::module::EvalRes; use crate::module::EvalRes;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::frame::StackFrame; use crate::runtime::frame::StackFrame;
use crate::runtime::program::Program; use crate::runtime::program::Program;
use crate::runtime::run_thread::state::RunState; use crate::runtime::run_thread::info::{UNIQ_BASE};
#[derive(Clone, Copy, Eq, PartialEq, Debug, Ord, PartialOrd)] #[derive(Clone, Copy, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub struct ThreadToken(pub u32); pub struct ThreadToken(pub u32);
@ -17,22 +18,29 @@ pub struct RunThread {
pub(crate) state: RunState, pub(crate) state: RunState,
} }
pub struct ThreadInfo { pub mod info;
/// Thread ID
pub id: ThreadToken,
/// Program to run
pub program: Arc<Program>,
/// Program to run
pub cycle_time: Duration,
}
pub mod state; pub mod state;
pub use info::ThreadInfo;
pub use state::RunState;
pub fn new_uniq() -> &'static AtomicU64 {
let uniq = AtomicU64::new(info::UNIQ_BASE);
Box::leak(Box::new(uniq))
}
impl RunThread { impl RunThread {
pub fn new(id: ThreadToken, program: Arc<Program>, pc: Addr, args: &[u64]) -> Self { pub fn new(id: ThreadToken, uniq: Option<&'static AtomicU64>, program: Arc<Program>, pc: Addr, args: &[u64]) -> Self {
let uniq = if let Some(u) = uniq {
u
} else {
let u = AtomicU64::new(UNIQ_BASE);
Box::leak(Box::new(u)) as &AtomicU64
};
Self { Self {
info: ThreadInfo { info: ThreadInfo {
id, id,
uniq,
program, program,
cycle_time: Duration::default(), cycle_time: Duration::default(),
}, },

@ -0,0 +1,25 @@
use crate::runtime::run_thread::ThreadToken;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use crate::runtime::program::Program;
use std::time::Duration;
use crate::asm::data::literal::Value;
pub struct ThreadInfo {
/// Thread ID
pub id: ThreadToken,
/// Thread ID
pub(crate) uniq: &'static AtomicU64,
/// Program to run
pub program: Arc<Program>,
/// Program to run
pub(crate) cycle_time: Duration,
}
pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000;
impl ThreadInfo {
pub fn uniq(&self) -> Value {
self.uniq.fetch_add(1, Ordering::Relaxed)
}
}

@ -1,7 +1,7 @@
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::collections::HashMap; use std::collections::HashMap;
use crate::asm::data::{DstDisp, Rd, Register, SrcDisp, Wr}; use crate::asm::data::{WrData, Rd, Register, RdData, Wr, RdObj};
use crate::asm::data::literal::{Addr, Value}; use crate::asm::data::literal::{Addr, Value};
use crate::asm::instr::Cond; use crate::asm::instr::Cond;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
@ -61,11 +61,16 @@ impl RunState {
self.frame.status.update(val); self.frame.status.update(val);
} }
/// Read object handle value
pub fn read_obj(&mut self, rdo: RdObj) -> Result<Value, Fault> {
self.read(Rd::new(RdData::Register(rdo.reg())))
}
/// Read a `Rd` value /// Read a `Rd` value
pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> { pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> {
match rd.d() { match rd.data() {
SrcDisp::Immediate(v) => Ok(v), RdData::Immediate(v) => Ok(v),
SrcDisp::Register(Register::Res(rn)) => { RdData::Register(Register::Res(rn)) => {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490 Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
} else { } else {
@ -73,7 +78,7 @@ impl RunState {
Ok(self.frame.res[rn as usize]) Ok(self.frame.res[rn as usize])
} }
} }
SrcDisp::Register(Register::Arg(rn)) => { RdData::Register(Register::Arg(rn)) => {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) }) Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
} else { } else {
@ -81,7 +86,7 @@ impl RunState {
Ok(self.frame.arg[rn as usize]) Ok(self.frame.arg[rn as usize])
} }
} }
SrcDisp::Register(Register::Gen(rn)) => { RdData::Register(Register::Gen(rn)) => {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
} else { } else {
@ -89,7 +94,7 @@ impl RunState {
Ok(self.frame.gen[rn as usize]) Ok(self.frame.gen[rn as usize])
} }
} }
SrcDisp::ObjectPtr(_) => { RdData::ObjectPtr(_) => {
unimplemented!("Read object ptr") unimplemented!("Read object ptr")
} }
} }
@ -100,25 +105,25 @@ impl RunState {
trace!("WR {:?} := {}", wr, val); trace!("WR {:?} := {}", wr, val);
match wr.d() { match wr.d() {
DstDisp::Discard => { WrData::Discard => {
/* Discard */ /* Discard */
Ok(()) Ok(())
} }
DstDisp::Register(Register::Res(rn)) => { WrData::Register(Register::Res(rn)) => {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490 Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
} else { } else {
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) }) Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
} }
} }
DstDisp::Register(Register::Arg(rn)) => { WrData::Register(Register::Arg(rn)) => {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) }) Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
} else { } else {
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) }) Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
} }
} }
DstDisp::Register(Register::Gen(rn)) => { WrData::Register(Register::Gen(rn)) => {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
} else { } else {
@ -126,7 +131,7 @@ impl RunState {
Ok(()) Ok(())
} }
} }
DstDisp::ObjectPtr(_) => { WrData::ObjectPtr(_) => {
unimplemented!("Write object ptr") unimplemented!("Write object ptr")
} }
} }

@ -2,7 +2,7 @@ use crsn::asm::data::{Rd, Wr};
use crsn::asm::error::Error; use crsn::asm::error::Error;
use crsn::asm::instr::Op; use crsn::asm::instr::Op;
use crsn::asm::parse::arg_parser::ArgParser; use crsn::asm::parse::arg_parser::ArgParser;
use crsn::module::{AsmModule, ParseOpRes}; use crsn::module::{CrsnExtension, ParseOpRes};
use crate::defs::ArithOp; use crate::defs::ArithOp;
@ -12,14 +12,14 @@ pub struct ArithOps {
} }
impl ArithOps { impl ArithOps {
pub fn new() -> Box<dyn AsmModule> { pub fn new() -> Box<dyn CrsnExtension> {
Box::new(Self { Box::new(Self {
_internal: () _internal: ()
}) })
} }
} }
impl AsmModule for ArithOps { impl CrsnExtension for ArithOps {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"arith" "arith"
} }

@ -1,7 +1,8 @@
use crsn::asm::data::{Rd, Wr}; use crsn::asm::data::{Rd, Wr, RdObj};
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum StackOp { pub enum StackOp {
Push { num: Rd, src: Rd }, NewStack { dst: Wr },
Pop { dst: Wr, num: Rd }, Push { obj: RdObj, src: Rd },
Pop { dst: Wr, obj: RdObj },
} }

@ -1,52 +1,51 @@
use std::collections::VecDeque; use std::collections::{VecDeque, HashMap};
use crsn::asm::data::literal::Value; use crsn::asm::data::literal::Value;
use crsn::asm::instr::Cond; use crsn::asm::instr::Cond;
use crsn::module::{EvalRes, OpTrait}; use crsn::module::{EvalRes, OpTrait, CrsnExtension};
use crsn::runtime::fault::Fault; use crsn::runtime::fault::Fault;
use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
use crate::defs::StackOp; use crate::defs::StackOp;
use crate::StackOps;
#[derive(Debug, Default)]
struct Stacks { struct Stacks {
stacks: Vec<VecDeque<Value>>, store: HashMap<Value, VecDeque<Value>>,
}
impl Default for Stacks {
fn default() -> Self {
Stacks {
stacks: vec![VecDeque::default(); 8],
}
}
} }
impl OpTrait for StackOp { impl OpTrait for StackOp {
fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
let eres = EvalRes::default(); let eres = EvalRes::default();
match self { match self {
StackOp::Push { num, src } => { StackOp::NewStack { dst } => {
let id = info.uniq();
let stacks: &mut Stacks = state.ext_mut();
stacks.store.insert(id, VecDeque::new());
state.write(*dst, id)?;
}
StackOp::Push { obj, src } => {
state.clear_status(); state.clear_status();
let stack_num = state.read(*num)?; let handle = state.read_obj(*obj)?;
let val = state.read(*src)?; let val = state.read(*src)?;
if stack_num > 8 { let stacks: &mut Stacks = state.ext_mut();
state.set_flag(Cond::Invalid, true); stacks.store.get_mut(&handle)
} else { .ok_or_else(|| Fault::ObjectNotExist(handle))?
let obj: &mut Stacks = state.ext_mut(); .push_back(val);
obj.stacks[stack_num as usize].push_back(val);
} }
} StackOp::Pop { dst, obj } => {
StackOp::Pop { dst, num } => {
state.clear_status(); state.clear_status();
let stack_num = state.read(*num)?; let handle = state.read_obj(*obj)?;
let stacks: &mut Stacks = state.ext_mut();
let stack = stacks.store.get_mut(&handle)
.ok_or_else(|| Fault::ObjectNotExist(handle))?;
if stack_num > 8 { let val = stack.pop_back();
state.set_flag(Cond::Invalid, true);
} else {
let obj: &mut Stacks = state.ext_mut();
let val = obj.stacks[stack_num as usize].pop_back();
if obj.stacks[stack_num as usize].is_empty() { if stack.is_empty() {
state.set_flag(Cond::Zero, true); state.set_flag(Cond::Zero, true);
} }
@ -62,12 +61,14 @@ impl OpTrait for StackOp {
state.write(*dst, val)?; state.write(*dst, val)?;
} }
// TODO
}
} }
Ok(eres) Ok(eres)
} }
// //
} }
pub(crate) fn drop_stack(state: &mut RunState, handle : Value) -> Result<Option<()>, Fault> {
let stacks: &mut Stacks = state.ext_mut();
Ok(stacks.store.remove(&handle).map(|_| ()))
}

@ -1,9 +1,12 @@
use crsn::asm::error::Error; use crsn::asm::error::Error;
use crsn::asm::instr::Op; use crsn::asm::instr::Op;
use crsn::asm::parse::arg_parser::ArgParser; use crsn::asm::parse::arg_parser::ArgParser;
use crsn::module::{AsmModule, ParseOpRes}; use crsn::module::{CrsnExtension, ParseOpRes};
use crate::defs::StackOp; use crate::defs::StackOp;
use crsn::runtime::run_thread::{ThreadInfo, RunState};
use crsn::asm::data::literal::Value;
use crsn::runtime::fault::Fault;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StackOps { pub struct StackOps {
@ -11,23 +14,29 @@ pub struct StackOps {
} }
impl StackOps { impl StackOps {
pub fn new() -> Box<dyn AsmModule> { pub fn new() -> Box<dyn CrsnExtension> {
Box::new(Self { Box::new(Self {
_internal: () _internal: ()
}) })
} }
} }
impl AsmModule for StackOps { impl CrsnExtension for StackOps {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"stacks" "stacks"
} }
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes, Error> { fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes, Error> {
Ok(ParseOpRes::Parsed(Op::Ext(Box::new(match keyword { Ok(ParseOpRes::Parsed(Op::Ext(Box::new(match keyword {
"stack" => {
StackOp::NewStack {
dst: args.next_wr()?,
}
}
"push" => { "push" => {
StackOp::Push { StackOp::Push {
num: args.next_rd()?, obj: args.next_rdobj()?,
src: args.next_rd()?, src: args.next_rd()?,
} }
} }
@ -35,7 +44,7 @@ impl AsmModule for StackOps {
"pop" => { "pop" => {
StackOp::Pop { StackOp::Pop {
dst: args.next_wr()?, dst: args.next_wr()?,
num: args.next_rd()?, obj: args.next_rdobj()?,
} }
} }
@ -44,4 +53,9 @@ impl AsmModule for StackOps {
} }
})))) }))))
} }
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle : Value) -> Result<Option<()>, Fault>
{
crate::exec::drop_stack(state, handle)
}
} }

@ -9,6 +9,8 @@ use crsn::asm::data::literal::Addr;
use crsn::runtime::run_thread::{RunThread, ThreadToken}; use crsn::runtime::run_thread::{RunThread, ThreadToken};
use crsn_arith::ArithOps; use crsn_arith::ArithOps;
use crsn_stacks::StackOps; use crsn_stacks::StackOps;
use std::sync::atomic::AtomicU64;
use crsn::runtime::run_thread;
fn main() { fn main() {
SimpleLogger::new().init().unwrap(); SimpleLogger::new().init().unwrap();
@ -70,34 +72,38 @@ fn main() {
let program = " let program = "
( (
(main (main
(push 0 10) (stack r7)
(push 0 20) (push @r7 10)
(call emptystack 0) (push @r7 20)
(push 0 30) (call emptystack r7)
(pop r0 0) (push @r7 30)
(pop r0 0) (pop r0 @r7)
(pop r0 0) (pop r0 @r7)
(drop @r7)
(pop r0 @r7) ; this fails
(halt) (halt)
) )
(emptystack (emptystack
(:again) (:again)
(pop _ arg0 (nz? (j :again))) (pop _ @arg0 (nz? (j :again)))
(ret) (ret)
) )
) )
"; ";
let parsers = vec![ let parsers = Box::leak(Box::new(vec![
ArithOps::new(), ArithOps::new(),
StackOps::new(), StackOps::new(),
]; ]));
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap(); let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap();
let mut thread1 = RunThread::new(ThreadToken(0), parsed.clone(), Addr(0), &[]); let uniq = run_thread::new_uniq();
thread1.set_speed(Duration::from_millis(250));
let _thread2 = RunThread::new(ThreadToken(1), parsed.clone(), Addr(0), &[]); let mut thread1 = RunThread::new(ThreadToken(0), Some(uniq), parsed.clone(), Addr(0), &[]);
//thread1.set_speed(Duration::from_millis(250));
let _thread2 = RunThread::new(ThreadToken(1), Some(uniq), parsed.clone(), Addr(0), &[]);
let a = thread1.start(); let a = thread1.start();
//let b = thread2.start(); //let b = thread2.start();

Loading…
Cancel
Save