change register count to 15, add global registers

pull/21/head
Ondřej Hruška 4 years ago
parent 9254635fd7
commit 74e3716ce4
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 13
      README.md
  2. 18
      crsn/src/asm/data/reg.rs
  3. 1
      crsn/src/asm/mod.rs
  4. 3
      crsn/src/asm/parse/mod.rs
  5. 8
      crsn/src/asm/parse/parse_data.rs
  6. 28
      crsn/src/builtin/parse.rs
  7. 2
      crsn/src/runtime/frame.rs
  8. 3
      crsn/src/runtime/run_thread.rs
  9. 20
      crsn/src/runtime/run_thread/state.rs
  10. 11
      examples/globals.csn
  11. 12
      examples/globals_sym.csn

@ -41,9 +41,12 @@ The runtime is built as a register machine with a stack and status flags.
## Registers ## Registers
- 8 general purpose registers `r0`-`r7` - 16 general purpose registers `r0`-`r15`
- 8 argument registers `arg0`-`arg7` - 16 argument registers `arg0`-`arg15`
- 8 result registers `res0`-`res7` - 16 result registers `res0`-`res15`
- 16 global registers `g0`-`g15`
Global registers are accessible everywhere. Other registers are only valid within an execution frame (in a routine, or the initial scope).
All registers are 64-bit unsigned integers that can be treated as All registers are 64-bit unsigned integers that can be treated as
signed, if you want to. Overflow is allowed and reported by status flags. signed, if you want to. Overflow is allowed and reported by status flags.
@ -336,7 +339,9 @@ Jumping to a label is always safer than a manual skip.
; Load status flags from a register ; Load status flags from a register
(ldf Rd) (ldf Rd)
; Define a register alias. The alias is only valid in the current routine or in the root of the program. ; Define a register alias.
; The alias is only valid in the current routine or in the root of the program.
; However, if the register is a global register, then the alias is valid everywhere.
(sym SYM REG) (sym SYM REG)
; Define a constant. These are valid in the whole program. ; Define a constant. These are valid in the whole program.

@ -14,6 +14,17 @@ pub enum Register {
Res(u8), Res(u8),
/// General purpose register /// General purpose register
Gen(u8), Gen(u8),
/// Global register
Global(u8),
}
impl Register {
pub fn is_global(self) -> bool {
match self {
Register::Global(_) => true,
_ => false,
}
}
} }
impl Display for Register { impl Display for Register {
@ -22,6 +33,7 @@ impl Display for Register {
Register::Arg(n) => write!(f, "arg{}", n), Register::Arg(n) => write!(f, "arg{}", n),
Register::Res(n) => write!(f, "res{}", n), Register::Res(n) => write!(f, "res{}", n),
Register::Gen(n) => write!(f, "r{}", n), Register::Gen(n) => write!(f, "r{}", n),
Register::Global(n) => write!(f, "g{}", n),
} }
} }
} }
@ -46,6 +58,12 @@ pub fn parse_reg(name: &str, at: &SourcePosition) -> Result<Register, CrsnError>
} }
let val: u8 = rn.parse().err_pos(at)?; let val: u8 = rn.parse().err_pos(at)?;
Ok(Register::Gen(val)) Ok(Register::Gen(val))
} else if let Some(rn) = name.strip_prefix("g") {
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
return Err(CrsnError::Parse(format!("Bad register: {}", name).into(), at.clone()))?;
}
let val: u8 = rn.parse().err_pos(at)?;
Ok(Register::Global(val))
} else { } else {
Err(CrsnError::Parse(format!("Bad reg name: {}", name).into(), at.clone()))? Err(CrsnError::Parse(format!("Bad reg name: {}", name).into(), at.clone()))?
} }

@ -39,6 +39,7 @@ pub fn assemble(source: &str, uniq : &CrsnUniq, mut parsers: Vec<Box<dyn CrsnExt
state: RefCell::new(ParserState { state: RefCell::new(ParserState {
reg_aliases: Default::default(), reg_aliases: Default::default(),
reg_alias_stack: vec![], reg_alias_stack: vec![],
global_reg_aliases: Default::default(),
constants: Default::default(), constants: Default::default(),
}), }),
}; };

