openvm_native_transpiler/
lib.rs

1use openvm_instructions::{instruction::Instruction, VmOpcode};
2use openvm_transpiler::{TranspilerExtension, TranspilerOutput};
3use p3_field::PrimeField32;
4
5/*
6 * The indicators use
7 * - opcode = 0x0b (custom-0 as defined in RISC-V spec document)
8 * - funct3 = 0b111
9 *
10 * `LONG_FORM_INSTRUCTION_INDICATOR` has funct7 = 0b0.
11 * `GAP_INDICATOR` has funct7 = 0b1.
12 */
13const OPCODE: u32 = 0x0b;
14const FUNCT3: u32 = 0b111;
15pub const LONG_FORM_INSTRUCTION_INDICATOR: u32 = (FUNCT3 << 12) + OPCODE;
16pub const GAP_INDICATOR: u32 = (1 << 25) + (FUNCT3 << 12) + OPCODE;
17
18pub struct LongFormTranspilerExtension;
19
20impl<F: PrimeField32> TranspilerExtension<F> for LongFormTranspilerExtension {
21    fn process_custom(&self, instruction_stream: &[u32]) -> Option<TranspilerOutput<F>> {
22        if instruction_stream[0] == LONG_FORM_INSTRUCTION_INDICATOR {
23            let num_operands = instruction_stream[1] as usize;
24            let opcode = VmOpcode::from_usize(instruction_stream[2] as usize);
25            let mut operands = vec![];
26            let mut j = 3;
27            for _ in 0..num_operands {
28                operands.push(F::from_canonical_u32(instruction_stream[j]));
29                j += 1;
30            }
31            while operands.len() < 7 {
32                operands.push(F::ZERO);
33            }
34            let instruction = Instruction {
35                opcode,
36                a: operands[0],
37                b: operands[1],
38                c: operands[2],
39                d: operands[3],
40                e: operands[4],
41                f: operands[5],
42                g: operands[6],
43            };
44            if operands.len() == 7 {
45                Some(TranspilerOutput::many_to_one(instruction, j))
46            } else {
47                None
48            }
49        } else if instruction_stream[0] == GAP_INDICATOR {
50            Some(TranspilerOutput::gap(instruction_stream[1] as usize, 2))
51        } else {
52            None
53        }
54    }
55}
56
57pub fn serialize_defined_instructions<F: PrimeField32>(
58    instructions: &[Instruction<F>],
59) -> Vec<u32> {
60    let mut words = vec![];
61    for instruction in instructions {
62        words.push(LONG_FORM_INSTRUCTION_INDICATOR);
63        let operands = instruction.operands();
64        words.push(operands.len() as u32);
65        words.push(instruction.opcode.as_usize() as u32);
66        words.extend(operands.iter().map(F::as_canonical_u32))
67    }
68    words
69}
70
71// panics if deserialization fails or results in gaps
72pub fn deserialize_defined_instructions<F: PrimeField32>(words: &[u32]) -> Vec<Instruction<F>> {
73    let mut index = 0;
74    let mut instructions = vec![];
75    while index < words.len() {
76        let next = LongFormTranspilerExtension
77            .process_custom(&words[index..])
78            .unwrap();
79        instructions.extend(next.instructions.into_iter().map(Option::unwrap));
80        index += next.used_u32s;
81    }
82    instructions
83}