use core::{
borrow::{Borrow, BorrowMut},
mem::size_of,
};
use super::{
chiplets::columns::{
AceCols, AceEvalCols, AceReadCols, BitwiseCols, ControllerCols, KernelRomCols, MemoryCols,
PermutationCols,
},
decoder::columns::DecoderCols,
range::columns::RangeCols,
stack::columns::StackCols,
system::columns::SystemCols,
};
use crate::trace::{CHIPLETS_WIDTH, TRACE_WIDTH};
#[repr(C)]
#[derive(Debug, Clone, Default)]
pub struct CoreCols<T> {
pub system: SystemCols<T>,
pub decoder: DecoderCols<T>,
pub stack: StackCols<T>,
pub range: RangeCols<T>,
}
pub const NUM_CORE_COLS: usize = size_of::<CoreCols<u8>>();
impl<T> Borrow<CoreCols<T>> for [T] {
fn borrow(&self) -> &CoreCols<T> {
debug_assert_eq!(self.len(), NUM_CORE_COLS);
let (prefix, shorts, suffix) = unsafe { self.align_to::<CoreCols<T>>() };
debug_assert!(prefix.is_empty() && suffix.is_empty() && shorts.len() == 1);
&shorts[0]
}
}
impl<T> BorrowMut<CoreCols<T>> for [T] {
fn borrow_mut(&mut self) -> &mut CoreCols<T> {
debug_assert_eq!(self.len(), NUM_CORE_COLS);
let (prefix, shorts, suffix) = unsafe { self.align_to_mut::<CoreCols<T>>() };
debug_assert!(prefix.is_empty() && suffix.is_empty() && shorts.len() == 1);
&mut shorts[0]
}
}
impl<T> CoreCols<T> {
pub fn as_slice(&self) -> &[T] {
let ptr = self as *const Self as *const T;
unsafe { core::slice::from_raw_parts(ptr, NUM_CORE_COLS) }
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct ChipletCols<T> {
pub s_00: T,
pub s_01: T,
pub chip_clk: T,
pub(crate) chiplets: [T; CHIPLETS_WIDTH - 3],
}
pub const NUM_CHIPLETS_COLS: usize = size_of::<ChipletCols<u8>>();
impl<T> ChipletCols<T> {
pub fn chiplet_selectors(&self) -> [T; 6]
where
T: Copy,
{
[
self.s_00,
self.s_01,
self.chiplets[0],
self.chiplets[1],
self.chiplets[2],
self.chiplets[3],
]
}
pub fn bitwise(&self) -> &BitwiseCols<T> {
self.chiplets[1..14].borrow()
}
pub fn memory(&self) -> &MemoryCols<T> {
self.chiplets[2..17].borrow()
}
pub fn memory_word_addr_lo(&self) -> T
where
T: Copy,
{
self.chiplets[17]
}
pub fn memory_word_addr_hi(&self) -> T
where
T: Copy,
{
self.chiplets[18]
}
pub fn ace(&self) -> &AceCols<T> {
self.chiplets[3..].borrow()
}
pub fn kernel_rom(&self) -> &KernelRomCols<T> {
self.chiplets[4..9].borrow()
}
pub fn permutation(&self) -> &PermutationCols<T> {
self.chiplets[..].borrow()
}
pub fn controller(&self) -> &ControllerCols<T> {
self.chiplets[..].borrow()
}
}
impl<T> Borrow<ChipletCols<T>> for [T] {
fn borrow(&self) -> &ChipletCols<T> {
debug_assert_eq!(self.len(), NUM_CHIPLETS_COLS);
let (prefix, shorts, suffix) = unsafe { self.align_to::<ChipletCols<T>>() };
debug_assert!(prefix.is_empty() && suffix.is_empty() && shorts.len() == 1);
&shorts[0]
}
}
impl<T> BorrowMut<ChipletCols<T>> for [T] {
fn borrow_mut(&mut self) -> &mut ChipletCols<T> {
debug_assert_eq!(self.len(), NUM_CHIPLETS_COLS);
let (prefix, shorts, suffix) = unsafe { self.align_to_mut::<ChipletCols<T>>() };
debug_assert!(prefix.is_empty() && suffix.is_empty() && shorts.len() == 1);
&mut shorts[0]
}
}
const _: () = assert!(NUM_CORE_COLS + NUM_CHIPLETS_COLS == TRACE_WIDTH);
pub const fn indices_arr<const N: usize>() -> [usize; N] {
let mut arr = [0; N];
let mut i = 0;
while i < N {
arr[i] = i;
i += 1;
}
arr
}
pub const NUM_SYSTEM_COLS: usize = size_of::<SystemCols<u8>>();
pub const NUM_DECODER_COLS: usize = size_of::<DecoderCols<u8>>();
pub const NUM_STACK_COLS: usize = size_of::<StackCols<u8>>();
pub const NUM_RANGE_COLS: usize = size_of::<RangeCols<u8>>();
pub const NUM_BITWISE_COLS: usize = size_of::<BitwiseCols<u8>>();
pub const NUM_MEMORY_COLS: usize = size_of::<MemoryCols<u8>>();
pub const NUM_ACE_COLS: usize = size_of::<AceCols<u8>>();
pub const NUM_ACE_READ_COLS: usize = size_of::<AceReadCols<u8>>();
pub const NUM_ACE_EVAL_COLS: usize = size_of::<AceEvalCols<u8>>();
pub const NUM_KERNEL_ROM_COLS: usize = size_of::<KernelRomCols<u8>>();
const _: () = assert!(NUM_SYSTEM_COLS == 6);
const _: () = assert!(NUM_DECODER_COLS == 24);
const _: () = assert!(NUM_STACK_COLS == 19);
const _: () = assert!(NUM_RANGE_COLS == 2);
const _: () = assert!(NUM_BITWISE_COLS == 13);
const _: () = assert!(NUM_MEMORY_COLS == 15);
const _: () = assert!(NUM_ACE_COLS == 16);
const _: () = assert!(NUM_ACE_READ_COLS == 4);
const _: () = assert!(NUM_ACE_EVAL_COLS == 4);
const _: () = assert!(NUM_KERNEL_ROM_COLS == 5);
#[cfg(test)]
mod tests {
use super::*;
use crate::trace::{DECODER_TRACE_WIDTH, STACK_TRACE_WIDTH, SYS_TRACE_WIDTH};
const CORE_COL_MAP: CoreCols<usize> = unsafe {
core::mem::transmute::<[usize; NUM_CORE_COLS], CoreCols<usize>>(
indices_arr::<NUM_CORE_COLS>(),
)
};
const CHIPLET_COL_MAP: ChipletCols<usize> = unsafe {
core::mem::transmute::<[usize; NUM_CHIPLETS_COLS], ChipletCols<usize>>(indices_arr::<
NUM_CHIPLETS_COLS,
>())
};
const DECODER_OFFSET: usize = SYS_TRACE_WIDTH;
const STACK_OFFSET: usize = SYS_TRACE_WIDTH + DECODER_TRACE_WIDTH;
const RANGE_OFFSET: usize = STACK_OFFSET + STACK_TRACE_WIDTH;
#[test]
fn col_map_system() {
assert_eq!(CORE_COL_MAP.system.clk, 0);
assert_eq!(CORE_COL_MAP.system.ctx, 1);
assert_eq!(CORE_COL_MAP.system.fn_hash[0], 2);
assert_eq!(CORE_COL_MAP.system.fn_hash[3], 5);
}
#[test]
fn col_map_decoder() {
assert_eq!(CORE_COL_MAP.decoder.addr, DECODER_OFFSET);
assert_eq!(CORE_COL_MAP.decoder.op_bits[0], DECODER_OFFSET + 1);
assert_eq!(CORE_COL_MAP.decoder.op_bits[6], DECODER_OFFSET + 7);
assert_eq!(CORE_COL_MAP.decoder.hasher_state[0], DECODER_OFFSET + 8);
assert_eq!(CORE_COL_MAP.decoder.in_span, DECODER_OFFSET + 16);
assert_eq!(CORE_COL_MAP.decoder.group_count, DECODER_OFFSET + 17);
assert_eq!(CORE_COL_MAP.decoder.op_index, DECODER_OFFSET + 18);
assert_eq!(CORE_COL_MAP.decoder.batch_flags[0], DECODER_OFFSET + 19);
assert_eq!(CORE_COL_MAP.decoder.extra[0], DECODER_OFFSET + 22);
}
#[test]
fn col_map_stack() {
assert_eq!(CORE_COL_MAP.stack.top[0], STACK_OFFSET);
assert_eq!(CORE_COL_MAP.stack.top[15], STACK_OFFSET + 15);
assert_eq!(CORE_COL_MAP.stack.b0, STACK_OFFSET + 16);
assert_eq!(CORE_COL_MAP.stack.b1, STACK_OFFSET + 17);
assert_eq!(CORE_COL_MAP.stack.h0, STACK_OFFSET + 18);
}
#[test]
fn col_map_range() {
assert_eq!(CORE_COL_MAP.range.multiplicity, RANGE_OFFSET);
assert_eq!(CORE_COL_MAP.range.value, RANGE_OFFSET + 1);
}
#[test]
fn col_map_chiplets() {
assert_eq!(CHIPLET_COL_MAP.s_00, 0);
assert_eq!(CHIPLET_COL_MAP.s_01, 1);
assert_eq!(CHIPLET_COL_MAP.chip_clk, 2);
assert_eq!(CHIPLET_COL_MAP.chiplets[0], 3);
assert_eq!(CHIPLET_COL_MAP.chiplets[18], 21);
}
#[test]
fn core_cols_width() {
assert_eq!(
NUM_CORE_COLS,
NUM_SYSTEM_COLS + NUM_DECODER_COLS + NUM_STACK_COLS + NUM_RANGE_COLS,
);
}
#[test]
fn chiplet_cols_width() {
assert_eq!(NUM_CHIPLETS_COLS, CHIPLETS_WIDTH);
}
macro_rules! col_map {
($cols:ident) => {{
const N: usize = core::mem::size_of::<$cols<u8>>();
const M: $cols<usize> =
unsafe { core::mem::transmute::<[usize; N], $cols<usize>>(indices_arr::<N>()) };
M
}};
}
#[test]
fn core_col_map_layout() {
insta::assert_debug_snapshot!(CORE_COL_MAP);
}
#[test]
fn chiplet_col_map_layout() {
insta::assert_debug_snapshot!(CHIPLET_COL_MAP);
}
#[test]
fn bitwise_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(BitwiseCols));
}
#[test]
fn memory_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(MemoryCols));
}
#[test]
fn ace_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(AceCols));
}
#[test]
fn ace_read_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(AceReadCols));
}
#[test]
fn ace_eval_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(AceEvalCols));
}
#[test]
fn kernel_rom_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(KernelRomCols));
}
#[test]
fn hasher_controller_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(ControllerCols));
}
#[test]
fn hasher_permutation_col_map_layout() {
insta::assert_debug_snapshot!(col_map!(PermutationCols));
}
}