@ -30,6 +30,9 @@ pub struct ParserContext<'a> {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ParserState { pub struct ParserState {
/// Register aliases valid globally
pub global_reg_aliases: HashMap<RegisterAlias, Register>,
/// Register aliases within the routine /// Register aliases within the routine
pub reg_aliases: HashMap<RegisterAlias, Register>, pub reg_aliases: HashMap<RegisterAlias, Register>,

@ -110,12 +110,16 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
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) {
return Ok(DataDisp::RegObject(*reg)) return Ok(DataDisp::RegObject(*reg))
} else if let Some(reg) = pstate.global_reg_aliases.get(reference) {
return Ok(DataDisp::RegObject(*reg))
} }
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 if pstate.global_reg_aliases.values().find(|v| **v == reg).is_some() {
Err(CrsnError::Parse(format!("Global sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos))
} else { } else {
Ok(DataDisp::RegObject(reg)) Ok(DataDisp::RegObject(reg))
} }
@ -136,6 +140,8 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
/* register aliases */ /* register aliases */
if let Some(val) = pstate.reg_aliases.get(&s) { if let Some(val) = pstate.reg_aliases.get(&s) {
return Ok(DataDisp::Register(*val)); return Ok(DataDisp::Register(*val));
} else if let Some(val) = pstate.global_reg_aliases.get(&s) {
return Ok(DataDisp::Register(*val));
} }
/* register */ /* register */
@ -144,6 +150,8 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
let pstate = pcx.state.borrow(); let pstate = pcx.state.borrow();
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 if pstate.global_reg_aliases.values().find(|v| **v == reg).is_some() {
Err(CrsnError::Parse(format!("Global sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos))
} else { } else {
Ok(DataDisp::Register(reg)) Ok(DataDisp::Register(reg))
} }

@ -55,18 +55,22 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
let mut pstate = pcx.state.borrow_mut(); let mut pstate = pcx.state.borrow_mut();
if pstate.reg_aliases.contains_key(&alias) { if pstate.reg_aliases.contains_key(&alias) {
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into(), rpos)); return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into(), rpos));
} } else if pstate.global_reg_aliases.contains_key(&alias) {
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined (global)!", alias).into(), rpos));
if pstate.constants.contains_key(&alias) { } else if pstate.constants.contains_key(&alias) {
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into(), aliaspos)); return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into(), aliaspos));
} else if let Some((name, _)) = pstate.reg_aliases.iter().find(|x| x.1 == &register) {
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased as \"{}\"!", register, name).into(), rpos));
} else if let Some((name, _)) = pstate.global_reg_aliases.iter().find(|x| x.1 == &register) {
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased (globally) as \"{}\"!", register, name).into(), rpos));
} }
if pstate.reg_aliases.iter().find(|x| x.1 == &register).is_some() { if register.is_global() {
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into(), rpos)); pstate.global_reg_aliases.insert(alias, register);
} else {
pstate.reg_aliases.insert(alias, register);
} }
pstate.reg_aliases.insert(alias, register);
return Ok(ParseRes::ParsedNone); return Ok(ParseRes::ParsedNone);
} }
@ -75,7 +79,9 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
let mut pstate = pcx.state.borrow_mut(); let mut pstate = pcx.state.borrow_mut();
if pstate.reg_aliases.remove(&alias.0).is_none() { if pstate.reg_aliases.remove(&alias.0).is_none() {
return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias.0).into(), alias.1)); if pstate.global_reg_aliases.remove(&alias.0).is_none() {
return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias.0).into(), alias.1));
}
} }
return Ok(ParseRes::ParsedNone); return Ok(ParseRes::ParsedNone);
} }
@ -87,10 +93,10 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
let mut pstate = pcx.state.borrow_mut(); let mut pstate = pcx.state.borrow_mut();
if pstate.constants.contains_key(&name) { if pstate.constants.contains_key(&name) {
return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into(), namepos)); return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into(), namepos));
} } else if pstate.reg_aliases.contains_key(&name) {
if pstate.reg_aliases.contains_key(&name) {
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into(), namepos)); return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into(), namepos));
} else if pstate.global_reg_aliases.contains_key(&name) {
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a global register alias!", name).into(), namepos));
} }
pstate.constants.insert(name, value); pstate.constants.insert(name, value);

