performance improvements

pull/21/head
Ondřej Hruška 4 years ago
parent a3eae0a8a9
commit e3fe3c6d72
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 10
      Cargo.lock
  2. 9
      README.md
  3. 1
      crsn/Cargo.toml
  4. 10
      crsn/src/asm/data/literal.rs
  5. 12
      crsn/src/asm/data/rd.rs
  6. 13
      crsn/src/asm/mod.rs
  7. 5
      crsn/src/asm/parse/parse_op.rs
  8. 28
      crsn/src/module/mod.rs
  9. 2
      crsn/src/runtime/exec.rs
  10. 1
      crsn/src/runtime/frame.rs
  11. 4
      crsn/src/runtime/frame/status.rs
  12. 12
      crsn/src/runtime/program.rs
  13. 19
      crsn/src/runtime/run_thread.rs
  14. 14
      crsn/src/runtime/run_thread/info.rs
  15. 65
      crsn/src/runtime/run_thread/state.rs
  16. 8
      crsn_arith/src/exec.rs
  17. 2
      crsn_stacks/src/exec.rs
  18. 14
      launcher/src/main.rs

10
Cargo.lock generated

@ -175,6 +175,7 @@ dependencies = [
"anyhow", "anyhow",
"dyn-clonable", "dyn-clonable",
"log", "log",
"nudge",
"num-traits", "num-traits",
"parking_lot", "parking_lot",
"sexp", "sexp",
@ -443,6 +444,15 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "nudge"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f379c3eafab28638ffb5cd95f1091dd21f5c6e7699e40b2ee96e9764a87f779"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "num" name = "num"
version = "0.1.42" version = "0.1.42"

@ -1,6 +1,6 @@
# CROISSANT VIRTUAL MACHINE # CROISSANT VIRTUAL MACHINE
Croissant (or Crsn for short) is an extensible runtime emulating a weird microcomputer (or not so micro, that depends on what extensions you install). Croissant (or *crsn* for short) is an extensible runtime emulating a weird microcomputer (or not so micro, that depends on what extensions you install).
## FAQ ## FAQ
@ -8,6 +8,13 @@ Croissant (or Crsn for short) is an extensible runtime emulating a weird microco
F U N F U N
### How is the performance?
Silly fast, actually. 60fps animations are perfectly doable if that's your thing.
It's probably faster than you need for most things, actually.
You can slow it down using the `-C` argument, or using sleep instructions.
#### What if I don't enjoy writing assembly that looks like weird Lisp? #### What if I don't enjoy writing assembly that looks like weird Lisp?
Maybe this is not for you Maybe this is not for you

@ -13,3 +13,4 @@ dyn-clonable = "0.9.0"
log = "0.4.11" log = "0.4.11"
num-traits = "0.2.12" num-traits = "0.2.12"
parking_lot = "0.11.0" parking_lot = "0.11.0"
nudge = "0.2.1"

@ -7,15 +7,18 @@ pub type DebugMsg = Cow<'static, str>;
/// Immediate value /// Immediate value
pub type Value = u64; pub type Value = u64;
pub fn is_positive(val: Value) -> bool { #[inline(always)]
pub const fn is_positive(val: Value) -> bool {
0 == (val & 0x8000_0000_0000_0000) 0 == (val & 0x8000_0000_0000_0000)
} }
pub fn is_negative(val: Value) -> bool { #[inline(always)]
pub const fn is_negative(val: Value) -> bool {
0 != (val & 0x8000_0000_0000_0000) 0 != (val & 0x8000_0000_0000_0000)
} }
pub fn as_signed(val: Value) -> i64 { #[inline(always)]
pub const fn as_signed(val: Value) -> i64 {
i64::from_ne_bytes(val.to_ne_bytes()) i64::from_ne_bytes(val.to_ne_bytes())
} }
@ -24,6 +27,7 @@ pub fn as_signed(val: Value) -> i64 {
pub struct Addr(pub u64); pub struct Addr(pub u64);
impl Addr { impl Addr {
#[inline(always)]
pub fn advance(&mut self, add: i64) { pub fn advance(&mut self, add: i64) {
if add < 0 { if add < 0 {
self.0 = self.0.wrapping_sub(-add as u64); self.0 = self.0.wrapping_sub(-add as u64);

@ -12,15 +12,17 @@ impl Rd {
pub const fn new(src: RdData) -> Self { pub const fn new(src: RdData) -> Self {
Rd(src, Mask::FULL) Rd(src, Mask::FULL)
} }
pub fn data(self) -> RdData {
pub const fn data(self) -> RdData {
self.0 self.0
} }
pub fn mask(self) -> Mask {
pub const fn mask(self) -> Mask {
self.1 self.1
} }
pub fn immediate(val: Value) -> Rd { pub const fn immediate(val: Value) -> Rd {
Rd(RdData::Immediate(val), Mask::default()) Rd(RdData::Immediate(val), Mask::FULL)
} }
} }
@ -48,7 +50,7 @@ impl Debug for Rd {
pub struct RdObj(Register); pub struct RdObj(Register);
impl RdObj { impl RdObj {
pub fn new(reg: Register) -> Self { pub const fn new(reg: Register) -> Self {
RdObj(reg) RdObj(reg)
} }
pub const fn reg(self) -> Register { pub const fn reg(self) -> Register {

@ -5,8 +5,9 @@ use sexp::SourcePosition;
use crate::asm::instr::flatten::labels_to_skips; use crate::asm::instr::flatten::labels_to_skips;
use crate::asm::parse::{ParserContext, ParserState}; use crate::asm::parse::{ParserContext, ParserState};
use crate::module::CrsnExtension; use crate::module::{CrsnExtension, CrsnUniq};
use crate::runtime::program::Program; use crate::runtime::program::Program;
use crate::builtin::BuiltinOps;
pub mod data; pub mod data;
pub mod error; pub mod error;
@ -15,7 +16,13 @@ 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: Arc<Vec<Box<dyn CrsnExtension>>>) -> Result<Arc<Program>, error::CrsnError> { pub fn assemble(source: &str, uniq : &CrsnUniq, mut parsers: Vec<Box<dyn CrsnExtension>>) -> Result<Arc<Program>, error::CrsnError> {
parsers.insert(0, BuiltinOps::new());
for p in &mut parsers {
p.init(uniq);
}
let pcx = ParserContext { let pcx = ParserContext {
parsers: &parsers, parsers: &parsers,
state: RefCell::new(ParserState { state: RefCell::new(ParserState {
@ -28,5 +35,5 @@ pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Resu
let ops = parse::parse(source, &SourcePosition::default(), &pcx)?; let ops = parse::parse(source, &SourcePosition::default(), &pcx)?;
let ops = labels_to_skips(ops)?; let ops = labels_to_skips(ops)?;
Ok(Program::new(ops, parsers)?) Ok(Program::new(ops, Arc::new(parsers))?)
} }

@ -4,12 +4,11 @@ use crate::asm::error::CrsnError;
use crate::asm::instr::cond::parse_cond; use crate::asm::instr::cond::parse_cond;
use crate::asm::instr::Op; use crate::asm::instr::Op;
use crate::asm::parse::arg_parser::TokenParser; use crate::asm::parse::arg_parser::TokenParser;
use crate::builtin::BuiltinOps;
use crate::module::ParseRes; use crate::module::ParseRes;
pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>, spos: &SourcePosition) -> Result<Option<Op>, CrsnError> { pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>, spos: &SourcePosition) -> Result<Option<Op>, CrsnError> {
// Include built-in instructions // Include built-in instructions
let builtins = [BuiltinOps::new()];
let mut cond = None; let mut cond = None;
if let Some(pos) = keyword.find('.') { if let Some(pos) = keyword.find('.') {
@ -17,7 +16,7 @@ pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>, spos: &S
keyword = &keyword[..pos]; keyword = &keyword[..pos];
} }
for p in builtins.iter().chain(arg_tokens.pcx.parsers) { for p in arg_tokens.pcx.parsers {
arg_tokens = match p.parse_op(spos, keyword, arg_tokens) { arg_tokens = match p.parse_op(spos, keyword, arg_tokens) {
Ok(ParseRes::Parsed(kind)) => return Ok(Some(Op { Ok(ParseRes::Parsed(kind)) => return Ok(Some(Op {
cond, cond,

@ -14,6 +14,8 @@ 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;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
mod eval_res; mod eval_res;
@ -41,7 +43,33 @@ pub trait OpTrait: Debug + Send + Sync + 'static {
fn to_sexp(&self) -> Sexp; fn to_sexp(&self) -> Sexp;
} }
/// CRSN initializer object.
/// Only one should be created for the lifespan of the parser and runtime.
#[derive(Default)]
pub struct CrsnUniq {
object_handle_counter : AtomicU64
}
pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000;
impl CrsnUniq {
pub fn new() -> Arc<Self> {
Arc::new(Self {
object_handle_counter: AtomicU64::new(UNIQ_BASE),
})
}
pub fn unique_handle(&self) -> u64 {
self.object_handle_counter.fetch_add(1, Ordering::Relaxed)
}
}
pub trait CrsnExtension: Debug + Send + Sync + 'static { pub trait CrsnExtension: Debug + Send + Sync + 'static {
fn init(&mut self, uniq: &CrsnUniq) {
//
}
/// Get name of the module /// Get name of the module
fn name(&self) -> &'static str; fn name(&self) -> &'static str;

@ -8,7 +8,7 @@ impl RunThread {
let state = &mut self.state; let state = &mut self.state;
let info = &self.info; let info = &self.info;
let op = info.program.read(state.frame.pc); let op = info.program.fetch_instr(state.frame.pc);
trace!("### {:04} : {:?}", state.frame.pc.0, op); trace!("### {:04} : {:?}", state.frame.pc.0, op);

@ -33,6 +33,7 @@ impl StackFrame {
sf sf
} }
#[inline(always)]
pub fn set_retvals(&mut self, vals: &[Value]) { pub fn set_retvals(&mut self, vals: &[Value]) {
for n in 0..(vals.len().min(REG_COUNT)) { for n in 0..(vals.len().min(REG_COUNT)) {
self.res[n] = vals[n]; self.res[n] = vals[n];

@ -27,6 +27,7 @@ pub struct StatusFlags {
} }
impl StatusFlags { impl StatusFlags {
#[inline(always)]
pub fn clear(&mut self) { pub fn clear(&mut self) {
*self = Self::default(); *self = Self::default();
} }
@ -57,12 +58,14 @@ impl StatusFlags {
if val & 0x100 != 0 { self.carry = true; } if val & 0x100 != 0 { self.carry = true; }
} }
#[inline(always)]
pub fn update(&mut self, val: Value) { pub fn update(&mut self, val: Value) {
self.zero = val == 0; self.zero = val == 0;
self.positive = is_positive(val); self.positive = is_positive(val);
self.negative = is_negative(val); self.negative = is_negative(val);
} }
#[inline(always)]
pub fn test(&self, cond: Cond) -> bool { pub fn test(&self, cond: Cond) -> bool {
match cond { match cond {
Cond::Equal => self.equal, Cond::Equal => self.equal,
@ -86,6 +89,7 @@ impl StatusFlags {
} }
} }
#[inline(always)]
pub fn set(&mut self, cond: Cond) { pub fn set(&mut self, cond: Cond) {
match cond { match cond {
Cond::Equal => { Cond::Equal => {

@ -90,8 +90,10 @@ impl Program {
} }
/// Read a program instruction at address /// Read a program instruction at address
pub fn read(&self, addr: Addr) -> &Op { pub fn fetch_instr(&self, addr: Addr) -> &Op {
if addr.0 >= self.ops.len() as u64 { if (addr.0 as usize) < self.ops.len() {
unsafe { self.ops.get_unchecked(addr.0 as usize) }
} else {
&Op { &Op {
kind: OpKind::BuiltIn(BuiltinOp::Halt), kind: OpKind::BuiltIn(BuiltinOp::Halt),
pos: SourcePosition { pos: SourcePosition {
@ -101,8 +103,6 @@ impl Program {
}, },
cond: None, cond: None,
} }
} else {
&self.ops[addr.0 as usize]
} }
} }
@ -116,7 +116,7 @@ impl Program {
if b0 != b1 { if b0 != b1 {
// block barrier that only partially intersects the jump // block barrier that only partially intersects the jump
if (*b0 >= from && *b0 <= to) != (*b1 >= from && *b1 <= to) { if (*b0 >= from && *b0 <= to) != (*b1 >= from && *b1 <= to) {
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind { if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.fetch_instr(*b0).kind {
return Err(Fault::JumpThroughBarrier { return Err(Fault::JumpThroughBarrier {
msg: msg.clone().unwrap_or("BLOCK BARRIER".into()) msg: msg.clone().unwrap_or("BLOCK BARRIER".into())
}); });
@ -127,7 +127,7 @@ impl Program {
} else { } else {
// point barrier // point barrier
if *b0 >= from && *b0 <= to { if *b0 >= from && *b0 <= to {
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind { if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.fetch_instr(*b0).kind {
return Err(Fault::JumpThroughBarrier { return Err(Fault::JumpThroughBarrier {
msg: msg.clone().unwrap_or("POINT BARRIER".into()) msg: msg.clone().unwrap_or("POINT BARRIER".into())
}); });

@ -1,5 +1,5 @@
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::AtomicU64;
use std::thread::JoinHandle; use std::thread::JoinHandle;
use std::time::Duration; use std::time::Duration;
@ -7,7 +7,7 @@ pub use info::ThreadInfo;
pub use state::RunState; pub use state::RunState;
use crate::asm::data::literal::Addr; use crate::asm::data::literal::Addr;
use crate::module::EvalRes; use crate::module::{EvalRes, CrsnUniq};
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;
@ -23,13 +23,9 @@ pub struct RunThread {
pub mod info; pub mod info;
pub mod state; pub mod state;
pub fn new_uniq() -> Arc<AtomicU64> {
Arc::new(AtomicU64::new(info::UNIQ_BASE))
}
pub struct ThreadParams<'a> { pub struct ThreadParams<'a> {
pub id: ThreadToken, pub id: ThreadToken,
pub uniq: Option<Arc<AtomicU64>>, pub uniq: Arc<CrsnUniq>,
pub program: Arc<Program>, pub program: Arc<Program>,
pub pc: Addr, pub pc: Addr,
pub cycle_time: Duration, pub cycle_time: Duration,
@ -42,7 +38,7 @@ impl RunThread {
let ti = Arc::new(ThreadInfo { let ti = Arc::new(ThreadInfo {
id: params.id, id: params.id,
uniq: params.uniq.unwrap_or_else(new_uniq), uniq: params.uniq,
program: params.program, program: params.program,
cycle_time: params.cycle_time, cycle_time: params.cycle_time,
extensions, extensions,
@ -73,12 +69,11 @@ impl RunThread {
'run: loop { 'run: loop {
match self.eval_op() { match self.eval_op() {
Ok(EvalRes { cycles, advance }) => { Ok(EvalRes { cycles, advance }) => {
std::thread::sleep(self.info.cycle_time * (cycles as u32)); if cycles > 0 {
std::thread::sleep(self.info.cycle_time * (cycles as u32));
}
trace!("Step {}; Status = {}", advance, self.state.frame.status); trace!("Step {}; Status = {}", advance, self.state.frame.status);
self.state.frame.pc.advance(advance); self.state.frame.pc.advance(advance);
if self.state.frame.status.invalid {
warn!("Operation failed with INVALID status!");
}
} }
Err(Fault::Halt) => { Err(Fault::Halt) => {
// TODO implement coordinated shutdown when more threads are running! // TODO implement coordinated shutdown when more threads are running!

@ -1,17 +1,17 @@
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration; 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; use crate::module::{CrsnExtension, CrsnUniq};
pub struct ThreadInfo { pub struct ThreadInfo {
/// Thread ID /// Thread ID
pub id: ThreadToken, pub id: ThreadToken,
/// Thread ID /// Initializer, used to generate unique IDs
pub(crate) uniq: Arc<AtomicU64>, pub(crate) uniq: Arc<CrsnUniq>,
/// Program to run /// Program to run
pub program: Arc<Program>, pub program: Arc<Program>,
/// Program to run /// Program to run
@ -20,10 +20,8 @@ pub struct ThreadInfo {
pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>, pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>,
} }
pub const UNIQ_BASE: u64 = 0x6372_736e_0000_0000;
impl ThreadInfo { impl ThreadInfo {
pub fn unique_value(&self) -> Value { pub fn unique_handle(&self) -> Value {
self.uniq.fetch_add(1, Ordering::Relaxed) self.uniq.unique_handle()
} }
} }

@ -8,6 +8,7 @@ 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 std::sync::Arc;
use crate::runtime::run_thread::ThreadInfo; use crate::runtime::run_thread::ThreadInfo;
use nudge::{likely};
pub struct RunState { pub struct RunState {
pub thread_info: Arc<ThreadInfo>, pub thread_info: Arc<ThreadInfo>,
@ -49,6 +50,7 @@ impl RunState {
} }
/// 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)
#[inline(always)]
pub fn set_flag(&mut self, cond: Cond, set: bool) { pub fn set_flag(&mut self, cond: Cond, set: bool) {
if set { if set {
self.frame.status.set(cond); self.frame.status.set(cond);
@ -56,6 +58,7 @@ impl RunState {
} }
/// Check status flags for a condition /// Check status flags for a condition
#[inline(always)]
pub fn test_cond(&self, cond: Cond) -> bool { pub fn test_cond(&self, cond: Cond) -> bool {
self.frame.status.test(cond) self.frame.status.test(cond)
} }
@ -72,12 +75,14 @@ impl RunState {
} }
/// Clear status flags /// Clear status flags
#[inline(always)]
pub fn clear_status(&mut self) { pub fn clear_status(&mut self) {
self.frame.status.clear(); self.frame.status.clear();
} }
/// Update status flags using a variable. /// Update status flags using a variable.
/// The update is additive - call `clear_status()` first if desired! /// The update is additive - call `clear_status()` first if desired!
#[inline(always)]
pub fn update_status(&mut self, val: Value) { pub fn update_status(&mut self, val: Value) {
self.frame.status.update(val); self.frame.status.update(val);
} }
@ -90,29 +95,29 @@ impl RunState {
/// 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.data() { match rd.data() {
RdData::Immediate(v) => Ok(v), RdData::Register(Register::Gen(rn)) => {
RdData::Register(Register::Res(rn)) => { if likely(rn < REG_COUNT as u8) {
if rn >= REG_COUNT as u8 { trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490 Ok(self.frame.gen[rn as usize])
} else { } else {
trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]); Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
Ok(self.frame.res[rn as usize])
} }
} }
RdData::Immediate(v) => Ok(v),
RdData::Register(Register::Arg(rn)) => { RdData::Register(Register::Arg(rn)) => {
if rn >= REG_COUNT as u8 { if likely(rn < REG_COUNT as u8) {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
} else {
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]); trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
Ok(self.frame.arg[rn as usize]) Ok(self.frame.arg[rn as usize])
} else {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
} }
} }
RdData::Register(Register::Gen(rn)) => { RdData::Register(Register::Res(rn)) => {
if rn >= REG_COUNT as u8 { if likely(rn < REG_COUNT as u8) {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]);
Ok(self.frame.res[rn as usize])
} else { } else {
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]); Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
Ok(self.frame.gen[rn as usize])
} }
} }
RdData::RegObject(register) => { RdData::RegObject(register) => {
@ -160,32 +165,32 @@ impl RunState {
trace!("WR {:?} := {}", wr, val); trace!("WR {:?} := {}", wr, val);
match wr.d() { match wr.d() {
WrData::Discard => { WrData::Register(Register::Gen(rn)) => {
/* Discard */ if likely(rn < REG_COUNT as u8) {
Ok(()) self.frame.gen[rn as usize] = val;
} Ok(())
WrData::Register(Register::Res(rn)) => {
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
} else { } else {
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) }) Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
} }
} }
WrData::Register(Register::Arg(rn)) => { WrData::Register(Register::Arg(rn)) => {
if rn >= REG_COUNT as u8 { if likely(rn < REG_COUNT as u8) {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
} else {
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) }) Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
} else {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
} }
} }
WrData::Register(Register::Gen(rn)) => { WrData::Register(Register::Res(rn)) => {
if rn >= REG_COUNT as u8 { if likely(rn < REG_COUNT as u8) {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
} else { } else {
self.frame.gen[rn as usize] = val; Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
Ok(())
} }
} }
WrData::Discard => {
/* Discard */
Ok(())
}
WrData::RegObject(register) => { WrData::RegObject(register) => {
let reference = self.read(Rd::new(RdData::Register(register)))?; let reference = self.read(Rd::new(RdData::Register(register)))?;
self.write_object(reference, wr.mask(), val) self.write_object(reference, wr.mask(), val)

@ -64,13 +64,13 @@ impl OpTrait for ArithOp {
state.clear_status(); state.clear_status();
let x = state.read(*a)?; let x = state.read(*a)?;
let y = state.read(*b)?; let y = state.read(*b)?;
let (res, ov) = if let Some(v) = x.checked_mul(y) { let res = if let Some(v) = x.checked_mul(y) {
(v, false) v
} else { } else {
(x.wrapping_mul(y), true) state.set_flag(Cond::Overflow, true);
x.wrapping_mul(y)
}; };
state.update_status(res); state.update_status(res);
state.set_flag(Cond::Overflow, ov);
state.write(*dst, res)?; state.write(*dst, res)?;
} }
ArithOp::Div { dst, rem, a, div } => { ArithOp::Div { dst, rem, a, div } => {

@ -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.unique_value(); let id = info.unique_handle();
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());

@ -2,7 +2,7 @@
extern crate log; extern crate log;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use clappconfig::{AppConfig, clap}; use clappconfig::{AppConfig, clap};
@ -10,7 +10,7 @@ use clappconfig::clap::ArgMatches;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crsn::asm::data::literal::Addr; use crsn::asm::data::literal::Addr;
use crsn::module::OpTrait; use crsn::module::{OpTrait, CrsnUniq};
use crsn::runtime::run_thread::{RunThread, ThreadToken, ThreadParams}; use crsn::runtime::run_thread::{RunThread, ThreadToken, ThreadParams};
use crsn_arith::ArithOps; use crsn_arith::ArithOps;
use crsn_screen::ScreenOps; use crsn_screen::ScreenOps;
@ -121,13 +121,13 @@ fn main() -> anyhow::Result<()> {
let source = read_file::read_file(&config.program_file)?; let source = read_file::read_file(&config.program_file)?;
let parsers = Arc::new(vec![ let uniq = CrsnUniq::new();
let parsed = crsn::asm::assemble(&source, &uniq, vec![
ArithOps::new(), ArithOps::new(),
StackOps::new(), StackOps::new(),
ScreenOps::new(), ScreenOps::new(),
]); ])?;
let parsed = crsn::asm::assemble(&source, parsers)?;
if config.asm_only { if config.asm_only {
for (n, op) in parsed.ops.iter().enumerate() { for (n, op) in parsed.ops.iter().enumerate() {
@ -147,7 +147,7 @@ fn main() -> anyhow::Result<()> {
let args = &[]; let args = &[];
let thread = RunThread::new(ThreadParams { let thread = RunThread::new(ThreadParams {
id: ThreadToken(0), id: ThreadToken(0),
uniq: None, uniq,
program: parsed, program: parsed,
pc: Addr(0), pc: Addr(0),
cycle_time: config.cycle_time, cycle_time: config.cycle_time,

Loading…
Cancel
Save