@reg and @value reading and writing is now possible

pull/21/head
Ondřej Hruška 4 years ago
parent 562fc48151
commit 4115e07ee6
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 42
      crsn/src/asm/data/mod.rs
  2. 2
      crsn/src/asm/parse/arg_parser.rs
  3. 4
      crsn/src/asm/parse/parse_data.rs
  4. 7
      crsn/src/module/mod.rs
  5. 47
      crsn/src/runtime/run_thread.rs
  6. 5
      crsn/src/runtime/run_thread/info.rs
  7. 80
      crsn/src/runtime/run_thread/state.rs
  8. 2
      crsn_stacks/src/exec.rs
  9. 12
      launcher/src/main.rs

@ -25,10 +25,12 @@ mod wr;
pub enum DataDisp { pub enum DataDisp {
/// Constant value /// Constant value
Immediate(Value), Immediate(Value),
/// Object pointer with immediate value
ImmObject(Value),
/// Register /// Register
Register(Register), Register(Register),
/// Object pointer /// Object pointer in register
ObjectPtr(Register), RegObject(Register),
/// Discard the written value /// Discard the written value
Discard, Discard,
} }
@ -42,9 +44,12 @@ impl Display for DataDisp {
DataDisp::Register(r) => { DataDisp::Register(r) => {
write!(f, "{}", r) write!(f, "{}", r)
} }
DataDisp::ObjectPtr(r) => { DataDisp::RegObject(r) => {
write!(f, "@{}", r) write!(f, "@{}", r)
} }
DataDisp::ImmObject(r) => {
write!(f, "@{:#x}", r)
}
DataDisp::Discard => { DataDisp::Discard => {
write!(f, "_") write!(f, "_")
} }
@ -57,7 +62,8 @@ impl From<RdData> for DataDisp {
match s { match s {
RdData::Immediate(x) => DataDisp::Immediate(x), RdData::Immediate(x) => DataDisp::Immediate(x),
RdData::Register(x) => DataDisp::Register(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<WrData> for DataDisp {
fn from(s: WrData) -> Self { fn from(s: WrData) -> Self {
match s { match s {
WrData::Register(x) => DataDisp::Register(x), 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, WrData::Discard => DataDisp::Discard,
} }
} }
@ -77,10 +84,12 @@ impl From<WrData> for DataDisp {
pub enum RdData { pub enum RdData {
/// Constant value /// Constant value
Immediate(Value), Immediate(Value),
/// Pointer into memory, address immediate
ImmObject(Value),
/// Register /// Register
Register(Register), Register(Register),
/// Pointer into memory, stored in a numbered register /// Pointer into memory, stored in a numbered register
ObjectPtr(Register), RegObject(Register),
} }
impl Display for RdData { impl Display for RdData {
@ -94,7 +103,8 @@ impl Display for RdData {
} }
} }
RdData::Register(r) => write!(f, "{}", r), 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<DataDisp> for RdData {
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(RdData::Immediate(x)), DataDisp::Immediate(x) => Ok(RdData::Immediate(x)),
DataDisp::ImmObject(x) => Ok(RdData::ImmObject(x)),
DataDisp::Register(x) => Ok(RdData::Register(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), DataDisp::Discard => Err(AsmError::DiscardAsValue),
} }
} }
@ -115,10 +126,12 @@ impl TryFrom<DataDisp> for RdData {
/// Data destination disposition /// Data destination disposition
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum WrData { pub enum WrData {
/// Pointer into memory, address immediate
ImmObject(Value),
/// Register /// Register
Register(Register), Register(Register),
/// Pointer into memory, stored in a numbered register /// Pointer into memory, stored in a numbered register
ObjectPtr(Register), RegObject(Register),
/// Discard the written value /// Discard the written value
Discard, Discard,
} }
@ -128,7 +141,8 @@ impl Display for WrData {
match self { match self {
WrData::Discard => f.write_str("_"), WrData::Discard => f.write_str("_"),
WrData::Register(r) => write!(f, "{}", r), 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<WrData> for RdData { impl From<WrData> for RdData {
fn from(s: WrData) -> Self { fn from(s: WrData) -> Self {
match s { match s {
WrData::ImmObject(x) => RdData::ImmObject(x),
WrData::Register(x) => RdData::Register(x), WrData::Register(x) => RdData::Register(x),
WrData::ObjectPtr(x) => RdData::ObjectPtr(x), WrData::RegObject(x) => RdData::RegObject(x),
WrData::Discard => RdData::Immediate(0), WrData::Discard => RdData::Immediate(0), // this should not be allowed by the assembler
} }
} }
} }
@ -149,8 +164,9 @@ impl TryFrom<DataDisp> for WrData {
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::ImmObject(x) => Ok(WrData::ImmObject(x)),
DataDisp::Register(x) => Ok(WrData::Register(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), DataDisp::Discard => Ok(WrData::Discard),
} }
} }

@ -93,7 +93,7 @@ impl<'a> TokenParser<'a> {
/// Get the next entry as read location /// Get the next entry as read location
pub fn next_rdobj(&mut self) -> Result<RdObj, CrsnError> { pub fn next_rdobj(&mut self) -> Result<RdObj, CrsnError> {
match parse_rd(self.next_or_err()?, self.pcx)? { 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)) Ok(RdObj::new(reg))
} }
other => { other => {

@ -96,14 +96,14 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
if let Some(reference) = s.strip_prefix('@') { if let Some(reference) = s.strip_prefix('@') {
let pstate = pcx.state.borrow(); let pstate = pcx.state.borrow();
if let Some(reg) = pstate.reg_aliases.get(reference) { if let Some(reg) = pstate.reg_aliases.get(reference) {
Ok(DataDisp::ObjectPtr(*reg)) Ok(DataDisp::RegObject(*reg))
} else { } else {
let reg = reg::parse_reg(reference, &pos)?; let reg = reg::parse_reg(reference, &pos)?;
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() { if pstate.reg_aliases.values().find(|v| **v == reg).is_some() {
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos)) Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos))
} else { } else {
Ok(DataDisp::ObjectPtr(reg)) Ok(DataDisp::RegObject(reg))
} }
} }
} else if s.starts_with(|c: char| c.is_ascii_digit() || c == '-') { } else if s.starts_with(|c: char| c.is_ascii_digit() || c == '-') {

@ -12,7 +12,7 @@ use crate::asm::instr::Flatten;
use crate::asm::instr::op::OpKind; use crate::asm::instr::op::OpKind;
use crate::asm::parse::arg_parser::TokenParser; use crate::asm::parse::arg_parser::TokenParser;
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;
mod eval_res; mod eval_res;
@ -72,7 +72,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
} }
/// Run-time method called to read an object (using the object handle syntax) /// Run-time method called to read an object (using the object handle syntax)
fn read_obj(&self, ti: &ThreadInfo, state: &mut RunState, handle: Value, _mask: Mask) fn read_obj(&self, state: &mut RunState, handle: Value, _mask: Mask)
-> Result<Option<Value>, Fault> -> Result<Option<Value>, Fault>
{ {
// Default impl - we do not support reading this object // 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) /// 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) fn write_obj(&self, state: &mut RunState, handle: Value, _mask: Mask, value: Value) -> Result<Option<()>, Fault>
-> Result<Option<()>, Fault>
{ {
// Default impl - we do not support writing this object // Default impl - we do not support writing this object
Ok(None) Ok(None)

@ -16,7 +16,7 @@ use crate::runtime::program::Program;
pub struct ThreadToken(pub u32); pub struct ThreadToken(pub u32);
pub struct RunThread { pub struct RunThread {
pub(crate) info: ThreadInfo, pub(crate) info: Arc<ThreadInfo>,
pub(crate) state: RunState, pub(crate) state: RunState,
} }
@ -27,27 +27,40 @@ pub fn new_uniq() -> Arc<AtomicU64> {
Arc::new(AtomicU64::new(info::UNIQ_BASE)) Arc::new(AtomicU64::new(info::UNIQ_BASE))
} }
pub struct ThreadParams<'a> {
pub id: ThreadToken,
pub uniq: Option<Arc<AtomicU64>>,
pub program: Arc<Program>,
pub pc: Addr,
pub cycle_time: Duration,
pub args: &'a [u64],
}
impl RunThread { impl RunThread {
pub fn new(id: ThreadToken, uniq: Option<Arc<AtomicU64>>, program: Arc<Program>, 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 { Self {
info: ThreadInfo { info: ti,
id, state: rs,
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(),
},
} }
} }
pub fn set_speed(&mut self, cycle_time: Duration) {
self.info.cycle_time = cycle_time;
}
/// Spawn as a thread /// Spawn as a thread
pub fn spawn(self) -> JoinHandle<()> { pub fn spawn(self) -> JoinHandle<()> {
std::thread::spawn(move || { std::thread::spawn(move || {

@ -5,6 +5,7 @@ use std::time::Duration;
use crate::asm::data::literal::Value; use crate::asm::data::literal::Value;
use crate::runtime::program::Program; use crate::runtime::program::Program;
use crate::runtime::run_thread::ThreadToken; use crate::runtime::run_thread::ThreadToken;
use crate::module::CrsnExtension;
pub struct ThreadInfo { pub struct ThreadInfo {
/// Thread ID /// Thread ID
@ -15,12 +16,14 @@ pub struct ThreadInfo {
pub program: Arc<Program>, pub program: Arc<Program>,
/// Program to run /// Program to run
pub(crate) cycle_time: Duration, pub(crate) cycle_time: Duration,
/// Extensions
pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>,
} }
pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000; pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000;
impl ThreadInfo { impl ThreadInfo {
pub fn uniq(&self) -> Value { pub fn unique_value(&self) -> Value {
self.uniq.fetch_add(1, Ordering::Relaxed) self.uniq.fetch_add(1, Ordering::Relaxed)
} }
} }

@ -1,32 +1,52 @@
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::collections::HashMap; 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::data::literal::{Addr, Value};
use crate::asm::instr::Cond; use crate::asm::instr::Cond;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame}; use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame};
use std::sync::Arc;
use crate::runtime::run_thread::ThreadInfo;
pub struct RunState { pub struct RunState {
pub thread_info: Arc<ThreadInfo>,
/// Active stack frame /// Active stack frame
pub frame: StackFrame, pub frame: StackFrame,
/// Call stack /// Call stack
pub call_stack: CallStack, pub call_stack: CallStack,
/// Extension data /// Extension data
pub ext_data: HashMap<TypeId, Box<dyn Any + Send>>, pub ext_data: ExtensionDataStore,
} }
impl RunState { #[derive(Debug,Default)]
pub struct ExtensionDataStore {
store: HashMap<TypeId, Box<dyn Any + Send>>
}
impl ExtensionDataStore {
pub fn new() -> Self {
Default::default()
}
/// Get an extension's persistent data object for mutation. /// Get an extension's persistent data object for mutation.
/// It will be created using Default if not present before. /// It will be created using Default if not present before.
pub fn ext_mut<T: Send + Default + 'static>(&mut self) -> &mut T { pub fn get_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
if !self.ext_data.contains_key(&TypeId::of::<T>()) { if !self.store.contains_key(&TypeId::of::<T>()) {
self.ext_data.insert(TypeId::of::<T>(), Box::new(T::default())); self.store.insert(TypeId::of::<T>(), Box::new(T::default()));
} }
self.ext_data.get_mut(&TypeId::of::<T>()).unwrap() self.store.get_mut(&TypeId::of::<T>()).unwrap()
.downcast_mut().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<T: Send + Default + 'static>(&mut self) -> &mut T {
self.ext_data.get_mut()
}
/// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual) /// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual)
pub fn set_flag(&mut self, cond: Cond, set: bool) { pub fn set_flag(&mut self, cond: Cond, set: bool) {
@ -95,12 +115,46 @@ impl RunState {
Ok(self.frame.gen[rn as usize]) Ok(self.frame.gen[rn as usize])
} }
} }
RdData::ObjectPtr(_) => { RdData::RegObject(register) => {
unimplemented!("Read object ptr") 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<Value, 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 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 /// Write a value to a `Wr` location
pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> { pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> {
trace!("WR {:?} := {}", wr, val); trace!("WR {:?} := {}", wr, val);
@ -132,8 +186,12 @@ impl RunState {
Ok(()) Ok(())
} }
} }
WrData::ObjectPtr(_) => { WrData::RegObject(register) => {
unimplemented!("Write object ptr") 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)
} }
} }
} }

@ -22,7 +22,7 @@ impl OpTrait for StackOp {
let eres = EvalRes::default(); let eres = EvalRes::default();
match self { match self {
StackOp::NewStack { dst } => { StackOp::NewStack { dst } => {
let id = info.uniq(); let id = info.unique_value();
let stacks: &mut Stacks = state.ext_mut(); let stacks: &mut Stacks = state.ext_mut();
stacks.store.insert(id, VecDeque::new()); stacks.store.insert(id, VecDeque::new());

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
use crsn::asm::data::literal::Addr; use crsn::asm::data::literal::Addr;
use crsn::module::OpTrait; 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_arith::ArithOps;
use crsn_screen::ScreenOps; use crsn_screen::ScreenOps;
use crsn_stacks::StackOps; use crsn_stacks::StackOps;
@ -145,8 +145,14 @@ fn main() -> anyhow::Result<()> {
info!("Start runtime"); info!("Start runtime");
let args = &[]; let args = &[];
let mut thread = RunThread::new(ThreadToken(0), None, parsed.clone(), Addr(0), args); let thread = RunThread::new(ThreadParams {
thread.set_speed(config.cycle_time); 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 // run without spawning, so it is on the main thread - required by some extensions
thread.run(); thread.run();

Loading…
Cancel
Save