Annotation of previous/src/debug/debugcpu.c, revision 1.1

1.1     ! root        1: /*
        !             2:   Hatari - debugcpu.c
        !             3: 
        !             4:   This file is distributed under the GNU Public License, version 2 or at
        !             5:   your option any later version. Read the file gpl.txt for details.
        !             6: 
        !             7:   debugcpu.c - function needed for the CPU debugging tasks like memory
        !             8:   and register dumps.
        !             9: */
        !            10: const char DebugCpu_fileid[] = "Hatari debugcpu.c : " __DATE__ " " __TIME__;
        !            11: 
        !            12: #include <stdio.h>
        !            13: 
        !            14: #include "config.h"
        !            15: 
        !            16: #include "main.h"
        !            17: #include "breakcond.h"
        !            18: #include "configuration.h"
        !            19: #include "debugui.h"
        !            20: #include "debug_priv.h"
        !            21: #include "debugcpu.h"
        !            22: #include "evaluate.h"
        !            23: #include "hatari-glue.h"
        !            24: #include "log.h"
        !            25: #include "m68000.h"
        !            26: #include "memorySnapShot.h"
        !            27: #include "nextMemory.h"
        !            28: #include "str.h"
        !            29: #include "symbols.h"
        !            30: 
        !            31: #define MEMDUMP_COLS   16      /* memdump, number of bytes per row */
        !            32: #define NON_PRINT_CHAR '.'     /* character to display for non-printables */
        !            33: 
        !            34: static Uint32 disasm_addr=0;     /* disasm address */
        !            35: static Uint32 memdump_addr=0;    /* memdump address */
        !            36: 
        !            37: static int nCpuActiveCBs = 0;  /* Amount of active conditional breakpoints */
        !            38: static int nCpuSteps = 0;      /* Amount of steps for CPU single-stepping */
        !            39: 
        !            40: 
        !            41: /**
        !            42:  * Load a binary file to a memory address.
        !            43:  */
        !            44: static int DebugCpu_LoadBin(int nArgc, char *psArgs[])
        !            45: {
        !            46:        FILE *fp;
        !            47:        unsigned char c;
        !            48:        Uint32 address;
        !            49:        int i=0;
        !            50: 
        !            51:        if (nArgc < 3)
        !            52:        {
        !            53:                DebugUI_PrintCmdHelp(psArgs[0]);
        !            54:                return DEBUGGER_CMDDONE;
        !            55:        }
        !            56: 
        !            57:        if (!Eval_Number(psArgs[2], &address))
        !            58:        {
        !            59:                fprintf(stderr, "Invalid address!\n");
        !            60:                return DEBUGGER_CMDDONE;
        !            61:        }
        !            62: 
        !            63:        if ((fp = fopen(psArgs[1], "rb")) == NULL)
        !            64:        {
        !            65:                fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
        !            66:                return DEBUGGER_CMDDONE;
        !            67:        }
        !            68: 
        !            69:        c = fgetc(fp);
        !            70:        while (!feof(fp))
        !            71:        {
        !            72:                i++;
        !            73:                NEXTMemory_WriteByte(address++, c);
        !            74:                c = fgetc(fp);
        !            75:        }
        !            76:        fprintf(stderr,"  Read 0x%x bytes.\n", i);
        !            77:        fclose(fp);
        !            78: 
        !            79:        return DEBUGGER_CMDDONE;
        !            80: }
        !            81: 
        !            82: 
        !            83: /**
        !            84:  * Dump memory from an address to a binary file.
        !            85:  */
        !            86: static int DebugCpu_SaveBin(int nArgc, char *psArgs[])
        !            87: {
        !            88:        FILE *fp;
        !            89:        unsigned char c;
        !            90:        Uint32 address;
        !            91:        Uint32 bytes, i = 0;
        !            92: 
        !            93:        if (nArgc < 4)
        !            94:        {
        !            95:                DebugUI_PrintCmdHelp(psArgs[0]);
        !            96:                return DEBUGGER_CMDDONE;
        !            97:        }
        !            98: 
        !            99:        if (!Eval_Number(psArgs[2], &address))
        !           100:        {
        !           101:                fprintf(stderr, "  Invalid address!\n");
        !           102:                return DEBUGGER_CMDDONE;
        !           103:        }
        !           104: 
        !           105:        if (!Eval_Number(psArgs[3], &bytes))
        !           106:        {
        !           107:                fprintf(stderr, "  Invalid length!\n");
        !           108:                return DEBUGGER_CMDDONE;
        !           109:        }
        !           110: 
        !           111:        if ((fp = fopen(psArgs[1], "wb")) == NULL)
        !           112:        {
        !           113:                fprintf(stderr,"  Cannot open file '%s'!\n", psArgs[1]);
        !           114:                return DEBUGGER_CMDDONE;
        !           115:        }
        !           116: 
        !           117:        while (i < bytes)
        !           118:        {
        !           119:                c = NEXTMemory_ReadByte(address++);
        !           120:                fputc(c, fp);
        !           121:                i++;
        !           122:        }
        !           123:        fclose(fp);
        !           124:        fprintf(stderr, "  Wrote 0x%x bytes.\n", bytes);
        !           125: 
        !           126:        return DEBUGGER_CMDDONE;
        !           127: }
        !           128: 
        !           129: 
        !           130: /**
        !           131:  * Check whether given address matches any CPU symbol, if yes,
        !           132:  * show the symbol information.
        !           133:  */
        !           134: static void DebugCpu_ShowMatchedSymbol(Uint32 addr)
        !           135: {
        !           136:        const char *symbol = Symbols_GetByCpuAddress(addr);
        !           137:        if (symbol)
        !           138:                fprintf(debugOutput, "%s:\n", symbol);
        !           139: }
        !           140: 
        !           141: /**
        !           142:  * Dissassemble - arg = starting address, or PC.
        !           143:  */
        !           144: int DebugCpu_DisAsm(int nArgc, char *psArgs[])
        !           145: {
        !           146:        Uint32 disasm_upper = 0;
        !           147:        int insts, max_insts;
        !           148:        uaecptr nextpc;
        !           149:        FILE* mydebugOutput=debugOutput;
        !           150: 
        !           151:        if (nArgc > 1)
        !           152:        {
        !           153:                switch (Eval_Range(psArgs[1], &disasm_addr, &disasm_upper))
        !           154:                {
        !           155:                case -1:
        !           156:                        /* invalid value(s) */
        !           157:                        return DEBUGGER_CMDDONE;
        !           158:                case 0:
        !           159:                        /* single value */
        !           160:                        break;
        !           161:                case 1:
        !           162:                        /* range */
        !           163:                        break;
        !           164:                }
        !           165:                if (nArgc > 2) {
        !           166:                        mydebugOutput=fopen(psArgs[2],"w");
        !           167:                        if (mydebugOutput==NULL)
        !           168:                        {
        !           169:                                fprintf(debugOutput,"Cannot open %s abort\n",psArgs[2]);
        !           170:                                return DEBUGGER_CMDDONE;
        !           171:                        }
        !           172:                }
        !           173:        }
        !           174:        else
        !           175:        {
        !           176:                /* continue */
        !           177:                if(!disasm_addr)
        !           178:                        disasm_addr = M68000_GetPC();
        !           179:        }
        !           180: 
        !           181:        /* limit is topmost address or instruction count */
        !           182:        if (disasm_upper)
        !           183:        {
        !           184:                max_insts = INT_MAX;
        !           185:        }
        !           186:        else
        !           187:        {
        !           188: //             max_insts = ConfigureParams.Debugger.nDisasmLines;
        !           189:                max_insts=5;
        !           190:        }
        !           191: 
        !           192:        /* output a range */
        !           193:        for (insts = 0; insts < max_insts && disasm_addr < disasm_upper; insts++)
        !           194:        {
        !           195:                DebugCpu_ShowMatchedSymbol(disasm_addr);
        !           196:                m68k_disasm(mydebugOutput, (uaecptr)disasm_addr, &nextpc, 1);
        !           197:                disasm_addr = nextpc;
        !           198:        }
        !           199:        fflush(mydebugOutput);
        !           200:        if (mydebugOutput!=debugOutput) {fclose(mydebugOutput);}
        !           201: 
        !           202:        return DEBUGGER_CMDCONT;
        !           203: }
        !           204: 
        !           205: 
        !           206: /**
        !           207:  * Readline match callback to list register names usable within debugger.
        !           208:  * STATE = 0 -> different text from previous one.
        !           209:  * Return next match or NULL if no matches.
        !           210:  */
        !           211: static char *DebugCpu_MatchRegister(const char *text, int state)
        !           212: {
        !           213:        static const char regs[][3] = {
        !           214:                "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
        !           215:                "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
        !           216:                "pc", "sr"
        !           217:        };
        !           218:        static int i, len;
        !           219:        
        !           220:        if (!state)
        !           221:        {
        !           222:                /* first match */
        !           223:                i = 0;
        !           224:                len = strlen(text);
        !           225:                if (len > 2)
        !           226:                        return NULL;
        !           227:        }
        !           228:        /* next match */
        !           229:        while (i < ARRAYSIZE(regs)) {
        !           230:                if (strncasecmp(regs[i++], text, len) == 0)
        !           231:                        return (strdup(regs[i-1]));
        !           232:        }
        !           233:        return NULL;
        !           234: }
        !           235: 
        !           236: 
        !           237: /**
        !           238:  * Set address of the named register to given argument.
        !           239:  * Return register size in bits or zero for uknown register name.
        !           240:  * Handles D0-7 data and A0-7 address registers, but not PC & SR
        !           241:  * registers as they need to be accessed using UAE accessors.
        !           242:  */
        !           243: int DebugCpu_GetRegisterAddress(const char *reg, Uint32 **addr)
        !           244: {
        !           245:        char r0, r1;
        !           246:        if (!reg[0] || !reg[1] || reg[2])
        !           247:                return 0;
        !           248:        
        !           249:        r0 = toupper(reg[0]);
        !           250:        r1 = toupper(reg[1]);
        !           251: 
        !           252:        if (r0 == 'D')  /* Data regs? */
        !           253:        {
        !           254:                if (r1 >= '0' && r1 <= '7')
        !           255:                {
        !           256:                        *addr = &(Regs[REG_D0 + r1 - '0']);
        !           257:                        return 32;
        !           258:                }
        !           259:                fprintf(stderr,"\tBad data register, valid values are 0-7\n");
        !           260:                return 0;
        !           261:        }
        !           262:        if(r0 == 'A')  /* Address regs? */
        !           263:        {
        !           264:                if (r1 >= '0' && r1 <= '7')
        !           265:                {
        !           266:                        *addr = &(Regs[REG_A0 + r1 - '0']);
        !           267:                        return 32;
        !           268:                }
        !           269:                fprintf(stderr,"\tBad address register, valid values are 0-7\n");
        !           270:                return 0;
        !           271:        }
        !           272:        return 0;
        !           273: }
        !           274: 
        !           275: 
        !           276: /**
        !           277:  * Dump or set CPU registers
        !           278:  */
        !           279: int DebugCpu_Register(int nArgc, char *psArgs[])
        !           280: {
        !           281:        char reg[3], *assign;
        !           282:        Uint32 value;
        !           283:        char *arg;
        !           284: 
        !           285:        /* If no parameter has been given, simply dump all registers */
        !           286:        if (nArgc == 1)
        !           287:        {
        !           288:                uaecptr nextpc;
        !           289:                /* use the UAE function instead */
        !           290:                m68k_dumpstate(debugOutput, &nextpc);
        !           291:                fflush(debugOutput);
        !           292:                return DEBUGGER_CMDDONE;
        !           293:        }
        !           294: 
        !           295:        arg = psArgs[1];
        !           296: 
        !           297:        assign = strchr(arg, '=');
        !           298:        if (!assign)
        !           299:        {
        !           300:                goto error_msg;
        !           301:        }
        !           302: 
        !           303:        *assign++ = '\0';
        !           304:        if (!Eval_Number(Str_Trim(assign), &value))
        !           305:        {
        !           306:                goto error_msg;
        !           307:        }
        !           308: 
        !           309:        arg = Str_Trim(arg);
        !           310:        if (strlen(arg) != 2)
        !           311:        {
        !           312:                goto error_msg;
        !           313:        }
        !           314:        reg[0] = toupper(arg[0]);
        !           315:        reg[1] = toupper(arg[1]);
        !           316:        reg[2] = '\0';
        !           317:        
        !           318:        /* set SR and update conditional flags for the UAE CPU core. */
        !           319:        if (reg[0] == 'S' && reg[1] == 'R')
        !           320:        {
        !           321:                M68000_SetSR(value);
        !           322:        }
        !           323:        else if (reg[0] == 'P' && reg[1] == 'C')   /* set PC? */
        !           324:        {
        !           325:                M68000_SetPC(value);
        !           326:        }
        !           327:        else
        !           328:        {
        !           329:                Uint32 *regaddr;
        !           330:                /* check&set data and address registers */
        !           331:                if (DebugCpu_GetRegisterAddress(reg, &regaddr))
        !           332:                {
        !           333:                        *regaddr = value;
        !           334:                }
        !           335:                else
        !           336:                {
        !           337:                        goto error_msg;
        !           338:                }
        !           339:        }
        !           340:        return DEBUGGER_CMDDONE;
        !           341: 
        !           342: error_msg:
        !           343:        fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR.\n");
        !           344:        return DEBUGGER_CMDDONE;
        !           345: }
        !           346: 
        !           347: 
        !           348: /**
        !           349:  * CPU wrapper for BreakAddr_Command/BreakPointCount.
        !           350:  */
        !           351: static int DebugCpu_BreakAddr(int nArgc, char *psArgs[])
        !           352: {
        !           353:        BreakAddr_Command(psArgs[1], false);
        !           354:        return DEBUGGER_CMDDONE;
        !           355: }
        !           356: 
        !           357: /**
        !           358:  * CPU wrapper for BreakCond_Command/BreakPointCount.
        !           359:  */
        !           360: static int DebugCpu_BreakCond(int nArgc, char *psArgs[])
        !           361: {
        !           362:        BreakCond_Command(psArgs[1], false);
        !           363:        return DEBUGGER_CMDDONE;
        !           364: }
        !           365: 
        !           366: 
        !           367: /**
        !           368:  * Do a memory dump, args = starting address.
        !           369:  */
        !           370: int DebugCpu_MemDump(int nArgc, char *psArgs[])
        !           371: {
        !           372:        int i;
        !           373:        char c;
        !           374:        Uint32 memdump_upper = 0;
        !           375: 
        !           376:        if (nArgc > 1)
        !           377:        {
        !           378:                switch (Eval_Range(psArgs[1], &memdump_addr, &memdump_upper))
        !           379:                {
        !           380:                case -1:
        !           381:                        /* invalid value(s) */
        !           382:                        return DEBUGGER_CMDDONE;
        !           383:                case 0:
        !           384:                        /* single value */
        !           385:                        break;
        !           386:                case 1:
        !           387:                        /* range */
        !           388:                        break;
        !           389:                }
        !           390:        } /* continue */
        !           391: 
        !           392:        if (!memdump_upper)
        !           393:        {
        !           394:                memdump_upper = memdump_addr + MEMDUMP_COLS * ConfigureParams.Debugger.nMemdumpLines;
        !           395:        }
        !           396: 
        !           397:        while (memdump_addr < memdump_upper)
        !           398:        {
        !           399:                fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
        !           400:                for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
        !           401:                        fprintf(debugOutput, "%2.2x ", NEXTMemory_ReadByte(memdump_addr++));
        !           402:                fprintf(debugOutput, "  ");                     /* print ASCII data */
        !           403:                for (i = 0; i < MEMDUMP_COLS; i++)
        !           404:                {
        !           405:                        c = NEXTMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
        !           406:                        if(!isprint((unsigned)c))
        !           407:                                c = NON_PRINT_CHAR;             /* non-printable as dots */
        !           408:                        fprintf(debugOutput,"%c", c);
        !           409:                }
        !           410:                fprintf(debugOutput, "\n");            /* newline */
        !           411:        } /* while */
        !           412:        fflush(debugOutput);
        !           413: 
        !           414:        return DEBUGGER_CMDCONT;
        !           415: }
        !           416: 
        !           417: 
        !           418: /**
        !           419:  * Command: Write to memory, arg = starting address, followed by bytes.
        !           420:  */
        !           421: static int DebugCpu_MemWrite(int nArgc, char *psArgs[])
        !           422: {
        !           423:        int i, numBytes;
        !           424:        Uint32 write_addr, d;
        !           425:        unsigned char bytes[256]; /* store bytes */
        !           426: 
        !           427:        if (nArgc < 3)
        !           428:        {
        !           429:                DebugUI_PrintCmdHelp(psArgs[0]);
        !           430:                return DEBUGGER_CMDDONE;
        !           431:        }
        !           432: 
        !           433:        /* Read address */
        !           434:        if (!Eval_Number(psArgs[1], &write_addr))
        !           435:        {
        !           436:                fprintf(stderr, "Bad address!\n");
        !           437:                return DEBUGGER_CMDDONE;
        !           438:        }
        !           439: 
        !           440:        numBytes = 0;
        !           441: 
        !           442:        /* get bytes data */
        !           443:        for (i = 2; i < nArgc; i++)
        !           444:        {
        !           445:                if (!Eval_Number(psArgs[i], &d) || d > 255)
        !           446:                {
        !           447:                        fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]);
        !           448:                        return DEBUGGER_CMDDONE;
        !           449:                }
        !           450: 
        !           451:                bytes[numBytes] = d & 0x0FF;
        !           452:                numBytes++;
        !           453:        }
        !           454: 
        !           455:        /* write the data */
        !           456:        for (i = 0; i < numBytes; i++)
        !           457:                NEXTMemory_WriteByte(write_addr + i, bytes[i]);
        !           458: 
        !           459:        return DEBUGGER_CMDDONE;
        !           460: }
        !           461: 
        !           462: 
        !           463: /**
        !           464:  * Command: Continue CPU emulation / single-stepping
        !           465:  */
        !           466: static int DebugCpu_Continue(int nArgc, char *psArgv[])
        !           467: {
        !           468:        int steps = 0;
        !           469:        
        !           470:        if (nArgc > 1)
        !           471:        {
        !           472:                steps = atoi(psArgv[1]);
        !           473:        }
        !           474:        if (steps <= 0)
        !           475:        {
        !           476:                nCpuSteps = 0;
        !           477:                fprintf(stderr,"Returning to emulation...\n");
        !           478:                return DEBUGGER_END;
        !           479:        }
        !           480:        nCpuSteps = steps;
        !           481:        fprintf(stderr,"Returning to emulation for %i CPU instructions...\n", steps);
        !           482:        return DEBUGGER_END;
        !           483: }
        !           484: 
        !           485: 
        !           486: /**
        !           487:  * This function is called after each CPU instruction when debugging is enabled.
        !           488:  */
        !           489: void DebugCpu_Check(void)
        !           490: {
        !           491:        if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
        !           492:        {
        !           493:                DebugCpu_ShowMatchedSymbol(M68000_GetPC());
        !           494:        }
        !           495:        if (nCpuActiveCBs)
        !           496:        {
        !           497:                if (BreakCond_MatchCpu())
        !           498:                        DebugUI();
        !           499:        }
        !           500:        if (nCpuSteps)
        !           501:        {
        !           502:                nCpuSteps -= 1;
        !           503:                if (nCpuSteps == 0)
        !           504:                        DebugUI();
        !           505:        }
        !           506: }
        !           507: 
        !           508: /**
        !           509:  * Should be called before returning back emulation to tell the CPU core
        !           510:  * to call us after each instruction if "real-time" debugging like
        !           511:  * breakpoints has been set.
        !           512:  */
        !           513: void DebugCpu_SetDebugging(void)
        !           514: {
        !           515:        nCpuActiveCBs = BreakCond_BreakPointCount(false);
        !           516:        if (nCpuActiveCBs || nCpuSteps)
        !           517:                M68000_SetSpecial(SPCFLAG_DEBUGGER);
        !           518:        else
        !           519:                M68000_UnsetSpecial(SPCFLAG_DEBUGGER);
        !           520: }
        !           521: 
        !           522: 
        !           523: static const dbgcommand_t cpucommands[] =
        !           524: {
        !           525:        { NULL, NULL, "CPU commands", NULL, NULL, NULL, false },
        !           526:        /* NULL as match function will complete file names */
        !           527:        { DebugCpu_BreakAddr, Symbols_MatchCpuCodeAddress,
        !           528:          "address", "a",
        !           529:          "set CPU PC address breakpoints",
        !           530:          BreakAddr_Description,
        !           531:          true  },
        !           532:        { DebugCpu_BreakCond, BreakCond_MatchCpuVariable,
        !           533:          "breakpoint", "b",
        !           534:          "set/remove/list conditional CPU breakpoints",
        !           535:          BreakCond_Description,
        !           536:          true },
        !           537:        { DebugCpu_DisAsm, Symbols_MatchCpuCodeAddress,
        !           538:          "disasm", "d",
        !           539:          "disassemble from PC, or given address",
        !           540:          "[<start address>[-<end address>]]\n"
        !           541:          "\tIf no address is given, this command disassembles from the last\n"
        !           542:          "\tposition or from current PC if no last position is available.",
        !           543:          false },
        !           544:        { DebugCpu_Register, DebugCpu_MatchRegister,
        !           545:          "cpureg", "r",
        !           546:          "dump register values or set register to value",
        !           547:          "[REG=value]\n"
        !           548:          "\tSet CPU register to value or dumps all register if no parameter\n"
        !           549:          "\thas been specified.",
        !           550:          true },
        !           551:        { DebugCpu_MemDump, Symbols_MatchCpuDataAddress,
        !           552:          "memdump", "m",
        !           553:          "dump memory",
        !           554:          "[<start address>[-<end address>]]\n"
        !           555:          "\tdump memory at address or continue dump from previous address.",
        !           556:          false },
        !           557:        { DebugCpu_MemWrite, Symbols_MatchCpuAddress,
        !           558:          "memwrite", "w",
        !           559:          "write bytes to memory",
        !           560:          "address byte1 [byte2 ...]\n"
        !           561:          "\tWrite bytes to a memory address, bytes are space separated\n"
        !           562:          "\thexadecimals.",
        !           563:          false },
        !           564:        { DebugCpu_LoadBin, NULL,
        !           565:          "loadbin", "l",
        !           566:          "load a file into memory",
        !           567:          "filename address\n"
        !           568:          "\tLoad the file <filename> into memory starting at <address>.",
        !           569:          false },
        !           570:        { DebugCpu_SaveBin, NULL,
        !           571:          "savebin", "s",
        !           572:          "save memory to a file",
        !           573:          "filename address length\n"
        !           574:          "\tSave the memory block at <address> with given <length> to\n"
        !           575:          "\tthe file <filename>.",
        !           576:          false },
        !           577:        { Symbols_Command, NULL,
        !           578:          "symbols", "",
        !           579:          "load CPU symbols & their addresses",
        !           580:          Symbols_Description,
        !           581:          false },
        !           582:        { DebugCpu_Continue, NULL,
        !           583:          "cont", "c",
        !           584:          "continue emulation / CPU single-stepping",
        !           585:          "[steps]\n"
        !           586:          "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
        !           587:          "\tor forever if no steps have been specified.",
        !           588:          false }
        !           589: };
        !           590: 
        !           591: 
        !           592: /**
        !           593:  * Should be called when debugger is first entered to initialize
        !           594:  * CPU debugging variables.
        !           595:  * 
        !           596:  * if you want disassembly or memdumping to start/continue from
        !           597:  * specific address, you can set them here.  If disassembly
        !           598:  * address is zero, disassembling starts from PC.
        !           599:  * 
        !           600:  * returns number of CPU commands and pointer to array of them.
        !           601:  */
        !           602: int DebugCpu_Init(const dbgcommand_t **table)
        !           603: {
        !           604:        memdump_addr = 0;
        !           605:        disasm_addr = 0;
        !           606:        
        !           607:        *table = cpucommands;
        !           608:        return ARRAYSIZE(cpucommands);
        !           609: }
        !           610: 
        !           611: /**
        !           612:  * Should be called when debugger is re-entered to reset
        !           613:  * relevant CPU debugging variables.
        !           614:  */
        !           615: void DebugCpu_InitSession(void)
        !           616: {
        !           617:        disasm_addr = M68000_GetPC();
        !           618: }

unix.superglobalmegacorp.com

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