@reg and @value reading and writing is now possible

pull/21/head
Ondřej Hruška 3 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 {
/// 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<RdData> 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<WrData> 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<WrData> 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<DataDisp> for RdData {
fn try_from(value: DataDisp) -> Result<Self, Self::Error> {
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<DataDisp> 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<WrData> 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<DataDisp> for WrData {
fn try_from(value: DataDisp) -> Result<Self, Self::Error> {
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),
}
}

@ -93,7 +93,7 @@ impl<'a> TokenParser<'a> {
/// Get the next entry as read location
pub fn next_rdobj(&mut self) -> Result<RdObj, CrsnError> {
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 => {

@ -96,14 +96,14 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
if let Some(reference) = s.strip_prefix('@') {
let pstate = pcx.state.borrow();
if let Some(reg) = pstate.reg_aliases.get(reference) {
Ok(DataDisp::ObjectPtr(*reg))
Ok(DataDisp::RegObject(*reg))
} else {
let reg = reg::parse_reg(reference, &pos)?;
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))
} else {
Ok(DataDisp::ObjectPtr(reg))
Ok(DataDisp::RegObject(reg))
}
}
} 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::parse::arg_parser::TokenParser;
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;
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)
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>
{
// 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<Option<()>, Fault>
fn write_obj(&self, state: &mut RunState, handle: Value, _mask: Mask, value: Value) -> Result<Option<()>, Fault>
{
// Default impl - we do not support writing this object
Ok(None)

@ -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<ThreadInfo>,
pub(crate) state: RunState,
}
@ -27,27 +27,40 @@ pub fn new_uniq() -> Arc<AtomicU64> {
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 {
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 {
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 || {

@ -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>,
/// Program to run
pub(crate) cycle_time: Duration,
/// Extensions
pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>,
}
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)
}
}

@ -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<ThreadInfo>,
/// Active stack frame
pub frame: StackFrame,
/// Call stack
pub call_stack: CallStack,
/// 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.
/// It will be created using Default if not present before.
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()));
pub fn get_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
if !self.store.contains_key(&TypeId::of::<T>()) {
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()
}
}
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)
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<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
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)
}
}
}

@ -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());

@ -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();

Loading…
Cancel
Save