Annotation of hatari/src/m68000.c, revision 1.1.1.12

1.1       root        1: /*
1.1.1.6   root        2:   Hatari - m68000.c
1.1       root        3: 
1.1.1.6   root        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:   These routines originally (in WinSTon) handled exceptions as well as some
1.1.1.5   root        8:   few OpCode's such as Line-F and Line-A. In Hatari it has mainly become a
                      9:   wrapper between the WinSTon sources and the UAE CPU code.
1.1       root       10: */
1.1.1.12! root       11: 
        !            12: /* 2007/03/xx  [NP]    Possibility to add several wait states for the same instruction in              */
        !            13: /*                     M68000_WaitState (e.g. clr.b $fa1b.w in Decade Demo Menu).                      */
        !            14: /* 2007/04/14  [NP]    Add support for instruction pairing in M68000_AddCycles, using OpcodeFamily and */
        !            15: /*                     LastOpcodeFamily (No Cooper Loader, Oh Crickey ... Hidden Screen).              */
        !            16: /* 2007/04/24  [NP]    Add pairing for BCLR/Bcc.                                                       */
        !            17: /* 2007/09/29  [NP]    Use the new int.c and INT_CONVERT_TO_INTERNAL.                                  */
        !            18: /* 2007/11/26  [NP]    We set BusErrorPC in m68k_run_1 instead of M68000_BusError, else the BusErrorPC */
        !            19: /*                     will not point to the opcode that generated the bus error.                      */
        !            20: /*                     In M68000_BusError, if we have 'move.l $0,$24', we need to generate a bus error */
        !            21: /*                     for the read, not for the write that should occur after (TransBeauce 2 Demo).   */
        !            22: /* 2008/01/07  [NP]    Function 'M68000_InitPairing' and 'PairingArray' as a lookup table for fast     */
        !            23: /*                     determination of valid pairing combinations (replace lots of 'if' tests in      */
        !            24: /*                     m68000.h).                                                                      */
        !            25: /* 2008/01/25  [NP]    Add pairing for LSR/MOVE (and all other bit shifting instr) (Anomaly Demo Intro)*/
        !            26: /* 2008/02/02  [NP]    Add pairing for CMP/Bcc (Level 16 Fullscreen (1988)).                           */
        !            27: /* 2008/02/08  [NP]    Add pairing for LSL/LEA (and all other bit shifting instr) (TVI 2 - The Year    */
        !            28: /*                     After Demo).                                                                    */
        !            29: /* 2008/02/11  [NP]    Add pairing for MULS/MOVEA (Delirious Demo IV Loader).                          */
        !            30: /* 2008/01/25  [NP]    Add pairing for LSR/MOVEA (and all other bit shifting instr) (Decade Demo Reset)*/
        !            31: /* 2008/02/16  [NP]    Add pairing for MULS/DIVS, but not 100% sure. This fixes e605 demo part 3, but  */
        !            32: /*                     this could be due to another missing pairing. FIXME : This needs to be checked  */
        !            33: /*                     on a real ST.                                                                   */
        !            34: /* 2008/03/08  [NP]    In M68000_Exception, we need to know if the exception was triggered by an MFP   */
        !            35: /*                     interrupt or by a video interrupt. In the case MFP vector base was changed in   */
        !            36: /*                     fffa17 to an other value than the default $40, testing exceptionNr is not enough*/
        !            37: /*                     to correctly process the exception. For example, if vector base is set to $10   */
        !            38: /*                     then MFP Timer A will call vector stored at address $74, which would be wrongly */
        !            39: /*                     interpreted as a level 5 int (which doesn't exist on Atari and will cause an    */
        !            40: /*                     assert to fail in intlevel()). We use InterruptType to correctly recognize the  */
        !            41: /*                     MFP interrupts (fix 'Toki' end part fullscreen which sets vector base to $10).  */
        !            42: 
        !            43: 
        !            44: /* [NP] possible pairing to check :             */
        !            45: /*      exg / move.b (a0),d0                    */
        !            46: /*     div / move                              */
        !            47: /*     btst / bxx                              */
        !            48: /*     mul/div div/mul                         */
        !            49: 
        !            50: 
        !            51: const char M68000_rcsid[] = "Hatari $Id: m68000.c,v 1.56 2008/03/09 12:53:28 npomarede Exp $";
