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!