[net.sources.mac] Disassembler for Modula-2 Link Files

bobc@tikal.UUCP (Bob Campbell) (09/11/85)

Here is the Disassembler that I announced in net.micro.mac

# The rest of this file is a shell script which will extract:
# README DecIO.DEF Disasm.DEF DecIO.MOD DecLink.MOD Disasm.MOD
echo x - README
cat >README <<'!Funky!Stuff!'
These files (DecIO.DEF DecIO.MOD DecLink.MOD Disasm.DEF Disasm.MOD)
are the modula-2 source for a 68000 disassembler for Modula-2 Link
files (.LNK ext).  The modules function as follows:

DecLink.MOD:
    This is the main module, it breaks the link file up in to it parts
    and calls the decoding routines to print out the various parts.

DecIO.MOD DecIO.DEF:
    This module defines all of the I/O Routines, it opens the input file,
    and the output file (the routine StartIO).  It also provides general
    input and output routines.  Output goes to the input file name
    conveterted to .DEC.

    The Output Routines are:
	WriteHex, WriteHexAdr, WriteCard, WriteInt, WriteDigit,
	printChecksum, ErrorMessage, Write (*a character*), WriteLn,
	WriteString, TabTo, WriteBlanks,

    The Input Routines are:
	Read (* a word *), and ReadBlock

    Startup is StartIO, cleanup is EndIO.
	
Disasm.MOD Disasm.DEF:
    This module is the disassembler proper it imports routines from
    DecIO to format and print.  It receives the data to disassemble
    as a address to a block of data, a load point, and the number of
    bytes to disassemble.

This program is compiled by first compiling all of the .DEF files,
and then all of the .MOD files.  Then the file DecLink.LNK is linked
and the program can be run.

Because of problems with the SFPackage and the M2Files Interface you
can only open files which are on the same disk as the Exec program is.
This is because SFPackage returns a File Name and the Vol #, but the
M2Files open only takes a strings of the form VOLUME:FILE.  I have not
yet figured out a solution to this problem.
!Funky!Stuff!
echo x - DecIO.DEF
cat >DecIO.DEF <<'!Funky!Stuff!'
DEFINITION MODULE DecIO;
    FROM SYSTEM IMPORT WORD,ADDRESS;
    FROM M2Files IMPORT File;
    FROM QuickDraw IMPORT Str255;
    EXPORT QUALIFIED WriteHex,WriteHexAdr,WriteCard,WriteInt,WriteDigit,
            checksum,printChecksum,ErrorMessage,StartIO,EndIO,
            Read,ReadBlock,Write,WriteLn,WriteString,
            WriteBlanks,LinkStream,TabTo;
    
VAR
    checksum:       CARDINAL;
    printChecksum:  BOOLEAN;
    LinkStream,decStream:       File;
    
PROCEDURE ErrorMessage(VAR str: ARRAY OF CHAR);
PROCEDURE TabTo(col:CARDINAL);
PROCEDURE StartIO(VAR found:BOOLEAN);
PROCEDURE EndIO;
PROCEDURE Read(VAR w: WORD);
PROCEDURE ReadBlock(a:ADDRESS;length:CARDINAL);
PROCEDURE Write(ch: CHAR);
PROCEDURE WriteLn;
PROCEDURE WriteString(VAR str: ARRAY OF CHAR);
PROCEDURE WriteBlanks(n: INTEGER);
PROCEDURE WriteHex(x: CARDINAL; l: INTEGER);
PROCEDURE WriteHexAdr(x: ADDRESS; l: INTEGER);
PROCEDURE WriteCard(x: CARDINAL; l: INTEGER);
PROCEDURE WriteInt(x,l: INTEGER);
PROCEDURE WriteDigit(x: CARDINAL);
END DecIO.

!Funky!Stuff!
echo x - Disasm.DEF
cat >Disasm.DEF <<'!Funky!Stuff!'
DEFINITION MODULE Disasm;
    FROM SYSTEM IMPORT ADDRESS;
    EXPORT QUALIFIED Disassemble,ReadCount;
VAR
    ReadCount:  CARDINAL;
    
PROCEDURE Disassemble(data:ADDRESS;loadpoint,maxbyte:CARDINAL);

END Disasm.

!Funky!Stuff!
echo x - DecIO.MOD
cat >DecIO.MOD <<'!Funky!Stuff!'
IMPLEMENTATION MODULE DecIO;
    FROM M2Files IMPORT Open,Create,Close,File,
        ReadWord, WriteChar, eolc;
    FROM SYSTEM IMPORT
        ADDRESS,WORD;
    IMPORT Terminal;
    IMPORT Conversions;
    FROM QuickDraw IMPORT Str255;
    FROM PascalStrings IMPORT MakePascalString, MakeModulaString;
    FROM SFpackage IMPORT SFGetFile,SFPutFile,SFReply,SFTypeList;
