|
|
1.1 root 1: #! /usr/local/bin/perl -w
2:
3: # m68k-inst-expand.pl - expands the m68k instruction templates into
4: # full instruction word patterns and their decodings:
5:
6: # $Header: /aquery/home0/fredette/project/tme/TME-CVS-LOCAL/tme/ic/m68k/m68k-iset-expand.pl,v 1.3 2003/04/23 19:16:16 fredette Exp $
7:
8: # globals:
9: $debug = 0;
10: @threefield = ("000", "001", "010", "011", "100", "101", "110", "111");
11:
12: # our single command line argument is the CPU name:
13: if (@ARGV != 1) {
14: print STDERR "usage: $0 CPU-NAME\n";
15: exit(1);
16: }
17: $cpu_name = shift(@ARGV);
18: print "cpu-begin $cpu_name\n";
19:
20: # to silence perl -w:
21: undef($field_q);
22:
23: # loop over the instruction set on standard input:
24: $pass = 1;
25: for($line = 1; defined($_ = <STDIN>); $line++) {
26: chomp;
27:
28: # split by spaces:
29: @tokens = split(/[,\s]+/, $_);
30:
31: # strip comments:
32: for ($token_i = 0; $token_i < @tokens; $token_i++) {
33: splice(@tokens, $token_i)
34: if ($tokens[$token_i] =~ /^\!/);
35: }
36:
37: # skip blank lines:
38: next if (@tokens == 0);
39:
40: # handle the preprocessor. this is the dumbest preprocessor ever:
41: if ($tokens[0] eq ".if") {
42: $pass = 0;
43: foreach $token (@tokens) {
44: $pass = 1 if ($token eq $cpu_name);
45: }
46: next;
47: }
48: elsif ($tokens[0] eq ".endif") {
49: $pass = 1;
50: next;
51: }
52: next if (!$pass);
53:
54: # handle an EAX category. an EAX category defines valid
55: # combinations of an EA "mode" and "reg" values found in an
56: # instruction patterns "x" field. see linear pp 60 of M68000PM.ps
57: # for a list of all possible mode and reg combinations.
58: #
59: # different combinations are valid depending on the instruction
60: # and operand being described, however most instructions use one
61: # of a small handful of common combinations.
62: #
63: # an EA category is defined as:
64: #
65: # eax-cat NAME DEFAULT-CYCLES COMBINATIONS
66: #
67: # NAME is a user-assigned name for the category
68: #
69: # DEFAULT-CYCLES specifies the default memory cycle behavior
70: # for this category of effective address. specific later uses
71: # of this category may still override this default. this is
72: # one of "un", "ro", "wo", or "rw", for no cycles, read-only,
73: # write-only, and read-write, respectively
74: #
75: # COMBINATIONS is a string of "y" and "n" characters indicating
76: # which mode and reg combinations are valid. positions zero
77: # through six in the string correspond to mode values zero
78: # through six, and positions seven through 14 correspond to
79: # mode value 7, reg values zero through seven:
80: #
81: if ($tokens[0] eq "eax-cat") {
82:
83: # get the category definition:
84: $eax_cat_name = $tokens[1];
85: $eax_cat_cycles_default = $tokens[2];
86: @eax_cat_modes = split(//, $tokens[3]);
87:
88: # expand this category once for each possible operand size,
89: # remembering what operand each valid combination of mode and
90: # reg means:
91: foreach $eax_size (0, 8, 16, 32) {
92: @eax_cat_fields = ();
93: @eay_cat_fields = ();
94: for ($mode = 0; $mode < @threefield; $mode++) {
95: for ($reg = 0; $reg < @threefield; $reg++) {
96:
97: # EXCEPTION: 8-bit address register direct is always
98: # illegal:
99: next if ($eax_size == 8 && $mode == 1);
100:
101: if ($eax_cat_modes[$mode + ($mode < 7 ? 0 : $reg)] eq "y") {
102: undef($field_x_value);
103: undef($field_y_value);
104: if ($mode == 0) {
105: # data register direct:
106: $field_x_value = "\%d${reg}.${eax_size}";
107: }
108: elsif ($mode == 1) {
109: # address register direct:
110: $field_x_value = "\%a${reg}.${eax_size}";
111: }
112: elsif ($mode == 7
113: && $reg == 4) {
114: # immediate:
115: $field_x_value = "imm.${eax_size}";
116: }
117: elsif ($eax_size == 0) {
118: # unsized, effective address complex:
119: $field_x_value = "eax.32";
120: }
121: else {
122: $field_x_value = "memx.${eax_size}.$eax_cat_cycles_default";
123: $field_y_value = "memy.${eax_size}.$eax_cat_cycles_default";
124: }
125: $field_y_value = $field_x_value if (!defined($field_y_value));
126: push(@eax_cat_fields, "$threefield[$mode]$threefield[$reg]/$field_x_value");
127: push(@eay_cat_fields, "$threefield[$reg]$threefield[$mode]/$field_y_value");
128: }
129: }
130: }
131: eval("\@eax_${eax_cat_name}${eax_size} = \@eax_cat_fields;");
132: eval("\@eay_${eax_cat_name}${eax_size} = \@eay_cat_fields;");
133: }
134: next;
135: }
136:
137: # handle a "specop" line. some instructions have a separate opcode
138: # word that needs to be read and decoded specially. we expand
139: # any .s suffixes on the instruction names but otherwise pass
140: # this line on untouched:
141: #
142: if ($tokens[0] eq "specop") {
143: foreach $token (@tokens) {
144: $token = "${1}8 ${1}16 ${1}32" if ($token =~ /^(\S+)\.s$/);
145: }
146: print join(" ", @tokens)."\n";
147: next;
148: }
149:
150: # form the instruction template from the first four tokens:
151: $template = join("", splice(@tokens, 0, 4));
152:
153: # the next token is the function:
154: $func = shift(@tokens);
155:
156: # the remaining tokens are the arguments:
157: @args = @tokens;
158: undef(@tokens);
159:
160: print "template $template, func $func, args: ".join(" ", @args)."\n" if ($debug);
161:
162: # break this template down into fields and sanity-check them.
163: # we work from the leftmost position in the template (the most
164: # significant bit, bit 15) to the rightmost position.
165: #
166: @fields = ("root");
167: for ($field_start = 15; $field_start >= 0; $field_start = $field_end - 1) {
168:
169: # find the extent of this field. a wildcard field (indicated
170: # by the "?" character, which is internally rewritten to the "w"
171: # character) is always a single bit wide, otherwise a constant
172: # field ends right before a non-constant bit, and any other field
173: # ends when it ends:
174: #
175: $field_char = substr($template, 15 - $field_start, 1);
176: $field_char =~ tr/\?/w/;
177: for ($field_end = $field_start; $field_end >= 0; $field_end--) {
178:
179: # get the next field character:
180: $field_char_next = substr($template, 15 - ($field_end - 1), 1);
181: $field_char_next =~ tr/\?/w/;
182:
183: # stop if this is the first character of the next field:
184: last if ($field_char eq "w"
185: || ($field_char =~ /[01]/
186: ? $field_char_next !~ /[01]/
187: : $field_char_next ne $field_char));
188: }
189:
190: # save this field:
191: push (@fields, ($field_char =~ /[01]/
192: ? substr($template, 15 - $field_start, $field_start - $field_end + 1)
193: : $field_char));
194:
195: # sanity check this field. some fields must be a fixed size,
196: # some fields must be used by some argument:
197: #
198: $field_size = $field_start - $field_end + 1;
199: print "$#fields: $field_char-field from $field_start to $field_end" if ($debug);
200: if ($field_char =~ /[01w]/) {
201: # constant and wildcard fields can have any size
202: }
203: elsif ($field_char =~ /[sS]/) {
204: # operand-size fields must be size two:
205: die "stdin:$line: $field_char field must be size two\n"
206: if ($field_size != 2);
207: }
208: elsif ($field_char =~ /[xy]/) {
209: # effective address fields must be size six:
210: die "stdin:$line: $field_char field must be size six\n"
211: if ($field_size != 6);
212: # effective address fields must be used by some argument:
213: for ($arg_i = 0; $arg_i < @args; $arg_i++) {
214: last if ($args[$arg_i] =~ /^$field_char([sS]|(\d+))\//);
215: }
216: die "stdin:$line: $field_char field not used by any argument\n"
217: if ($arg_i == @args);
218: print ", arg #$arg_i" if ($debug);
219: eval("\$field_${field_char}_arg = $arg_i;");
220: }
221: elsif ($field_char =~ /[daDAq]/) {
222: # register and small-immediate fields must be size three:
223: die "stdin:$line: $field_char field must be size three\n"
224: if ($field_size != 3);
225: }
226: elsif ($field_char eq "c") {
227: # condition code fields must be size four:
228: die "stdin:$line: c field must be size four\n"
229: if ($field_size != 4);
230: }
231: else {
232: die "stdin:$line: unknown field type $field_char\n";
233: }
234: print "\n" if ($debug);
235: }
236: print "fields: ".join(" ", @fields)."\n" if ($debug);
237:
238: # recursively go over the fields of this template, forming real,
239: # legal instruction patterns, and their full decoding:
240: $field_depth = 0;
241: undef(@field_n0_values);
242: @field_n0_values = ("");
243: @pattern_stack = ("");
244: @instruction_stack = ("");
245: print "root\n" if ($debug);
246: $pattern = "";
247: $instruction = "";
248: for (;;) {
249:
250: # find the next field value, popping the stack as needed, and
251: # form the next pattern:
252: for (; !defined($field_value = eval("shift(\@field_n${field_depth}_values)")); ) {
253: eval("undef(\$field_$fields[$field_depth]);");
254: last if (--$field_depth < 0);
255: $field_type = $fields[$field_depth];
256: pop(@pattern_stack);
257: pop(@instruction_stack);
258: }
259: last if ($field_depth < 0);
260: ($pattern_part, $field_value, $instruction_part) = split(/\//, $field_value, 3);
261: $pattern_part = "" if (!defined($pattern_part));
262: $field_value = $pattern_part if (!defined($field_value) || $field_value eq "");
263: $instruction_part = "" if (!defined($instruction_part));
264: $pattern = $pattern_stack[$field_depth].$pattern_part;
265: $instruction = $instruction_stack[$field_depth].$instruction_part;
266: eval("\$field_$fields[$field_depth] = \"$field_value\";");
267:
268: # if we don't have a complete pattern, descend into the
269: # next field and expand it:
270: if ($field_depth < $#fields) {
271: $field_type = $fields[++$field_depth];
272: push(@pattern_stack, $pattern);
273: push(@instruction_stack, $instruction);
274: @field_values = ();
275:
276: # a constant field:
277: if ($field_type =~ /^[01]/) {
278: @field_values = ($field_type);
279: }
280:
281: # a wildcard field:
282: elsif ($field_type eq "w") {
283: @field_values = ("0", "1");
284: }
285:
286: # a size field:
287: elsif ($field_type eq "s") {
288: @field_values = ("00/8", "01/16", "10/32");
289: }
290:
291: # the wacko size field:
292: elsif ($field_type eq "S") {
293: @field_values = ("01/8", "11/16", "10/32");
294: }
295:
296: # an eax or eay field:
297: elsif ($field_type =~ /[xy]/) {
298:
299: # take apart the argument:
300: $arg_i = eval("\$field_${field_type}_arg;");
301: die "stdin:$line: $args[$arg_i] is a bad EA argument\n"
302: unless ($args[$arg_i] =~ /^${field_type}([sS]|(\d+))\/([^\/]+)(\/(\S\S))?$/);
303: ($eax_size, $eax_cat_name, $eax_arg_cycles) = ($1, $3, $5);
304:
305: # if the EA size depends on a size field, get it:
306: if ($eax_size =~ /[sS]/) {
307: die "stdin:$line: $args[$arg_i] argument with no size field?\n"
308: if (!defined($eax_size = eval("\$field_$eax_size;")));
309: }
310:
311: # get the field values:
312: eval("\@field_values = \@ea${field_type}_${eax_cat_name}${eax_size};");
313:
314: # if this argument is overriding the default cycles on the
315: # EA category, enforce the override on the field values:
316: if (defined($eax_arg_cycles)
317: && $eax_arg_cycles ne "") {
318: foreach $field_value (@field_values) {
319: $field_value =~ s/\.(un|ro|wo|rw)$/\.$eax_arg_cycles/;
320: }
321: }
322: }
323:
324: # a register field:
325: elsif ($field_type =~ /[daDA]/) {
326: @field_values = ("000/0", "001/1", "010/2", "011/3", "100/4", "101/5", "110/6", "111/7");
327: }
328:
329: # a quick constant field:
330: elsif ($field_type eq "q") {
331: @field_values = ("000/8", "001/1", "010/2", "011/3", "100/4", "101/5", "110/6", "111/7");
332: }
333:
334: # a condition code field:
335: elsif ($field_type eq "c") {
336: @field_values = ("0000/t", "0001/f", "0010/hi", "0011/ls",
337: "0100/cc", "0101/cs", "0110/ne", "0111/eq",
338: "1000/vc", "1001/vs", "1010/pl", "1011/mi",
339: "1100/ge", "1101/lt", "1110/gt", "1111/le");
340: }
341:
342: # this field must have some values:
343: die "stdin:$line: $field_type-field has no values\n"
344: if (@field_values == 0);
345: print "".(" " x $field_depth)."$field_type-field values: ".join(" ", @field_values)."\n" if ($debug);
346: eval("\@field_n${field_depth}_values = \@field_values;");
347:
348: # loop to pick up the first value from this depth,
349: # and possibly continue descending:
350: next;
351: }
352:
353: # the function name:
354: if ($func =~ /^(.*)\.([sS])$/) {
355: die "stdin:$line: $func with no size field?\n"
356: if (!defined($_ = eval("\$field_$2;")));
357: $instruction .= " func=$1$_";
358: }
359: else {
360: $instruction .= " func=$func";
361: }
362:
363: # handle the arguments:
364: for ($arg_i = 0; $arg_i < @args ; $arg_i++) {
365: $arg = $args[$arg_i];
366:
367: # replace any .s with the s-field:
368: $arg = "$1.$field_s" if ($arg =~ /^(.*)\.s$/);
369: $arg = "$1.$field_S" if ($arg =~ /^(.*)\.S$/);
370:
371: # an immediate argument:
372: $arg = "#$field_s" if ($arg eq "#s");
373: $arg = "#$field_S" if ($arg eq "#S");
374: if ($arg =~ /^\#(\d+)$/ || $arg =~ /^\#(16S32)$/) {
375: $instruction .= " imm_size=$1 imm_operand=$arg_i";
376: }
377:
378: # an EA argument:
379: elsif ($arg =~ /^([xy])/) {
380: $field_type = $1;
381: $field_value = eval("\$field_${field_type};");
382: if ($field_value =~ /^mem${field_type}\.(\d+)\.(\S\S)$/) {
383: die "stdin:$line: unsized ea${field_type} memory argument $field_value (internal error?)\n"
384: if ($1 == 0);
385: die "stdin:$line: ea${field_type} memory argument with no cycles (internal error?)\n"
386: if ($2 eq "un");
387: $instruction .= " ea${field_type}_size=$1 ea${field_type}_cycles=$2";
388: $field_value = "mem${field_type}.$1";
389: }
390: elsif ($field_value =~ /^imm\.(\d+)$/) {
391: $instruction .= " imm_size=$1 imm_operand=$arg_i";
392: $field_value = "";
393: }
394: elsif ($field_value eq "eax.32") {
395: $instruction .= " eax_size=UNSIZED";
396: }
397: $instruction .= " op${arg_i}=$field_value" if ($field_value ne "");
398: }
399:
400: # a register argument:
401: elsif ($arg =~ /^\%([daDA])(\.\d+)$/) {
402: $field_type = $1;
403: $reg = $field_type;
404: $reg =~ tr/A-Z/a-d/;
405: $instruction .= " op${arg_i}=\%$reg".eval("\$field_$1;").$2;
406: }
407:
408: # a register number argument:
409: elsif ($arg =~ /^\#([daDa])/) {
410: $field_type = $1;
411: $instruction .= " op${arg_i}=imm".eval("\$field_$1;").".32";
412: }
413:
414: # a quick integer argument:
415: elsif ($arg =~ /^\#q\.(\d+)/) {
416: $instruction .= " op${arg_i}=imm${field_q}.$1";
417: }
418:
419: # a hard-coded immediate argument:
420: elsif ($arg =~ /^\#(\d+)\.(\d+)/) {
421: $instruction .= " op${arg_i}=imm$1.$2";
422: }
423:
424: # handle a dummy argument:
425: elsif ($arg eq "X") {
426: }
427:
428: else {
429: die "stdin:$line: argument type $arg unknown\n";
430: }
431: }
432:
433: # we have a complete pattern and decoded instruction:
434: print "$pattern$instruction\n";
435: }
436:
437: }
438:
439: print "cpu-end $cpu_name\n";
440:
441: # done:
442: exit(0);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.