zkevm_assembly/assembly/instruction/
div.rs1use super::*;
6use crate::error::InstructionReadError;
7use std::collections::HashMap;
8use std::convert::TryFrom;
9
10#[derive(Debug, Clone, PartialEq)]
14pub struct Div {
15 pub condition: ConditionCase,
17 pub set_flags_option: SetFlags,
19 pub source_1: FullOperand,
21 pub source_2: RegisterOperand,
23 pub quotient_destination: FullOperand,
25 pub remainder_destination: RegisterOperand,
27 pub swap_operands: bool,
29}
30
31impl Div {
32 pub const NUM_ARGUMENTS: usize = 4;
34
35 pub fn build_from_parts(
36 mut modifiers: HashSet<&str>,
37 operands: Vec<&str>,
38 ) -> Result<Self, InstructionReadError> {
39 let operands = parse_canonical_operands_sequence(
40 operands,
41 &[marker_full_operand(), marker_register_operand()],
42 &[marker_full_operand(), marker_register_operand()],
43 )?;
44
45 let src0 = operands[0].clone();
46 let src1 = operands[1].clone();
47 let dst0 = operands[2].clone();
48 let dst1 = operands[3].clone();
49
50 let condition = pick_condition(&mut modifiers)?;
51 let set_flags_option = pick_setting_flags(&mut modifiers)?;
52
53 let mut swap_operands = false;
54 if modifiers.remove("s") {
55 swap_operands = true;
56 }
57
58 if !modifiers.is_empty() {
59 return Err(InstructionReadError::UnknownArgument(format!(
60 "Div instruction contains unknown modifiers: {:?}",
61 modifiers
62 )));
63 }
64
65 let new = Self {
66 condition,
67 set_flags_option,
68 source_1: src0,
69 source_2: src1.as_register_operand(1)?,
70 quotient_destination: dst0,
71 remainder_destination: dst1.as_register_operand(3)?,
72 swap_operands,
73 };
74
75 Ok(new)
76 }
77
78 #[track_caller]
79 pub(crate) fn link<const N: usize, E: VmEncodingMode<N>>(
80 &mut self,
81 function_labels_to_pc: &HashMap<String, usize>,
82 constant_labels_to_offset: &HashMap<String, usize>,
83 globals_to_offsets: &HashMap<String, usize>,
84 ) -> Result<(), AssemblyParseError> {
85 link_operand::<N, E>(
86 &mut self.source_1,
87 function_labels_to_pc,
88 constant_labels_to_offset,
89 globals_to_offsets,
90 )?;
91
92 link_operand::<N, E>(
93 &mut self.quotient_destination,
94 function_labels_to_pc,
95 constant_labels_to_offset,
96 globals_to_offsets,
97 )?;
98
99 Ok(())
100 }
101}
102
103impl<const N: usize, E: VmEncodingMode<N>> TryFrom<Div> for DecodedOpcode<N, E> {
104 type Error = InstructionReadError;
105 fn try_from(value: Div) -> Result<Self, Self::Error> {
106 let mut new = DecodedOpcode::default();
107 new.variant = OpcodeVariant {
108 opcode: Opcode::Div(DivOpcode),
109 ..OpcodeVariant::default()
110 };
111 set_src0_or_dst0_full_operand(&value.source_1.as_generic_operand(0)?, &mut new, false);
112 set_register_operand(&value.source_2, &mut new, false);
113 set_src0_or_dst0_full_operand(
114 &value.quotient_destination.as_generic_operand(2)?,
115 &mut new,
116 true,
117 );
118 set_register_operand(&value.remainder_destination, &mut new, true);
119 new.condition = value.condition.0;
120 new.variant.flags[SET_FLAGS_FLAG_IDX] = value.set_flags_option.0;
121 new.variant.flags[SWAP_OPERANDS_FLAG_IDX_FOR_ARITH_OPCODES] = value.swap_operands;
122
123 Ok(new)
124 }
125}