pull/21/head
Ondřej Hruška 4 years ago
parent f493cc102a
commit 8f076e195a
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 10
      asm/src/data/literal.rs
  2. 4
      asm/src/data/mask.rs
  3. 27
      asm/src/data/mod.rs
  4. 9
      asm/src/data/reg.rs
  5. 15
      asm/src/error.rs
  6. 9
      asm/src/instr/flatten.rs
  7. 13
      asm/src/instr/mod.rs
  8. 14
      asm/src/instr/op.rs
  9. 29
      asm/src/lib.rs
  10. 12
      asm/src/parse/mod.rs
  11. 5
      asm/src/parse/parse_cond.rs
  12. 28
      asm/src/parse/parse_data.rs
  13. 10
      asm/src/parse/parse_instr.rs
  14. 13
      asm/src/parse/parse_op.rs
  15. 7
      asm/src/parse/parse_routines.rs
  16. 3
      asm/src/parse/sexp_expect.rs
  17. 5
      asm/src/patches/mod.rs
  18. 7
      crsn/src/main.rs
  19. 13
      runtime/src/exec/mod.rs
  20. 9
      runtime/src/fault.rs
  21. 8
      runtime/src/frame.rs
  22. 5
      runtime/src/frame/status.rs
  23. 3
      runtime/src/lib.rs
  24. 7
      runtime/src/mlock.rs
  25. 8
      runtime/src/program.rs
  26. 11
      runtime/src/run_thread.rs
  27. 4
      runtime/src/span.rs