(*
 *  EXPORT WriteHex,WriteHexAdr,WriteCard,WriteInt,WriteDigit,
 *          checksum,printChecksum,ErrorMessage,StartIO,EndIO,
 *          Read,ReadBlock,Write,WriteLn,WriteString,
 *          WriteBlanks,WriteNumbers,LinkStream;
 *) 

    VAR
        Column:CARDINAL;

    PROCEDURE ErrorMessage(VAR str: ARRAY OF CHAR);
    BEGIN
        Terminal.WriteString(str);
        Terminal.WriteLn;
    END ErrorMessage;
    
    
    PROCEDURE StartIO(VAR found:BOOLEAN);
    VAR
        FileName:       ARRAY [0..50] OF CHAR;
        optError    : BOOLEAN;
        length, i   : CARDINAL;
        reply   : BOOLEAN;
        ch      : CHAR;
        List:       SFTypeList;
        MPrompt:    Str255;         
        REPLY:      SFReply;
    BEGIN
        Column := 0;
        found := FALSE;
        printChecksum := TRUE;
        optError := FALSE;
        i := 1;
        MakePascalString('Open What Link File?',MPrompt);
        List[1] := 'LNK ';
        (* Because the compiler is not consistant with the
         * file type this is not used!!
         *)
        SFGetFile(100,100,MPrompt,ADDRESS(0),0,List,ADDRESS(0),REPLY);
        Terminal.ClearTerminal;
        IF (REPLY.good) THEN
            MakeModulaString(REPLY.fName,FileName);
            Open(LinkStream,FileName,TRUE,found);
            IF found THEN
                i := 0;
                WHILE (FileName[i] # 0C) AND (FileName[i] # '.') DO
                    INC(i)
                END;
                FileName[i+1] := 'D';
                FileName[i+2] := 'E';
                FileName[i+3] := 'C';
                FileName[i+4] := 0C;
                Create(decStream, FileName, found);
                IF NOT found THEN
                    Terminal.WriteString(' ---- file not created');
                    Terminal.WriteLn
                END
            ELSE
                Terminal.WriteString(FileName);
                Terminal.WriteString(' ---- file not found');
                Terminal.WriteLn
            END
        ELSE
            Terminal.WriteString(' ---- filename required on command line');
            Terminal.WriteLn
        END
    END StartIO;
    
    PROCEDURE EndIO;
    VAR
        Done:   BOOLEAN;
    BEGIN
        Close(decStream,Done);
        Close(LinkStream,Done);
    END EndIO;
    
    PROCEDURE TabTo(col:CARDINAL);
    BEGIN
        IF (Column < col) THEN
            WriteBlanks(col - Column)
        END
    END TabTo;
    
    PROCEDURE Read(VAR w: WORD);
    BEGIN
        ReadWord(LinkStream,w);
        (*$T-*) INC(checksum,CARDINAL(w)); (*$T=*)
    END Read;
    
    PROCEDURE ReadBlock(a:ADDRESS; length:CARDINAL);
    VAR
        i:      CARDINAL;
        w:      WORD;
        a1:     ADDRESS;
    BEGIN
        FOR i := 0 TO (length - 2) BY 2 DO
            Read(w);
            a1 := (a + ADDRESS(i));
            a1^ := w
        END
    END ReadBlock;
    PROCEDURE Write(ch: CHAR);
    BEGIN
        WriteChar(decStream,ch);
        INC(Column);
        IF Column >= 80 THEN
            WriteLn
        END
    END Write;
    
    PROCEDURE WriteLn;
    BEGIN
        WriteChar(decStream,eolc);
        Column := 0
    END WriteLn;
    
    PROCEDURE WriteString(VAR str: ARRAY OF CHAR);
        VAR k: CARDINAL;
    BEGIN
        k := 0;
        WHILE (k <= HIGH(str)) AND (str[k] <> 0C) DO
            Write(str[k]); INC(k)
        END;
    END WriteString;
    
    PROCEDURE WriteBlanks(n: INTEGER);
    BEGIN
        WHILE n > 0 DO
            DEC(n);
            Write(' ')
        END
    END WriteBlanks;
    
    PROCEDURE WriteHex(x: CARDINAL; l: INTEGER);
    VAR
        String: ARRAY [0..16] OF CHAR;
    BEGIN
        Conversions.ConvertHex(x,l,String);
        WriteString(String);
        IF Column >= 80 THEN WriteLn END;
    END WriteHex;
    
    PROCEDURE WriteHexAdr(x: ADDRESS; l: INTEGER);
    VAR
        String: ARRAY [0..16] OF CHAR;
    BEGIN
        Conversions.ConvertAddrHex(x,l,String);
        WriteString(String);
        IF Column >= 80 THEN WriteLn END;
    END WriteHexAdr;
    
    PROCEDURE WriteCard(x: CARDINAL; l: INTEGER);
    VAR
        String: ARRAY [0..16] OF CHAR;
    BEGIN
        Conversions.ConvertCardinal(x,l,String);
        WriteString(String);
        IF Column >= 80 THEN WriteLn END;
    END WriteCard;
    
    PROCEDURE WriteInt(x,l: INTEGER);
    VAR
        String: ARRAY [0..16] OF CHAR;
    BEGIN
        Conversions.ConvertInteger(x,l,String);
        WriteString(String);
        IF Column >= 80 THEN WriteLn END;
    END WriteInt;
    
    PROCEDURE WriteDigit(x: CARDINAL);
    BEGIN
        Write(CHR(x + 60B));
        IF Column >= 80 THEN WriteLn END;
    END WriteDigit;

BEGIN
    checksum := 0
END DecIO.

!Funky!Stuff!
echo x - DecLink.MOD
cat >DecLink.MOD <<'!Funky!Stuff!'
(*****************************************
*                                        *
*    The Following Code is Derived from  *
*    A Hardcopy printout of              *
******************************************
*           D E C O D E                  *
*                                        *
*    for PDP11 MODULA-2 compiler.        *
*                                        *
*    Decodes MODULA-2 Load files         *
*    (extension .LOD).                   *
*                                        *
*    Version of 19.03.80                 *
*    Unix version 19.05.81               *
*                                        *
*    Institut fuer Informatik            *
*    ETH-Zentrum                         *
*    CH-8092 Zuerich                     *
*                                        *
*    Derived from DECODE for MODULA-2    *
*    link files (extension .LNK).        *
******************************************
*    Details of the link file were       *
*    Derived from a Hardcopy of the      *
*    Code for Pass Five of the PDP-11    *
*    Modula-2 Compiler                   *
******************************************
*    This code is                        *
*    Version of 09/10/85                 *
*****************************************)
MODULE DecLink;
    IMPORT SYSTEM;
    IMPORT DecIO;
    IMPORT M2Files,Terminal,QuickDraw,PascalStrings;
    FROM DecIO IMPORT StartIO,EndIO;
    IMPORT Storage;
    IMPORT Disasm;
    
    MODULE Binary;
        FROM DecIO IMPORT
            Read,Write,WriteHex,WriteBlanks,WriteString,WriteLn;
        FROM SYSTEM IMPORT ADDRESS;
        EXPORT NoDecode,StringDecode;
        
        PROCEDURE LineHeader(ic,Linkpoint: CARDINAL);
        BEGIN
            WriteHex(ic,4);
            IF Linkpoint <> 0 THEN
                Write(':');
                WriteHex(Linkpoint + ic,4)
            ELSE
                WriteBlanks(5)
            END
        END LineHeader;
        
        PROCEDURE NoDecode(Linkpoint,maxbyte: CARDINAL);
            VAR
                ic,printed,w: CARDINAL;
        BEGIN
            WriteString('NO DECODE -------- ');
            WriteString('DATA');
            ic := 0;
            printed := 16;
            WHILE ic < maxbyte DO
                IF printed = 16 THEN
                    printed := 0;
                    WriteLn;
                    LineHeader(ic,Linkpoint);
                    Write(' ')
                END;
                Read(w);
                WriteHex(w,5);
                INC(ic,2);
                INC(printed)
            END;
            WriteLn;
        END NoDecode;

        PROCEDURE WriteAsChar(w:CARDINAL);
            VAR
                c1,c2:  CHAR;
        BEGIN
            c1 := CHR(w DIV 400B);
            IF c1 # 0C THEN
                Write(c1)
            ELSE
                Write('.')
            END;
            c2 := CHR(w MOD 400B);
            IF c2 <> 0C THEN
                Write(c2)
            ELSE
                Write('.')
            END
        END WriteAsChar;
        
        PROCEDURE StringDecode(Linkpoint,maxbyte: CARDINAL);
            VAR
                ic,printed,w: CARDINAL;
        BEGIN
            WriteString('STRING DECODE -------- ');
            WriteString('CONSTANTS');
            ic := 0;
            printed := 32;
            WHILE ic < maxbyte DO
                IF printed = 32 THEN
                    printed := 0;
                    WriteLn;
                    LineHeader(ic,Linkpoint);
                    Write(' ')
                END;
                Read(w);
                WriteAsChar(w);
                INC(ic,2);
                INC(printed)
            END;
            WriteLn;
        END StringDecode;
        
    END Binary;
    
    MODULE DecodeLinkFormat;
        FROM SYSTEM IMPORT ADDRESS;
        IMPORT Terminal,NoDecode,StringDecode;
        FROM M2Files IMPORT EndFile;
        FROM DecIO IMPORT checksum,printChecksum,ErrorMessage,
                Read,ReadBlock,Write,WriteLn,WriteString,
                WriteBlanks,LinkStream,
                WriteHex,WriteHexAdr,WriteCard,
                WriteInt,WriteDigit,TabTo;
        FROM Disasm IMPORT Disassemble,ReadCount;
        FROM Storage IMPORT ALLOCATE,DEALLOCATE;

        EXPORT InitFlagNames,LinkDecoder;
        
        TYPE FlagType =
                (SCModHeader,ImportElement,DataSize,FilledData,
                 ProcCode,InitCode,SCModInitCode,ExcpCode (**),
                 RefOwnData,RefExtData,RefOwnCode(**),
                 RefOwnProcCall,RefExtProcCall,
                 RefOwnProcAss,RefExtProcAss,
                 RefOwnExcp (**),RefExtExcp(**),RefExtInitCall,
                 SCModEnd,LinkCodeVersion,
                 (*extension used by compiler only:*)
                 RefAnyProcCall,RefAnyProcAss,
                 (* New 68000 Flags *)
                 StringData,Sym17,
                 RefStrData,Sym19,RefSysProcCall
                 );
        (**) (* Directives marked with such an empty comment 
                are not output of the compiler up to now.*)
        
        CONST modnamlength = 24;
        
        VAR flagName:   ARRAY FlagType,[0..32] OF CHAR;
        
        PROCEDURE GetWriteModuleName;
            VAR k,l:    CARDINAL;
                ch: CHAR;
                print:  BOOLEAN;
        BEGIN
            l := 0;
            print := TRUE;
            REPEAT
                Read(k);
                INC(l);
                IF print THEN
                    ch := CHR(k DIV 400B);
                    IF ch # 0C THEN
                        Write(ch)
                    ELSE
                        print := FALSE
                    END
                END;
                IF print THEN
                    ch := CHR(k MOD 400B);
                    IF ch <> 0C THEN
                        Write(ch)
                    ELSE
                        print := FALSE
                    END
                END;
            UNTIL l >= modnamlength DIV 2;
        END GetWriteModuleName;
        
        PROCEDURE GetWriteHex(VAR k: CARDINAL);
        BEGIN
            Read(k);
            WriteHex(k,5);
        END GetWriteHex;
        
        PROCEDURE GetWriteAddress(VAR x: ADDRESS);
            VAR k:RECORD
                    CASE INTEGER OF
                    0: a:   ADDRESS
                    | 1: w: ARRAY [0..1] OF CARDINAL;
                    END
                END;
        BEGIN
            Read(k.w[0]);
            Read(k.w[1]);
            WriteHexAdr(k.a,9);
            x := k.a
        END GetWriteAddress;
        
        PROCEDURE GetWriteLength(VAR length: CARDINAL);
        BEGIN
            Read(length);
            WriteString(', number of bytes = ');
            WriteCard(length,0);
        END GetWriteLength;
        
        PROCEDURE GetWriteChecksum;
            VAR savechecksum,lchecksum: CARDINAL;
        BEGIN
            savechecksum := checksum;
            Read(lchecksum);
(*
 *          WriteString(' checksum:');
 *          IF printChecksum THEN
 *              WriteHex(lchecksum,5);
 *          END;
 *)
            IF savechecksum # lchecksum THEN
                WriteString(' checksum:');
                IF printChecksum THEN
                    WriteHex(lchecksum,5);
                END;
                WriteString(' ----- error -----');
                IF printChecksum THEN
                    WriteHex(savechecksum,5)
                END;
                WriteLn
            END;
            checksum := savechecksum
        END GetWriteChecksum;
        
        PROCEDURE InitFlagNames;
        BEGIN
            flagName[SCModHeader]           := 'Module Header';
            flagName[ImportElement]         := 'Import';
            flagName[DataSize]              := 'Data Size';
            flagName[FilledData]            := 'Filled Data';
            flagName[ProcCode]              := 'Procedure Code';
            flagName[InitCode]              := 'Init Code';
            flagName[SCModInitCode]         := 'Init Code For Module';
            flagName[ExcpCode]              := 'Unused ExcpCode';
            flagName[RefOwnData]            := 'Own Data';
            flagName[RefExtData]            := 'Extern Data';
            flagName[RefOwnCode]            := 'Own Code';
            flagName[RefOwnProcCall]        := 'Own Proc Call';
            flagName[RefExtProcCall]        := 'Extern Proc Call';
            flagName[RefOwnProcAss]         := 'Own Proc Ass';
            flagName[RefExtProcAss]         := 'Extern Proc Ass';
            flagName[RefOwnExcp]            := 'Own Excp';
            flagName[RefExtExcp]            := 'Extern Excp';
            flagName[RefExtInitCall]        := 'Extern Init Call';
            flagName[SCModEnd]              := 'SC Module End';
            flagName[LinkCodeVersion]       := 'Link Code Version';
            flagName[RefAnyProcCall]        := 'Any Proc Call';
            flagName[RefAnyProcAss]         := 'Any Proc Ass';
            flagName[StringData]            := 'StringData';
            flagName[Sym17]                 := 'Unknown Sym 17';
            flagName[RefStrData]            := 'String Data';
            flagName[Sym19]                 := 'Unknown Sym 19';
            flagName[RefSysProcCall]        := 'System Proc Call'
        END InitFlagNames;
        
        TYPE
            JumpTable = RECORD
                Addr,Len,Link:  CARDINAL
            END;
        
        VAR
            DataBlock:      ADDRESS;
            HasBlock:       BOOLEAN;
            Current,Length: CARDINAL;
            JumpTables:     ARRAY [0..14] OF JumpTable;
            NumJumpTables:  CARDINAL;
        
        PROCEDURE AddJumpTable(address,length,linkpoint:CARDINAL);
        VAR
            I,J:        CARDINAL;
            
        BEGIN
            WITH JumpTables[NumJumpTables] DO
                Addr    := address;
                Len     := length;
                Link    := linkpoint;
                INC(NumJumpTables)
            END
        END AddJumpTable;
        
        PROCEDURE DecodeJumpTable(j:JumpTable);
        VAR
            a:  ADDRESS;
            i:  CARDINAL;
            v:  CARDINAL;
        BEGIN
            WriteString("JumpTable");
            WriteLn;
            FOR i := 0 TO j.Len DO (* Len + 1 == Default case *)
                a := DataBlock + ADDRESS((i * 2) + j.Addr);
                v := CARDINAL(a^);
                TabTo(18);
                WriteHex(v,4);
                WriteString(' {');
                WriteHex(v + j.Link,4);
                Write('}');
                WriteLn;
            END;
            Current := j.Addr + (j.Len * 2) + 2; (* 2 for 0 case *)
        END DecodeJumpTable;
        
        PROCEDURE DecodeTo(LinkPoint:CARDINAL);
        VAR
            I:  CARDINAL;
            a:  ADDRESS;
        BEGIN
            IF LinkPoint >= Length THEN RETURN END;
            IF NumJumpTables > 0 THEN
                FOR I := NumJumpTables -1 TO 0 BY -1 DO
                    WITH JumpTables[I] DO
                        IF Addr < LinkPoint THEN
                            a := DataBlock + ADDRESS(Current);
                            Disassemble(a,Current,Addr - Current);
                            DecodeJumpTable(JumpTables[I]);
                            DEC(NumJumpTables)
                        END
                    END
                END
            END;
            a := DataBlock + ADDRESS(Current);
            Disassemble(a,Current,LinkPoint - Current + 2);
            Current := Current + ReadCount
        END DecodeTo;
        
        PROCEDURE DecodeCase(LinkPoint:CARDINAL);
        VAR
            a:  ADDRESS;
            v,len:  CARDINAL;
        BEGIN
            DecodeTo(LinkPoint + 2);
            TabTo(9);
            WriteString('SYSTEM CALL CASE');
            WriteLn;
            WriteString('Min Value: ');
            a := DataBlock + ADDRESS(LinkPoint + 4);
            v := CARDINAL(a^);
            WriteHex(v,4);
            a := DataBlock + ADDRESS(LinkPoint + 6);
            v := CARDINAL(a^);
            WriteHex(v,4);
            WriteString(' Number of Cases: ');
            a := DataBlock + ADDRESS(LinkPoint + 8);
            len := CARDINAL(a^);
            WriteHex(len,4);
            a := DataBlock + ADDRESS(LinkPoint + 10);
            len := CARDINAL(a^);
            WriteHex(len,4);
            WriteString(" Jump Table Offset: ");
            a := DataBlock + ADDRESS(LinkPoint + 12);
            v := CARDINAL(a^);
            WriteHex(v,4);
            a := DataBlock + ADDRESS(LinkPoint + 14);
            v := CARDINAL(a^);
            WriteHex(v,4);
            Current := Current + 12;
            AddJumpTable(LinkPoint + 4 + v,len,LinkPoint + 4)
        END DecodeCase;         
        
        PROCEDURE LinkDecoder;
            VAR
                flag:       FlagType;
                k,i:    CARDINAL;
                savechecksum,lchecksum: CARDINAL;
                ok:         BOOLEAN;
        
        BEGIN
            WriteString('Link key = ');
            GetWriteHex(k);
            WriteString(', LinkCodeKey & LinkFileKey = ');
            GetWriteHex(k);
            WriteLn;
            GetWriteChecksum;
            ok  := TRUE;
            HasBlock := FALSE;
            NumJumpTables   := 0;
            LOOP
                IF NOT ok THEN EXIT END;
                Read(k);
                IF EndFile(LinkStream) THEN EXIT END;
                WriteLn;
                IF k <= ORD(RefSysProcCall) THEN
                    flag := VAL(FlagType,k);
                    Terminal.WriteString(flagName[flag]);
                    Terminal.WriteLn;
                    CASE flag OF
                    SCModHeader:
                        WriteString(flagName[flag]);
                        WriteString(' : ');
                        GetWriteModuleName;
                        WriteLn;
                        WriteString('key = ');
                        GetWriteHex(k);
                        GetWriteHex(k);
                        GetWriteHex(k);
                    | ImportElement:
                        WriteString(flagName[flag]);
                        WriteString(' : ');
                        GetWriteModuleName;
                        WriteString(', Key = ');
                        GetWriteHex(k);
                        GetWriteHex(k);
                        GetWriteHex(k);
                        WriteString(', Module Number = ');
                        GetWriteHex(k);
                    | DataSize:
                        WriteString(flagName[flag]);
                        WriteString(' : ');
                        GetWriteHex(k);
                    | FilledData:
                        WriteString(flagName[flag]);
                        WriteString(' Relative Start Address = ');
                        GetWriteHex(k);
                        GetWriteLength(Length);
                        WriteLn;
                        NoDecode(k,Length)
                    | ProcCode, InitCode, SCModInitCode,SCModEnd:
                        IF HasBlock THEN
                            DecodeTo(Length - 2);
                            DEALLOCATE(DataBlock,Length)
                        END;
                        IF flag = SCModEnd THEN
                            RETURN
                        END;
                        WriteLn;
                        WriteString(flagName[flag]);
                        WriteString(' Proc # ');
                        Read(k);
                        WriteCard(k,0);
                        WriteLn;
                        WriteString(' Entry Point ');
                        GetWriteHex(k);
                        IF flag = SCModInitCode THEN
                            WriteString(' First Code (after Init) ');
                            GetWriteHex(i)
                        END;
                        GetWriteLength(Length);
                        ALLOCATE(DataBlock,Length);
                        ReadBlock(DataBlock,Length);
                        HasBlock := TRUE;
                        Current := 0;
                    | ExcpCode:
                        WriteString(flagName[flag]);
                        WriteString(' Found ExcpCode Error');
                        ok := FALSE
                    | RefOwnData, RefStrData:
                        Read(k);
                        DecodeTo(k + 2);
                        TabTo(9);
                        WriteString(flagName[flag]);
                    | RefExtData:
                        Read(k);
                        DecodeTo(k + 2);
                        TabTo(9);
                        WriteString(flagName[flag]);
                        WriteString(' Module # ');
                        Read(k);
                        WriteCard(k,0)
                    | RefOwnCode:
                        WriteString(flagName[flag]);
                        WriteString('Error Found RefOwnCode');
                        ok := FALSE
                    | RefOwnProcCall,RefOwnProcAss:
                        Read(k);
                        DecodeTo(k + 2);
                        TabTo(9);
                        WriteString(flagName[flag]);
                        WriteString(' Proc # ');
                        Read(k);
                        WriteCard(k,0)
                    | RefExtProcCall,RefExtProcAss:
                        Read(k);
                        DecodeTo(k + 2);
                        TabTo(9);
                        WriteString(flagName[flag]);
                        WriteString(' Proc # ');
                        Read(k);
                        WriteCard(k,0);
                        WriteString(' Module # ');
                        Read(k);
                        WriteCard(k,0)
                    | RefOwnExcp,RefExtExcp:
                        WriteString(flagName[flag]);
                        WriteString(' Error');
                        ok := FALSE
                    | RefExtInitCall:
                        Read(k);
                        DecodeTo(k + 2);
                        TabTo(9);
                        WriteString(flagName[flag]);
                    | LinkCodeVersion:
                        WriteString(flagName[flag]);
                        WriteString(" I don't know why it's just here.");
                        WriteLn
                    | StringData:
                        WriteString(flagName[flag]);
                        GetWriteLength(Length);
                        WriteLn;
                        StringDecode(0,Length)                      
                    | Sym17,Sym19:
                        WriteString(flagName[flag]);
                        IF EndFile(LinkStream) THEN 
                            ok := FALSE;
                            EXIT
                        END;
                        REPEAT
                            savechecksum := checksum;
                            Read(lchecksum);
                            IF EndFile(LinkStream) THEN 
                                ok := FALSE;
                            END;
                            IF savechecksum # lchecksum THEN
                                WriteHex(lchecksum,5)
                            END;
                        UNTIL (ok = FALSE) OR (savechecksum = lchecksum);
                        checksum := savechecksum
                    | RefSysProcCall:
                        Read(k);
                        Read(i);
                        IF i = 1 THEN (* SYSTEM CODE IS CASE *);
                            DecodeCase(k);
                        ELSE
                            DecodeTo(k + 2);
                            TabTo(9);
                            WriteString(flagName[flag]);
                            WriteString(' Proc # ');
                            WriteCard(i,0); 
                        END 
                    END (*CASE*);
                    GetWriteChecksum;
                ELSE
                    Terminal.WriteString('Found Unknown Key ');
                    Terminal.WriteLn;
                    WriteString('Found Key ');
                    WriteHex(k,5);
                    IF EndFile(LinkStream) THEN 
                        ok := FALSE;
                        EXIT
                    END;
                    REPEAT
                        savechecksum := checksum;
                        Read(lchecksum);
                        IF EndFile(LinkStream) THEN 
                            ok := FALSE;
                        END;
                        IF savechecksum # lchecksum THEN
                            WriteHex(lchecksum,5)
                        END;
                    UNTIL (ok = FALSE) OR (savechecksum = lchecksum);
                    checksum := savechecksum;
                END;
            END (*LOOP*);
            IF NOT ok THEN
                Terminal.WriteString('---- wrong format');
                Terminal.WriteLn;
                WriteString('---- wrong format');
                WriteLn;
            END
        END LinkDecoder;
        
    END DecodeLinkFormat;
    
VAR found: BOOLEAN;

BEGIN (*DecLink*)
    StartIO(found);
    IF found THEN
        InitFlagNames;
        LinkDecoder;
        EndIO;
    END
END DecLink.

!Funky!Stuff!
echo x - Disasm.MOD
cat >Disasm.MOD <<'!Funky!Stuff!'
(*
 * The Following Code is Free to any one who cares to use it, provided
 * that they are willing to pass it on to any one else who wishes it.
 *
 * Bob Campbell, Kirkland Wa (uw-beaver!tikal!bobc).
 *
 * The code that follows is a crude implementation of a Motorola 68000 
 * Disassembler, it can disassemble illegal op codes mostly with respect
 * to addressing modes which are not valid.  (MOVE.B #'a',A0 etc).
 *
 * The code breaks the instruction up into line codes (as in "LINE 1010"
 * or in mac terms "A-LINE" Trap).  This is done based on the first
 * nibble there are then routines for Line0,Line4-Line9,LineB-LineE.
 * Line1 Line2 and Line3 are move instructions and are handled by
 * DecMove, LineA and LineF are traps and are printed out as such
 * in the main routine.
 *
 * Version of 09/10/85
 *
 *)
IMPLEMENTATION MODULE Disasm;

    FROM SYSTEM IMPORT WORD,ASH,ADDRESS;
    IMPORT DecIO;
    IMPORT Terminal,OutTerminal;
    FROM DecIO IMPORT Write,WriteLn,WriteString,
        WriteHex,WriteInt,WriteCard,TabTo;
(*
 *  EXPORT QUALIFIED Disassemble;
 *) 
    VAR (* ReadCount:CARDINAL; for Telling when done *)
        WordsUsed: ARRAY[0..15] OF CARDINAL;
        WordCount,LoadOffset: CARDINAL;
        DataPointer: ADDRESS;
    
(*
 * Read a Word and save the value in WordsUsed (until printed).
 *)
    PROCEDURE Read(VAR I:WORD);
    BEGIN
        ReadCount := ReadCount + 2;
        I := DataPointer^;
        INC(DataPointer,2);
        WordsUsed[WordCount] := CARDINAL(I);
        INC(WordCount)
    END Read;

(*
 *  Write Effective Address
 *  The parameter IsLong is only used for mode 7 register 4.
 *)
    PROCEDURE WriteEA(Mode,Reg:CARDINAL;IsLong:BOOLEAN);
    VAR
        Data,Index,Disp:CARDINAL;
        LongIndex,AddressReg: BOOLEAN;
    BEGIN
        CASE Mode OF
        0:                      (* Dn *)
            Write('D');
            WriteCard(Reg,0)
        | 1:                    (* An *)
            Write('A');
            WriteCard(Reg,0)
        | 2:                    (* (An) *)
            WriteString('(A');
            WriteCard(Reg,0);
            Write(')')
        | 3:                    (* (An)+ *)
            WriteString('(A');
            WriteCard(Reg,0);
            WriteString(')+')
        | 4:                    (* -(An) *)
            WriteString('-(A');
            WriteCard(Reg,0);
            Write(')')
        | 5:                    (* d(An) *)
            Read(Data);
            WriteHex(Data,4);
            WriteString('(A');
            WriteCard(Reg,0);
            Write(')')
        | 6:                    (* d(An,Xi) *)
            Read(Data);
            Index := ASH(Data,-12) MOD 8;
            AddressReg := (15 IN BITSET(Data));
            LongIndex := (11 IN BITSET(Data));
            Disp := Data MOD 256;
            WriteHex(Disp,2);
            WriteString('(A');
            WriteCard(Reg,0);
            IF AddressReg THEN
                WriteString(',A')
            ELSE
                WriteString(',D')
            END (*IF*);
            WriteCard(Index,0);
            IF LongIndex THEN
                WriteString('.W)')
            ELSE
                WriteString('.L)')
            END
        | 7:
            CASE Reg OF
            0:                      (* Abs.W *)
                Read(Data);
                WriteHex(Data,4);
            | 1:                    (* Abs.L *)
                Read(Data);
                WriteHex(Data,4);
                Read(Data);
                WriteHex(Data,4);
            | 2:                    (* d(PC) *)
                Read(Data);
                WriteHex(Data,4);
                WriteString('(PC)');
                WriteString('    {');
                WriteHex(Data + ReadCount + LoadOffset - 2,4);
                Write('}')
            | 3:                    (* d(PC,Xi) *)
                Read(Data);
                Index := ASH(Data,-12) MOD 8;
                AddressReg := (15 IN BITSET(Data));
                LongIndex := (11 IN BITSET(Data));
                Disp := Data MOD 256;
                WriteHex(Disp,2);
                WriteString('(PC');
                IF AddressReg THEN
                    WriteString(',A')
                ELSE
                    WriteString(',D')
                END (*IF*);
                WriteCard(Index,0);
                IF LongIndex THEN
                    WriteString('.W)')
                ELSE
                    WriteString('.L)')
                END;
                WriteString('    {');
                WriteHex(Disp + ReadCount + LoadOffset - 2,4);
                WriteString('(Xi)}')
            | 4:                    (* #data *)
                Read(Data);
                Write('#');
                WriteHex(Data,4);
                IF IsLong THEN
                    Read(Data);
                    WriteHex(Data,4)
                END (*IF*)
            END (*CASE*)
        ELSE
            WriteCard(Mode,1);
        END (*CASE*)
    END WriteEA;

    PROCEDURE Write1EA(Mode1,Reg1:CARDINAL;Long:BOOLEAN);
    BEGIN
        TabTo(18);
        WriteEA(Mode1,Reg1,Long);
    END Write1EA;

    PROCEDURE Write2EA(Mode1,Reg1,Mode2,Reg2:CARDINAL;Long:BOOLEAN);
    BEGIN
        Write1EA(Mode1,Reg1,Long);
        Write(',');
        WriteEA(Mode2,Reg2,Long)
    END Write2EA;

    PROCEDURE WriteMnemonic(VAR Str:ARRAY OF CHAR; Length:CARDINAL);

    BEGIN
        WriteString(Str);
        CASE Length OF
        0:
            WriteString(".B")
        | 1:
            WriteString(".W")
        | 2:
            WriteString(".L")
        END (*CASE*)
    END WriteMnemonic;
    
    PROCEDURE WriteData(Inst:CARDINAL);
    
    BEGIN
        WriteString("DATA");
        TabTo(10);
        WriteHex(Inst,4)
    END WriteData;
    
    PROCEDURE WriteRegList(First,Last:CARDINAL;PreDec:BOOLEAN);
    VAR
        FirstRegNum,LastRegNum,RegType:CARDINAL;
        
    BEGIN
        IF PreDec THEN
            FirstRegNum := 15 - First;
            LastRegNum := 15 - Last
        ELSE
            FirstRegNum := First;
            LastRegNum := Last
        END;
        WriteEA(ASH(FirstRegNum,-3),FirstRegNum MOD 8,FALSE);
        IF (First # Last) THEN
            Write('-');
            WriteEA(ASH(LastRegNum,-3),LastRegNum MOD 8,FALSE);
        END
    END WriteRegList;
    
    PROCEDURE WriteRegMask(Mask:CARDINAL;PreDec:BOOLEAN);
    VAR
        Regs:BITSET;
        First,Last,I:CARDINAL;
        FoundOne,NeedComma:BOOLEAN;
    BEGIN
        Regs := BITSET(Mask);
        FoundOne := FALSE;
        NeedComma := FALSE;
        FOR I := 0 TO 15 DO
            IF I IN Regs THEN
                IF FoundOne THEN
                    Last := I
                ELSE
                    First := I;
                    Last := I;
                    FoundOne := TRUE
                END (*IF*)
            ELSE
                IF FoundOne THEN
                    IF NeedComma THEN Write(',') END;
                    WriteRegList(First,Last,PreDec);
                    FoundOne := FALSE;
                    NeedComma := TRUE
                END
            END
        END (*FOR*);
        IF FoundOne THEN
            IF NeedComma THEN Write(',') END;
            WriteRegList(First,Last,PreDec);
        END (*IF*)
    END WriteRegMask;
        
    
    PROCEDURE WriteCC(Cond:CARDINAL);
    
    BEGIN
        CASE Cond OF
        0:
            WriteString('T ')
        | 1:
            WriteString('F ')
        | 2:
            WriteString('HI')
        | 3:
            WriteString('LS')
        | 4:
            WriteString('CC')
        | 5:
            WriteString('CS')
        | 6:
            WriteString('NE')
        | 7:
            WriteString('EQ')
        | 8:
            WriteString('VC')
        | 9:
            WriteString('VS')
        | 0AH:
            WriteString('PI')
        | 0BH:
            WriteString('MI')
        | 0CH:
            WriteString('GE')
        | 0DH:
            WriteString('LT')
        | 0EH:
            WriteString('GT')
        | 0FH:
            WriteString('LE')
        END (*CASE*)
    END WriteCC;
    
    
    PROCEDURE Line0(Inst:CARDINAL);
    VAR
        Nibble,Size,Mode,Register,Data:CARDINAL;
    
    BEGIN
        Nibble  := ASH(Inst,-8) MOD 16;
        Size    := ASH(Inst,-6) MOD 4;
        Mode    := ASH(Inst,-3) MOD 8;
        Register:= Inst MOD 8;
        IF ODD(Nibble) THEN (* MOVEP or BIT *)
            IF (Mode = 1) THEN
                WriteMnemonic('MOVEP',(Size MOD 2) + 1);
                IF (Size = 0) OR (Size = 1) THEN
                    Write2EA(5,Register,0,Nibble DIV 2,FALSE)
                ELSE
                    Write2EA(0,Nibble DIV 2,5,Register,FALSE)
                END (* IF *)
            ELSIF (Mode = 7) AND (Register > 1) THEN
                WriteData(Inst);
            ELSE (* DYNAMIC BIT *)
                Write('B');
                CASE Size OF
                0:
                    WriteString('TST')
                | 1:
                    WriteString('CHG')
                | 2:
                    WriteString('CLR')
                | 3:
                    WriteString('SET')
                END (*CASE*);
                Write2EA(0,Nibble DIV 2,Mode,Register,FALSE)
            END
        ELSIF ((Nibble # 8) AND (Size = 3)) OR
        ((Mode = 7) AND (Register > 1)) THEN
            WriteData(Inst);
        ELSE
            CASE Nibble OF
            0:
                WriteMnemonic('ORI',Size)
            | 2:
                WriteMnemonic('ANDI',Size)
            | 4:
                WriteMnemonic('SUBI',Size)
            | 6:
                WriteMnemonic('ADDI',Size)
            | 8:
                Write('B');
                CASE Size OF
                0:
                    WriteString('TST')
                | 1:
                    WriteString('CHG')
                | 2:
                    WriteString('CLR')
                | 3:
                    WriteString('SET')
                END (*CASE*)
            | 10:
                WriteMnemonic('EORI',Size)
            | 12:
                WriteMnemonic('CMPI',Size)
            | 14:
                WriteMnemonic('MOVES',Size)
            END; (*CASE*)
            IF (Mode = 7) AND (Register = 4) THEN
                Write1EA(7,4,(Nibble # 8) AND (Size = 2));
                Write(',');
                IF Size = 0 THEN
                    WriteString('CCR')
                ELSIF Size = 1 THEN
                    WriteString('SR')
                ELSE
                    WriteString('BAD')
                END
            ELSE
                Write2EA(7,4,Mode,Register,(Nibble # 8) AND (Size = 2))
            END (*IF*)
        END (*IF*)
    END Line0;
    
    PROCEDURE DecMove(Inst:CARDINAL);
    VAR
        Size,DReg,SReg,DMode,SMode:CARDINAL;
    BEGIN
        Size    := ASH(Inst,-12);
        IF Size # 2 THEN
            Size := ASH(Size,-1)
        END;
        DReg    := ASH(Inst,-9) MOD 8;
        DMode   := ASH(Inst,-6) MOD 8;
        SMode   := ASH(Inst,-3) MOD 8;
        SReg    := Inst MOD 8;
        IF ((SMode = 7) AND (SReg > 4)) OR ((DMode = 7) AND (DReg > 1)) THEN
            WriteData(Inst)
        ELSE
            IF (DMode = 1) THEN
                WriteMnemonic('MOVEA',Size)
            ELSE
                WriteMnemonic('MOVE',Size)
            END (*IF*);
            Write2EA(SMode,SReg,DMode,DReg,Size = 2)
        END (*IF*)
    END DecMove;
    
    PROCEDURE Line4(Inst:CARDINAL);
    VAR
        Nibble1,Nibble2,Nibble3:CARDINAL;
        Size,Mode,Reg,Data:CARDINAL;
        
    BEGIN
        Nibble1 := ASH(Inst,-8) MOD 16;
        Nibble2 := ASH(Inst,-4) MOD 16;
        Nibble3 := Inst MOD 16;
        Size    := ASH(Nibble2,-2) MOD 4;
        Mode    := ASH(Inst,-3) MOD 8;
        Reg     := Inst MOD 8;
        IF Nibble1 = 0EH THEN
            CASE Nibble2 OF
            0,1,2,3:
                WriteData(Inst);
            | 4:
                WriteString('TRAP       ');
                WriteHex(Nibble3,1)
            | 5:
                IF Mode = 2 THEN
                    WriteString('LINK');
                    TabTo(18);
                    Write2EA(1,Reg,7,4,FALSE)
                ELSE
                    WriteString('UNLK      ');
                    TabTo(18);
                    Write1EA(1,Reg,FALSE)
                END
            | 6:
                IF Nibble3 = 0 THEN
                    WriteString('RESET')
                ELSE
                    WriteString('MOVE.L');
                    IF Mode = 4 THEN
                        Write1EA(1,Reg,TRUE);
                        WriteString(',USP')
                    ELSE
                        TabTo(18);
                        WriteString('USP,');
                        WriteEA(1,Reg,TRUE)
                    END (*IF*)
                END
            | 7:
                CASE Nibble3 OF
                1:
                    WriteString('NOP')
                | 2:
                    WriteString('STOP')
                | 3:
                    WriteString('RTE')
                | 4:
                    WriteString('RTD')
                | 5:
                    WriteString('RTS')
                | 6:
                    WriteString('TRAPV')
                | 7:
                    WriteString('RTR')
                | 8,9,0AH,0BH,0CH,0DH,0EH,0FH:
                    WriteData(Inst)
                END (* CASE *)
            | 8,9,10,11:
                WriteString('JSR');
                Write1EA(Mode,Reg,FALSE)
            ELSE (* 12 13 14 15 *)
                WriteString('JMP');
                Write1EA(Mode,Reg,FALSE)
            END (* CASE *);
        ELSIF Nibble1 = 8 THEN
            IF Nibble2 = 4 THEN
                WriteString('SWAP');
                Write1EA(0,Reg,FALSE)
            ELSIF Nibble2 = 8 THEN
                WriteString('EXT.W');
                Write1EA(0,Reg,FALSE)
            ELSIF Nibble2 = 0CH THEN
                WriteString('EXT.L');
                Write1EA(0,Reg,FALSE)
            ELSIF Size = 0 THEN
                WriteString('NBCD');
                Write1EA(Mode,Reg,FALSE)
            ELSIF Size = 1 THEN
                WriteString('PEA');
                Write1EA(Mode,Reg,FALSE)
            ELSE
                WriteMnemonic('MOVEM',Size - 1);
                TabTo(18);
                Read(Data);
                WriteRegMask(Data,Mode = 4);
                Write(',');
                WriteEA(Mode,Reg,Size = 3)
            END (*IF*)
        ELSIF Nibble1 = 0CH THEN
            IF Size < 2 THEN
                WriteData(Inst)
            ELSE
                WriteMnemonic('MOVEM',Size - 1);
                TabTo(18);
                Read(Data);
                WriteRegMask(Data,Mode = 4);
                Write(',');
                WriteEA(Mode,Reg,Size = 3)
            END (*IF*)
        ELSIF ODD(Nibble1) THEN
            IF (Size = 2) THEN
                WriteString('CHK');
                Write2EA(0,ASH(Nibble1,-1) MOD 8,Mode,Reg,FALSE)
            ELSIF Size = 3 THEN
                WriteString('LEA');
                Write2EA(1,ASH(Nibble1,-1) MOD 8,Mode,Reg,FALSE)
            ELSE
                WriteData(Inst)
            END (*IF*)
        ELSIF Size = 3 THEN
            CASE Nibble1 OF
            0:
                WriteString('MOVE.W    SR,');
                WriteEA(Mode,Reg,FALSE)
            | 2:
                WriteString('MOVE.W   CCR,');
                WriteEA(Mode,Reg,FALSE)
            | 4:
                WriteString('MOVE.W   ');
                WriteEA(Mode,Reg,FALSE);
                WriteString(',CCR')
            | 6:
                WriteString('MOVE.W   ');
                WriteEA(Mode,Reg,FALSE);
                WriteString(',SR')
            | 10:
                WriteString('TAS');
                Write1EA(Mode,Reg,FALSE)
            END (* CASE *)
        ELSE
            CASE Nibble1 OF
            0:
                WriteMnemonic('NEGX',Size)
            | 2:
                WriteMnemonic('CLR',Size)
            | 4:
                WriteMnemonic('NEG',Size)
            | 6:
                WriteMnemonic('NOT',Size)
            | 0AH:
                WriteMnemonic('TST',Size)
            END (*CASE*);
            Write1EA(Mode,Reg,Size = 2)
        END (* IF *)
    END Line4;
    
    PROCEDURE Line5(Inst:CARDINAL);
    
    VAR
        Nibble,Size,Mode,Reg,Data:CARDINAL;
    BEGIN
        Nibble  := ASH(Inst,-8) MOD 16;
        Size    := ASH(Inst,-6) MOD 4;
        Mode    := ASH(Inst,-3) MOD 8;
        Reg     := Inst MOD 8;
        IF Size = 3 THEN
            IF Mode = 1 THEN
                WriteString('DB');
                WriteCC(Nibble);
                Write1EA(0,Reg,FALSE);
                Write(',');
                Read(Data);
                WriteInt(INTEGER(Data),0);
                WriteString('    {');
                WriteHex(ReadCount + LoadOffset + Data - 2,4);
                Write('}')
            ELSE
                Write('S');
                WriteCC(Nibble);
                Write1EA(0,Reg,FALSE)
            END (*IF*)
        ELSE
            IF ODD(Nibble) THEN
                WriteMnemonic('SUBQ',Size)
            ELSE
                WriteMnemonic('ADDQ',Size)
            END (*IF*);
            TabTo(18);
            IF Nibble = 0 THEN
                WriteString('#8')
            ELSE
                Write('#');
                WriteHex(ASH(Nibble,-1),1)
            END (*IF*);
            Write(',');
            WriteEA(Mode,Reg,Size = 2)
        END (*IF*)
    END Line5;
    
    PROCEDURE Line6(Inst:CARDINAL);
    VAR
        Cond:CARDINAL;
        Disp:INTEGER;
    BEGIN
        Cond := ASH(Inst,-8) MOD 16;
        Disp := Inst MOD 100H;
        IF Disp = 0 THEN
            Read(Disp)
        ELSIF Disp > 07FH THEN
            Disp := INTEGER(BITSET(Disp) + BITSET(0FF00H))
        END;
        IF Cond = 0 THEN
            WriteString('BRA')
        ELSIF Cond = 1 THEN
            WriteString('BSR')
        ELSE
            Write('B');
            WriteCC(Cond)
        END (*IF*);
        TabTo(18);
        WriteInt(Disp,0);
        WriteString('    {');
        WriteHex(Disp + INTEGER(ReadCount + LoadOffset),4);
        Write('}')
    END Line6;
    
    PROCEDURE Line7(Inst:CARDINAL);
    VAR
        Reg:CARDINAL;
        Data:INTEGER;
    BEGIN
        IF 8 IN BITSET(Inst) THEN
            WriteData(Inst)
        ELSE
            WriteString('MOVEQ.L  #');
            Reg     := ASH(Inst,-9) MOD 8;
            Data    := Inst MOD 100H;
            IF Data > 07FH THEN
                Data := INTEGER(BITSET(Data) + BITSET(0FF00H))
            END;
            WriteHex(Data,4);
            Write(',');
            WriteEA(0,Reg,FALSE)
        END
    END Line7;
    
    PROCEDURE Line8(Inst:CARDINAL);
    VAR
        DReg,SReg,OMode,SMode:CARDINAL;
    BEGIN
        DReg    := ASH(Inst,-9) MOD 8;
        OMode   := ASH(Inst,-6) MOD 8;
        SMode   := ASH(Inst,-3) MOD 8;
        SReg    := Inst MOD 8;
        IF (OMode = 3) OR (OMode = 7) THEN
            IF (OMode = 3) THEN
                WriteString('DIVU.W')
            ELSE
                WriteString('DIVS.W')
            END;
            Write2EA(SMode,SReg,0,DReg,FALSE)
        ELSIF (OMode = 4) AND ((SMode = 0) OR (SMode = 1)) THEN
            WriteString('SBCD');
            IF SMode = 0 THEN
                Write2EA(0,SReg,0,DReg,FALSE)
            ELSE
                Write2EA(4,SReg,4,DReg,FALSE)
            END (*IF*)
        ELSE
            WriteMnemonic('OR.B',OMode MOD 4);
            IF (OMode < 4) THEN
                Write2EA(SMode,SReg,0,DReg,OMode = 2);
            ELSE
                Write2EA(0,DReg,SMode,SReg,OMode = 6)
            END
        END (*IF*)
    END Line8;
    
    PROCEDURE Line9(Inst:CARDINAL);
    VAR
        DReg,OMode,SReg,SMode:CARDINAL;
    BEGIN
        DReg    := ASH(Inst,-9) MOD 8;
        OMode   := ASH(Inst,-6) MOD 8;
        SMode   := ASH(Inst,-3) MOD 8;
        SReg    := Inst MOD 8;
        IF (SMode < 2) AND (OMode > 3) AND (OMode # 7) THEN
            WriteMnemonic('SUBX',OMode MOD 4);
            IF SMode = 0 THEN
                Write2EA(0,SReg,0,DReg,FALSE)
            ELSE
                Write2EA(4,SReg,4,DReg,FALSE)
            END (*IF*)
        ELSIF (OMode = 3) OR (OMode = 7) THEN
            WriteMnemonic('SUBA',(OMode DIV 2) - 1);
            Write2EA(SMode,SReg,1,DReg,OMode = 7)
        ELSE
            WriteMnemonic('SUB',OMode MOD 4);
            IF (OMode = 0) OR (OMode = 1) OR (OMode = 2) THEN
                Write2EA(SMode,SReg,0,DReg,OMode = 2)
            ELSE
                Write2EA(0,DReg,SMode,SReg,OMode = 6)
            END (*IF*)
        END (*IF*)
    END Line9;
    
    PROCEDURE LineB(Inst:CARDINAL);
    VAR
        DReg,OMode,SReg,SMode:CARDINAL;
    BEGIN
        DReg    := ASH(Inst,-9) MOD 8;
        OMode   := ASH(Inst,-6) MOD 8;
        SMode   := ASH(Inst,-3) MOD 8;
        SReg    := Inst MOD 8;
        IF (SMode = 1) AND (OMode > 3) AND (OMode # 7) THEN
            WriteMnemonic('CMPM',OMode MOD 4);
            Write2EA(4,SReg,4,DReg,FALSE);
        ELSIF (OMode = 3) OR (OMode = 7) THEN
            WriteMnemonic('CMPA',(OMode DIV 4) + 1);
            Write2EA(SMode,SReg,1,DReg,OMode = 7)
        ELSIF  OMode > 3 THEN
            WriteMnemonic('EOR',OMode MOD 4);
            Write2EA(0,DReg,SMode,SReg,OMode = 6)
        ELSE
            WriteMnemonic('CMP',OMode);
            Write2EA(SMode,SReg,0,DReg,OMode = 2)
        END (*IF*)
    END LineB;
    
    PROCEDURE LineC(Inst:CARDINAL);
    VAR
        DReg,OMode,SReg,SMode:CARDINAL;
    BEGIN
        DReg    := ASH(Inst,-9) MOD 8;
        OMode   := ASH(Inst,-6) MOD 8;
        SMode   := ASH(Inst,-3) MOD 8;
        SReg    := Inst MOD 8;
        IF ((OMode = 5) AND (SMode < 2)) OR
        ((OMode = 6) AND (SMode = 1)) THEN
            WriteString('EXG');
            IF OMode = 6 THEN
                Write2EA(0,DReg,1,SReg,FALSE)
            ELSIF (SMode = 0) THEN
                Write2EA(0,DReg,0,SReg,FALSE)
            ELSE
                Write2EA(1,DReg,1,SReg,FALSE)
            END (*IF*);
        ELSIF (OMode = 3) OR (OMode = 7) THEN
            IF (OMode = 3) THEN
                WriteString('MULU.W')
            ELSE
                WriteString('MULS.W')
            END;
            Write2EA(SMode,SReg,0,DReg,OMode = 7)
        ELSIF (OMode = 4) AND ((SMode = 0) OR (SMode = 1)) THEN
            WriteString('ABCD');
            IF SMode = 0 THEN
                Write2EA(0,SReg,0,DReg,FALSE)
            ELSE
                Write2EA(4,SReg,4,DReg,FALSE)
            END (*IF*)
        ELSE
            WriteMnemonic('AND',OMode MOD 4);
            IF (OMode < 4) THEN
                Write2EA(SMode,SReg,0,DReg,OMode = 2)
            ELSE
                Write2EA(0,DReg,SMode,SReg,OMode = 6)
            END
        END (*IF*)
    END LineC;
    
    PROCEDURE LineD(Inst:CARDINAL);
    VAR
        DReg,OMode,SReg,SMode:CARDINAL;
    BEGIN
        DReg    := ASH(Inst,-9) MOD 8;
        OMode   := ASH(Inst,-6) MOD 8;
        SMode   := ASH(Inst,-3) MOD 8;
        SReg    := Inst MOD 8;
        IF (SMode < 2) AND (OMode > 3) AND (OMode # 7) THEN
            WriteMnemonic('ADDX',OMode MOD 4);
            IF SMode = 0 THEN
                Write2EA(0,SReg,0,DReg,FALSE)
            ELSE
                Write2EA(4,SReg,4,DReg,FALSE)
            END (*IF*)
        ELSIF (OMode = 3) OR (OMode = 7) THEN
            WriteString('ADDA');
            IF (OMode = 3) THEN
                WriteString('.W   ')
            ELSE
                WriteString('.L   ')
            END;
            Write2EA(SMode,SReg,1,DReg,OMode = 7)
        ELSE
            WriteMnemonic('ADD',OMode MOD 4);
            IF (OMode = 0) OR (OMode = 1) OR (OMode = 2) THEN
                Write2EA(SMode,SReg,0,DReg,OMode = 2)
            ELSE
                Write2EA(0,DReg,SMode,SReg,OMode = 6)
            END (*IF*)
        END (*IF*)
    END LineD;

    PROCEDURE LineE(Inst:CARDINAL);
    VAR
        Count,Size,Type,Mode,Reg:CARDINAL;
        Left:BOOLEAN;
    BEGIN
        Size    := ASH(Inst,-6) MOD 4;
        Reg     := Inst MOD 8;
        Left    := (ASH(Inst,-8) MOD 2) = 1;
        IF Size = 3 THEN
            Type    := ASH(Inst,-9) MOD 4;
            Mode    := ASH(Inst,-3) MOD 8;
            CASE Type OF
            0:
                IF (Left) THEN
                    WriteString('ASL.W')
                ELSE
                    WriteString('ASR.W')
                END (*IF*)
            | 1:
                IF (Left) THEN
                    WriteString('LSL.W')
                ELSE
                    WriteString('LSR.W')
                END
            | 2:
                IF (Left) THEN
                    WriteString('ROXL.W')
                ELSE
                    WriteString('ROXR.W')
                END
            | 3:
                IF Left THEN
                    WriteString('ROL.W')
                ELSE
                    WriteString('ROR.W')
                END
            END (*CASE*);
            Write1EA(Mode,Reg,FALSE)
        ELSE
            Count   := ASH(Inst,-9) MOD 8;
            Size    := ASH(Inst,-6) MOD 4;
            Type    := ASH(Inst,-3) MOD 4;
            CASE Type OF
            0:
                IF (Left) THEN
                    WriteMnemonic('ASL',Size)
                ELSE
                    WriteMnemonic('ASR',Size)
                END (*IF*)
            | 1:
                IF (Left) THEN
                    WriteMnemonic('LSL',Size)
                ELSE
                    WriteMnemonic('LSR',Size)
                END
            | 2:
                IF (Left) THEN
                    WriteMnemonic('ROXL',Size)
                ELSE
                    WriteMnemonic('ROXR',Size)
                END
            | 3:
                IF Left THEN
                    WriteMnemonic('ROL',Size)
                ELSE
                    WriteMnemonic('ROR',Size)
                END
            END (*CASE*);
            IF (ASH(Inst,-5) MOD 2) = 1 THEN
                Write1EA(0,Count,FALSE)
            ELSE
                TabTo(18);
                IF Count = 0 THEN
                    WriteString('#8')
                ELSE
                    Write('#');
                    WriteHex(Count,1)
                END
            END;
            Write(',');
            WriteEA(0,Reg,FALSE)
        END (*IF*)
    END LineE;
    
PROCEDURE Disassemble(data:ADDRESS;loadpoint,maxbyte:CARDINAL);
VAR
    nibble,w:CARDINAL;
    i       :CARDINAL;
BEGIN
    ReadCount := 0;
    LoadOffset := loadpoint;
    DataPointer := data;
    WHILE (ReadCount < maxbyte) DO
        WordCount := 0;
        WriteHex(ReadCount + loadpoint,5);
        WriteString('    ');
        Read(w);
        nibble := ASH(w,-12) MOD 16;
        CASE nibble OF
        0:
            Line0(w)
        | 1,2,3:
            DecMove(w)
        | 4:
            Line4(w)
        | 5:
            Line5(w)
        | 6:
            Line6(w)
        | 7:
            Line7(w)
        | 8:
            Line8(w)
        | 9:
            Line9(w)
        | 0AH:
            WriteString('A-LINE');
            TabTo(18);
            WriteHex(w,4)
        | 0BH:
            LineB(w)
        | 0CH:
            LineC(w)
        | 0DH:
            LineD(w)
        | 0EH:
            LineE(w)
        | 0FH:
            WriteString('F-LINE');
            TabTo(18);
            WriteHex(w,4)
        END (*CASE*);
        TabTo(40);
        Write(11C); (* write a tab *);
        FOR i := 0 TO WordCount - 1 DO
            WriteHex(WordsUsed[i],5)
        END;
        WriteLn
    END (*WHILE*)
END Disassemble;
                
END Disasm.

!Funky!Stuff!