1.1       root       52: 
                     53: #include "main.h"
1.1.1.12! root       54: #include "configuration.h"
1.1       root       55: #include "gemdos.h"
1.1.1.6   root       56: #include "hatari-glue.h"
1.1       root       57: #include "int.h"
                     58: #include "m68000.h"
                     59: #include "memorySnapShot.h"
                     60: #include "mfp.h"
1.1.1.12! root       61: #include "options.h"
        !            62: #include "savestate.h"
1.1       root       63: #include "stMemory.h"
                     64: #include "tos.h"
                     65: 
                     66: 
1.1.1.12! root       67: Uint32 BusErrorAddress;         /* Stores the offending address for bus-/address errors */
        !            68: Uint32 BusErrorPC;              /* Value of the PC when bus error occurs */
        !            69: BOOL bBusErrorReadWrite;        /* 0 for write error, 1 for read error */
        !            70: int nCpuFreqShift;              /* Used to emulate higher CPU frequencies: 0=8MHz, 1=16MHz, 2=32Mhz */
        !            71: int nWaitStateCycles;           /* Used to emulate the wait state cycles of certain IO registers */
        !            72: 
        !            73: int LastOpcodeFamily = -1;      /* see the enum in readcpu.h i_XXX */
        !            74: int LastInstrCycles = -1;       /* number of cycles for previous instr. (not rounded to 4) */
        !            75: int Pairing = 0;                /* set to 1 if the latest 2 intr paired */
        !            76: char PairingArray[ MAX_OPCODE_FAMILY ][ MAX_OPCODE_FAMILY ];
        !            77: 
        !            78: 
        !            79: /* to convert the enum from OpcodeFamily to a readable value for pairing's debug */
        !            80: const char *OpcodeName[] = { "ILLG",
        !            81:        "OR","AND","EOR","ORSR","ANDSR","EORSR",
        !            82:        "SUB","SUBA","SUBX","SBCD",
        !            83:        "ADD","ADDA","ADDX","ABCD",
        !            84:        "NEG","NEGX","NBCD","CLR","NOT","TST",
        !            85:        "BTST","BCHG","BCLR","BSET",
        !            86:        "CMP","CMPM","CMPA",
        !            87:        "MVPRM","MVPMR","MOVE","MOVEA","MVSR2","MV2SR",
        !            88:        "SWAP","EXG","EXT","MVMEL","MVMLE",
        !            89:        "TRAP","MVR2USP","MVUSP2R","RESET","NOP","STOP","RTE","RTD",
        !            90:        "LINK","UNLK",
        !            91:        "RTS","TRAPV","RTR",
        !            92:        "JSR","JMP","BSR","Bcc",
        !            93:        "LEA","PEA","DBcc","Scc",
        !            94:        "DIVU","DIVS","MULU","MULS",
        !            95:        "ASR","ASL","LSR","LSL","ROL","ROR","ROXL","ROXR",
        !            96:        "ASRW","ASLW","LSRW","LSLW","ROLW","RORW","ROXLW","ROXRW",
        !            97:        "CHK","CHK2",
        !            98:        "MOVEC2","MOVE2C","CAS","CAS2","DIVL","MULL",
        !            99:        "BFTST","BFEXTU","BFCHG","BFEXTS","BFCLR","BFFFO","BFSET","BFINS",
        !           100:        "PACK","UNPK","TAS","BKPT","CALLM","RTM","TRAPcc","MOVES",
        !           101:        "FPP","FDBcc","FScc","FTRAPcc","FBcc","FSAVE","FRESTORE",
        !           102:        "CINVL","CINVP","CINVA","CPUSHL","CPUSHP","CPUSHA","MOVE16",
        !           103:        "MMUOP"
        !           104: };
