static void parseLL (git_uint32* pc, Label op)
{
    int modes [2];
    parseModeNibbles (pc, 2, modes);

    parseLoad (pc, reg_L1, modes [0], size32, NULL);
    parseLoad (pc, reg_L2, modes [1], size32, NULL);
    emitCode (op);
}
static void parseLLL_branch (git_uint32* pc, Label op)
{
    int modes [3];
    parseModeNibbles (pc, 3, modes);

    parseLoad (pc, reg_L1, modes [0], size32, NULL);
    parseLoad (pc, reg_L2, modes [1], size32, NULL);
    parse_finish_branch (pc, op, reg_L3, modes [2]);
}
static void parseLLSS (git_uint32* pc, Label op)
{
    int modes [4];
    parseModeNibbles (pc, 4, modes);

    parseLoad (pc, reg_L1, modes [0], size32, NULL);
    parseLoad (pc, reg_L2, modes [1], size32, NULL);
    emitCode (op);
    parseStore (pc, reg_S1, modes [2], size32);
    parseStore (pc, reg_S2, modes [3], size32);
}
static void parse_finish_branch (git_uint32* pc, Label op, LoadReg reg, int mode)
{
    git_sint32 val;
    if (parseLoad (pc, reg, mode, size32, &val))
    {
        // The branch offset is a constant, so we can
        // check for the special values 0 and 1 right here.
        
        if (val == 0)
        {
            emitCode (op - label_jeq_var + label_jeq_return0);
        }
        else if (val == 1)
        {
            emitCode (op - label_jeq_var + label_jeq_return1);
        }
        else
        {
            // Calculate the destination address and
            // emit a constant branch opcode.
            emitConstBranch (op - label_jeq_var + label_jeq_const, *pc + val - 2);
        }
    }
    else
    {
        // The branch offset isn't a constant, so just
        // emit the normal opcode plus the current PC.
        
        emitCode (op);
        emitData(*pc);
    }
}
Exemple #5
0
/**
 * \brief Main..
 */
