zkevm_assembly/assembly/instruction/
div.rs

1//!
2//! The arithmetic division or remainder instruction.
3//!
4
5use super::*;
6use crate::error::InstructionReadError;
7use std::collections::HashMap;
8use std::convert::TryFrom;
9
10///
11/// The arithmetic division or remainder instruction.
12///
13#[derive(Debug, Clone, PartialEq)]
14pub struct Div {
15    /// Condition for execution
16    pub condition: ConditionCase,
17    /// Whether we set flags or not
18    pub set_flags_option: SetFlags,
19    /// The first source operand.
20    pub source_1: FullOperand,
21    /// The second source register.
22    pub source_2: RegisterOperand,
23    /// The quotient destination register.
24    pub quotient_destination: FullOperand,
25    /// The remainder destination register.
26    pub remainder_destination: RegisterOperand,
27    /// if it is set then source operands have be swapped.
28    pub swap_operands: bool,
29}
30
31impl Div {
32    // Total number of arguments in canonical form
33    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}