forked from MightyPork/crsn
Example extension: Stacks; fixes to allow module data storage in thread context
This commit is contained in:
Generated
+8
@@ -71,6 +71,13 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crsn_stacks"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crsn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clonable"
|
name = "dyn-clonable"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -114,6 +121,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"crsn",
|
"crsn",
|
||||||
"crsn_arith",
|
"crsn_arith",
|
||||||
|
"crsn_stacks",
|
||||||
"log",
|
"log",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ members = [
|
|||||||
"launcher",
|
"launcher",
|
||||||
"crsn",
|
"crsn",
|
||||||
"crsn_arith",
|
"crsn_arith",
|
||||||
|
"crsn_stacks",
|
||||||
]
|
]
|
||||||
|
|||||||
+10
-14
@@ -1,19 +1,15 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::asm::data::{
|
|
||||||
literal::DebugMsg, literal::Label,
|
|
||||||
literal::RoutineName,
|
|
||||||
Rd,
|
|
||||||
Wr,
|
|
||||||
};
|
|
||||||
use crate::asm::data::literal::Addr;
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::asm::instr::Cond;
|
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
use crate::builtin::defs::BuiltinOp;
|
use crate::builtin::defs::BuiltinOp;
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::runtime::frame::{CallStack, StackFrame};
|
|
||||||
use crate::runtime::program::Program;
|
|
||||||
|
use crate::runtime::run_thread::{RunState, ThreadInfo};
|
||||||
|
|
||||||
/// A higher level simple opration
|
/// A higher level simple opration
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -24,7 +20,7 @@ pub enum Op {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait OpTrait: Debug + Send + Sync + 'static {
|
pub trait OpTrait: Debug + Send + Sync + 'static {
|
||||||
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault>;
|
fn execute(&self, ti : &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ParseOpResult {
|
pub enum ParseOpResult {
|
||||||
@@ -64,13 +60,13 @@ impl Default for EvalRes {
|
|||||||
|
|
||||||
|
|
||||||
impl OpTrait for Op {
|
impl OpTrait for Op {
|
||||||
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
|
fn execute(&self, ti : &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||||
match self {
|
match self {
|
||||||
Op::BuiltIn(op) => {
|
Op::BuiltIn(op) => {
|
||||||
op.execute(&program, call_stack, frame)
|
op.execute(ti, state)
|
||||||
}
|
}
|
||||||
Op::Ext(op) => {
|
Op::Ext(op) => {
|
||||||
op.execute(&program, call_stack, frame)
|
op.execute(ti, state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::asm::instr::Op;
|
|
||||||
use crate::asm::instr::op::AsmModule;
|
use crate::asm::instr::op::AsmModule;
|
||||||
use crate::runtime::program::Program;
|
use crate::runtime::program::Program;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::asm::data::literal::{Label, RoutineName};
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
use crate::asm::instr::cond::parse_cond;
|
|
||||||
use crate::asm::instr::op::{AsmModule, ParseOpResult};
|
use crate::asm::instr::op::{AsmModule, ParseOpResult};
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
use crate::asm::parse::parse_data::{parse_label, parse_rd};
|
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
|
||||||
use crate::builtin::parse::BuiltinOpParser;
|
use crate::builtin::parse::BuiltinOpParser;
|
||||||
|
|
||||||
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 AsmModule>]) -> Result<Op, Error> {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use crate::asm::data::{Rd, Wr};
|
|||||||
pub enum BuiltinOp {
|
pub enum BuiltinOp {
|
||||||
/// Do nothing
|
/// Do nothing
|
||||||
Nop,
|
Nop,
|
||||||
|
/// Stop execution
|
||||||
|
Halt,
|
||||||
/// Mark a jump target.
|
/// Mark a jump target.
|
||||||
Label(Label),
|
Label(Label),
|
||||||
/// Jump to a label
|
/// Jump to a label
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
use std::ops::Rem;
|
|
||||||
|
|
||||||
use num_traits::PrimInt;
|
|
||||||
|
|
||||||
|
|
||||||
use crate::asm::instr::op::{OpTrait, EvalRes};
|
use crate::asm::instr::op::{OpTrait, EvalRes};
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::runtime::frame::{CallStack, StackFrame};
|
use crate::runtime::frame::{StackFrame};
|
||||||
use crate::runtime::program::Program;
|
|
||||||
use crate::builtin::defs::BuiltinOp;
|
use crate::builtin::defs::BuiltinOp;
|
||||||
use crate::asm::data::literal::Addr;
|
use crate::asm::data::literal::Addr;
|
||||||
|
use crate::runtime::run_thread::{ThreadInfo, RunState};
|
||||||
|
|
||||||
impl OpTrait for BuiltinOp {
|
impl OpTrait for BuiltinOp {
|
||||||
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
|
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||||
|
let frame = &mut state.frame;
|
||||||
|
let program = &info.program;
|
||||||
let mut res = EvalRes::default();
|
let mut res = EvalRes::default();
|
||||||
match self {
|
match self {
|
||||||
BuiltinOp::Nop => {}
|
BuiltinOp::Nop => {}
|
||||||
|
BuiltinOp::Halt => {
|
||||||
|
trace!("HALT - stop execution");
|
||||||
|
return Err(Fault::Halt);
|
||||||
|
}
|
||||||
BuiltinOp::Label(_) | BuiltinOp::FarLabel(_) | BuiltinOp::Routine(_) => {
|
BuiltinOp::Label(_) | BuiltinOp::FarLabel(_) | BuiltinOp::Routine(_) => {
|
||||||
/* this is nop, but without any cost - just markers */
|
/* this is nop, but without any cost - just markers */
|
||||||
res.cycles = 0;
|
res.cycles = 0;
|
||||||
@@ -82,7 +89,7 @@ impl OpTrait for BuiltinOp {
|
|||||||
|
|
||||||
let mut frame2 = StackFrame::new(pos, &values);
|
let mut frame2 = StackFrame::new(pos, &values);
|
||||||
std::mem::swap(frame, &mut frame2);
|
std::mem::swap(frame, &mut frame2);
|
||||||
call_stack.push(frame2);
|
state.call_stack.push(frame2);
|
||||||
res.advance = 0;
|
res.advance = 0;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -91,7 +98,7 @@ impl OpTrait for BuiltinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BuiltinOp::Ret(retvals) => {
|
BuiltinOp::Ret(retvals) => {
|
||||||
match call_stack.pop() {
|
match state.call_stack.pop() {
|
||||||
Some(previous) => {
|
Some(previous) => {
|
||||||
let mut values = Vec::with_capacity(retvals.len());
|
let mut values = Vec::with_capacity(retvals.len());
|
||||||
for arg in retvals {
|
for arg in retvals {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::asm::data::{Rd, Wr};
|
|
||||||
use crate::asm::error::{Error};
|
use crate::asm::error::{Error};
|
||||||
use crate::asm::instr::op::{AsmModule, ParseOpResult};
|
use crate::asm::instr::op::{AsmModule, ParseOpResult};
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
@@ -30,6 +30,14 @@ impl AsmModule for BuiltinOpParser {
|
|||||||
|
|
||||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> {
|
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> {
|
||||||
Ok(ParseOpResult::Parsed(Op::BuiltIn(match keyword {
|
Ok(ParseOpResult::Parsed(Op::BuiltIn(match keyword {
|
||||||
|
"nop" => {
|
||||||
|
BuiltinOp::Nop
|
||||||
|
}
|
||||||
|
|
||||||
|
"halt" => {
|
||||||
|
BuiltinOp::Halt
|
||||||
|
}
|
||||||
|
|
||||||
"j" => {
|
"j" => {
|
||||||
let dest = parse_label(args.next())?;
|
let dest = parse_label(args.next())?;
|
||||||
BuiltinOp::Jump(dest)
|
BuiltinOp::Jump(dest)
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
use crate::asm::data::literal::Addr;
|
|
||||||
use crate::asm::instr::Op;
|
|
||||||
use crate::asm::instr::op::{EvalRes, OpTrait};
|
use crate::asm::instr::op::{EvalRes, OpTrait};
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::runtime::frame::StackFrame;
|
|
||||||
use crate::runtime::run_thread::RunThread;
|
use crate::runtime::run_thread::RunThread;
|
||||||
|
|
||||||
impl RunThread {
|
impl RunThread {
|
||||||
// TODO unit tests
|
// TODO unit tests
|
||||||
pub fn eval_op(&mut self) -> Result<EvalRes, Fault> {
|
pub fn eval_op(&mut self) -> Result<EvalRes, Fault> {
|
||||||
let frame = &mut self.frame;
|
|
||||||
|
|
||||||
let op = self.program.read(frame.pc);
|
let state = &mut self.state;
|
||||||
|
let info = &self.info;
|
||||||
|
|
||||||
trace!("### {:04} : {:?}", frame.pc.0, op);
|
let op = info.program.read(state.frame.pc);
|
||||||
|
|
||||||
|
trace!("### {:04} : {:?}", state.frame.pc.0, op);
|
||||||
|
|
||||||
/* Operations can be given different execution times when run in slow mode. */
|
/* Operations can be given different execution times when run in slow mode. */
|
||||||
/* Presently, all that do anything use 1 cycle. */
|
/* Presently, all that do anything use 1 cycle. */
|
||||||
|
|
||||||
let rv = op.execute(&self.program, &mut self.call_stack, frame);
|
let rv = op.execute(info, state);
|
||||||
trace!("-> {:?}", rv);
|
trace!("-> {:?}", rv);
|
||||||
rv
|
rv
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ pub enum Fault {
|
|||||||
msg: DebugMsg,
|
msg: DebugMsg,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("Program ended.")]
|
||||||
|
Halt,
|
||||||
|
|
||||||
// #[error("Memory region {area:?} is locked by thread {owner:?}")]
|
// #[error("Memory region {area:?} is locked by thread {owner:?}")]
|
||||||
// MemoryLocked {
|
// MemoryLocked {
|
||||||
// area: MemorySpan,
|
// area: MemorySpan,
|
||||||
|
|||||||
@@ -8,36 +8,58 @@ use crate::asm::data::literal::Addr;
|
|||||||
use crate::asm::instr::op::EvalRes;
|
use crate::asm::instr::op::EvalRes;
|
||||||
use crate::runtime::frame::{CallStack, StackFrame};
|
use crate::runtime::frame::{CallStack, StackFrame};
|
||||||
use crate::runtime::program::Program;
|
use crate::runtime::program::Program;
|
||||||
|
use crate::runtime::fault::Fault;
|
||||||
const CYCLE_TIME: Duration = Duration::from_millis(0);
|
|
||||||
//const CYCLE_TIME : Duration = Duration::from_millis(100);
|
|
||||||
|
|
||||||
#[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);
|
||||||
|
|
||||||
pub struct RunThread {
|
pub struct RunThread {
|
||||||
|
pub(crate) info: ThreadInfo,
|
||||||
|
pub(crate) state: RunState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ThreadInfo {
|
||||||
/// Thread ID
|
/// Thread ID
|
||||||
pub id: ThreadToken,
|
pub id: ThreadToken,
|
||||||
|
/// Program to run
|
||||||
|
pub program: Arc<Program>,
|
||||||
|
/// Program to run
|
||||||
|
pub cycle_time: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RunState {
|
||||||
/// Active stack frame
|
/// Active stack frame
|
||||||
pub frame: StackFrame,
|
pub frame: StackFrame,
|
||||||
/// Call stack
|
/// Call stack
|
||||||
pub call_stack: CallStack,
|
pub call_stack: CallStack,
|
||||||
/// Program to run
|
|
||||||
pub program: Arc<Program>,
|
|
||||||
/// Extension data
|
/// Extension data
|
||||||
ext_data: HashMap<TypeId, Box<dyn Any + Send>>,
|
ext_data: HashMap<TypeId, Box<dyn Any + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RunState {
|
||||||
|
pub fn ext_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
|
||||||
|
if !self.ext_data.contains_key(&TypeId::of::<T>()) {
|
||||||
|
self.ext_data.insert(TypeId::of::<T>(), Box::new(T::default()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ext_data.get_mut(&TypeId::of::<T>()).unwrap()
|
||||||
|
.downcast_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RunThread {
|
impl RunThread {
|
||||||
pub fn new(id: ThreadToken, program: Arc<Program>, pc: Addr, args: &[u64]) -> Self {
|
pub fn new(id: ThreadToken, program: Arc<Program>, pc: Addr, args: &[u64]) -> Self {
|
||||||
let sf = StackFrame::new(pc, args);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
info: ThreadInfo {
|
||||||
id,
|
id,
|
||||||
frame: sf,
|
|
||||||
call_stack: vec![],
|
|
||||||
program,
|
program,
|
||||||
|
cycle_time: Duration::default(),
|
||||||
|
},
|
||||||
|
state: RunState {
|
||||||
|
frame: StackFrame::new(pc, args),
|
||||||
|
call_stack: vec![],
|
||||||
ext_data: Default::default(),
|
ext_data: Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +72,17 @@ impl RunThread {
|
|||||||
fn run(mut self) {
|
fn run(mut self) {
|
||||||
'run: loop {
|
'run: loop {
|
||||||
match self.eval_op() {
|
match self.eval_op() {
|
||||||
Ok(EvalRes {
|
Ok(EvalRes { cycles, advance }) => {
|
||||||
cycles, advance
|
std::thread::sleep(self.info.cycle_time * (cycles as u32));
|
||||||
}) => {
|
trace!("Step {}; Status = {}", advance, self.state.frame.status);
|
||||||
std::thread::sleep(CYCLE_TIME * (cycles as u32));
|
self.state.frame.pc.advance(advance);
|
||||||
trace!("Step {}; Status = {}", advance, self.frame.status);
|
if self.state.frame.status.invalid {
|
||||||
self.frame.pc.advance(advance);
|
warn!("Operation failed with INVALID status!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Fault::Halt) => {
|
||||||
|
info!("Program ended.");
|
||||||
|
break 'run;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Fault: {:?}", e);
|
error!("Fault: {:?}", e);
|
||||||
@@ -64,13 +91,4 @@ impl RunThread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ext_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
|
|
||||||
if !self.ext_data.contains_key(&TypeId::of::<T>()) {
|
|
||||||
self.ext_data.insert(TypeId::of::<T>(), Box::new(T::default()));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ext_data.get_mut(&TypeId::of::<T>()).unwrap()
|
|
||||||
.downcast_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ use num_traits::PrimInt;
|
|||||||
|
|
||||||
use crsn::asm::instr::op::{OpTrait, EvalRes};
|
use crsn::asm::instr::op::{OpTrait, EvalRes};
|
||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::frame::{CallStack, StackFrame};
|
|
||||||
use crsn::runtime::program::Program;
|
|
||||||
|
|
||||||
use crate::defs::ArithOp;
|
use crate::defs::ArithOp;
|
||||||
|
use crsn::runtime::run_thread::{ThreadInfo, RunState};
|
||||||
|
|
||||||
impl OpTrait for ArithOp {
|
impl OpTrait for ArithOp {
|
||||||
fn execute(&self, _program: &Program, _call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
|
fn execute(&self, _ti : &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||||
|
let frame = &mut state.frame;
|
||||||
let eres = EvalRes::default();
|
let eres = EvalRes::default();
|
||||||
match self {
|
match self {
|
||||||
ArithOp::Test { a } => {
|
ArithOp::Test { a } => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub use parse::ArithOpParser;
|
pub use parse::ArithOps;
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ use crsn::asm::parse::arg_parser::ArgParser;
|
|||||||
use crate::defs::ArithOp;
|
use crate::defs::ArithOp;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ArithOpParser {
|
pub struct ArithOps {
|
||||||
_internal: ()
|
_internal: ()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArithOpParser {
|
impl ArithOps {
|
||||||
pub fn new() -> Box<dyn AsmModule> {
|
pub fn new() -> Box<dyn AsmModule> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
_internal: ()
|
_internal: ()
|
||||||
@@ -19,7 +19,7 @@ impl ArithOpParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsmModule for ArithOpParser {
|
impl AsmModule for ArithOps {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"arith"
|
"arith"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "crsn_stacks"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
crsn = { path = "../crsn" }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use crsn::asm::data::{Rd, Wr};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum StackOp {
|
||||||
|
Push { num: Rd, src: Rd },
|
||||||
|
Pop { dst: Wr, num: Rd },
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
|
||||||
|
use crsn::asm::data::literal::Value;
|
||||||
|
use crsn::asm::instr::op::{EvalRes, OpTrait};
|
||||||
|
use crsn::runtime::fault::Fault;
|
||||||
|
|
||||||
|
|
||||||
|
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
||||||
|
|
||||||
|
use crate::defs::StackOp;
|
||||||
|
|
||||||
|
struct Stacks {
|
||||||
|
stacks: Vec<VecDeque<Value>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Stacks {
|
||||||
|
fn default() -> Self {
|
||||||
|
Stacks {
|
||||||
|
stacks: vec![VecDeque::default(); 8],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpTrait for StackOp {
|
||||||
|
fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||||
|
let eres = EvalRes::default();
|
||||||
|
match self {
|
||||||
|
StackOp::Push { num, src } => {
|
||||||
|
state.frame.status.clear();
|
||||||
|
let stack_num = state.frame.read(*num)?;
|
||||||
|
let val = state.frame.read(*src)?;
|
||||||
|
|
||||||
|
if stack_num > 8 {
|
||||||
|
state.frame.status.invalid = true;
|
||||||
|
} else {
|
||||||
|
let obj: &mut Stacks = state.ext_mut();
|
||||||
|
obj.stacks[stack_num as usize].push_back(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StackOp::Pop { dst, num } => {
|
||||||
|
state.frame.status.clear();
|
||||||
|
let stack_num = state.frame.read(*num)?;
|
||||||
|
|
||||||
|
if stack_num > 8 {
|
||||||
|
state.frame.status.invalid = true;
|
||||||
|
} else {
|
||||||
|
let obj: &mut Stacks = state.ext_mut();
|
||||||
|
let val = obj.stacks[stack_num as usize].pop_back();
|
||||||
|
|
||||||
|
let val = match val {
|
||||||
|
None => {
|
||||||
|
state.frame.status.overflow = true;
|
||||||
|
0
|
||||||
|
}
|
||||||
|
Some(val) => {
|
||||||
|
val
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
state.frame.write(*dst, val)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(eres)
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
pub use parse::StackOps;
|
||||||
|
|
||||||
|
mod defs;
|
||||||
|
mod parse;
|
||||||
|
mod exec;
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
use crsn::asm::error::Error;
|
||||||
|
use crsn::asm::instr::op::{AsmModule, ParseOpResult};
|
||||||
|
use crsn::asm::instr::Op;
|
||||||
|
use crsn::asm::parse::arg_parser::ArgParser;
|
||||||
|
|
||||||
|
use crate::defs::StackOp;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct StackOps {
|
||||||
|
_internal: ()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StackOps {
|
||||||
|
pub fn new() -> Box<dyn AsmModule> {
|
||||||
|
Box::new(Self {
|
||||||
|
_internal: ()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsmModule for StackOps {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"stacks"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> {
|
||||||
|
Ok(ParseOpResult::Parsed(Op::Ext(Box::new(match keyword {
|
||||||
|
"push" => {
|
||||||
|
StackOp::Push {
|
||||||
|
num: args.next_rd()?,
|
||||||
|
src: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"pop" => {
|
||||||
|
StackOp::Pop {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
num: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_other => {
|
||||||
|
return Ok(ParseOpResult::Unknown(args));
|
||||||
|
}
|
||||||
|
}))))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
crsn = { path = "../crsn" }
|
crsn = { path = "../crsn" }
|
||||||
crsn_arith = { path = "../crsn_arith" }
|
crsn_arith = { path = "../crsn_arith" }
|
||||||
|
crsn_stacks = { path = "../crsn_stacks" }
|
||||||
|
|
||||||
simple_logger = "1.9.0"
|
simple_logger = "1.9.0"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
|
|||||||
+27
-6
@@ -4,9 +4,10 @@ extern crate log;
|
|||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
|
|
||||||
use crsn::asm::data::literal::Addr;
|
use crsn::asm::data::literal::Addr;
|
||||||
use crsn::runtime::program::Program;
|
|
||||||
use crsn::runtime::run_thread::{RunThread, ThreadToken};
|
use crsn::runtime::run_thread::{RunThread, ThreadToken};
|
||||||
use crsn_arith::ArithOpParser;
|
use crsn_arith::ArithOps;
|
||||||
|
use crsn_stacks::StackOps;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
SimpleLogger::new().init().unwrap();
|
SimpleLogger::new().init().unwrap();
|
||||||
@@ -42,7 +43,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
";*/
|
";*/
|
||||||
|
|
||||||
let program = "
|
/* let program = "
|
||||||
(
|
(
|
||||||
(main
|
(main
|
||||||
(j :lbl)
|
(j :lbl)
|
||||||
@@ -63,15 +64,35 @@ fn main() {
|
|||||||
(ret r0)
|
(ret r0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
";*/
|
||||||
|
|
||||||
|
let program = "
|
||||||
|
(
|
||||||
|
(main
|
||||||
|
(push 0 10)
|
||||||
|
(push 0 20)
|
||||||
|
(push 0 30)
|
||||||
|
(pop r0 0)
|
||||||
|
(pop r0 0)
|
||||||
|
(pop r0 0)
|
||||||
|
(halt)
|
||||||
|
)
|
||||||
|
)
|
||||||
";
|
";
|
||||||
|
|
||||||
let parsers = vec![
|
let parsers = vec![
|
||||||
ArithOpParser::new()
|
ArithOps::new(),
|
||||||
|
StackOps::new(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap();
|
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap();
|
||||||
|
|
||||||
let thread = RunThread::new(ThreadToken(0), parsed, Addr(0), &[]);
|
let thread1 = RunThread::new(ThreadToken(0), parsed.clone(), Addr(0), &[]);
|
||||||
|
let thread2 = RunThread::new(ThreadToken(1), parsed.clone(), Addr(0), &[]);
|
||||||
|
|
||||||
thread.start().join().unwrap();
|
let a = thread1.start();
|
||||||
|
let b = thread2.start();
|
||||||
|
|
||||||
|
a.join().unwrap();
|
||||||
|
b.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user