Merge branch 'indirect'
[platform/upstream/nasm.git] / insns.pl
1 #!/usr/bin/perl
2 #
3 # insns.pl   produce insnsa.c, insnsd.c, insnsi.h, insnsn.c from insns.dat
4 #
5 # The Netwide Assembler is copyright (C) 1996 Simon Tatham and
6 # Julian Hall. All rights reserved. The software is
7 # redistributable under the license given in the file "LICENSE"
8 # distributed in the NASM archive.
9
10 # Opcode prefixes which need their own opcode tables
11 # LONGER PREFIXES FIRST!
12 @disasm_prefixes = qw(0F24 0F25 0F38 0F3A 0F7A 0FA6 0FA7 0F);
13
14 # This should match MAX_OPERANDS from nasm.h
15 $MAX_OPERANDS = 5;
16
17 # Add VEX prefixes
18 @vexlist = ();
19 for ($m = 0; $m < 32; $m++) {
20     for ($lp = 0; $lp < 8; $lp++) {
21         push(@vexlist, sprintf("VEX%02X%01X", $m, $lp));
22     }
23 }
24 @disasm_prefixes = (@vexlist, @disasm_prefixes);
25
26 @bytecode_count = (0) x 256;
27
28 print STDERR "Reading insns.dat...\n";
29
30 @args   = ();
31 undef $output;
32 foreach $arg ( @ARGV ) {
33     if ( $arg =~ /^\-/ ) {
34         if  ( $arg =~ /^\-([abdin])$/ ) {
35             $output = $1;
36         } else {
37             die "$0: Unknown option: ${arg}\n";
38         }
39     } else {
40         push (@args, $arg);
41     }
42 }
43
44 $fname = "insns.dat" unless $fname = $args[0];
45 open (F, $fname) || die "unable to open $fname";
46
47 %dinstables = ();
48 @bytecode_list = ();
49
50 $line = 0;
51 $insns = 0;
52 while (<F>) {
53   $line++;
54   chomp;
55   next if ( /^\s*(\;.*|)$/ );   # comments or blank lines
56
57   unless (/^\s*(\S+)\s+(\S+)\s+(\S+|\[.*\])\s+(\S+)\s*$/) {
58       warn "line $line does not contain four fields\n";
59       next;
60   }
61   @fields = ($1, $2, $3, $4);
62   ($formatted, $nd) = format_insn(@fields);
63   if ($formatted) {
64     $insns++;
65     $aname = "aa_$fields[0]";
66     push @$aname, $formatted;
67   }
68   if ( $fields[0] =~ /cc$/ ) {
69       # Conditional instruction
70       $k_opcodes_cc{$fields[0]}++;
71   } else {
72       # Unconditional instruction
73       $k_opcodes{$fields[0]}++;
74   }
75   if ($formatted && !$nd) {
76     push @big, $formatted;
77     my @sseq = startseq($fields[2]);
78     foreach $i (@sseq) {
79         if (!defined($dinstables{$i})) {
80             $dinstables{$i} = [];
81         }
82         push(@{$dinstables{$i}}, $#big);
83     }
84   }
85 }
86
87 close F;
88
89 #
90 # Generate the bytecode array.  At this point, @bytecode_list contains
91 # the full set of bytecodes.
92 #
93
94 # Sort by descending length
95 @bytecode_list = sort { scalar(@$b) <=> scalar(@$a) } @bytecode_list;
96 @bytecode_array = ();
97 %bytecode_pos = ();
98 $bytecode_next = 0;
99 foreach $bl (@bytecode_list) {
100     my $h = hexstr(@$bl);
101     next if (defined($bytecode_pos{$h}));
102
103     push(@bytecode_array, $bl);
104     while ($h ne '') {
105         $bytecode_pos{$h} = $bytecode_next;
106         $h = substr($h, 2);
107         $bytecode_next++;
108     }
109 }
110 undef @bytecode_list;
111
112 @opcodes    = sort keys(%k_opcodes);
113 @opcodes_cc = sort keys(%k_opcodes_cc);
114
115 if ( !defined($output) || $output eq 'b') {
116     print STDERR "Writing insnsb.c...\n";
117
118     open B, ">insnsb.c";
119
120     print B "/* This file auto-generated from insns.dat by insns.pl" .
121         " - don't edit it */\n\n";
122
123     print B "#include \"nasm.h\"\n";
124     print B "#include \"insns.h\"\n\n";
125
126     print B "const uint8_t nasm_bytecodes[$bytecode_next] = {\n";
127
128     $p = 0;
129     foreach $bl (@bytecode_array) {
130         printf B "    /* %5d */ ", $p;
131         foreach $d (@$bl) {
132             printf B "%#o,", $d;
133             $p++;
134         }
135         printf B "\n";
136     }
137     print B "};\n";
138
139     print B "\n";
140     print B "/*\n";
141     print B " * Bytecode frequencies (including reuse):\n";
142     print B " *\n";
143     for ($i = 0; $i < 32; $i++) {
144         print B " *";
145         for ($j = 0; $j < 256; $j += 32) {
146             print B " |" if ($j);
147             printf B " %3o:%4d", $i+$j, $bytecode_count[$i+$j];
148         }
149         print B "\n";
150     }
151     print B " */\n";
152
153     close B;
154 }
155
156 if ( !defined($output) || $output eq 'a' ) {
157     print STDERR "Writing insnsa.c...\n";
158
159     open A, ">insnsa.c";
160
161     print A "/* This file auto-generated from insns.dat by insns.pl" .
162         " - don't edit it */\n\n";
163
164     print A "#include \"nasm.h\"\n";
165     print A "#include \"insns.h\"\n\n";
166
167     foreach $i (@opcodes, @opcodes_cc) {
168         print A "static const struct itemplate instrux_${i}[] = {\n";
169         $aname = "aa_$i";
170         foreach $j (@$aname) {
171             print A "    ", codesubst($j), "\n";
172         }
173         print A "    ITEMPLATE_END\n};\n\n";
174     }
175     print A "const struct itemplate * const nasm_instructions[] = {\n";
176     foreach $i (@opcodes, @opcodes_cc) {
177         print A "    instrux_${i},\n";
178     }
179     print A "};\n";
180
181     close A;
182 }
183
184 if ( !defined($output) || $output eq 'd' ) {
185     print STDERR "Writing insnsd.c...\n";
186
187     open D, ">insnsd.c";
188
189     print D "/* This file auto-generated from insns.dat by insns.pl" .
190         " - don't edit it */\n\n";
191
192     print D "#include \"nasm.h\"\n";
193     print D "#include \"insns.h\"\n\n";
194
195     print D "static const struct itemplate instrux[] = {\n";
196     $n = 0;
197     foreach $j (@big) {
198         printf D "    /* %4d */ %s\n", $n++, codesubst($j);
199     }
200     print D "};\n";
201
202     foreach $h (sort(keys(%dinstables))) {
203         next if ($h eq '');     # Skip pseudo-instructions
204         print D "\nstatic const struct itemplate * const itable_${h}[] = {\n";
205         foreach $j (@{$dinstables{$h}}) {
206             print D "    instrux + $j,\n";
207         }
208         print D "};\n";
209     }
210
211     @prefix_list = ();
212     foreach $h (@disasm_prefixes, '') {
213         for ($c = 0; $c < 256; $c++) {
214             $nn = sprintf("%s%02X", $h, $c);
215             if ($is_prefix{$nn} || defined($dinstables{$nn})) {
216                 # At least one entry in this prefix table
217                 push(@prefix_list, $h);
218                 $is_prefix{$h} = 1;
219                 last;
220             }
221         }
222     }
223
224     foreach $h (@prefix_list) {
225         print D "\n";
226         print D "static " unless ($h eq '');
227         print D "const struct disasm_index ";
228         print D ($h eq '') ? 'itable' : "itable_$h";
229         print D "[256] = {\n";
230         for ($c = 0; $c < 256; $c++) {
231             $nn = sprintf("%s%02X", $h, $c);
232             if ($is_prefix{$nn}) {
233                 die "$fname: ambiguous decoding of $nn\n"
234                     if (defined($dinstables{$nn}));
235                 printf D "    { itable_%s, -1 },\n", $nn;
236             } elsif (defined($dinstables{$nn})) {
237                 printf D "    { itable_%s, %u },\n",
238                 $nn, scalar(@{$dinstables{$nn}});
239             } else {
240                 printf D "    { NULL, 0 },\n";
241             }
242         }
243         print D "};\n";
244     }
245
246     print D "\nconst struct disasm_index * const itable_VEX[32][8] = {\n   ";
247     for ($m = 0; $m < 32; $m++) {
248         print D " {\n";
249         for ($lp = 0; $lp < 8; $lp++) {
250             $vp = sprintf("VEX%02X%01X", $m, $lp);
251             if ($is_prefix{$vp}) {
252                 printf D "        itable_%s,\n", $vp;
253             } else {
254                 print  D "        NULL,\n";
255             }
256         }
257         print D "    },";
258     }
259     print D "\n};\n";
260
261     close D;
262 }
263
264 if ( !defined($output) || $output eq 'i' ) {
265     print STDERR "Writing insnsi.h...\n";
266
267     open I, ">insnsi.h";
268
269     print I "/* This file is auto-generated from insns.dat by insns.pl" .
270         " - don't edit it */\n\n";
271     print I "/* This file in included by nasm.h */\n\n";
272
273     print I "/* Instruction names */\n\n";
274     print I "#ifndef NASM_INSNSI_H\n";
275     print I "#define NASM_INSNSI_H 1\n\n";
276     print I "enum opcode {\n";
277     $maxlen = 0;
278     foreach $i (@opcodes, @opcodes_cc) {
279         print I "\tI_${i},\n";
280         $len = length($i);
281         $len++ if ( $i =~ /cc$/ ); # Condition codes can be 3 characters long
282         $maxlen = $len if ( $len > $maxlen );
283     }
284     print I "\tI_none = -1\n";
285     print I "\n};\n\n";
286     print I "#define MAX_INSLEN ", $maxlen, "\n";
287     print I "#define FIRST_COND_OPCODE I_", $opcodes_cc[0], "\n\n";
288     print I "#endif /* NASM_INSNSI_H */\n";
289
290     close I;
291 }
292
293 if ( !defined($output) || $output eq 'n' ) {
294     print STDERR "Writing insnsn.c...\n";
295
296     open N, ">insnsn.c";
297
298     print N "/* This file is auto-generated from insns.dat by insns.pl" .
299         " - don't edit it */\n\n";
300     print N "#include \"tables.h\"\n\n";
301
302     print N "const char * const nasm_insn_names[] = {";
303     $first = 1;
304     foreach $i (@opcodes, @opcodes_cc) {
305         print N "," if ( !$first );
306         $first = 0;
307         $ilower = $i;
308         $ilower =~ s/cc$//;     # Remove conditional cc suffix
309         $ilower =~ tr/A-Z/a-z/; # Change to lower case (Perl 4 compatible)
310         print N "\n\t\"${ilower}\"";
311     }
312     print N "\n};\n";
313     close N;
314 }
315
316 printf STDERR "Done: %d instructions\n", $insns;
317
318 # Count primary bytecodes, for statistics
319 sub count_bytecodes(@) {
320     my $skip = 0;
321     foreach my $bc (@_) {
322         if ($skip) {
323             $skip--;
324             next;
325         }
326         $bytecode_count[$bc]++;
327         if ($bc >= 01 && $bc <= 04) {
328             $skip = $bc;
329         } elsif (($bc & ~03) == 010) {
330             $skip = 1;
331         } elsif (($bc & ~013) == 0144) {
332             $skip = 1;
333         } elsif ($bc == 0172) {
334             $skip = 1;
335         } elsif ($bc >= 0260 && $bc <= 0270) {
336             $skip = 2;
337         } elsif ($bc == 0330) {
338             $skip = 1;
339         }
340     }
341 }
342
343 sub format_insn(@) {
344     my ($opcode, $operands, $codes, $flags) = @_;
345     my $num, $nd = 0;
346     my @bytecode;
347
348     return (undef, undef) if $operands eq "ignore";
349
350     # format the operands
351     $operands =~ s/:/|colon,/g;
352     $operands =~ s/mem(\d+)/mem|bits$1/g;
353     $operands =~ s/mem/memory/g;
354     $operands =~ s/memory_offs/mem_offs/g;
355     $operands =~ s/imm(\d+)/imm|bits$1/g;
356     $operands =~ s/imm/immediate/g;
357     $operands =~ s/rm(\d+)/rm_gpr|bits$1/g;
358     $operands =~ s/(mmx|xmm|ymm)rm/rm_$1/g;
359     $operands =~ s/\=([0-9]+)/same_as|$1/g;
360     if ($operands eq 'void') {
361         @ops = ();
362     } else {
363         @ops = split(/\,/, $operands);
364     }
365     $num = scalar(@ops);
366     while (scalar(@ops) < $MAX_OPERANDS) {
367         push(@ops, '0');
368     }
369     $operands = join(',', @ops);
370     $operands =~ tr/a-z/A-Z/;
371
372     # format the flags
373     $flags =~ s/,/|IF_/g;
374     $flags =~ s/(\|IF_ND|IF_ND\|)//, $nd = 1 if $flags =~ /IF_ND/;
375     $flags = "IF_" . $flags;
376
377     @bytecode = (decodify($codes), 0);
378     push(@bytecode_list, [@bytecode]);
379     $codes = hexstr(@bytecode);
380     count_bytecodes(@bytecode);
381
382     ("{I_$opcode, $num, {$operands}, \@\@CODES-$codes\@\@, $flags},", $nd);
383 }
384
385 #
386 # Look for @@CODES-xxx@@ sequences and replace them with the appropriate
387 # offset into nasm_bytecodes
388 #
389 sub codesubst($) {
390     my($s) = @_;
391     my $n;
392
393     while ($s =~ /\@\@CODES-([0-9A-F]+)\@\@/) {
394         my $pos = $bytecode_pos{$1};
395         if (!defined($pos)) {
396             die "$fname: no position assigned to byte code $1\n";
397         }
398         $s = $` . "nasm_bytecodes+${pos}" . "$'";
399     }
400     return $s;
401 }
402
403 sub addprefix ($@) {
404     my ($prefix, @list) = @_;
405     my $x;
406     my @l = ();
407
408     foreach $x (@list) {
409         push(@l, sprintf("%s%02X", $prefix, $x));
410     }
411
412     return @l;
413 }
414
415 #
416 # Turn a code string into a sequence of bytes
417 #
418 sub decodify($) {
419   # Although these are C-syntax strings, by convention they should have
420   # only octal escapes (for directives) and hexadecimal escapes
421   # (for verbatim bytes)
422     my($codestr) = @_;
423
424     if ($codestr =~ /^\s*\[([^\]]*)\]\s*$/) {
425         return byte_code_compile($1);
426     }
427
428     my $c = $codestr;
429     my @codes = ();
430
431     while ($c ne '') {
432         if ($c =~ /^\\x([0-9a-f]+)(.*)$/i) {
433             push(@codes, hex $1);
434             $c = $2;
435             next;
436         } elsif ($c =~ /^\\([0-7]{1,3})(.*)$/) {
437             push(@codes, oct $1);
438             $c = $2;
439             next;
440         } else {
441             die "$fname: unknown code format in \"$codestr\"\n";
442         }
443     }
444
445     return @codes;
446 }
447
448 # Turn a numeric list into a hex string
449 sub hexstr(@) {
450     my $s = '';
451     my $c;
452
453     foreach $c (@_) {
454         $s .= sprintf("%02X", $c);
455     }
456     return $s;
457 }
458
459 # Here we determine the range of possible starting bytes for a given
460 # instruction. We need only consider the codes:
461 # \[1234]      mean literal bytes, of course
462 # \1[0123]     mean byte plus register value
463 # \330         means byte plus condition code
464 # \0 or \340   mean give up and return empty set
465 # \34[4567]    mean PUSH/POP of segment registers: special case
466 # \17[234]     skip is4 control byte
467 # \26x \270    skip VEX control bytes
468 sub startseq($) {
469   my ($codestr) = @_;
470   my $word, @range;
471   my @codes = ();
472   my $c = $codestr;
473   my $c0, $c1, $i;
474   my $prefix = '';
475
476   @codes = decodify($codestr);
477
478   while ($c0 = shift(@codes)) {
479       $c1 = $codes[0];
480       if ($c0 >= 01 && $c0 <= 04) {
481           # Fixed byte string
482           my $fbs = $prefix;
483           while (1) {
484               if ($c0 >= 01 && $c0 <= 04) {
485                   while ($c0--) {
486                       $fbs .= sprintf("%02X", shift(@codes));
487                   }
488               } else {
489                   last;
490               }
491               $c0 = shift(@codes);
492           }
493
494           foreach $pfx (@disasm_prefixes) {
495               if (substr($fbs, 0, length($pfx)) eq $pfx) {
496                   $prefix = $pfx;
497                   $fbs = substr($fbs, length($pfx));
498                   last;
499               }
500           }
501
502           if ($fbs ne '') {
503               return ($prefix.substr($fbs,0,2));
504           }
505
506           unshift(@codes, $c0);
507       } elsif ($c0 >= 010 && $c0 <= 013) {
508           return addprefix($prefix, $c1..($c1+7));
509       } elsif (($c0 & ~013) == 0144) {
510           return addprefix($prefix, $c1, $c1|2);
511       } elsif ($c0 == 0330) {
512           return addprefix($prefix, $c1..($c1+15));
513       } elsif ($c0 == 0 || $c0 == 0340) {
514           return $prefix;
515       } elsif ($c0 == 0344) {
516           return addprefix($prefix, 0x06, 0x0E, 0x16, 0x1E);
517       } elsif ($c0 == 0345) {
518           return addprefix($prefix, 0x07, 0x17, 0x1F);
519       } elsif ($c0 == 0346) {
520           return addprefix($prefix, 0xA0, 0xA8);
521       } elsif ($c0 == 0347) {
522           return addprefix($prefix, 0xA1, 0xA9);
523       } elsif (($c0 & ~3) == 0260 || $c0 == 0270) {
524           my $m,$wlp,$vxp;
525           $m   = shift(@codes);
526           $wlp = shift(@codes);
527           $prefix .= sprintf('VEX%02X%01X', $m, $wlp & 7);
528       } elsif ($c0 >= 0172 && $c0 <= 174) {
529           shift(@codes);        # Skip is4 control byte
530       } else {
531           # We really need to be able to distinguish "forbidden"
532           # and "ignorable" codes here
533       }
534   }
535   return $prefix;
536 }
537
538 #
539 # This function takes a series of byte codes in a format which is more
540 # typical of the Intel documentation, and encode it.
541 #
542 # The format looks like:
543 #
544 # [operands: opcodes]
545 #
546 # The operands word lists the order of the operands:
547 #
548 # r = register field in the modr/m
549 # m = modr/m
550 # v = VEX "v" field
551 # d = DREX "dst" field
552 # i = immediate
553 # s = register field of is4/imz2 field
554 # - = implicit (unencoded) operand
555 #
556 # For an operand that should be filled into more than one field,
557 # enter it as e.g. "r+v".
558 #
559 sub byte_code_compile($) {
560     my($str) = @_;
561     my $opr;
562     my $opc;
563     my @codes = ();
564     my $litix = undef;
565     my %oppos = ();
566     my $i;
567     my $op, $oq;
568     my $opex;
569
570     unless ($str =~ /^(([^\s:]*)\:|)\s*(.*\S)\s*$/) {
571         die "$fname: $line: cannot parse: [$str]\n";
572     }
573     $opr = "\L$2";
574     $opc = "\L$3";
575
576     my $op = 0;
577     for ($i = 0; $i < length($opr); $i++) {
578         my $c = substr($opr,$i,1);
579         if ($c eq '+') {
580             $op--;
581         } else {
582             $oppos{$c} = $op++;
583         }
584     }
585
586     $prefix_ok = 1;
587     foreach $op (split(/\s*(?:\s|(?=[\/\\]))/, $opc)) {
588         if ($op eq 'o16') {
589             push(@codes, 0320);
590         } elsif ($op eq 'o32') {
591             push(@codes, 0321);
592         } elsif ($op eq 'o64') {  # 64-bit operand size requiring REX.W
593             push(@codes, 0324);
594         } elsif ($op eq 'o64nw') { # Implied 64-bit operand size (no REX.W)
595             push(@codes, 0323);
596         } elsif ($op eq 'a16') {
597             push(@codes, 0310);
598         } elsif ($op eq 'a32') {
599             push(@codes, 0311);
600         } elsif ($op eq 'a64') {
601             push(@codes, 0313);
602         } elsif ($op eq '!osp') {
603             push(@codes, 0364);
604         } elsif ($op eq '!asp') {
605             push(@codes, 0365);
606         } elsif ($op eq 'rex.l') {
607             push(@codes, 0334);
608         } elsif ($op eq 'repe') {
609             push(@codes, 0335);
610         } elsif ($prefix_ok && $op =~ /^(66|f2|f3|np)$/) {
611             # 66/F2/F3 prefix used as an opcode extension, or np = no prefix
612             if ($op eq '66') {
613                 push(@codes, 0361);
614             } elsif ($op eq 'f2') {
615                 push(@codes, 0362);
616             } elsif ($op eq 'f3') {
617                 push(@codes, 0363);
618             } else {
619                 push(@codes, 0360);
620             }
621         } elsif ($op =~ /^[0-9a-f]{2}$/) {
622             if (defined($litix) && $litix+$codes[$litix]+1 == scalar @codes &&
623                 $codes[$litix] < 4) {
624                 $codes[$litix]++;
625                 push(@codes, hex $op);
626             } else {
627                 $litix = scalar(@codes);
628                 push(@codes, 01, hex $op);
629             }
630             $prefix_ok = 0;
631         } elsif ($op eq '/r') {
632             if (!defined($oppos{'r'}) || !defined($oppos{'m'})) {
633                 die "$fname: $line: $op requires r and m operands\n";
634             }
635             $opex = (($oppos{'m'} & 4) ? 06 : 0) |
636                     (($oppos{'r'} & 4) ? 05 : 0);
637             push(@codes, $opex) if ($opex);
638             push(@codes, 0100 + (($oppos{'m'} & 3) << 3) + ($oppos{'r'} & 3));
639             $prefix_ok = 0;
640         } elsif ($op =~ m:^/([0-7])$:) {
641             if (!defined($oppos{'m'})) {
642                 die "$fname: $line: $op requires m operand\n";
643             }
644             push(@codes, 06) if ($oppos{'m'} & 4);
645             push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1);
646             $prefix_ok = 0;
647         } elsif ($op =~ /^vex(|\..*)$/) {
648             my ($m,$w,$l,$p) = (undef,2,undef,0);
649             my $has_nds = 0;
650             foreach $oq (split(/\./, $op)) {
651                 if ($oq eq 'vex') {
652                     # prefix
653                 } elsif ($oq eq '128' || $oq eq 'l0') {
654                     $l = 0;
655                 } elsif ($oq eq '256' || $oq eq 'l1') {
656                     $l = 1;
657                 } elsif ($oq eq 'w0') {
658                     $w = 0;
659                 } elsif ($oq eq 'w1') {
660                     $w = 1;
661                 } elsif ($oq eq 'wx') {
662                     $w = 2;
663                 } elsif ($oq eq 'ww') {
664                     $w = 3;
665                 } elsif ($oq eq '66') {
666                     $p = 1;
667                 } elsif ($oq eq 'f3') {
668                     $p = 2;
669                 } elsif ($oq eq 'f2') {
670                     $p = 3;
671                 } elsif ($oq eq '0f') {
672                     $m = 1;
673                 } elsif ($oq eq '0f38') {
674                     $m = 2;
675                 } elsif ($oq eq '0f3a') {
676                     $m = 3;
677                 } elsif ($oq =~ /^m([0-9]+)$/) {
678                     $m = $1+0;
679                 } elsif ($oq eq 'nds' || $oq eq 'ndd') {
680                     if (!defined($oppos{'v'})) {
681                         die "$fname: $line: vex.$oq without 'v' operand\n";
682                     }
683                     $has_nds = 1;
684                 } else {
685                     die "$fname: $line: undefined VEX subcode: $oq\n";
686                 }
687             }
688             if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) {
689                 die "$fname: $line: missing fields in VEX specification\n";
690             }
691             if (defined($oppos{'v'}) && !$has_nds) {
692                 die "$fname: $line: 'v' operand without vex.nds or vex.ndd\n";
693             }
694             push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270,
695                  $m, ($w << 3)+($l << 2)+$p);
696             $prefix_ok = 0;
697         } elsif ($op =~ /^\/drex([01])$/) {
698             my $oc0 = $1;
699             if (!defined($oppos{'d'})) {
700                 die "$fname: $line: DREX without a 'd' operand\n";
701             }
702             # Note the use of *unshift* here, as opposed to *push*.
703             # This is because NASM want this byte code at the start of
704             # the instruction sequence, but the AMD documentation puts
705             # this at (roughly) the position of the drex byte itself.
706             # This allows us to match the AMD documentation and still
707             # do the right thing.
708             unshift(@codes, 0160+($oppos{'d'} & 3)+($oc0 ? 4 : 0));
709             unshift(@codes, 05) if ($oppos{'d'} & 4);
710         } elsif ($op =~ /^(ib\,s|ib|ibx|ib\,w|iw|iwd|id|idx|iwdq|rel|rel8|rel16|rel32|iq|seg|ibw|ibd|ibd,s)$/) {
711             if (!defined($oppos{'i'})) {
712                 die "$fname: $line: $op without 'i' operand\n";
713             }
714             if ($op eq 'ib,s') { # Signed imm8
715                 push(@codes, 05) if ($oppos{'i'} & 4);
716                 push(@codes, 014+($oppos{'i'} & 3));
717             } elsif ($op eq 'ib') { # imm8
718                 push(@codes, 05) if ($oppos{'i'} & 4);
719                 push(@codes, 020+($oppos{'i'} & 3));
720             } elsif ($op eq 'ib,u') { # Unsigned imm8
721                 push(@codes, 05) if ($oppos{'i'} & 4);
722                 push(@codes, 024+($oppos{'i'} & 3));
723             } elsif ($op eq 'iw') { # imm16
724                 push(@codes, 05) if ($oppos{'i'} & 4);
725                 push(@codes, 030+($oppos{'i'} & 3));
726             } elsif ($op eq 'ibx') { # imm8 sign-extended to opsize
727                 push(@codes, 05) if ($oppos{'i'} & 4);
728                 push(@codes, 0274+($oppos{'i'} & 3));
729             } elsif ($op eq 'iwd') { # imm16 or imm32, depending on opsize
730                 push(@codes, 05) if ($oppos{'i'} & 4);
731                 push(@codes, 034+($oppos{'i'} & 3));
732             } elsif ($op eq 'id') { # imm32
733                 push(@codes, 05) if ($oppos{'i'} & 4);
734                 push(@codes, 040+($oppos{'i'} & 3));
735             } elsif ($op eq 'idx') { # imm32 extended to 64 bits
736                 push(@codes, 05) if ($oppos{'i'} & 4);
737                 push(@codes, 0254+($oppos{'i'} & 3));
738             } elsif ($op eq 'iwdq') { # imm16/32/64, depending on opsize
739                 push(@codes, 05) if ($oppos{'i'} & 4);
740                 push(@codes, 044+($oppos{'i'} & 3));
741             } elsif ($op eq 'rel8') {
742                 push(@codes, 05) if ($oppos{'i'} & 4);
743                 push(@codes, 050+($oppos{'i'} & 3));
744             } elsif ($op eq 'iq') {
745                 push(@codes, 05) if ($oppos{'i'} & 4);
746                 push(@codes, 054+($oppos{'i'} & 3));
747             } elsif ($op eq 'rel16') {
748                 push(@codes, 05) if ($oppos{'i'} & 4);
749                 push(@codes, 060+($oppos{'i'} & 3));
750             } elsif ($op eq 'rel') { # 16 or 32 bit relative operand
751                 push(@codes, 05) if ($oppos{'i'} & 4);
752                 push(@codes, 064+($oppos{'i'} & 3));
753             } elsif ($op eq 'rel32') {
754                 push(@codes, 05) if ($oppos{'i'} & 4);
755                 push(@codes, 070+($oppos{'i'} & 3));
756             } elsif ($op eq 'seg') {
757                 push(@codes, 05) if ($oppos{'i'} & 4);
758                 push(@codes, 074+($oppos{'i'} & 3));
759             } elsif ($op eq 'ibw') { # imm16 that can be bytified
760                 if (!defined($s_pos)) {
761                     die "$fname: $line: $op without a +s byte\n";
762                 }
763                 $codes[$s_pos] += 0144;
764                 push(@codes, 05) if ($oppos{'i'} & 4);
765                 push(@codes, 0140+($oppos{'i'} & 3));
766             } elsif ($op eq 'ibd') { # imm32 that can be bytified
767                 if (!defined($s_pos)) {
768                     die "$fname: $line: $op without a +s byte\n";
769                 }
770                 $codes[$s_pos] += 0154;
771                 push(@codes, 05) if ($oppos{'i'} & 4);
772                 push(@codes, 0150+($oppos{'i'} & 3));
773             } elsif ($op eq 'ibd,s') {
774                 # imm32 that can be bytified, sign extended to 64 bits
775                 if (!defined($s_pos)) {
776                     die "$fname: $line: $op without a +s byte\n";
777                 }
778                 $codes[$s_pos] += 0154;
779                 push(@codes, 05) if ($oppos{'i'} & 4);
780                 push(@codes, 0250+($oppos{'i'} & 3));
781             }
782             $prefix_ok = 0;
783         } elsif ($op eq '/is4') {
784             if (!defined($oppos{'s'})) {
785                 die "$fname: $line: $op without 's' operand\n";
786             }
787             if (defined($oppos{'i'})) {
788                 push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'});
789             } else {
790                 push(@codes, 0174, $oppos{'s'});
791             }
792             $prefix_ok = 0;
793         } elsif ($op =~ /^\/is4\=([0-9]+)$/) {
794             my $imm = $1;
795             if (!defined($oppos{'s'})) {
796                 die "$fname: $line: $op without 's' operand\n";
797             }
798             if ($imm < 0 || $imm > 15) {
799                 die "$fname: $line: invalid imm4 value for $op: $imm\n";
800             }
801             push(@codes, 0173, ($oppos{'s'} << 4) + $imm);
802             $prefix_ok = 0;
803         } elsif ($op =~ /^([0-9a-f]{2})\+s$/) {
804             if (!defined($oppos{'i'})) {
805                 die "$fname: $line: $op without 'i' operand\n";
806             }
807             $s_pos = scalar @codes;
808             push(@codes, 05) if ($oppos{'i'} & 4);
809             push(@codes, $oppos{'i'} & 3, hex $1);
810             $prefix_ok = 0;
811         } elsif ($op =~ /^([0-9a-f]{2})\+c$/) {
812             push(@codes, 0330, hex $1);
813             $prefix_ok = 0;
814         } elsif ($op =~ /^\\([0-7]+|x[0-9a-f]{2})$/) {
815             # Escape to enter literal bytecodes
816             push(@codes, oct $1);
817         } else {
818             die "$fname: $line: unknown operation: $op\n";
819         }
820     }
821
822     return @codes;
823 }