|
|
1.1 root 1: #! /usr/local/bin/perl -w
2:
1.1.1.4 ! root 3: # $Id: m68k-opmap-make.pl,v 1.10 2007/08/25 21:16:05 fredette Exp $
1.1.1.2 root 4:
1.1 root 5: # m68k-opmap-make.pl - compiles the complete decoding of all legal
6: # first-instruction-word values into the opcode map used by the C
7: # decoder:
8:
1.1.1.2 root 9: #
1.1.1.3 root 10: # Copyright (c) 2002, 2003, 2005 Matt Fredette
1.1.1.2 root 11: # All rights reserved.
12: #
13: # Redistribution and use in source and binary forms, with or without
14: # modification, are permitted provided that the following conditions
15: # are met:
16: # 1. Redistributions of source code must retain the above copyright
17: # notice, this list of conditions and the following disclaimer.
18: # 2. Redistributions in binary form must reproduce the above copyright
19: # notice, this list of conditions and the following disclaimer in the
20: # documentation and/or other materials provided with the distribution.
21: # 3. All advertising materials mentioning features or use of this software
22: # must display the following acknowledgement:
23: # This product includes software developed by Matt Fredette.
24: # 4. The name of the author may not be used to endorse or promote products
25: # derived from this software without specific prior written permission.
26: #
27: # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28: # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29: # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30: # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
31: # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32: # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33: # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34: # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35: # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36: # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: # POSSIBILITY OF SUCH DAMAGE.
38: #
1.1 root 39:
40: # globals:
41: $0 =~ /^(.*\/)?([^\/]+)$/; $PROG = $2;
42: $debug = 0;
43:
44: # to silence -w:
45: undef($value);
1.1.1.3 root 46: $debug = $debug;
1.1 root 47:
48: # emit our header:
49: print <<"EOF;";
50: /* generated automatically by $PROG, do not edit! */
51:
52: /* includes: */
53: #include "m68k-impl.h"
54: EOF;
55:
1.1.1.3 root 56: # we start with no previous CPU and no root inits:
57: #
58: undef ($cpu_name_previous);
59: $root_init_i_next = 0;
60:
61: # opcode immediates:
62: #
63: %op_imm = ('0', 'ZERO',
64: '1', 'ONE',
65: '2', 'TWO',
66: '3', 'THREE',
67: '4', 'FOUR',
68: '5', 'FIVE',
69: '6', 'SIX',
70: '7', 'SEVEN',
71: '8', 'EIGHT',
72: );
73:
74: # the instruction ordering hints:
75: #
76: @insn_i_to_func = split(/[\r\n\s]+/, <<'EOF;');
77: EOF;
78: for($insn_i = 0; $insn_i < @insn_i_to_func; $insn_i++) {
79: $func = $insn_i_to_func[$insn_i];
80: $func_to_insn_i{$func} = $insn_i;
81: }
1.1 root 82:
83: # loop over standard input:
84: for ($line = 1; defined($_ = <STDIN>); $line++) {
85: chomp;
86:
87: # break the line into tokens:
88: @tokens = split(' ', $_);
89:
90: # if this is the beginning of a new CPU:
91: if ($tokens[0] eq "cpu-begin") {
92: $cpu_name = $tokens[1];
93:
94: # initialize for this CPU:
95: print STDERR "$PROG: initializing for $cpu_name...";
96:
97: # initialize the full map:
98: undef(@map_line);
99: for ($pattern = 65536; $pattern-- > 0;) {
100: $map_op0[$pattern] = "U";
101: $map_op1[$pattern] = "U";
102: $map_eax_size[$pattern] = "U";
103: $map_eax_cycles[$pattern] = "U";
104: $map_imm_operand[$pattern] = "U";
105: $map_imm_size[$pattern] = "U";
106: $map_eay_size[$pattern] = "U";
107: $map_eay_cycles[$pattern] = "U";
108: }
109:
110: # initialize the special operations:
111: undef(%specop);
112:
113: # we're done initializing and we're now reading patterns:
114: $patterns = 0;
115: print STDERR " done\n$PROG: reading $cpu_name patterns...";
116: }
117:
118: # if this is a special-operation line:
119: elsif ($tokens[0] eq "specop") {
120: shift(@tokens);
121: $specop = shift(@tokens);
122: foreach (@tokens) {
123: $specop{$_} = $specop;
124: }
125: }
126:
127: # if this is a pattern:
128: elsif ($tokens[0] =~ /^[01]/) {
129:
130: # the first token is the pattern. die if this pattern has already
131: # appeared:
132: $pattern = oct("0b".shift(@tokens));
1.1.1.3 root 133: if (defined($map_line[$pattern])) {
134: $func = $map_func[$pattern];
135:
136: # to allow for an earlier, more specific iset pattern
137: # while still using very general iset patterns later,
138: # simply add to the function name on the earlier, more
139: # specific iset pattern, the number of asterixes for the
140: # number of later general iset pattern expansions that
141: # will collide with it. these collisions will be ignored:
142: #
143: if ($func =~ /^(.*)\*$/) {
144: $map_func[$pattern] = $1;
145: next;
146: }
147: die "stdin:$line: duplicate pattern of line $map_line[$pattern]\n";
148: }
1.1 root 149: $map_line[$pattern] = $line;
150:
151: # fill this map entry:
152: foreach $token (@tokens) {
153: ($what, $value) = split(/=/, $token, 2);
154: eval("\$map_".$what."[$pattern] = \$value;");
155: }
156: die "stdin:$line: no function given\n"
157: if (!defined($map_func[$pattern]));
158: $patterns++;
159: }
160:
161: # if this is the end of a CPU:
162: elsif ($tokens[0] eq "cpu-end") {
163: $cpu_name = $tokens[1];
164:
165: # note how many patterns we read:
166: print STDERR " read $patterns $cpu_name patterns\n";
167:
168: # sanity-check the information read in, and force all unused
169: # full map entries to illegal:
170: print STDERR "$PROG: finding unused $cpu_name patterns...";
171: $unused = 0;
172: for ($pattern = 65536; $pattern-- > 0;) {
173:
174: # if this is an unused map entry:
175: if (!defined($map_line[$pattern])) {
176: $map_func[$pattern] = "illegal";
177: $unused++;
178: next;
179: }
180:
181: # since the overwhelming majority of instructions use at
182: # most one effective address path (the eax path), only the
183: # size of the eax path operand is stored in the opcode
184: # maps. any instruction that uses the eay path must do so
185: # with the same size as the eax path:
186: if ($map_eay_size[$pattern] ne "U") {
187:
188: # if this instruction isn't using the eax path, switch
189: # to using the eax path instead. the only instruction
190: # allowed to do this is move.S. temporarily rewrite
191: # this function to a special function "movenonmemtomem":
192: if ($map_eax_size[$pattern] eq "U") {
193: die "$PROG: pattern ".sprintf("%b", $pattern)." ($map_func[$pattern]) uses the eay path\n"
1.1.1.4 ! root 194: if ($map_func[$pattern] !~ /^(move)(\d+)$/
! 195: && $map_func[$pattern] !~ /^(move_srp[id])(\d+)$/);
1.1 root 196: $map_func[$pattern] = $1."nonmemtomem".$2;
197: $map_eax_size[$pattern] = $map_eay_size[$pattern];
198: $map_eax_cycles[$pattern] = $map_eay_cycles[$pattern];
199: $map_op0[$pattern] =~ s/^memy/memx/;
200: $map_op1[$pattern] =~ s/^memy/memx/;
201: }
202:
203: # otherwise, this instruction is using both ea paths.
204: # the only instruction allowed to do this is move.S.
205: # temporarily rewrite this function to a special
206: # function "movememtomem":
207: else {
208: die "$PROG: pattern ".sprintf("%b", $pattern)." ($map_func[$pattern]) uses both ea paths\n"
209: if ($map_func[$pattern] !~ /^(move)(\d+)$/);
210: $map_func[$pattern] = $1."memtomem".$2;
211: die "$PROG: pattern ".sprintf("%b", $pattern)." ($map_func[$pattern]) uses both ea paths at different sizes\n"
212: if ($map_eay_size[$pattern] ne $map_eax_size[$pattern]);
213: die "$PROG: pattern ".sprintf("%b", $pattern)." ($map_func[$pattern]) doesn't use eay write-only\n"
214: if ($map_eay_cycles[$pattern] ne "wo");
215: }
216: }
217: }
218: print STDERR " found $unused unused $cpu_name patterns\n";
219:
1.1.1.3 root 220: # start the opcode map initialization for this CPU. if there
221: # is a previous CPU, call its initialization function first:
222: #
223: $opcode_map_init = '';
224: if (defined($cpu_name_previous)) {
225: $opcode_map_init .= "\n tme_m68k_opcodes_init_${cpu_name_previous}(opcodes);\n";
226: }
227: $opcode_map_init .= "\n";
228:
229: # loop over the root patterns:
230: #
231: %param_to_local = ();
232: $local_next = 0;
233: undef (@root_init_calls);
234: $root_group_i_next = 0;
1.1 root 235: for ($root = 0; $root < 1024; $root++) {
236:
1.1.1.3 root 237: # loop over the patterns under this root:
238: #
239: %param_to_submask = ();
240: print STDERR "root $root\n" if ($debug);
1.1 root 241: for ($sub = 0, $pattern = $root << 6; $sub < 64 ; $sub++, $pattern++) {
242:
1.1.1.3 root 243: # start the opcode parameters:
244: #
245: $line = $map_line[$pattern];
246: @params = ();
247:
248: # the opcode function. NB that a memory-to-memory move
249: # generates the Y effective address after generating the
250: # normal EA, and that a nonmemory-to-memory move generates
251: # only the Y EA:
1.1 root 252: #
253: $func = $map_func[$pattern];
1.1.1.3 root 254: if ($func =~ /^movememtomem(\d+)$/) {
255: $func = "move${1}";
256: push (@params,
257: 'TME_M68K_OPCODE_EA_Y',
258: 'TME_M68K_OPCODE_SPECOP');
259: }
1.1.1.4 ! root 260: elsif ($func =~ /^(move.*)nonmemtomem(\d+)$/) {
! 261: $func = "${1}${2}";
1.1.1.3 root 262: push (@params,
263: 'TME_M68K_OPCODE_EA_Y');
264: }
265: $insn_i = $func_to_insn_i{$func};
266: if (!defined($insn_i)) {
267: $insn_i = $func_to_insn_i{$func} = (@insn_i_to_func + 0);
268: push (@insn_i_to_func, $func);
269: }
270: unshift(@params,
271: "TME_M68K_OPCODE_INSN($insn_i)");
272:
273: # the two operands:
274: #
275: undef ($eax_size);
276: undef ($cycles);
277: for ($op_i = 0; $op_i < 2; $op_i++) {
278: eval("\$op = \$map_op${op_i}[\$pattern];");
279:
280: # if this operand is a register:
281: #
282: if ($op =~ /^\%([ad][0-7])\.(\d+)/) {
283: ($op, $op_size) = ($1, $2);
284: $op =~ tr/a-z/A-Z/;
285: if ($op_size == 16) {
286: $op .= " << 1";
287: }
288: elsif ($op_size == 8) {
289: $op .= " << 2";
290: }
291: $op = "tme_m68k_ireg_uint${op_size}(TME_M68K_IREG_${op})";
292: }
293:
294: # if this operand is the effective address:
295: #
296: elsif ($op eq "eax.32") {
297: $op = "_tme_m68k_ea_address";
298: $eax_size = $map_eax_size[$pattern];
299: $cycles = $map_eax_cycles[$pattern];
300: if ($eax_size ne 'UNSIZED') {
301: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has a sized control EA\n";
302: }
303: if ($cycles ne 'U'
304: && $cycles ne 'un') {
305: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has cycles ($cycles) on a control EA\n";
306: }
307: }
308:
309: # if this operand is an opcode immediate:
310: #
311: elsif ($op =~ /^imm(\d+)\.(\d+)/) {
312: ($op, $op_size) = ($1, $2);
313: $op = $op_imm{$op};
314: if ($op_size == 16) {
315: $op .= " << 1";
316: }
317: elsif ($op_size == 8) {
318: $op .= " << 2";
319: }
320: $op = "tme_m68k_ireg_uint${op_size}(TME_M68K_IREG_${op})";
321: }
322:
323: # if this operand is a memory buffer:
324: #
325: elsif ($op =~ /^mem([xy])\.(\d+)/) {
326: $op = "tme_m68k_ireg_mem${1}${2}";
327: $eax_size = $map_eax_size[$pattern];
328: $cycles = $map_eax_cycles[$pattern];
329: if ($eax_size eq 'UNSIZED') {
330: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has an unsized EA\n";
331: }
332: if ($cycles eq 'U'
333: || $cycles eq 'un') {
334: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has no cycles on an EA\n";
335: }
336: }
337:
338: elsif ($op ne 'U') {
339: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) op${op_i} unknown: $op\n";
340: }
341:
342: # if this operand is an immediate:
343: #
344: if ($map_imm_operand[$pattern] eq $op_i) {
345: if ($op ne 'U') {
346: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) op${op_i} is already $op\n";
347: }
348: $op_size = $map_imm_size[$pattern];
349: $op = 'TME_M68K_IREG_IMM32';
350: $imm_size = '16';
351: if ($op_size eq '8') {
352: $op .= " << 2";
353: }
354: elsif ($op_size eq '16') {
355: $op .= " << 1";
356: }
357: elsif ($op_size eq '16S32') {
358: $op_size = '32';
359: }
360: elsif ($op_size eq '32') {
361: $imm_size = '32';
362: }
363: else {
364: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has bad immediate size $op_size\n";
365: }
366: $op = "tme_m68k_ireg_uint${op_size}(${op})";
367: push (@params,
368: 'TME_M68K_OPCODE_IMM_'.$imm_size);
369: }
370:
371: # if this operand is defined:
372: #
373: if ($op ne 'U') {
374: push (@params,
375: 'TME_M68K_OPCODE_OP'
376: .$op_i
377: .'('.$op.')');
378: }
379: }
380:
381: # any EA operand:
382: #
383: if (defined($eax_size)
384: && $eax_size ne 'U') {
385: if ($eax_size eq 'UNSIZED') {
386: if ($cycles ne 'un'
387: && $cycles ne 'U') {
388: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has an unsized EA with $cycles cycles\n";
389: }
390: push (@params, "TME_M68K_OPCODE_EA_UNSIZED");
391: }
392: elsif ($eax_size eq '8'
393: || $eax_size eq '16'
394: || $eax_size eq '32') {
395: push (@params, "TME_M68K_OPCODE_EA_SIZE(TME_M68K_SIZE_${eax_size})");
1.1 root 396: }
397: else {
1.1.1.3 root 398: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has an $eax_size sized EA\n";
399: }
400: if ($cycles eq 'U'
401: || $cycles eq 'un') {
402: # nothing to do
403: #
404: }
405: elsif ($cycles eq 'ro') {
406: push (@params,
407: 'TME_M68K_OPCODE_EA_READ');
408: }
409: elsif ($cycles eq 'rw') {
410: push (@params,
411: 'TME_M68K_OPCODE_EA_READ',
412: 'TME_M68K_OPCODE_EA_WRITE');
413: }
414: elsif ($cycles eq 'wo') {
415: push (@params,
416: 'TME_M68K_OPCODE_EA_WRITE');
417: }
418: else {
419: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has bad EA cycles\n";
1.1 root 420: }
421: }
1.1.1.3 root 422:
423: # any opcode specop:
424: #
425: $specop = $specop{$func};
426: if (defined($specop)) {
427: if ($specop ne 'specop16'
428: && $specop ne 'fpgen') {
429: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has a bad specop\n";
430: }
431: push (@params,
432: "TME_M68K_OPCODE_SPECOP");
433: }
434:
435: # each param has an associated submask - a 64-bit mask
436: # with a set bit for each sub in this root that needs
437: # that param. for each param used by this pattern,
438: # set this sub's bit in the param's submask:
439: #
440: foreach $param (@params) {
441: $_ = $param_to_submask{$param};
442: if (!defined($_)) {
443: $_ = '0:0';
444: }
445: ($submask_hi, $submask_lo) = split(/:/, $_);
446: if ($sub > 31) {
447: $submask_hi |= (1 << ($sub & 31));
448: }
449: else {
450: $submask_lo |= (1 << $sub);
451: }
452: $param_to_submask{$param} = "${submask_hi}:${submask_lo}";
453: }
1.1 root 454: }
1.1.1.3 root 455:
456: # within a root, params usually share submasks. gather
457: # the sets of params that share submasks into a hash
458: # indexed by submask, and then sort those keys to get a
459: # list of the submasks for the params passed to a root
460: # initialization function:
461: #
462: undef(%submasks);
463: foreach $param (sort(keys(%param_to_submask))) {
464: $submask = $param_to_submask{$param};
465: $submasks{$submask} .= "${param};";
466: }
467: @submasks = (sort(keys(%submasks)));
468:
469: # if this root hasn't changed since the previous CPU,
470: # don't bother emitting anything for it - the previous
471: # CPU's initialization will take care of it:
472: #
473: $root_key = '';
474: foreach $submask (@submasks) {
475: $root_key .= "${submask} $submasks{$submask} %";
476: }
477: $_ = $root_key_previous[$root];
478: if (defined($_)
479: && $_ eq $root_key) {
480: next;
1.1 root 481: }
1.1.1.3 root 482: $root_key_previous[$root] = $root_key;
1.1 root 483:
1.1.1.3 root 484: # if a root initialization function doesn't already exist
485: # for this submasks list:
1.1 root 486: #
1.1.1.3 root 487: $submasks = join(' ', @submasks);
488: $root_init_i = $submasks_to_root_init_i{$submasks};
489: if (!defined($root_init_i)) {
1.1 root 490:
1.1.1.3 root 491: # create a new root initialization function:
492: #
493: $root_init_i = $submasks_to_root_init_i{$submasks} = $root_init_i_next++;
494: print "\n/* root init ${root_init_i}: */\n";
495: print "static void\n_tme_m68k_opcode_root_init_${root_init_i}(tme_uint32_t *root, const tme_uint32_t *params)\n{\n";
1.1 root 496:
1.1.1.3 root 497: # loop over the subs:
498: #
499: for ($sub = 0; $sub < 64; $sub++) {
500:
501: # make a list of params for this sub:
502: #
503: @params = ();
504: for ($param_i = 0; $param_i < @submasks; $param_i++) {
505: ($submask_hi, $submask_lo) = split(/:/, $submasks[$param_i]);
506: if ((($sub > 31)
507: ? $submask_hi
508: : $submask_lo)
509: & (1 << ($sub & 31))) {
510: push (@params, "params[${param_i}]");
511: }
1.1 root 512: }
513:
1.1.1.3 root 514: # add in this sub's parameters:
515: #
516: if (@params > 0) {
517: print " root[${sub}] = ".join(' | ', @params).";\n";
518: }
1.1 root 519: }
1.1.1.3 root 520: print "}\n";
1.1 root 521: }
1.1.1.3 root 522: print STDERR "root init ${root_init_i} submasks are $submasks\n" if ($debug);
523:
524: # loop over the parameters for the root initialization function:
525: #
526: @root_init_params = ();
527: for ($param_i = 0; $param_i < @submasks; $param_i++) {
528:
529: # get the params that this root needs to provide for
530: # this root initialization parameter, and store certain
531: # params in constant locals, to try to make compilation
532: # easier:
533: #
534: @params = split(/;/, $submasks{$submasks[$param_i]});
535: foreach $param (@params) {
536: if ($param =~ /^TME_M68K_OPCODE_OP\d/) {
537: $local = $param_to_local{$param};
538: if (!defined($local)) {
539: $local = $param_to_local{$param} = $local_next++;
540: $opcode_map_init = " const tme_uint32_t param${local} = $param;\n".$opcode_map_init;
541: }
542: $param = "param${local}";
543: }
1.1 root 544: }
1.1.1.3 root 545:
546: push (@root_init_params, join(' | ', @params));
1.1 root 547: }
1.1.1.3 root 548:
549: # assume that the best place to initialize this root is at
550: # the end of all current root initializations:
551: #
552: $root_init_call_best = $#root_init_calls;
553: $root_init_call_best_score = 0;
554:
555: # loop over all current root initializations, tracking the
556: # values that each leaves in params[], and finding the
557: # current root initialization that leaves params[] closest
558: # to what this root initialization needs:
559: #
560: undef (@params_state);
561: for ($root_init_call = 0;
562: $root_init_call < @root_init_calls;
563: $root_init_call++) {
564:
565: # get this current root initialization, and update the params[] state:
566: #
567: ($junk, $junk, @root_init_params_other) = split(/\#/, $root_init_calls[$root_init_call]);
568: splice(@params_state, 0, @root_init_params_other + 0, @root_init_params_other);
569:
570: # score our closeness to this current root initialization's params[]:
571: #
572: $root_init_call_score = 0;
573: for ($param_i = 0;
574: $param_i < @params_state && $param_i < @root_init_params;
575: $param_i++) {
576: if ($params_state[$param_i] eq $root_init_params[$param_i]) {
577: $root_init_call_score++;
578: }
1.1 root 579: }
1.1.1.3 root 580:
581: # update the closest current root initialization:
582: #
583: if ($root_init_call_best_score <= $root_init_call_score) {
584: $root_init_call_best_score = $root_init_call_score;
585: $root_init_call_best = $root_init_call;
1.1 root 586: }
587: }
1.1.1.3 root 588:
589: # add this root initialization to the list:
590: #
591: splice(@root_init_calls, $root_init_call_best + 1, 0,
592: join("\#", $root, $root_init_i, @root_init_params));
1.1 root 593: }
594:
1.1.1.3 root 595: # make the root initialization function calls:
596: #
597: undef (@params_state);
598: @root_init_group = ();
599: $root_init_i_group = -1;
600: for ($root_init_call = 0;
601: $root_init_call < @root_init_calls;
602: $root_init_call++) {
1.1 root 603:
1.1.1.3 root 604: # get this next root:
605: #
606: ($root, $root_init_i, @root_init_params) = split(/\#/, $root_init_calls[$root_init_call]);
1.1 root 607:
1.1.1.3 root 608: # if this root uses a different init function than the
609: # current group, flush this group and start a new one:
610: #
611: if ($root_init_i != $root_init_i_group) {
612: &root_init_group_flush();
1.1 root 613: }
614:
1.1.1.3 root 615: # loop over this root's params:
616: #
617: for ($param_i = 0; $param_i < @root_init_params; $param_i++) {
1.1 root 618:
1.1.1.3 root 619: # if this param doesn't already have the right value:
620: #
621: if (!defined($params_state[$param_i])
622: || $params_state[$param_i] ne $root_init_params[$param_i]) {
1.1 root 623:
1.1.1.3 root 624: # flush the current group:
625: #
626: &root_init_group_flush();
1.1 root 627:
1.1.1.3 root 628: # set the new param value:
629: #
630: $opcode_map_init .= " params[${param_i}] = ".$root_init_params[$param_i].";\n";
631: $params_state[$param_i] = $root_init_params[$param_i];
1.1 root 632: }
633: }
634:
1.1.1.3 root 635: # add this root to the current group:
636: #
637: push (@root_init_group, $root);
1.1 root 638: }
639:
1.1.1.3 root 640: # flush the last group:
641: #
642: &root_init_group_flush();
1.1 root 643:
1.1.1.3 root 644: # define the opcode map:
645: #
1.1 root 646: print "\n";
1.1.1.3 root 647: print "/* the ${cpu_name} opcode map: */\n";
648: print "tme_uint32_t tme_m68k_opcodes_${cpu_name}[65536];\n";
649:
650: # define the opcode map initialization function:
651: #
652: print "\n";
653: print "/* the ${cpu_name} opcode map initialization: */\n";
654: print "void\ntme_m68k_opcodes_init_${cpu_name}(tme_uint32_t *opcodes)\n{\n";
655: print " tme_uint32_t params[64];\n";
656: print $opcode_map_init;
657: print "}\n";
1.1 root 658:
1.1.1.3 root 659: $cpu_name_previous = $cpu_name;
1.1 root 660: }
661:
662: # anything else is an error:
663: else {
664: print STDERR "stdin:$line $PROG error: don't know how to handle: ".join(" ", @tokens)."\n";
665: exit(1);
666: }
667: }
668:
1.1.1.3 root 669: print STDERR "$PROG: $root_init_i_next total root inits\n";
670:
671: # emit the insn array:
672: #
673: print "\n";
674: print "/* the insn array: */\n";
675: print "const _tme_m68k_insn tme_m68k_opcode_insns[] = {\n";
676: print " tme_m68k_".join(",\n tme_m68k_", @insn_i_to_func)."\n";
677: print "};\n\n";
678:
1.1 root 679: # done:
680: exit(0);
681:
1.1.1.3 root 682: # this flushes the current group of root inits:
683: #
684: sub root_init_group_flush {
685: my ($root);
686: my ($root_group_i);
687:
688: # if there is only one root in this group:
689: #
690: if (@root_init_group == 1) {
691: $root = $root_init_group[0];
692:
693: $opcode_map_init .= "\n /* root $root: */\n";
694: $opcode_map_init .= " _tme_m68k_opcode_root_init_${root_init_i_group}(opcodes + ($root * 64), params);\n\n";
1.1 root 695: }
1.1.1.3 root 696:
697: # if there are multiple roots in this group:
698: #
699: elsif (@root_init_group > 1) {
700:
701: # emit the group:
702: #
703: $root_group_i = $root_group_i_next++;
704: if ($root_group_i == 0) {
705: $opcode_map_init = " tme_uint16_t root_i;\n".$opcode_map_init;
706: }
707: $opcode_map_init = ' const tme_uint16_t root_group'.$root_group_i.'[] = {'.join(', ', @root_init_group)."};\n".$opcode_map_init;
708:
709: # emit the group root init call:
710: #
711: $opcode_map_init .= "\n /* roots ".join(', ', @root_init_group).": */\n";
712: $opcode_map_init .= " for (root_i = 0; root_i < ".(@root_init_group + 0)."; root_i++) {\n";
713: $opcode_map_init .= " _tme_m68k_opcode_root_init_${root_init_i_group}(opcodes + (root_group".$root_group_i."[root_i] * 64), params);\n";
714: $opcode_map_init .= " }\n\n";
715: }
716:
717: # initialize for the next group:
718: #
719: @root_init_group = ();
720: $root_init_i_group = $root_init_i;
721: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.