1 //! Generate format-related Rust code; this also includes generation of encoding
2 //! Rust code.
3 use super::{Formatter, fmtln};
4 use crate::dsl;
5 
6 /// Different methods of emitting a ModR/M operand and encoding various bits and
7 /// pieces of information into it. The REX/VEX formats plus the operand kinds
8 /// dictate how exactly each instruction uses this, if at all.
9 #[derive(Copy, Clone)]
10 enum ModRmStyle {
11     /// This instruction does not use a ModR/M byte.
12     None,
13 
14     /// The R/M bits are encoded with `rm` which is a `Gpr` or `Xmm` (it does
15     /// not have a "mem" possibility), and the Reg/Opcode bits are encoded
16     /// with `reg`.
17     Reg { reg: ModRmReg, rm: dsl::Location },
18 
19     /// The R/M bits are encoded with `rm` which is a `GprMem` or `XmmMem`, and
20     /// the Reg/Opcode bits are encoded with `reg`.
21     RegMem {
22         reg: ModRmReg,
23         rm: dsl::Location,
24         evex_scaling: Option<i8>,
25     },
26 
27     /// Same as `RegMem` above except that this is also used for VEX-encoded
28     /// instructions with "/is4" which indicates that the 4th register operand
29     /// is encoded in a byte after the ModR/M byte.
30     RegMemIs4 {
31         reg: ModRmReg,
32         rm: dsl::Location,
33         is4: dsl::Location,
34         evex_scaling: Option<i8>,
35     },
36 }
37 
38 /// Different methods of encoding the Reg/Opcode bits in a ModR/M byte.
39 #[derive(Copy, Clone)]
40 enum ModRmReg {
41     /// A static set of bits is used.
42     Digit(u8),
43     /// A runtime-defined register is used with this field name.
44     Reg(dsl::Location),
45 }
46 
47 impl dsl::Format {
48     /// Re-order the Intel-style operand order to accommodate ATT-style
49     /// printing.
50     ///
51     /// This is an unfortunate necessity to match Cranelift's current
52     /// disassembly, which uses AT&T-style printing. The plan is to eventually
53     /// transition to Intel-style printing (and avoid this awkward reordering)
54     /// once Cranelift has switched to using this assembler predominantly
55     /// (TODO).
56     #[must_use]
generate_att_style_operands(&self) -> String57     pub(crate) fn generate_att_style_operands(&self) -> String {
58         let ordered_ops: Vec<_> = self
59             .operands
60             .iter()
61             .filter(|o| !o.implicit)
62             .rev()
63             .map(|o| format!("{{{}}}", o.location))
64             .collect();
65         ordered_ops.join(", ")
66     }
67 
68     #[must_use]
generate_implicit_operands(&self) -> String69     pub(crate) fn generate_implicit_operands(&self) -> String {
70         let ops: Vec<_> = self
71             .operands
72             .iter()
73             .filter(|o| o.implicit)
74             .map(|o| format!("{{{}}}", o.location))
75             .collect();
76         if ops.is_empty() {
77             String::new()
78         } else {
79             format!(" ;; implicit: {}", ops.join(", "))
80         }
81     }
82 
generate_rex_encoding(&self, f: &mut Formatter, rex: &dsl::Rex)83     pub(crate) fn generate_rex_encoding(&self, f: &mut Formatter, rex: &dsl::Rex) {
84         self.generate_prefixes(f, rex);
85         let style = self.generate_rex_prefix(f, rex);
86         rex.generate_opcodes(f, self.locations().next());
87         self.generate_modrm_byte(f, style);
88         self.generate_immediate(f, style);
89     }
90 
generate_vex_encoding(&self, f: &mut Formatter, vex: &dsl::Vex)91     pub fn generate_vex_encoding(&self, f: &mut Formatter, vex: &dsl::Vex) {
92         let style = self.generate_vex_prefix(f, vex);
93         vex.generate_opcode(f);
94         self.generate_modrm_byte(f, style);
95         self.generate_immediate(f, style);
96     }
97 
generate_evex_encoding(&self, f: &mut Formatter, evex: &dsl::Evex)98     pub fn generate_evex_encoding(&self, f: &mut Formatter, evex: &dsl::Evex) {
99         let style = self.generate_evex_prefix(f, evex);
100         evex.generate_opcode(f);
101         self.generate_modrm_byte(f, style);
102         self.generate_immediate(f, style);
103     }
104 
105     /// `buf.put1(...);`
generate_prefixes(&self, f: &mut Formatter, rex: &dsl::Rex)106     fn generate_prefixes(&self, f: &mut Formatter, rex: &dsl::Rex) {
107         if !rex.opcodes.prefixes.is_empty() {
108             f.empty_line();
109             f.comment("Emit prefixes.");
110         }
111         if let Some(group1) = &rex.opcodes.prefixes.group1 {
112             fmtln!(f, "buf.put1({group1});");
113         }
114         if let Some(group2) = &rex.opcodes.prefixes.group2 {
115             fmtln!(f, "buf.put1({group2});");
116         }
117         if let Some(group3) = &rex.opcodes.prefixes.group3 {
118             fmtln!(f, "buf.put1({group3});");
119         }
120         if let Some(group4) = &rex.opcodes.prefixes.group4 {
121             fmtln!(f, "buf.put1({group4});");
122         }
123     }
124 
generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) -> ModRmStyle125     fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) -> ModRmStyle {
126         use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
127 
128         // If this instruction has only immediates there's no rex/modrm/etc, so
129         // skip everything below.
130         match self.operands_by_kind().as_slice() {
131             [] | [Imm(_)] => return ModRmStyle::None,
132             _ => {}
133         }
134 
135         f.empty_line();
136         f.comment("Possibly emit REX prefix.");
137 
138         let find_8bit_registers =
139             |l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Reg(_) | RegMem(_));
140         let uses_8bit = self.locations().any(find_8bit_registers);
141         fmtln!(f, "let uses_8bit = {uses_8bit};");
142         fmtln!(f, "let w_bit = {};", rex.w.as_bool());
143         let bits = "w_bit, uses_8bit";
144 
145         let style = match self.operands_by_kind().as_slice() {
146             [FixedReg(dst), FixedReg(_)] | [FixedReg(dst)] | [FixedReg(dst), Imm(_)] => {
147                 // TODO: don't emit REX byte here.
148                 assert_eq!(rex.unwrap_digit(), None);
149                 fmtln!(f, "let digit = 0;");
150                 fmtln!(f, "let dst = self.{dst}.enc();");
151                 fmtln!(f, "let rex = RexPrefix::with_digit(digit, dst, {bits});");
152                 ModRmStyle::None
153             }
154             [Reg(dst)] => {
155                 assert_eq!(rex.unwrap_digit(), None);
156                 assert!(rex.opcode_mod.is_some());
157                 fmtln!(f, "let dst = self.{dst}.enc();");
158                 fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
159                 ModRmStyle::None
160             }
161             [Reg(dst), Imm(_)] => match rex.unwrap_digit() {
162                 Some(digit) => {
163                     fmtln!(f, "let digit = 0x{digit:x};");
164                     fmtln!(f, "let dst = self.{dst}.enc();");
165                     fmtln!(f, "let rex = RexPrefix::two_op(digit, dst, {bits});");
166                     ModRmStyle::Reg {
167                         reg: ModRmReg::Digit(digit),
168                         rm: *dst,
169                     }
170                 }
171                 None => {
172                     assert!(rex.opcode_mod.is_some());
173                     fmtln!(f, "let dst = self.{dst}.enc();");
174                     fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
175                     ModRmStyle::None
176                 }
177             },
178             [FixedReg(_), RegMem(mem)]
179             | [FixedReg(_), FixedReg(_), RegMem(mem)]
180             | [RegMem(mem), FixedReg(_)]
181             | [Mem(mem), Imm(_)]
182             | [RegMem(mem), Imm(_)]
183             | [RegMem(mem)]
184             | [FixedReg(_), FixedReg(_), FixedReg(_), FixedReg(_), Mem(mem)] => {
185                 let digit = rex.unwrap_digit().unwrap();
186                 fmtln!(f, "let digit = 0x{digit:x};");
187                 fmtln!(f, "let rex = self.{mem}.as_rex_prefix(digit, {bits});");
188                 ModRmStyle::RegMem {
189                     reg: ModRmReg::Digit(digit),
190                     rm: *mem,
191                     evex_scaling: None,
192                 }
193             }
194             [Reg(reg), RegMem(mem) | Mem(mem)]
195             | [Reg(reg), RegMem(mem), Imm(_) | FixedReg(_)]
196             | [RegMem(mem) | Mem(mem), Reg(reg)]
197             | [RegMem(mem) | Mem(mem), Reg(reg), Imm(_) | FixedReg(_)] => {
198                 fmtln!(f, "let reg = self.{reg}.enc();");
199                 fmtln!(f, "let rex = self.{mem}.as_rex_prefix(reg, {bits});");
200                 ModRmStyle::RegMem {
201                     reg: ModRmReg::Reg(*reg),
202                     rm: *mem,
203                     evex_scaling: None,
204                 }
205             }
206             [Reg(dst), Reg(src), Imm(_)] | [Reg(dst), Reg(src)] => {
207                 fmtln!(f, "let reg = self.{dst}.enc();");
208                 fmtln!(f, "let rm = self.{src}.enc();");
209                 fmtln!(f, "let rex = RexPrefix::two_op(reg, rm, {bits});");
210                 ModRmStyle::Reg {
211                     reg: ModRmReg::Reg(*dst),
212                     rm: *src,
213                 }
214             }
215 
216             unknown => unimplemented!("unknown pattern: {unknown:?}"),
217         };
218 
219         fmtln!(f, "rex.encode(buf);");
220         style
221     }
222 
generate_vex_prefix(&self, f: &mut Formatter, vex: &dsl::Vex) -> ModRmStyle223     fn generate_vex_prefix(&self, f: &mut Formatter, vex: &dsl::Vex) -> ModRmStyle {
224         f.empty_line();
225         f.comment("Emit VEX prefix.");
226         fmtln!(f, "let len = {:#03b};", vex.length.vex_bits());
227         fmtln!(f, "let pp = {:#04b};", vex.pp.map_or(0b00, |pp| pp.bits()));
228         fmtln!(f, "let mmmmm = {:#07b};", vex.mmmmm.unwrap().bits());
229         fmtln!(f, "let w = {};", vex.w.as_bool());
230         let bits = "len, pp, mmmmm, w";
231 
232         self.generate_vex_or_evex_prefix(f, "VexPrefix", &bits, vex.is4, None, || {
233             vex.unwrap_digit()
234         })
235     }
236 
generate_evex_prefix(&self, f: &mut Formatter, evex: &dsl::Evex) -> ModRmStyle237     fn generate_evex_prefix(&self, f: &mut Formatter, evex: &dsl::Evex) -> ModRmStyle {
238         f.empty_line();
239         f.comment("Emit EVEX prefix.");
240         let ll = evex.length.evex_bits();
241         fmtln!(f, "let ll = {ll:#04b};");
242         fmtln!(f, "let pp = {:#04b};", evex.pp.map_or(0b00, |pp| pp.bits()));
243         fmtln!(f, "let mmm = {:#07b};", evex.mmm.unwrap().bits());
244         fmtln!(f, "let w = {};", evex.w.as_bool());
245         // NB: when bcast is supported in the future the `evex_scaling`
246         // calculation for `Full` and `Half` below need to be updated.
247         let bcast = false;
248         fmtln!(f, "let bcast = {bcast};");
249         let bits = format!("ll, pp, mmm, w, bcast");
250         let is4 = false;
251 
252         let length_bytes = match evex.length {
253             dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),
254             dsl::Length::L128 => 16,
255             dsl::Length::L256 => 32,
256             dsl::Length::L512 => 64,
257         };
258 
259         // Figure out, according to table 2-34 and 2-35 in the Intel manual,
260         // what the scaling factor is for 8-bit displacements to pass through to
261         // encoding.
262         let evex_scaling = Some(match evex.tuple_type {
263             dsl::TupleType::Full => {
264                 assert!(!bcast);
265                 length_bytes
266             }
267             dsl::TupleType::Half => {
268                 assert!(!bcast);
269                 length_bytes / 2
270             }
271             dsl::TupleType::FullMem => length_bytes,
272             // FIXME: according to table 2-35 this needs to take into account
273             // "InputSize" which isn't accounted for in our `Evex` structure at
274             // this time.
275             dsl::TupleType::Tuple1Scalar => unimplemented!(),
276             dsl::TupleType::Tuple1Fixed => unimplemented!(),
277             dsl::TupleType::Tuple2 => unimplemented!(),
278             dsl::TupleType::Tuple4 => unimplemented!(),
279             dsl::TupleType::Tuple8 => 32,
280             dsl::TupleType::HalfMem => length_bytes / 2,
281             dsl::TupleType::QuarterMem => length_bytes / 4,
282             dsl::TupleType::EigthMem => length_bytes / 8,
283             dsl::TupleType::Mem128 => 16,
284             dsl::TupleType::Movddup => match evex.length {
285                 dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),
286                 dsl::Length::L128 => 8,
287                 dsl::Length::L256 => 32,
288                 dsl::Length::L512 => 64,
289             },
290         });
291 
292         self.generate_vex_or_evex_prefix(f, "EvexPrefix", &bits, is4, evex_scaling, || {
293             evex.unwrap_digit()
294         })
295     }
296 
297     /// Helper function to generate either a vex or evex prefix, mostly handling
298     /// all the operand formats and structures here the same between the two
299     /// forms.
generate_vex_or_evex_prefix( &self, f: &mut Formatter, prefix_type: &str, bits: &str, is4: bool, evex_scaling: Option<i8>, unwrap_digit: impl Fn() -> Option<u8>, ) -> ModRmStyle300     fn generate_vex_or_evex_prefix(
301         &self,
302         f: &mut Formatter,
303         prefix_type: &str,
304         bits: &str,
305         is4: bool,
306         evex_scaling: Option<i8>,
307         unwrap_digit: impl Fn() -> Option<u8>,
308     ) -> ModRmStyle {
309         use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
310 
311         let style = match self.operands_by_kind().as_slice() {
312             [Reg(reg), Reg(vvvv), Reg(rm)] => {
313                 assert!(!is4);
314                 fmtln!(f, "let reg = self.{reg}.enc();");
315                 fmtln!(f, "let vvvv = self.{vvvv}.enc();");
316                 fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
317                 fmtln!(
318                     f,
319                     "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
320                 );
321                 ModRmStyle::Reg {
322                     reg: ModRmReg::Reg(*reg),
323                     rm: *rm,
324                 }
325             }
326             [Reg(reg), Reg(vvvv), RegMem(rm)]
327             | [Reg(reg), Reg(vvvv), Mem(rm)]
328             | [Reg(reg), Reg(vvvv), RegMem(rm), Imm(_) | FixedReg(_)]
329             | [Reg(reg), RegMem(rm), Reg(vvvv)] => {
330                 assert!(!is4);
331                 fmtln!(f, "let reg = self.{reg}.enc();");
332                 fmtln!(f, "let vvvv = self.{vvvv}.enc();");
333                 fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
334                 fmtln!(
335                     f,
336                     "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
337                 );
338                 ModRmStyle::RegMem {
339                     reg: ModRmReg::Reg(*reg),
340                     rm: *rm,
341                     evex_scaling,
342                 }
343             }
344             [Reg(reg), Reg(vvvv), RegMem(rm), Reg(r_is4)] => {
345                 assert!(is4);
346                 fmtln!(f, "let reg = self.{reg}.enc();");
347                 fmtln!(f, "let vvvv = self.{vvvv}.enc();");
348                 fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
349                 fmtln!(
350                     f,
351                     "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
352                 );
353                 ModRmStyle::RegMemIs4 {
354                     reg: ModRmReg::Reg(*reg),
355                     rm: *rm,
356                     is4: *r_is4,
357                     evex_scaling,
358                 }
359             }
360             [Reg(reg_or_vvvv), RegMem(rm)]
361             | [RegMem(rm), Reg(reg_or_vvvv)]
362             | [Reg(reg_or_vvvv), RegMem(rm), Imm(_)] => match unwrap_digit() {
363                 Some(digit) => {
364                     assert!(!is4);
365                     let vvvv = reg_or_vvvv;
366                     fmtln!(f, "let reg = {digit:#x};");
367                     fmtln!(f, "let vvvv = self.{vvvv}.enc();");
368                     fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
369                     fmtln!(
370                         f,
371                         "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
372                     );
373                     ModRmStyle::RegMem {
374                         reg: ModRmReg::Digit(digit),
375                         rm: *rm,
376                         evex_scaling,
377                     }
378                 }
379                 None => {
380                     assert!(!is4);
381                     let reg = reg_or_vvvv;
382                     fmtln!(f, "let reg = self.{reg}.enc();");
383                     fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
384                     fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
385                     ModRmStyle::RegMem {
386                         reg: ModRmReg::Reg(*reg),
387                         rm: *rm,
388                         evex_scaling,
389                     }
390                 }
391             },
392             [Reg(reg_or_vvvv), Reg(rm)] | [Reg(reg_or_vvvv), Reg(rm), Imm(_)] => {
393                 match unwrap_digit() {
394                     Some(digit) => {
395                         assert!(!is4);
396                         let vvvv = reg_or_vvvv;
397                         fmtln!(f, "let reg = {digit:#x};");
398                         fmtln!(f, "let vvvv = self.{vvvv}.enc();");
399                         fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
400                         fmtln!(
401                             f,
402                             "let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
403                         );
404                         ModRmStyle::Reg {
405                             reg: ModRmReg::Digit(digit),
406                             rm: *rm,
407                         }
408                     }
409                     None => {
410                         assert!(!is4);
411                         let reg = reg_or_vvvv;
412                         fmtln!(f, "let reg = self.{reg}.enc();");
413                         fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
414                         fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
415                         ModRmStyle::Reg {
416                             reg: ModRmReg::Reg(*reg),
417                             rm: *rm,
418                         }
419                     }
420                 }
421             }
422             [Reg(reg), Mem(rm)] | [Mem(rm), Reg(reg)] | [RegMem(rm), Reg(reg), Imm(_)] => {
423                 assert!(!is4);
424                 fmtln!(f, "let reg = self.{reg}.enc();");
425                 fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
426                 fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
427                 ModRmStyle::RegMem {
428                     reg: ModRmReg::Reg(*reg),
429                     rm: *rm,
430                     evex_scaling,
431                 }
432             }
433             unknown => unimplemented!("unknown pattern: {unknown:?}"),
434         };
435 
436         fmtln!(f, "prefix.encode(buf);");
437         style
438     }
439 
generate_modrm_byte(&self, f: &mut Formatter, modrm_style: ModRmStyle)440     fn generate_modrm_byte(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
441         let operands = self.operands_by_kind();
442         let bytes_at_end = match operands.as_slice() {
443             [.., dsl::OperandKind::Imm(imm)] => imm.bytes(),
444             _ => match modrm_style {
445                 ModRmStyle::RegMemIs4 { .. } => 1,
446                 _ => 0,
447             },
448         };
449 
450         f.empty_line();
451 
452         match modrm_style {
453             ModRmStyle::None => f.comment("No need to emit a ModRM byte."),
454             _ => f.comment("Emit ModR/M byte."),
455         }
456 
457         match modrm_style {
458             ModRmStyle::None => {}
459             ModRmStyle::RegMem {
460                 reg,
461                 rm,
462                 evex_scaling,
463             }
464             | ModRmStyle::RegMemIs4 {
465                 reg,
466                 rm,
467                 is4: _,
468                 evex_scaling,
469             } => {
470                 match reg {
471                     ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
472                     ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
473                 }
474                 fmtln!(
475                     f,
476                     "self.{rm}.encode_rex_suffixes(buf, reg, {bytes_at_end}, {evex_scaling:?});"
477                 );
478             }
479             ModRmStyle::Reg { reg, rm } => {
480                 match reg {
481                     ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
482                     ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
483                 }
484                 fmtln!(f, "self.{rm}.encode_modrm(buf, reg);");
485             }
486         }
487     }
488 
generate_immediate(&self, f: &mut Formatter, modrm_style: ModRmStyle)489     fn generate_immediate(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
490         use dsl::OperandKind::Imm;
491         match self.operands_by_kind().as_slice() {
492             [prefix @ .., Imm(imm)] => {
493                 assert!(!prefix.iter().any(|o| matches!(o, Imm(_))));
494                 f.empty_line();
495                 f.comment("Emit immediate.");
496                 fmtln!(f, "self.{imm}.encode(buf);");
497             }
498             unknown => {
499                 if let ModRmStyle::RegMemIs4 { is4, .. } = modrm_style {
500                     fmtln!(f, "buf.put1(self.{is4}.enc() << 4);");
501                 }
502 
503                 // Do nothing: no immediates expected.
504                 assert!(!unknown.iter().any(|o| matches!(o, Imm(_))));
505             }
506         }
507     }
508 }
509 
510 impl dsl::Rex {
511     // `buf.put1(...);`
generate_opcodes(&self, f: &mut Formatter, first_op: Option<&dsl::Location>)512     fn generate_opcodes(&self, f: &mut Formatter, first_op: Option<&dsl::Location>) {
513         f.empty_line();
514         f.comment("Emit opcode(s).");
515         if self.opcodes.escape {
516             fmtln!(f, "buf.put1(0x0f);");
517         }
518         if self.opcode_mod.is_some() {
519             let first_op = first_op.expect("Expected first operand for opcode_mod");
520             assert!(matches!(first_op.kind(), dsl::OperandKind::Reg(_)));
521             fmtln!(f, "let low_bits = self.{first_op}.enc() & 0b111;");
522             fmtln!(f, "buf.put1(0x{:x} | low_bits);", self.opcodes.primary);
523         } else {
524             fmtln!(f, "buf.put1(0x{:x});", self.opcodes.primary);
525         }
526         if let Some(secondary) = self.opcodes.secondary {
527             fmtln!(f, "buf.put1(0x{:x});", secondary);
528         }
529     }
530 }
531 
532 impl dsl::Vex {
533     // `buf.put1(...);`
generate_opcode(&self, f: &mut Formatter)534     fn generate_opcode(&self, f: &mut Formatter) {
535         f.empty_line();
536         f.comment("Emit opcode.");
537         fmtln!(f, "buf.put1(0x{:x});", self.opcode);
538     }
539 }
540 
541 impl dsl::Evex {
542     // `buf.put1(...);`
generate_opcode(&self, f: &mut Formatter)543     fn generate_opcode(&self, f: &mut Formatter) {
544         f.empty_line();
545         f.comment("Emit opcode.");
546         fmtln!(f, "buf.put1(0x{:x});", self.opcode);
547     }
548 }
549