Croissant Runtime
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
crsn/crsn/src/builtin/defs.rs

189 lines
5.0 KiB

use sexp::SourcePosition;
use crate::asm::data::{Rd, RdObj, Wr, RdWr};
use crate::asm::data::literal::{DebugMsg, Label, RoutineName, Value};
use crate::asm::instr::Op;
use crate::asm::instr::op::OpKind;
use std::fmt::{Display, Formatter};
use std::fmt;
use crate::asm::error::CrsnError;
#[derive(Debug)]
pub enum Barrier {
/// Barrier that logically opens a section that cannot be jumped into, typically a routine
Open(Label),
/// Closing counterpart to the Open barrier
Close(Label),
/// Stand-alone barrier
Standalone,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SleepUnit {
Usec, Msec, Sec
}
impl SleepUnit {
pub fn micros(self) -> u64 {
match self {
SleepUnit::Usec => 1,
SleepUnit::Msec => 1000,
SleepUnit::Sec => 1000000,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum LdsValue {
Values(Vec<Rd>),
Handle(RdObj),
Chars(String),
}
/// Instruction's bit mask
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BitMask {
/// Operation bit width
pub width: u32,
/// Destination (or first operand's) offset
pub dst_pos: u32,
/// Source (or second operand's) offset
pub src_pos: u32,
/// Source 2 offset (if used)
pub src2_pos: u32,
}
impl Display for BitMask {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.is_full() {
return Ok(());
}
write!(f, "{}", self.width)?;
if self.src_pos != 0 || self.dst_pos != 0 {
write!(f, "/{}", self.dst_pos)?;
}
if self.src_pos != 0 {
write!(f, "/{}", self.src_pos)?;
}
Ok(())
}
}
impl Default for BitMask {
fn default() -> Self {
Self {
width: 64,
dst_pos: 0,
src_pos: 0,
src2_pos: 0,
}
}
}
impl BitMask {
pub fn full() -> Self {
Self::default()
}
pub fn validate(&self, pos: &SourcePosition) -> Result<(), CrsnError> {
#[allow(non_snake_case)]
let MAXWIDTH = (std::mem::size_of::<Value>() as u32)*8;
if self.width == 0 || self.width > MAXWIDTH {
return Err(CrsnError::Parse(format!("Bit width must be 1-{}", MAXWIDTH).into(), pos.clone()));
}
// Validation
if self.src_pos + self.width > MAXWIDTH {
return Err(CrsnError::Parse("Invalid source bit mask".into(), pos.clone()));
}
if self.src2_pos + self.width > MAXWIDTH {
return Err(CrsnError::Parse("Invalid source 2 bit mask".into(), pos.clone()));
}
if self.dst_pos + self.width > MAXWIDTH {
return Err(CrsnError::Parse("Invalid destination bit mask".into(), pos.clone()));
}
Ok(())
}
pub fn is_full(self) -> bool {
self.width == 64
}
}
#[derive(Debug)]
pub enum BuiltinOp {
/// Do nothing (costs one cycle)
Nop,
/// Stop execution
Halt,
/// Sleep
Sleep {
count: Rd,
unit_us: SleepUnit,
},
/// Mark a jump target.
Label(Label),
/// Jump to a label
Jump(Label),
/// Mark a far jump target (can be jumped to from another routine).
/// This label is preserved in optimized code.
FarLabel(Label),
/// Jump to a label that can be in another function
FarJump(Label),
/// Call a routine with arguments.
/// The arguments are passed as argX. Return values are stored in resX registers.
Call(RoutineName, Vec<Rd>),
/// Exit the current routine with return values
Ret(Vec<Rd>),
/// Mark a routine entry point (call target).
/// The RoutineName struct includes its arity
Routine(RoutineName),
/// Skip backward or forward. The skip count can be defined by an argument.
Skip(Rd),
/// Deny jumps, skips and run across this address, producing a run-time fault.
Barrier {
kind: Barrier,
msg: Option<DebugMsg>,
},
/// Generate a run-time fault with a debugger message
Fault(Option<DebugMsg>),
/// Deallocate an extension object.
/// The object is released and the handle becomes invalid.
Delete(RdObj),
/// Move a value
Load { dst: Wr, src: Rd },
/// Move bits of a value
LoadBits { dst: Wr, a: Rd, b: Rd, mask: BitMask },
/// Move N values
LoadMultiple { dst: Wr, src: Rd, count: Rd },
/// Move values from a string or integer list
LoadSequence { dst: Wr, value: LdsValue },
/// Swap two registers
Exchange { a: RdWr, b: RdWr, mask: BitMask },
/// Swap if equal to a pattern
CompareSwap { dst: RdWr, expected: Rd, src: Rd, mask: BitMask },
/// Store runtime status to a register
StoreFlags { dst: Wr },
/// Load runtime status from a register
LoadFlags { src: Rd },
}
impl BuiltinOp {
pub fn into_op(self: BuiltinOp, pos: SourcePosition) -> Op {
Op {
kind: self.into(),
pos,
cond: None,
}
}
}
impl From<BuiltinOp> for OpKind {
fn from(bo: BuiltinOp) -> Self {
OpKind::BuiltIn(bo)
}
}