use core::marker::PhantomData;
use miden_core::{field::PrimeCharacteristicRing, operations::opcodes};
#[cfg(test)]
use crate::trace::decoder::NUM_OP_BITS;
use crate::trace::{
decoder::{IS_LOOP_FLAG_COL_IDX, OP_BITS_EXTRA_COLS_RANGE, OP_BITS_RANGE},
stack::{B0_COL_IDX, H0_COL_IDX},
};
pub const NUM_DEGREE_7_OPS: usize = 64;
pub const NUM_DEGREE_6_OPS: usize = 8;
pub const NUM_DEGREE_5_OPS: usize = 16;
pub const NUM_DEGREE_4_OPS: usize = 8;
pub const NUM_STACK_IMPACT_FLAGS: usize = 16;
const DEGREE_7_OPCODE_STARTS: usize = 0;
const DEGREE_7_OPCODE_ENDS: usize = DEGREE_7_OPCODE_STARTS + 63;
const DEGREE_6_OPCODE_STARTS: usize = DEGREE_7_OPCODE_ENDS + 1;
const DEGREE_6_OPCODE_ENDS: usize = DEGREE_6_OPCODE_STARTS + 15;
const DEGREE_5_OPCODE_STARTS: usize = DEGREE_6_OPCODE_ENDS + 1;
const DEGREE_5_OPCODE_ENDS: usize = DEGREE_5_OPCODE_STARTS + 15;
const DEGREE_4_OPCODE_STARTS: usize = DEGREE_5_OPCODE_ENDS + 1;
#[allow(dead_code)]
const DEGREE_4_OPCODE_ENDS: usize = DEGREE_4_OPCODE_STARTS + 31;
#[allow(dead_code)]
pub struct OpFlags<E> {
degree7_op_flags: [E; NUM_DEGREE_7_OPS],
degree6_op_flags: [E; NUM_DEGREE_6_OPS],
degree5_op_flags: [E; NUM_DEGREE_5_OPS],
degree4_op_flags: [E; NUM_DEGREE_4_OPS],
no_shift_flags: [E; NUM_STACK_IMPACT_FLAGS],
left_shift_flags: [E; NUM_STACK_IMPACT_FLAGS],
right_shift_flags: [E; NUM_STACK_IMPACT_FLAGS],
left_shift: E,
right_shift: E,
control_flow: E,
overflow: E,
u32_rc_op: E,
}
pub trait DecoderAccess<E> {
fn op_bit(&self, index: usize) -> E;
fn op_bit_extra(&self, index: usize) -> E;
fn overflow_register(&self) -> E;
fn stack_depth(&self) -> E;
fn is_loop_end(&self) -> E;
}
impl<T> DecoderAccess<T> for &crate::MainTraceRow<T>
where
T: Clone,
{
#[inline]
fn op_bit(&self, index: usize) -> T {
self.decoder[OP_BITS_RANGE.start + index].clone()
}
#[inline]
fn op_bit_extra(&self, index: usize) -> T {
self.decoder[OP_BITS_EXTRA_COLS_RANGE.start + index].clone()
}
#[inline]
fn overflow_register(&self) -> T {
self.stack[H0_COL_IDX].clone()
}
#[inline]
fn stack_depth(&self) -> T {
self.stack[B0_COL_IDX].clone()
}
#[inline]
fn is_loop_end(&self) -> T {
self.decoder[IS_LOOP_FLAG_COL_IDX].clone()
}
}
pub struct ExprDecoderAccess<'a, V, E> {
row: &'a crate::MainTraceRow<V>,
_phantom: PhantomData<E>,
}
impl<'a, V, E> ExprDecoderAccess<'a, V, E> {
pub fn new(row: &'a crate::MainTraceRow<V>) -> Self {
Self { row, _phantom: PhantomData }
}
}
impl<'a, V, E> DecoderAccess<E> for ExprDecoderAccess<'a, V, E>
where
V: Clone + Into<E>,
{
#[inline]
fn op_bit(&self, index: usize) -> E {
self.row.decoder[OP_BITS_RANGE.start + index].clone().into()
}
#[inline]
fn op_bit_extra(&self, index: usize) -> E {
self.row.decoder[OP_BITS_EXTRA_COLS_RANGE.start + index].clone().into()
}
#[inline]
fn overflow_register(&self) -> E {
self.row.stack[H0_COL_IDX].clone().into()
}
#[inline]
fn stack_depth(&self) -> E {
self.row.stack[B0_COL_IDX].clone().into()
}
#[inline]
fn is_loop_end(&self) -> E {
self.row.decoder[IS_LOOP_FLAG_COL_IDX].clone().into()
}
}
#[inline]
fn binary_not<E>(x: E) -> E
where
E: Clone + core::ops::Sub<Output = E> + PrimeCharacteristicRing,
{
E::ONE - x
}
#[derive(Clone)]
struct Op<E> {
bit: E,
not: E,
}
impl<E: Clone> Op<E> {
#[inline]
fn is(&self) -> E {
self.bit.clone()
}
#[inline]
fn not(&self) -> E {
self.not.clone()
}
}
macro_rules! op_flag_getters {
($array:ident, $( $(#[$meta:meta])* $name:ident => $op:expr ),* $(,)?) => {
$(
$(#[$meta])*
#[inline(always)]
pub fn $name(&self) -> E {
self.$array[get_op_index($op)].clone()
}
)*
};
}
#[allow(dead_code)]
impl<E> OpFlags<E>
where
E: Clone
+ Default
+ core::ops::Add<Output = E>
+ core::ops::Sub<Output = E>
+ core::ops::Mul<Output = E>
+ PrimeCharacteristicRing,
{
pub fn new<D: DecoderAccess<E>>(frame: D) -> Self {
let mut degree7_op_flags: [E; NUM_DEGREE_7_OPS] = core::array::from_fn(|_| E::default());
let mut degree6_op_flags: [E; NUM_DEGREE_6_OPS] = core::array::from_fn(|_| E::default());
let mut degree5_op_flags: [E; NUM_DEGREE_5_OPS] = core::array::from_fn(|_| E::default());
let mut degree4_op_flags: [E; NUM_DEGREE_4_OPS] = core::array::from_fn(|_| E::default());
let mut no_shift_flags: [E; NUM_STACK_IMPACT_FLAGS] =
core::array::from_fn(|_| E::default());
let mut left_shift_flags: [E; NUM_STACK_IMPACT_FLAGS] =
core::array::from_fn(|_| E::default());
let mut right_shift_flags: [E; NUM_STACK_IMPACT_FLAGS] =
core::array::from_fn(|_| E::default());
let op: [Op<E>; 7] = core::array::from_fn(|i| {
let bit = frame.op_bit(i);
let not = binary_not(bit.clone());
Op { bit, not }
});
let prefix_010 = op[6].not() * op[5].is() * op[4].not();
let prefix_011 = op[6].not() * op[5].is() * op[4].is();
let add3_madd_prefix = op[6].is() * op[5].not() * op[4].not() * op[3].is() * op[2].is();
degree7_op_flags[0] = op[5].not() * op[4].not();
degree7_op_flags[16] = op[5].not() * op[4].is();
degree7_op_flags[32] = op[5].is() * op[4].not();
degree7_op_flags[0b110000] = op[5].is() * op[4].is();
let f100 = degree7_op_flags[0].clone() * op[6].is();
let f1000 = f100.clone() * op[3].not();
let not_6_not_3 = op[6].not() * op[3].not();
let not_6_yes_3 = op[6].not() * op[3].is();
for i in (0..64).step_by(16) {
let base = degree7_op_flags[i].clone();
degree7_op_flags[i + 8] = base.clone() * not_6_yes_3.clone();
degree7_op_flags[i] = base * not_6_not_3.clone();
}
let f011 = degree7_op_flags[48].clone() + degree7_op_flags[56].clone();
let _f010 = degree7_op_flags[32].clone() + degree7_op_flags[40].clone();
let f0000 = degree7_op_flags[0].clone();
let f0100 = degree7_op_flags[32].clone();
for i in (0..64).step_by(8) {
let base = degree7_op_flags[i].clone();
degree7_op_flags[i + 4] = base.clone() * op[2].is();
degree7_op_flags[i] = base * op[2].not();
}
for i in (0..64).step_by(4) {
let base = degree7_op_flags[i].clone();
degree7_op_flags[i + 2] = base.clone() * op[1].is();
degree7_op_flags[i] = base * op[1].not();
}
let mov2_flag = degree7_op_flags[10].clone();
let mov3_flag = degree7_op_flags[12].clone();
let mov4_flag = degree7_op_flags[16].clone();
let mov5_flag = degree7_op_flags[18].clone();
let mov6_flag = degree7_op_flags[20].clone();
let mov7_flag = degree7_op_flags[22].clone();
let mov8_flag = degree7_op_flags[26].clone();
let swapwx_flag = degree7_op_flags[28].clone();
let adv_popw_expacc = degree7_op_flags[14].clone();
for i in (0..64).step_by(2) {
let base = degree7_op_flags[i].clone();
degree7_op_flags[i + 1] = base.clone() * op[0].is();
degree7_op_flags[i] = base * op[0].not();
}
let ext2mul_flag = degree7_op_flags[25].clone();
let no_change_1_flag = f0000.clone() - degree7_op_flags[0].clone();
let left_change_1_flag = f0100 - degree7_op_flags[32].clone();
let degree_6_flag = op[6].is() * op[5].not() * op[4].not();
let not_2_not_3 = op[2].not() * op[3].not();
let yes_2_not_3 = op[2].is() * op[3].not();
let not_2_yes_3 = op[2].not() * op[3].is();
let yes_2_yes_3 = op[2].is() * op[3].is();
degree6_op_flags[0] = op[1].not() * not_2_not_3.clone(); degree6_op_flags[1] = op[1].is() * not_2_not_3.clone(); degree6_op_flags[2] = op[1].not() * yes_2_not_3.clone(); degree6_op_flags[3] = op[1].is() * yes_2_not_3.clone(); degree6_op_flags[4] = op[1].not() * not_2_yes_3.clone(); degree6_op_flags[5] = op[1].is() * not_2_yes_3.clone(); degree6_op_flags[6] = op[1].not() * yes_2_yes_3.clone(); degree6_op_flags[7] = op[1].is() * yes_2_yes_3.clone();
for flag in degree6_op_flags.iter_mut() {
*flag = flag.clone() * degree_6_flag.clone();
}
let degree_5_flag = frame.op_bit_extra(0);
let not_0_not_1 = op[0].not() * op[1].not();
let yes_0_not_1 = op[0].is() * op[1].not();
let not_0_yes_1 = op[0].not() * op[1].is();
let yes_0_yes_1 = op[0].is() * op[1].is();
degree5_op_flags[0] = not_0_not_1.clone() * op[2].not(); degree5_op_flags[1] = yes_0_not_1.clone() * op[2].not(); degree5_op_flags[2] = not_0_yes_1.clone() * op[2].not(); degree5_op_flags[3] = yes_0_yes_1.clone() * op[2].not(); degree5_op_flags[4] = not_0_not_1.clone() * op[2].is(); degree5_op_flags[5] = yes_0_not_1.clone() * op[2].is(); degree5_op_flags[6] = not_0_yes_1.clone() * op[2].is(); degree5_op_flags[7] = yes_0_yes_1.clone() * op[2].is();
for i in 0..8 {
degree5_op_flags[i + 8] = degree5_op_flags[i].clone();
}
let deg_5_not_3 = op[3].not() * degree_5_flag.clone();
for flag in degree5_op_flags.iter_mut().take(8) {
*flag = flag.clone() * deg_5_not_3.clone();
}
let deg_5_yes_3 = op[3].is() * degree_5_flag.clone();
for flag in degree5_op_flags.iter_mut().skip(8) {
*flag = flag.clone() * deg_5_yes_3.clone();
}
let degree_4_flag = frame.op_bit_extra(1);
degree4_op_flags[0] = not_2_not_3.clone(); degree4_op_flags[1] = yes_2_not_3; degree4_op_flags[2] = not_2_yes_3; degree4_op_flags[3] = yes_2_yes_3;
for i in 0..4 {
degree4_op_flags[i + 4] = degree4_op_flags[i].clone();
}
let deg_4_not_4 = op[4].not() * degree_4_flag.clone();
for flag in degree4_op_flags.iter_mut().take(4) {
*flag = flag.clone() * deg_4_not_4.clone();
}
let deg_4_yes_4 = op[4].is() * degree_4_flag.clone();
for flag in degree4_op_flags.iter_mut().skip(4) {
*flag = flag.clone() * deg_4_yes_4.clone();
}
let shift_left_on_end = degree4_op_flags[4].clone() * frame.is_loop_end();
no_shift_flags[0] = degree7_op_flags[0].clone() + degree6_op_flags[5].clone() + degree5_op_flags[1].clone() + degree5_op_flags[6].clone() + degree5_op_flags[7].clone() + degree7_op_flags[31].clone() + degree4_op_flags[6].clone() + degree4_op_flags[7].clone() + degree4_op_flags[3].clone() + degree4_op_flags[4].clone() * binary_not(frame.is_loop_end());
no_shift_flags[1] = no_shift_flags[0].clone() + no_change_1_flag;
no_shift_flags[2] = no_shift_flags[1].clone()
+ degree7_op_flags[8].clone() + f1000.clone(); no_shift_flags[3] = no_shift_flags[2].clone() + mov2_flag.clone();
no_shift_flags[4] = no_shift_flags[3].clone()
+ mov3_flag.clone()
+ adv_popw_expacc.clone()
+ swapwx_flag.clone()
+ ext2mul_flag.clone()
+ degree4_op_flags[0].clone();
no_shift_flags[5] = no_shift_flags[4].clone() + mov4_flag.clone();
no_shift_flags[6] = no_shift_flags[5].clone() + mov5_flag.clone();
no_shift_flags[7] = no_shift_flags[6].clone() + mov6_flag.clone();
no_shift_flags[8] =
no_shift_flags[7].clone() + mov7_flag.clone() + degree7_op_flags[24].clone()
- degree7_op_flags[28].clone();
no_shift_flags[9] = no_shift_flags[8].clone() + mov8_flag.clone();
no_shift_flags[10] = no_shift_flags[9].clone();
no_shift_flags[11] = no_shift_flags[9].clone();
no_shift_flags[12] = no_shift_flags[9].clone() - degree7_op_flags[29].clone()
+ degree7_op_flags[28].clone()
+ degree5_op_flags[0].clone();
no_shift_flags[13] = no_shift_flags[12].clone();
no_shift_flags[14] = no_shift_flags[12].clone();
no_shift_flags[15] = no_shift_flags[12].clone();
let movdnn_flag = degree7_op_flags[11].clone()
+ degree7_op_flags[13].clone()
+ degree7_op_flags[17].clone()
+ degree7_op_flags[19].clone()
+ degree7_op_flags[21].clone()
+ degree7_op_flags[23].clone()
+ degree7_op_flags[27].clone();
let split_loop_flag = degree5_op_flags[4].clone() + degree5_op_flags[5].clone();
let add3_madd_flag = degree6_op_flags[6].clone() + degree6_op_flags[7].clone();
left_shift_flags[1] = degree7_op_flags[32].clone()
+ movdnn_flag.clone()
+ degree7_op_flags[41].clone()
+ degree7_op_flags[45].clone()
+ degree7_op_flags[47].clone()
+ degree7_op_flags[46].clone()
+ split_loop_flag.clone()
+ shift_left_on_end.clone()
+ degree5_op_flags[8].clone() + degree5_op_flags[12].clone();
left_shift_flags[2] = left_shift_flags[1].clone() + left_change_1_flag;
left_shift_flags[3] =
left_shift_flags[2].clone() + add3_madd_flag.clone() + degree7_op_flags[42].clone()
- degree7_op_flags[11].clone();
left_shift_flags[4] = left_shift_flags[3].clone() - degree7_op_flags[13].clone();
left_shift_flags[5] = left_shift_flags[4].clone() + degree7_op_flags[44].clone()
- degree7_op_flags[17].clone();
left_shift_flags[6] = left_shift_flags[5].clone() - degree7_op_flags[19].clone();
left_shift_flags[7] = left_shift_flags[6].clone() - degree7_op_flags[21].clone();
left_shift_flags[8] = left_shift_flags[7].clone() - degree7_op_flags[23].clone();
left_shift_flags[9] = left_shift_flags[8].clone() + degree7_op_flags[43].clone()
- degree7_op_flags[27].clone();
left_shift_flags[10] = left_shift_flags[9].clone();
left_shift_flags[11] = left_shift_flags[9].clone();
left_shift_flags[12] = left_shift_flags[9].clone();
left_shift_flags[13] = left_shift_flags[9].clone();
left_shift_flags[14] = left_shift_flags[9].clone();
left_shift_flags[15] = left_shift_flags[9].clone();
let movupn_flag = degree7_op_flags[10].clone()
+ degree7_op_flags[12].clone()
+ degree7_op_flags[16].clone()
+ degree7_op_flags[18].clone()
+ degree7_op_flags[20].clone()
+ degree7_op_flags[22].clone()
+ degree7_op_flags[26].clone();
right_shift_flags[0] = f011.clone()
+ degree5_op_flags[11].clone() + movupn_flag.clone();
right_shift_flags[1] = right_shift_flags[0].clone() + degree6_op_flags[4].clone();
right_shift_flags[2] = right_shift_flags[1].clone() - degree7_op_flags[10].clone();
right_shift_flags[3] = right_shift_flags[2].clone() - degree7_op_flags[12].clone();
right_shift_flags[4] = right_shift_flags[3].clone() - degree7_op_flags[16].clone();
right_shift_flags[5] = right_shift_flags[4].clone() - degree7_op_flags[18].clone();
right_shift_flags[6] = right_shift_flags[5].clone() - degree7_op_flags[20].clone();
right_shift_flags[7] = right_shift_flags[6].clone() - degree7_op_flags[22].clone();
right_shift_flags[8] = right_shift_flags[7].clone() - degree7_op_flags[26].clone();
right_shift_flags[9] = right_shift_flags[8].clone();
right_shift_flags[10] = right_shift_flags[8].clone();
right_shift_flags[11] = right_shift_flags[8].clone();
right_shift_flags[12] = right_shift_flags[8].clone();
right_shift_flags[13] = right_shift_flags[8].clone();
right_shift_flags[14] = right_shift_flags[8].clone();
right_shift_flags[15] = right_shift_flags[8].clone();
let right_shift = prefix_011.clone()
+ degree5_op_flags[11].clone() + degree6_op_flags[4].clone();
let left_shift = prefix_010.clone()
+ add3_madd_prefix.clone()
+ split_loop_flag
+ degree4_op_flags[5].clone() + shift_left_on_end
+ degree5_op_flags[8].clone();
let control_flow = degree_5_flag * op[3].not() * op[2].is() + degree_4_flag * op[4].is() + degree5_op_flags[8].clone() + degree5_op_flags[12].clone() + degree4_op_flags[2].clone() + degree4_op_flags[3].clone();
let u32_rc_op = f100;
let overflow = (frame.stack_depth() - E::from_u64(16)) * frame.overflow_register();
Self {
degree7_op_flags,
degree6_op_flags,
degree5_op_flags,
degree4_op_flags,
no_shift_flags,
left_shift_flags,
right_shift_flags,
left_shift,
right_shift,
control_flow,
overflow,
u32_rc_op,
}
}
op_flag_getters!(degree7_op_flags,
#[allow(dead_code)]
noop => opcodes::NOOP,
eqz => opcodes::EQZ,
neg => opcodes::NEG,
inv => opcodes::INV,
incr => opcodes::INCR,
not => opcodes::NOT,
mload => opcodes::MLOAD,
swap => opcodes::SWAP,
caller => opcodes::CALLER,
movup2 => opcodes::MOVUP2,
movdn2 => opcodes::MOVDN2,
movup3 => opcodes::MOVUP3,
movdn3 => opcodes::MOVDN3,
#[allow(dead_code)]
advpopw => opcodes::ADVPOPW,
expacc => opcodes::EXPACC,
movup4 => opcodes::MOVUP4,
movdn4 => opcodes::MOVDN4,
movup5 => opcodes::MOVUP5,
movdn5 => opcodes::MOVDN5,
movup6 => opcodes::MOVUP6,
movdn6 => opcodes::MOVDN6,
movup7 => opcodes::MOVUP7,
movdn7 => opcodes::MOVDN7,
swapw => opcodes::SWAPW,
movup8 => opcodes::MOVUP8,
movdn8 => opcodes::MOVDN8,
swapw2 => opcodes::SWAPW2,
swapw3 => opcodes::SWAPW3,
swapdw => opcodes::SWAPDW,
ext2mul => opcodes::EXT2MUL,
assert_op => opcodes::ASSERT,
eq => opcodes::EQ,
add => opcodes::ADD,
mul => opcodes::MUL,
and => opcodes::AND,
or => opcodes::OR,
u32and => opcodes::U32AND,
u32xor => opcodes::U32XOR,
#[allow(dead_code)]
drop => opcodes::DROP,
cswap => opcodes::CSWAP,
cswapw => opcodes::CSWAPW,
mloadw => opcodes::MLOADW,
mstore => opcodes::MSTORE,
mstorew => opcodes::MSTOREW,
pad => opcodes::PAD,
dup => opcodes::DUP0,
dup1 => opcodes::DUP1,
dup2 => opcodes::DUP2,
dup3 => opcodes::DUP3,
dup4 => opcodes::DUP4,
dup5 => opcodes::DUP5,
dup6 => opcodes::DUP6,
dup7 => opcodes::DUP7,
dup9 => opcodes::DUP9,
dup11 => opcodes::DUP11,
dup13 => opcodes::DUP13,
dup15 => opcodes::DUP15,
#[allow(dead_code)]
advpop => opcodes::ADVPOP,
sdepth => opcodes::SDEPTH,
clk => opcodes::CLK,
);
op_flag_getters!(degree6_op_flags,
u32add => opcodes::U32ADD,
u32sub => opcodes::U32SUB,
u32mul => opcodes::U32MUL,
u32div => opcodes::U32DIV,
u32split => opcodes::U32SPLIT,
u32assert2 => opcodes::U32ASSERT2,
u32add3 => opcodes::U32ADD3,
u32madd => opcodes::U32MADD,
);
op_flag_getters!(degree5_op_flags,
hperm => opcodes::HPERM,
mpverify => opcodes::MPVERIFY,
split => opcodes::SPLIT,
loop_op => opcodes::LOOP,
span => opcodes::SPAN,
join => opcodes::JOIN,
push => opcodes::PUSH,
dyn_op => opcodes::DYN,
dyncall => opcodes::DYNCALL,
evalcircuit => opcodes::EVALCIRCUIT,
log_precompile => opcodes::LOGPRECOMPILE,
hornerbase => opcodes::HORNERBASE,
hornerext => opcodes::HORNEREXT,
mstream => opcodes::MSTREAM,
pipe => opcodes::PIPE,
);
op_flag_getters!(degree4_op_flags,
mrupdate => opcodes::MRUPDATE,
call => opcodes::CALL,
syscall => opcodes::SYSCALL,
end => opcodes::END,
repeat => opcodes::REPEAT,
respan => opcodes::RESPAN,
halt => opcodes::HALT,
cryptostream => opcodes::CRYPTOSTREAM,
);
#[inline(always)]
pub fn no_shift_at(&self, index: usize) -> E {
self.no_shift_flags[index].clone()
}
#[inline(always)]
pub fn left_shift_at(&self, index: usize) -> E {
self.left_shift_flags[index].clone()
}
#[inline(always)]
pub fn right_shift_at(&self, index: usize) -> E {
self.right_shift_flags[index].clone()
}
#[inline(always)]
pub fn right_shift(&self) -> E {
self.right_shift.clone()
}
#[inline(always)]
pub fn left_shift(&self) -> E {
self.left_shift.clone()
}
#[inline(always)]
pub fn control_flow(&self) -> E {
self.control_flow.clone()
}
#[inline(always)]
#[allow(dead_code)]
pub fn u32_rc_op(&self) -> E {
self.u32_rc_op.clone()
}
#[inline(always)]
pub fn overflow(&self) -> E {
self.overflow.clone()
}
#[cfg(test)]
pub fn degree7_op_flags(&self) -> &[E; NUM_DEGREE_7_OPS] {
&self.degree7_op_flags
}
#[cfg(test)]
pub fn degree6_op_flags(&self) -> &[E; NUM_DEGREE_6_OPS] {
&self.degree6_op_flags
}
#[cfg(test)]
pub fn degree5_op_flags(&self) -> &[E; NUM_DEGREE_5_OPS] {
&self.degree5_op_flags
}
#[cfg(test)]
pub fn degree4_op_flags(&self) -> &[E; NUM_DEGREE_4_OPS] {
&self.degree4_op_flags
}
}
pub const fn get_op_index(opcode: u8) -> usize {
let opcode = opcode as usize;
if opcode <= DEGREE_7_OPCODE_ENDS {
opcode
} else if opcode <= DEGREE_6_OPCODE_ENDS {
(opcode - DEGREE_6_OPCODE_STARTS) / 2
} else if opcode <= DEGREE_5_OPCODE_ENDS {
opcode - DEGREE_5_OPCODE_STARTS
} else {
(opcode - DEGREE_4_OPCODE_STARTS) / 4
}
}
#[cfg(test)]
pub fn generate_test_row(opcode: usize) -> crate::MainTraceRow<miden_core::Felt> {
use miden_core::{ONE, ZERO};
use crate::trace::{
CHIPLETS_WIDTH, DECODER_TRACE_WIDTH, RANGE_CHECK_TRACE_WIDTH, STACK_TRACE_WIDTH,
decoder::OP_BITS_EXTRA_COLS_RANGE,
};
let op_bits = get_op_bits(opcode);
let mut decoder = [ZERO; DECODER_TRACE_WIDTH];
for (i, &bit) in op_bits.iter().enumerate() {
decoder[OP_BITS_RANGE.start + i] = bit;
}
let bit_6 = op_bits[6];
let bit_5 = op_bits[5];
let bit_4 = op_bits[4];
decoder[OP_BITS_EXTRA_COLS_RANGE.start] = bit_6 * (ONE - bit_5) * bit_4;
decoder[OP_BITS_EXTRA_COLS_RANGE.start + 1] = bit_6 * bit_5;
crate::MainTraceRow {
clk: ZERO,
ctx: ZERO,
fn_hash: [ZERO; 4],
decoder,
stack: [ZERO; STACK_TRACE_WIDTH],
range: [ZERO; RANGE_CHECK_TRACE_WIDTH],
chiplets: [ZERO; CHIPLETS_WIDTH],
}
}
#[cfg(test)]
pub fn get_op_bits(opcode: usize) -> [miden_core::Felt; NUM_OP_BITS] {
use miden_core::{Felt, ZERO};
let mut opcode_copy = opcode;
let mut bit_array = [ZERO; NUM_OP_BITS];
for bit in bit_array.iter_mut() {
*bit = Felt::new((opcode_copy & 1) as u64);
opcode_copy >>= 1;
}
assert_eq!(opcode_copy, 0, "Opcode must be 7 bits");
bit_array
}
#[cfg(test)]
mod tests;