@ -4,7 +4,7 @@ use crate::asm::data::literal::{Addr, Value};
pub(crate) mod status; pub(crate) mod status;
pub const REG_COUNT: usize = 8; pub const REG_COUNT: usize = 16;
pub type CallStack = Vec<StackFrame>; pub type CallStack = Vec<StackFrame>;

@ -9,7 +9,7 @@ pub use state::RunState;
use crate::asm::data::literal::Addr; use crate::asm::data::literal::Addr;
use crate::module::{EvalRes, CrsnUniq}; 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, REG_COUNT};
use crate::runtime::program::Program; use crate::runtime::program::Program;
#[derive(Clone, Copy, Eq, PartialEq, Debug, Ord, PartialOrd)] #[derive(Clone, Copy, Eq, PartialEq, Debug, Ord, PartialOrd)]
@ -48,6 +48,7 @@ impl RunThread {
thread_info: ti.clone(), thread_info: ti.clone(),
frame: StackFrame::new(params.pc, params.args), frame: StackFrame::new(params.pc, params.args),
call_stack: vec![], call_stack: vec![],
global_regs: [0; REG_COUNT],
ext_data: Default::default(), ext_data: Default::default(),
}; };

@ -17,6 +17,8 @@ pub struct RunState {
pub frame: StackFrame, pub frame: StackFrame,
/// Call stack /// Call stack
pub call_stack: CallStack, pub call_stack: CallStack,
/// General purpose registers that stay valid for the entire run-time of the thread
pub global_regs: [Value; REG_COUNT],
/// Extension data /// Extension data
pub ext_data: ExtensionDataStore, pub ext_data: ExtensionDataStore,
} }
@ -95,6 +97,7 @@ impl RunState {
/// Read a `Rd` value /// Read a `Rd` value
pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> { pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> {
let rd = rd.into(); let rd = rd.into();
// TODO dedupe
match rd.0 { match rd.0 {
RdData::Register(Register::Gen(rn)) => { RdData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) { if likely(rn < REG_COUNT as u8) {
@ -104,6 +107,14 @@ impl RunState {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
} }
} }
RdData::Register(Register::Global(rn)) => {
if likely(rn < REG_COUNT as u8) {
trace!("Rd {:?} = {}", rd, self.global_regs[rn as usize]);
Ok(self.global_regs[rn as usize])
} else {
Err(Fault::RegisterNotExist { reg: Register::Global(rn) })
}
}
RdData::Immediate(v) => Ok(v), RdData::Immediate(v) => Ok(v),
RdData::Register(Register::Arg(rn)) => { RdData::Register(Register::Arg(rn)) => {
if likely(rn < REG_COUNT as u8) { if likely(rn < REG_COUNT as u8) {
@ -167,6 +178,7 @@ impl RunState {
trace!("WR {:?} := {}", wr, val); trace!("WR {:?} := {}", wr, val);
// TODO dedupe
match wr.0 { match wr.0 {
WrData::Register(Register::Gen(rn)) => { WrData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) { if likely(rn < REG_COUNT as u8) {
@ -176,6 +188,14 @@ impl RunState {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
} }
} }
WrData::Register(Register::Global(rn)) => {
if likely(rn < REG_COUNT as u8) {
self.global_regs[rn as usize] = val;
Ok(())
} else {
Err(Fault::RegisterNotExist { reg: Register::Global(rn) })
}
}
WrData::Register(Register::Arg(rn)) => { WrData::Register(Register::Arg(rn)) => {
if likely(rn < REG_COUNT as u8) { if likely(rn < REG_COUNT as u8) {
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) }) Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })

@ -0,0 +1,11 @@
(
(ld g0 15)
(call add_cat)
(cmp g0 16
(ne? (fault)))
(proc add_cat
(add g0 1)
(ret)
)
)

@ -0,0 +1,12 @@
(
(sym cats g0)
(ld cats 15)
(call add_cat)
(cmp cats 16
(ne? (fault)))
(proc add_cat
(add cats 1)
(ret)
)
)
Loading…
Cancel
Save