forked from MightyPork/crsn
change register count to 15, add global registers
This commit is contained in:
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-11
@@ -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 == ®ister) {
|
||||||
|
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 == ®ister) {
|
||||||
|
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased (globally) as \"{}\"!", register, name).into(), rpos));
|
||||||
}
|
}
|
||||||
|
|
||||||
if pstate.reg_aliases.iter().find(|x| x.1 == ®ister).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)
|
||||||
|
)
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user