add more sensible API for object handles, add drop instruction
This commit is contained in:
+33
-92
@@ -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)]
|
||||||
|
|||||||
+3
-3
@@ -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(':') {
|
||||||
|
|||||||
+35
-1
@@ -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 mod state;
|
||||||
pub id: ThreadToken,
|
pub use info::ThreadInfo;
|
||||||
/// Program to run
|
pub use state::RunState;
|
||||||
pub program: Arc<Program>,
|
|
||||||
/// Program to run
|
pub fn new_uniq() -> &'static AtomicU64 {
|
||||||
pub cycle_time: Duration,
|
let uniq = AtomicU64::new(info::UNIQ_BASE);
|
||||||
|
Box::leak(Box::new(uniq))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod state;
|
|
||||||
|
|
||||||
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 },
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-31
@@ -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)?;
|
||||||
|
|
||||||
if stack_num > 8 {
|
let stacks: &mut Stacks = state.ext_mut();
|
||||||
state.set_flag(Cond::Invalid, true);
|
let stack = stacks.store.get_mut(&handle)
|
||||||
} else {
|
.ok_or_else(|| Fault::ObjectNotExist(handle))?;
|
||||||
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() {
|
let val = stack.pop_back();
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-13
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user