1use std::mem::{size_of, transmute};
2
3use crate::opcode::Opcode;
4use zkvmc_trace::{RecordDecoder, RecordEncoder};
5
6pub const RECORD_SIZE: usize = size_of::<Rv32imRecord<u32>>() / 4;
7
8const _: () = assert!(std::mem::size_of::<Rv32imRecord<u32>>() / 4 == RECORD_SIZE);
9
10#[derive(Debug, Clone, Copy)]
13#[repr(C)]
14pub struct Rv32imRecord<T> {
15 pub opcode: Opcode,
17 pub a: T,
19 pub a_record: MemoryRecord<T>,
21 pub b: T,
23 pub b_record: MemoryRecord<T>,
25 pub c: T,
27 pub c_record: MemoryRecord<T>,
29 pub op_a_0: OperandA,
31}
32
33#[derive(Debug, Clone, Copy)]
34#[repr(u32)]
35pub enum OperandA {
36 Zero = 0,
37 NonZero = 1,
38}
39
40impl OperandA {
41 pub fn new(r: usize) -> OperandA {
42 if r == 0 {
43 OperandA::Zero
44 } else {
45 OperandA::NonZero
46 }
47 }
48}
49
50#[derive(Debug, Clone, Copy)]
51#[repr(u32)]
52pub enum MemoryRecord<T> {
53 None,
55 Read(T),
57 Write(T),
59}
60
61impl RecordDecoder for Rv32imRecord<u32> {
62 type Value = u32;
63
64 fn decode(buf: &[u32]) -> Self {
65 const OFFSET: usize = 0;
66 Self {
67 opcode: unsafe { transmute(buf[OFFSET]) },
68 a: buf[OFFSET + 1],
69 a_record: decode_option_memory_record(buf, OFFSET + 2),
70 b: buf[OFFSET + 4],
71 b_record: decode_option_memory_record(buf, OFFSET + 5),
72 c: buf[OFFSET + 7],
73 c_record: decode_option_memory_record(buf, OFFSET + 8),
74 op_a_0: unsafe { transmute(buf[OFFSET + 10]) },
75 }
76 }
77}
78
79impl<T: Copy> RecordEncoder for Rv32imRecord<T> {
80 type Value = T;
81 const RECORD_SIZE: usize = RECORD_SIZE;
82
83 fn encode(&self, buf: &mut [Self::Value], mut const_value: impl FnMut(u32) -> Self::Value) {
84 const OFFSET: usize = 0;
85 buf[OFFSET] = const_value(self.opcode as u32);
86 buf[OFFSET + 1] = self.a;
87 encode_option_memory_record(buf, OFFSET + 2, self.a_record, &mut const_value);
88 buf[OFFSET + 4] = self.b;
89 encode_option_memory_record(buf, OFFSET + 5, self.b_record, &mut const_value);
90 buf[OFFSET + 7] = self.c;
91 encode_option_memory_record(buf, OFFSET + 8, self.c_record, &mut const_value);
92 buf[OFFSET + 10] = const_value(self.op_a_0 as u32);
93 }
94}
95
96fn encode_option_memory_record<T>(
97 buf: &mut [T],
98 offset: usize,
99 value: MemoryRecord<T>,
100 mut const_value: impl FnMut(u32) -> T,
101) {
102 match value {
103 MemoryRecord::None => {
104 buf[offset] = const_value(0);
105 buf[offset + 1] = const_value(0);
106 }
107 MemoryRecord::Read(v) => {
108 buf[offset] = const_value(1);
109 buf[offset + 1] = v;
110 }
111 MemoryRecord::Write(v) => {
112 buf[offset] = const_value(2);
113 buf[offset + 1] = v;
114 }
115 }
116}
117
118fn decode_option_memory_record(buf: &[u32], offset: usize) -> MemoryRecord<u32> {
119 match buf[offset] {
120 0 => MemoryRecord::None,
121 1 => MemoryRecord::Read(buf[offset + 1]),
122 2 => MemoryRecord::Write(buf[offset + 1]),
123 _ => unreachable!(),
124 }
125}