1use openvm_circuit::arch::instructions::{
2 instruction::{Instruction, NUM_OPERANDS},
3 program::Program,
4 LocalOpcode,
5};
6use openvm_continuations::F;
7use openvm_native_compiler::{asm::A0, conversion::AS, NativeJalOpcode};
8use openvm_stark_backend::p3_field::{FieldAlgebra, PrimeField32};
9use rrs_lib::instruction_formats::IType;
10
11const OPCODE: u32 = 0x0b;
12const FUNCT3: u32 = 0b111;
13const LONG_FORM_INSTRUCTION_INDICATOR: u32 = (FUNCT3 << 12) + OPCODE;
14const GAP_INDICATOR: u32 = (1 << 25) + (FUNCT3 << 12) + OPCODE;
15
16pub fn program_to_asm(mut program: Program<F>) -> String {
17 let pc_diff = handle_pc_diff(&mut program);
18 let assembly_and_comments = convert_program_to_u32s_and_comments(&program, pc_diff);
19 let mut asm_output = String::new();
20 for (u32s, comment) in &assembly_and_comments {
21 for (idx, x) in u32s.iter().enumerate() {
22 asm_output.push_str(&u32_to_directive(*x));
23 if idx == 0 {
24 asm_output.push_str(" // ");
25 asm_output.push_str(comment);
26 }
27 asm_output.push('\n');
28 }
29 }
30 asm_output
31}
32
33fn u32_to_directive(x: u32) -> String {
34 let opcode = x & 0b1111111;
35 let dec_insn = IType::new(x);
36 format!(
37 ".insn i {}, {}, x{}, x{}, {}",
38 opcode, dec_insn.funct3, dec_insn.rd, dec_insn.rs1, dec_insn.imm
39 )
40}
41
42fn handle_pc_diff(program: &mut Program<F>) -> usize {
53 const GAP_INDICATOR_WIDTH: usize = 2;
54 const LONG_FORM_NATIVE_INSTRUCTION_WIDTH: usize = 10;
55 const PC_STEP: usize = 4;
56 let mut pc_diff = GAP_INDICATOR_WIDTH;
58 pc_diff += program.num_defined_instructions() * (LONG_FORM_NATIVE_INSTRUCTION_WIDTH - 1);
60 pc_diff += LONG_FORM_NATIVE_INSTRUCTION_WIDTH - 1;
62 let jal = Instruction::<F> {
63 opcode: NativeJalOpcode::JAL.global_opcode(),
64 a: F::from_canonical_usize(A0 as usize), b: F::from_canonical_usize(PC_STEP * (pc_diff + 1)),
67 c: F::from_canonical_usize(0),
68 d: F::from_canonical_u32(AS::Native as u32),
69 e: F::from_canonical_usize(0),
70 f: F::from_canonical_usize(0),
71 g: F::from_canonical_usize(0),
72 };
73 program.push_instruction(jal);
74 pc_diff
75}
76
77fn convert_program_to_u32s_and_comments(
78 program: &Program<F>,
79 pc_diff: usize,
80) -> Vec<(Vec<u32>, String)> {
81 program
82 .defined_instructions()
83 .iter()
84 .map(|ins| {
85 (
86 vec![
87 LONG_FORM_INSTRUCTION_INDICATOR,
88 NUM_OPERANDS as u32,
89 ins.opcode.as_usize() as u32,
90 ins.a.as_canonical_u32(),
91 ins.b.as_canonical_u32(),
92 ins.c.as_canonical_u32(),
93 ins.d.as_canonical_u32(),
94 ins.e.as_canonical_u32(),
95 ins.f.as_canonical_u32(),
96 ins.g.as_canonical_u32(),
97 ],
98 format!("{:?}", ins.opcode),
99 )
100 })
101 .chain(std::iter::once((
102 vec![GAP_INDICATOR, pc_diff as u32],
103 "GAP_INDICATOR".to_string(),
104 )))
105 .collect()
106}