@ -1,21 +1,21 @@
use std::borrow::Cow;
use std::fmt::{self, Display, Formatter};
use std::sync::atomic::AtomicU32;
use std::borrow::Cow;
pub type DebugMsg = Cow<'static, str>;
/// Immediate value
pub type Value = u64;
pub fn is_positive(val : Value) -> bool {
pub fn is_positive(val: Value) -> bool {
0 == (val & 0x8000_0000_0000_0000)
}
pub fn is_negative(val : Value) -> bool {
pub fn is_negative(val: Value) -> bool {
0 != (val & 0x8000_0000_0000_0000)
}
pub fn as_signed(val : Value) -> i64 {
pub fn as_signed(val: Value) -> i64 {
i64::from_ne_bytes(val.to_ne_bytes())
}
@ -70,7 +70,7 @@ pub enum Label {
impl Label {
/// Generate a unique numbered label from a counter
pub fn unique(counter : &AtomicU32) -> Self {
pub fn unique(counter: &AtomicU32) -> Self {
Label::Numbered(counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
}
}

@ -15,7 +15,7 @@ impl Default for Mask {
fn default() -> Self {
Mask {
len: 64,
offset: 0
offset: 0,
}
}
}
@ -44,7 +44,7 @@ impl Mask {
// create the invalid mask to display it in the error
return Err(AsmError::BadMask(Mask {
len,
offset
offset,
}));
}

@ -1,20 +1,19 @@
use super::error::AsmError;
use std::convert::TryFrom;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use literal::Addr;
pub use mask::Mask;
pub use reg::Register;
use crate::data::literal::{as_signed, Value};
use super::error::AsmError;
pub mod literal;
pub mod reg;
pub mod mask;
pub use reg::Register;
pub use mask::Mask;
use literal::Addr;
use std::convert::TryFrom;
use crate::data::literal::{Value, as_signed};
use std::fmt::{Debug, Formatter, Display};
use std::fmt;
/// Data source disposition
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum DataDisp {
@ -154,7 +153,7 @@ impl Rd {
self.1
}
pub fn immediate(val : Value) -> Rd {
pub fn immediate(val: Value) -> Rd {
Rd(SrcDisp::Immediate(val), Mask::default())
}
}
@ -185,7 +184,7 @@ impl Wr {
impl Debug for Rd {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Rd(")?;
let disp : DataDisp = self.0.into();
let disp: DataDisp = self.0.into();
write!(f, "{}", disp)?;
if !self.mask().is_default() {
write!(f, ",{:?}", self.mask())?;
@ -197,7 +196,7 @@ impl Debug for Rd {
impl Debug for Wr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Wr(")?;
let disp : DataDisp = self.0.into();
let disp: DataDisp = self.0.into();
write!(f, "{}", disp)?;
if !self.mask().is_default() {
write!(f, ",{:?}", self.mask())?;

@ -1,4 +1,5 @@
use std::fmt::{self, Display, Formatter};
use crate::error::Error;
/// Register name
@ -22,15 +23,15 @@ impl Display for Register {
}
}
pub fn parse_reg(name : &str) -> anyhow::Result<Register> {
pub fn parse_reg(name: &str) -> anyhow::Result<Register> {
if let Some(rn) = name.strip_prefix("arg") {
let val : u8 = rn.parse()?;
let val: u8 = rn.parse()?;
Ok(Register::Arg(val))
} else if let Some(rn) = name.strip_prefix("res") {
let val : u8 = rn.parse()?;
let val: u8 = rn.parse()?;
Ok(Register::Res(val))
} else if let Some(rn) = name.strip_prefix("r") {
let val : u8 = rn.parse()?;
let val: u8 = rn.parse()?;
Ok(Register::Gen(val))
} else {
Err(Error::Parse(format!("Bad reg name: {}", name).into()))?

@ -1,12 +1,13 @@
use crate::instr::{Cond};
use crate::data::{Mask, Register};
use thiserror::Error;
use std::borrow::Cow;
use crate::data::literal::Label;
use thiserror::Error;
use crate::data::{Mask, Register};
use crate::data::literal::Label;
use crate::instr::Cond;
/// csn_asm unified error type
#[derive(Error,Debug)]
#[derive(Error, Debug)]
pub enum Error {
#[error("S-expression syntax error: {0:?}")]
PreParse(#[from] Box<sexp::Error>),
@ -23,7 +24,7 @@ pub enum Error {
}
/// Error from the assembler stage (after parsing S-expressions and basic validation)
#[derive(Error,Debug)]
#[derive(Error, Debug)]
pub enum AsmError {
#[error("Unknown instruction")]
UnknownInstruction,
@ -44,7 +45,7 @@ pub enum AsmError {
}
/// Architectural error - the code is syntactically OK, but cannot run
#[derive(Error,Debug)]
#[derive(Error, Debug)]
pub enum ArchError {
#[error("Register {0} does not exist")]
RegisterNotExist(Register),

@ -1,9 +1,10 @@
use std::sync::atomic::AtomicU32;
use crate::instr::{HLOp, Instr, Cond, Routine, Op};
use crate::error::{Error, AsmError};
use std::collections::HashMap;
use crate::data::literal::{Label, Value};
use std::sync::atomic::AtomicU32;
use crate::data::{Rd, SrcDisp};
use crate::data::literal::{Label, Value};
use crate::error::{AsmError, Error};
use crate::instr::{Cond, HLOp, Instr, Op, Routine};
/// A trait for something that can turn into multiple instructions
pub trait Flatten {

@ -1,17 +1,14 @@
mod op;
mod cond;
mod flatten;
pub use cond::Cond;
pub use flatten::Flatten;
pub use flatten::lower;
pub use op::HLOp;
pub use op::Op;
pub use cond::Cond;
use crate::data::literal::{RoutineName};
use crate::data::literal::RoutineName;
mod op;
mod cond;
mod flatten;
/// A higher-level instruction
#[derive(Debug, Clone, Eq, PartialEq)]

@ -1,10 +1,10 @@
use crate::data::{
Wr, Rd,
literal::Label,
literal::DebugMsg, literal::Label,
literal::RoutineName,
literal::DebugMsg,
Rd,
Wr,
};
use crate::instr::{Cond};
use crate::instr::Cond;
/// A higher level simple opration
#[derive(Clone, Debug, Eq, PartialEq)]
@ -64,9 +64,11 @@ pub enum Op {
Or { dst: Wr, a: Rd, b: Rd },
Xor { dst: Wr, a: Rd, b: Rd },
Cpl { dst: Wr, a: Rd },
Rol { dst: Wr, a: Rd, n: Rd }, // Rotate (with wrap-around)
Rol { dst: Wr, a: Rd, n: Rd },
// Rotate (with wrap-around)
Ror { dst: Wr, a: Rd, n: Rd },
Lsl { dst: Wr, a: Rd, n: Rd }, // Shift
Lsl { dst: Wr, a: Rd, n: Rd },
// Shift
Lsr { dst: Wr, a: Rd, n: Rd },
Asr { dst: Wr, a: Rd, n: Rd },
}

@ -1,25 +1,26 @@
use crate::instr::{lower, Op};
pub mod data;
pub mod error;
pub mod instr;
pub mod parse;
pub mod patches;
use crate::instr::{Op, lower};
/// Parse a program from string and assemble a low level instruction sequence from it.
pub fn assemble(source : &str) -> Result<Vec<Op>, error::Error> {
pub fn assemble(source: &str) -> Result<Vec<Op>, error::Error> {
let parsed = parse::parse(source)?;
Ok(lower(parsed)?)
}
#[cfg(test)]
mod tests {
use crate::parse::{parse, parse_instructions};
use crate::instr::{HLOp, Op, Flatten, Instr, lower};
use crate::data::{Wr, DstDisp, Register, SrcDisp, Rd};
use crate::data::literal::{Addr, Label};
use std::sync::atomic::AtomicU32;
use crate::data::{DstDisp, Rd, Register, SrcDisp, Wr};
use crate::data::literal::{Addr, Label};
use crate::instr::{Flatten, HLOp, Instr, lower, Op};
use crate::instr::Cond;
use crate::parse::{parse, parse_instructions};
#[test]
fn test_parse_empty() {
@ -147,11 +148,11 @@ mod tests {
], parsed);
}
fn parse_single_instr(src : &str) -> anyhow::Result<Instr> {
fn parse_single_instr(src: &str) -> anyhow::Result<Instr> {
Ok(parse_instructions(vec![sexp::parse(src)?])?.remove(0))
}
fn parse_single_op(src : &str) -> anyhow::Result<Vec<HLOp>> {
fn parse_single_op(src: &str) -> anyhow::Result<Vec<HLOp>> {
let num = AtomicU32::new(0);
Ok(parse_single_instr(src)?.flatten(&num)?)
}
@ -187,14 +188,14 @@ mod tests {
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
)),
branches: None
branches: None,
},
Instr {
op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(2))),
)),
branches: None
branches: None,
}
]
),
@ -206,18 +207,18 @@ mod tests {
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
)),
branches: None
branches: None,
},
Instr {
op: HLOp::L(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
)),
branches: None
branches: None,
}
]
)
])
]),
}
, parsed);
}

@ -1,9 +1,10 @@
use std::sync::atomic::AtomicU32;
use crate::instr::{Routine, HLOp, Flatten};
use crate::error::Error;
pub use parse_instr::parse_instructions;
use parse_routines::parse_routines;
use std::sync::atomic::AtomicU32;
use crate::error::Error;
use crate::instr::{Flatten, HLOp, Routine};
use crate::parse::sexp_expect::expect_list;
mod parse_cond;
@ -13,9 +14,6 @@ mod parse_routines;
mod sexp_expect;
mod parse_op;
use parse_routines::parse_routines;
pub use parse_instr::parse_instructions;
pub fn parse(source: &str) -> Result<Vec<HLOp>, Error> {
let root = sexp::parse(source)?;

@ -1,8 +1,9 @@
use crate::parse::sexp_expect::{expect_list, expect_string_atom};
use sexp::Sexp;
use crate::instr::{Cond, Instr};
use crate::error::Error;
use crate::instr::{Cond, Instr};
use crate::parse::parse_instr::parse_instructions;
use crate::parse::sexp_expect::{expect_list, expect_string_atom};
use crate::patches::TryRemove;
pub fn parse_cond_branch(tok: Sexp) -> Result<(Cond, Vec<Instr>), Error> {

@ -1,12 +1,14 @@
use sexp::{Sexp, Atom};
use crate::data::{DataDisp, Rd, Wr, DstDisp, SrcDisp, reg};
use crate::error::Error;
use crate::data::literal::{Addr, Label};
use std::convert::TryFrom;
use sexp::{Atom, Sexp};
use crate::data::{DataDisp, DstDisp, Rd, reg, SrcDisp, Wr};
use crate::data::literal::{Addr, Label};
use crate::error::Error;
use crate::parse::sexp_expect::expect_string_atom;
/// Parse a label
pub fn parse_label(name : Option<Sexp>) -> Result<Label, Error> {
pub fn parse_label(name: Option<Sexp>) -> Result<Label, Error> {
let name = expect_string_atom(name)?;
Ok(Label::Named(name.trim_start_matches(':').into()))
}
@ -24,32 +26,32 @@ pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, Error> {
match &tok {
Sexp::Atom(Atom::I(val)) => {
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(*val) }))
},
}
Sexp::Atom(Atom::S(s)) => {
if s == "_" {
return Ok(DataDisp::Discard);
}
if let Some(reference) = s.strip_prefix('@') {
if reference.starts_with(|c : char| c.is_ascii_digit()) {
let val : u64 = parse_u64(reference)?;
if reference.starts_with(|c: char| c.is_ascii_digit()) {
let val: u64 = parse_u64(reference)?;
Ok(DataDisp::ImmediatePtr(Addr(val)))
} else {
Ok(DataDisp::RegisterPtr(reg::parse_reg(reference)?))
}
} else if s.starts_with(|c : char| c.is_ascii_digit()) {
} else if s.starts_with(|c: char| c.is_ascii_digit()) {
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(s)?) }))
} else {
Ok(DataDisp::Register(reg::parse_reg(s)?))
}
},
}
_ => {
Err(Error::Parse(format!("bad data disp: {:?}", tok).into()))
},
}
}
}
pub fn parse_u64(literal : &str) -> anyhow::Result<u64> {
pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
if let Some(hex) = literal.strip_prefix("0x") {
Ok(u64::from_str_radix(hex, 16)?)
} else if let Some(hex) = literal.strip_prefix("0b") {
@ -59,7 +61,7 @@ pub fn parse_u64(literal : &str) -> anyhow::Result<u64> {
}
}
pub fn parse_i64(literal : &str) -> anyhow::Result<i64> {
pub fn parse_i64(literal: &str) -> anyhow::Result<i64> {
if let Some(_value) = literal.strip_prefix("-") {
Ok(-1 * i64::try_from(parse_u64(literal)?)?)
} else {

@ -1,11 +1,11 @@
use sexp::Sexp;
use crate::instr::{Instr};
use crate::error::Error;
use crate::parse::parse_cond::{parse_cond_branch};
use crate::error::Error;
use crate::instr::Instr;
use crate::parse::parse_cond::parse_cond_branch;
use crate::parse::sexp_expect::{expect_list, expect_string_atom};
use crate::patches::SexpIsA;
use super::parse_op::parse_op;
pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, Error> {
@ -43,7 +43,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, Error> {
parsed.push(Instr {
op: parse_op(name.as_str(), far, arg_tokens.into_iter())?,
branches
branches,
});
}
Ok(parsed)

@ -1,11 +1,12 @@
use crate::instr::{HLOp, Op};
use sexp::Sexp;
use crate::data::{Rd, Wr};
use crate::data::literal::{Label, RoutineName};
use crate::error::Error;
use crate::data::literal::{RoutineName, Label};
use crate::parse::sexp_expect::expect_string_atom;
use crate::parse::parse_data::{parse_rd, parse_wr, parse_label};
use crate::instr::{HLOp, Op};
use crate::parse::parse_cond::parse_cond;
use crate::data::{Rd, Wr};
use crate::parse::parse_data::{parse_label, parse_rd, parse_wr};
use crate::parse::sexp_expect::expect_string_atom;
pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: impl ExactSizeIterator<Item=Sexp> + Clone) -> Result<HLOp, Error> {
Ok(match keyword {
@ -193,7 +194,7 @@ pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: impl ExactSizeIterator
4 => {
Op::Div {
dst: parse_wr(arg_tokens.next())?,
rem : parse_wr(arg_tokens.next())?,
rem: parse_wr(arg_tokens.next())?,
a: parse_rd(arg_tokens.next())?,
div: parse_rd(arg_tokens.next())?,
}

@ -1,8 +1,9 @@
use crate::parse::parse_instr::parse_instructions;
use crate::instr::Routine;
use crate::data::literal::RoutineName;
use sexp::Sexp;
use crate::data::literal::RoutineName;
use crate::error::Error;
use crate::instr::Routine;
use crate::parse::parse_instr::parse_instructions;
use crate::parse::sexp_expect::{expect_list, expect_string_atom};
use crate::patches::TryRemove;

@ -1,4 +1,5 @@
use sexp::{Sexp, Atom};
use sexp::{Atom, Sexp};
use crate::error::Error;
pub fn expect_list(expr: Option<Sexp>, allow_empty: bool) -> Result<Vec<Sexp>, Error> {

@ -1,5 +1,6 @@
pub use sexp_is_a::SexpIsA;
pub use try_remove::TryRemove;
mod try_remove;
mod sexp_is_a;
pub use try_remove::TryRemove;
pub use sexp_is_a::SexpIsA;

@ -2,9 +2,10 @@
extern crate log;
use simple_logger::SimpleLogger;
use runtime::run_thread::{RunThread, ThreadToken};
use runtime::program::Program;
use asm::data::literal::Addr;
use runtime::program::Program;
use runtime::run_thread::{RunThread, ThreadToken};
fn main() {
SimpleLogger::new().init().unwrap();
@ -21,7 +22,7 @@ fn main() {
)
)
";*/
/*
/*
let program = "
(
(main

@ -1,10 +1,13 @@
use crate::run_thread::{RunThread};
use asm::instr::{Op};
use std::ops::Rem;
use num_traits::PrimInt;
use asm::data::literal::Addr;
use asm::instr::Op;
use crate::fault::Fault;
use crate::frame::StackFrame;
use asm::data::literal::{Addr};
use std::ops::{Rem};
use num_traits::PrimInt;
use crate::run_thread::RunThread;
pub type CyclesSpent = usize;

@ -1,15 +1,16 @@
use thiserror::Error;
// use super::span::MemorySpan;
// use crate::run_thread::ThreadToken;
// use crate::mlock::ClaimId;
use asm::data::literal::{DebugMsg, RoutineName, Label};
use asm::data::literal::{DebugMsg, Label, RoutineName};
use asm::data::Register;
#[derive(Error,Debug)]
#[derive(Error, Debug)]
pub enum Fault {
#[error("Bad instruction at addr {addr:#10x}: {cause}")]
BadInstruction {
addr : u32,
addr: u32,
cause: InstrError,
},
@ -64,7 +65,7 @@ pub enum Fault {
CallStackUnderflow,
}
#[derive(Error,Debug)]
#[derive(Error, Debug)]
pub enum InstrError {
#[error("Instruction not recognized")]
UnknownInstruction,

@ -1,12 +1,10 @@
use asm::data::{DstDisp, Rd, Register, SrcDisp, Wr};
use asm::data::literal::{Addr, Value};
use asm::data::{Rd, SrcDisp, Register, Wr, DstDisp};
use crate::fault::Fault;
use status::StatusFlags;
use crate::fault::Fault;
mod status;
use status::StatusFlags;
pub const REG_COUNT: usize = 8;

@ -1,6 +1,7 @@
use std::fmt::{Display, Formatter};
use std::fmt;
use asm::data::literal::{Value, is_positive, is_negative};
use asm::data::literal::{is_negative, is_positive, Value};
use asm::instr::Cond;
#[derive(Default, Clone, Debug)]
@ -44,7 +45,7 @@ impl StatusFlags {
val
}
pub fn load(&mut self, val : Value) {
pub fn load(&mut self, val: Value) {
if val & 0x01 != 0 { self.equal = true; }
if val & 0x02 != 0 { self.lower = true; }
if val & 0x04 != 0 { self.greater = true; }

@ -1,4 +1,5 @@
#[macro_use] extern crate log;
#[macro_use]
extern crate log;
pub mod run_thread;
// pub mod mlock;

@ -1,8 +1,9 @@
use std::sync::atomic::{AtomicU32, Ordering};
use std::fmt;
use std::fmt::Formatter;
use crate::run_thread::ThreadToken;
use std::sync::atomic::{AtomicU32, Ordering};
use crate::fault::Fault;
use crate::run_thread::ThreadToken;
use crate::span::MemorySpan;
/// Records memory claims and protects from illegal access
@ -85,7 +86,7 @@ impl MemoryGuard {
/// Release all owned by a thread, with claim ID >= a given value
/// (return from a subroutine)
pub fn release_owned_after(&mut self, owner: ThreadToken, epoch : ClaimId) {
pub fn release_owned_after(&mut self, owner: ThreadToken, epoch: ClaimId) {
self.claims.retain(|c| c.owner != owner || c.id >= epoch);
}
}

@ -1,8 +1,10 @@
use asm::instr::{Op};
use asm::data::literal::{Addr, RoutineName, Label};
use crate::fault::Fault;
use std::collections::HashMap;
use asm::data::literal::{Addr, Label, RoutineName};
use asm::instr::Op;
use crate::fault::Fault;
#[derive(Clone, Debug)]
pub struct Program {
ops: Vec<Op>,

@ -1,16 +1,13 @@
use std::time::Duration;
use std::thread::JoinHandle;
use std::time::Duration;
use asm::data::literal::{Addr};
use asm::data::literal::Addr;
use crate::exec::EvalRes;
use crate::frame::StackFrame;
use crate::program::Program;
use crate::exec::EvalRes;
const CYCLE_TIME : Duration = Duration::from_millis(0);
const CYCLE_TIME: Duration = Duration::from_millis(0);
//const CYCLE_TIME : Duration = Duration::from_millis(100);
#[derive(Clone, Copy, Eq, PartialEq, Debug, Ord, PartialOrd)]

@ -1,8 +1,6 @@
use asm::data::literal::Addr;
#[derive(Debug,Clone,Copy)]
#[derive(Debug, Clone, Copy)]
pub struct MemorySpan {
addr: usize,
len: usize,

Loading…
Cancel
Save