forked from MightyPork/crsn
performance improvements
This commit is contained in:
Generated
+10
@@ -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 {
|
||||||
|
|||||||
+10
-3
@@ -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::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 {
|
|
||||||
trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]);
|
|
||||||
Ok(self.frame.res[rn as usize])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RdData::Register(Register::Arg(rn)) => {
|
|
||||||
if rn >= REG_COUNT as u8 {
|
|
||||||
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
|
||||||
} else {
|
|
||||||
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
|
|
||||||
Ok(self.frame.arg[rn as usize])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RdData::Register(Register::Gen(rn)) => {
|
RdData::Register(Register::Gen(rn)) => {
|
||||||
if rn >= REG_COUNT as u8 {
|
if likely(rn < REG_COUNT as u8) {
|
||||||
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
|
||||||
} else {
|
|
||||||
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
|
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
|
||||||
Ok(self.frame.gen[rn as usize])
|
Ok(self.frame.gen[rn as usize])
|
||||||
|
} else {
|
||||||
|
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RdData::Immediate(v) => Ok(v),
|
||||||
|
RdData::Register(Register::Arg(rn)) => {
|
||||||
|
if likely(rn < REG_COUNT as u8) {
|
||||||
|
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
|
||||||
|
Ok(self.frame.arg[rn as usize])
|
||||||
|
} else {
|
||||||
|
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RdData::Register(Register::Res(rn)) => {
|
||||||
|
if likely(rn < REG_COUNT as u8) {
|
||||||
|
trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]);
|
||||||
|
Ok(self.frame.res[rn as usize])
|
||||||
|
} else {
|
||||||
|
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user