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

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

unix.superglobalmegacorp.com

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