Skip to content

Commit

Permalink
zkaluvm: inception :)
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Oct 21, 2024
1 parent a03daaf commit 4891df0
Show file tree
Hide file tree
Showing 19 changed files with 528 additions and 189 deletions.
27 changes: 16 additions & 11 deletions src/core/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
// limitations under the License.

use core::fmt::{self, Debug, Display, Formatter};
use core::str::FromStr;

//#[cfg(feature = "str")]
//use crate::util::ByteStr;
Expand All @@ -46,31 +47,34 @@ impl Status {
pub fn is_ok(self) -> bool { self == Status::Ok }
}

pub trait SiteId: Copy + Ord + Debug + Display + FromStr {}

/// Location inside the instruction sequence which can be executed by the core.
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub struct Site<Id> {
pub struct Site<Id: SiteId> {
pub prog_id: Id,
pub offset: u16,
}

impl<Id> Site<Id> {
impl<Id: SiteId> Site<Id> {
#[inline]
pub fn new(prog_id: Id, offset: u16) -> Self { Self { prog_id, offset } }
}

impl<Id: Display> Display for Site<Id> {
impl<Id: SiteId> Display for Site<Id> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{}:{:04X}.h", self.prog_id, self.offset) }
}

/// Registers of a single CPU/VM core.
#[derive(Clone)]
pub struct AluCore<Id> {
pub struct AluCore<Id: SiteId> {
// ============================================================================================
// Arithmetic integer registers (ALU64 ISA).
pub(super) a8: [Option<u8>; 32],
pub(super) a16: [Option<u16>; 32],
pub(super) a32: [Option<u32>; 32],
pub(super) a64: [Option<u64>; 32],
pub(super) a128: [Option<u128>; 32],

// ============================================================================================
// Arithmetic integer registers (A1024 ISA extension).
Expand Down Expand Up @@ -139,7 +143,7 @@ pub struct AluCore<Id> {
cf: Status,

/// Test register, which acts as boolean test result (also a carry flag).
pub(super) ct: bool,
pub(super) co: bool,

/// Counts number of jumps (possible cycles). The number of jumps is limited by 2^16 per
/// script.
Expand Down Expand Up @@ -197,7 +201,7 @@ impl Default for CoreConfig {
}
}

impl<Id> AluCore<Id> {
impl<Id: SiteId> AluCore<Id> {
/// Initializes registers. Sets `st0` to `true`, counters to zero, call stack to empty and the
/// rest of registers to `None` value.
///
Expand All @@ -212,13 +216,14 @@ impl<Id> AluCore<Id> {
a16: Default::default(),
a32: Default::default(),
a64: Default::default(),
a128: Default::default(),

//#[cfg(feature = "str")]
//b: Default::default(),
ch: config.halt,
ck: Status::Ok,
cf: Status::Ok,
ct: false,
co: false,
cy: 0,
ca: 0,
cl: config.complexity_lim,
Expand All @@ -229,15 +234,15 @@ impl<Id> AluCore<Id> {
}

/// Microcode for flag registers.
impl<Id> AluCore<Id> {
impl<Id: SiteId> AluCore<Id> {
/// Return whether check register `ck` was set to a failed state for at least once.
pub fn had_failed(&self) -> bool { self.cf == Status::Fail }

/// Return complexity limit value.
pub fn cl(&self) -> Option<u64> { return self.cl }
pub fn cl(&self) -> Option<u64> { return self.cl; }
}

impl<Id: Display> Debug for AluCore<Id> {
impl<Id: SiteId> Debug for AluCore<Id> {
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 { ("", "", "", "") };
Expand All @@ -246,7 +251,7 @@ impl<Id: Display> Debug for AluCore<Id> {
write!(f, "{reg}ch{reset} {val}{}, ", self.ch)?;
write!(f, "{reg}ck{reset} {val}{}, ", self.ck)?;
write!(f, "{reg}cf{reset} {val}{}, ", self.cf)?;
write!(f, "{reg}ct{reset} {val}{}, ", self.ct)?;
write!(f, "{reg}ct{reset} {val}{}, ", self.co)?;
write!(f, "{reg}cy{reset} {val}{}, ", self.cy)?;
write!(f, "{reg}ca{reset} {val}{}, ", self.ca)?;
let cl = self
Expand Down
90 changes: 74 additions & 16 deletions src/core/alu64.rs → src/core/microcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use core::iter;

use amplify::num::{u3, u5};

use super::{AluCore, Idx32, Status};
use super::{AluCore, Idx32, SiteId, Status};

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
pub enum A {
Expand All @@ -40,6 +40,8 @@ pub enum A {
A32,
#[display("A64")]
A64,
#[display("A128")]
A128,
}

impl From<u3> for A {
Expand All @@ -49,8 +51,9 @@ impl From<u3> for A {
1 => A::A16,
2 => A::A32,
3 => A::A64,
4 => A::A128,
_ => panic!(
"A registers above A64 are not supported under the current architecture. Consider using architecture \
"A registers above A128 are not supported under the current architecture. Consider using architecture \
extension."
),
}
Expand All @@ -67,6 +70,8 @@ pub enum RegA {
A32(IdxA),
#[display("A64{0}")]
A64(IdxA),
#[display("A128{0}")]
A128(IdxA),
}

impl RegA {
Expand All @@ -76,6 +81,7 @@ impl RegA {
A::A16 => Self::A16(idx),
A::A32 => Self::A32(idx),
A::A64 => Self::A64(idx),
A::A128 => Self::A128(idx),
}
}

Expand All @@ -85,6 +91,17 @@ impl RegA {
RegA::A16(_) => 16,
RegA::A32(_) => 32,
RegA::A64(_) => 64,
RegA::A128(_) => 128,
}
}

pub fn a(self) -> A {
match self {
RegA::A8(_) => A::A8,
RegA::A16(_) => A::A16,
RegA::A32(_) => A::A32,
RegA::A64(_) => A::A64,
RegA::A128(_) => A::A128,
}
}
}
Expand Down Expand Up @@ -123,11 +140,20 @@ impl IdxA {
}

/// Microcode for flag registers.
impl<Id> AluCore<Id> {
/// Returns whether check register `ck` was set to a failed state for at least once.
impl<Id: SiteId> AluCore<Id> {
/// Read overflow/carry flag.
pub fn co(&self) -> bool { self.co }

/// Set overflow/carry flag to a value.
pub fn set_co(&mut self, co: bool) { self.co = co }

/// Return whether check register `ck` was set to a failed state for at least once.
pub fn ck(&self) -> Status { self.ck }

/// Resets `ck` register.
/// Set `ck` register to a failed state.
pub fn fail_ck(&mut self) { self.ck = Status::Fail }

/// Reset `ck` register.
pub fn reset_ck(&mut self) { self.ck = Status::Ok }

/// Accumulate complexity value.
Expand All @@ -142,68 +168,100 @@ impl<Id> AluCore<Id> {
}

/// Microcode for arithmetic registers.
impl<Id> AluCore<Id> {
pub fn get(&self, reg: Reg) -> Option<u64> {
impl<Id: SiteId> AluCore<Id> {
pub fn get(&self, reg: Reg) -> Option<u128> {
match reg {
Reg::A(a) => match a {
RegA::A8(idx) => self.a8[idx.pos()].map(u64::from),
RegA::A16(idx) => self.a16[idx.pos()].map(u64::from),
RegA::A32(idx) => self.a32[idx.pos()].map(u64::from),
RegA::A64(idx) => self.a64[idx.pos()],
RegA::A8(idx) => self.a8[idx.pos()].map(u128::from),
RegA::A16(idx) => self.a16[idx.pos()].map(u128::from),
RegA::A32(idx) => self.a32[idx.pos()].map(u128::from),
RegA::A64(idx) => self.a64[idx.pos()].map(u128::from),
RegA::A128(idx) => self.a128[idx.pos()],
},
}
}

pub fn a(&self, reg: RegA) -> Option<u128> {
match reg {
RegA::A8(idx) => self.a8(idx).map(u128::from),
RegA::A16(idx) => self.a16(idx).map(u128::from),
RegA::A32(idx) => self.a32(idx).map(u128::from),
RegA::A64(idx) => self.a64(idx).map(u128::from),
RegA::A128(idx) => self.a128(idx),
}
}

pub fn set_a(&mut self, reg: RegA, val: u128) -> bool {
match reg {
RegA::A8(idx) => self.set_a8(idx, val as u8),
RegA::A16(idx) => self.set_a16(idx, val as u16),
RegA::A32(idx) => self.set_a32(idx, val as u32),
RegA::A64(idx) => self.set_a64(idx, val as u64),
RegA::A128(idx) => self.set_a128(idx, val),
}
}

pub fn a8(&self, idx: IdxA) -> Option<u8> { self.a8[idx.pos()] }
pub fn a16(&self, idx: IdxA) -> Option<u16> { self.a16[idx.pos()] }
pub fn a32(&self, idx: IdxA) -> Option<u32> { self.a32[idx.pos()] }
pub fn a64(&self, idx: IdxA) -> Option<u64> { self.a64[idx.pos()] }
pub fn a128(&self, idx: IdxA) -> Option<u128> { self.a128[idx.pos()] }

pub fn clr_a8(&mut self, idx: IdxA) -> bool { self.take_a8(idx).is_some() }
pub fn clr_a16(&mut self, idx: IdxA) -> bool { self.take_a16(idx).is_some() }
pub fn clr_a32(&mut self, idx: IdxA) -> bool { self.take_a32(idx).is_some() }
pub fn clr_a64(&mut self, idx: IdxA) -> bool { self.take_a64(idx).is_some() }
pub fn clr_a128(&mut self, idx: IdxA) -> bool { self.take_a128(idx).is_some() }

pub fn take_a8(&mut self, idx: IdxA) -> Option<u8> { self.a8[idx.pos()].take() }
pub fn take_a16(&mut self, idx: IdxA) -> Option<u16> { self.a16[idx.pos()].take() }
pub fn take_a32(&mut self, idx: IdxA) -> Option<u32> { self.a32[idx.pos()].take() }
pub fn take_a64(&mut self, idx: IdxA) -> Option<u64> { self.a64[idx.pos()].take() }
pub fn take_a128(&mut self, idx: IdxA) -> Option<u128> { self.a128[idx.pos()].take() }

pub fn set_a8(&mut self, idx: IdxA, val: u8) -> bool { self.a8[idx.pos()].replace(val).is_some() }
pub fn set_a16(&mut self, idx: IdxA, val: u16) -> bool { self.a16[idx.pos()].replace(val).is_some() }
pub fn set_a32(&mut self, idx: IdxA, val: u32) -> bool { self.a32[idx.pos()].replace(val).is_some() }
pub fn set_a64(&mut self, idx: IdxA, val: u64) -> bool { self.a64[idx.pos()].replace(val).is_some() }
pub fn set_a128(&mut self, idx: IdxA, val: u128) -> bool { self.a128[idx.pos()].replace(val).is_some() }

pub fn swp_a8(&mut self, idx: IdxA, val: u8) -> Option<u8> { self.a8[idx.pos()].replace(val) }
pub fn swp_a16(&mut self, idx: IdxA, val: u16) -> Option<u16> { self.a16[idx.pos()].replace(val) }
pub fn swp_a32(&mut self, idx: IdxA, val: u32) -> Option<u32> { self.a32[idx.pos()].replace(val) }
pub fn swp_a64(&mut self, idx: IdxA, val: u64) -> Option<u64> { self.a64[idx.pos()].replace(val) }
pub fn swp_a128(&mut self, idx: IdxA, val: u128) -> Option<u128> { self.a128[idx.pos()].replace(val) }

pub fn a_values(&self) -> impl Iterator<Item = (RegA, u64)> + '_ {
pub fn a_values(&self) -> impl Iterator<Item = (RegA, u128)> + '_ {
iter::empty()
.chain(
self.a8
.iter()
.enumerate()
.filter_map(|(i, v)| v.map(|v| (RegA::A8(IdxA::from_expected(i)), v as u64))),
.filter_map(|(i, v)| v.map(|v| (RegA::A8(IdxA::from_expected(i)), v as u128))),
)
.chain(
self.a16
.iter()
.enumerate()
.filter_map(|(i, v)| v.map(|v| (RegA::A8(IdxA::from_expected(i)), v as u64))),
.filter_map(|(i, v)| v.map(|v| (RegA::A16(IdxA::from_expected(i)), v as u128))),
)
.chain(
self.a32
.iter()
.enumerate()
.filter_map(|(i, v)| v.map(|v| (RegA::A8(IdxA::from_expected(i)), v as u64))),
.filter_map(|(i, v)| v.map(|v| (RegA::A32(IdxA::from_expected(i)), v as u128))),
)
.chain(
self.a64
.iter()
.enumerate()
.filter_map(|(i, v)| v.map(|v| (RegA::A8(IdxA::from_expected(i)), v))),
.filter_map(|(i, v)| v.map(|v| (RegA::A64(IdxA::from_expected(i)), v as u128))),
)
.chain(
self.a128
.iter()
.enumerate()
.filter_map(|(i, v)| v.map(|v| (RegA::A128(IdxA::from_expected(i)), v))),
)
}
}
6 changes: 3 additions & 3 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
//! AluVM registers system
mod core;
mod alu64;
mod microcode;
mod regs;

pub use self::alu64::{IdxA, Reg, RegA, A};
pub use self::core::{AluCore, CoreConfig, Site, Status, CALL_STACK_SIZE_MAX};
pub use self::core::{AluCore, CoreConfig, Site, SiteId, Status, CALL_STACK_SIZE_MAX};
pub use self::microcode::{IdxA, Reg, RegA, A};
pub(self) use self::regs::Idx32;
30 changes: 6 additions & 24 deletions src/isa/alu64/bytecode.rs → src/isa/alu/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@

use core::ops::RangeInclusive;

use super::{CtrlInstr, FieldInstr, RegInstr};
use super::{CtrlInstr, RegInstr};
use crate::core::SiteId;
use crate::isa::bytecode::CodeEofError;
use crate::isa::{Bytecode, BytecodeRead, BytecodeWrite, Instr, InstructionSet, ReservedInstr};

impl<Id, Ext: InstructionSet> Bytecode<Id> for Instr<Ext> {
impl<Id: SiteId, Ext: InstructionSet<Id>> Bytecode<Id> for Instr<Id, Ext> {
fn op_range() -> RangeInclusive<u8> { todo!() }

fn opcode_byte(&self) -> u8 { todo!() }
Expand All @@ -47,7 +48,7 @@ impl<Id, Ext: InstructionSet> Bytecode<Id> for Instr<Ext> {
}
}

impl<Id> Bytecode<Id> for ReservedInstr {
impl<Id: SiteId> Bytecode<Id> for ReservedInstr {
fn op_range() -> RangeInclusive<u8> { todo!() }

fn opcode_byte(&self) -> u8 { todo!() }
Expand All @@ -66,7 +67,7 @@ impl<Id> Bytecode<Id> for ReservedInstr {
}
}

impl<Id> Bytecode<Id> for CtrlInstr {
impl<Id: SiteId> Bytecode<Id> for CtrlInstr<Id> {
fn op_range() -> RangeInclusive<u8> { todo!() }

fn opcode_byte(&self) -> u8 { todo!() }
Expand All @@ -85,26 +86,7 @@ impl<Id> Bytecode<Id> for CtrlInstr {
}
}

impl<Id> Bytecode<Id> for RegInstr {
fn op_range() -> RangeInclusive<u8> { todo!() }

fn opcode_byte(&self) -> u8 { todo!() }

fn encode_operands<W>(&self, writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
todo!()
}

fn decode_operands<R>(reader: &mut R, opcode: u8) -> Result<Self, CodeEofError>
where
Self: Sized,
R: BytecodeRead<Id>,
{
todo!()
}
}

impl<Id> Bytecode<Id> for FieldInstr {
impl<Id: SiteId> Bytecode<Id> for RegInstr {
fn op_range() -> RangeInclusive<u8> { todo!() }

fn opcode_byte(&self) -> u8 { todo!() }
Expand Down
Loading

0 comments on commit 4891df0

Please sign in to comment.