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