use alloc::vec::Vec;
use miden_core::{
Felt, Word, ZERO,
program::{MIN_STACK_DEPTH, StackInputs},
};
use super::{
super::stack_ops::{op_pad, op_push},
op_advpop, op_advpopw, op_mload, op_mloadw, op_mstore, op_mstorew, op_mstream, op_pipe,
};
use crate::{
AdviceInputs, ContextId,
fast::{FastProcessor, NoopTracer},
processor::{Processor, StackInterface, SystemInterface},
};
#[test]
fn test_op_advpop() {
let advice_stack: Vec<u64> = vec![3];
let advice_inputs = AdviceInputs::default().with_stack_values(advice_stack).unwrap();
let mut processor = FastProcessor::new(StackInputs::default()).with_advice(advice_inputs);
let mut tracer = NoopTracer;
op_push(&mut processor, Felt::new(1)).unwrap();
processor.system_mut().increment_clock();
op_advpop(&mut processor, &mut tracer).unwrap();
processor.system_mut().increment_clock();
let expected = build_expected(&[3, 1]);
assert_eq!(expected, processor.stack_top());
assert!(op_advpop(&mut processor, &mut tracer).is_err());
}
#[test]
fn test_op_advpopw() {
let advice_stack: Vec<u64> = vec![3, 4, 5, 6];
let advice_inputs = AdviceInputs::default().with_stack_values(advice_stack).unwrap();
let mut processor = FastProcessor::new(StackInputs::default()).with_advice(advice_inputs);
let mut tracer = NoopTracer;
op_push(&mut processor, Felt::new(1)).unwrap();
processor.system_mut().increment_clock();
for _ in 0..4 {
op_pad(&mut processor).unwrap();
processor.system_mut().increment_clock();
}
op_advpopw(&mut processor, &mut tracer).unwrap();
processor.system_mut().increment_clock();
let expected = build_expected(&[3, 4, 5, 6, 1]);
assert_eq!(expected, processor.stack_top());
}
#[test]
fn test_op_mloadw() {
let mut processor = FastProcessor::new(StackInputs::default());
let mut tracer = NoopTracer;
assert_eq!(0, processor.memory().num_accessed_words());
let word: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into();
store_word(&mut processor, 4, word, &mut tracer);
for _ in 0..4 {
op_pad(&mut processor).unwrap();
processor.system_mut().increment_clock();
}
op_push(&mut processor, Felt::new(4)).unwrap();
processor.system_mut().increment_clock();
op_mloadw(&mut processor, &mut tracer).unwrap();
processor.system_mut().increment_clock();
let expected = build_expected(&[1, 3, 5, 7, 1, 3, 5, 7]);
assert_eq!(expected, processor.stack_top());
assert_eq!(1, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word =
processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap();
assert_eq!(word, stored_word);
op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap();
processor.system_mut().increment_clock();
assert!(op_mloadw(&mut processor, &mut tracer).is_err());
let mut processor = FastProcessor::new(StackInputs::default());
assert!(op_mloadw(&mut processor, &mut tracer).is_ok());
}
#[test]
fn test_op_mload() {
let mut processor = FastProcessor::new(StackInputs::default());
let mut tracer = NoopTracer;
assert_eq!(0, processor.memory().num_accessed_words());
let word: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into();
store_word(&mut processor, 4, word, &mut tracer);
op_push(&mut processor, Felt::new(4)).unwrap();
processor.system_mut().increment_clock();
op_mload(&mut processor, &mut tracer).unwrap();
processor.system_mut().increment_clock();
let expected = build_expected(&[1, 1, 3, 5, 7]);
assert_eq!(expected, processor.stack_top());
assert_eq!(1, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word =
processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap();
assert_eq!(word, stored_word);
op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap();
processor.system_mut().increment_clock();
assert!(op_mload(&mut processor, &mut tracer).is_err());
let mut processor = FastProcessor::new(StackInputs::default());
assert!(op_mload(&mut processor, &mut tracer).is_ok());
}
#[test]
fn test_op_mstream() {
let mut processor = FastProcessor::new(StackInputs::default());
let mut tracer = NoopTracer;
let word1: Word = [Felt::new(30), Felt::new(29), Felt::new(28), Felt::new(27)].into();
let word2: Word = [Felt::new(26), Felt::new(25), Felt::new(24), Felt::new(23)].into();
store_word(&mut processor, 4, word1, &mut tracer);
store_word(&mut processor, 8, word2, &mut tracer);
assert_eq!(2, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word1 =
processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap();
assert_eq!(word1, stored_word1);
let stored_word2 =
processor.memory_mut().read_word(ContextId::root(), Felt::new(8), clk).unwrap();
assert_eq!(word2, stored_word2);
for _ in 0..8 {
Processor::stack_mut(&mut processor).decrement_size().unwrap();
processor.system_mut().increment_clock();
}
op_push(&mut processor, Felt::new(101)).unwrap();
processor.system_mut().increment_clock();
op_push(&mut processor, Felt::new(4)).unwrap();
processor.system_mut().increment_clock();
for i in 1..13 {
op_push(&mut processor, Felt::new(i)).unwrap();
processor.system_mut().increment_clock();
}
op_mstream(&mut processor, &mut tracer).unwrap();
processor.system_mut().increment_clock();
let expected = build_expected(&[
word1[0].as_canonical_u64(),
word1[1].as_canonical_u64(),
word1[2].as_canonical_u64(),
word1[3].as_canonical_u64(),
word2[0].as_canonical_u64(),
word2[1].as_canonical_u64(),
word2[2].as_canonical_u64(),
word2[3].as_canonical_u64(),
4,
3,
2,
1,
4 + 8, 101, ]);
assert_eq!(expected, processor.stack_top());
}
#[test]
fn test_op_mstorew() {
let mut processor = FastProcessor::new(StackInputs::default());
let mut tracer = NoopTracer;
assert_eq!(0, processor.memory().num_accessed_words());
let word1: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into();
store_word(&mut processor, 0, word1, &mut tracer);
let expected = build_expected(&[1, 3, 5, 7]);
assert_eq!(expected, processor.stack_top());
assert_eq!(1, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word =
processor.memory_mut().read_word(ContextId::root(), Felt::new(0), clk).unwrap();
assert_eq!(word1, stored_word);
let word2: Word = [Felt::new(2), Felt::new(4), Felt::new(6), Felt::new(8)].into();
store_word(&mut processor, 4, word2, &mut tracer);
let expected = build_expected(&[2, 4, 6, 8, 1, 3, 5, 7]);
assert_eq!(expected, processor.stack_top());
assert_eq!(2, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word1 =
processor.memory_mut().read_word(ContextId::root(), Felt::new(0), clk).unwrap();
assert_eq!(word1, stored_word1);
let stored_word2 =
processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap();
assert_eq!(word2, stored_word2);
op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap();
processor.system_mut().increment_clock();
assert!(op_mstorew(&mut processor, &mut tracer).is_err());
let mut processor = FastProcessor::new(StackInputs::default());
assert!(op_mstorew(&mut processor, &mut tracer).is_ok());
}
#[test]
fn test_op_mstore() {
let mut processor = FastProcessor::new(StackInputs::default());
let mut tracer = NoopTracer;
assert_eq!(0, processor.memory().num_accessed_words());
let element = Felt::new(10);
store_element(&mut processor, 0, element, &mut tracer);
let expected = build_expected(&[10]);
assert_eq!(expected, processor.stack_top());
let expected_word: Word = [element, ZERO, ZERO, ZERO].into();
assert_eq!(1, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word =
processor.memory_mut().read_word(ContextId::root(), Felt::new(0), clk).unwrap();
assert_eq!(expected_word, stored_word);
let word2: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into();
store_word(&mut processor, 4, word2, &mut tracer);
let element2 = Felt::new(12);
store_element(&mut processor, 4, element2, &mut tracer);
let expected = build_expected(&[12, 1, 3, 5, 7, 10]);
assert_eq!(expected, processor.stack_top());
let expected_word2: Word = [element2, Felt::new(3), Felt::new(5), Felt::new(7)].into();
assert_eq!(2, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word2 =
processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap();
assert_eq!(expected_word2, stored_word2);
op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap();
processor.system_mut().increment_clock();
assert!(op_mstore(&mut processor, &mut tracer).is_err());
let mut processor = FastProcessor::new(StackInputs::default());
assert!(op_mstore(&mut processor, &mut tracer).is_ok());
}
#[test]
fn test_op_pipe() {
let advice_stack: Vec<u64> = vec![30, 29, 28, 27, 26, 25, 24, 23];
let advice_inputs = AdviceInputs::default().with_stack_values(advice_stack).unwrap();
let mut processor = FastProcessor::new(StackInputs::default()).with_advice(advice_inputs);
let mut tracer = NoopTracer;
op_push(&mut processor, Felt::new(101)).unwrap();
processor.system_mut().increment_clock();
op_push(&mut processor, Felt::new(4)).unwrap();
processor.system_mut().increment_clock();
for i in 1..13 {
op_push(&mut processor, Felt::new(i)).unwrap();
processor.system_mut().increment_clock();
}
op_pipe(&mut processor, &mut tracer).unwrap();
processor.system_mut().increment_clock();
assert_eq!(2, processor.memory().num_accessed_words());
let clk = processor.clock();
let stored_word1 =
processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap();
let stored_word2 =
processor.memory_mut().read_word(ContextId::root(), Felt::new(8), clk).unwrap();
let word1 = stored_word1;
let word2 = stored_word2;
let expected = build_expected(&[
word1[0].as_canonical_u64(),
word1[1].as_canonical_u64(),
word1[2].as_canonical_u64(),
word1[3].as_canonical_u64(),
word2[0].as_canonical_u64(),
word2[1].as_canonical_u64(),
word2[2].as_canonical_u64(),
word2[3].as_canonical_u64(),
4,
3,
2,
1,
4 + 8, 101, ]);
assert_eq!(expected, processor.stack_top());
}
fn store_word(processor: &mut FastProcessor, addr: u64, word: Word, tracer: &mut NoopTracer) {
for &value in word.iter().rev() {
op_push(processor, value).unwrap();
processor.system_mut().increment_clock();
}
op_push(processor, Felt::new(addr)).unwrap();
processor.system_mut().increment_clock();
op_mstorew(processor, tracer).unwrap();
processor.system_mut().increment_clock();
}
fn store_element(processor: &mut FastProcessor, addr: u64, value: Felt, tracer: &mut NoopTracer) {
op_push(processor, value).unwrap();
processor.system_mut().increment_clock();
op_push(processor, Felt::new(addr)).unwrap();
processor.system_mut().increment_clock();
op_mstore(processor, tracer).unwrap();
processor.system_mut().increment_clock();
}
fn build_expected(values: &[u64]) -> Vec<Felt> {
let mut expected = vec![ZERO; MIN_STACK_DEPTH];
for (i, &value) in values.iter().enumerate() {
expected[15 - i] = Felt::new(value);
}
expected
}