1.1.1.8   root      105: 
1.1.1.12! root      106: 
        !           107: /*-----------------------------------------------------------------------*/
        !           108: /**
        !           109:  * Init the pairing matrix
        !           110:  * Two instructions can pair if PairingArray[ LastOpcodeFamily ][ OpcodeFamily ] == 1
        !           111:  */
        !           112: void M68000_InitPairing(void)
        !           113: {
        !           114:        /* First, clear the matrix (pairing is false) */
        !           115:        memset(PairingArray , 0 , MAX_OPCODE_FAMILY * MAX_OPCODE_FAMILY);
        !           116: 
        !           117:        /* Set all valid pairing combinations to 1 */
        !           118:        PairingArray[  i_EXG ][ i_DBcc ] = 1;
        !           119:        PairingArray[ i_CMPA ][  i_Bcc ] = 1;
        !           120:        PairingArray[  i_ASR ][ i_DBcc ] = 1;
        !           121:        PairingArray[  i_ASL ][ i_DBcc ] = 1;
        !           122:        PairingArray[  i_LSR ][ i_DBcc ] = 1;
        !           123:        PairingArray[  i_LSL ][ i_DBcc ] = 1;
        !           124:        PairingArray[  i_ROL ][ i_DBcc ] = 1;
        !           125:        PairingArray[  i_ROR ][ i_DBcc ] = 1;
        !           126:        PairingArray[ i_ROXR ][ i_DBcc ] = 1;
        !           127:        PairingArray[ i_ROXL ][ i_DBcc ] = 1;
        !           128:        PairingArray[  i_ASR ][ i_MOVE ] = 1; 
        !           129:        PairingArray[  i_ASL ][ i_MOVE ] = 1; 
        !           130:        PairingArray[  i_LSR ][ i_MOVE ] = 1; 
        !           131:        PairingArray[  i_LSL ][ i_MOVE ] = 1; 
        !           132:        PairingArray[  i_ROL ][ i_MOVE ] = 1; 
        !           133:        PairingArray[  i_ROR ][ i_MOVE ] = 1; 
        !           134:        PairingArray[ i_ROXR ][ i_MOVE ] = 1; 
        !           135:        PairingArray[ i_ROXL ][ i_MOVE ] = 1; 
        !           136:        PairingArray[  i_ASR ][ i_MOVEA] = 1; 
        !           137:        PairingArray[  i_ASL ][ i_MOVEA] = 1; 
        !           138:        PairingArray[  i_LSR ][ i_MOVEA] = 1; 
        !           139:        PairingArray[  i_LSL ][ i_MOVEA] = 1; 
        !           140:        PairingArray[  i_ROL ][ i_MOVEA] = 1; 
        !           141:        PairingArray[  i_ROR ][ i_MOVEA] = 1; 
        !           142:        PairingArray[ i_ROXR ][ i_MOVEA] = 1; 
        !           143:        PairingArray[ i_ROXL ][ i_MOVEA] = 1; 
        !           144:        PairingArray[  i_CMP ][  i_Bcc ] = 1;
        !           145:        PairingArray[  i_ASR ][  i_LEA ] = 1; 
        !           146:        PairingArray[  i_ASL ][  i_LEA ] = 1; 
        !           147:        PairingArray[  i_LSR ][  i_LEA ] = 1; 
        !           148:        PairingArray[  i_LSL ][  i_LEA ] = 1; 
        !           149:        PairingArray[  i_ROL ][  i_LEA ] = 1; 
        !           150:        PairingArray[  i_ROR ][  i_LEA ] = 1; 
        !           151:        PairingArray[ i_ROXR ][  i_LEA ] = 1; 
        !           152:        PairingArray[ i_ROXL ][  i_LEA ] = 1; 
        !           153:        PairingArray[ i_MULU ][ i_MOVEA] = 1; 
        !           154:        PairingArray[ i_MULS ][ i_MOVEA] = 1; 
        !           155:        PairingArray[ i_MULU ][ i_MOVE ] = 1; 
        !           156:        PairingArray[ i_MULS ][ i_MOVE ] = 1; 
        !           157:        PairingArray[ i_MULS ][ i_DIVS ] = 1;           /* not 100% sure of this one */
        !           158: }
1.1       root      159: 
                    160: 
1.1.1.3   root      161: /*-----------------------------------------------------------------------*/
1.1.1.12! root      162: /**
        !           163:  * Reset CPU 68000 variables
        !           164:  */
