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
|
||||
|
||||
- 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))
|
||||
}
|
||||
|
||||
+16
-10
@@ -55,17 +55,21 @@ 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 == ®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() {
|
||||
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);
|
||||
}
|
||||
|
||||
return Ok(ParseRes::ParsedNone);
|
||||
}
|
||||
@@ -75,8 +79,10 @@ 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() {
|
||||
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)
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user