From 4115e07ee600ce5f82af94d6a670ca8164e007d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 7 Oct 2020 22:24:30 +0200 Subject: [PATCH] @reg and @value reading and writing is now possible --- crsn/src/asm/data/mod.rs | 42 ++++++++++----- crsn/src/asm/parse/arg_parser.rs | 2 +- crsn/src/asm/parse/parse_data.rs | 4 +- crsn/src/module/mod.rs | 7 ++- crsn/src/runtime/run_thread.rs | 47 ++++++++++------ crsn/src/runtime/run_thread/info.rs | 5 +- crsn/src/runtime/run_thread/state.rs | 80 ++++++++++++++++++++++++---- crsn_stacks/src/exec.rs | 2 +- launcher/src/main.rs | 12 +++-- 9 files changed, 148 insertions(+), 53 deletions(-) diff --git a/crsn/src/asm/data/mod.rs b/crsn/src/asm/data/mod.rs index d796dab..dfe55c8 100644 --- a/crsn/src/asm/data/mod.rs +++ b/crsn/src/asm/data/mod.rs @@ -25,10 +25,12 @@ mod wr; pub enum DataDisp { /// Constant value Immediate(Value), + /// Object pointer with immediate value + ImmObject(Value), /// Register Register(Register), - /// Object pointer - ObjectPtr(Register), + /// Object pointer in register + RegObject(Register), /// Discard the written value Discard, } @@ -42,9 +44,12 @@ impl Display for DataDisp { DataDisp::Register(r) => { write!(f, "{}", r) } - DataDisp::ObjectPtr(r) => { + DataDisp::RegObject(r) => { write!(f, "@{}", r) } + DataDisp::ImmObject(r) => { + write!(f, "@{:#x}", r) + } DataDisp::Discard => { write!(f, "_") } @@ -57,7 +62,8 @@ impl From for DataDisp { match s { RdData::Immediate(x) => DataDisp::Immediate(x), RdData::Register(x) => DataDisp::Register(x), - RdData::ObjectPtr(x) => DataDisp::ObjectPtr(x), + RdData::RegObject(x) => DataDisp::RegObject(x), + RdData::ImmObject(x) => DataDisp::ImmObject(x), } } } @@ -66,7 +72,8 @@ impl From for DataDisp { fn from(s: WrData) -> Self { match s { WrData::Register(x) => DataDisp::Register(x), - WrData::ObjectPtr(x) => DataDisp::ObjectPtr(x), + WrData::RegObject(x) => DataDisp::RegObject(x), + WrData::ImmObject(x) => DataDisp::ImmObject(x), WrData::Discard => DataDisp::Discard, } } @@ -77,10 +84,12 @@ impl From for DataDisp { pub enum RdData { /// Constant value Immediate(Value), + /// Pointer into memory, address immediate + ImmObject(Value), /// Register Register(Register), /// Pointer into memory, stored in a numbered register - ObjectPtr(Register), + RegObject(Register), } impl Display for RdData { @@ -94,7 +103,8 @@ impl Display for RdData { } } RdData::Register(r) => write!(f, "{}", r), - RdData::ObjectPtr(r) => write!(f, "@{}", r) + RdData::RegObject(r) => write!(f, "@{}", r), + RdData::ImmObject(v) => write!(f, "@{:#x}", v), } } } @@ -105,8 +115,9 @@ impl TryFrom for RdData { fn try_from(value: DataDisp) -> Result { match value { DataDisp::Immediate(x) => Ok(RdData::Immediate(x)), + DataDisp::ImmObject(x) => Ok(RdData::ImmObject(x)), DataDisp::Register(x) => Ok(RdData::Register(x)), - DataDisp::ObjectPtr(x) => Ok(RdData::ObjectPtr(x)), + DataDisp::RegObject(x) => Ok(RdData::RegObject(x)), DataDisp::Discard => Err(AsmError::DiscardAsValue), } } @@ -115,10 +126,12 @@ impl TryFrom for RdData { /// Data destination disposition #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum WrData { + /// Pointer into memory, address immediate + ImmObject(Value), /// Register Register(Register), /// Pointer into memory, stored in a numbered register - ObjectPtr(Register), + RegObject(Register), /// Discard the written value Discard, } @@ -128,7 +141,8 @@ impl Display for WrData { match self { WrData::Discard => f.write_str("_"), WrData::Register(r) => write!(f, "{}", r), - WrData::ObjectPtr(r) => write!(f, "@{}", r) + WrData::RegObject(r) => write!(f, "@{}", r), + WrData::ImmObject(v) => write!(f, "@{:#x}", v), } } } @@ -136,9 +150,10 @@ impl Display for WrData { impl From for RdData { fn from(s: WrData) -> Self { match s { + WrData::ImmObject(x) => RdData::ImmObject(x), WrData::Register(x) => RdData::Register(x), - WrData::ObjectPtr(x) => RdData::ObjectPtr(x), - WrData::Discard => RdData::Immediate(0), + WrData::RegObject(x) => RdData::RegObject(x), + WrData::Discard => RdData::Immediate(0), // this should not be allowed by the assembler } } } @@ -149,8 +164,9 @@ impl TryFrom for WrData { fn try_from(value: DataDisp) -> Result { match value { DataDisp::Immediate(_x) => Err(AsmError::ValueAsOutput), + DataDisp::ImmObject(x) => Ok(WrData::ImmObject(x)), DataDisp::Register(x) => Ok(WrData::Register(x)), - DataDisp::ObjectPtr(x) => Ok(WrData::ObjectPtr(x)), + DataDisp::RegObject(x) => Ok(WrData::RegObject(x)), DataDisp::Discard => Ok(WrData::Discard), } } diff --git a/crsn/src/asm/parse/arg_parser.rs b/crsn/src/asm/parse/arg_parser.rs index 8f4e3dc..61a62b4 100644 --- a/crsn/src/asm/parse/arg_parser.rs +++ b/crsn/src/asm/parse/arg_parser.rs @@ -93,7 +93,7 @@ impl<'a> TokenParser<'a> { /// Get the next entry as read location pub fn next_rdobj(&mut self) -> Result { match parse_rd(self.next_or_err()?, self.pcx)? { - Rd(RdData::ObjectPtr(reg), Mask::FULL) => { + Rd(RdData::RegObject(reg), Mask::FULL) => { Ok(RdObj::new(reg)) } other => { diff --git a/crsn/src/asm/parse/parse_data.rs b/crsn/src/asm/parse/parse_data.rs index 42c4cad..6e6a27a 100644 --- a/crsn/src/asm/parse/parse_data.rs +++ b/crsn/src/asm/parse/parse_data.rs @@ -96,14 +96,14 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result Result, Fault> { // Default impl - we do not support reading this object @@ -80,8 +80,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static { } /// Run-time method called to write an object (using the object handle syntax) - fn write_obj(&self, ti: &ThreadInfo, state: &mut RunState, handle: Value, mask: Mask) - -> Result, Fault> + fn write_obj(&self, state: &mut RunState, handle: Value, _mask: Mask, value: Value) -> Result, Fault> { // Default impl - we do not support writing this object Ok(None) diff --git a/crsn/src/runtime/run_thread.rs b/crsn/src/runtime/run_thread.rs index 2c5dc12..1ec04eb 100644 --- a/crsn/src/runtime/run_thread.rs +++ b/crsn/src/runtime/run_thread.rs @@ -16,7 +16,7 @@ use crate::runtime::program::Program; pub struct ThreadToken(pub u32); pub struct RunThread { - pub(crate) info: ThreadInfo, + pub(crate) info: Arc, pub(crate) state: RunState, } @@ -27,27 +27,40 @@ pub fn new_uniq() -> Arc { Arc::new(AtomicU64::new(info::UNIQ_BASE)) } +pub struct ThreadParams<'a> { + pub id: ThreadToken, + pub uniq: Option>, + pub program: Arc, + pub pc: Addr, + pub cycle_time: Duration, + pub args: &'a [u64], +} + impl RunThread { - pub fn new(id: ThreadToken, uniq: Option>, program: Arc, pc: Addr, args: &[u64]) -> Self { + pub fn new(params: ThreadParams) -> Self { + let extensions = params.program.extensions.clone(); + + let ti = Arc::new(ThreadInfo { + id: params.id, + uniq: params.uniq.unwrap_or_else(new_uniq), + program: params.program, + cycle_time: params.cycle_time, + extensions, + }); + + let rs = RunState { + thread_info: ti.clone(), + frame: StackFrame::new(params.pc, params.args), + call_stack: vec![], + ext_data: Default::default(), + }; + Self { - info: ThreadInfo { - id, - uniq: uniq.unwrap_or_else(new_uniq), - program, - cycle_time: Duration::default(), - }, - state: RunState { - frame: StackFrame::new(pc, args), - call_stack: vec![], - ext_data: Default::default(), - }, + info: ti, + state: rs, } } - pub fn set_speed(&mut self, cycle_time: Duration) { - self.info.cycle_time = cycle_time; - } - /// Spawn as a thread pub fn spawn(self) -> JoinHandle<()> { std::thread::spawn(move || { diff --git a/crsn/src/runtime/run_thread/info.rs b/crsn/src/runtime/run_thread/info.rs index c76cabe..83df3c4 100644 --- a/crsn/src/runtime/run_thread/info.rs +++ b/crsn/src/runtime/run_thread/info.rs @@ -5,6 +5,7 @@ use std::time::Duration; use crate::asm::data::literal::Value; use crate::runtime::program::Program; use crate::runtime::run_thread::ThreadToken; +use crate::module::CrsnExtension; pub struct ThreadInfo { /// Thread ID @@ -15,12 +16,14 @@ pub struct ThreadInfo { pub program: Arc, /// Program to run pub(crate) cycle_time: Duration, + /// Extensions + pub extensions: Arc>>, } pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000; impl ThreadInfo { - pub fn uniq(&self) -> Value { + pub fn unique_value(&self) -> Value { self.uniq.fetch_add(1, Ordering::Relaxed) } } diff --git a/crsn/src/runtime/run_thread/state.rs b/crsn/src/runtime/run_thread/state.rs index da16b6e..c9f190c 100644 --- a/crsn/src/runtime/run_thread/state.rs +++ b/crsn/src/runtime/run_thread/state.rs @@ -1,32 +1,52 @@ use std::any::{Any, TypeId}; use std::collections::HashMap; -use crate::asm::data::{Rd, RdData, RdObj, Register, Wr, WrData}; +use crate::asm::data::{Rd, RdData, RdObj, Register, Wr, WrData, Mask}; use crate::asm::data::literal::{Addr, Value}; use crate::asm::instr::Cond; use crate::runtime::fault::Fault; use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame}; +use std::sync::Arc; +use crate::runtime::run_thread::ThreadInfo; pub struct RunState { + pub thread_info: Arc, /// Active stack frame pub frame: StackFrame, /// Call stack pub call_stack: CallStack, /// Extension data - pub ext_data: HashMap>, + pub ext_data: ExtensionDataStore, } -impl RunState { +#[derive(Debug,Default)] +pub struct ExtensionDataStore { + store: HashMap> +} + +impl ExtensionDataStore { + pub fn new() -> Self { + Default::default() + } + /// Get an extension's persistent data object for mutation. /// It will be created using Default if not present before. - pub fn ext_mut(&mut self) -> &mut T { - if !self.ext_data.contains_key(&TypeId::of::()) { - self.ext_data.insert(TypeId::of::(), Box::new(T::default())); + pub fn get_mut(&mut self) -> &mut T { + if !self.store.contains_key(&TypeId::of::()) { + self.store.insert(TypeId::of::(), Box::new(T::default())); } - self.ext_data.get_mut(&TypeId::of::()).unwrap() + self.store.get_mut(&TypeId::of::()).unwrap() .downcast_mut().unwrap() } +} + +impl RunState { + /// Get an extension's persistent data object for mutation. + /// It will be created using Default if not present before. + pub fn ext_mut(&mut self) -> &mut T { + self.ext_data.get_mut() + } /// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual) pub fn set_flag(&mut self, cond: Cond, set: bool) { @@ -95,12 +115,46 @@ impl RunState { Ok(self.frame.gen[rn as usize]) } } - RdData::ObjectPtr(_) => { - unimplemented!("Read object ptr") + RdData::RegObject(register) => { + let reference = self.read(Rd::new(RdData::Register(register)))?; + self.read_object(reference, rd.mask()) + } + RdData::ImmObject(reference) => { + self.read_object(reference, rd.mask()) } } } + fn read_object(&mut self, reference: Value, mask: Mask) -> Result { + // This is a shitty dirty hack to allow iterating over the extensions while passing a mutable reference + // to self to the reading methods. Since the extensions array is in an Arc, it can't be mutated internally + // anyway, and we know it will still live after the method returns - unless someone does something incredibly stupid. + let ti: &ThreadInfo = unsafe { &*(self.thread_info.as_ref() as *const _) }; // If this fails, just clone the arc for the loop... + + for ext in ti.extensions.iter() { + if let Some(value) = ext.read_obj(self, reference, mask)? { + return Ok(value); + } + } + + Err(Fault::ObjectNotExist(reference)) + } + + fn write_object(&mut self, reference: Value, mask: Mask, value: Value) -> Result<(), Fault> { + // This is a shitty dirty hack to allow iterating over the extensions while passing a mutable reference + // to self to the reading methods. Since the extensions array is in an Arc, it can't be mutated internally + // anyway, and we know it will still live after the method returns - unless someone does something incredibly stupid. + let ti: &ThreadInfo = unsafe { &*(self.thread_info.as_ref() as *const _) }; // If this fails, just clone the arc for the loop... + + for ext in ti.extensions.iter() { + if ext.write_obj(self, reference, mask, value)?.is_some() { + return Ok(()); + } + } + + Err(Fault::ObjectNotExist(reference)) + } + /// Write a value to a `Wr` location pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> { trace!("WR {:?} := {}", wr, val); @@ -132,8 +186,12 @@ impl RunState { Ok(()) } } - WrData::ObjectPtr(_) => { - unimplemented!("Write object ptr") + WrData::RegObject(register) => { + let reference = self.read(Rd::new(RdData::Register(register)))?; + self.write_object(reference, wr.mask(), val) + } + WrData::ImmObject(reference) => { + self.write_object(reference, wr.mask(), val) } } } diff --git a/crsn_stacks/src/exec.rs b/crsn_stacks/src/exec.rs index f11554f..a39faa6 100644 --- a/crsn_stacks/src/exec.rs +++ b/crsn_stacks/src/exec.rs @@ -22,7 +22,7 @@ impl OpTrait for StackOp { let eres = EvalRes::default(); match self { StackOp::NewStack { dst } => { - let id = info.uniq(); + let id = info.unique_value(); let stacks: &mut Stacks = state.ext_mut(); stacks.store.insert(id, VecDeque::new()); diff --git a/launcher/src/main.rs b/launcher/src/main.rs index 748c0f5..336873c 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crsn::asm::data::literal::Addr; use crsn::module::OpTrait; -use crsn::runtime::run_thread::{RunThread, ThreadToken}; +use crsn::runtime::run_thread::{RunThread, ThreadToken, ThreadParams}; use crsn_arith::ArithOps; use crsn_screen::ScreenOps; use crsn_stacks::StackOps; @@ -145,8 +145,14 @@ fn main() -> anyhow::Result<()> { info!("Start runtime"); let args = &[]; - let mut thread = RunThread::new(ThreadToken(0), None, parsed.clone(), Addr(0), args); - thread.set_speed(config.cycle_time); + let thread = RunThread::new(ThreadParams { + id: ThreadToken(0), + uniq: None, + program: parsed, + pc: Addr(0), + cycle_time: config.cycle_time, + args + }); // run without spawning, so it is on the main thread - required by some extensions thread.run();