1.1       root      165: void M68000_Reset(BOOL bCold)
                    166: {
1.1.1.12! root      167:        int i;
        !           168: 
        !           169:        /* Clear registers */
        !           170:        if (bCold)
        !           171:        {
        !           172:                for (i=0; i<(16+1); i++)
        !           173:                        Regs[i] = 0;
        !           174:        }
        !           175: 
        !           176:        /* Now directly reset the UAE CPU core: */
        !           177:        m68k_reset();
        !           178: 
        !           179:        /* Init the pairing matrix */
        !           180:        M68000_InitPairing();
        !           181: }
        !           182: 
        !           183: 
        !           184: /*-----------------------------------------------------------------------*/
        !           185: /**
        !           186:  * Reset and start 680x0 emulation
        !           187:  */
        !           188: void M68000_Start(void)
        !           189: {
        !           190:        m68k_reset();
1.1       root      191: 
1.1.1.12! root      192:        /* Load initial memory snapshot */
        !           193:        if (bLoadMemorySave)
        !           194:        {
        !           195:                MemorySnapShot_Restore(ConfigureParams.Memory.szMemoryCaptureFileName, FALSE);
        !           196:        }
        !           197:        else if (bLoadAutoSave)
        !           198:        {
        !           199:                MemorySnapShot_Restore(ConfigureParams.Memory.szAutoSaveFileName, FALSE);
        !           200:        }
1.1.1.7   root      201: 
1.1.1.12! root      202:        m68k_go(TRUE);
1.1       root      203: }
                    204: 
1.1.1.3   root      205: 
                    206: /*-----------------------------------------------------------------------*/
1.1.1.12! root      207: /**
        !           208:  * Check wether the CPU mode has been changed.
        !           209:  */
        !           210: void M68000_CheckCpuLevel(void)
        !           211: {
        !           212:        changed_prefs.cpu_level = ConfigureParams.System.nCpuLevel;
        !           213:        changed_prefs.cpu_compatible = ConfigureParams.System.bCompatibleCpu;
        !           214: #ifndef UAE_NEWCPU_H
        !           215:        changed_prefs.cpu_cycle_exact = 0;  // TODO
        !           216: #endif
        !           217:        if (table68k)
        !           218:                check_prefs_changed_cpu();
        !           219: }
        !           220: 
        !           221: 
        !           222: /*-----------------------------------------------------------------------*/
        !           223: /**
        !           224:  * Save/Restore snapshot of CPU variables ('MemorySnapShot_Store' handles type)
        !           225:  */
