title 'DISZ80 disassembler Z80 mnemonics' ;----------------------------------------------------------------; ; Author: D. Powys-Lybbe ; Written: Summer 1984 (modified DIS.ASM) ; Revisions: ; Nov 1984 - various corrections ; ;----------------------------------------------------------------; ; Module 01 - Program ;----------------------------------------------------------------; page public cpm,pass1,pass1a,pass2,pass3 extrn sets ; 1st op byte types extrn set$cb ; 0CBH double op byte types extrn sets$dd ; 0DDH double op byte types and mnemonics extrn sets$ed ; 0EDH double op byte types and mnemonics extrn sets$fd ; 0FDH double op byte types and mnemonics ;------ extrn nemon ; 1st op byte mnemonics ;------ extrn nemon$cb ; 0CBH double op byte mnemonics extrn set$ddcb ; 0DDH,0CBH triple op byte types and mnemonics extrn set$fdcb ; 0FDH,0CBH triple op byte types and mnemonics extrn progend ; end of program ;----------- start of program -------------------- cseg CPM EQU $ LXI d,DIS push d ret DB CR,LF DB ' PROGRAM DIS to disassemble Z80 programs',CR,LF DB ' using Zilog Mnemonics',CR,LF DB ' (c) COPYRIGHT D. POWYS-LYBBE 06 FEB 1984',CR,LF DB ' MML Systems Ltd., 11 SUN STREET, LONDON. E.C.2.',CR,LF DB CR,LF DB ' Program reads .COM file and forms a .M80 and .MAP file' DB CR,LF,CR,LF,1ah lenid equ $-cpm if lenid lt 256 ; minimum size for stack ds 256-lenid endif stack equ $ ; stack overwrites copyright message ;------------; ; File types ; ;------------; t$m80: db 'M80' t$map: db 'MAP' t$com: db 'COM' t$tmp: db '$$$' t$bak: db 'BAK' CR EQU 0DH LF EQU 0AH TAB EQU 09H ;--------------; ; BDOS equates ; ;--------------; BDOS EQU 0005h dfcb EQU 005CH dmabuf EQU 0080H COUT EQU 2 CIN EQU 1 CSTAT EQU 11 CMSG EQU 9 FOPEN EQU 15 FCLOSE EQU 16 FDELETE EQU 19 FREAD EQU 20 FWRITE EQU 21 FCREATE EQU 22 FRENAME EQU 23 FDMA EQU 26 ; .8080 ; we are using 8080 codes ;======; ; MAIN ; ;======; DIS: LXI SP,stack ;Use local stack ; lxi h,CPM ; default load address shld load ; Default LOAD address of COM file lxi d,PROGEND ; must be actual end of program call sdehl ; = - shld OFSET ; OFSET to add to program address ; xchg lhld load ; load address dad d ; DMA address set to PROGEND SHLD dmaptr ; call opencom ; open file call readcom ; read file call pass1 ; build up symbol table ; call opentmp ; open .TMP output file call pass2 call done ; flush buffer and close file call makem80 ; and make into M80 file ; call openmap ; open file call pass3 call done ; flush buffer and close file ; jmp return ; and terminate OFSET: dw PROGEND ; OFSET to add/subtract to code load: dw cpm ; load start address of COM file START: dw PROGEND ; pointer to start of MAP table FREE: dw cpm ; absolute address of end of COM file + 1 dmaptr: dw cpm ; dma address COUNT: DS 1 ; bytes in output buffer DATA: DB 010H ; Next program location can be data NOSPACE: DB 'DIRECTORY FULL',0DH,0AH,'$' OLDFILE: DB 'OLD .M80 FILE',0DH,0AH,'$' msgp1: db cr,lf,'PASS 1',cr,lf,'$' msgp2: db cr,lf,'PASS 2',cr,lf,'$' msgp3: db cr,lf,'PASS 3',cr,lf,'$' ;------------------------------------; ; Check file exists and read file in ; ;------------------------------------; opencom: lxi h,t$com lxi d,dfcb+9 lxi b,3 call copy ; FCB set to COM type call zrofcb ; intialise FCB to zero ; LXI D,dfcb MVI C,FOPEN CALL BDOS ;OPEN FILE CPI 255 rnz ; -ok- LXI D,NOTFOUND MVI c,CMSG CALL BDOS JMP RETURN ;FILE NOT FOUND NOTFOUND: DB 'NEW .COM FILE',0DH,0AH,'$' readcom: LHLD dmaptr ; Get DMA address ; NXTBUF: ;READ NEXT BUFFER FROM DISK XCHG ; Copy DMA into MVI C,FDMA CALL BDOS ; Set DMA LXI D,dfcb MVI C,FREAD CALL BDOS ;READ RECORD ORA A ; Check if read beyondd last record rnz ; -at EOF- LHLD dmaptr ; Get DMA address lxi b,128 DAD B ; & increment by 128 bytes SHLD dmaptr JMP NXTBUF ;--------------------------; ; Rename output $$$ to M80 ; ;--------------------------; makem80: lxi h,t$bak lxi d,dfcb+9 lxi b,3 call copy ; FCB set to .BAK type call zrofcb ; intialise FCB to zero ; lxi d,dfcb mvi c,FDELETE call bdos ;DELETE .BAK file ; lxi h,dfcb lxi d,dfcb+16 lxi b,16 call copy ; 2nd 16 bytes of FCB set to .BAK ; lxi h,t$m80 lxi d,dfcb+9 lxi b,3 call copy ; FCB set to .M80 type lxi d,dfcb mvi c,FRENAME call bdos ;RENAME .M80 to .BAK ; lxi h,dfcb lxi d,dfcb+16 lxi b,16 call copy ; 2nd 16 bytes of FCB set to .M80 ; lxi h,t$tmp lxi d,dfcb+9 lxi b,3 call copy ; FCB set to .$$$ type lxi d,dfcb mvi c,FRENAME call bdos ;RENAME .$$$ to .M80 ret ;---------------------; ; Create new MAP file ; ;---------------------; openmap: lxi h,t$map lxi d,dfcb+9 lxi b,3 call copy ; FCB set to .MAP type jmp create ;-----------------------------; ; flush buffer and close file ; ;-----------------------------; DONE: MVI A,1AH ; ADD EOF CALL CHAR ABORT: LDA COUNT ORA A CNZ WRITE ; Write BUFFER to file CLOSE: LXI D,dfcb MVI C,FCLOSE jmp BDOS ;----------------; ; Return to BDOS ; ;----------------; RETURN: ;NORMAL RETURN mvi c,0 jmp bdos ; system reset (warm boot) page ;----------------------------------------------------------------- ; Each branch address is recorded in a table ; as a 3 Byte address ; Byte 1 - Type of branch ;CODE: 00 - END of table ; 01 - Unresolved JUMP or CALL to branch ; 03 - Undefined & Unresolved program branch ; 05 - Program continues ; 07 - CALL branch (unresolved) followed by data byte ; 09 - CALL branch (unresolved) followed by data word ; 0b - CALL branch (unresolved) followed by data string ; 80 - Branch point contains INSTRUCTION ; (All 01 types should end up as 80 type) ; 82 - Branch point contains undefined INSTRUCTION ; (All 03 types should end up as 82 type) ; 84 - Address contains INSTRUCTION without label ; (All 05 types should end up as 84 type) ; 86 - CALL branch followed by data byte ; 88 - CALL branch followed by data word ; 8a - CALL branch followed by data string ; ;DATA: 40 - Branch point contains DATA ; 48 - Branch point contains DATA ADDRESS ; 44 - Unresolved table of program jumps ; 4A - Resolved table of program jumps ; 4c - Unlabeled DATA ; 4e - Unlabeled DATA ADDRESS ; ; 20 - No reference to location ; (Previous instruction PCHL, JMP, RET or DW) ; 24 - Next unresolved entry in table of program jumps ; 2A - Next resolved entry in table of program jumps ; 10 - EQU address/value for single byte ; 18 - EQU address/value for two byte address ; 1A - EQU address/value for JMP or CALL outside program ; 08 - End of program ; ; Byte 2 & 3 - Address of branch or end ; ; NOTE ; The MAP contains the absolute address and NOT the OFSET address ; BIT 0 of BYTE 1 flags UNRESOLVED instruction ; HIGH NIBBLE = 1 FOR EQUATES ; HIGH NIBBLE = 2 FOR UNKNOWN PROGRAM ; HIGH NIBBLE = 4 FOR DATA ; HIGH NIBBLE = 8 FOR CODE ;--------------------------------------------------------------------------- INITMAP: LHLD dmaptr ; DMA points to first location after data SHLD START ; MAP to begin at this location XCHG ; This location is adjusted to absolute location lhld OFSET call sdehl ; = - SHLD FREE ; which is saved in FREE XCHG ; and held in MVI M,01H ; Set first location to unresolved instruction type INX H ; Set program start adress to CP/M start 0100H lda load ; load LOW address of COM file (default 0100h) MOV M,a INX H lda load+1 ; load HIGH address of COM file (default 0100h) MOV M,a INX H MVI M,08H ; A NULL entry is included to INX H ; allow EQU to be inserted MOV M,E ; after end of program INX H MOV M,D INX H MVI M,0 ; Table ends with a zero INX H MOV M,E ; Which is set to FREE location INX H MOV M,D RET setload: ; = load address (default 0100h) shld LOAD ; set load address lxi d,PROGEND call sdehl ; = - shld OFSET ; set OFSET value lhld START ; MAP to begin at this location XCHG ; This location is adjusted to absolute location lhld OFSET call sdehl ; = - SHLD FREE ; which is saved in FREE XCHG ; and held in ; Set program start adress to specified load address call setfst MVI M,03H ; Set first location to unresolved instruction type INX H lda load ; load LOW address of COM file (default 0100h) MOV M,a INX H lda load+1 ; load HIGH address of COM file (default 0100h) MOV M,a INX H ; Adjust program end address for change in start address call setlst INX H MOV M,e INX H MOV M,d INX H RET setfst: mov a,m ; search TABLE for first program entry point cpi 01h ; and assume this was the previous load address rz cpi 03h rz inx h inx h inx h jmp setfst setlst: mov a,m ; search TABLE for NULL entry point cpi 08h rz inx h inx h inx h jmp setlst ; ;Test if MAP input file exists and read its contents ; RDMAP: ; Read .MAP file if it exists lxi h,t$map LXI d,dfcb+9 ; FCB set to MAP type lxi b,3 call copy call zrofcb ; intialise FCB to zero LXI D,dfcb MVI C,FOPEN CALL BDOS ;OPEN FILE CPI 255 rz ; no file lxi h,-1 shld maprec mvi c,FDMA lxi d,dmabuf call bdos ; set DMA lxi d,getmsg CALL dsply ;--------------------------------------------------------; ; read .MAP file for previous symbol and direction table ; structure: ; 0000 /n/ name ; where: 0000 - hex address ; n - type L, P, B, W, T or S enclosed between slashes ; name - optional character name ; Note: if /L/ is used then it should be the first item ;--------------------------------------------------------; getmap: call getmline rnz ; -no- line lxi h,mline call getmadr rnz ; -bad- address xchg shld addopt xchg call getmtype rnz ; -bad- type sta defopt inr a jz getload ; special flag lxi d,addopt ; address lda defopt ; type mov b,a call insx ; add to table jmp getmap getload: lhld addopt ; LOAD address call setload ; set pointers for this load address jmp getmap mline: ds 20 ; should be enough getmsg: db cr,lf,'Entry points read from file .MAP$' maprec: dw 0 ; pointer to next character getmline: ; fetch next line lxi h,mline getml2: push h call getmchar pop h rnz ; no characters left mov m,a inx h cpi cr jnz getml2 call getmchar cpi lf ret ; return NZ if error getmrec: ; read next record lxi h,0 shld maprec lxi d,dfcb mvi c,FREAD call bdos ; read record ora a rnz ; at EOF getmchar: ; get next character lhld maprec mov d,h mov e,l inx hl shld maprec mov a,e cpi 128 jnc getmrec lxi h,dmabuf dad d mov a,m cpi 1ah ; ctrl-Z jz getmeof cmp a ret ; with CF=Z getmeof: ori 0ffh ret ; with CF=NZ getmadr: ; construct address mov a,m inx h cpi ' ' jz getmadr call unhex jc badmadr rlc rlc rlc rlc mov d,a mov a,m inx h call unhex jc badmadr ora d mov d,a mov a,m inx h call unhex jc badmadr rlc rlc rlc rlc mov e,a mov a,m inx h call unhex jc badmadr ora e mov e,a xra a ret badmadr: ori -1 ret getmtype: ; construct type mov a,m inx h cpi ' ' jz getmtype cpi '/' rnz mov b,m inx h mov a,m inx h cpi '/' rnz mov a,b cpi 'P' mvi a,03h rz ; Program entry point mov a,b cpi 'N' mvi a,40h rz ; DB entry point mov a,b cpi 'B' mvi a,40h rz ; DB entry point mov a,b cpi 'W' mvi a,48h rz ; DW entry point mov a,b cpi 'T' mvi a,44h rz ; Table of vectors entry point mov a,b cpi 'S' mvi a,0bh rz ; Subroutine expects string of data terminated by 0 mov a,b cpi 'L' mvi a,0ffh rz ; Load address (default 0100h) ret ; ADDOPT: DW 0000H DEFOPT: DB 003H NONHEX: DB '?',CR,'$' addhelp: db cr,lf db ' The dis-assembly may be controlled by predefining the activity' db cr,lf db ' at an address using one or more of the following commands:' db cr,lf db cr,lf db ' L0000 - Program load address in HEX' db cr,lf db ' 0000 - Program entry point in HEX' db cr,lf db ' P0000 - Program entry point in HEX' db cr,lf db ' B0000 - Byte wide data entry point in HEX' db cr,lf db ' W0000 - Word wide data entry point in HEX' db cr,lf db ' S0000 - String follows call to this subroutine entry point in HEX' db cr,lf db ' T0000 - Table of pointers entry point in HEX' db cr,lf db '$' ENTRY: DB CR,LF,'Add entry point (0000 to quit): ','$' NEWLN: DB CR,LF,'$' ; ADDBR: CALL OPT LXI D,NEWLN CALL DSPLY RET ; DSPLY: MVI C,CMSG CALL BDOS RET ; BAD: LXI D,NONHEX CALL DSPLY ; OPT: LXI D,ENTRY CALL DSPLY MVI A,003H STA DEFOPT OPT5: LXI H,ADDOPT INX H CALL CONS RZ JNC OPT6 MOV A,C CPI 'P' JZ DOPT1 CPI 'B' JZ DOPT2 CPI 'N' JZ DOPT2 CPI 'W' JZ DOPT3 CPI 'T' JZ DOPT4 CPI 'S' JZ DOPT5 CPI 'L' JZ DOPT6 JMP BAD DOPT1: MVI A,03H ; Program entry point JMP DOPT9 DOPT2: MVI A,040H ; DB entry point JMP DOPT9 DOPT3: MVI A,048H ; DW entry point JMP DOPT9 DOPT4: MVI A,044H ; DW entry point to table of program jumps JMP DOPT9 DOPT5: MVI A,00bH ; subroutine requires string JMP DOPT9 DOPT6: ; Load address (default 0100h) mvi a,0ffh ; special function JMP DOPT9 DOPT9: STA DEFOPT JMP OPT5 OPT6: lxi d,0 RAL RAL RAL RAL MOV D,A CALL CONS JC BAD JNZ OPT1 OPT0: MOV A,D ORA E RZ JMP BAD ; OPT1: ADD D MOV M,A MOV D,A ; DCX H CALL CONS JC BAD JZ OPT0 RAL RAL RAL RAL MOV E,A CALL CONS JC BAD JZ OPT0 ; OPT3: ADD E MOV M,A JNZ OPT4 ADD D RZ OPT4: LXI D,ADDOPT LDA DEFOPT MOV B,A inr a jz opt4a ; special flag CALL INSX JMP OPT opt4a: lhld addopt ; LOAD address call setload ; set pointers for this load address jmp OPT ; CONS: PUSH H PUSH D CONS1: mvi c,cstat CALL Bdos ORA A JZ CONS1 mvi c,cin CALL Bdos POP D POP H cpi CR RZ ; CF=Z if UNHEX: ANI 07FH MOV C,A CPI 'A' JNC ATOF SUI '0' RC ; CF=C if not numeric CPI 10 CMC ; Compliment carry flag ;- rc ; CF=C if not numeric RET ; CF=NZ if numeric ATOF: ANI 05FH MOV C,A SUI 'A' RC ADI 10 CPI 16 CMC ; Compliment carry flag RET ;-------------------------------------------------------------- ; First pass through program to find all branch locations ;-------------------------------------------------------------- PASS1: lxi d,msgp1 mvi c,CMSG call bdos SUB A STA COUNT ; Set output buffer to zero CALL initmap ; Initialise START table LXI D,addhelp CALL DSPLY ; INFO re ENTRY points CALL RDMAP ; Read .MAP file if it exists CALL ADDBR ; Add ENTRY points to force program type code DO1: LHLD START LOOP: MOV A,M CPI 0 ; Check if END of MAP jz pass1a ANI 01H ; Branch contains unresolved INSTRUCTION JNZ NEXT INX H INX H INX H JMP LOOP NEXT: CALL CODE JMP DO1 ;---------------------------------------------------------------------- ; repeat pass through program to find any program table locations ;---------------------------------------------------------------------- PASS1a: LHLD START LOOP1a: MOV A,M CPI 0 ; Check if END of MAP rz ; -yes- completed 2nd pass ;----- ANI 004H ; Start of table of program pointers ;----- JNZ next1a cpi 044h ; Start of table of program pointers jz next1a cpi 024h ; next unresolved entry in table jz next1a INX H INX H INX H JMP LOOP1a next1a: CALL POINT JMP DO1 ; Re-run pass1 for new branch points ;--------------------------------------------------- ; Second pass through program to write to file ;--------------------------------------------------- BEGIN: DB TAB,'.z80',CR,LF DB TAB,'aseg',CR,LF db 'BASE',tab,'EQU',tab,'$',cr,lf DB TAB,'cseg',CR,LF db 0 PASS2: lxi d,msgp2 mvi c,CMSG call bdos SUB A STA COUNT ; Set output buffer to zero LHLD START ; Table Pointer PUSH H LXI H,BEGIN CALL STRING POP H jmp do2 end2: LXI H,endmsg CALL STRING ret endmsg: DB CR,LF db tab,'END',cr,lf db 0 ; DO2: MOV A,M ; 1st byte is type of MAP address CPI 0 jz end2 ; -DONE- INX H ; Table Pointer set to absolute program ADDRESS ;---------------------------------- ; Test if INSTRUCTION or DATA ;---------------------------------- CPI 080H ; INSTRUCTION JZ INSTR CPI 082H ; Pre-defined INSTRUCTIONS JZ INSTR ; was UDFI CPI 084H ; INSTRUCTION without label JZ nlbl CPI 086H ; INSTRUCTION JZ INSTR CPI 088H ; INSTRUCTION JZ INSTR CPI 08aH ; INSTRUCTION JZ INSTR CPI 040H ; DATA BYTE JZ DATB CPI 048H ; DATA WORD JZ DATW CPI 04AH ; DATA WORD JZ DATT CPI 04cH ; Unlabeled data byte JZ DATBS CPI 04eH ; unlabeled data word JZ DATWS CPI 020H ; Unused location JZ SPARE CPI 010H ; Equate byte JZ EQUB CPI 018H ; Equate address JZ EQUW CPI 01AH ; Call/Jump address outside program JZ EQUC CPI 008H ; End of COM file JZ PREND CALL QUERY JMP DO2 UDFI: CALL UDFD ; Write Undefined label to file from address in M JMP INS0 nlbl: call space ; instruction without lable jmp ins0 INSTR: CALL LABEL ; Write label to file from address in M INS0: CALL PROG ; Add OFSET to absolute program address in INS2: LDAX D ; Read Instruction INX D CALL MNEM ; Write mnemonics to file and operand if any ; If the instruction is a RET or JMP, then ; DATA flag is non zero JZ INS9 ; error lda DATA ; MAP address = program pointer ora a ; Check if last instruction JMP or RET jnz DATC ; -YES- ; is set to next instruction INS1: CALL TEST JC INS8 JNZ INS4 ; MAP address < program pointer ;----- LDA DATA ; MAP address = program pointer ;----- ORA A ; Check if last instruction JMP or RET ;----- JNZ DO2 ; YES MOV A,M ; Test next type CPI 080H ; Another instruction label JZ DO2 CPI 082H ; Another instruction label JZ DO2 cpi 084H ; INSTRUCTION without label jz do2 cpi 086H ; CALL INSTRUCTION with DB jz do2 cpi 088H ; CALL INSTRUCTION with DW jz do2 cpi 08aH ; CALL INSTRUCTION with '..',0 jz do2 CPI 04cH ; Unlabeled data byte following CALL JZ do2 CPI 04eH ; unlabeled data word following CALL JZ do2 CPI 020H ; Unused location JZ INS3 CPI 008H ; End of COM file JZ INS6 CPI 018H ; EQU word (it should never be EQU byte) JZ INSW MOV B,A ANI 040H MOV a,b JNZ INS3 ; DB or DW CALL QUERY JMP DO2 INS3: CALL WARN ; 'Should be WARN: Data reference within program ;----- JMP INSW ; Write data reference as EQU PUSH H PUSH D INX H XCHG CALL WORD call equp POP D POP H JMP INS7 INS4: ;----- LDA DATA ; Check instruction type ;----- ORA A ; Test if RET or JMP ;----- JZ INS5 ; -no- ;----- CALL QUERY ;----- JMP DO2 INS5: MOV A,M ; Check type CPI 018H ; EQU JZ INSW CPI 008H ; NULL JZ INS7 CPI 020H JZ INS7 CPI 000H ; END JZ INS6 CALL QUERY JMP INSW INS6: CALL QUERY JMP DO2 INSW: PUSH H PUSH D INX H XCHG PUSH D CALL WORD POP D CALL EQUAL MVI A,'0' CALL CHAR CALL CONST CALL CRLF POP D POP H INS7: INX H INX H INX H JMP INS1 ; INS8: CALL SPACE ; Write SPACE to file JMP INS2 ; INS9: DCX D ; Non Z80 instruction CALL SPACE JMP DAT2 ; PROG: MOV E,M ; Move address at location M to INX H MOV D,M ; is absolute program pointer INX H ; H is now pointing to next entry in MAP PUSH H lhld OFSET ; ofset DAD D XCHG ; is OFSET to actual program location POP H RET ; TEST: PUSH H INX H MOV C,M ; Read next MAP address into B,C INX H MOV B,M lhld OFSET ; ofset DAD B MOV B,H MOV C,L ; B,C is MAP address + OFSET POP H TEST1: MOV A,D ; Compare with position of program pointer CMP B MOV A,E RC ; MAP address > program pointer RNZ ; MAP address < program pointer CMP C RET ; DATW1: DB 'DW',TAB,'0',0 DATB1: DB 'DB',TAB,0 DATT1: DB 'DW',TAB,'X',0 ; DATBS: call SPACE ; No label, write TAB to file jmp DAT1 DATB: CALL LABEL ; Write label to file from address in M DAT1: CALL PROG ; Add OFSET to absolute program address in DAT2: CALL TEST DAT3: PUSH H ; Save next branch location PUSH D ; Save program pointer CALL ZERO ; Test if Data is zero and returns byte count POP D JNZ DAT4 SUB A ADD H JNZ SPR2 ADD L DCR A JNZ SPR2 ; Data is all zero DAT4: POP H PUSH H LXI H,DATB1 ; Write 'DB 0..H' to file CALL STRING POP H CALL VALUE ; Write byte as hex text to file ; is set to next instruction CALL CRLF DATC: CALL TEST JC DAT6 JZ DO2 ; MAP address = program pointer DAT5: CALL QUERY ; MAP address < program pointer JMP DO2 DAT6: CALL SPACE ; Write TAB to file JMP DAT3 ; DATWS: call SPACE ; No label, write TAB to file jmp DATWP DATW: CALL LABEL ; Write label to file from address in M DATWP: CALL PROG ; Add OFSET to absolute program address in INX D CALL TEST ; Check if next byte is not in table DCX D JZ DAT3 ; YES therefore write as DB PUSH H LXI H,DATW1 ; Write 'DW 0....H' to file CALL STRING POP H CALL CONST ; Write byte as hex text to file ; is set to next instruction CALL CRLF CALL TEST CNZ QUERY JMP DO2 ; DATT: CALL LABEL ; Write label to file from address in M CALL PROG ; Add OFSET to absolute program address in DAT7: INX D CALL TEST ; Check if next byte is not in table DCX D JZ DAT3 ; YES therefore write as DB PUSH H LXI H,DATT1 ; Write 'DW X....H' to file CALL STRING POP H CALL CONST ; Write byte as hex text to file ; is set to next instruction CALL CRLF CALL TEST JC DAT9 JNZ DAT5 MOV A,M CPI 024H JZ DAT8 CPI 02AH JZ DAT8 JMP DO2 DAT8: INX H INX H INX H DAT9: CALL SPACE JMP DAT7 ; SPARE: CALL UDFD CALL PROG CALL TEST PUSH H ; Save next branch location PUSH D ; Save program pointer CALL ZERO POP D JNZ SPR4 ; Data is non zero SPR2: MVI A,'D' CALL CHAR MVI A,'S' CALL CHAR MVI A,TAB CALL CHAR MOV A,H CALL DIGIT MOV A,L CALL DIGIT MVI A,'H' CALL CHAR CALL CRLF POP H JMP DO2 SPR4: SUB A MOV L,A MOV H,A MVI A,'D' CALL CHAR MVI A,'B' CALL CHAR MVI A,TAB CALL CHAR SPR5: MVI A,'0' CALL CHAR CALL HEX MVI A,'H' CALL CHAR CALL TEST1 JZ SPR7 JNC ERROR ; ERROR INX H MOV A,L CPI 16 JZ SPR6 MVI A,',' CALL CHAR JMP SPR5 SPR6: CALL CRLF CALL SPACE JMP SPR4 SPR7: CALL CRLF POP H JMP DO2 ZERO: MVI L,1 MVI H,0 ; Initialise count of spare area ZER1: LDAX D ORA A RNZ ; Data is non zero INX D CALL TEST1 RZ INX H JC ZER1 JMP ERROR ; EQUC: PUSH H XCHG PUSH D CALL WORD POP D CALL BASE MVI A,'0' CALL CHAR CALL CONST CALL CRLF POP H JMP NULL ; EQUW: PUSH H XCHG PUSH D CALL WORD POP D CALL EQUAL MVI A,'0' CALL CHAR CALL CONST CALL CRLF POP H JMP NULL ; EQUB: PUSH H XCHG PUSH D CALL HALF POP D CALL EQUAL MVI A,'0' CALL CHAR CALL VALUE CALL CRLF POP H ; NULL: INX H INX H JMP DO2 ; PREND1: DB 'ORG',TAB,'$',CR,LF,0 ; PREND: CALL LABEL PUSH H LXI H,PREND1 CALL STRING POP H JMP NULL ; BASE1: DB 'BASE+',0 ; BASE: CALL EQUAL PUSH H LXI H,BASE1 CALL STRING POP H RET ; EQUAL1: DB TAB,'EQU',TAB,0 ; EQUAL: PUSH H LXI H,EQUAL1 CALL STRING POP H RET ; equp1: DB TAB,'EQU',TAB,'$',CR,LF,0 ; equp: PUSH H LXI H,equp1 CALL STRING POP H RET ; ; PASS2 Subroutine to write label to file ; UDFD: MVI A,'U' JMP LBL ; LABEL: MVI A,'X' LBL: CALL CHAR PUSH D MOV D,H MOV E,L CALL CONST POP D MVI A,':' CALL CHAR CALL SPACE RET ;------------------------------------------------------ ; Third pass through program to write to MAP file ;------------------------------------------------------ PASS3: lxi d,msgp3 mvi c,CMSG call bdos SUB A STA COUNT ; Set output buffer to zero LHLD START ; Table Pointer ; DO3: MOV A,M ; 1st byte is type of MAP address CPI 0 rz ; -DONE- inx h ; -> absolute address ;------------------------------------ ; Test for suitable ENTRY POINT ;------------------------------------ cpi 080H ; 'P' MAP point jz map$p cpi 082H ; 'P' MAP point jz map$pl cpi 08aH ; 'S' MAP point jz map$s cpi 040H ; 'B' MAP point jz map$b cpi 048H ; 'W' MAP point jz map$w cpi 04aH ; 'T' MAP point jz map$t nxt03: inx h inx h jmp do3 map$pl: ; 'P' MAP point or 'L' MAP point push d push h lhld load ; load address xchg pop h mov a,m cmp e jnz not$l inx h mov a,m dcx h cmp d jnz not$l pop d jmp map$l not$l: pop d map$p: mvi a,'P' jmp mapitem map$l: ; 'L' MAP point mvi a,'L' jmp mapitem map$s: ; 'S' MAP point mvi a,'S' jmp mapitem map$b: ; 'B' MAP point mvi a,'B' jmp mapitem map$w: ; 'W' MAP point mvi a,'W' jmp mapitem map$t: ; 'T' MAP point mvi a,'T' jmp mapitem mapitem: push psw ; write address '0000 ' push d mov d,h mov e,l inx d call hex ; HIGH byte dcx d dcx d call hex ; LOW byte pop d mvi a,' ' call char ; write type '/?/' mvi a,'/' call char pop psw call char mvi a,'/' call char ; terminate line mvi a,cr call char mvi a,lf call char jmp nxt03 ;----------------------------------------- ; pass1a Subroutines to decode instructions ;----------------------------------------- CODE: MOV A,M ANI 00EH ; Clear unresolved bit ORI 080H ; Mark MAP type type as resolved MOV M,A INX H CALL PROG ; Add OFSET to absolute program address in OPER: push h lhld start ; check if >= top of program call insx3 ; cf -> - pop h rnc ; -YES- so stop decoding PUSH H LDAX D INX D ; Read instruction LXI H,SETS call getset ; return , = operand type POP H cpi 07h cz moper ; multi byte operand mov a,b ANI 0FH ; Check valid instruction RZ ; Non Z80 instruction MOV A,B CPI 01H ; Single byte non branch instruction JZ OPER CPI 13H JZ OPER2 CPI 23H JZ OPER3 CPI 31H JZ OPER4 CPI 42H JZ OPER5 CPI 0c3h ; dual byte of data JZ OPER5b CPI 43H JZ OPER6 CPI 53H JZ OPER7 CPI 92H ; conditional branch relative JZ OPER2r CPI 0a2H ; unconditional branch relative JZ OPER3r CPI 83H ; CALL (may be followed by data) JZ OPER1 ; ; ERROR in operand type ; lxi d,pass1err mvi c,cmsg call bdos jmp abort pass1err: db 'DISZ80: PASS1 Program error',cr,lf,'$' ;----------------------------------------- ; MULTI BYTE OPERAND ;----------------------------------------- moper: push h lxi h,tble2 moper0: mov a,m cmp c jz moper1 ora a jz moper2 ; fatal program error inx h inx h inx h jmp moper0 moper1: inx h mov a,m inx h mov h,m mov l,a ; -> second operand process call jphl mov a,b moper2: pop h ret jphl: pchl ;------------------------------; ; table of multi byte operands ; ;------------------------------; tble2: db 0cbh dw m2$cb db 0ddh dw m2$dd db 0edh dw m2$ed db 0fdh dw m2$fd db 0 ; end of table m2$cb: ldax d ; 2nd byte of operand inx d ; Read instruction lxi h,set$cb call getset ; return & = op type ret m2$dd: ldax d ; 2nd byte of operand inx d ; Read instruction lxi h,sets$dd ; Table of instruction call cmpset mov a,b cpi 07h ; test for multi byte operand rnz mov a,c cpi 0cbh ; special 2.1 operand jz m3$dd mvi b,0 ; ERROR ret m3$dd: ; 0ddh,03bh,disp,? inx d ; skip displacement to 4th byte of instruction ldax d ; Read 3rd byte of operand dcx d lxi h,set$ddcb ; Table of instruction call cmpset ; Low = byte count, -> mnemonic text ret m2$ed: ldax d ; 2nd byte of operand inx d ; Read instruction lxi h,sets$ed ; Table of instruction call cmpset ; Low = byte count, -> mnemonic text ret m2$fd: ldax d ; 2nd byte of operand inx d ; Read instruction lxi h,sets$fd ; Table of instruction call cmpset ; Low = byte count, -> mnemonic text mov a,b cpi 07h ; test for multi byte operand rnz mov a,c cpi 0cbh ; special 2.1 operand jz m3$fd mvi b,0 ; ERROR ret m3$fd: ; 0fdh,03bh,disp,? inx d ; skip displacement to 4th byte of instruction ldax d ; Read 3rd byte of operand dcx d lxi h,set$fdcb ; Table of instruction call cmpset ; Low = byte count, -> mnemonic text ret ;-----------------------------------------------; ; search table for op code in ; ; on entry: = op code ; ; -> start of table ; ; returns: , = op type ; ; = address of mnemonics ; ; = op code ; ; preserved: ; ;-----------------------------------------------; cmpset: mov c,a ; save op code to find cset1: mov a,m ; OP CODE inx h mov b,m ; High nibble = type, Low nibble = byte count inx h ; (HL) -> mnemonic text cmp c jz fndset ora a rz ; error - not Z80 multi byte instruction inx h inx h ; skip pointer jmp cset1 fndset: mov a,m inx h mov h,m mov l,a ; = mnemonic mov a,b ; & = op code type ret ;-----------------------------------------------; ; fetch op type and mnemonic from set table ; ; on entry: = op code ; ; -> start of table ; ; returns: , = op type ; ; = op code ; ; = address of mnemonics ; ; preserved: ; ;-----------------------------------------------; getset: mov c,a mvi b,0 dad b dad b dad b ; -> 3 byte paramter mov b,m ; High nibble = type, Low nibble = byte count inx h ; (HL) -> mnemonic text mov a,m inx h mov h,m mov l,a ; = mnemonic mov a,b ; & = op code type ret ;--------------------------------------- ; CALL INSTRUCTION ;--------------------------------------- OPER1: MVI B,01 CALL INSX mov a,b cpi 007h jz oper1a ; call with data byte cpi 009h jz oper1b ; call with data word cpi 00bh jz oper1c ; call with data string terminated with 0h cpi 086h jz oper1a ; call with data byte cpi 088h jz oper1b ; call with data word cpi 08ah jz oper1c ; call with data string terminated with 0h JMP OPER oper1a: ; call with data byte mvi b,04ch call inso ; next byte is data byte push d mvi b,005h inx d call inso ; next byte is code pop d ret oper1b: ; call with data word mvi b,04eh call inso ; next byte is data word push d inx d inx d mvi b,005h call inso ; followed by code pop d ret oper1c: ; call with data string terminated with 0h mvi b,04ch call inso ; next byte is data byte (s) push d oper1d: ldax d inx d ora a ; is it zero jnz oper1d ; -no- mvi b,005h call inso ; followed by code pop d ret ;----------------------------------------- ; CONDITIONAL BRANCH ;----------------------------------------- OPER2: MVI B,01 CALL INSX JMP OPER ;-------------------------------------------------- ; CONDITIONAL BRANCH RELATIVE ;-------------------------------------------------- OPER2r: MVI B,01 CALL INSR JMP OPER ;---------------------------------------------------- ; UNCONDITIONAL BRANCH RELATIVE ;---------------------------------------------------- OPER3r: MVI B,01 CALL INSR JMP OPER4 ;------------------------------------------- ; UNCONDITIONAL BRANCH ;------------------------------------------- OPER3: MVI B,01 CALL INSX ;--------------------------------------- ; RETURN (or HALT) ;--------------------------------------- OPER4: MVI B,20H CALL INSO RET ;--------------------------------------- ; Single BYTE data ;--------------------------------------- OPER5: ;----- MVI B,10H ;----- LDAX D INX D ;----- CPI 10 ;----- JC OPER ; Values less than 10 are printed as numeric ;----- PUSH D ;----- MOV E,A ;----- MVI D,0 ;----- CALL INSERT ;----- POP D JMP OPER ;------------------------------------- ; Dual BYTE data ;------------------------------------- OPER5b: INX D INX D JMP OPER ;-------------------------------- ; Data word ;-------------------------------- OPER6: MVI B,40H CALL INSX JMP OPER ; PAD: DS 2 ;----------------------------------- ; Data address ;----------------------------------- OPER7: ; JMP OPER8 PUSH H ; Save & PUSH D LDAX D MOV L,A INX D LDAX D MOV H,A INX H INX H SHLD PAD LXI D,PAD MVI B,20H CALL INSX ; ( + 2) marked as No reference to location POP D POP H jmp oper8 ;----------------------------------- ; CALL Data address ;----------------------------------- OPER7a: PUSH H ; Save & PUSH D LDAX D MOV L,A INX D LDAX D MOV H,A INX H INX H SHLD PAD LXI D,PAD MVI B,20H CALL INSX ; ( + 2) marked as No reference to location POP D POP H ;--------check for data following call statement---------------- jmp oper8 ;---------------------------------------------- ; and () marked as DW ;---------------------------------------------- OPER8: MVI B,48H CALL INSX JMP OPER ; POINT: MOV A,M ANI 0FBH ; Clear unresolved bit ORI 00AH ; Mark MAP as resolved MOV M,A INX H CALL PROG ; Add OFSET to absolute program address in MVI B,01 CALL INSX MVI B,24H CALL INSO RET ; INSX: ; Put address at () into table PUSH H PUSH D ; But first check if address within program XCHG MOV E,M INX H MOV D,M LXI H,CPM CALL INSX3 JC INSX1 LHLD FREE ; FREE contains first absolute location after program XCHG CALL INSX3 xchg JNC INSX2 INSX1: MOV A,B MVI B,1AH ; Address outside range, thus made an EQU CPI 20H ; Unless 020H type, then ignored! JZ INSX5 INSX2: CALL INSERT ; insert into table with mode INSX5: POP D INX D INX D POP H RET ; INSX3: MOV A,D ; returns flag set for - CMP H RNZ MOV A,E CMP L RET ; INSR: ; Put address based on offset at () into table PUSH H ldax d ; offset inx d ; move to next OP code PUSH D push psw lhld OFSET ; ofset call sdehl ; = - ; now contains absolute program address pop psw mov e,a ; offset rlc mvi a,0 sbb a ; = 0 for plus, or 0ffh for minus mov d,a dad d xchg ; now contains jump address LXI H,CPM ; But first check if address within program CALL INSX3 JC INSR1 LHLD FREE ; FREE contains first absolute location after program XCHG CALL INSX3 XCHG JNC INSR2 INSR1: ; outside program range MOV A,B MVI B,1AH ; Address outside range, thus made an EQU CPI 20H ; Unless 020H type, then ignored! JZ INSR5 INSR2: CALL INSERT ; insert into table with mode INSR5: pop D POP H RET ; ; INSO: PUSH H ; Insert absolute program pointer to table lhld OFSET ; ofset PUSH D call sdehl ; = - xchg ; now contains absolute program address CALL INSERT POP D POP H RET ; INSERT: PUSH D PUSH H PUSH B LHLD START IRT1: MOV A,M ; Read MAP type INX H MOV C,M INX H MOV B,M ; Read MAP address INX H CPI 0 ; Test for END of table JZ IRT2 MOV A,D ; Test if MAP address = INSERT address CMP B JC IRT2 ; INSERT < MAP JNZ IRT1 ; INSERT > MAP MOV A,E CMP C JZ IRT3 ; INSERT = MAP JNC IRT1 ; INSERT > MAP ; IRT2: DCX H ; Copy INSERT entry into current entry of MAP MOV M,D DCX H MOV M,E DCX H MOV D,B MOV E,C ; Previous MAP address moved to POP B ; Recover INSERT type SUB A CMP B ; Check if END of MAP MOV A,M ; Previous MAP type is saved in A MOV M,B JZ IRT8 MOV B,A PUSH B ; then put into stack pointer for B INX H INX H INX H INX H MOV C,M ; Next MAP address is saved in B,C INX H MOV B,M INX H ; CPI 0 ; CZ INS9 ; Check if new MAP location is not corrupting program JMP IRT2 ; IRT3: DCX H ; INSERT = MAP DCX H DCX H MOV A,M ; MAP type POP B MOV C,A ; MAP type saved in CMP B ; Compared with INSERT type JZ IRT8 ; SAME ANI 010H ; Test if MAP type or INSERT is EQU JNZ IRT9 ; MAP type is EQU mov a,b ani 010h JNZ IRT9 ; INSERT is EQU MOV A,B ANI 020H JNZ IRT8 ; INSERT is NO REFERENCE TO LOCATION MOV A,C ; test MAP type CPI 020H JZ IRT4 CPI 024H JZ IRT4 CPI 02AH JZ IRT10 CPI 080H JZ IRT5 CPI 082H JZ IRT5 CPI 084H ; unlabeled instruction JZ IRT5a CPI 086H ; call with data byte JZ IRT5b CPI 088H ; call with data word JZ IRT5b CPI 08aH ; call with string JZ IRT5b mov a,c ani 040h jnz IRT7 ; data types mov a,c CPI 010H JZ IRT9 ; MAP type is byte EQU CPI 018H JZ IRT4 CPI 01AH JZ IRT9 CPI 008H JZ IRT4 CPI 001H JZ IRT6 CPI 003H JZ IRT6 CPI 005H ; unlabelled instruction continues JZ IRT6a CPI 007H ; CALL with Data byte JZ IRT6 CPI 009H ; CALL with Data word JZ IRT6 CPI 00bH ; CALL with Data string JZ IRT6 JMP ERROR IRT4: MOV M,B ; Update MAP type to INSERT type JMP IRT8 IRT4a: ; resolve MAP type mov a,b ani 00eh ori 080h mov m,a jmp IRT8 IRT5: ; MAP type is already RESOLVED MOV A,B CPI 001H JZ IRT8 CPI 003H JZ IRT8 cpi 005h jz irt8 CPI 080H JZ IRT8 CPI 082H JZ IRT4 CPI 084H JZ IRT8 CPI 044H ; Perhaps print WARNING ! JZ IRT4 CPI 04AH ; Perhaps print WARNING ! JZ IRT4 MOV A,B ani 40h ; any other data jnz IRT8 ; Perhaps print WARNING ! JMP ERROR irt5a: ; resolved unlabeled instruction MOV A,B ani 80h ; resolved instruction jnz IRT4 mov a,b ani 001h ; unresolved instruction jnz IRT4a ; now resolved CPI 044H ; Perhaps print WARNING ! JZ IRT4 CPI 04AH ; Perhaps print WARNING ! JZ IRT4 MOV A,B ani 40h ; any other data jnz IRT8 ; Perhaps print WARNING ! JMP ERROR irt5b: ; MAP type is already RESOLVED call with data mov a,b ani 080h jnz IRT8 mov A,B ani 001h jnz irt8 mov A,B ani 040h jnz IRT8 ; Perhaps print WARNING ! JMP ERROR IRT6: ; MAP type is unresolved mov a,b cpi 001h jz irt8 cpi 005h jz irt8 cpi 003h jz irt8 MOV A,B ani 040h ; test for data type jnz IRT8 ; Perhaps print WARNING ! JMP ERROR irt6a: ; MAP type is unresolved & unlabelled mov a,b cpi 001h jz irt4 cpi 003h jz irt8 cpi 005h jz irt8 MOV A,B ; MAP type is unresolved ani 040h ; test for data type jnz IRT8 ; Perhaps print WARNING ! JMP ERROR IRT7: ; MAP type is DATA entry point MOV A,B CPI 048H JZ IRT4 ; DW has priority over DB CPI 040H JZ IRT8 CPI 044H JZ IRT4 CPI 04AH JZ IRT4 CPI 04cH ; unlabeled data byte JZ IRT8 CPI 04eH ; unlabeled data word JZ IRT8 CPI 001H JZ IRT4 CPI 003H JZ IRT4 cpi 005h jz irt4 JMP ERROR IRT10: ; MAP type is (2a, 44, 4a) DATA MAP type entry point MOV A,B ani 040h ; test for data type jnz IRT8 MOV A,B CPI 001H JZ IRT4 CPI 003H JZ IRT4 cpi 005h jz irt4 JMP ERROR IRT8: mov b,m ; return MAP type in POP H POP D RET ; IRT9: INX H ; MAP type is EQU BYTE INX H INX H PUSH B JMP IRT1 ;------------------------------------------------------------ ; Subroutine to write MNEMONICS to file ; B contains length of instruction ; Returns CF = NZ if ok, = Z if error ;------------------------------------------------------------ mnemsp: dw 0 ; save stack pointer for error quit MNEM: PUSH H ; Subroutine to return length in B of instruction in A lxi h,0 dad sp shld mnemsp ; save stack ;------------------------------------------ ; entry = op code, (SP) -> next byte ; return -> MNEMONIC, = byte count ;------------------------------------------ LXI H,SETS ; standard set of op codes call getset ; returns & = op type, -> mnemonic cpi 07h ; test op type jnz mnem1 ; single byte operand ;----------------------------------------- ; MULTI BYTE OPERAND ;----------------------------------------- lxi h,tble3 mnem01: mov a,m cmp c jz mnem02 ora a jz mnemerr ; fatal program error inx h inx h inx h jmp mnem01 mnem02: inx h mov a,m inx h mov h,m mov l,a ; -> second operand process ldax d ; 2nd byte of operand inx d ; Read instruction call jphl ; pchl ;------------------------------------------ ; entry: -> MNEMONIC, = byte count ;------------------------------------------ MNEM1: ; test for unconditional jump or return or PCHL MOV a,b ANI 20H ; Unconditional jump, return, PCHL, or jr STA DATA ; test for zero length - invalid op code MOV a,b ANI 0FH jz mnemerr mov b,a ; = length of instruction (1, 2 or 3 bytes) ; print mnemonic scanning for ? indicating data MVI C,16 ; points to start of MNEMONICS string MNEM2: MOV A,M ; Write up to 16 characters to file CPI 0 ; Each MNEMONIC ends with a zero JZ mnem4 CPI '?' ; ? denotes address or offset goes here jz mnem5 CPI '!' ; ! denotes extra instruction byte to be ignored jz mnem11 CPI '@' ; @ denotes byte relative address jz mnem12 CALL CHAR mnem3: ; increment to next bytes INX H DCR C ; unless done 16 bytes JNZ MNEM2 mnem4: dcr b ; check reached zero jnz mnemerr ; wrong number of operands CALL CRLF POP H ori -1 ; return ok RET ;--------------------------------- ; found a '?' in the mnemonic text ;--------------------------------- mnem5: inx h dcr c jz mnem6 mov a,m cpi '?' ; test for pointer jz mnem9 ; fill ?? with data mnem6: dcx h inr c ; fill ? with data byte DCR B jz mnemerr ; should be 1 push b mnem7: LDAX D ; -> next byte CPI 10 ; Check if byte value below 10 JNC mnem8 INX D ; YES - Write as constant ADI '0' CALL CHAR JMP mnem10 mnem8: ;------ CALL BYTE ; write as data label call value ; write as HEX constant jmp mnem10 ;---------------------------------- ; found a '??' in the mnemonic text ;---------------------------------- mnem9: ; fill ?? with data word DCR B jz mnemerr ; should be 2 DCR B jz mnemerr ; should be 2 push b CALL WORD ; where -> next byte mnem10: pop b jmp mnem3 ;--------------------------------- ; found a '!' in the mnemonic text ;--------------------------------- mnem11: DCR B jz mnemerr ; should be 1 inx d ; skip next instruction byte jmp mnem3 ;--------------------------------- ; found a '@' in the mnemonic text ;--------------------------------- mnem12: ; fill @ with calculated data word DCR B jz mnemerr ; should be 1 push b PUSH H ldax d ; offset inx d ; move to next OP code push psw lhld OFSET ; ofset call sdehl ; = - ; now contains absolute program address pop psw mov c,a ; offset rlc mvi a,0 sbb a ; = 0 for plus, or 0ffh for minus mov b,a dad b ; = actual address MVI A,'X' CALL CHAR mov a,h call digit ; HIGH byte first mov a,l call digit ; LOW byte next MVI A,'H' CALL CHAR pop h pop b jmp mnem3 ; error in mnemonics mnemerr: lhld mnemsp ; recover stack on entry sphl lxi d,progerr mvi c,cmsg call bdos call QUERY ; Zero byte length CALL CRLF POP H xra a ; return error RET progerr: db cr,lf,'DISZ80 - Program error in mnenomic table','$' savehl: dw 0 savede: dw 0 ;------------------------------------------------- ; entry = op code, (SP+2) -> next byte ; -> OP TYPE, -> mnemonic table ; return -> mnemonic string, = op type ;------------------------------------------------- ;-----lookup: MVI b,0 ;----- MOV c,A ; contains index ;----- DAD b ; -> OP code type ;----- MOV a,M ;----- ;----- mov h,b ;----- mov l,c ;----- dad h ;----- dad h ;----- dad h ;----- dad h ; *16 ;----- dad d ; -> standard mnemonics ;----- ;----- MOV b,a ;----- ret ;------------------------------; ; table of multi byte operands ; ;------------------------------; tble3: db 0cbh dw mn2$cb db 0ddh dw mn2$dd db 0edh dw mn2$ed db 0fdh dw mn2$fd db 0 ; end of table mn2$cb: lxi h,set$cb call getset ; returns & = op type, -> mnemonic ret mn2$dd: lxi h,sets$dd ; set of 2nd op codes call cmpset ; Low = byte count, -> mnemonic text mov a,b cpi 7 ; test for multi byte rnz ; -no- mov a,c ; check 2nd operand cpi 0cbh ; special 2.1 operand jz mn3$dd xra a ; -no- mov b,a ; set return to zero ret ; ERROR mn3$dd: ; 0ddh,0cbh,disp,? inx d ; skip displacement to 4th byte of instruction ldax d ; Read 3rd byte of operand dcx d lxi h,set$ddcb ; Table of instruction call cmpset ; Low = byte count, -> mnemonic text ret mn2$ed: lxi h,sets$ed ; set of 2nd op codes call cmpset ; Low = byte count, -> mnemonic text ret mn2$fd: lxi h,sets$fd ; set of 2nd op codes call cmpset ; Low = byte count, -> mnemonic text mov a,b cpi 7 ; test for multi byte rnz ; -no- mov a,c ; check 2nd operand cpi 0cbh ; special 2.1 operand jz mn3$fd xra a ; -no- mov b,a ; set return to zero ret ; ERROR mn3$fd: ; 0fdh,0cbh,disp,? inx d ; skip displacement to 4th byte of instruction ldax d ; Read 3rd byte of operand dcx d lxi h,set$fdcb ; Table of instruction call cmpset ; Low = byte count, -> mnemonic text ret ;----------------- ; add word address ;----------------- WORD: MVI A,'X' CALL CHAR CONST: INX D ; Write 2nd byte first CALL HEX DCX D DCX D CALL HEX MVI A,'H' CALL CHAR INX D RET ; HALF: MVI A,'X' CALL CHAR CALL HEX MVI A,'H' CALL CHAR LDAX D INX D CPI 0 ; Check not data WORD JNZ ERROR RET ; BYTE: MVI A,'X' jmp leadb VALUE: MVI A,'0' leadb: CALL CHAR CALL HEX PUSH PSW MVI A,'H' CALL CHAR POP PSW ; Recover data byte CPI ' ' ; If byte is >= to a space then it is also written RC ; as a character string: ;'.' CPI 21H ; Unless it is = 021H RZ CPI 7FH ; or it is => 07FH RNC MOV B,A MVI A,';' CALL CHAR MVI A,'''' CALL CHAR MOV A,B CALL CHAR MVI A,'''' CALL CHAR RET ; Subroutine to write in HEX contents of () ; and increment HEX: LDAX D INX D DIGIT: PUSH B MOV B,A RAR RAR RAR RAR CALL HEX1 MOV A,B CALL HEX1 MOV A,B POP B RET HEX1: ANI 0FH CPI 10 JC HEX2 ADI 'A'-10 JMP HEX3 HEX2: ADI '0' HEX3: CALL CHAR RET ; CRLF: MVI A,CR CALL CHAR MVI A,LF CALL CHAR RET ; Write 8 charcters to BUFFER SPACE: MVI A,TAB CALL CHAR RET ; STRING: MOV A,M ; Write string of characters INX H ; Terminated by a zero ORA A RZ CALL CHAR JMP STRING ; Write character in A to file BUFFER CHAR: PUSH H PUSH D PUSH B PUSH PSW MOV D,A ; Save character in D LDA COUNT ; Number of characters in BUFFER LXI H,dmabuf MOV C,A MVI B,0 DAD B ; = BUFFER + COUNT MOV M,D ; Write character to BUFFER INR C MOV A,C STA COUNT ; Increment counter and save in COUNT CM WRITE ; If BUFFER filled with 128 characters then write to file POP PSW POP B POP D POP H RET ; ;Open output file ; OPENtmp: lxi h,t$tmp LXI d,dfcb+9 ; FCB set to M80 type lxi b,3 call copy create: call zrofcb ; intialise FCB to zero LXI D,dfcb MVI C,FDELETE CALL BDOS ;DELETE FILE LXI D,dfcb MVI C,FCREATE CALL BDOS ;CREATE FILE CPI 255 JNZ SETDMA LXI D,NOSPACE MVI C,CMSG CALL BDOS JMP RETURN ;FILE NOT FOUND ; SETDMA: LXI D,dmabuf MVI C,FDMA CALL BDOS RET ; WRITE: LXI D,dfcb MVI C,FWRITE CALL BDOS SUB A STA COUNT RET ; WARN1: DB ';WARN',TAB,'DB',CR,LF,0 ; WARN: PUSH H LXI H,WARN1 CALL STRING POP H PUSH D PUSH H PUSH B LXI D,WARNS MVI C,CMSG CALL BDOS POP B POP H POP D RET WARNS: DB '! WARN !',CR,LF,'$' ; QUER0: DB 'ERROR',CR,LF,0 ; QUERY: PUSH H LXI H,QUER0 CALL STRING POP H QUER1: PUSH D PUSH H PUSH B LXI D,QUERYS MVI C,CMSG CALL BDOS POP B POP H POP D RET QUERYS: DB '! ERROR !',CR,LF,'$' ; ERROR: CALL QUER1 LDA COUNT CPI 0 cnz DONE JMP ABORT ;----------------------------------------; zrofcb: ; zeroes RC to CR of default FCB ;----------------------------------------; lxi h,dfcb+12 lxi d,dfcb+13 lxi b,1+(32-9-3)-1 mvi m,0 jmp copy ; zero remaining bytes ;---------------------------------------------; copy: ; copies bytes from (HL) to (DE) ;---------------------------------------------; mov a,b ora c rz mov a,m stax d inx h inx d dcx b jmp copy ;-------------------------------------------; sdehl: ; = - (destroys ) ;-------------------------------------------; mov a,e sub l mov l,a mov a,d sbb h mov h,a ret ;-------------------------------; ; load program on page boundary ; ;-------------------------------; lenprog equ ($-cpm) bound equ (lenprog + 0ffh) and not 0ffh ds bound - lenprog END