14586390ed637b7c8a79b0ccf267ff95240e7aed
[platform/upstream/nasm.git] / insns.pl
1 #!/usr/bin/perl
2 #
3 # insns.pl   produce insnsa.c and insnsd.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 licence given in the file "Licence"
8 # distributed in the NASM archive.
9
10 print STDERR "Reading insns.dat...\n";
11
12 open (F, "insns.dat") || die "unable to open insns.dat";
13
14 $line = 0;
15 $opcodes = 0;
16 $insns = 0;
17 while (<F>) {
18   $line++;
19   next if /^\s*;/;   # comments
20   chomp;
21   split;
22   next if $#_ == -1; # blank lines
23   (warn "line $line does not contain four fields\n"), next if $#_ != 3;
24   ($formatted, $nd) = &format(@_);
25   if ($formatted) {
26     $insns++;
27     $aname = "aa_$_[0]";
28     push @$aname, $formatted;
29   }
30   $opcodes[$opcodes++] = $_[0], $done{$_[0]} = 1 if !$done{$_[0]};
31   if ($formatted && !$nd) {
32     push @big, $formatted;
33     foreach $i (&startbyte($_[2])) {
34       $aname = sprintf "dd_%02X",$i;
35       push @$aname, $#big;
36     }
37   }
38 }
39
40 close F;
41
42 print STDERR "Writing insnsa.c...\n";
43
44 open A, ">insnsa.c";
45
46 print A "/* This file auto-generated from insns.dat by insns.pl" .
47         " - don't edit it */\n\n";
48 print A "#include <stdio.h>\n";
49 print A "#include \"nasm.h\"\n";
50 print A "#include \"insns.h\"\n";
51 print A "\n";
52
53 foreach $i (@opcodes) {
54   print A "static struct itemplate instrux_${i}[] = {\n";
55   $aname = "aa_$i";
56   foreach $j (@$aname) {
57     print A "    $j\n";
58   }
59   print A "    {-1}\n};\n\n";
60 }
61 print A "struct itemplate *nasm_instructions[] = {\n";
62 foreach $i (@opcodes) {
63   print A "    instrux_${i},\n";
64 }
65 print A "};\n";
66
67 close A;
68
69 print STDERR "Writing insnsd.c...\n";
70
71 open D, ">insnsd.c";
72
73 print D "/* This file auto-generated from insns.dat by insns.pl" .
74         " - don't edit it */\n\n";
75 print D "#include <stdio.h>\n";
76 print D "#include \"nasm.h\"\n";
77 print D "#include \"insns.h\"\n";
78 print D "\n";
79
80 print D "static struct itemplate instrux[] = {\n";
81 foreach $j (@big) {
82   print D "    $j\n";
83 }
84 print D "    {-1}\n};\n\n";
85
86 for ($c=0; $c<256; $c++) {
87   $h = sprintf "%02X", $c;
88   print D "static struct itemplate *itable_${h}[] = {\n";
89   $aname = "dd_$h";
90   foreach $j (@$aname) {
91     print D "    instrux + $j,\n";
92   }
93   print D "    NULL\n};\n\n";
94 }
95
96 print D "struct itemplate **itable[] = {\n";
97 for ($c=0; $c<256; $c++) {
98   printf D "    itable_%02X,\n", $c;
99 }
100 print D "};\n";
101
102 close D;
103
104 printf STDERR "Done: %d instructions\n", $insns;
105
106 sub format {
107   local ($opcode, $operands, $codes, $flags) = @_;
108   local $num, $nd = 0;
109
110   return (undef, undef) if $operands eq "ignore";
111
112   # format the operands
113   $operands =~ s/:/|colon,/g;
114   $operands =~ s/mem(\d+)/mem|bits$1/g;
115   $operands =~ s/mem/memory/g;
116   $operands =~ s/memory_offs/mem_offs/g;
117   $operands =~ s/imm(\d+)/imm|bits$1/g;
118   $operands =~ s/imm/immediate/g;
119   $operands =~ s/rm(\d+)/regmem|bits$1/g;
120   $num = 3;
121   $operands = '0,0,0', $num = 0 if $operands eq 'void';
122   $operands .= ',0', $num-- while $operands !~ /,.*,/;
123   $operands =~ tr/a-z/A-Z/;
124
125   # format the flags
126   $flags =~ s/,/|IF_/g;
127   $flags =~ s/(\|IF_ND|IF_ND\|)//, $nd = 1 if $flags =~ /IF_ND/;
128   $flags = "IF_" . $flags;
129
130   ("{I_$opcode, $num, {$operands}, \"$codes\", $flags},", $nd);
131 }
132
133 # Here we determine the range of possible starting bytes for a given
134 # instruction. We need only consider the codes:
135 # \1 \2 \3     mean literal bytes, of course
136 # \4 \5 \6 \7  mean PUSH/POP of segment registers: special case
137 # \10 \11 \12  mean byte plus register value
138 # \17          means byte zero
139 # \330         means byte plus condition code
140 # \0 or \340   mean give up and return empty set
141 sub startbyte {  # FIXME we cheat, for now :-)
142   local ($codes) = @_;
143   local $word, @range;
144
145   while (1) {
146     die "couldn't get code in '$codes'" if $codes !~ /^(\\[^\\]+)(\\.*)?$/;
147     $word = $1, $codes = $2;
148     return (hex $1) if $word =~ /^\\[123]$/ && $codes =~ /^\\x(..)/;
149     return (0x07, 0x17, 0x1F) if $word eq "\\4";
150     return (0xA1, 0xA9) if $word eq "\\5";
151     return (0x06, 0x0E, 0x16, 0x1E) if $word eq "\\6";
152     return (0xA0, 0xA8) if $word eq "\\7";
153     $start=hex $1, $r=8, last if $word =~ /^\\1[012]$/ && $codes =~/^\\x(..)/;
154     return (0) if $word eq "\\17";
155     $start=hex $1, $r=16, last if $word =~ /^\\330$/ && $codes =~ /^\\x(..)/;
156     return () if $word eq "\\0" || $word eq "\\340";
157   }
158   @range = ();
159   push @range, $start++ while ($r-- > 0);
160   @range;
161 }