; XXI.MAC -- Translates Zilog Z80 mnemonics to extended Intel 8080 mnemonics ; Vers equ 10 Subvers equ ' ' ; current modification level ; ; Version 1.0 -- April 28, 1990 -- Gene Pizzetta ; Translates Zilog mnemonics to extended Intel mnemonics as used ; by SLRMAC and Digital Research's Z80.LIB. Translates all Zilog ; opcodes except those referencing index registers X and Y. Inserts ; "MACLIB Z80" at head of file. Based on Richard Conn's XLATE2, ; which translates Intel to Zilog, and Frank Zerilli's XLT80. ; LinLen equ 128 ; MAXIMUM LINE LENGTH OpcLen equ 5 ; maximum opcode length BufSiz equ 4 ; FILE BUFFER SIZE IN K InSec equ 8*BufSiz ; number of input sectors OutSec equ 8*BufSiz ; number of output sectors Sector equ 128 ; sector (record) size StkSiz equ 128 ; stack size InSiz equ InSec*Sector ; input buffer size OutSiz equ OutSec*Sector ; output buffer size ; CtrlC equ 3 BEL equ 7 TAB equ 9 LF equ 0Ah CR equ 0Dh ESC equ 1Bh SP equ 20h ; Bdos equ 05 CpmFcb equ 5Ch AltFcb equ 6Ch CpmDma equ 80h ; EOS equ 4 CpmEof equ 1Ah ; ; BDOS functions ; FOpen equ 15 FClose equ 16 FErase equ 19 FRead equ 20 FWrite equ 21 FMake equ 22 CurDsk equ 25 SetDma equ 26 ; MACLIB Z80 ; ext crlf,epstr,cout,cin,condin,codend,caps,pfn2 ext f$read,f$write,f$open,f$make,f$close,f$delete ext initfcb,phldc,phlfdc,mhldc,pafdc ext z3init,gzmtop,gua,sua,getefcb,zfname ; jmp START ; db 'Z3ENV' db 1 Z3EAdr: dw 0FE00h ; address of environment descriptor ; ; Messages . . . ; MsgSOn: db 'XXI Zilog to Extended Intel Translator Version ' db Vers/10+'0','.',(Vers MOD 10)+'0',SubVers,CR,LF,0 MsgUse: db 'Usage:',CR,LF MsgSpc: db ' ',0 MsgUs1: db ' {dir:}infile{.typ} {dir:}{outfile}{.typ} {/option}',CR,LF db 'Options:',CR,LF db ' L instructions to lower-case.',CR,LF db ' U instructions to upper-case.',CR,LF db 'Default is to preserve case. Default source filetype is',CR,LF db 'Z80. Default destination filetype is MAC. Default',CR,LF db 'destination filename is the same as the source filename.',CR,LF db 'Untranslated opcodes are flagged with "#".',0 MsgNam: db 'XXI',0 MsgAbt: db 'Aborted.',0 MsgMem: db BEL,'Line number table out of memory!',0 MsgAmb: db 'Ambiguous filename.',0 MsgBdO: db 'Invalid option.',0 MsgFNF: db 'File not found.',0 MsgDir: db 'No directory space.',0 MsgFEx: db BEL,'Output file exists, delete (Y/[N]) ? ',0 MsgWEr: db 'File write error.',0 MsgArr: db ' --> ',0 MsgUnk: db ' lines containing untranslated opcodes:',CR,LF,0 MsgExc: db 0,'Following operands are not fully translated: ',CR,LF,0 MsgEls: db 0,' ELSE',0 MsgMac: db 0,' MACRO',0 MsgPrc: db ' input lines processed.',0 StrLib: db ';',CR,LF,TAB,'MACLIB',TAB,'Z80',CR,LF,';',CR,LF,0 StrUnk: db ';',CR,LF db '; Lines containing untranslated opcodes:',CR,LF db ';',CR,LF db ';',0 StrFlg: db '# ',0 ; ; Start of program . . . ; Start: lhld Z3EAdr ; set up environment call z3init call gzmtop ; get top of memory shld MemTop sspd OldStk ; set up stack lxi sp,OldStk call codend ; set up UnkTbl shld UnkTbl shld UnkPtr ; ; Main program loop . . . ; Begin: call Init ; initialize data and sign on call SetFls ; open files NxtLin: call GetLin ; get line from input file to buffer call PrcLin ; process line jr NxtLin ; ; Subroutines . . . ; ; Init -- initialize data and flags, and print sign on. ; Init: mvi a,100 ; dot every 100 lines sta DotLin mvi a,50 ; dots per line sta DotCol mvi a,10 ; dots per group sta DotCnt mvi a,1 sta CurCol mvi a,3 ; line count starts at 3 sta CurLin xra a lxi h,CurLin+1 ; clear data area mvi b,NumBuf-CurLin InitLp: mov m,a inx h djnz InitLp call GetOpt lxi h,MsgSOn call epstr ret ; ; SetFls -- open input and output files ; SetFls: mvi c,CurDsk call Bdos inr a sta DftDsk call GetFns call OpenIn call MakeFl lxi h,StrLib ; print MACLIB request call PutLin mvi a,1 sta CurCol ret ; ; GetOpt -- checks command tail for user supplied options and sets ; appropriate option flags. Invalid options are ignored. ; GetOpt: lxi h,CpmDma+1 ; point to command tail lda CpmDma ; anything there? ora a rz ; (no) mov b,a ; yes, put number of chars in B ScnDLp: mov a,m ; get character cpi '/' ; delimiter? jz ScnOpt ; (yes) mov d,a ; save character ScnDL2: inx h ; no, keep looking djnz ScnDLp ret ; (none found, return) ; ScnOpt: push psw ; save current character mov a,d ; get back previous character pop d ; put current character in D cpi ' ' ; was previous char a space? jnz ScnDL2 ; (no) jmp ScnOp2 ; ScnOLp: call ScnTbl xchg ; point back to options ScnOp2: inx h djnz ScnOLp ; loop through options ret ; ScnTbl: mov c,m ; put option in C lxi d,OptTbl ; point DE to option table ScnTLp: ldax d ; get table option ora a ; end of table? jz NoMat ; (yes, no match) inx d ; no, keep looking cmp c ; match? jz TMatch ; (yes) inx d ; move pointer to next entry inx d jmp ScnTLp ; ..and keep looking ; NoMat: xchg ; no match mov a,c ; get back option cpi ' ' ; was it a space? rz ; that's okay mvi a,4 ; set error flag lxi h,MsgBdO ; say bad option jmp ErExit ; TMatch: push h ; save option pointer ldax d ; put address from table into HL mov l,a inx d ldax d mov h,a pop d ; recover option pointer in DE mvi a,1 ; set option flag by jumping to pchl ; ..table routine and returning ; ; OptTbl -- Option jump table ; OptTbl: db '/' ; / = usage message dw OptH db 'L' ; L = instructions to lower-case dw OptL db 'U' ; U = instructions to upper-case dw OptU db 0 ; end of option jump table ; ; Option setting routines ; OptH: lxi h,MsgSOn call epstr OptH1: lxi h,MsgUse ; print help message call epstr call ComNam ; print name we're called by, if possible lxi h,MsgUs1 jmp ErExit ; OptL: push psw mvi a,'L' sta CasFlg ; just set the flag pop psw ret ; OptU: push psw mvi a,'U' sta CasFlg pop psw ret ; ; ComNam -- Print actual name by which this program was called, if available ; from external file control block. Otherwise, use "XXI". ; ComNam: call getefcb jrz NoEFcb ; (no external fcb) mvi b,8 ; print filename ComNLp: inx hl mov a,m ani 7Fh cpi ' ' cnz cout djnz ComNLp ret ; NoEFcb: lxi h,MsgNam ; print default name call epstr ret ; ; GetLin -- Gets line from input file to line buffer until CR. Filters ; out ctrl chars except for TAB. Truncates lines after LinLen chars. ; Terminates line with "CR,LF,0". ; GetLin: call PrtDot ; print activity dot call condin ; check for abort cpi CtrlC cz crlf jz UAbort xra a sta QFlag sta CFlag lxi h,LinBuf ; line buffer mvi b,LinLen ; max # of char GetLn1: xchg lhld InPtr xchg mov a,d cpi (InBuf+InSiz)/256 jrnz GetLn4 mov a,e cpi (InBuf+InSiz) MOD 256 jnz GetLn4 push h push b lxi d,InBuf GetLn2: mvi c,SetDma push d call Bdos pop d xchg lda InUsr ; set input user call sua lxi d,InFcb call f$read dcr a jrnz GetLn3 mvi a,CpmEof mov m,a GetLn3: lxi d,Sector dad d xchg mov a,d cpi (InBuf+InSiz)/256 jrnz GetLn2 mov a,e cpi (InBuf+InSiz) MOD 256 jrnz GetLn2 pop b pop h lxi d,InBuf GetLn4: ldax d inx d xchg shld InPtr xchg mov m,a cpi '''' ; set or reset QFlag jrnz GetL41 lda QFlag cma sta QFlag GetL41: lda CasFlg ; Translate to upper- or lower-case? ora a jrz GetL46 ; (no) lda QFlag ; If in quote, do nothing ora a jrnz GetL43 mov a,m ; otherwise, ';' sets CFlag cpi ';' jrz GetL42 cpi EOS ; and EOS resets it jnz GetL43 xra a GetL42: sta CFlag GetL43: lda QFlag ; If in quote, do nothing ora a jrnz GetL46 lda CFlag ; If in comment, do nothing ora a jrnz GetL46 lda CasFlg ; Otherwise, if CasFlg = U.. cpi 'U' mov a,m jrz GetL44 call Lower ; ..trans to lower-case jmp GetL45 GetL44: call caps ; ..else tran to upper-case GetL45: mov m,a GetL46: mov a,m cpi CR jrz GetLn6 cpi TAB ; filters out all ctrl chars jrz GetLn5 cpi CpmEof jrz Finish cpi ' ' ; except tab jc GetLn1 GetLn5: dcr b inx h jnz GetLn1 inr b dcx h jmp GetLn1 ; GetLn6: inx h mvi m,LF inx h mvi m,0 xchg shld InPtr lhld CurLin inx h shld CurLin ret ; ; Exit ; Finish: lhld UnkPtr call ChkMem ; return NC if HL < MemTop jnc Finis1 call ErrMem Finis1: xra a mov m,a inx h mov m,a call PutUnk call ClsOut call crlf call PrtUnk ; print lines with unknown opcodes lxi h,MsgExc call epstr lxi h,MsgEls ; print partially translated opcodes call epstr lxi h,MsgMac call epstr call crlf lhld CurLin ; get line count dcx h ; ..subtract 3 dcx h dcx h call phlfdc ; ..and print it lxi h,MsgPrc jr ErExit ; ; Error handlers . . . ; ErrFNF: lxi h,MsgFNF ; file not found jr ErExit ; ErrDir: lxi h,MsgDir ; no directory space jr ErExit ; ErrFEx: lxi h,MsgFEx ; file already exists call epstr call GetYN jrnz Abort call crlf call f$delete jmp MakeF4 ; ErrMem: call crlf lxi h,MsgMem ; insufficent memory jr ErExit ; ; Print message and abort ; UAbort: call ClsOut ; user abort, file open Abort: lxi h,MsgAbt ; user abort, no file open ErExit: call epstr Exit: lspd OldStk ; restore system stack ret ; ..and return to CCP ; ; AddLin -- Add current line number to UnkTbl ; AddLin: lhld CurLin xchg lhld UnkPtr call ChkMem ; ret NC if ok rc mov m,e inx h mov m,d inx h shld UnkPtr lhld UnkCnt inx h shld UnkCnt ret ; ; PrtUnk -- Print list of line numbers in which unknown or untranslatable ; Z80 opcodes found. ; PrtUnk: lhld UnkTbl shld UnkPtr lhld UnkCnt mov a,l ora h rz call phlfdc lxi h,MsgUnk call epstr mvi b,10 PrtUn1: lhld UnkPtr mov e,m inx h mov d,m inx h shld UnkPtr xchg mov a,h ora l jrz PrtUn2 mvi a,' ' call cout push b call phldc pop b dcr b jrnz PrtUn1 call crlf mvi b,10 jr PrtUn1 ; PrtUn2: mvi a,10 cmp b cnz crlf ret ; ; PutUnk -- Put to output file list of line numbers in which unknown or ; untranslatable Z80 opcodes found. ; PutUnk: lhld UnkTbl shld UnkPtr lhld UnkCnt mov a,l ora h rz lxi h,StrUnk call PutLin mvi b,10 PutUn1: lhld UnkPtr mov e,m inx h mov d,m inx h shld UnkPtr xchg mov a,h ora l jrz PutUn2 mvi a,' ' call PutChr push b call PutNum pop b dcr b jrnz PutUn1 call Pcrlf mvi a,';' call PutChr mvi b,10 jr PutUn1 ; PutUn2: mvi a,10 cmp b jrz Pcrlf call Pcrlf mvi a,';' call PutChr ; Pcrlf: mvi a,CR call PutChr mvi a,LF call PutChr ret ; ; PrcLin -- Process line ; PrcLin: lxi h,LinBuf PrcLn0: call FndOpc jz PutEn6 lxi h,OptLog lxi b,3*OpcLen call ScanOp jz DoLog lxi h,OptADD lxi b,3*OpcLen call ScanOp jz DoADD lxi h,OptADC lxi b,3*OpcLen call ScanOp jz DoADC lxi h,OptEX lxi b,2*OpcLen call ScanOp jz DoEX lxi h,OptPP lxi b,2*OpcLen call ScanOp jz DoPP lxi h,OptINC lxi b,3*OpcLen call ScanOp jz DoINC lxi h,OptLD lxi b,3*OpcLen call ScanOp jz DoLD lxi h,OptOne lxi b,2*OpcLen call ScanOp jz Do180 lxi h,OptPsd lxi b,2*OpcLen call ScanOp jz DoPsd lxi h,OptShf lxi b,2*OpcLen call ScanOp jz DoShft lxi h,OptBIT lxi b,2*OpcLen call ScanOp jz DoBIT lxi h,OptIO lxi b,2*OpcLen+2 call ScanOp jz Exec lhld OpcPtr ; Unrecognized opcode, put jmp PutEnd ; out line as is PutOpr: lhld OprPtr PutEnd: xra a sta LcFlg sta LcdFlg mvi c,0 ; putout w/o change PutEn1: mov a,m cpi ' ' jrz PutEn3 cpi TAB jrz PutEn3 cpi CR jz PutLin cpi ';' jrz PutEn4 cpi EOS ; Process exclamation point jrz PutE21 ; separator cpi '''' jrnz PutEn2 dcr c jrz PutEn2 mvi c,1 PutEn2: call PutChr inx h jr PutEn1 ; ; Process exclamation point. ; PutE21: call SkpWht inx h ; inc past EOS PutE22: mov a,m cpi ';' jrz PutEn5 PutE24: lda Tmp cpi ' ' jrz PutE25 cpi TAB jrz PutE25 mvi a,' ' call PutChr PutE25: mvi a,'!' call PutChr jmp PrcLn0 ; ; Space or Tab comes here ; PutEn3: push h call SkpWht cpi CR ; filters out jz PutLnB ; trailing spaces or tabs pop h cpi EOS ; process exclamation point jrz PutE21 ; statement separator cpi ';' mov a,m ; prevent blank being replaced ; by ';' in string data jrz PutEn4 call PutSpT jmp PutEn1 ; PutEn4: dcr c ; ';' come here inr c jrnz PutEn2 call SkpWht ; ; Tab comments to proper column ; PutEn5: mvi b,41 PutE51: lda CurCol cmp b ; CurCol>=41? jrnc PutE54 dcr a ; no, insert tabs to column 33 ani 0F8h ; mod 8 adi 9 ; tabs every 8 columns cmp b jrz PutE54 jrc PutE52 mvi A,' ' jr PutE53 ; PutE52: mvi a,TAB PutE53: call PutChr jr PutE51 PutE54: lda Tmp ; insure cpi ' ' ; space jrz PutEn6 ; before cpi TAB ; semi-colon jrz PutEn6 mvi A,' ' call PutChr PutEn6: mov a,m inx h cpi EOS jrz PutE22 ora a rz call PutChr jr PutEn6 ; ; PutLnB -- Put line at HL to output file until 0 and reset CurCol to 1. ; PutLnB: xthl ; filter trailing pop h ; blanks or tabs PutLnC: jmp PutLin ; ; FndOpc -- Process labels, find potential opcode. ; FndOpc: mov a,m cpi ' ' jrz FndOp3 cpi TAB jrz FndOp3 cpi CR ; Pass blank lines rz cpi ';' ; ..and comment lines rz cpi '*' ; asterisk in column 1 is comment line jrnz FndOp1 mvi m,';' ; change asterisk to semi-colon ret ; ; Come here to process label ; FndOp1: mvi c,0 ; C will has length of label FndOp2: mov a,m cpi ':' jrz FndOp4 cpi TAB jrz FndOp7 cpi ' ' jrz FndOp7 cpi CR rz cpi EOS rz cpi ';' jrz FndOp7 call PutChr inx h inr c jr FndOp2 ; ; come here only if a space or a tab is at beginning of line. ; FndOp3: push h call SkpWht ; Find first non-space or tab cpi CR ; Filter out tabs and space at end-of-line jrz FndOp9 cpi EOS jrz FndOp9 pop h call PutSpT ; print until non-space or TAB push h call FinDlm ; find ,:+-/*); CR TAB or SP at HL cpi ':' pop h jrz FndOp1 ; found a label, process it jr FndOp7 ; ; colon terminating label comes here ; FndOp4: inx h mov a,m cpi ':' ; is it a double colon ? jrnz FndOp5 call PutChr inx h FndOp5: mvi a,':' call PutChr ; ; TAB or SP comes here. See if there is an opcode field. ; FndOp7: push h call SkpWht mov a,m cpi CR jrz FndOp9 ; filter trailing SP or TAB cpi EOS jrz FndOp9 ; exclamation point separator cpi ';' jrnz FndOp8 ; found opcode field xthl ; found comment field pop h pop b ; clear return jmp PutEn5 ; tab to proper column ; ; opcode field has been located ; FndOp8: pop h call PutSpT ; ; move potential opcode to OpcBuf ; MovOpc: shld OpcPtr mvi b,OpcLen lxi d,OpcBuf call MovBDH ; move up to B chars from HL to call SkpWht ; DE until ,:+-/*); CR TAB SP shld OprPtr sub a inr a ret ; ; come here on CR to filter trailing SP or TAB ; FndOp9: xthl pop h ret ; ; Exec -- Gets routine address from HL+2*OpcLen and jumps to routine. ; Exec: push h lxi b,2*OpcLen dad b mov c,m inx h mov b,m pop h push b ; address on stack ret ; go to it ; ; ScanOp -- Scan table at HL for match to OpcLen char string at OpcBuf. ; Ret Z and HL-> entry if match. ; ScanOp: mov a,m ana a jrz ScnOp1 push b mvi b,OpcLen lxi d,OpcBuf call CBDEHL ; compare B bytes (DE)-(HL) pop b rz dad b jr ScanOp ; ScnOp1: inr a ret ; ; Scan -- Scan table at HL for match to string pointed to by DE. Enter ; with A = string length and BC = offset to next entry. Return Z and ; HL pointing to table entry if match. ; Scan: push b mov b,a mov a,m ora a jrz NotFnd call Comp ; compare B bytes (DE)-(HL) mov a,b pop b rz dad b jr Scan ; NotFnd: inr a pop b ret ; ; CBDEHL -- Compares B chars at DE with chars at HL. Return Z if match. ; Preserve HL, DE, BC ; CBDEHL: push h push d push b CBDH1: ldax d cpi 'a' jrc CBDH2 sta LcFlg ani 05Fh CBDH2: cmp m jrnz CBDH3 inx h inx d dcr b jrnz CBDH1 CBDH3: pop b pop d pop h ret ; ; Comp -- Compare B bytes at DE with B bytes at HL. Set (LcdFlg) if any ; byte at DE is lower-case. ; Comp: push h push d push b Comp1: ldax d cpi 'a' jrc Comp2 sta LcdFlg ani 5Fh Comp2: cmp m jrnz Comp3 inx h inx d dcr b jrnz Comp1 Comp3: pop b pop d pop h ret ; ; PutOpHt -- Put up to OpcLen chars at HL+OpcLen to output file. Stop at ; space, and put tab to output file. ; PutOpHT: call PutOpc PutTab: mvi a,TAB jmp PutChr ; PutOpc: lxi b,OpcLen dad b ; HL -> new opcode mov b,c PutOp1: mov a,m cpi ' ' rz cpi TAB rz lda LcFlg ora a mov a,m jrz PutOp2 ori 20h PutOp2: call PutChr inx h dcr b jrnz PutOp1 ret ; ; PutOps -- Put string at HL to output file until 0. If (LcFlg) set, ; convert to lower-case. ; PutOps: mov a,m ora a rz lda LcFlg ora a mov a,m jrz PutOs0 call Lower PutOs0: call PutChr inx h jmp PutOps ; ; PutRnd -- Put string at HL to output file until 0. If (LcdFlg) set, ; convert to lower-case. ; PutRnd: mov a,m ora a rz lda LcdFlg ora a mov a,m jrz PutRn0 call Lower PutRn0: call PutChr inx h jr PutRnd ; ; PutStr -- Put BC character string at HL to output file. ; PutStr: mov a,b ora c rz mov a,m call PutChr inx h dcx b jr PutStr ; ; PutEOE -- Put string at HL until End of Expression (EOE). EOE is the ; first of the tabs or spaces before a semicolon or CR. Returns HL ; pointing to EOE. ; PutEOE: push b push d push h ; HL -> start call FndEOE ; returns HL -> EOE mov b,m mvi m,0 pop h ; HL -> start call PutLin mov m,b ; restore original char pop d pop b ret ; ; PutSpt -- Put spaces or tabs at HL to output file until non-(space or tab) ; PutSpt: mov a,m cpi ' ' jz PutSp1 cpi TAB rnz PutSp1: call PutChr inx h jr PutSpt ; ; FindPr -- Find '),' and return HL -> ')'. Return NZ if not found. ; FindPr: mov a,m cpi CR jz FndNPr cpi ',' jrz FndPr1 inx h jr FindPr ; FndPr1: dcx h mov a,m cpi ')' ret ; FndNPr: ora a ret ; ; FndEOE -- Find End of Expression (EOE). EOE is the first of the spaces ; or tabs before a semicolon or CR. Returns HL -> EOE. ; FndEOE: mov a,m cpi ';' jrz FndEO1 cpi CR jrz FndEO1 inx h jr FndEOE ; FndEO1: dcx h mov a,m cpi ' ' jrz FndEO1 cpi TAB jrz FndEO1 inx h ret ; ; FinDlm -- Find first ,:+-/*); CR TAB SP or exclamation point at HL, ; return A = (HL). ; FinDlm: push b call ChkDlm pop b rz inx h jr FinDlm ; ; ChkDlm -- Ret Z, A=(HL) if HL is ,:+-/*); CR TAB SP or exclamation point ; ChkDlm: mov a,m cpi ':' rz cpi '+' rz cpi '-' rz cpi '/' rz cpi '*' rz cpi ')' rz cpi '!' rz ; ; ChkSep -- Ret Z, A=(HL) if (HL) is CR, SP, TAB, comma, or semicolon. ; ChkSep: mov a,m cpi ',' rz cpi ' ' rz cpi TAB rz cpi ';' rz cpi CR ret ; ; MovBDH -- Fill B locations at DE with spaces. Move up to B char from HL ; to DE until ,:+-/*); CR TAB or SP encountered. Return Z and HL -> special ; char if found. (search B+1 loc for special char.) ; MovBDH: mov c,b mvi b,0 push b push d push h ; fill BC locations call FillBD ; at DE with spaces pop h pop d pop b MovBD1: push b ; ret Z, A=(HL) call ChkDlm ; if (HL) is pop b ; ,:+-/*); CR TAB or SP rz mov a,m stax d inx d inx h dcx b mov a,b ora c jz ChkDlm jmp MovBD1 ; ; SkpWht -- Skip white spaces (spaces and tabs). On return ; HL points to first non-space or or non-tab character. ; SkpWht: mov a,m cpi ' ' jrz SkpWh1 cpi TAB rnz SkpWh1: inx h jr SkpWht ; ; FillBD -- Fill BC locations starting at DE with spaces. Returns A = ; space, DE -> next free location, HL = DE - 1, BC = 0. ; FillBD: mvi a,' ' stax d mov h,d mov l,e inx d dcx b ldir ret ; ; GetFns -- set up input and output FCB's from command tail ; GetFns: lxi h,CpmDma+1 ; point to command tail call SkpWht ora a jz OptH1 cpi '/' jz OptH1 lxi d,InFcb ; initialize FCB call initfcb xra a call zfname jnz Ambig call SkpWht cpi 0 jrz NoFile cpi '/' jrz NoFile lxi d,OutFcb call initfcb xra a call zfname jrnz Ambig jr GetFn0 ; NoFile: lxi b,11 lxi d,OutFcb+1 call FillBD lxi d,OutFcb call initfcb call gua sta OutFcb+13 GetFn0: lda InFcb+9 ; check for input filetype cpi ' ' jrnz GetFn1 lxi h,Z80Typ ; no, move default Z80 lxi d,InFcb+9 lxi b,3 ldir GetFn1: lda OutFcb+9 ; check for output filetype cpi ' ' jrnz GetFn2 lxi h,MACTyp ; no, move default MAC lxi d,OutFcb+9 lxi b,3 ldir GetFn2: lda OutFcb+1 ; check for output filename cpi ' ' jrnz GetFn3 lxi h,InFcb+1 ; no, move filename of input file lxi d,OutFcb+1 lxi b,8 ldir GetFn3: lda InFcb+13 ; get user areas sta InUsr lda OutFcb+13 sta OutUsr GetFn4: lxi h,MsgSpc call epstr lda InUsr lxi h,InFcb call PrtFn lxi h,MsgArr call epstr lda OutUsr lxi h,OutFcb call PrtFn call crlf ret ; Ambig: lxi h,MsgAmb jmp ErExit ; ; PrtFn -- print filenames ; PrtFn: mov b,a ; save user in B mov a,m ; print drive ora a jrnz PrtFn1 lda DftDsk PrtFn1: adi '@' call cout mov a,b ; print user call pafdc mvi a,':' call cout inx h xchg ; put fcb address in DE call pfn2 ret ; ; OpenIn -- open source file with filetype Z80 ; OpenIn: lda InUsr call sua lxi d,InFcb call f$open cpi 0FFh jz ErrFNF lxi h,InBuf+InSiz shld InPtr ret ; ; MakeFl -- create output file with filetype ; MakeFl: lda OutUsr ; set output user call sua lxi d,OutFcb call f$open cpi 0FFh jnz ErrFEx MakeF4: call f$make cpi 0FFh jz ErrDir call f$open mvi a,Sector sta OutCnt lxi h,OutBuf shld OutPtr ret ; ; PutChr -- put char in A to output file, update column number. ; PutChr: push h push d push b push psw sta Tmp lhld OutPtr mov m,a cpi CR jrz PutCh0 cpi LF jrz PutCh0 cpi TAB jrnz PutCh1 lda CurCol dcr a ani 0F8h ; mod 8 adi 9 ; tabs every 8 columns jr PutCh2 ; PutCh0: mvi a,1 jmp PutCh2 ; PutCh1: lda CurCol inr a PutCh2: sta CurCol inx h ; inc OutBuf ptr lda OutCnt dcr a ; dec OutBuf count jrnz PtCh21 mvi a,Sector PtCh21: sta OutCnt mov a,h cpi (OutBuf+OutSiz)/256 jrnz PutCh4 mov a,l cpi (OutBuf+OutSiz) MOD 256 jrnz PutCh4 lxi d,OutBuf PutCh3: mvi c,SetDma push d call Bdos pop d xchg lda OutUsr call sua lxi d,OutFcb call WrtRec ; write record lxi d,Sector dad d xchg mov a,d cpi (OutBuf+OutSiz)/256 jrnz PutCh3 mov a,e cpi (OutBuf+OutSiz) MOD 256 jrnz PutCh3 lxi h,OutBuf PutCh4: shld OutPtr pop psw pop b pop d pop h ret ; ; PutLin -- put line at HL to output file until 0. ; PutLin: mov a,m ora a rz call PutChr inx h jr PutLin ; ; WrtRec -- Write record. ; WrtRec: call f$write ana a rz call crlf lxi d,MsgWEr ; write error jmp ErExit ; ; ClsOut -- Fill rest of OutBuf with CpmEof, write record, and close file. ; ClsOut: mvi a,CpmEof call PutChr lda OutCnt cpi Sector jrnz ClsOut ; ClsO1: lxi d,OutBuf lhld OutPtr mov A,H cmp d jrnz ClsO3 mov a,l cmp e jrnz ClsO3 ClsO2: lda OutUsr call sua lxi d,OutFcb call f$close ret ; ClsO3: mvi c,SetDma push d call Bdos pop d xchg lxi d,OutFcb lda OutUsr call sua call WrtRec lxi d,Sector dad d xchg lda OutPtr+1 cmp d jrnz ClsO3 lda OutPtr cmp e jrnz ClsO3 jr ClsO2 ; ; GetYN -- get char in A from console and return as upper-case. ; GetYN: call cin call caps mov b,a cpi 'Y' cz cout rz mvi a,'N' call cout jmp crlf ; ; ChkMem -- If HL < MemTop return NC. Otherwise, return C. ; ChkMem: push d xchg lhld MemTop ora a dsbc de xchg pop d ret ; ; Lower -- convert upper-case in A to lower-case. ; Lower: cpi 'A' rc cpi 'Z'+1 rnc ori 20h ret ; ; PutNum -- Puts to output file the number in HL as a decimal number. ; PutNum: lxi d,NumBuf call mhldc lxi h,NumBuf mvi b,5 NumLp: mov a,m call PutChr inx h djnz NumLp ret ; ; PrtDot -- print activity dot every 100 lines ; PrtDot: lda DotLin dcr a sta DotLin rnz mvi a,'.' call cout mvi a,100 ; Dot every 100 lines sta DotLin lda DotCnt dcr a sta DotCnt jrnz PrtDt1 mvi a,' ' call cout mvi a,10 ; Space every 10 dots sta DotCnt PrtDt1: lda DotCol dcr a sta DotCol rnz call crlf mvi a,50 ; 50 dots per line sta DotCol ret ; MACLIB XXITR ; translation routines and mnemonic tables ; ; Data and storage . . . ; Z80Typ: db 'Z80' MACTyp: db 'MAC' ; ; uninitialized data area . . . ; DSEG ; DotLin: ds 1 ; dot line count DotCnt: ds 1 ; dot group count DotCol: ds 1 ; dot column count CurCol: ds 1 ; current column pointer CurLin: ds 2 ; current line Tmp: ds 1 ; temporary storage TmpPtr: ds 2 ; temporary pointer QFlag: ds 1 ; quote flag CFlag: ds 1 ; comment flag LcFlg: ds 1 ; lower-case flags LcdFlg: ds 1 CasFlg: ds 1 ; 0 to preserve case OpNC: ds 1 OpCC: ds 2 UnkCnt: ds 2 ; number of lines with untranslated opcodes NumBuf: ds 5 ; number conversion buffer UnkPtr: ds 2 ; pointer for unknown table UnkTbl: ds 2 ; unknown opcode table address OpcPtr: ds 2 ; opcode pointer OprPtr: ds 2 ; operand pointer DftDsk: ds 1 ; default (current) disk InDrv: ds 1 ; input file drive InUsr: ds 1 ; input file user InPtr: ds 2 ; input buffer pointer OutDrv: ds 1 ; output file drive OutUsr: ds 1 ; output file user OutPtr: ds 2 ; output buffer pointer OutCnt: ds 1 ; output sector counter OpcBuf: ds OpcLen ; opcode buffer LinBuf: ds LinLen+3 ; line buffer ds StkSiz ; stack OldStk: ds 2 ; old stack pointer storage MemTop: ds 2 ; top of memory InFcb: ds 36 ; input FCB OutFcb: ds 36 ; output FCB OutBuf: ds OutSiz ; output file buffer InBuf: ds InSiz ; input file buffer ; end