1.1       root      226: void M68000_MemorySnapShot_Capture(BOOL bSave)
                    227: {
1.1.1.12! root      228:        Uint32 savepc;
1.1       root      229: 
1.1.1.12! root      230:        /* Save/Restore details */
        !           231:        MemorySnapShot_Store(Regs,sizeof(Regs));
        !           232:        MemorySnapShot_Store(&STRamEnd,sizeof(STRamEnd));
        !           233: 
        !           234:        /* For the UAE CPU core: */
        !           235:        MemorySnapShot_Store(&currprefs.address_space_24,
        !           236:                             sizeof(currprefs.address_space_24));
        !           237:        MemorySnapShot_Store(&regs.regs[0], sizeof(regs.regs));       /* D0-D7 A0-A6 */
        !           238: 
        !           239:        if (bSave)
        !           240:        {
        !           241:                savepc = M68000_GetPC();
        !           242:                MemorySnapShot_Store(&savepc, sizeof(savepc));            /* PC */
        !           243:        }
        !           244:        else
        !           245:        {
        !           246:                MemorySnapShot_Store(&savepc, sizeof(savepc));            /* PC */
        !           247:                regs.pc = savepc;
        !           248: #ifdef UAE_NEWCPU_H
        !           249:                regs.prefetch_pc = regs.pc + 128;
        !           250: #endif
        !           251:        }
1.1.1.8   root      252: 
1.1.1.12! root      253: #ifdef UAE_NEWCPU_H
        !           254:        MemorySnapShot_Store(&regs.prefetch, sizeof(regs.prefetch));  /* prefetch */
        !           255: #else
        !           256:        uae_u32 prefetch_dummy;
        !           257:        MemorySnapShot_Store(&prefetch_dummy, sizeof(prefetch_dummy));
        !           258: #endif
        !           259: 
        !           260:        if (bSave)
        !           261:        {
        !           262: #ifdef UAE_NEWCPU_H
        !           263:                MakeSR();
        !           264: #else
        !           265:                MakeSR(&regs);
        !           266: #endif
        !           267:                if (regs.s)
        !           268:                {
        !           269:                        MemorySnapShot_Store(&regs.usp, sizeof(regs.usp));    /* USP */
        !           270:                        MemorySnapShot_Store(&regs.regs[15], sizeof(regs.regs[15]));  /* ISP */
        !           271:                }
        !           272:                else
        !           273:                {
        !           274:                        MemorySnapShot_Store(&regs.regs[15], sizeof(regs.regs[15]));  /* USP */
        !           275:                        MemorySnapShot_Store(&regs.isp, sizeof(regs.isp));    /* ISP */
        !           276:                }
        !           277:                MemorySnapShot_Store(&regs.sr, sizeof(regs.sr));          /* SR/CCR */
        !           278:        }
        !           279:        else
        !           280:        {
        !           281:                MemorySnapShot_Store(&regs.usp, sizeof(regs.usp));
        !           282:                MemorySnapShot_Store(&regs.isp, sizeof(regs.isp));
        !           283:                MemorySnapShot_Store(&regs.sr, sizeof(regs.sr));
        !           284:        }
        !           285:        MemorySnapShot_Store(&regs.stopped, sizeof(regs.stopped));
        !           286:        MemorySnapShot_Store(&regs.dfc, sizeof(regs.dfc));            /* DFC */
        !           287:        MemorySnapShot_Store(&regs.sfc, sizeof(regs.sfc));            /* SFC */
        !           288:        MemorySnapShot_Store(&regs.vbr, sizeof(regs.vbr));            /* VBR */
        !           289:        MemorySnapShot_Store(&caar, sizeof(caar));                    /* CAAR */
        !           290:        MemorySnapShot_Store(&cacr, sizeof(cacr));                    /* CACR */
        !           291:        MemorySnapShot_Store(&regs.msp, sizeof(regs.msp));            /* MSP */
        !           292: 
        !           293:        if (!bSave)
        !           294:        {
        !           295:                M68000_SetPC(regs.pc);
        !           296:                /* MakeFromSR() must not swap stack pointer */
        !           297:                regs.s = (regs.sr >> 13) & 1;
        !           298: #ifdef UAE_NEWCPU_H
        !           299:                MakeFromSR();
        !           300:                /* set stack pointer */
        !           301:                if (regs.s)
        !           302:                        m68k_areg(regs, 7) = regs.isp;
        !           303:                else
        !           304:                        m68k_areg(regs, 7) = regs.usp;
        !           305: #else
        !           306:                MakeFromSR(&regs);
        !           307:                /* set stack pointer */
        !           308:                if (regs.s)
        !           309:                        m68k_areg(&regs, 7) = regs.isp;
        !           310:                else
        !           311:                        m68k_areg(&regs, 7) = regs.usp;
        !           312: #endif
        !           313:        }
        !           314: 
        !           315:        if (bSave)
        !           316:                save_fpu();
        !           317:        else
        !           318:                restore_fpu();
1.1       root      319: }
                    320: 
                    321: 
1.1.1.3   root      322: /*-----------------------------------------------------------------------*/
1.1.1.12! root      323: /**
        !           324:  * BUSERROR - Access outside valid memory range.
        !           325:  * Use bReadWrite = 0 for write errors and bReadWrite = 1 for read errors!
        !           326:  */
1.1.1.10  root      327: void M68000_BusError(Uint32 addr, BOOL bReadWrite)
1.1       root      328: {
1.1.1.12! root      329:        /* FIXME: In prefetch mode, m68k_getpc() seems already to point to the next instruction */
        !           330:        // BusErrorPC = M68000_GetPC();         /* [NP] We set BusErrorPC in m68k_run_1 */
1.1.1.7   root      331: 
1.1.1.12! root      332:        if (BusErrorPC < TosAddress || BusErrorPC > TosAddress + TosSize)
        !           333:        {
        !           334:                /* Print bus errors (except for TOS' hardware tests) */
        !           335:                fprintf(stderr, "M68000_BusError at address $%lx\n", (long)addr);
        !           336:        }
        !           337: 
        !           338:        if ((regs.spcflags & SPCFLAG_BUSERROR) == 0)    /* [NP] Check that the opcode has not already generated a read bus error */
        !           339:        {
        !           340:                BusErrorAddress = addr;                         /* Store for exception frame */
        !           341:                bBusErrorReadWrite = bReadWrite;
        !           342:                M68000_SetSpecial(SPCFLAG_BUSERROR);            /* The exception will be done in newcpu.c */
        !           343:        }
1.1       root      344: }
                    345: 
