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
- 8 general purpose registers `r0`-`r7`
- 8 argument registers `arg0`-`arg7`
- 8 result registers `res0`-`res7`
- 16 general purpose registers `r0`-`r15`
- 16 argument registers `arg0`-`arg15`
- 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
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
(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)
; Define a constant. These are valid in the whole program.

@ -14,6 +14,17 @@ pub enum Register {
Res(u8),
/// General purpose register
Gen(u8),
/// Global register
Global(u8),
}
impl Register {
pub fn is_global(self) -> bool {
match self {
Register::Global(_) => true,
_ => false,
}
}
}
impl Display for Register {
@ -22,6 +33,7 @@ impl Display for Register {
Register::Arg(n) => write!(f, "arg{}", n),
Register::Res(n) => write!(f, "res{}", 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)?;
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 {
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 {
reg_aliases: Default::default(),
reg_alias_stack: vec![],
global_reg_aliases: Default::default(),
constants: Default::default(),
}),
};

@ -30,6 +30,9 @@ pub struct ParserContext<'a> {
#[derive(Default, Debug)]
pub struct ParserState {
/// Register aliases valid globally
pub global_reg_aliases: HashMap<RegisterAlias, Register>,
/// Register aliases within the routine
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();
if let Some(reg) = pstate.reg_aliases.get(reference) {
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)?;
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 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 {
Ok(DataDisp::RegObject(reg))
}
@ -136,6 +140,8 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
/* register aliases */
if let Some(val) = pstate.reg_aliases.get(&s) {
return Ok(DataDisp::Register(*val));
} else if let Some(val) = pstate.global_reg_aliases.get(&s) {
return Ok(DataDisp::Register(*val));
}
/* register */
@ -144,6 +150,8 @@ pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnE
let pstate = pcx.state.borrow();
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 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 {
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();
if pstate.reg_aliases.contains_key(&alias) {
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into(), rpos));
}
if pstate.constants.contains_key(&alias) {
} else if pstate.global_reg_aliases.contains_key(&alias) {
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined (global)!", alias).into(), rpos));
} else if pstate.constants.contains_key(&alias) {
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() {
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into(), rpos));
if register.is_global() {
pstate.global_reg_aliases.insert(alias, register);
} else {
pstate.reg_aliases.insert(alias, register);
}
pstate.reg_aliases.insert(alias, register);
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();
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);
}
@ -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();
if pstate.constants.contains_key(&name) {
return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into(), namepos));
}
if pstate.reg_aliases.contains_key(&name) {
} else if pstate.reg_aliases.contains_key(&name) {
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);

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

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

@ -17,6 +17,8 @@ pub struct RunState {
pub frame: StackFrame,
/// Call stack
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
pub ext_data: ExtensionDataStore,
}
@ -95,6 +97,7 @@ impl RunState {
/// Read a `Rd` value
pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> {
let rd = rd.into();
// TODO dedupe
match rd.0 {
RdData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) {
@ -104,6 +107,14 @@ impl RunState {
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::Register(Register::Arg(rn)) => {
if likely(rn < REG_COUNT as u8) {
@ -167,6 +178,7 @@ impl RunState {
trace!("WR {:?} := {}", wr, val);
// TODO dedupe
match wr.0 {
WrData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) {
@ -176,6 +188,14 @@ impl RunState {
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)) => {
if likely(rn < REG_COUNT as u8) {
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