int main(int argc, char **argv, char **envp) {
    int i, last;
    Load load_data;
    char **load_names = NULL;
    int load_filesize = 0;
    char *load_buffer = NULL;
    int config_filesize = 0;
    char *config_buffer = NULL;
    char *config_file = NULL;
    char *log_file = NULL;
    int num_loads = 0;
    struct timeval StartTime, CurrentTime;

    int **errorFlags;
    int err = ERR_CLEAN;
    int pflag = 0;
    Plan *CommPlan;
    int iflag;
    unsigned int nap;

    comm_setup(&argc, &argv);
    MyRank = comm_getrank();

    last = 0;

    num_loads = initialize(argc, argv, &log_file, &config_file, &load_names);

    /* Initialize ROOT's global variables using input files. */
    if(MyRank == ROOT) {
        config_filesize = initConfigOptions(config_file, &config_buffer);         /* parse configuration file. */
        if((config_filesize <= 0) || (config_buffer == NULL) ) {
            EmitLog(MyRank, SCHEDULER_THREAD, "Aborting run - A config file could not be opened/read.", -1, PRINT_ALWAYS);
            config_filesize = 0;
            if(config_buffer != NULL) {
                free(config_buffer);
            }
        }
        comm_broadcast_int(&config_filesize);
    } else {
        comm_broadcast_int(&config_filesize);
        config_buffer = getFileBuffer(config_filesize);
    }

    if(config_filesize == 0) {
        comm_finalize();
        exit(1);
    }

    err = broadcast_buffer(config_buffer, config_filesize);

    err += parseConfig(config_buffer, config_filesize);
    free(config_buffer);

    if(MyRank == ROOT) {
        if(PRINT_RARELY <= verbose_flag) {          /* Print status info. */
            printf("num_loads                = %d\n", num_loads);
            printf("num_workers              = %d\n", num_workers);
            printf("thermal_panic            = %d\n", thermal_panic);
            printf("thermal_relaxation_time  = %d\n", thermal_relaxation_time);
            printf("monitor_frequency        = %d\n", monitor_frequency);
            printf("monitor_output_frequency = %d\n", monitor_output_frequency);
            printf("temperature_path         = %s\n", temperature_path);
            for(i = 0; i < num_loads; i++) {
                printf("load_names[%d]           = %s\n", i, load_names[i]);
            }
            printf("log_file                 = %s\n", log_file);
        }
    }

    // num_loads = bcastConfig(num_loads); // Broadcast global variables from ROOT to all others.
    if(num_loads <= 0) {                    // If there are no loads to run, exit the program.
        comm_finalize();
        exit(0);
    }

    /* Initialize the communication load if it is to be run */
    if(comm_flag != 0) {
        data pass;
        pass.isize = 1;
        pass.i = &comm_flag;
        CommPlan = makeCommPlan(&pass);
    } else {
        CommPlan = 0;
    }
    if(CommPlan != 0) {
        iflag = (CommPlan->fptr_initplan)(CommPlan);
    }

    /* Initialize the array of ThreadHandle structures for the workers. */
    WorkerHandle = (ThreadHandle *)malloc(num_workers * sizeof(ThreadHandle));
    if(WorkerHandle == NULL) {
        EmitLog(MyRank, SCHEDULER_THREAD, "Aborting run - Insufficient memory for the WorkerHandle struct", -1, PRINT_ALWAYS);
        comm_finalize();
        exit(1);
    }

    errorFlags = initErrorFlags();
    initWorkerFlags();

    if(DO_PERF) {
        performance_init();
    }     //DO_PERF

    if(MyRank == ROOT) {
        EmitLog(MyRank, SCHEDULER_THREAD, "Initialization complete. Beginning run.", -1, PRINT_ALWAYS);
    }

    StartMonitorThread();
    StartWorkerThreads();

    sleep(thermal_relaxation_time);     /* idle for a baseline */
    reduceTemps();
    sleep(thermal_relaxation_time);

    /*********************************************************************************
    * The following code will subscribe plans and their sizes to worker threads.
    * This is a temporary load distribution being that it comes from a single load.
    * In the future we would like to have several loads lined up to distribute to the
    * worker threads in a simlar fashion. This will allow us to run the benchmark
    * for different time durations depending on the total load schedule.
    *********************************************************************************/
    nap = monitor_output_frequency / 4;
    if(nap < 1) {
        nap = 1;
    }
    for(i = 0; i < num_loads; i++) {
        if(MyRank == ROOT) {                                    // Pull load data from a load file.
            assert(load_names);
            load_filesize = initLoadOptions(load_names[i], &load_buffer);
            if((load_filesize <= 0) || (load_buffer == NULL) ) {
                // /* Redundant */fprintf(stderr, "This load file could not be opened/read... trying next (if available).\n");
                EmitLog(MyRank, SCHEDULER_THREAD, "This load file could not be opened/read... trying next (if available).", -1, PRINT_ALWAYS);
                load_filesize = 0;
                if(load_buffer != NULL) {
                    free(load_buffer);
                }
            }
            comm_broadcast_int(&load_filesize);
            if(load_filesize == 0) {
                continue;
            }
        } else {
            comm_broadcast_int(&load_filesize);
            if(load_filesize == 0) {
                continue;
            }
            load_buffer = getFileBuffer(load_filesize);
        }
        err = broadcast_buffer(load_buffer, load_filesize);
        err += parseLoad(load_buffer, &load_data);
        free(load_buffer);
        // err = bcastLoad(&load_data);             // Broadcast the load structure to all nodes (processes).
        err = WorkerSched(&load_data);                                  // Assign the load to worker threads and check for errors
        if(MyRank == ROOT) {
            printLoad(&load_data);                                      // Print the load data to the terminal.
        }
        if(err != ERR_CLEAN) {
            errorFlags[SYSTEM + 1][err]++;
        }
#define SB_CONTINUE      0x0
#define SB_LAST_TRIP     0x1
#define SB_DO_REDUCTIONS 0x2
        if(MyRank == ROOT) {                                            // ROOT notes when we start this load
            gettimeofday(&StartTime, NULL);
            last = StartTime.tv_sec;
        }
        do {            // DELAY WHILE LOAD RUNS: loop while the load executes until ROOT's clock says stop.  Sleep if CommPlan isn't valid.
            if((comm_flag != 0) && (CommPlan) && (CommPlan->fptr_execplan) && (CommPlan->vptr)) {
                iflag = (CommPlan->fptr_execplan)(CommPlan);                             // run an iteration of the comm plan if enabled
            } else {
                gettimeofday(&CurrentTime, NULL);
                if(nap + CurrentTime.tv_sec < StartTime.tv_sec + load_data.runtime) {
                    sleep(nap);
                } else {
                    sleep((StartTime.tv_sec + load_data.runtime)-CurrentTime.tv_sec);
                }
            }
            if(MyRank == ROOT) {
                gettimeofday(&CurrentTime, NULL);
                pflag = ((CurrentTime.tv_sec > last + monitor_output_frequency) << 1) | (CurrentTime.tv_sec < StartTime.tv_sec + load_data.runtime);
            }
            comm_broadcast_int(&pflag);
            if(pflag & SB_DO_REDUCTIONS) {
                assert(errorFlags);
                reduceFlags(errorFlags);
                reduceTemps();
                if(MyRank == ROOT) {
                    last = CurrentTime.tv_sec;
                }
            }
        } while(pflag & SB_LAST_TRIP);
        // LOAD COMPLETE
        if(MyRank == ROOT) {
            EmitLog(MyRank, SCHEDULER_THREAD, "Elapsed time for this load:", CurrentTime.tv_sec - StartTime.tv_sec, PRINT_ALWAYS);
        }
        freeLoad(&load_data);
    }
    sleep(thermal_relaxation_time);
    reduceTemps();
    StopWorkerThreads();                        // tell them all to finish

    // Clean up the Communication Plan
    if((comm_flag != 0) && (CommPlan) && (CommPlan->vptr)) {
        if(CommPlan->fptr_perfplan) {
            iflag = (CommPlan->fptr_perfplan)(CommPlan);
        }
        if(CommPlan->fptr_killplan) {
            CommPlan = (CommPlan->fptr_killplan)(CommPlan);
        }
    }

    sleep(thermal_relaxation_time);

    if(DO_PERF) {
        sleep(30);
        perf_table_print(LOCAL, PRINT_OFTEN);
        perf_table_reduce();

        perf_table_maxreduce();
        perf_table_minreduce();

        if(MyRank == ROOT) {
            perf_table_print(GLOBAL, PRINT_ALWAYS);
        }
    } //DO_PERF

    if(MyRank == ROOT) {
        EmitLog(MyRank, SCHEDULER_THREAD, "Run Completed. Exiting.", -1, PRINT_ALWAYS);
    }

    comm_finalize();
    exit(0);
} /* main */
void parseInstruction (git_uint32* pc, int * done)
{
    git_uint32 pcStart = *pc;
    int modes [8];
    git_uint32 opcode;
    
    static int ops = 0;
    ++ops;
    
    // Fetch the opcode.
    opcode = memRead8((*pc)++);

    // Check for multi-byte opcode.
    if (opcode & 0x80)
    {
        if (opcode & 0x40)
        {
            // Four-byte opcode.
            opcode &= 0x3F;
            opcode = (opcode << 8) | memRead8((*pc)++);
            opcode = (opcode << 8) | memRead8((*pc)++);
            opcode = (opcode << 8) | memRead8((*pc)++);
        }
        else
        {
            // Two-byte opcode.
            opcode &= 0x7F;
            opcode = (opcode << 8) | memRead8((*pc)++);
        }
    }

    if (gDebug)
    {
        emitCode (label_debug_step);
        emitData (pcStart);
        emitData (opcode);
    }
    
    // printf (" opcode=0x%x", opcode);
    
    // Now we have an opcode number,
    // parse the operands and emit code.
    
    switch (opcode)
    {
        case op_nop: emitCode (label_nop); break;

        // Arithmetic and logic

        case op_add: parseLLS (pc, label_add_discard); break;
        case op_sub: parseLLS (pc, label_sub_discard); break;        
        case op_mul: parseLLS (pc, label_mul_discard); break;
        case op_div: parseLLS (pc, label_div_discard); break;
        case op_mod: parseLLS (pc, label_mod_discard); break;
        
        case op_bitand: parseLLS (pc, label_bitand_discard); break;
        case op_bitor:  parseLLS (pc, label_bitor_discard);  break;
        case op_bitxor: parseLLS (pc, label_bitxor_discard); break;

        case op_neg:    parseLS (pc, label_neg_discard);    break;
        case op_bitnot: parseLS (pc, label_bitnot_discard); break;

        case op_shiftl:  parseLLS (pc, label_shiftl_discard);  break;
        case op_ushiftr: parseLLS (pc, label_ushiftr_discard); break;
        case op_sshiftr: parseLLS (pc, label_sshiftr_discard); break;

        // Branches

        case op_jump: parseL_branch (pc, label_jump_var); *done = 1; break;
        case op_jz:   parseLL_branch (pc, label_jz_var);  break;
        case op_jnz:  parseLL_branch (pc, label_jnz_var); break;
        case op_jeq:  parseLLL_branch (pc, label_jeq_var);  break;
        case op_jne:  parseLLL_branch (pc, label_jne_var);  break;
        case op_jlt:  parseLLL_branch (pc, label_jlt_var);  break;
        case op_jgt:  parseLLL_branch (pc, label_jgt_var);  break;
        case op_jle:  parseLLL_branch (pc, label_jle_var);  break;
        case op_jge:  parseLLL_branch (pc, label_jge_var);  break;
        case op_jltu: parseLLL_branch (pc, label_jltu_var); break;
        case op_jgtu: parseLLL_branch (pc, label_jgtu_var); break;
        case op_jleu: parseLLL_branch (pc, label_jleu_var); break;
        case op_jgeu: parseLLL_branch (pc, label_jgeu_var); break;
        
        case op_jumpabs: parseL (pc, label_jumpabs); *done = 1; break;

        // Moving data

        case op_copy:
            parseModeNibbles (pc, 2, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseStore (pc, reg_S1, modes [1], size32);
            break;

        case op_copys:
            parseModeNibbles (pc, 2, modes);
            parseLoad (pc, reg_L1, modes [0], size16, NULL);
            emitCode (label_copys_discard);
            parseStore (pc, reg_S1, modes [1], size16);
            break;
        
        case op_copyb:
            parseModeNibbles (pc, 2, modes);
            parseLoad (pc, reg_L1, modes [0], size8, NULL);
            emitCode (label_copyb_discard);
            parseStore (pc, reg_S1, modes [1], size8);
            break;

        case op_sexs: parseLS (pc, label_sexs_discard); break;
        case op_sexb: parseLS (pc, label_sexb_discard); break;

        // Array data

        case op_aload:    parseLLS (pc, label_aload_discard);    break;
        case op_aloads:   parseLLS (pc, label_aloads_discard);   break;
        case op_aloadb:   parseLLS (pc, label_aloadb_discard);   break;
        case op_aloadbit: parseLLS (pc, label_aloadbit_discard); break;
        
        case op_astore:    parseLLL (pc, label_astore);    break;
        case op_astores:   parseLLL (pc, label_astores);   break;
        case op_astoreb:   parseLLL (pc, label_astoreb);   break;
        case op_astorebit: parseLLL (pc, label_astorebit); break;

        // The stack

        case op_stkcount: parseS (pc, label_stkcount);  break;
        case op_stkpeek:  parseLS (pc, label_stkpeek);  break;
        case op_stkswap:  emitCode (label_stkswap); break;
        case op_stkcopy:  parseL (pc, label_stkcopy);   break;
        case op_stkroll:  parseLL (pc, label_stkroll);  break;

        // Functions

        case op_call:
            parseModeNibbles (pc, 3, modes);        
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseLoad (pc, reg_L2, modes [1], size32, NULL);
            emitCode (label_args_stack);
            parseCallStub (pc, modes [2]);
            break;

        case op_callf:
            parseModeNibbles (pc, 2, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            emitCode (label_args_0);
            parseCallStub (pc, modes [1]);
            break;

        case op_callfi:
            parseModeNibbles (pc, 3, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseLoad (pc, reg_L2, modes [1], size32, NULL);
            emitCode (label_args_1);
            parseCallStub (pc, modes [2]);
            break;

        case op_callfii:
            parseModeNibbles (pc, 4, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseLoad (pc, reg_L2, modes [1], size32, NULL);
            parseLoad (pc, reg_L3, modes [2], size32, NULL);
            emitCode (label_args_2);
            parseCallStub (pc, modes [3]);
            break;

        case op_callfiii:
            parseModeNibbles (pc, 5, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseLoad (pc, reg_L2, modes [1], size32, NULL);
            parseLoad (pc, reg_L3, modes [2], size32, NULL);
            parseLoad (pc, reg_L4, modes [3], size32, NULL);
            emitCode (label_args_3);
            parseCallStub (pc, modes [4]);
            break;

        case op_return:
            parseL (pc, label_return);
            *done = 1;
            break;

        case op_tailcall:
            parseModeNibbles (pc, 2, modes);        
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseLoad (pc, reg_L2, modes [1], size32, NULL);
            emitCode (label_args_stack);
            emitCode (label_tailcall);
            *done = 1;
            break;

        // Continuations

        case op_catch: parseCatch (pc); break;
        case op_throw:
            parseLL (pc, label_throw);
            *done = 1;
            break;

        case op_random:  parseLS (pc, label_random); break;
        case op_setrandom:  parseL (pc, label_setrandom); break;

        case op_getmemsize: parseS (pc, label_getmemsize); break;
        case op_setmemsize: parseLS (pc, label_setmemsize); break;
        
        case op_quit:
            emitCode (label_quit);
            *done = 1;
            break;
        
        case op_restart:
            emitCode (label_restart);
            *done = 1;
            break;
        
        case op_restore: parseLS (pc, label_restore); break;
        case op_restoreundo: parseS (pc, label_restoreundo); break;
        case op_protect: parseLL (pc, label_protect); break;
        case op_verify: parseS (pc, label_verify); break;

        case op_save:
            parseModeNibbles (pc, 2, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseSaveStub (pc, modes [1]);
            break;

        case op_saveundo:
            parseModeNibbles (pc, 1, modes);
            parseUndoStub (pc, modes [0]);
            break;

        case op_getiosys: parseSS (pc, label_getiosys);  break;
        case op_setiosys: parseLL (pc, label_setiosys);  break;

        case op_getstringtbl: parseS (pc, label_getstringtbl);  break;
        case op_setstringtbl: parseL (pc, label_setstringtbl);  break;

        case op_streamchar:    parseL (pc, label_streamchar);    emitData(*pc); break;
        case op_streamnum:     parseL (pc, label_streamnum);     emitData(*pc); break;
        case op_streamstr:     parseL (pc, label_streamstr);     emitData(*pc); break;
        case op_streamunichar: parseL (pc, label_streamunichar); emitData(*pc); break;
 
        case op_glk: parseLLS (pc, label_glk); break;
        case op_gestalt: parseLLS (pc, label_gestalt); break;

        case op_binarysearch:
        case op_linearsearch:
            parseModeNibbles (pc, 8, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseLoad (pc, reg_L2, modes [1], size32, NULL);
            parseLoad (pc, reg_L3, modes [2], size32, NULL);
            parseLoad (pc, reg_L4, modes [3], size32, NULL);
            parseLoad (pc, reg_L5, modes [4], size32, NULL);
            parseLoad (pc, reg_L6, modes [5], size32, NULL);
            parseLoad (pc, reg_L7, modes [6], size32, NULL);
            emitCode (opcode == op_linearsearch ? label_linearsearch : label_binarysearch);
            parseStore (pc, reg_S1, modes [7], size32);
            break;

        case op_linkedsearch:
            parseModeNibbles (pc, 7, modes);
            parseLoad (pc, reg_L1, modes [0], size32, NULL);
            parseLoad (pc, reg_L2, modes [1], size32, NULL);
            parseLoad (pc, reg_L3, modes [2], size32, NULL);
            parseLoad (pc, reg_L4, modes [3], size32, NULL);
            parseLoad (pc, reg_L5, modes [4], size32, NULL);
            parseLoad (pc, reg_L6, modes [5], size32, NULL);
            emitCode (label_linkedsearch);
            parseStore (pc, reg_S1, modes [6], size32);
            break;
        
        case op_debugtrap:
            parseL (pc, label_debugtrap);
            break;
        
        // Memory management
            
        case op_mzero: parseLL (pc, label_mzero); break;
        case op_mcopy: parseLLL (pc, label_mcopy); break;
        
        case op_malloc: parseLS (pc, label_malloc); break;
        case op_mfree: parseL (pc, label_mfree); break;
        
        // Function acceleration
            
        case op_accelfunc: parseLL (pc, label_accelfunc); break;
        case op_accelparam: parseLL (pc, label_accelparam); break;

        // Floating point

        case op_numtof: parseLS (pc, label_numtof); break;
        case op_ftonumz: parseLS (pc, label_ftonumz); break;
        case op_ftonumn: parseLS (pc, label_ftonumn); break;
        case op_ceil: parseLS (pc, label_ceil); break;
        case op_floor: parseLS (pc, label_floor); break;
        case op_sqrt: parseLS (pc, label_sqrt); break;
        case op_exp: parseLS (pc, label_exp); break;
        case op_log: parseLS (pc, label_log); break;

        case op_fadd: parseLLS (pc, label_fadd_discard); break;
        case op_fsub: parseLLS (pc, label_fsub_discard); break;
        case op_fmul: parseLLS (pc, label_fmul_discard); break;
        case op_fdiv: parseLLS (pc, label_fdiv_discard); break;
        case op_pow: parseLLS (pc, label_pow); break;
        case op_atan2: parseLLS (pc, label_atan2); break;

        case op_fmod: parseLLSS (pc, label_fmod); break;

        case op_sin: parseLS (pc, label_sin); break;
        case op_cos: parseLS (pc, label_cos); break;
        case op_tan: parseLS (pc, label_tan); break;
        case op_asin: parseLS (pc, label_asin); break;
        case op_acos: parseLS (pc, label_acos); break;
        case op_atan: parseLS (pc, label_atan); break;

        case op_jfeq: parseLLLL_branch (pc, label_jfeq_var); break;
        case op_jfne: parseLLLL_branch (pc, label_jfne_var); break;

        case op_jflt: parseLLL_branch (pc, label_jflt_var); break;
        case op_jfle: parseLLL_branch (pc, label_jfle_var); break;
        case op_jfgt: parseLLL_branch (pc, label_jfgt_var); break;
        case op_jfge: parseLLL_branch (pc, label_jfge_var); break;

        case op_jisnan: parseLL_branch (pc, label_jisnan_var); break;
        case op_jisinf: parseLL_branch (pc, label_jisinf_var); break;

        // Special Git opcodes
        
        case op_git_setcacheram: parseL (pc, label_git_setcacheram); break;
        case op_git_prunecache: parseLL (pc, label_git_prunecache); break;
        
        default:
            // Unknown opcode.
            abortCompilation();
            break;
    }
}
Exemple #7
0
void parseCatchStub (git_uint32 * pc, int * modes)
{
    git_uint32 tokenVal;
    git_sint32 branchVal;
    git_uint32 branchConst = 0;
    Block stubCode;

    switch (modes[0])
    {
        case 0x0: // Discard
            goto store_discard;
        case 0x5: // Contents of address 00 to FF. (One byte)
            tokenVal = memRead8(*pc);
            *pc += 1;
            goto store_addr;
        case 0x6: // Contents of address 0000 to FFFF. (Two bytes)
            tokenVal = memRead16(*pc);
            *pc += 2;
            goto store_addr;
        case 0x7: // Contents of any address. (Four bytes)
            tokenVal = memRead32(*pc);
            *pc += 4;
            goto store_addr;
        case 0x8: // Value popped off stack. (Zero bytes)
            goto store_stack;
        case 0x9: // Call frame local at store_address 00 to FF. (One byte)
            tokenVal = memRead8(*pc);
            *pc += 1;
            goto store_local;
        case 0xA: // Call frame local at store_address 0000 to FFFF. (Two bytes)
            tokenVal = memRead16(*pc);
            *pc += 2;
            goto store_local;
        case 0xB: // Call frame local at any store_address. (Four bytes)
            tokenVal = memRead32(*pc);
            *pc += 4;
            goto store_local;
        case 0xD: // Contents of RAM address 00 to FF. (One byte)
            tokenVal = memRead8(*pc) + gRamStart;
            *pc += 1;
            goto store_addr;
        case 0xE: // Contents of RAM address 0000 to FFFF. (Two bytes)
            tokenVal = memRead16(*pc) + gRamStart;
            *pc += 2;
            goto store_addr;
        case 0xF: // Contents of RAM, any address. (Four bytes)
            tokenVal = memRead32(*pc) + gRamStart;
            *pc += 4;
            goto store_addr;
        // ------------------------------------------------------
        store_discard:
            branchConst = parseLoad (pc, reg_L1, modes[1], size32, &branchVal);
            emitCode (label_catch_stub_discard);
            break;
        store_stack:
            branchConst = parseLoad (pc, reg_L1, modes[1], size32, &branchVal);
            emitCode (label_catch_stub_stack);
            break;
        store_addr:
            branchConst = parseLoad (pc, reg_L1, modes[1], size32, &branchVal);
            emitCode (label_catch_stub_addr);
            emitData (tokenVal);
            break;
        store_local:
            branchConst = parseLoad (pc, reg_L1, modes[1], size32, &branchVal);
            emitCode (label_catch_stub_local);
            emitData (tokenVal);
            break;
    }
    
    // The catch stub ends with the address to go to on throw,
    // which is after the branch, so we don't know what it is yet.
    emitData (0);
    stubCode = peekAtEmittedStuff (1);

    // Emit the branch taken after storing the catch token.
    if (branchConst)
    {
        if (branchVal == 0)
            emitCode (label_jump_return0);
        else if (branchVal == 1)
            emitCode (label_jump_return1);
        else
            emitConstBranch (label_jump_const, *pc + branchVal - 2);
    }
    else
    {
        emitCode (label_jump_var);
        emitData (*pc);
    }

    // Fix up the throw return address
    *stubCode = *pc;
    nextInstructionIsReferenced ();
}