1.1.1.3   root      346: 
                    347: /*-----------------------------------------------------------------------*/
1.1.1.12! root      348: /**
        !           349:  * Exception handler
        !           350:  */
        !           351: void M68000_Exception(Uint32 ExceptionVector , int InterruptType)
        !           352: {
        !           353:        int exceptionNr = ExceptionVector/4;
        !           354: 
        !           355:        if ( ( InterruptType == M68000_INT_VIDEO )
        !           356:                && (exceptionNr>24 && exceptionNr<32) ) /* 68k autovector interrupt? */
        !           357:        {
        !           358:                /* Handle autovector interrupts the UAE's way
        !           359:                 * (see intlev() and do_specialties() in UAE CPU core) */
        !           360:                /* In our case, this part is only called for HBL and VBL interrupts */
        !           361:                int intnr = exceptionNr - 24;
        !           362:                pendingInterrupts |= (1 << intnr);
        !           363:                M68000_SetSpecial(SPCFLAG_INT);
        !           364:        }
        !           365:        else
        !           366:        {
        !           367:                Uint16 SR;
        !           368: 
        !           369:                /* Was the CPU stopped, i.e. by a STOP instruction? */
        !           370:                if (regs.spcflags & SPCFLAG_STOP)
        !           371:                {
        !           372:                        regs.stopped = 0;
        !           373:                        M68000_UnsetSpecial(SPCFLAG_STOP);    /* All is go,go,go! */
        !           374:                }
        !           375: 
        !           376:                /* 68k exceptions are handled by Exception() of the UAE CPU core */
        !           377: #ifdef UAE_NEWCPU_H
        !           378:                Exception(exceptionNr, m68k_getpc());
        !           379: #else
        !           380:                Exception(exceptionNr, &regs, m68k_getpc(&regs));
        !           381: #endif
        !           382: 
        !           383:                SR = M68000_GetSR();
        !           384: 
        !           385:                /* Set Status Register so interrupt can ONLY be stopped by another interrupt
        !           386:                 * of higher priority! */
1.1.1.6   root      387: #if 0  /* VBL and HBL are handled in the UAE CPU core (see above). */
1.1.1.12! root      388:                if (ExceptionVector == EXCEPTION_VBLANK)
        !           389:                        SR = (SR&SR_CLEAR_IPL)|0x0400;  /* VBL, level 4 */
        !           390:                else if (ExceptionVector == EXCEPTION_HBLANK)
        !           391:                        SR = (SR&SR_CLEAR_IPL)|0x0200;  /* HBL, level 2 */
        !           392:                else
        !           393: #endif
        !           394:                {
        !           395:                        Uint32 MFPBaseVector = (unsigned int)(MFP_VR&0xf0)<<2;
        !           396:                        if ( (ExceptionVector>=MFPBaseVector) && (ExceptionVector<=(MFPBaseVector+0x3c)) )
        !           397:                                SR = (SR&SR_CLEAR_IPL)|0x0600; /* MFP, level 6 */
        !           398:                }
        !           399: 
        !           400:                M68000_SetSR(SR);
        !           401:        }
1.1       root      402: }
                    403: 
1.1.1.8   root      404: 
                    405: /*-----------------------------------------------------------------------*/
1.1.1.12! root      406: /**
        !           407:  * There seem to be wait states when a program accesses certain hardware
        !           408:  * registers on the ST. Use this function to simulate these wait states.
        !           409:  * [NP] with some instructions like CLR, we have a read then a write at the
        !           410:  * same location, so we may have 2 wait states (read and write) to add
        !           411:  * (nWaitStateCycles should be reset to 0 after the cycles were added).
        !           412:  */
1.1.1.11  root      413: void M68000_WaitState(int nCycles)
1.1.1.8   root      414: {
1.1.1.12! root      415:        M68000_SetSpecial(SPCFLAG_EXTRA_CYCLES);
1.1.1.11  root      416: 
1.1.1.12! root      417:        nWaitStateCycles += nCycles;    /* add all the wait states for this instruction */
1.1.1.8   root      418: }

unix.superglobalmegacorp.com

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