Annotation of tme/ic/m68k/m68k-opmap-make.pl, revision 1.1.1.3

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.