title MS-Linker .. L80 name ('L80') ; DASMed version of L80 ; By W.Cirsovius V3.43 equ FALSE ;; L80 v3.44 ;;V3.43 equ TRUE ;; L80 v3.43 ;;_MODS equ TRUE ;; Expansions to standard _MODS equ FALSE ;; No expansions to standard FALSE equ 0 TRUE equ NOT FALSE OS equ 0000h BDOS equ 0005h TPATOP equ BDOS+1 CCPbuf equ 0080h TPA equ 0100h .conout equ 2 .rdrin equ 3 .lstout equ 5 .getlin equ 10 .resdsk equ 13 .seldsk equ 14 .open equ 15 .close equ 16 .delete equ 19 .rdseq equ 20 .wrseq equ 21 .make equ 22 .rename equ 23 .curdsk equ 25 .setdma equ 26 CPMerr equ 255 .drv equ 1 .nam equ 8 .ext equ 3 _EX equ 12 _DIR equ 16 _CR equ 32 FCBlen equ 33 RecLng equ 128 null equ 00h tab equ 09h lf equ 0ah ff equ 0ch cr equ 0dh eof equ 1ah MSB equ 10000000b NoMSB equ 01111111b LoMask equ 00001111b COLTAB equ 00000111b ; ; Address modes ; @@mod equ 11b ; Two bits ; @cseg equ 01b ; CSEG @dseg equ 10b ; DSEG @COMM equ 11b ; COMMON relbits equ 8 ; ; Microsoft REL types ; _ENTRY equ 0000b _SELCOM equ 0001b _PRGNAM equ 0010b _LIBRQ equ 0011b _MSLNK equ 0100b _DEFCOM equ 0101b _CHNEXT equ 0110b _DEFENT equ 0111b _EXTOFF equ 1001b _DATSIZ equ 1010b _LOCATE equ 1011b _PRGSIZ equ 1101b _ENDMOD equ 1110b _ENDPRG equ 1111b ; Label flag definition .COMMON equ 10000000b .Public equ 01000000b .Libreq equ 00100000b .Unk equ 00010000b .Known equ 00001000b .LenMsk equ 00000111b ; ModLen equ 6 ; Max module name length SymLen equ 6 ; Max symbol name length LabLen equ 16 ; Max label length defPC equ TPA+3 _ModLen equ 7 _HEXlen equ 32 ; Length of .HEX data ; Option definition .Mopt equ 10000000b .Gopt equ 01000000b .Eopt equ 00100000b .Xopt equ 00010000b .Yopt equ 00001000b .Sopt equ 00000010b .Uopt equ 00000001b ; Special subtype arithmetic codes .StB equ 1 .StW equ 2 .OpMax equ 11 ; Max allowed codes .MVI.C macro db 00eh endm .MVI.A macro db 03eh endm .ORI macro db 0f6h endm .JPC macro db 0dah endm .JP equ 0c3h .ADI equ 0c6h SymCol equ 4 ; Symbols per line ; ##### L80 starts and restarts here ##### L80.restart: ld hl,(BDOS+1) ; Get top of memory dec hl ld sp,hl ld (mystack),hl ; Save stack ld de,-250 add hl,de ld (SymBase),hl ; Init symbol table pointer ld (CurSym),hl ld de,-2048 add hl,de ld (CurExpr),hl ; Set expression pointers ld (TopExpr),hl xor a ld h,a ld l,a ld (ExecAdr),hl ; Clear a bit ld (UnDefCnt),hl ld (wrkb1),a ld (wrkb2),a ld (commflg),a ld (UnDef?),a ld (lodflag),a ld (wrkb6),a ld (wrkb7),a ld (_PSW_),a ld (wrkb9),a ld (Sav.Prg),a ld (radixmod),a ld hl,topl80 ld (topw1),hl ; Init ld (topw2),hl ld (topw3),hl ld (topw4),hl ld (PRGpt),hl ; .. CSEG ld (DATpt),hl ; .. DSEG ld hl,defPC ld (resv1),hl ld (_prog),hl ld (resv3),hl ld (resv4),hl ld (wrkb12),a ld (wFCB+.drv),a ; Clear output file ld hl,-1 ld (freebytes),hl jp go80 ; Real go ; $NO.STRT: db '?No Start Address',null $LOAD.ERR: db '?Loading Error',null $NO.LOAD: db '?Nothing Loaded',null $ILL.MEM: db '?Out of memory',null $ILL.POL: db '?Illegal Polish Exp',null ; ; #################### ; ## ERROR ROUTINES ## ; #################### ; readerr: ld a,(commflg) or a jp nz,commrderr loaderr: ld hl,$LOAD.ERR jp ErFilRes ; Tell load error polisherr: ld hl,$ILL.POL jp ErFilRes ; Tell expression error memerr: ld hl,$ILL.MEM ; Tell out of memory ErFilRes: xor a ld (commflg),a jp anyerrmsg nothlod: ld hl,$NO.LOAD jp anyerrmsg ; Tell nothing loaded cmderr: ld hl,$CMD.ERR ; Tell input error anyerrmsg: call puts rego: xor a ld (CCPbuf),a ; Clear input from CCP ; ; -->> Entry of L80 ; go80:: ld hl,(mystack) ; Get stack ld sp,hl ld hl,headflg ld a,(hl) or a ; Test head given jp nz,headnot inc (hl) ld hl,$HEAD ; .. tell what we are call puts headnot: ld a,1 ld (iniflg1),a xor a ld (iniflg2),a call getcmdline ld a,(_PSW_) and .Xopt+.Yopt ; Mask bits from processing ld (_PSW_),a nxdeltst: call getcmdchar ; Get file and/or option jp c,cmderr ; .. syntax error delimtest: cp cr ; Test end jp z,itemend cp ',' ; Test file separator jp z,itemend cp '/' ; Test option jp nz,cmderr ; .. should be call CmdUPPER ; Get next character ld bc,level1 push bc ; Set execution after success cp 'M' jp nz,notokM ld b,.Mopt ; Set /M.ap list ret notokM: cp 'G' ld b,.Gopt ; Set /G.o after linking ret z cp 'R' jp z,L80.restart ; Process /R.eset LINK80 cp 'S' ld b,.Sopt ; Set /S.earch library ret z cp 'U' ld b,.Uopt ; Set /U.ndefined list ret z cp 'X' ld b,.Xopt ; Set /X -> produce COM file ret z cp 'Y' ld b,.Yopt ; Set /Y -> produce HEX file ret z cp 'E' jp nz,notokE ld b,.Eopt ; Set /E.xit to OS ret prepexit: call GetExec ; Prepare execution call l083a ld bc,0 push bc jp exfer .OS: jp OS notokE: cp 'O' ; Test /O.ctal radix jp nz,notokO ld (radixmod),a ; Set radix ld b,0 ; .. clear flag ret notokO: sub 'H' ; Test /H.ex radix jp nz,tsttokmore ld (radixmod),a ; Set radix ld b,a ; .. clear flag ret ; ; Exit from option setting ; level1:: ld a,(_PSW_) or b ; Insert new option ld (_PSW_),a call CmdUPPER cp ':' ; Test name input jp nz,delimtest push de ld a,.Gopt+.Eopt ; Test /G or /E selected and b jp z,cmderr ; .. should be call decodecmd ; Sample expression ex de,hl ld de,$Name ld a,b ; Test any or a jp z,cmderr ; .. should be cp _ModLen ; Test length in range jp nc,cmderr ; .. should be ld (de),a ; Set length inc de collect: call CmdUPPER ld (de),a ; Sample name inc de dec b jp nz,collect call CmdUPPER ; Get next pop de jp delimtest ; .. decode itemend: ld (curcmdpnt),hl ; Save buffer IF NOT _MODS ld c,.curdsk call BDOS ; Get current disk push af ; .. save ld c,.resdsk call BDOS ; .. reset disk system pop af ld e,a ld c,.seldsk call BDOS ; Log current ENDIF ;NOT _MODS xor a ld (CCPbuf),a ; Clear line from CCP ld a,(ActiveFlg) ; Test file or a call nz,fopen_r ; .. prepare for reading xor a ld (CCPbuf),a ld bc,level2 push bc ; Set return ld hl,_PSW_ ld a,(hl) and NOT .Uopt cp (hl) ld (hl),a jp z,strtlink ; Process list undefined or a jp m,strtlink ; .. and map option ld a,(ActiveFlg) ; Test file requested or a jp z,LoadREL ; .. load it ld a,(hl) strtlink: and NOT .Sopt cp (hl) ; Test LIB search ld (hl),a jp nz,strtlnk2 ld a,(ActiveFlg) ; Test file or a ret z ld (iniflg2),a jp DoLoad ; Load if any strtlnk2: ld (iniflg2),a ld hl,(UnDefCnt) ; Test undefined ld a,h or l ret z ; .. no ; ; ; rdloop: call ReadItem ; Get item jp c,rdloop ; .. skip constant jp z,rdloop ; .. and address setting ld a,c cp _ENDPRG ; Test end of file ret z or a ; Test ENTRY jp nz,rdloop call SaveLabel ; Look for label jp c,rdlpsk1 ; .. new one ld a,(hl) and .Public ; Test entry jp nz,rdloop jp rdlpsk2 rdlpsk1: ld (CurSym),hl ; Set current jp rdloop rdlpsk2: call ExeLoad ld hl,(UnDefCnt) ld a,h or l ret z jp rdloop ; ; Exit from main loop ; level2:: ld hl,(curcmdpnt) ; Get line pointer ld a,(hl) and NoMSB cp cr ; Test end of line jp nz,nxdeltst ld a,(iniflg2) or a ld a,(_PSW_) jp z,l037e cp .Mopt ; Test map option call l0bd1 l036f: ld b,a and .Gopt ; Test global option jp nz,l0803 ld a,b and .Eopt ; Test end option jp nz,prepexit jp rego l037e: cp .Mopt ; Check map option call nc,l0bd1 ; .. yeap jp l036f ; $HEAD: db cr,lf,'Link-80 ' IF V3.43 db '3.43 14-Apr-81' ELSE db '3.44 09-Dec-81' ENDIF ; V3.43 db ' Copyright (c) 1981 Microsoft',cr,lf,null $CMD.ERR: db '?Command Error',null ; ; Print string on console ; ENTRY Reg HL points to zero closed string ; puts: ld a,(hl) or a ret z ; .. test end call putc ; .. else print inc hl jp puts ; ; Get UPPER case from command line ; ENTRY Reg HL points to string ; EXIT Accu holds UPPER case character ; CmdUPPER: ld a,(hl) ; Get character and NoMSB inc hl cp ' ' ; Skip blanks jp z,CmdUPPER cp lf ; .. and LFs jp z,CmdUPPER cp 'a'-1 ; Test range a..z jp c,SkpUPPER cp 'z'+1 jp nc,SkpUPPER sub 'a'-'A' ; .. map into A..Z SkpUPPER: cp cr ; Check end of line ret nz dec hl ; .. freeze pointer if so ret ; ; Process CCP command line ; EXIT Reg HL points to start of input ; getcmdline: push de push bc ld hl,CCPbuf ld a,(hl) ; Test any in buffer or a ld b,a skpblcmd: jp z,nullcmd inc hl ld a,(hl) cp ' ' jp nz,movecmd ; Skip leading blanks dec b jp skpblcmd movecmd: ld de,rdbuff+1 ; Init local buffer ld a,b dec hl inc b unpkcmd: ld (de),a ; Unpack CCP line inc de inc hl dec b jp z,rdymove ld a,(hl) jp unpkcmd nullcmd: ld a,(iniflg1) ; Test state or a jp z,noast call nl ; Give new line ld a,'*' call putc ; Indicate mode noast: ld c,.getlin ld de,rdbuff call BDOS ; .. get from console ld a,lf call putc ; .. close line rdymove: ld a,(rdbuff+1) ld hl,rdbuff+2 push hl add a,l ld l,a ld a,0 adc a,h ; Point to end ld h,a ld (hl),cr ; .. close line pop hl pop bc pop de ret tsttokmore: sub 'P'-'H' ; Test /P.rogram start scf jp z,prgorg sub 'D'-'P' ; Test /D.ata start jp z,prgorg sub 'N'-'D' ; Test /N.ew output file IF _MODS jp nz,more.opts? ; .. maybe more ELSE jp nz,cmderr ; .. should be ENDIF ;_MODS call CmdUPPER cp cr ; Test /N only jp z,toklinend cp ':' ; Test /N:P dec hl jp nz,toklinend inc hl call CmdUPPER cp 'P' ; .. verify jp nz,cmderr ld (Sav.Prg),a ; Set flag toklinend: xor a ld (ActiveFlg),a ; Reset file flag push hl ld de,rFCB ld hl,wFCB ld bc,.drv+.nam+.ext call .LDIR ; Copy file name pop hl ret prgorg: push af call CmdUPPER ; Get next cp ':' jp nz,cmderr ; .. must be delimiter call scanf ; Get number pop af push hl ld b,a adc a,a add a,a ld c,a jp nz,dataorg ld a,(wrkb12) or a jp nz,dataorg call l06e5 ex de,hl push hl ld bc,0 call GetBottom ld (resv1),hl ld (resv3),hl pop hl ld (_prog),hl ; Set $PROG address ld (resv4),hl ld hl,(topw2) push hl ld hl,(topw1) ld (topw2),hl ld (DATpt),hl ; Set DSEG call SegAdr ; Calculate segment addresses pop de ld hl,(topw1) ex de,hl call SubHL.DE ld hl,(topw3) add hl,de or a call l1b06 ld b,d ld c,e ld hl,(topw1) ex de,hl ld hl,(topw3) push hl push de call LD.Dwn ; Move down ld (PRGpt),hl ; Set top of CSEG xor a ld (SegFlg),a ; .. clear segment flag ld b,a inc a ld (wrkb12),a ; .. set flag pop de pop hl push af jp l05d1 IF _MODS ; ; Test more options if expand mode selected ; more.opts?: cp 'Z'-'N' ; Test /^Z to last record jp z,_OptZ cp 'L'-'N' ; Test /L.ess zero header jp nz,cmderr ; .. should be ; ; >>>> OPTION /L <<<< ; ; Disable zero filling at start of file ; ld a,TRUE ld (@Lopt),a ; Set /L.ess flag ret ; ; >>>> OPTION /Z <<<< ; ; Enable EOFs as filler of last record instead of zeroes ; _OptZ: ld a,eof ld (@Zopt),a ; .. save ret ENDIF ;_MODS ; ; Clear data field ; ENTRY Reg DE points to start of buffer ; Reg HL points to end of buffer ; ClrData: push de call SubHL.DE ; Get difference pop hl ld a,d ; Test remainder or e ret z ; .. nope ClrLoop: ld (hl),0 ; .. clear field inc hl dec de ld a,d or e jp nz,ClrLoop ret ; ; ; dataorg: push af jp c,l051e ld a,(wrkb12) or a jp nz,l051e ld c,a l051e: call l06e5 pop af push af jp c,l0534 push de call GetTop1 call GetTop2 call cmpHL.DE ; Compare pointers jp z,l057b ; .. same pop de l0534: call GetBottom ex de,hl call SubHL.DE jp nc,l058e push hl ld hl,0 call SubHL.DE call GetTop1 push hl add hl,de push bc ld a,c call l1b0b pop bc ex de,hl ex (sp),hl call GetTop2 push de call SubHL.DE ld a,c ld b,d ld c,e pop de pop hl add hl,de push hl push de push af call LD.Dwn ; Move down pop af ld c,a pop de pop hl call ClrData ; Clear field call GetTop2 pop hl pop af ret c push af push hl ld hl,DATpt ; Get DSEG add hl,bc ld (hl),e inc hl ld (hl),d l057b: pop de ld hl,_prog ; Get base add hl,bc ld (hl),e ; .. save address inc hl ld (hl),d pop af ret c ld hl,resv4 add hl,bc ld (hl),e inc hl ld (hl),d pop hl ret l058e: push de ex de,hl call GetTop inc de call cmpHL.DE ; Compare pointers dec de push af call nc,ovlnl ; .. HL > DE pop af pop hl ex (sp),hl push af push hl pop af jp c,l05ac ld hl,resv4 add hl,bc ld (hl),e inc hl ld (hl),d l05ac: pop de pop hl push de push af call GetTop2 add hl,de ex de,hl ld hl,DATpt ; Get DSEG add hl,bc pop af push af jp c,l05c1 ld (hl),e inc hl ld (hl),d l05c1: pop hl pop af push hl jp nc,l05d4 call GetTop1 ex de,hl ld a,c push bc call l1b0b pop bc l05d1: call ClrData ; Clear field l05d4: pop af ret c pop hl ret ; ; ENTRY Reg BC holds offset ; EXIT Reg HL holds ???? ; GetBottom: ld hl,_prog ; Point to base ; ; ENTRY Reg BC holds offset ; Reg HL holds ???? ; EXIT Reg HL holds ???? ; getpntany: add hl,bc ; Build pointer ld a,(hl) ; .. fetch content inc hl ld h,(hl) ld l,a ret ; ; ENTRY Reg BC holds offset ; GetTop1: ld hl,topw2 jp getpntany ; ; Get difference of ???? ; EXIT Reg HL holds difference ; Zero flag set indicates same amount ; getamount: push de call GetTop1 ; Get 1st pointer call GetTop2 ; .. 2nd pointer call SubHL.DE ; .. get difference ex de,hl pop de or l ret ; ; ENTRY Reg BC holds offset ; EXIT Reg DE holds ???? ; GetTop2: ex de,hl ld hl,topw1 call getpntany ; Get content ex de,hl ; .. swap reg ret ; ; Get top pointer ; ENTRY Reg BC holds offset ; EXIT Reg HL holds ???? ; GetTop: push de call GetBottom ; Get 1st pair call GetTop2 call SubHL.DE ; .. build difference call GetTop1 ; Get 2nd pointer add hl,de ; .. build top address pop de ret ; ; DE:=HL-DE ; SubHL.DE: ld a,l sub e ; .. subtract ld e,a ld a,h sbc a,d ld d,a ret ; ; Calculate segment addresses ; SegAdr:: ld a,1 ld (SegFlg),a ; Set segment flag ld hl,(_prog) ; Get start of program ex de,hl ld hl,(resv1) call SubHL.DE jp c,l063c ld hl,(topw2) add hl,de ex de,hl ld hl,(TopExpr) ; Get expression pointer ld a,(wrkb12) ; Test flag or a jp z,l063c call cmpHL.DE ; Compare pointers jp nc,l0650 ; .. HL > DE l063c: ld hl,(topw2) ex de,hl ld hl,(TopExpr) ; Get expression pointer call SubHL.DE rra ; Divide by two ld d,a ld a,e rra ld e,a ld hl,(topw2) add hl,de ; .. add half ex de,hl l0650: ex de,hl inc hl ld (topw3),hl ld (topw4),hl ld (PRGpt),hl ; .. and CSEG ret ; ; Input number depending on radix ; ENTRY Reg HL points to ASCII presentation ; EXIT Reg DE holds number ; scanf: ld de,0 ; Clear result ld a,(radixmod) ld b,a ; Get radix ex de,hl nextdigit: ex de,hl call CmdUPPER ; Fetch digit ld c,a sub '0' ; Test end jp c,numbend cp 10 ; Test 0..9 jp c,insertdigit sub 'A'-'9'-1 ; .. fix for A..Z jp c,numbend insertdigit: ex de,hl add hl,hl ; * 2 add hl,hl ; * 4 add hl,hl ; * 8 cp 16 ; Test done jp nc,numbendswap inc b dec b jp z,doinsert ; Check mode cp 8 jp nc,numbendswap .MVI.C doinsert: add hl,hl ; * 16 on hex add a,l ; Add digit ld l,a ld a,0 adc a,h ld h,a jp nextdigit numbendswap: ex de,hl ; Set right register numbend: ld a,c ; Get last character cp cr ; Test CR ret z dec hl ; Fix pointer if not ret ; $OVL.MES: db '%Overlaying ',null $OVL.AREA: db ' area',null SegTab: dw $DATA dw $PRGM $DATA: db 'Data',null $PRGM: db 'Program',null ; ; ; ovlnl: call ovltlerr jp nl ; .. give new line ; ; ; ovltlerr: push hl ld hl,$OVL.MES l06cb: call puts ld hl,SegTab add hl,bc ld a,(hl) inc hl ld h,(hl) ld l,a call puts ld hl,$OVL.AREA call puts pop.hl: pop hl ret ; ; ; l06e1: push hl jp l06cb ; ; ; l06e5: push hl push bc ld bc,0 l06ea: call GetBottom inc de call cmpHL.DE ; Compare pointers dec de jp nc,l0715 ; .. HL > DE push hl call GetTop ex de,hl ex (sp),hl call cmpHL.DE ; Compare pointers pop hl ex de,hl jp z,l0715 ; .. same call cmpHL.DE ; Compare pointers jp c,l0726 ; .. HL < DE pop hl ld a,l inc a jp z,l0720 dec a cp c call nz,ovlnl push hl l0715: inc c inc c ld a,c cp 4 jp nz,l06ea l071d: pop bc pop hl ret l0720: push hl ld a,c scf jp l071d l0726: ex de,hl ex (sp),hl push bc ld a,c ld c,l cp c push hl scf jp z,l073e inc l jp z,l073e call GetBottom inc hl ex de,hl call cmpHL.DE ; Compare pointers ex de,hl l073e: pop hl pop bc pop de push hl jp c,l0715 ; .. HL < DE ld hl,$INTER.SECT call l06e1 ; .. intersecting error jp rego ; ; Print tabulator on console ; put.tab: ld a,tab ; ; Print character on console ; ENTRY Accu holds character ; putc: push af push bc push de push hl ld c,.conout and NoMSB ; .. no MSB ld e,a ; Get character call BDOS ; .. print pop hl pop de pop bc pop af ret ; ; Tell file not found ; prfile: ld hl,rFCB+.drv ld a,'?' call putc ; Indicate ld b,.nam prfilnam: ld a,(hl) inc hl call putc ; Give name cp ' '+1 ; .. till blank jp c,tstfilext dec b jp nz,prfilnam tstfilext: ld hl,$NOT.FOUND ; Give message ld a,(commflg) or a jp z,errjmp ld hl,$NO.HEADER ; .. no header errjmp: jp ErFilRes ; $NOT.FOUND: db ' Not Found',null ; ; Close line on console ; nl: ld a,cr ; Give CR call putc ld a,lf ; .. and LF jp putc ; ; Prepare file for reading ; fopen_r: ld a,RecLng ld (FileByte),a ; Force read ld de,mDMA ld c,.setdma call BDOS ; Set disk buffer ld de,rFCB call PrepFCB ld c,.open call BDOS ; Open file inc a jp z,prfile ; Test on disk ld a,-1 ld (BitCnt),a ; Init bit count ret ; ; Read byte from file ; fget: push hl push de ld a,(FileByte) ; Get pointer or a call m,ReadRec ; .. read record ld e,a ld d,0 inc a ld (FileByte),a ld hl,mDMA add hl,de ; Point to buffer ld a,(hl) ; .. get byte pop de pop hl ret ; ; Read record from file ; ReadRec: push bc ld c,.setdma ld de,mDMA call BDOS ; Set disk buffer ld de,rFCB ld c,.rdseq call BDOS ; Read record pop bc or a jp nz,readerr ; Test end xor a ret ; ; Prepare FCB for opening ; ENTRY Reg DE points to FCB ; PrepFCB: ld hl,_EX ; Point to extent add hl,de xor a ld b,4 clrfcbx: ld (hl),a ; .. clear bytes inc hl dec b jp nz,clrfcbx ld hl,_CR add hl,de ld (hl),a ; .. clear current record ret ; ; ; l0803: call GetExec ; Prepare execution ld a,h or l ; Test success ex de,hl ld hl,$NO.STRT jp z,anyerrmsg ; .. nope, tell no start ex de,hl push hl call l083a push hl ld hl,$TELL.EX call puts ; Tell start of execution call nl ld hl,(ExecAdr) ; Get execution address ld b,h ld c,l pop hl push bc jp exfer ; $TELL.EX: db '[Begin execution]',null ; ; ; l083a: ld a,(lodflag) ; Test any loaded or a jp z,nothlod ; .. nope, give error ld a,(UnDef?) ; Test undefined label or a jp z,l08c3 ; .. nope ld hl,(SymBase) l084b: ex de,hl ld hl,(CurSym) ex de,hl call cmpHL.DE ; Compare pointers jp z,l08c3 ; .. same, end of search ld a,(hl) and 0e0h cp 60h ld a,(hl) jp nz,l08a8 xor 40h ld (hl),a and 7 push hl dec hl dec hl dec hl cp 7 jp c,l086f ld a,7 l086f: ld b,a ld c,a ld de,SrcFN+.drv l0874: ld a,(hl) ld (de),a ; Unpack file name dec hl inc de dec b jp nz,l0874 ld a,7 sub c jp z,l088a ex de,hl l0883: ld (hl),' ' inc hl dec a jp nz,l0883 l088a: pop de ld hl,(SymBase) call SubHL.DE push de ld hl,SrcFN call CopyFCB ; Copy to file name xor a ld (UnDef?),a ; .. clear flag call LoadREL ; .. load it ld hl,(SymBase) pop de call SubHL.DE ex de,hl ld a,(hl) l08a8: ld c,a and 7 ld e,a ld d,0 call SubHL.DE ex de,hl dec hl dec hl dec hl ld a,c or a jp p,l08bc dec hl dec hl l08bc: ld a,(UnDef?) ; Test more undefined or a jp nz,l084b ; .. yeap l08c3: call nl ld a,(_PSW_) and .Xopt+.Yopt ; Reset bits ld (_PSW_),a call LoadREL ; .. load it ld hl,(ExecAdr) ; Get execution address ld a,'[' call putc call printf ; .. print address call put.tab ld bc,0 call GetTop push hl ld hl,$$PROG call l0b20 ; Find $$PROG jp c,l08fc ; .. unknown jp z,l08fc ; .. not public call l1e5e ld hl,(_prog) ; Get address ex de,hl ld (hl),e ; .. save inc hl ld (hl),d l08fc: ld hl,$COMNM call l0b20 ; Find $COMNM jp c,l0916 ; .. unknown jp z,l0916 ; .. not public call l1e5e ld hl,wrkb1 l090e: ld a,(hl) ld (de),a inc hl inc de or a jp nz,l090e l0916: ld hl,$MEMRY call l0b20 ; Find $MEMRY jp c,l093d ; .. unknown jp z,l093d ; .. not public call l1e5e ld hl,(TopExpr) ; Get expression pointer ex de,hl call cmpHL.DE ; Compare jp nc,l093d ; .. HL > DE ld de,topl80 call cmpHL.DE ; Compare jp c,l093d ; .. HL < DE pop de ld (hl),e inc hl ld (hl),d push de l093d: pop hl ; Get address push hl call printf ; .. print call put.tab xor a ld (ExprCnt),a ; Clear expression count ld hl,(CurExpr) ; Get pointers ex de,hl l094d: ld hl,(TopExpr) ; Get top call cmpHL.DE ; Test end jp z,l0a90 ; .. yeap ld a,(de) and 00000111b ; Mask cp 00000111b ; Test mask jp z,l0985 ld a,(de) sub 11000101b ; Calculate address mode ld (AddrMode),a push de call l1a4f call l1e5e ex de,hl ld a,(AddrMode) or a ; Test ABS jp nz,l097a ; .. nope ld a,b cpl ; Get one's complement ld b,a ld a,c cpl ld c,a inc bc ; .. make two's complement l097a: ld a,(hl) add a,c ld (hl),a inc hl ld a,(hl) adc a,b ld (hl),a pop de jp l094d l0985: push de call l1a4f pop hl ld (l20b3),hl ld a,d and 0fh cp 0ch jp nc,l09d1 rlca ld e,a ld a,d ld d,0 ld hl,l09a3 add hl,de ld e,(hl) inc hl ld d,(hl) ex de,hl jp (hl) ; ; ; l09a3: dw l09bb dw l09e2 dw l09e2 dw l09fb dw l0a04 dw l0a0a dw l0a13 dw l0a24 dw l0a32 dw l0a3d dw l0a5d dw l0a6d ; ; ; l09bb: ld h,b ld l,c or a jp p,l09c5 ld e,(hl) dec hl ld d,(hl) ex de,hl l09c5: push hl ld hl,ExprCnt inc (hl) ; Bump expression count l09ca: ld hl,(l20b3) ex de,hl jp l094d l09d1: ld hl,ExprCnt inc (hl) ; Bump expression count jp l0a90 ; ; ; l09d8: ld hl,ExprCnt dec (hl) ; Count down expression count jp m,l0a90 ; .. underflow pop hl ex (sp),hl ret ; ; ; l09e2: push af ld d,b ld e,c call l1e5e pop af call l09d8 jp nz,l0a90 ex de,hl ld (hl),e cp 2 jp nz,l09ca inc hl ld (hl),d jp l09ca ; ; ; l09fb: call l09d8 ld l,h l09ff: xor a ld h,a jp l09c5 ; ; ; l0a04: call l09d8 jp l09ff ; ; ; l0a0a: call l09d8 call neghl jp l09c5 ; ; ; l0a13: call l09d8 call neghl inc hl jp l09c5 ; ; ; neghl: ld a,h cpl ld h,a ld a,l cpl ld l,a ret ; ; ; l0a24: call l09d8 ex de,hl call l09d8 call SubHL.DE ex de,hl jp l09c5 ; ; ; l0a32: call l09d8 ex de,hl call l09d8 add hl,de jp l09c5 ; ; ; l0a3d: call l09d8 ex de,hl call l09d8 ld b,h ld c,l ld hl,0 ld a,17 l0a4b: dec a jp z,l09c5 add hl,hl push hl push bc pop hl add hl,hl ex (sp),hl pop bc jp nc,l0a4b add hl,de jp l0a4b ; ; ; l0a5d: call l09d8 ex de,hl call l09d8 ld a,d or e call nz,l0a7f l0a69: ex de,hl jp l09c5 ; ; ; l0a6d: call l09d8 ex de,hl call l09d8 ld a,d or e jp z,l0a69 call l0a7f jp l09c5 ; ; ; l0a7f: ld b,d ld c,e ld de,-1 l0a84: ld a,l sub c ld l,a ld a,h sbc a,b ld h,a inc de jp nc,l0a84 add hl,bc ret ; ; ; l0a90: pop hl ld bc,0 call GetTop ld a,(wrkb12) or a jp z,l0aab ex de,hl ld c,2 call GetTop call cmpHL.DE ; Compare pointers jp nc,l0aab ; .. HL > DE ex de,hl l0aab: ld de,TPA xor a sub l ld a,h adc a,0 sub d call DecimByte ld a,']' call putc ; .. close call nl ld a,(ExprCnt) ; Tell expression count or a jp nz,polisherr ; .. should be zero ld a,(wFCB+.drv) ; Test output file or a call nz,PrepFO ; .. yeap, prepare it ld a,.JP ; Set JP code ld (L80.restart),a ld hl,(ExecAdr) ; Get execution address ld (L80.restart+1),hl jp l2113 ; ; Print decimal byte ; ENTRY Accu holds byte ; DecimByte: ld l,a ; .. expand to 16 bit ld h,0 ; ; Print decimal word ; ENTRY Reg HL holds word ; DecimWord: push de ld c,0 ; Clear zero flag ld de,10000 call DecDigit ; Print 10000s ld de,1000 call DecDigit ; .. 1000s ld de,100 call DecDigit ; .. 100s ld de,10 call DecDigit ; .. 10s ld a,'0' add a,l ; Make units ASCII ld b,a pop de jp decprnt ; ; Print decimal digit ; ENTRY Reg HL holds word ; Reg DE holds current digit position ; EXIT Reg HL fixed to new digit ; DecDigit: ld b,'0'-1 decloop: inc b ld a,l sub e ld l,a ld a,h sbc a,d ld h,a jp nc,decloop add hl,de ld a,b sub '0' jp nz,decprnt cp c jp nz,decprnt ld b,' ' .MVI.A decprnt: inc c ld a,b jp putc ; ; Find special label ; ENTRY Reg HL points to label to be searched ; EXIT Carry set if ??? ; Zero set if ??? ; l0b20: ld de,ItemName ld a,6 ld (de),a ld b,a l0b27: ld a,(hl) inc hl inc de ld (de),a dec b jp nz,l0b27 xor a call SaveLabel ; Look for label ret c ; .. unknown ld a,(hl) and .Public ; Check entry ret z ; .. no dec hl ld e,(hl) ; Fetch address dec hl ld d,(hl) ret ; $MEMRY: db '$MEMRY' $$PROG: db '$$PROG' $COMNM: db '$COMNM' ; ; Prepare execution ; EXIT Reg HL holds execution address ; GetExec: ld hl,(ExecAdr) ; Get execution address ld de,$Name ; Get name of label ld a,(de) or a ; Test any length ret z ; .. nope ld hl,ItemName ld b,.LenMsk l0b5d: ld a,(de) ; Unpack name ld (hl),a inc hl inc de dec b jp nz,l0b5d xor a call SaveLabel ; Find label jp c,StrtErr ; .. unknown ld a,(hl) and .Public ; Test entry jp z,StrtErr ; .. should be dec hl ld e,(hl) ; Get address dec hl ld d,(hl) ex de,hl ld (ExecAdr),hl ; .. save it ret StrtErr: push hl ; .. save symbol pointer ld hl,$NO.STRT.SYM call puts ; Tell undefined start label pop hl call PrLabel ; .. give name of label xor a ld ($Name),a ld hl,$UNDEF jp ErFilRes ; $NO.STRT.SYM: db '?Start symbol - ',null $UNDEF: db ' - undefined',null ; ; Copy file name, open it ; ENTRY Reg HL points to original file ; CopyFCB: ld de,rFCB ld b,.drv+.nam+.ext copyflop: ld a,(hl) and NoMSB ld (de),a inc hl inc de dec b jp nz,copyflop call fopen_r ; .. open file jp strtlnk2 ; SrcFN: db 0,' REL' ; .ORI LoadREL: scf ; ; ENTRY Carry flag reset on map option ; l0bd1:: push af ; Save state ld hl,(UnDefCnt) ; Get undefined count ld a,l or h ld (UnDef?),a ; .. build flag ld a,(_PSW_) and .Gopt+.Eopt ; Test /E or /G option jp z,nogoexit pop af ; Get state ret c ; .. no map push af jp xload nogoexit: ld c,0 call TelLoadMode ; Tell main mode ld a,(wrkb12) or a ld c,2 call nz,TelLoadMode ; .. with other offset call nl xload: pop af jp c,skpxlo ld b,0c0h call l0c70 ld b,40h call l0c70 call nl skpxlo: ld b,60h call l0c70 ld b,80h call l0c70 ld b,0 call l0c70 ld hl,(SymBase) l0c1c: call l0d7d jp z,l0c2c ld a,0efh and (hl) ld (hl),a call l0d6b jp l0c1c l0c2c: call l0cf6 ld a,(UnDefCnt) or a jp z,NoUndef call DecimByte ld hl,$UNDEFINED call puts ; .. tell undefined globals NoUndef: ld hl,(freebytes) call DecimWord ld hl,$FREE jp puts ; .. give free bytes ; $UNDEFINED: db ' Undefined Global(s)',cr,lf,null $FREE: db ' Bytes Free',cr,lf,null ; ; ; l0c70: xor a ld (l1f64),a l0c74: call l0d50 jp c,l0cf6 call l0d02 push hl ld a,(hl) and 7 ld c,a ld a,(hl) and 0e0h ld a,'-' jp z,l0c91 ld a,' ' jp p,l0c91 ld a,'/' l0c91: call putc push af dec hl ld e,(hl) dec hl ld d,(hl) l0c99: dec hl ld a,(hl) call putc dec c jp nz,l0c99 pop af cp '/' call z,putc call put.tab ex (sp),hl ld a,(hl) and 20h ex de,hl jp z,l0cbc ld hl,$RQST call puts ; Tell request jp l0cbf l0cbc: call printf ; Print value l0cbf: ex de,hl ld a,(hl) or a ex (sp),hl jp p,l0cdb call put.tab dec hl ld e,(hl) dec hl ld d,(hl) ex de,hl ld a,'<' call putc call DecimWord ld a,'>' call putc l0cdb: call put.tab ld a,(l1f64) cp 2 ccf adc a,1 and 3 ld (l1f64),a call z,nl pop hl ld a,10h or (hl) ld (hl),a jp l0c74 ; ; ; l0cf6: ld a,(l1f64) or a ret z xor a ld (l1f64),a jp nl ; ; ; l0d02: push bc push hl l0d04: call l0d6b l0d07: call l0d5b jp c,l0d4d jp nz,l0d07 pop de ex de,hl push hl push de ld a,(hl) dec hl dec hl and 7 ld b,a ld a,(de) dec de dec de and 7 ld c,a push bc cp b jp c,l0d26 ld c,b l0d26: dec de dec hl ld a,(de) cp (hl) jp c,l0d44 jp nz,l0d3b dec c jp nz,l0d26 pop bc ld a,c cp b jp c,l0d45 .MVI.A l0d3b: pop bc pop hl pop de pop bc push bc push de jp l0d04 l0d44: pop bc l0d45: pop hl pop de pop bc push bc push hl jp l0d04 l0d4d: pop hl pop bc ret l0d50: ld hl,(SymBase) l0d53: call l0d5b ret c ret z jp l0d53 ; ; ; l0d5b: call l0d7d scf ret z ld a,(hl) and 10h jp nz,l0d6b ld a,(hl) and 0e0h cp b ret z l0d6b: ld a,(hl) or a jp p,l0d72 inc a inc a l0d72: and 0fh add a,2 cpl ld e,a ld d,-1 add hl,de or a ret ; ; ; l0d7d: ex de,hl ld hl,(CurSym) ex de,hl jp cmpHL.DE ; .. fall in compare ; ; Compare addresses ; ENTRY Regs HL and DE hold addresses ; EXIT Zero set if equal ; Carry set if HL < DE ; cmpHL.DE: ld a,h ; Check HI sub d ret nz ; .. exit if .NEQ. ld a,l ; .. check LO sub e ret ; ; Write symbol table ; WrtSym: ld hl,wFCB+.drv+.nam ld (hl),'S' ; Set extension .SYM inc hl ld (hl),'Y' inc hl ld (hl),'M' call fopen_w ; Create file ld a,SymCol ; Init symbol column push af ld hl,(SymBase) ; Init symbol base WrtSym.loop: ex de,hl ld hl,(CurSym) ex de,hl call cmpHL.DE ; Test symbols written jp z,SymWrt.end ; .. end ld a,(hl) and .LenMsk ; Get count ld c,a ld a,(hl) and .Public ; Test entry jp z,SymWrt.skp ; .. no push hl dec hl ld e,(hl) ; Fetch value dec hl ld d,(hl) ex de,hl call hexhl ; .. print it ex de,hl ld a,' ' call fput ; Give delimiter SymWrt.Label: dec hl ld a,(hl) ; Print label call fput dec c jp nz,SymWrt.Label ld a,tab call fput ; Give tab pop hl pop af ; Get counter dec a ; Check line filled jp nz,WrtSym.NoNL call fnl ; Close line ld a,SymCol WrtSym.NoNL: push af SymWrt.skp: ld a,(hl) ; Get flag and count or a ; Test COMMON jp p,WrtSym.NoCOMMON inc a ; .. fix count if so inc a WrtSym.NoCOMMON: and LoMask ; Get length add a,2 ; .. add address length cpl ; Make negative ld c,a ld b,-1 add hl,bc ; Point to next label jp WrtSym.loop SymWrt.end: pop af cp SymCol call nz,fnl ; Close line call fput.eof ; Give EOF jp fclose ; Close .SYM file ; ; Put hex value to file ; ENTRY Reg HL holds hex value ; hexhl: ld a,h ; Put HI byte call hexhlbyte ld a,l ; .. then LO byte hexhlbyte: push af rrca ; Get HI nibble rrca rrca rrca call hexhlnibble pop af push af ; .. then LO nibble call hexhlnibble pop af add a,b ld b,a ret hexhlnibble: call nibbleget ; Get ASCII jp fput ; .. put to file ; ; Give new line to file ; fnl: ld a,cr ; Simple CR/LF call fput ld a,lf jp fput ; ; Print number in requested mode ; ENTRY Reg HL holds number to be printed ; printf: ld a,(radixmod) ; Check radix or a jp z,hexprint ; .. hex ; ; %%% OCTAL %%% ; xor a add hl,hl ; Get HI bit as 1st octal adc a,'0' ; .. make ASCII call putc ; .. print push bc ld b,5 ; 16 DIV 3 -> 5 oktloop: xor a ld c,3 ; Set bit count getoktal: add hl,hl ; Get bits adc a,a ; .. into accu dec c jp nz,getoktal add a,'0' ; Make ASCII call putc ; .. print dec b ; Test all done jp nz,oktloop pop bc ret ; ; %%% HEXADECIMAL %%% ; hexprint: ld a,h ; Get HI byte call byteprint ld a,l ; .. then LO byte byteprint: push af rrca ; Get HI nibble rrca rrca rrca call nibprint pop af ; .. then LO nibble nibprint: call nibbleget ; Get ASCII jp putc ; .. put to console ; ; Get ASCII representation of hex nibble ; ENTRY Accu holds hex nibble ; EXIT Accu holds ASCII character ; nibbleget: and LoMask ; Get four bits add a,'0' ; Add ASCII offset cp '9'+1 ; Test hex ret c add a,'A'-'9'-1 ; Fix for A..F ret ; ; >>> DUMMY CODE <<< ; l0e69:: call nl pop af ret ; ; Give statistic about loading in form: ; ; Data strt end ; Program strt end ; ; ENTRY Reg C holds index 0 or 2 ; TelLoadMode: ld hl,SegTab ld b,0 add hl,bc ld a,(hl) inc hl ld h,(hl) ld l,a call puts ; Tell Data/Program call put.tab call GetBottom ; Get start call printf ; .. print call put.tab call GetTop ; Get top call printf ; .. print call put.tab ld a,'<' call putc call getamount ; Get length call DecimWord ; .. print ld a,'>' call putc jp nl ; $RQST: db 'RQUEST',null ; ; Start load of LIB file ; DoLoad: call ExeLoad ; .. load jp DoLoad ; ; ; ExeLoad: ld hl,(SymBase) ; Get symbol base ld a,(SpcCase) ; Test special # request or a jp z,BegLoad ; .. nope l0eb6: ex de,hl ld hl,(CurSym) call cmpHL.DE ; Test table scanned ex de,hl jp z,BegLoad ; .. yeap ld a,(hl) and .LenMsk ; Get count ld e,a ld d,0 ld a,(hl) push hl and .Public ; Test entry jp z,l0ef0 ; .. nope dec hl dec hl dec hl ld a,(hl) sub '#' ; Test special jp nz,l0ef0 ; .. nope call SubHL.DE ld hl,(CurSym) ex de,hl call SubHL.DE ld b,d ld c,e ex de,hl pop hl push hl call .LDDR ; Move down ld (CurSym),hl ; .. set top pop hl jp l0eb6 ; Try next l0ef0: pop hl call SubHL.DE ; Fix pointer ex de,hl dec hl dec hl dec hl jp l0eb6 ; .. try next ; ; Start loading ; BegLoad:: xor a ld (commflg),a ; Init a bit ld (SegFlg),a ld (SpcCase),a ld (l20b7),a ld a,(wrkb12) or a call z,SegAdr ; .. init segment addreses xor a ld h,a ld l,a ld (l20b8),hl ; Init a bit ld (l20e8),hl ld (l20ea),hl ld (UnDef?),a ld (l20ec),hl inc a ld (_seg_),a ; Set CSEG ld a,(wrkb12) or a ld hl,(topw2) ex de,hl ld hl,(topw3) call nz,ClrData ; Clear data ld hl,(topw4) ex de,hl ld hl,(TopExpr) call ClrData ; .. clear data ld hl,(PRGpt) ; Get CSEG push hl ; ; Link item 0 : ENTRY ; LnkItm.0: pop hl call l1d9f ; ; The REL-80 stream processing ; RdRELloop: call ReadItem ; Read item jp nc,RdREL.Adr? ; Check constant call Byt.Seg ; .. process it jp RdRELloop RdREL.Adr?: jp nz,RdREL.Lnk ; Check 16 bit call Adr.Seg ; .. process it jp RdRELloop RdREL.Lnk: push hl ld b,0 ld hl,LinkTab add hl,bc ; Get link item control add hl,bc ld a,(hl) ; Get address inc hl ld h,(hl) ld l,a ld b,d ld c,e jp (hl) ; .. execute ; ; Store byte into current segment ; ENTRY Reg B holds byte to be stored ; Byt.Seg: push de push bc push hl inc hl ld a,(_seg_) ; Get segment dec a ; Test CSEG ex de,hl jp z,l0f9e ; .. yeap ld a,(l20ec) or a jp nz,l0f95 ld hl,(topw2) ld a,h sub d jp z,l0f8a jp nc,l0f95 jp nz,l0f8f l0f8a: ld a,l sub e jp nc,l0f95 l0f8f: ex de,hl IF V3.43 inc hl ENDIF ; V3.43 or a call l1b09 l0f95: pop hl call l1d9f pop bc ld (hl),b inc hl pop de ret l0f9e: ld a,(l20ed) or a jp nz,l0f95 ld hl,(topw4) ld a,h sub d jp z,l0fb3 jp nc,l0f95 jp nz,l0fb8 l0fb3: ld a,l sub e jp nc,l0f95 l0fb8: ex de,hl IF V3.43 inc hl ENDIF ; V3.43 or a call l1b06 jp l0f95 ; ; Store address into segment ; ENTRY Reg DE holds address ; Adr.Seg: push de ld a,(AddrMode) dec a ; Test CSEG jp nz,l0fed ; .. nope ld a,(SegFlg) ; Test segment flag or a jp z,l0fed ; .. no attached push hl call l1d57 ex de,hl ex (sp),hl call l1dd0 push hl ex de,hl sbc a,a and 80h ld (hl),a dec hl ld (hl),b dec hl ld (hl),c pop de pop bc dec hl ld (hl),b dec hl ld (hl),c ex de,hl ld de,-1 l0fed: inc hl call l1e21 ld b,d ; .. get byte call Byt.Seg ; .. store push hl dec hl dec hl ld (hl),e pop hl pop de ret ; ; Get character from command input ; ENTRY Reg HL points to current input ; EXIT Accu holds character ; Carry set on invalid input ; getcmdchar: ld (comstrtpnt),hl ; .. save buffer call decodecmd ; Decode chars cp ':' ; Test drive delimiter scf ld a,0 jp nz,nodrive ; Set default drive if not ex de,hl call CmdUPPER ; Get 1st FCB character cp 'Z'+1 ; .. test legal ccf ret c sub 'A'-1 ret c ex de,hl nodrive: ld (rFCB),a ; Save drive call nc,decodecmd ; Get file name if requested ld a,b cp .nam+.ext ; Test length of input jp c,maxfilein ld b,.nam+.ext ; .. truncate maxfilein: push bc ex de,hl push de ld de,rFCB+.drv ; Init name pointer inc b fillfile: dec b jp z,filegot call CmdUPPER ld (de),a ; Fill file name inc de jp fillfile filegot: pop hl pop bc ld a,.drv+.nam+1 ; Test room in name sub b jp c,filefull ex de,hl fileblnk: ld (hl),' ' ; Fill with blanks inc hl dec a jp p,fileblnk ex de,hl filefull: ld a,b ld (ActiveFlg),a ; Set file found ld a,c ld b,0 cp '.' ; Test delimiter push af call z,decodecmd ; Get more if so ex (sp),hl ex de,hl push de ld de,rFCB+.drv+.nam ld a,b cp .ext+1 ; Test length jp c,maxext ld b,.ext ; .. truncate if necessary maxext: inc b fillext: dec b jp z,extgot call CmdUPPER ld (de),a ; Unpack extension inc de jp fillext extgot: pop af jp z,nodefext ; Test extension given ld hl,rFCB+.drv+.nam ld a,(hl) ; Test blank cp ' ' jp nz,nodefext ld (hl),'R' ; Set default .REL inc hl ld (hl),'E' inc hl ld (hl),'L' nodefext: pop hl ld a,c ; Get last character or a ; .. set success ret ; ; Check valid characters in command line ; ENTRY Reg HL points to string ; EXIT Reg DE points to start of string ; Reg HL points at next invalid character ; Reg B holds length of valid characters ; Reg C and Accu hold last character fetched ; decodecmd: ld b,0 ; Clear count push hl deccnt: call CmdUPPER ; Get UPPER case cp 'Z'+1 ; .. check A..Z jp nc,decgtz cp '0' ; .. and 0..9 jp c,decgtz cp 'A' jp nc,decoklet cp '9'+1 jp nc,decgtz decoklet: inc b ; .. bump count jp deccnt decgtz: cp '[' ; Test special jp z,decoklet cp ']' jp z,decoklet cp '@' jp z,decoklet cp '\' jp z,decoklet cp '^' jp z,decoklet cp '_' jp z,decoklet ld c,a ; Save character pop de ; .. get back pointer ret ; ; Link item C : CHAIN ADDRESS ; LnkItm.C: ex de,hl pop de push de call IsMemOk? ; Verify memory in range ld a,(SegFlg) ; Test segment flag or a jp nz,l10f6 ; .. segments attached ld a,(_seg_) ; Get segment ld (AddrMode),a ; .. as address mode call l1e21 ld b,d ld c,e l10e0: ld a,h or l jp z,LnkItm.0 l10e5: ld a,(hl) ld e,a ld (hl),c inc hl l10e9: or (hl) ld d,(hl) ld (hl),b call l1e5e ex de,hl jp nz,l10e5 jp LnkItm.0 l10f6: ex de,hl push hl call l1d57 ld a,(AddrMode) dec a ; Test CSEG jp z,l1107 ; .. yeap call l1e21 ld a,80h ; .. set flag l1107: inc a ld b,a ld a,(_seg_) ; Get segment dec a ; Test CSEG jp z,l1112 ; .. yeap ld a,40h ; Set flag l1112: add a,b ld (hl),a dec hl ld (hl),d dec hl ld (hl),e dec hl pop de and 40h push hl call z,l17e5 pop hl call l1133 ld a,(_seg_) ; Get segment ld (AddrMode),a ; .. as address mode call l1e21 ld (hl),d dec hl ld (hl),e jp LnkItm.0 ; ; ; l1133: ld a,(_seg_) ; Get segment dec a ; Test CSEG ret nz ; .. nope push hl ld hl,(l20b8) add hl,de ex de,hl pop hl ret ; ; Link item 5 : COMMON SIZE ; LnkItm.5: ld a,.COMMON call SaveLabel ; Look for LABEL jp c,LI.5.new ; .. looks new push hl ; Save pointer ld a,(de) ; Get COMMON length cpl ; .. negate ld l,a dec de ld a,(de) cpl ld h,a add hl,bc ; Test against requested length jp c,IllCOMMlen ; .. too big pop hl jp LnkItm.0 LI.5.new: ld a,(hl) or .Public ; Set PUBLIC ld (hl),a ld a,(wrkb6) ld (wrkb7),a or a jp z,l1175 push hl dec hl dec hl dec hl ld a,(hl) pop hl cp 20h jp z,l1175 xor a ld (wrkb7),a l1175: ex de,hl ld (hl),c dec hl ld (hl),b push bc ld a,(wrkb7) ld c,a ld b,0 ld hl,DATpt ; Set DSEG call getpntany push hl dec de ex de,hl ld a,@COMM ld (AddrMode),a ; Set COMMON call l1e21 ex de,hl ld a,l ld (de),a dec de ld a,h ld (de),a pop hl pop de add hl,de ex de,hl ld hl,DATpt ; Get pointer add hl,bc ld (hl),e inc hl ld (hl),d call GetTop1 ex de,hl call cmpHL.DE ; Compare ld a,c call nc,l1b0b ; .. HL > DE jp LnkItm.0 IllCOMMlen: ld hl,$COMM.ERR ; Tell error call puts pop hl ; Get back name call PrLabel ; .. print COMMON ld a,'/' call putc ; .. give delimiter call nl jp LnkItm.0 ; ; Print name of label ; ENTRY Reg HL points to symbol ; PrLabel: ld a,(hl) ; Get control and .LenMsk ; .. extract length ld d,a dec hl ; .. point to symbol dec hl dec hl Pr.Label: ld a,(hl) ; Get label call putc ; .. print dec hl dec d jp nz,Pr.Label ret ; $COMM.ERR: db '%2nd COMMON Larger /',null ; ; Link item A : DATA SIZE ; LnkItm.A: ld hl,(DATpt) ; Get DSEG ex de,hl ld (l20e8),hl ex de,hl add hl,bc ld a,h ld (l20ec),a ex de,hl ld hl,(topw2) ex de,hl call cmpHL.DE ; Compare call nc,l1b09 ; HL > DE push hl call l191a pop hl jp LnkItm.0 ; ; Link item 3 : LIBRARY REQUEST ; LnkItm.3: ld a,.Libreq call SaveLabel ; .. find label ld a,(hl) or .Public ; .. force PUBLIC ld (hl),a jp LnkItm.0 ; ; Link item 8 : EXTERNAL - OFFSET ; LnkItm.8: .ORI ; ; Link item 9 : EXTERNAL + OFFSET ; LnkItm.9: scf push af call l1d57 ld a,(SegFlg) ; Test segment flag or a ld a,0c0h jp z,l123a ; .. not attached ld a,(_seg_) ; Get segment dec a ; Test CSEG jp z,l122f ; .. yeap ld a,80h l122f: ld b,a ld a,(AddrMode) ; Get mode dec a ; Test CSEG jp z,l1239 ; .. yeap ld a,40h l1239: add a,b l123a: add a,4 ld (hl),a pop af ; Get back sign sbc a,a ; .. - maps to FF inc a add a,(hl) ld (hl),a dec hl call l1e21 ex de,hl ex (sp),hl ex de,hl push de call l1133 ld a,(_seg_) ; Get segment ld (AddrMode),a ; .. as address mode call l1e21 ld a,(SegFlg) ; Test segment attached or a jp z,l1266 ; .. nope ld a,(_seg_) ; Get segment dec a ; Test CSEG push hl call z,l17e5 ; .. yeap pop hl l1266: ld (hl),d dec hl ld (hl),e dec hl ex de,hl pop hl ex (sp),hl ex de,hl ld (hl),d dec hl ld (hl),e jp LnkItm.0 ; ; Link item 4 : SPECIAL LINK ITEM ; LnkItm.4: ld a,(ItemName+1) ; Test sub-type cp '5' ; .. COBOL overlay segment jp z,COBOL cp 'A' ; .. arithmetic operator jp z,SpcOP cp 'B' ; .. external reference jp z,SpcRef cp 'C' ; .. area base + offset jp z,SpcOff cp 'H' ; .. any new type jp z,Spc??? jp loaderr ; ; Subtype A --> Arithmetic operator ; SpcOP: ld a,(ItemName+2) ; Get operator cp .StB ; Test store jp z,l12b1 cp .StW ; .. dto. jp z,l12b1 cp .Opmax+1 ; Test legal range jp nc,loaderr push af call l1d57 ld (hl),0c7h dec hl pop af ld (hl),a jp LnkItm.0 l12b1: push af call l1d57 ld a,(SegFlg) ; Test segment attached or a jp z,l12c3 ; .. nope ld a,(_seg_) ; Get segment dec a ; Test CSEG jp z,l12c5 ; .. yeap l12c3: ld a,40h l12c5: or 87h ld (hl),a dec hl pop af ld (hl),a dec hl dec hl pop de push de call l1133 ld a,(_seg_) ; Get segment ld (AddrMode),a ; .. as address mode call l1e21 ld a,(SegFlg) ; Test segment attached or a jp z,l12eb ; .. nope ld a,(_seg_) ; Get segment dec a ; Test CSEG push hl call z,l17e5 ; .. yeap pop hl l12eb: ld (hl),d ; Set value dec hl ld (hl),e jp LnkItm.0 ; ; Subtype B --> External reference ; SpcRef: ld hl,ItemName ld de,ItemName+1 ld b,(hl) ; Get old length dec (hl) ; .. fix length l12f9: inc hl inc de ld a,(de) ; Get new label ld (hl),a ; .. overwrite 1st character dec b jp nz,l12f9 xor a call SaveLabel ; Find label ld a,(hl) ; Get control byte dec hl call c,l16c0 ; .. aha, new label push hl call l1d57 ld (hl),0c7h dec hl ld (hl),80h dec hl dec hl pop de ld (hl),d ; Set value dec hl ld (hl),e jp LnkItm.0 ; ; Subtype C --> Area Base + Offset ; SpcOff: ld hl,(ItemName+3) ; Get offset ex de,hl ld a,(ItemName+2) ; Get address mode ld (AddrMode),a ; .. set it call l1768 call l1e21 call l1d57 ld a,(SegFlg) ; Test segment attached or a jp z,l133d ; .. nope ld a,(AddrMode) ; Test ABS or a jp nz,l133f ; .. nope l133d: ld a,40h l133f: or 87h ld (hl),a dec hl ld (hl),0 dec hl dec hl ld (hl),d dec hl ld (hl),e jp LnkItm.0 ; ; Subtype H --> UNKNOWN ; Spc???: ld a,(wrkb2) or a jp nz,LnkItm.0 ld a,'.' ld (commflg),a ld (l1f52),a ld hl,(comstrtpnt) push hl ld hl,ItemName+2 call getcmdchar call fopen_r ; Prepare file for reading l1369: call fget cp ' '+1 ; Wait till normal characters jp c,l1369 ld (wrkb2),a cp '+' ; Test sign jp nz,l137f ; .. nope ld (wrkb9),a ; .. set flag call fget l137f: ld hl,wrkb1 ld c,6 l1384: ld (hl),a ; Sample characters inc hl cp ' '+1 jp c,l1392 call fget dec c jp nz,l1384 l1392: ld hl,wrkb1 call scanf ; Get number ex de,hl ld (_prog),hl ; .. save as $PROG address ld (resv4),hl ld a,(wrkb12) or a jp nz,l13d8 ld a,(lodflag) or a jp nz,l13de l13ad: call fget cp ' '+1 jp c,l13ad ; Wait for more ld hl,wrkb1 ld c,32 l13ba: ld (hl),a inc hl cp ' '+1 jp c,l13c8 call fget dec c jp nz,l13ba l13c8: dec hl xor a ld (hl),a ld (commflg),a pop hl call getcmdchar call fopen_r ; Reset file jp LnkItm.0 l13d8: ld hl,$ILL.D.OPT jp ErFilRes l13de: ld hl,$ILL.P.OPT jp ErFilRes ; $ILL.D.OPT: db '?/D illegal with common runtime',null $ILL.P.OPT: db '?No code can be loaded before ' db 'program withcommon runtime',null $NO.HEADER: db ' not found, please create header file',null $COMM.LOD.ERR: db '?End of file on common runtime header',null ; ; ; commrderr: ld hl,$COMM.LOD.ERR jp ErFilRes ; ; Link item F : END OF FILE ; LnkItm.F: pop bc ; Clean stack pop bc jp level2 ; .. and exit ; ; Link item E : END OF MODULE ; LnkItm.E: call l1c86 ; Test transfer address ld a,d or e pop bc jp z,l14a5 ; .. no address xor a call l1e86 ; Get start address ex de,hl ld (ExecAdr),hl ; .. save l14a5: ld bc,0 ; Init offset call IsMemOk? ; Verify memory in range l14ab: ld hl,l20e8 add hl,bc ld e,(hl) inc hl ld d,(hl) ld hl,resv4 call Add@HL_BC.DE ; .. add ld hl,DATpt ; Get DSEG call Add@HL_BC.DE inc bc ; .. fix offset inc bc ld a,c cp 3 jp c,l14ab ld a,(wrkb12) or a ret nz ld hl,(topw2) ex de,hl ld hl,(topw1) call cmpHL.DE ; Compare jp nz,l14de ; .. not same ld hl,(resv1) ld (_prog),hl ; .. set $PROG address l14de: ld bc,0 call GetTop ex de,hl ld hl,(resv1) call SubHL.DE jp c,l1529 ld hl,(topw2) add hl,de push hl call l1b09 ld hl,(topw3) ex de,hl ld hl,(topw4) call SubHL.DE ld b,d ld c,e ld hl,(topw3) ex de,hl pop hl ld (topw3),hl call cmpHL.DE ; .. compare call nc,LD.Dwn ; Move down call c,.LDIR ; Move bytes ld (topw4),hl ; .. save top ld (topw2),hl ld (DATpt),hl ; .. and DSEG l151c: ld bc,0 call GetTop ld (resv3),hl ld (resv4),hl ret l1529: call GetTop ex de,hl ld c,2 call GetTop call cmpHL.DE ; Compare jp c,l1539 ; .. HL < DE ex de,hl l1539: ld hl,(resv1) ex de,hl call SubHL.DE push de ld hl,(topw3) ex de,hl ld hl,(topw4) call SubHL.DE pop hl call cmpHL.DE ; Compare jp nc,l155f ; .. HL > DE ld hl,0 call SubHL.DE ld hl,(topw4) add hl,de call l1b06 l155f: ld hl,(topw1) ex de,hl ld hl,(topw2) call SubHL.DE ld b,d ld c,e ld hl,(resv1) ex de,hl ld hl,(_prog) ; Get $PROG address call SubHL.DE ld hl,(topw3) add hl,de ex de,hl ld hl,(topw1) ex de,hl call LD.Dwn ; Move down ld hl,(resv1) ld (_prog),hl ; Get $PROG address ld hl,(topw3) ex de,hl ld hl,(topw4) call SubHL.DE ld b,d ld c,e ld hl,(topw3) ex de,hl ld hl,(topw1) ld (topw3),hl call .LDIR ; Move bytes ld (topw2),hl ; .. save top ld (topw4),hl ld (DATpt),hl ; .. and DSEG jp l151c ; ; ^(HL+BC):=^(HL+BC) + DE ; Add@HL_BC.DE: add hl,bc ; .. fix address ld a,(hl) add a,e ; .. add value ld (hl),a inc hl ld a,(hl) adc a,d ld (hl),a ret ; ; Link item 7 : ENTRY POINT ; LnkItm.7: ld d,b ld e,c call IsMemOk? ; Verify memory in range ld a,4 call l1e86 ld b,d ld c,e xor a call SaveLabel ; Find label call nc,l1621 ; .. alreday known ld a,(hl) and .Public ; Test already PUBLIC jp nz,MultDef ; .. multiple definition ld a,(SegFlg) ; Test segment attached or a jp nz,l15e1 ; .. yeap ld a,(hl) or .Public ld (hl),a dec hl ld a,(hl) ld e,a ld (hl),c dec hl jp l10e9 l15e1: ex de,hl call l1d57 ld a,(AddrMode) dec a ; Test CSEG jp z,l15ee ; .. yeap ld a,.COMMON l15ee: add a,.Public+3 ld (hl),a ; Set flag dec hl ld (hl),b ; Set address dec hl ld (hl),c dec hl ld (hl),d ; .. twice dec hl ld (hl),e jp LnkItm.0 MultDef: push hl ; .. save symbol pointer ld hl,$MULT.DEF call puts pop hl call PrLabel ; .. tell name call nl jp LnkItm.0 ; $MULT.DEF: db '%Mult. Def. Global ',null ; ; Check symbol known, fix undefined count ; l1621: ld a,(hl) and .Public ; Test PUBLIC ret nz ; .. yep push hl ld hl,(UnDefCnt) dec hl ; .. bump count down ld (UnDefCnt),hl pop hl ret ; ; Link item 6 : CHAIN EXTERNAL ; LnkItm.6: ld d,b ld e,c call IsMemOk? ; Verify memory in range ld a,2 call l1e86 ld b,d ld c,e push bc xor a call SaveLabel ; .. look for label ld a,(hl) dec hl jp c,LI.6.new ; .. new one ld c,(hl) dec hl ld b,(hl) and .Public ex de,hl pop hl jp nz,l1689 ld a,(SegFlg) ; Test segment attached or a jp nz,l169d ; .. yeap ld a,(l2845) or a jp z,l1664 ld a,(AddrMode) dec a ; Test CSEG jp nz,l169d ; .. nope l1664: ex de,hl ld a,d or e jp z,LnkItm.0 call l19f1 jp LnkItm.0 LI.6.new: ex de,hl call l16c0 pop hl ld a,h or l jp z,LnkItm.0 ld a,(SegFlg) ; Test segment attached or a dec de jp nz,l169d ; .. nope ex de,hl ld (hl),d inc hl ld (hl),e jp LnkItm.0 l1689: ld a,(SegFlg) ; Test segment attached or a jp nz,l169d ; .. yeap ld a,h or l jp z,LnkItm.0 ex de,hl call l1e5e ex de,hl jp l10e0 l169d: ex de,hl ld a,d or e jp z,LnkItm.0 inc hl push hl call l1d57 ld a,(AddrMode) dec a ; Test CSEG jp z,l16b1 ; .. yeap ld a,.COMMON l16b1: add a,.Public+2 ld (hl),a dec hl ld (hl),d dec hl ld (hl),e dec hl pop de ld (hl),d dec hl ld (hl),e jp LnkItm.0 l16c0: push hl ld hl,(UnDefCnt) inc hl ; Bump undefine count ld (UnDefCnt),hl pop hl ret ; ; Read bit from LINK-80 stream ; EXIT Carry set reflects state of bit read ; Read1Bit: push hl ld hl,BitVal ld a,(hl) ; Get bits inc hl inc (hl) ; Bump count jp nz,MoreBits ; .. check any left call fget ; Get new byte if not ld (hl),-relbits ; Init count MoreBits: add a,a ; Shift carry out dec hl ld (hl),a ; .. bring back the bits pop hl ret ; ; Read 8 bits from stream ; EXIT Accu and reg B hold byte read ; Read8Bit: ld c,8 ; Set counter ; ; Read bits from stream ; ENTRY Reg C holds bit count ; EXIT Accu and reg B hold bits read ; Read?Bit: ld b,0 NxtBit: call Read1Bit ; Get bit ld a,b rla ; .. shift it in ld b,a dec c jp nz,NxtBit ret ; ; Read one item from bit stream ; EXIT Carry set indicates constant read ; Reg B holds constant ; Zero set indicates 16 bit address read ; Reg DE holds address ; Reg C holds link item read ; ReadItem: xor a ld (AddrMode),a ; Reset address mode call Read1Bit ; Get control bit jp c,Coded ; .. aha, no constant call Read8Bit ; Get byte scf ret Coded: ld c,2 call Read?Bit ; Get control word or a jp z,Control ; .. aha, link item call AField ; Get address field xor a ret Control: push hl ld c,4 call Read?Bit ; Get link item cp _DEFCOM ; Test name field only push af jp c,BField ; .. do it cp _ENDPRG ; Test end of file jp z,enditem ld c,2 call Read?Bit ; .. read mode bits call AField ; Process addressing ; ; Process BFIELD ; ; +---------------+-------------------------+ ; | 3 bits length | Length bytes characters | ; +---------------+-------------------------+ ; BField: pop af ; Get back control push af cp _DEFENT+1 ; Test name requested jp nc,enditem push de ld c,3 call Read?Bit ; Get length ld hl,ItemName or a ; .. test zero ld (hl),a jp nz,skpitm0 inc (hl) ; Map 0 ->> 1 skpitm0: inc hl ld (hl),' ' ; .. init 1st character ld e,a itemfill: dec e jp m,itempop call Read8Bit ld (hl),a ; Fill with name inc hl jp itemfill itempop: pop de enditem: pop af ld hl,-1*256 cp _ENDMOD ; Test end of module jp nz,noxfer ld (BitVal),hl ; .. set byte boundary if so noxfer: ld c,a ; Save link item inc a or a ; .. clear Carry and Zero pop hl ret ; ; Process AFIELD ; ENTRY Accu holds address segment ; EXIT Reg DE holds address ; ; +-------------+-----------------+ ; | 2 bits mode | 16 bits address | ; +-------------+-----------------+ ; AField: push af ld (AddrMode),a ; Set mode call Read8Bit ; Get address ld e,b call Read8Bit ld d,b pop af l1768: cp @cseg ; Check CSEG call z,l178c add a,a push hl jp z,l1779 cp @dseg+@dseg+1 ; Check COMMON jp nc,l1779 ; .. yes xor @COMM+@COMM ; Reverse bits l1779: ld c,a ; Get as index ld b,0 ld hl,AddrTab add hl,bc ; Point to address table ld c,(hl) ; Fetch current inc hl ld b,(hl) ex de,hl add hl,bc ; Add amount sbc a,a ; .. remember overflow (CY) ld (MemOvl?),a ; .. save ex de,hl pop hl ret ; ; ; l178c: push af ld a,(SegFlg) ; Test segment attached or a jp z,l179c ; .. nope xor a ld (MemOvl?),a ; Clear overflow flag pop af ex (sp),hl pop hl ret l179c: pop af ret ; ; Link item table ; LinkTab: dw LnkItm.0 ; ENTRY dw LnkItm.1 ; COMMON dw LnkItm.2 ; MODULE NAME dw LnkItm.3 ; LIBRARY REQUEST dw LnkItm.4 ; SPECIAL LINK ITEM dw LnkItm.5 ; COMMON SIZE dw LnkItm.6 ; CHAIN EXTERNAL dw LnkItm.7 ; ENTRY POINT dw LnkItm.8 ; EXTERNAL - OFFSET dw LnkItm.9 ; EXTERNAL + OFFSET dw LnkItm.A ; DATA SIZE dw LnkItm.B ; LOCATION COUNTER dw LnkItm.C ; CHAIN ADDRESS dw LnkItm.D ; PROGRAM SIZE dw LnkItm.E ; END OF MODULE dw LnkItm.F ; END OF FILE ; ; Link item D : PROGRAM SIZE ; LnkItm.D: ld a,(SegFlg) ; Test segment attached or a call z,l17e5 ; .. nope push de call l191a pop hl ld (l20ea),hl ex de,hl ld hl,(PRGpt) ; Get CSEG add hl,de ld a,-1 ld (l20ed),a ex de,hl ld hl,(topw4) ex de,hl call cmpHL.DE ; Compare call nc,l1b06 ; .. HL > DE jp LnkItm.0 ; ; ; l17e5: ld hl,(PRGpt) ; Get CSEG ex de,hl jp SubHL.DE ; .. get difference ; ; Link item 1 : SELECT COMMON ; LnkItm.1: ld a,.COMMON call SaveLabel ; Find label jp c,loaderr ; .. should be in list dec hl ld e,(hl) dec hl ld d,(hl) call l1e5e ex de,hl ld (ABSpt),hl ; Set ASEG jp LnkItm.0 ; ; Link item B : LOCATION COUNTER ; LnkItm.B: pop hl push bc call IsMemOk? ; Verify memory in range ld a,(AddrMode) dec a ; Test ABS jp m,l1825 ; .. yeap inc a ld (_seg_),a ; Save segment dec a ; Test CSEG jp nz,LnkItm.0 ; .. nope ld a,(SegFlg) ; Test segment attached or a jp z,LnkItm.0 ; .. nope ld hl,(PRGpt) ; Get CSEG add hl,bc ex (sp),hl jp LnkItm.0 l1825: ld d,b ld e,c ld bc,2 push de scf call dataorg pop de ld hl,(resv1) ex de,hl call SubHL.DE jp nc,l184d ld (resv1),hl ld hl,0 call SubHL.DE ld hl,(PRGpt) ; Fix CSEG add hl,de ld (PRGpt),hl ld de,0 l184d: ld hl,(topw3) add hl,de pop bc push hl ld hl,0 ld (l20b8),hl ld a,l ld (l20ed),a inc a ld (_seg_),a ; Set segment jp LnkItm.0 ; ; Verify menory in range ; IsMemOk?: ld a,(MemOvl?) ; Get flag or a ; .. test 0000..FFFF ret z ; .. yeap jp memerr ; ; Insert or find symbol ; ENTRY Accu holds mode byte ; 1000.0000 for COMMON ; 0010.0000 for LIB Request ; 0000.0000 else ; EXIT Carry set if label inserted - that is not found in list ; Reg HL points to label flag ; Reg DE points to end of label item ; ; Structure of symbol table: ; ; Length : 2 1..7 2 1 byte(s) ; +--------+--------......----------+-------+---------+ ; | COMMON | Name in reversed order | Value | Control | ; +--------+--------......----------+-------+---------+ ; ^ ; +--- On COMMON only ; SaveLabel: ld hl,(SymBase) ; Get symbol base push bc push af SavLab.loop: ex de,hl ld hl,(CurSym) ; Test end of table ex de,hl ld a,h xor d ld b,a ld a,l xor e or b jp z,SavLab.End ; .. scan done ld a,(hl) and .LenMsk ; Get length ld c,a pop af push af xor (hl) ; Test same type and NOT (.Public+.LenMsk) jp nz,SavLab.NoSrc ld de,ItemName ld a,(de) inc de xor c ; Test same length jp nz,SavLab.NoSrc push hl ld b,c dec hl ; Point to name field dec hl dec hl SavLab.Comp: ld a,(de) cp (hl) ; Compare jp nz,SavLab.NoSame inc de dec hl dec b jp nz,SavLab.Comp ex de,hl pop hl pop af pop bc xor a ; Set found flag ret SavLab.NoSame: pop hl ; Get back pointer SavLab.NoSrc: ld a,(hl) ; Get flag or a ; Check COMMON jp p,SavLab.SkpCOM inc c ; Give extra space inc c SavLab.SkpCOM: ld a,c add a,3 ; Add flag and address space cpl ld c,a ld b,-1 inc bc add hl,bc ; Bump to next jp SavLab.loop ; ; Label not found, so insert it ; SavLab.End: pop bc ; Get back code ld de,ItemName ld a,(de) ; Get length of label push af add a,3 ; .. add flag and address space ld c,a ld a,b ; Get code on rlca ; Allocate more space on COMMON rlca ; .. -->> results in +2 if so add a,c push hl push de ld e,a ld d,0 call SubHL.DE ; Point to start ex de,hl call l1b00 pop de pop hl pop af inc de ld c,a ; Get count or b ; Insert flag ld (hl),a ; .. save ld a,(de) ; Get label cp '#' ; .. check special jp nz,SavLab.SkpSpec ld (SpcCase),a ; Indicate special SavLab.SkpSpec: push hl xor a dec hl ld (hl),a ; Clear address field dec hl ld (hl),a dec hl SavLab.Pack: ld a,(de) ; Unpack label name ld (hl),a dec hl inc de dec c jp nz,SavLab.Pack pop de ; Get flag ld a,(de) or a ; .. test COMMON push hl jp p,SavLab.NoAllo xor a ld (hl),a ; Clear allocated space dec hl ld (hl),a dec hl SavLab.NoAllo: ld (CurSym),hl ; Set new pointer ex de,hl pop de pop bc scf ; Indicate inserted ret l190a: dw l19ab dw l19c1 dw l19d6 dw l1a0a dw l1a2b dw l1a2b dw l27fb dw l1a2b ; ; ; l191a: ld a,(l2845) or a jp nz,l1926 ld a,(SegFlg) ; Test segment attached or a ret z ; .. nope l1926: call l1c86 ld a,(SegFlg) ; Test segment attached or a jp z,l1974 ; .. nope xor a ld (SegFlg),a ; .. clear segment flag ld hl,(topw2) ex de,hl ld hl,(topw3) push de ex de,hl call SubHL.DE ex de,hl ld b,h ld c,l ld hl,(l20b8) add hl,bc ld (l20b8),hl ex de,hl ld hl,(PRGpt) ; Fix CSEG push hl add hl,bc ld (PRGpt),hl pop de ld hl,(topw4) push de call SubHL.DE ld b,d ld c,e pop de pop hl ld (topw3),hl ; Get destination call .LDIR ; .. move into ld (topw4),hl ; Set new top ld bc,0 call GetTop ld (resv1),hl ld (resv3),hl l1974: ld hl,(CurExpr) ; Get expression pointer ld (l20ba),hl push hl call l27b9 l197e: pop de ld hl,(TopExpr) ; Get top of expression ld a,h sub d jp nz,l1989 ld a,l sub e l1989: jp z,l19a2 ex de,hl ld a,(hl) add a,a and 0eh ld e,a ld d,0 ld bc,l197e push bc push hl ld hl,l190a add hl,de ld e,(hl) inc hl ld d,(hl) ex de,hl jp (hl) l19a2: ld hl,(l20ba) ld (TopExpr),hl ; .. set top of expression jp l280f ; ; ; l19ab: call l1a4f pop hl ex (sp),hl push hl call l1e5e ex de,hl ld a,(hl) inc hl and (hl) dec hl inc a jp nz,l1a6e ld (hl),c inc hl ld (hl),b ret ; ; ; l19c1: call l1a4f pop hl ex (sp),hl push hl l19c7: call l1e5e ex de,hl ld e,(hl) ld (hl),c inc hl ld d,(hl) ld (hl),b ld a,e or d jp nz,l19c7 ret ; ; ; l19d6: call l1a4f pop hl ex (sp),hl push hl push bc pop hl inc hl ld a,(hl) and 40h push de dec hl ld e,(hl) dec hl ld d,(hl) ex de,hl ex (sp),hl ex de,hl jp nz,l1a06 pop bc ld a,e or d ret z l19f1: ld (hl),d inc hl ld (hl),e push bc l19f5: call l1e5e ex de,hl ld e,(hl) inc hl ld d,(hl) ld a,e or d jp nz,l19f5 pop de ld (hl),d dec hl ld (hl),e ret l1a06: pop bc jp l19c7 ; ; ; l1a0a: call l1a4f pop hl ex (sp),hl push hl push bc pop hl ld a,(hl) ld c,a or 40h ld (hl),a ld a,c l1a18: and 40h dec hl ld c,(hl) ld (hl),e dec hl ld b,(hl) ld (hl),d push bc push de pop bc pop de ret nz ld a,e or d ret z jp l19c7 ; ; ; l1a2b: pop hl push hl ld a,(hl) ld (ActiveFlg),a call l1a4f pop hl ex (sp),hl push hl ld hl,(l20ba) ld a,(ActiveFlg) and 7 or 0c0h ld (hl),a dec hl ld (hl),d dec hl ld (hl),e dec hl ld (hl),b dec hl ld (hl),c dec hl ld (l20ba),hl ret ; ; ; l1a4f: pop hl ex (sp),hl ld a,(hl) dec hl ld d,(hl) dec hl ld e,(hl) dec hl ld b,(hl) dec hl ld c,(hl) dec hl ex (sp),hl push hl ld hl,(resv1) or a jp m,l1a67 ex de,hl add hl,de ex de,hl l1a67: and 40h ret nz add hl,bc ld b,h ld c,l ret ; ; ; l1a6e: push hl ld hl,$BAD.FIX call puts ; Tell bad fixup ld h,b ld l,c call printf ; .. print number pop de call put.tab ; Give tab ld hl,(PRGpt) ; Get CSEG call cmpHL.DE ; Compare jp nc,l1a8a ; .. HL > DE ld hl,(DATpt) ; Get DSEG l1a8a: ex de,hl call SubHL.DE ; Get difference ex de,hl call printf ; .. print it call putc call put.tab ; Give tab pop hl pop de push de push hl ld hl,5 add hl,de push hl call printf ; Print value call put.tab ; Give tab pop de ld hl,(CurExpr) ; Get expression pointer call SubHL.DE ex de,hl call printf ; .. print call nl ret ; $BAD.FIX: db '%%Bad fixup offset entry, will be ignored' db cr,lf db 'Value',tab db 'Loc',tab db 'Entry A',tab db 'Entry rel.' db cr,lf,null ; ; ; l1b00: ld a,6 .JPC l1b03: ld a,4 .JPC l1b06: ld a,2 .JPC l1b09: ld a,0 l1b0b: push bc cp 4 jp nc,l1b16 inc a ld (lodflag),a dec a l1b16: ld c,a ld b,0 push de push hl cp 3 ld hl,topw3 jp c,l1b26 ld hl,topw4-4 l1b26: add hl,bc ld e,(hl) inc hl ld d,(hl) pop hl cp 3 jp c,l1b32 push hl ex de,hl l1b32: call SubHL.DE push af ld a,c cp 3 jp c,l1b3f pop af pop hl push af l1b3f: pop af push hl jp nc,l1b57 ld a,c cp 3 ccf jp c,l1b5e push de call GetTop2 call cmpHL.DE ; Compare pop de ccf jp c,l1b5e ; .. HL > DE l1b57: push af push bc call l1b7e pop bc pop af l1b5e: push af ld a,c cp 3 ld hl,topw2 jp c,l1b6b ld hl,TopExpr-4 ; .. init pointer l1b6b: add hl,bc pop af pop de jp nc,l1b77 ld (hl),e inc hl ld (hl),d jp l1b7a l1b77: ld e,(hl) inc hl ld d,(hl) l1b7a: ex de,hl pop de pop bc ret ; ; ; l1b7e: push hl push de call l1ca0 push de call SubHL.DE jp c,memerr jp z,memerr pop hl call l1cf7 ld hl,l20dc ld b,2 l1b96: ld (hl),b inc hl dec b jp nz,l1b96 l1b9c: ld de,0 ld hl,(topw1) l1ba2: push hl ld hl,l20ce add hl,de ld c,(hl) inc hl ld b,(hl) inc hl ld a,(hl) inc hl ld h,(hl) ld l,a push hl ld hl,l20d6 add hl,de push de ld e,(hl) inc hl ld d,(hl) ex de,hl add hl,bc pop de pop bc ex de,hl ex (sp),hl push bc add hl,de push hl add hl,bc pop bc ex de,hl pop hl ex (sp),hl ex de,hl push hl ld hl,TopExpr ; Get base add hl,de ld a,(hl) inc hl ld h,(hl) ld l,a ex de,hl ex (sp),hl call cmpHL.DE pop de jp nc,l1c4a push hl ld hl,l20dc ld a,e rrca ld e,a add hl,de ld a,e add a,a ld e,a ld a,(hl) pop hl or a jp z,l1c4a ex (sp),hl ld hl,topw3 add hl,de push de ld e,(hl) ld (hl),c inc hl ld d,(hl) ld (hl),b ex de,hl ex (sp),hl ex de,hl pop hl ex (sp),hl push hl ld hl,topw4 add hl,de ex de,hl ex (sp),hl ex de,hl ld a,(hl) ld (hl),e inc hl ld e,a ld a,(hl) ld (hl),d ld d,a pop hl ex (sp),hl ex de,hl push de call SubHL.DE pop hl ex (sp),hl ld a,l ex (sp),hl ex de,hl or a jp z,l1c28 push af ld a,(l20b7) or a jp z,l1c26 inc bc inc bc inc bc inc bc inc bc l1c26: pop af inc hl l1c28: call z,l1d73 push hl push bc pop hl pop bc push hl call cmpHL.DE call nc,LD.Dwn ; .. fix bytes call c,.LDIR ; Unpack bytes pop hl pop de ld a,e rra ld e,a push hl ld hl,l20dc add hl,de ld (hl),0 ex de,hl add hl,hl ex de,hl pop bc push bc l1c4a: inc e inc e ld h,b ld l,c pop bc ld a,e cp 4 jp c,l1ba2 ld hl,l20dc xor a ld b,2 l1c5b: add a,(hl) ; Build sum inc hl dec b jp nz,l1c5b or a jp nz,l1b9c ld hl,(l20d4) ex de,hl ld hl,(TopExpr) ; Get expression pointer ld (hl),0 ld hl,(SymBase) ; Get start of table call SubHL.DE ; .. fix ex de,hl ld (CurSym),hl ; Set current table ld hl,(l20ce) ex de,hl ld hl,(topw1) add hl,de ld (topw2),hl pop de pop hl ret ; ; ENTRY Reg C holds ??? ; l1c86: push af push bc push de push hl call l1ca0 ex de,hl ld hl,(freebytes) ; Get free bytes ex de,hl call cmpHL.DE ; .. compare jp nc,l1c9b ld (freebytes),hl ; Change free bytes l1c9b: pop hl pop de pop bc pop af ret ; ; ENTRY Reg C holds ??? ; l1ca0: push bc push de ld hl,topw2 ; Get pointer ld a,c cp 3 ; Test code jp c,l1cae ld hl,topw1 ; .. change pointer l1cae: add hl,bc ld e,(hl) ; Fetch content inc hl ld d,(hl) ld bc,9 ; Get increment cp 3 ; Test code agian jp c,l1cbd ld bc,-11 ; .. change increment l1cbd: add hl,bc ld b,(hl) ; Get value inc hl ld h,(hl) ld l,b cp 3 ; Test mode jp c,l1cc8 ex de,hl ; .. swap l1cc8: call SubHL.DE ; Get difference pop hl add hl,de push hl ld b,3 ; Set loop count ld hl,topw2 ld de,0 push de l1cd7: ld e,(hl) inc hl ld d,(hl) push de ld de,9 add hl,de ld e,(hl) inc hl ld d,(hl) ex (sp),hl ex de,hl call SubHL.DE pop hl ex (sp),hl add hl,de ex (sp),hl ld de,-9 add hl,de dec b jp nz,l1cd7 pop hl pop de pop bc ret ; ; ; l1cf7: ld a,c ld bc,0 push de push hl l1cfd: ld hl,topw2 add hl,bc ld e,(hl) inc hl ld d,(hl) push de ld de,7 add hl,de ld e,(hl) inc hl ld d,(hl) pop hl push af call SubHL.DE pop af cp c jp nz,l1d1a pop hl push hl add hl,de ex de,hl l1d1a: ld hl,l20ce add hl,bc ld (hl),e inc hl ld (hl),d inc c inc c ld b,a ld a,c cp 8 ld a,b ld b,0 jp nz,l1cfd pop hl ld hl,l20d6 ld b,3 l1d33: ex (sp),hl call l1d42 ex (sp),hl ld (hl),e inc hl ld (hl),d inc hl dec b jp nz,l1d33 pop hl ret ; ; ; l1d42: ld a,b sub 1 jp z,l1d55 ld a,h rra ; Divide by 2 ld d,a ld a,l rra ld e,a push de call SubHL.DE ex de,hl pop de ex de,hl l1d55: ex de,hl ret ; ; ; l1d57: push de push bc ld bc,-5 ld a,b ld (l20b7),a ld hl,(TopExpr) ; Get pointer add hl,bc or a call l1b03 xor a ld (l20b7),a ld de,5 add hl,de pop bc pop de ret ; ; ; l1d73: ex de,hl push hl ld a,c sub l ld l,a ld a,b sbc a,h ld h,a push de ex de,hl ld hl,(l20b8) add hl,de ld (l20b8),hl ex de,hl ld hl,(PRGpt) ; Bump CSEG add hl,de ld (PRGpt),hl ld hl,(ABSpt) ; .. and ASEG add hl,de ld d,b ld e,c call cmpHL.DE jp c,l1d9b ld (ABSpt),hl ; Save ASEG l1d9b: pop de pop hl ex de,hl ret ; ; ; l1d9f: push de ld a,(_seg_) ; Get segment cp @COMM ; Test COMMON jp z,l1dbb ; .. yeap dec a ; Test CSEG jp nz,l1db1 ; .. nope ex de,hl ld hl,(l20b8) add hl,de l1db1: ex de,hl ld hl,0 ld (l20b8),hl ex de,hl pop de ret l1dbb: push hl ex de,hl ld hl,(l20b8) add hl,de ex de,hl ld hl,(topw3) call cmpHL.DE pop hl jp nc,l1db1 ex de,hl jp l1db1 ; ; ; l1dd0: call l1d9f jp nz,l1de4 push de ex de,hl ld hl,(PRGpt) ; Get CSEG ld a,e sub l ld c,a ld a,d sbc a,h ld b,a ex de,hl pop de ret l1de4: push hl push de ex de,hl ld hl,(topw1) ex de,hl call SubHL.DE ld hl,(_prog) ; Get $PROG address add hl,de ld b,h ld c,l pop de pop hl scf ret ; ; Move bytes up ; ENTRY Reg DE points to source ; Reg HL points to destination ; Reg BC holds length ; .LDIR: ld a,b ; Test end or c ret z ld a,(de) ; .. copy ld (hl),a inc hl inc de dec bc jp .LDIR ; ; Move bytes down ; ENTRY Reg DE points to bottom of source ; Reg HL points to bottom of destination ; Reg BC holds length ; EXIT Reg HL points behind top of destination ; LD.Dwn: add hl,bc ; Point to top push hl ex de,hl add hl,bc dec hl ; .. fix buffers dec de .LD.Dwn: ld a,b or c ; Test end jp z,pop.hl ; .. yeap, get back reg ld a,(hl) ; .. copy ld (de),a dec de dec hl dec bc jp .LD.Dwn ; ; Move bytes down ; ENTRY Reg DE points to source ; Reg HL points to destination ; Reg BC holds length ; .LDDR: ld a,b or c ; Test end ret z ld a,(de) ; .. copy ld (hl),a dec de dec hl dec bc jp .LDDR ; ; ; l1e21: ld a,(AddrMode) scf dec a ; Check ABS ret m ; .. yeap push hl push bc cp @COMM-1 ; Check COMMON call z,l1e7d ; .. yeap xor 1 add a,a ld c,a ld b,0 or a jp z,l1e40 ld a,(SegFlg) ; Test segment attached or a scf jp nz,l1e4c ; .. yeap l1e40: ex de,hl call GetTop2 call SubHL.DE call GetBottom add hl,de ex de,hl l1e4c: pop bc pop hl ret ; $INTER.SECT: db '?Intersecting ',null ; ; ; l1e5e: push af push bc push hl ld bc,255 call l06e5 jp nc,l1e79 ld c,a push de call GetTop2 call GetBottom ex de,hl call SubHL.DE pop hl add hl,de ex de,hl l1e79: pop hl pop bc pop af ret ; ; ; l1e7d: ld hl,(topw2) ; Get pointer call cmpHL.DE ; .. compare sbc a,a ; .. FF if HL < DE inc a ; .. map to 00 ret ; ; ; l1e86: ld (l1f38),a call l1e21 ret c push hl push bc ld a,(AddrMode) cp @dseg ; Check DSEG ccf sbc a,a and 2 ld b,0 ld c,a jp z,l1ea5 ld a,(SegFlg) ; Test segment attached or a jp nz,l1e4c ; .. yeap l1ea5: call GetBottom call cmpHL.DE jp nc,l1e4c call GetTop ex de,hl call cmpHL.DE ex de,hl jp nc,l1e4c push hl ld hl,$INTER.SECT call l06e1 ; Intersecting error ld a,',' call putc ld hl,(l1f38) ld h,0 ld de,StatTbl ld c,l add hl,de ld e,(hl) inc hl ld d,(hl) ex de,hl call puts ; .. print string ld a,c or a jp nz,l1ee2 pop hl call l1f01 jp rego l1ee2: ld hl,ItemName ld b,(hl) inc hl l1ee7: ld a,(hl) inc hl call putc ; .. print dec b jp nz,l1ee7 ld a,'(' call putc pop hl call l1f01 ld a,')' call putc jp rego l1f01: ld a,(AddrMode) cp @dseg ; Check DSEG sbc a,a and 2 call GetTop2 call SubHL.DE ; .. get difference jp printf ; .. print ; $START: db ' Start = ',null $EXTERN: db ' External ',null $PUBLIC: db ' Public = ',null StatTbl: dw $START dw $EXTERN dw $PUBLIC IF _MODS @Zopt: db null @Lopt: db FALSE ENDIF ;_MODS l1f38: db 0 BitVal: db 0 BitCnt: db 0 AddrTab: ; \ dw 0 ; | COMMON DATpt: ; | dw 0 ; | DSEG PRGpt: ; | dw 0 ; | CSEG ABSpt: ; | dw 0 ; / ABSOLUTE ; $Name: ; Name for /G and /E option ds _Modlen ItemName: db 0 ; .. length ds _ModLen l1f52: db 0 ExecAdr: dw 0 mystack: dw l2ad3 curcmdpnt: dw 0 radixmod: db 0 UnDef?: db 0 iniflg2: db 0 lodflag: db 0 MemOvl?: db 0 Sav.Prg: ; 0 = save all onto disk, db 0 ; else CSEG only wrkb6: db 0 wrkb7: db 0 wrkb9: db 0 UnDefCnt: dw 0 l1f64: db 0 _PSW_: db 00000000b rdbuff: db RecLng ds RecLng+1 mDMA: ds RecLng ActiveFlg: db 0 rFCB: ds FCBlen+3 wFCB: ds FCBlen iniflg1: db 0 SegFlg: db 0 wrkb12: db 0 SpcCase: db 0 ExprCnt: db 0 l20b3: dw 0 AddrMode: db 0 ; Two bit addressing mode _seg_: db 0 l20b7: db 0 l20b8: dw 0 l20ba: dw 0 FileByte: dw 0 topw2: ; \ dw 0 ; | topw4: ; | \ dw 0 ; / | CurExpr: ; | dw 0 ; / SymBase: dw 0 ; Start of symbol table topw1: dw 0 topw3: ; \ dw 0 ; | TopExpr: ; | \ dw 0 ; / | CurSym: ; | dw 0 ; / End of symbol table l20ce: ds 6 l20d4: dw 0 l20d6: ds 6 l20dc: dw 0 freebytes: dw 0 _prog: ; \ dw 0 ; | resv1: ; | dw 0 ; / resv4: ; \ dw 0 ; | resv3: ; | dw 0 ; / l20e8: dw 0 l20ea: dw 0 l20ec: db 0 l20ed: db 0 headflg: db 0 comstrtpnt: dw 0 wrkb1: ds 32 wrkb2: db 0 commflg: db 0 ; ; ; l2113: ld bc,2 call getamount ld c,0 jp nz,l2124 call getamount ld (lodflag),a l2124: ld de,defPC ld hl,0203h ld a,(lodflag) or a ret z l212f: call getamount jp z,l2141 call GetBottom call l219b call GetTop call l219b l2141: inc c inc c ld a,c cp 4 jp nz,l212f ld hl,(_prog) ; Get $PROG address ex de,hl ld hl,(resv1) call cmpHL.DE call c,l230b ld hl,(topw1) ld de,TPA ld bc,4 call l2216 ld c,0 l2164: call GetTop1 inc c inc c call GetTop2 push hl call GetTop1 call cmpHL.DE pop hl jp nz,l217e ex de,hl ld hl,(mystack) ex de,hl ld c,2 l217e: ex de,hl call cmpHL.DE call nc,l2216 ld a,c cp 2 jp nz,l2164 call GetTop1 ex de,hl ld hl,(mystack) call cmpHL.DE call nc,l2216 jp memerr ; ; ; l219b: ld de,TPA call cmpHL.DE jp c,l21b7 ex de,hl ld hl,(mystack) call cmpHL.DE ex de,hl jp c,l21b0 ret l21b0: push hl ld hl,$ABOVE jp l21bb l21b7: push hl ld hl,$BELOW l21bb: push hl ld hl,$ORIG call puts ; .. tell state pop hl call puts ld hl,$MOVE? call puts xor a ld (iniflg1),a call getcmdline call CmdUPPER cp 'Y' pop hl ret z jp .OS ; Hard stop ; $BELOW: db 'below',null $ABOVE: db 'above',null $ORIG: db 'Origin ',null $MOVE?: db ' loader memory, move anyway(Y or N)?',null ; ; ; l2216: push bc push de ld bc,2 ex de,hl l221c: call GetTop push de ex de,hl call GetBottom call cmpHL.DE ex de,hl pop de jp z,l2232 call cmpHL.DE call c,l2246 l2232: dec c dec c jp p,l221c ld c,4 ld hl,TPA call cmpHL.DE call c,l2246 ex de,hl pop de pop bc ret ; ; ; l2246: push bc push hl ld a,c or a jp nz,l2255 ld a,(wrkb12) or a jp z,l2259 xor a l2255: add a,2 cp 4 l2259: ld hl,(mystack) jp z,l2282 jp c,l2263 xor a l2263: ld c,a call GetBottom push de ex de,hl call GetTop call cmpHL.DE ex de,hl pop de jp nz,l2282 ld a,c or a ld hl,(mystack) jp nz,l2282 ld hl,resv1 call getpntany l2282: call cmpHL.DE jp nc,l2289 ex de,hl l2289: ld hl,6 add hl,sp ld sp,hl pop hl push hl dec sp dec sp dec sp dec sp dec sp dec sp ex de,hl call cmpHL.DE jp c,l22c7 ex (sp),hl call cmpHL.DE jp c,l22a5 ex de,hl l22a5: pop hl push de call SubHL.DE ld a,d or a pop de jp z,l22cb ld bc,l2729 scf call l22ce jp c,l22c1 inc b call l22ce jp z,l22cb l22c1: pop bc pop bc pop bc pop bc pop bc ret l22c7: pop de ex de,hl pop bc ret l22cb: ex de,hl pop bc ret ; ; ; l22ce: push bc push de push hl push bc pop hl push af call cmpHL.DE jp c,l2305 pop af pop de push de push af ex de,hl call cmpHL.DE jp c,l2305 pop af jp nc,l22f0 pop hl pop bc push bc push hl push bc pop hl ex de,hl l22f0: push de call SubHL.DE ld a,d or a jp z,l22ff pop de pop bc pop bc pop bc scf ret l22ff: pop de pop hl pop de pop bc xor a ret l2305: pop bc pop hl pop de pop bc or a ret ; ; ; l230b: ld hl,(topw2) ld (DATpt),hl ; Restore DSEG ld hl,(topw4) ld (PRGpt),hl ; .. and CSEG l2317: ld hl,(topw1) ex de,hl ld hl,(DATpt) ; Check DSEG call SubHL.DE jp nz,l232b or e jp z,l23cb jp p,l232d l232b: ld e,RecLng l232d: ld c,e ld b,0 ld d,b push bc ld hl,(DATpt) ; Get DSEG push hl call SubHL.DE ex de,hl ld (DATpt),hl ; .. set new ex de,hl ld hl,mDMA call .LDIR ; Move into buffer pop de ld hl,(topw2) push de call SubHL.DE ld b,d ld c,e or c pop de ld hl,(DATpt) ; Get DSEG call nz,.LDIR ; .. move into ld hl,(topw3) ex de,hl ld hl,(PRGpt) ; Get CSEG call SubHL.DE pop bc push bc jp nz,l236e or e jp z,l23b0 cp c jp nc,l236e ld c,a l236e: ld hl,(topw2) pop de call SubHL.DE ld hl,(topw3) push bc ex de,hl call .LDIR ld (topw2),hl ld hl,(topw3) pop de push de add hl,de ex de,hl ld hl,(PRGpt) ; Check CSEG call SubHL.DE ld b,d ld c,e ld hl,(topw3) pop de push de ex de,hl add hl,de ex de,hl call .LDIR l239a: ld hl,(PRGpt) ; Get CSEG pop de push de call SubHL.DE ex de,hl ld (PRGpt),hl ; .. set new ld de,mDMA pop bc call .LDIR ; Get from buffer jp l2317 l23b0: ld d,b ld e,c ld hl,(topw2) call SubHL.DE ex de,hl ld (topw2),hl ld hl,(topw3) pop de push de call SubHL.DE ex de,hl ld (topw3),hl jp l239a l23cb: ld hl,(topw3) ex de,hl ld hl,(PRGpt) ; Check CSEG call SubHL.DE jp c,l23e8 ld b,d ld c,e or e ld hl,(topw3) ex de,hl ld hl,(topw2) call nz,.LDIR ld (topw2),hl l23e8: ld hl,(resv1) ex de,hl ld hl,(_prog) ; Get $PROG address ld (resv1),hl ex de,hl ld (_prog),hl ld hl,(PRGpt) ; Save CSEG ld (topw3),hl ld hl,(DATpt) ; .. and DSEG ld (topw1),hl ret ; ; Prepare output file ; ENTRY Accu holds first character of name of file ; PrepFO: cp ' ' ; Test empty ret z ; .. yeap ld hl,wFCB+.drv+.nam ld bc,RewrFO ; Set return address push bc ld a,(hl) ; Test extension .REL cp 'R' ret nz ; .. nope inc hl ld a,(hl) cp 'E' ret nz inc hl ld a,(hl) cp 'L' ret nz ld b,.ext ld de,$COM+.ext-1 ld a,(_PSW_) ; Look for destination and .Xopt jp z,PrepCOM ld de,$HEX+.ext-1 ; .. set hex PrepCOM: ld a,(de) ld (hl),a ; Unpack extension dec hl dec de dec b jp nz,PrepCOM ret ; $COM: db 'COM' $HEX: db 'HEX' ; ; Rewrite output file ; RewrFO: ld bc,WriteFO ; Set return push bc ; ; Rewrite output file ; fopen_w: IF _MODS call resDMA ENDIF ;_MODS ld de,mDMA ld c,.setdma call BDOS ; Set disk buffer ld de,wFCB call PrepFCB ld c,.delete call BDOS ; Delete existing file ld de,wFCB ld c,.make call BDOS ; .. create new one inc a jp z,wrterr ; .. oops, error xor a ld (FileByte),a ; Reset buffer pointer ret ; ; Write to output file(s) ; WriteFO: ld bc,0 ld a,(wrkb12) or a jp z,l2481 call getamount jp z,l247f ld hl,(resv1) ex de,hl ld hl,(_prog) ; Get $PROG address call cmpHL.DE jp c,l2481 l247f: ld c,2 l2481: ld hl,_PSW_ ld a,(hl) and .Yopt ; Test symbol table write jp z,l248e ld de,WrtSym ; Set return address push de l248e: ld a,(hl) and .Xopt ; Test normal format jp z,l24c8 ld a,(Sav.Prg) ; Test all to be saved or a jp z,l24b4 ; .. yes ld a,(wrkb12) or a ld c,0 jp nz,l24b7 ld hl,(ExecAdr) ; Get execution address push hl ex de,hl call l1e5e ex de,hl ld (topw1),hl pop hl ld (_prog),hl ; .. set $PROG address l24b4: call WrtHEX ; .. write .HEX file l24b7: ld a,c xor 2 ld c,a ld a,(wrkb12) ; Test any remaining or a call nz,WrtHEX ; .. write it call LastHEXrec ; .. write last record jp fclose ; .. close file ; ; ; l24c8: ld hl,(ExecAdr) ; Get execution address ld de,TPA ld a,h or l jp z,l24f7 call cmpHL.DE jp z,l24f7 ld de,defPC call l25db call cmpHL.DE ld de,TPA jp c,l24f7 ld de,0180h call cmpHL.DE jp nc,l24fb call wrjp ; Set execution jump ld de,defPC l24f7: call wrhead ; .. write header to file scf l24fb: call nc,l2594 call wr.com ; Write .COM file ld a,(wrkb12) ; Test flag or a jp z,fclose ; .. close file call GetTop ex de,hl ld a,c xor 2 ld c,a call getamount jp z,fclose ; .. close file call wrhead ; .. else write header call wr.com ; Write to .COM file fclose: ld a,(FileByte) ; Test any in buffer or a call nz,WrtRec ; .. write record if so ld de,wFCB ld c,.close call BDOS ; Close file inc a ; .. test success jp z,wrterr ret ; ; Set execution jump ; wrjp: ld a,.JP ; Set JP code call fput ld hl,(ExecAdr) ; Get execution address ld a,l call fput ; .. to file ld a,h jp fput ; ; Write zero header to file ; ENTRY Reg DE holds start address ; wrhead: call GetBottom ; Get bottom call SubHL.DE ; .. subtract start address ret c ; .. out of range or e ret z ; .. same IF _MODS ld a,(@Lopt) or a ; Test zero header skipping jp z,l2549 ; .. nope ld d,0 ; .. clear high ld a,e and a ; Test any page remainder ret z ; .. nope ENDIF ;_MODS l2549: xor a call fput ; Fill zeroes in header dec de ld a,d or e jp nz,l2549 ret ; ; Write data to .COM file ; wr.com: call l25e6 ; Get top call GetTop1 ; .. get pointer ex de,hl call SubHL.DE ; Get length of data ; ; Write data to file ; ENTRY Reg HL points to start address in memory ; Reg DE holds length of data as two's complement ; wrfile:: ld a,d ; Test done or e ret z ; .. yeap ld a,(hl) inc hl call fput ; .. put to file inc de jp wrfile ; ; Put byte to output file ; ENTRY Accu holds byte ; fput: push de push hl push af ld hl,mDMA ld a,(FileByte) ; Get index ld e,a ld d,0 add hl,de ; .. calculate buffer pop af ld (hl),a ; .. store byte ld a,e inc a ; Bump count call m,WrtRec ; .. write record if filled ld (FileByte),a ; Save index pop hl pop de ret ; ; Write record to file ; WrtRec:: push bc ld de,wFCB ld c,.wrseq ; .. write call BDOS or a ; Test error jp nz,wrterr IF _MODS call resDMA ; Reset buffer ENDIF ;_MODS pop bc xor a ret IF _MODS ; ; Preset buffer for writing ; resDMA:: push hl ld de,mDMA ld hl,mDMA+1 ld a,(@Zopt) ; Get filler ld (de),a ld bc,RecLng-1 call .LDIR ; .. unpack pop hl ret ENDIF ;_MODS ; ; ; l2594: call l25db ; Get address ld (lo.adr),hl push hl push bc ld a,c xor 2 ld c,a call GetTop pop bc pop de call SubHL.DE ex de,hl inc hl ; Fix length ld (lo.len),hl ld de,-lo.code ld hl,lo.base call wrfile ; .. write loader code to file call wrjp ; Set jump to execution address ld b,RecLng-lo.code-3 l25bb: xor a call fput ; .. fill remainder with zeroes dec b jp nz,l25bb ret ; ; Loader code moved into first record ; lo.base equ $ .phase TPA lo.adr equ lo.base+$-TPA+1 ld hl,$-$ ; Filled in by loader lo.len equ lo.base+$-TPA+1 ld bc,$-$ ; .. length, too ld de,TPA+RecLng add hl,bc ex de,hl add hl,bc inc bc lo.010d: ld a,(hl) ld (de),a dec hl dec de dec bc ld a,b or c jp nz,lo.010d .dephase lo.code equ $-lo.base ; ; ; l25db: ld a,(wrkb9) or a jp z,GetBottom ld hl,(ExecAdr) ; Get execution address ret ; ; ; l25e6: ld a,(wrkb9) ; Get flag or a jp z,GetTop2 push bc ld hl,(ExecAdr) ; Get execution address ex de,hl call l1e5e pop bc ret ; ; Proces file write error ; wrterr: ld hl,$WRT.ERR jp ErFilRes ; $WRT.ERR: db '?Can''t save object file',null ; ; Write file in INTEL .HEX format ; WrtHEX: call GetTop ; Get end of code ex de,hl call GetBottom ; .. get start of code ex de,hl push de call SubHL.DE ; .. get length of code ld a,e or d ; Test code there pop hl ret z ; .. nope, empty push bc push hl IF V3.43 dec de ENDIF ; V3.43 push de call GetTop2 ex de,hl pop de HEXdata: ld a,e sub _HEXlen ; Subtract HEX length ld e,a ld a,d sbc a,0 ld d,a jp c,l263e ; .. less default ld a,_HEXlen ; .. set default jp l2644 l263e: ld a,e add a,_HEXlen ; Make > 0 ld de,0 l2644: or a ; Test remainder jp nz,HEXrec ; .. yeap pop bc pop bc ret ; ; Write HEX record ; ; Format: ; ; :00... ; ; Length of data bytes ; Current address ; Current byte ; Checksum of bytes (Two's complement) ; ; Last record has and of 0. The only byte is 01 ; resulting in a CRC of FF ; HEXrec: ld c,a ; Save length ld b,0 ld a,':' call fput ; Write sync character ld a,c call hexhlbyte ; .. length ex (sp),hl push de call hexhl ; Write address ld d,0 ld e,c add hl,de ; .. point to end pop de ex (sp),hl xor a call hexhlbyte ; Write delimiter l2666: ld a,(hl) inc hl call hexhlbyte ; Write bytes dec c jp nz,l2666 xor a sub b ; Calculate checksum call hexhlbyte ; .. write it call fnl ; .. get new line jp HEXdata ; .. try next ; ; Write last record of .HEX file ; ; Format: ; ; :0000 01 FF ; LastHEXrec: ld a,':' call fput ; Print delimiter xor a ld b,a call hexhlbyte ; .. write zero ld hl,(ExecAdr) ; Get execution address call hexhl ; Write control word ld a,1 call hexhlbyte ; Give 01 xor a sub b call hexhlbyte ; .. and checksum fput.eof: call fnl ; Give new line ld a,eof jp fput ; .. and EOF ; ; ; exfer: push hl inc de ld hl,l272c+1 call l27a1 ld hl,l2732+1 call l27a1 ld hl,l2735+1 call l27a1 ld hl,l273b+1 ld b,6 l26b5: call l27a1 inc hl inc hl dec b jp nz,l26b5 inc hl inc hl ld b,3 l26c2: call l27a1 inc hl inc hl dec b jp nz,l26c2 inc hl call l27a1 ld hl,l277c+1 call l27a1 ld hl,l2787+1 call l27a1 push de ld hl,(topw1) ld (l278c),hl ex de,hl ld hl,(topw2) call SubHL.DE ex de,hl ld (l278a),hl ld hl,(_prog) ; Get $PROG address ld (l278e),hl ld hl,(topw3) ld (l2792),hl ex de,hl ld hl,(topw4) call SubHL.DE ex de,hl ld (l2790),hl ld hl,(resv1) ld (l2794),hl pop de pop hl pop bc ld sp,hl push bc ex de,hl l2710: ld de,l2729 ld bc,006dh jp l2729 ; ds 16 l2729: call l2796 l272c: jp l272f l272f: ld bc,0 l2732: call l2759 l2735: jp c,l274a ld bc,6 l273b: call l2759 call nc,l276f call c,l277f call l2759 jp l276f l274a: call l277f ld c,6 call l2759 call nc,l276f call c,l277f ret ; ; ; l2759: ld hl,l278a add hl,bc ld c,(hl) inc hl ld b,(hl) inc hl ld e,(hl) inc hl ld d,(hl) inc hl ld a,(hl) inc hl ld h,(hl) ld l,a ld a,h sub d ret nz ld a,l sub e ret ; ; ; l276f: add hl,bc ex de,hl add hl,bc dec hl dec de l2774: ld a,b or c ret z ld a,(hl) ld (de),a dec hl dec de dec bc l277c: jp l2774 ; ; ; l277f: ld a,b or c ret z ld a,(de) ld (hl),a inc de inc hl dec bc l2787: jp l277f ; l278a: dw 0 l278c: dw 0 l278e: dw 0 l2790: dw 0 l2792: dw 0 l2794: dw 0 ; ; ; l2796: ld a,b or c ret z ld a,(de) ld (hl),a inc de inc hl dec bc jp l2796 ; ; ; l27a1: push bc push hl push de ld a,(hl) inc hl ld h,(hl) ld l,a ld de,l2729 call SubHL.DE ex de,hl pop de add hl,de push hl pop bc pop hl ld (hl),c inc hl ld (hl),b pop bc ret ; ; ; l27b9: ld a,(l2845) or a ret z push hl l27bf: pop de ld hl,(TopExpr) ; Get expression pointer call cmpHL.DE ret z ex de,hl ld a,(hl) and 7 cp 3 ld bc,l27bf push bc push hl jp z,l1a0a call l1a4f pop hl ex (sp),hl jp (hl) ; ; COBOL overlay segment sentinel ; COBOL: call l281e ld a,(ItemName+2) ; Get overlay segment ld (OvlSeg),a ld hl,(DATpt) ; Save DSEG ld (topw2),hl xor a ld (l20ec),a call l1d57 ld (hl),.ADI ; Set "ADD A," code dec hl ld a,(OvlSeg) ; .. set segment ld (hl),a jp LnkItm.0 ; ; ; l27fb: call l1a4f pop hl ex (sp),hl push hl ld a,d push af call l281e pop af ld (OvlSeg),a ; Set segment or a ret z jp l283a ; ; ; l280f: ld a,(l2845) or a ret z call l281e ld hl,(DATpt) ; Save DSEG ld (topw2),hl ret ; ; ; l281e: ld a,(OvlSeg) ; Get segment or a ; .. test zero ret z ld (l2845),a ld bc,0 call getamount ex de,hl ld hl,(DATpt) ; Save into DSEG ld (hl),d inc hl ld (hl),e dec hl ld a,(OvlSeg) ; Get segment jp l286c ; ; ; l283a: ld hl,(DATpt) ; Get DSEG call l28a5 ld (topw2),hl ret ; OvlSeg: db 0 l2845: db 0 ; ; Link item 2 : MODULE NAME ; !!! NOTE: MODNAME only used here ; LnkItm.2: xor a ld (OvlSeg),a ; Clear segment ld (l2845),a ld hl,ModName ; Load buffer ld bc,' '*256+_ModLen LI.2.ClNam: ld (hl),b ; .. blank buffer inc hl dec c jp nz,LI.2.ClNam ld hl,ItemName ld c,(hl) ; .. fetch length inc hl ld de,ModName LI.2.CpyNam: ld a,(hl) ; .. copy module name ld (de),a inc hl inc de dec c jp nz,LI.2.CpyNam jp LnkItm.0 ; ; ; l286c: push hl push de ld (hl),d inc hl ld (hl),e call OVL.prep ; Prepare temp FCB call fopen_w_ovl ; Create overlay file pop de ld a,e and 7fh jp z,l2888 ld a,e and 80h add a,80h ld e,a jp nc,l2888 inc d l2888: ld a,d or e pop hl jp z,l28a1 push de push hl call fwrite_ovl ; Write to overlay file pop hl ld de,RecLng add hl,de ex (sp),hl ld de,-RecLng add hl,de ex de,hl jp l2888 l28a1: call fclose_ovl ; Close overlay file ret ; ; ; l28a5: push hl call OVL.prep ; Prepare temp FCB call fopen_r_ovl ; Open overlay file ld hl,oDMA call fread_ovl ; Read overlay file ld hl,oDMA ld d,(hl) ; Get address inc hl ld e,(hl) pop hl call IsInRecord ; Test length .GT. record jp c,l28f0 ; .. nope push de ld de,RecLng call OVL.unp ; Unpack overlay buffer l28c6: pop de push hl ld hl,-RecLng ;; 128 add hl,de ex de,hl pop hl call IsInRecord ; Test length .GT. record jp c,l28e1 ; .. nope push de push hl call fread_ovl ; Read overlay file pop hl ld de,RecLng add hl,de jp l28c6 l28e1: ld a,d or e jp z,l28f3 push hl ld hl,oDMA push de call fread_ovl ; Read overlay file pop de pop hl l28f0: call OVL.unp ; Unpack overlay buffer l28f3: push hl call fclose_ovl ; Close overlay file pop hl ret ; ; Test range of record ; ENTRY Reg DE holds current length ; EXIT Carry flag set if length less record length ; IsInRecord: ld a,d or a ; Test HI ret nz ; .. ok ld a,e ; Test LO or a ret m ; Ok if .GEQ. 128 scf ; .. set .LT. ret ; ; Unpack overlay buffer ; ENTRY Reg DE holds length of data ; Reg HL holds address to be copied into ; OVL.unp: ld bc,oDMA ..OVL.unp: ld a,d ; Test end or e ret z ; .. yeap ld a,(bc) ; .. copy ld (hl),a inc hl inc bc dec de jp ..OVL.unp ; ; Convert ASCII HEX binary to character ; ENTRY Accu holds binary ; EXIT Accu and hold character ; GetExtNum: and 00001111b ; Mask LO part add a,'0' ; .. make ASCII cp '9'+1 ; Test range ld (hl),a ret c sub '9'-'A'+1 ; Fix for HEX ld (hl),a ret ; ; Print segment ; PrSeg: ld a,(OVL.num) ; Get overlay number ld hl,$SEG.num+1 push af call GetExtNum ; Build number dec hl pop af rra rra rra rra call GetExtNum ld hl,$SEGMENT jp puts ; Tell segment ; $SEGMENT: db '?Segment ' $SEG.num: db ' , ',null $FIL.NOFND: db 'file not found',null $FIL.NOCREC: db 'can''t create file',null $RD.ERR: db 'read error',null $WR.ERR: db 'Disk is full',null ; ; ; l297c: call PrSeg ; Print segment ld hl,$FIL.NOFND jp ErFilRes l2985: call PrSeg ld hl,$FIL.NOCREC jp ErFilRes l298e: call PrSeg call fclose_ovl ; Close overlay file ld hl,$RD.ERR jp ErFilRes l299a: call PrSeg call fclose_ovl ; Close overlay file ld hl,$WR.ERR jp ErFilRes ; ; Close overlay file ; fclose_ovl: ld de,oDMA ld c,.setdma call BDOS ; Reset buffer ld c,.close ld de,oFCB call BDOS ; Close file ret ; ; Read record from overlay file ; ENTRY Reg HL points to buffer ; fread_ovl: ld c,.setdma ex de,hl call BDOS ; Set buffer ld c,.rdseq ld de,oFCB call BDOS ; .. read record or a ; Test success jp nz,l298e ret ; ; Write record to overlay file ; ENTRY Reg HL points to buffer ; fwrite_ovl: ld c,.setdma ex de,hl call BDOS ; Set buffer ld c,.wrseq ld de,oFCB call BDOS ; .. write record or a ; Test success jp nz,l299a ret ; ; Open overlay file ; fopen_r_ovl: ld c,.setdma ld de,oDMA call BDOS ; Set default buffer ld c,.open ld de,oFCB call BDOS ; .. open file inc a ; Test success jp z,l297c ret ; ; Create overlay file ; fopen_w_ovl: ld c,.setdma ld de,oDMA call BDOS ; Set default buffer ld de,oFCB ld c,.delete call BDOS ; Delete existing file ld c,.make ld de,oFCB call BDOS ; .. create new one inc a ; Test success jp z,l2985 ret ; ; Prepare overlay FCB ; ENTRY Accu holds number of overlay ; OVL.prep: push af ld (OVL.num),a ; Set overlay number ld hl,oFCB+.drv+.nam+.ext-1 call GetExtNum ; .. build extension pop af rra rra rra rra dec hl call GetExtNum ld c,21 inc hl inc hl xor a ld (oFCB),a ; Set default drive l2a2a: ld (hl),a ; Clear rest of FCB inc hl dec c jp nz,l2a2a ret ; oDMA: ds RecLng OVL.num: db 0 oFCB: ;; l2ab2 db 0 ModName: ds _ModLen db ' ' db 'V ' ds 21 l2ad3: db '0' ; ; ##### END OF L80 ##### ; topl80: end