|
|
1.1 root 1: #! /usr/local/bin/perl -w
2:
1.1.1.3 ! root 3: # $Id: m68k-opmap-make.pl,v 1.9 2005/05/14 19:15:37 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"
194: if ($map_func[$pattern] !~ /^(move)(\d+)$/);
195: $map_func[$pattern] = $1."nonmemtomem".$2;
196: $map_eax_size[$pattern] = $map_eay_size[$pattern];
197: $map_eax_cycles[$pattern] = $map_eay_cycles[$pattern];
198: $map_op0[$pattern] =~ s/^memy/memx/;
199: $map_op1[$pattern] =~ s/^memy/memx/;
200: }
201:
202: # otherwise, this instruction is using both ea paths.
203: # the only instruction allowed to do this is move.S.
204: # temporarily rewrite this function to a special
205: # function "movememtomem":
206: else {
207: die "$PROG: pattern ".sprintf("%b", $pattern)." ($map_func[$pattern]) uses both ea paths\n"
208: if ($map_func[$pattern] !~ /^(move)(\d+)$/);
209: $map_func[$pattern] = $1."memtomem".$2;
210: die "$PROG: pattern ".sprintf("%b", $pattern)." ($map_func[$pattern]) uses both ea paths at different sizes\n"
211: if ($map_eay_size[$pattern] ne $map_eax_size[$pattern]);
212: die "$PROG: pattern ".sprintf("%b", $pattern)." ($map_func[$pattern]) doesn't use eay write-only\n"
213: if ($map_eay_cycles[$pattern] ne "wo");
214: }
215: }
216: }
217: print STDERR " found $unused unused $cpu_name patterns\n";
218:
1.1.1.3 ! root 219: # start the opcode map initialization for this CPU. if there
! 220: # is a previous CPU, call its initialization function first:
! 221: #
! 222: $opcode_map_init = '';
! 223: if (defined($cpu_name_previous)) {
! 224: $opcode_map_init .= "\n tme_m68k_opcodes_init_${cpu_name_previous}(opcodes);\n";
! 225: }
! 226: $opcode_map_init .= "\n";
! 227:
! 228: # loop over the root patterns:
! 229: #
! 230: %param_to_local = ();
! 231: $local_next = 0;
! 232: undef (@root_init_calls);
! 233: $root_group_i_next = 0;
1.1 root 234: for ($root = 0; $root < 1024; $root++) {
235:
1.1.1.3 ! root 236: # loop over the patterns under this root:
! 237: #
! 238: %param_to_submask = ();
! 239: print STDERR "root $root\n" if ($debug);
1.1 root 240: for ($sub = 0, $pattern = $root << 6; $sub < 64 ; $sub++, $pattern++) {
241:
1.1.1.3 ! root 242: # start the opcode parameters:
! 243: #
! 244: $line = $map_line[$pattern];
! 245: @params = ();
! 246:
! 247: # the opcode function. NB that a memory-to-memory move
! 248: # generates the Y effective address after generating the
! 249: # normal EA, and that a nonmemory-to-memory move generates
! 250: # only the Y EA:
1.1 root 251: #
252: $func = $map_func[$pattern];
1.1.1.3 ! root 253: if ($func =~ /^movememtomem(\d+)$/) {
! 254: $func = "move${1}";
! 255: push (@params,
! 256: 'TME_M68K_OPCODE_EA_Y',
! 257: 'TME_M68K_OPCODE_SPECOP');
! 258: }
! 259: elsif ($func =~ /^movenonmemtomem(\d+)$/) {
! 260: $func = "move${1}";
! 261: push (@params,
! 262: 'TME_M68K_OPCODE_EA_Y');
! 263: }
! 264: $insn_i = $func_to_insn_i{$func};
! 265: if (!defined($insn_i)) {
! 266: $insn_i = $func_to_insn_i{$func} = (@insn_i_to_func + 0);
! 267: push (@insn_i_to_func, $func);
! 268: }
! 269: unshift(@params,
! 270: "TME_M68K_OPCODE_INSN($insn_i)");
! 271:
! 272: # the two operands:
! 273: #
! 274: undef ($eax_size);
! 275: undef ($cycles);
! 276: for ($op_i = 0; $op_i < 2; $op_i++) {
! 277: eval("\$op = \$map_op${op_i}[\$pattern];");
! 278:
! 279: # if this operand is a register:
! 280: #
! 281: if ($op =~ /^\%([ad][0-7])\.(\d+)/) {
! 282: ($op, $op_size) = ($1, $2);
! 283: $op =~ tr/a-z/A-Z/;
! 284: if ($op_size == 16) {
! 285: $op .= " << 1";
! 286: }
! 287: elsif ($op_size == 8) {
! 288: $op .= " << 2";
! 289: }
! 290: $op = "tme_m68k_ireg_uint${op_size}(TME_M68K_IREG_${op})";
! 291: }
! 292:
! 293: # if this operand is the effective address:
! 294: #
! 295: elsif ($op eq "eax.32") {
! 296: $op = "_tme_m68k_ea_address";
! 297: $eax_size = $map_eax_size[$pattern];
! 298: $cycles = $map_eax_cycles[$pattern];
! 299: if ($eax_size ne 'UNSIZED') {
! 300: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has a sized control EA\n";
! 301: }
! 302: if ($cycles ne 'U'
! 303: && $cycles ne 'un') {
! 304: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has cycles ($cycles) on a control EA\n";
! 305: }
! 306: }
! 307:
! 308: # if this operand is an opcode immediate:
! 309: #
! 310: elsif ($op =~ /^imm(\d+)\.(\d+)/) {
! 311: ($op, $op_size) = ($1, $2);
! 312: $op = $op_imm{$op};
! 313: if ($op_size == 16) {
! 314: $op .= " << 1";
! 315: }
! 316: elsif ($op_size == 8) {
! 317: $op .= " << 2";
! 318: }
! 319: $op = "tme_m68k_ireg_uint${op_size}(TME_M68K_IREG_${op})";
! 320: }
! 321:
! 322: # if this operand is a memory buffer:
! 323: #
! 324: elsif ($op =~ /^mem([xy])\.(\d+)/) {
! 325: $op = "tme_m68k_ireg_mem${1}${2}";
! 326: $eax_size = $map_eax_size[$pattern];
! 327: $cycles = $map_eax_cycles[$pattern];
! 328: if ($eax_size eq 'UNSIZED') {
! 329: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has an unsized EA\n";
! 330: }
! 331: if ($cycles eq 'U'
! 332: || $cycles eq 'un') {
! 333: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has no cycles on an EA\n";
! 334: }
! 335: }
! 336:
! 337: elsif ($op ne 'U') {
! 338: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) op${op_i} unknown: $op\n";
! 339: }
! 340:
! 341: # if this operand is an immediate:
! 342: #
! 343: if ($map_imm_operand[$pattern] eq $op_i) {
! 344: if ($op ne 'U') {
! 345: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) op${op_i} is already $op\n";
! 346: }
! 347: $op_size = $map_imm_size[$pattern];
! 348: $op = 'TME_M68K_IREG_IMM32';
! 349: $imm_size = '16';
! 350: if ($op_size eq '8') {
! 351: $op .= " << 2";
! 352: }
! 353: elsif ($op_size eq '16') {
! 354: $op .= " << 1";
! 355: }
! 356: elsif ($op_size eq '16S32') {
! 357: $op_size = '32';
! 358: }
! 359: elsif ($op_size eq '32') {
! 360: $imm_size = '32';
! 361: }
! 362: else {
! 363: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has bad immediate size $op_size\n";
! 364: }
! 365: $op = "tme_m68k_ireg_uint${op_size}(${op})";
! 366: push (@params,
! 367: 'TME_M68K_OPCODE_IMM_'.$imm_size);
! 368: }
! 369:
! 370: # if this operand is defined:
! 371: #
! 372: if ($op ne 'U') {
! 373: push (@params,
! 374: 'TME_M68K_OPCODE_OP'
! 375: .$op_i
! 376: .'('.$op.')');
! 377: }
! 378: }
! 379:
! 380: # any EA operand:
! 381: #
! 382: if (defined($eax_size)
! 383: && $eax_size ne 'U') {
! 384: if ($eax_size eq 'UNSIZED') {
! 385: if ($cycles ne 'un'
! 386: && $cycles ne 'U') {
! 387: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has an unsized EA with $cycles cycles\n";
! 388: }
! 389: push (@params, "TME_M68K_OPCODE_EA_UNSIZED");
! 390: }
! 391: elsif ($eax_size eq '8'
! 392: || $eax_size eq '16'
! 393: || $eax_size eq '32') {
! 394: push (@params, "TME_M68K_OPCODE_EA_SIZE(TME_M68K_SIZE_${eax_size})");
1.1 root 395: }
396: else {
1.1.1.3 ! root 397: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has an $eax_size sized EA\n";
! 398: }
! 399: if ($cycles eq 'U'
! 400: || $cycles eq 'un') {
! 401: # nothing to do
! 402: #
! 403: }
! 404: elsif ($cycles eq 'ro') {
! 405: push (@params,
! 406: 'TME_M68K_OPCODE_EA_READ');
! 407: }
! 408: elsif ($cycles eq 'rw') {
! 409: push (@params,
! 410: 'TME_M68K_OPCODE_EA_READ',
! 411: 'TME_M68K_OPCODE_EA_WRITE');
! 412: }
! 413: elsif ($cycles eq 'wo') {
! 414: push (@params,
! 415: 'TME_M68K_OPCODE_EA_WRITE');
! 416: }
! 417: else {
! 418: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has bad EA cycles\n";
1.1 root 419: }
420: }
1.1.1.3 ! root 421:
! 422: # any opcode specop:
! 423: #
! 424: $specop = $specop{$func};
! 425: if (defined($specop)) {
! 426: if ($specop ne 'specop16'
! 427: && $specop ne 'fpgen') {
! 428: die "$PROG: pattern ".sprintf("%016b", $pattern)." ($map_func[$pattern]) has a bad specop\n";
! 429: }
! 430: push (@params,
! 431: "TME_M68K_OPCODE_SPECOP");
! 432: }
! 433:
! 434: # each param has an associated submask - a 64-bit mask
! 435: # with a set bit for each sub in this root that needs
! 436: # that param. for each param used by this pattern,
! 437: # set this sub's bit in the param's submask:
! 438: #
! 439: foreach $param (@params) {
! 440: $_ = $param_to_submask{$param};
! 441: if (!defined($_)) {
! 442: $_ = '0:0';
! 443: }
! 444: ($submask_hi, $submask_lo) = split(/:/, $_);
! 445: if ($sub > 31) {
! 446: $submask_hi |= (1 << ($sub & 31));
! 447: }
! 448: else {
! 449: $submask_lo |= (1 << $sub);
! 450: }
! 451: $param_to_submask{$param} = "${submask_hi}:${submask_lo}";
! 452: }
1.1 root 453: }
1.1.1.3 ! root 454:
! 455: # within a root, params usually share submasks. gather
! 456: # the sets of params that share submasks into a hash
! 457: # indexed by submask, and then sort those keys to get a
! 458: # list of the submasks for the params passed to a root
! 459: # initialization function:
! 460: #
! 461: undef(%submasks);
! 462: foreach $param (sort(keys(%param_to_submask))) {
! 463: $submask = $param_to_submask{$param};
! 464: $submasks{$submask} .= "${param};";
! 465: }
! 466: @submasks = (sort(keys(%submasks)));
! 467:
! 468: # if this root hasn't changed since the previous CPU,
! 469: # don't bother emitting anything for it - the previous
! 470: # CPU's initialization will take care of it:
! 471: #
! 472: $root_key = '';
! 473: foreach $submask (@submasks) {
! 474: $root_key .= "${submask} $submasks{$submask} %";
! 475: }
! 476: $_ = $root_key_previous[$root];
! 477: if (defined($_)
! 478: && $_ eq $root_key) {
! 479: next;
1.1 root 480: }
1.1.1.3 ! root 481: $root_key_previous[$root] = $root_key;
1.1 root 482:
1.1.1.3 ! root 483: # if a root initialization function doesn't already exist
! 484: # for this submasks list:
1.1 root 485: #
1.1.1.3 ! root 486: $submasks = join(' ', @submasks);
! 487: $root_init_i = $submasks_to_root_init_i{$submasks};
! 488: if (!defined($root_init_i)) {
1.1 root 489:
1.1.1.3 ! root 490: # create a new root initialization function:
! 491: #
! 492: $root_init_i = $submasks_to_root_init_i{$submasks} = $root_init_i_next++;
! 493: print "\n/* root init ${root_init_i}: */\n";
! 494: 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 495:
1.1.1.3 ! root 496: # loop over the subs:
! 497: #
! 498: for ($sub = 0; $sub < 64; $sub++) {
! 499:
! 500: # make a list of params for this sub:
! 501: #
! 502: @params = ();
! 503: for ($param_i = 0; $param_i < @submasks; $param_i++) {
! 504: ($submask_hi, $submask_lo) = split(/:/, $submasks[$param_i]);
! 505: if ((($sub > 31)
! 506: ? $submask_hi
! 507: : $submask_lo)
! 508: & (1 << ($sub & 31))) {
! 509: push (@params, "params[${param_i}]");
! 510: }
1.1 root 511: }
512:
1.1.1.3 ! root 513: # add in this sub's parameters:
! 514: #
! 515: if (@params > 0) {
! 516: print " root[${sub}] = ".join(' | ', @params).";\n";
! 517: }
1.1 root 518: }
1.1.1.3 ! root 519: print "}\n";
1.1 root 520: }
1.1.1.3 ! root 521: print STDERR "root init ${root_init_i} submasks are $submasks\n" if ($debug);
! 522:
! 523: # loop over the parameters for the root initialization function:
! 524: #
! 525: @root_init_params = ();
! 526: for ($param_i = 0; $param_i < @submasks; $param_i++) {
! 527:
! 528: # get the params that this root needs to provide for
! 529: # this root initialization parameter, and store certain
! 530: # params in constant locals, to try to make compilation
! 531: # easier:
! 532: #
! 533: @params = split(/;/, $submasks{$submasks[$param_i]});
! 534: foreach $param (@params) {
! 535: if ($param =~ /^TME_M68K_OPCODE_OP\d/) {
! 536: $local = $param_to_local{$param};
! 537: if (!defined($local)) {
! 538: $local = $param_to_local{$param} = $local_next++;
! 539: $opcode_map_init = " const tme_uint32_t param${local} = $param;\n".$opcode_map_init;
! 540: }
! 541: $param = "param${local}";
! 542: }
1.1 root 543: }
1.1.1.3 ! root 544:
! 545: push (@root_init_params, join(' | ', @params));
1.1 root 546: }
1.1.1.3 ! root 547:
! 548: # assume that the best place to initialize this root is at
! 549: # the end of all current root initializations:
! 550: #
! 551: $root_init_call_best = $#root_init_calls;
! 552: $root_init_call_best_score = 0;
! 553:
! 554: # loop over all current root initializations, tracking the
! 555: # values that each leaves in params[], and finding the
! 556: # current root initialization that leaves params[] closest
! 557: # to what this root initialization needs:
! 558: #
! 559: undef (@params_state);
! 560: for ($root_init_call = 0;
! 561: $root_init_call < @root_init_calls;
! 562: $root_init_call++) {
! 563:
! 564: # get this current root initialization, and update the params[] state:
! 565: #
! 566: ($junk, $junk, @root_init_params_other) = split(/\#/, $root_init_calls[$root_init_call]);
! 567: splice(@params_state, 0, @root_init_params_other + 0, @root_init_params_other);
! 568:
! 569: # score our closeness to this current root initialization's params[]:
! 570: #
! 571: $root_init_call_score = 0;
! 572: for ($param_i = 0;
! 573: $param_i < @params_state && $param_i < @root_init_params;
! 574: $param_i++) {
! 575: if ($params_state[$param_i] eq $root_init_params[$param_i]) {
! 576: $root_init_call_score++;
! 577: }
1.1 root 578: }
1.1.1.3 ! root 579:
! 580: # update the closest current root initialization:
! 581: #
! 582: if ($root_init_call_best_score <= $root_init_call_score) {
! 583: $root_init_call_best_score = $root_init_call_score;
! 584: $root_init_call_best = $root_init_call;
1.1 root 585: }
586: }
1.1.1.3 ! root 587:
! 588: # add this root initialization to the list:
! 589: #
! 590: splice(@root_init_calls, $root_init_call_best + 1, 0,
! 591: join("\#", $root, $root_init_i, @root_init_params));
1.1 root 592: }
593:
1.1.1.3 ! root 594: # make the root initialization function calls:
! 595: #
! 596: undef (@params_state);
! 597: @root_init_group = ();
! 598: $root_init_i_group = -1;
! 599: for ($root_init_call = 0;
! 600: $root_init_call < @root_init_calls;
! 601: $root_init_call++) {
1.1 root 602:
1.1.1.3 ! root 603: # get this next root:
! 604: #
! 605: ($root, $root_init_i, @root_init_params) = split(/\#/, $root_init_calls[$root_init_call]);
1.1 root 606:
1.1.1.3 ! root 607: # if this root uses a different init function than the
! 608: # current group, flush this group and start a new one:
! 609: #
! 610: if ($root_init_i != $root_init_i_group) {
! 611: &root_init_group_flush();
1.1 root 612: }
613:
1.1.1.3 ! root 614: # loop over this root's params:
! 615: #
! 616: for ($param_i = 0; $param_i < @root_init_params; $param_i++) {
1.1 root 617:
1.1.1.3 ! root 618: # if this param doesn't already have the right value:
! 619: #
! 620: if (!defined($params_state[$param_i])
! 621: || $params_state[$param_i] ne $root_init_params[$param_i]) {
1.1 root 622:
1.1.1.3 ! root 623: # flush the current group:
! 624: #
! 625: &root_init_group_flush();
1.1 root 626:
1.1.1.3 ! root 627: # set the new param value:
! 628: #
! 629: $opcode_map_init .= " params[${param_i}] = ".$root_init_params[$param_i].";\n";
! 630: $params_state[$param_i] = $root_init_params[$param_i];
1.1 root 631: }
632: }
633:
1.1.1.3 ! root 634: # add this root to the current group:
! 635: #
! 636: push (@root_init_group, $root);
1.1 root 637: }
638:
1.1.1.3 ! root 639: # flush the last group:
! 640: #
! 641: &root_init_group_flush();
1.1 root 642:
1.1.1.3 ! root 643: # define the opcode map:
! 644: #
1.1 root 645: print "\n";
1.1.1.3 ! root 646: print "/* the ${cpu_name} opcode map: */\n";
! 647: print "tme_uint32_t tme_m68k_opcodes_${cpu_name}[65536];\n";
! 648:
! 649: # define the opcode map initialization function:
! 650: #
! 651: print "\n";
! 652: print "/* the ${cpu_name} opcode map initialization: */\n";
! 653: print "void\ntme_m68k_opcodes_init_${cpu_name}(tme_uint32_t *opcodes)\n{\n";
! 654: print " tme_uint32_t params[64];\n";
! 655: print $opcode_map_init;
! 656: print "}\n";
1.1 root 657:
1.1.1.3 ! root 658: $cpu_name_previous = $cpu_name;
1.1 root 659: }
660:
661: # anything else is an error:
662: else {
663: print STDERR "stdin:$line $PROG error: don't know how to handle: ".join(" ", @tokens)."\n";
664: exit(1);
665: }
666: }
667:
1.1.1.3 ! root 668: print STDERR "$PROG: $root_init_i_next total root inits\n";
! 669:
! 670: # emit the insn array:
! 671: #
! 672: print "\n";
! 673: print "/* the insn array: */\n";
! 674: print "const _tme_m68k_insn tme_m68k_opcode_insns[] = {\n";
! 675: print " tme_m68k_".join(",\n tme_m68k_", @insn_i_to_func)."\n";
! 676: print "};\n\n";
! 677:
1.1 root 678: # done:
679: exit(0);
680:
1.1.1.3 ! root 681: # this flushes the current group of root inits:
! 682: #
! 683: sub root_init_group_flush {
! 684: my ($root);
! 685: my ($root_group_i);
! 686:
! 687: # if there is only one root in this group:
! 688: #
! 689: if (@root_init_group == 1) {
! 690: $root = $root_init_group[0];
! 691:
! 692: $opcode_map_init .= "\n /* root $root: */\n";
! 693: $opcode_map_init .= " _tme_m68k_opcode_root_init_${root_init_i_group}(opcodes + ($root * 64), params);\n\n";
1.1 root 694: }
1.1.1.3 ! root 695:
! 696: # if there are multiple roots in this group:
! 697: #
! 698: elsif (@root_init_group > 1) {
! 699:
! 700: # emit the group:
! 701: #
! 702: $root_group_i = $root_group_i_next++;
! 703: if ($root_group_i == 0) {
! 704: $opcode_map_init = " tme_uint16_t root_i;\n".$opcode_map_init;
! 705: }
! 706: $opcode_map_init = ' const tme_uint16_t root_group'.$root_group_i.'[] = {'.join(', ', @root_init_group)."};\n".$opcode_map_init;
! 707:
! 708: # emit the group root init call:
! 709: #
! 710: $opcode_map_init .= "\n /* roots ".join(', ', @root_init_group).": */\n";
! 711: $opcode_map_init .= " for (root_i = 0; root_i < ".(@root_init_group + 0)."; root_i++) {\n";
! 712: $opcode_map_init .= " _tme_m68k_opcode_root_init_${root_init_i_group}(opcodes + (root_group".$root_group_i."[root_i] * 64), params);\n";
! 713: $opcode_map_init .= " }\n\n";
! 714: }
! 715:
! 716: # initialize for the next group:
! 717: #
! 718: @root_init_group = ();
! 719: $root_init_i_group = $root_init_i;
! 720: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.