use core::fmt::{self, Debug, Formatter};
use amplify::confinement::ConfinedVec;
use super::{Site, SiteId, Status};
use crate::{Register, LIB_NAME_ALUVM};
pub const CALL_STACK_SIZE_MAX: u16 = 0xFF;
pub trait CoreExt: Clone + Debug {
type Reg: Register;
type Config: Default;
fn with(config: Self::Config) -> Self;
fn get(&self, reg: Self::Reg) -> Option<<Self::Reg as Register>::Value>;
fn clr(&mut self, reg: Self::Reg);
fn set(&mut self, reg: Self::Reg, val: <Self::Reg as Register>::Value) {
self.put(reg, Some(val))
}
fn put(&mut self, reg: Self::Reg, val: Option<<Self::Reg as Register>::Value>);
fn reset(&mut self);
}
pub trait Supercore<Subcore> {
fn subcore(&self) -> Subcore;
fn merge_subcore(&mut self, subcore: Subcore);
}
#[derive(Clone)]
pub struct Core<
Id: SiteId,
Cx: CoreExt,
const CALL_STACK_SIZE: usize = { CALL_STACK_SIZE_MAX as usize },
> {
pub(super) ch: bool,
pub(super) ck: Status,
pub(super) cf: u64,
pub(super) co: Status,
pub(super) cy: u16,
pub(super) ca: u64,
pub(super) cl: Option<u64>,
pub(super) cs: ConfinedVec<Site<Id>, 0, CALL_STACK_SIZE>,
pub cx: Cx,
}
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_ALUVM)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CoreConfig {
pub halt: bool,
pub complexity_lim: Option<u64>,
}
impl Default for CoreConfig {
fn default() -> Self { CoreConfig { halt: true, complexity_lim: None } }
}
impl<Id: SiteId, Cx: CoreExt, const CALL_STACK_SIZE: usize> Default
for Core<Id, Cx, CALL_STACK_SIZE>
{
fn default() -> Self { Core::new() }
}
impl<Id: SiteId, Cx: CoreExt, const CALL_STACK_SIZE: usize> Core<Id, Cx, CALL_STACK_SIZE> {
#[inline]
pub fn new() -> Self {
assert!(CALL_STACK_SIZE <= CALL_STACK_SIZE_MAX as usize, "Call stack size is too large");
Core::with(default!(), default!())
}
pub fn with(config: CoreConfig, cx_config: Cx::Config) -> Self {
assert!(CALL_STACK_SIZE <= CALL_STACK_SIZE_MAX as usize, "Call stack size is too large");
Core {
ch: config.halt,
ck: Status::Ok,
cf: 0,
co: Status::Ok,
cy: 0,
ca: 0,
cl: config.complexity_lim,
cs: ConfinedVec::with_capacity(CALL_STACK_SIZE),
cx: Cx::with(cx_config),
}
}
pub fn reset(&mut self) {
let mut new = Self::new();
new.ch = self.ch;
new.cl = self.cl;
new.cx.reset();
*self = new;
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl<Id: SiteId, Cx: CoreExt, const CALL_STACK_SIZE: usize> Debug
for Core<Id, Cx, CALL_STACK_SIZE>
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let (sect, reg, val, reset) = if f.alternate() {
("\x1B[0;4;1m", "\x1B[0;1m", "\x1B[0;32m", "\x1B[0m")
} else {
("", "", "", "")
};
writeln!(f, "{sect}C-regs:{reset}")?;
write!(f, "{reg}CH{reset} {val}{}{reset}, ", self.ch)?;
write!(f, "{reg}CK{reset} {val}{}{reset}, ", self.ck)?;
write!(f, "{reg}CF{reset} {val}{}{reset}, ", self.cf)?;
write!(f, "{reg}CO{reset} {val}{}{reset}, ", self.co)?;
write!(f, "{reg}CY{reset} {val}{}{reset}, ", self.cy)?;
write!(f, "{reg}CA{reset} {val}{}{reset}, ", self.ca)?;
let cl = self
.cl
.map(|v| v.to_string())
.unwrap_or_else(|| "~".to_string());
write!(f, "{reg}CL{reset} {val}{cl}{reset}, ")?;
write!(f, "{reg}CP{reset} {val}{}{reset}, ", self.cp())?;
write!(f, "\n{reg}CS{reset} {val}{reset}")?;
for item in &self.cs {
write!(f, "{} ", item)?;
}
writeln!(f)?;
Debug::fmt(&self.cx, f)
}
}
impl<Id: SiteId, Cx: CoreExt + Supercore<Cx2>, Cx2: CoreExt, const CALL_STACK_SIZE: usize>
Supercore<Core<Id, Cx2, CALL_STACK_SIZE>> for Core<Id, Cx, CALL_STACK_SIZE>
{
fn subcore(&self) -> Core<Id, Cx2, CALL_STACK_SIZE> {
Core {
ch: self.ch,
ck: self.ck,
cf: self.cf,
co: self.co,
cy: self.cy,
ca: self.ca,
cl: self.cl,
cs: self.cs.clone(),
cx: self.cx.subcore(),
}
}
fn merge_subcore(&mut self, subcore: Core<Id, Cx2, CALL_STACK_SIZE>) {
assert_eq!(self.ch, subcore.ch);
self.ck = subcore.ck;
self.co = subcore.co;
self.cf = subcore.cf;
self.cy = subcore.cy;
self.ca = subcore.ca;
assert_eq!(self.cl, subcore.cl);
self.cs = subcore.cs;
self.cx.merge_subcore(subcore.cx);
}
}