; ; Z80DOS - Z80 Disk Operating System ; ; Version 2.4 Maskable disk reset's using variable fixdrv ; Now can assemble with Z80MR if Z80MR equate ; set to -1. ; Gene Nolan 4/9/89 ; ;------------------------------------------------------ ; ; Version 2.3 Fast file lookup, ZRL compatability ; Date: 4 Nov 88 ; Update: Eugene Nolan ; ;------------------------------------------------------------ ; ; Version 2.0a - BETA TEST VERSION - 6 Nov 87 by Carson Wilson ; ; Support file: Z80DCHAR.Z80 ; Version: 2.0 ; Date: 6 Nov 87 ; Author: Carson Wilson ; Changes: Combined BIOS read and write error messages into one ; message - "Data error" so that BDOS error intecepts ; work same as standard CP/M. ; ; Added disk changed error routine. ; ; Description: DOS Entry Points, Character I/O, and Error Routines ; ; Use ONE only of the following lines: ;--------------------------------------------- ; Use following line for assembly to .COM file, comment it out for a .ZRL org DOS db 'Z80D24' ;--------------------------------------------- ; ; Start DOS ; start: jp entry ; Jump to entry point DOS ; ; Error messages DOS - for programs which intercept DOS errors ; StRW: defw RWErr ; Read or write error StSel: defw SelErr ; Select error stro: defw rdonly ; Drive read only sfilro: defw filro ; File read only ; ; Run-time configurable options: ; timead: if RTC defw BIOStim ; Dummy or address of BIOS routine else defw 0 endif ;RTC fixdrvs: dw 0 ; This word specifies fixed drives, ie: ; ones that do not need their ALV's ; re-built for every non-specific ; BDOS disk reset command. Set to ; 1 the bits for drives not to be reset ; 1=A; 3=A,B, 5=A,C etc flags: defb options ; Flag byte for public and ^S interrupt ; ---------------------------------------------------------------------- ; RAM area ; ------------- tabcnt: defb 0 ; Tab counter tabcx1: defb 0 ; Temporary tab counter (used by rdbuf) fcontp: defb 0 ; List enable flag (control p) lastch: defb 0 ; Last character delay: defb 0ffh ; Delay counter ; trans: defw 0 ; Translation vector temp0: defw 0 ; Number of files on drive dirbuf: defw 0 ; Directory buffer ixp: defw 0 ; Disk parameter block csv: defw 0 ; Checksum pointer alv: defw 0 ; Allocation vector pointer ; maxsec: defw 0 ; Maximum number of sectors/track nblock: defb 0 ; Number of blocks nmask: defb 0 ; Mask number of blocks nextnd: defb 0 ; Extent mask maxlen: defw 0 ; Maximum block number-1 nfiles: defw 0 ; Maximum number of files-1 ndir0: defb 0 ; First two entries alv buffer ndir1: defb 0 ncheck: defw 0 ; Number of checksum entries nftrk: defw 0 ; First track number ; dskro: defw 0 ; Disk R/O vector login: defw 0 ; Login vector diff: defw 0 ; Disk changed vector ; DMA: defw 080h ; DMA address ; funct: defb 0 ; Function number pexit: defw 0 ; Exit code fldrv: defb 0 ; Drive select used flag rdwr: defb 0 ; Read/write flag ; FCB0: defb 0 ; FCB byte 0 user: defb 0 ; User number drive: defb 0 ; Drive number defdrv: defb 0 ; Default drive number recdir: defw 0 ; Record directory (checksum) filcnt: defw 0 ; File counter secpnt: defb 0 ; Sector pointer subflg: defb 0 ; Submit flag (reset disk command) ; dcopy: defw 0 ; Copy address FCB searex: defb 0 ; Exit code search searnb: defb 0 ; Search number of bytes searqu: defb 0 ; Search question mark used searpu: defb 0 ; Search public file ; retflg: db 0 ; Allow retry on error when non-zero ; dtime db 0 ; Flag for UseStp cdate ds 2 ; Create date storage udate ds 4 ; Update date/time adate ds 4 ; Last access date/time ; spsave: defw 0 ; Stack pointer location defs 54 DOSstk: equ $ ; DOS internal 64 byte stack DOSstop equ $ ; ; ; Entry point for DOS commands ; Entry: ld a,c ; Get function number ld (funct),a ; Save it for later use ld hl,0 ; Set hl to zero ld (pexit),hl ; Clear exit code ld (fldrv),hl ld b,l ld (spsave),sp ; Save stack pointer ld sp,DOSstk ; Get internal stack pointer push ix ; Save index register push de ; Save parameter register pop ix ; Get it back in ix ld hl,p2exit ; Get exit address DOS push hl ; Save it on stack to return from DOS cp maxcmd+1 jr C,lowcmd cp 105 ; Test get time jp Z,gettim ; Yes then get time cp 104 ; Test set time jp Z,settim ; Yes then set time cp 55 ; Test use time stamp jp Z,UseStp cp 54 ; Test get time stamp jp Z,Getstp ret lowcmd: ld hl,ctable ; Load table add a,c ld c,a add hl,bc ; Add ld a,(hl) ; Get LSB inc hl ; Pointer to MSB ld h,(hl) ; Get MSB ld l,a ; Save LSB in l jp (hl) ; Jump to routine ; ; Command Jump Table ; CTable: defw WBoot ; Warm boot defw rdcon ; Console input defw bwrcon ; Console output defw rdrdr ; Reader input defw wpunch ; Punch output defw wlist ; List output defw dcio ; Direct console I/O defw giost ; Get I/O byte defw siost ; Set I/O byte defw mess ; Print string defw rdbuf ; Read console buffer defw tstcs ; Get console status defw cmnd12 ; Return version number defw cmnd13 ; Reset disk system defw cmnd14 ; Select disk defw cmnd15 ; Open file defw cmnd16 ; Close file defw cmnd17 ; Search for first defw cmnd18 ; Search for next defw cmnd19 ; Delete file defw cmnd20 ; Read sequential defw cmnd21 ; Write sequential defw cmnd22 ; Make file defw cmnd23 ; Rename file defw cmnd24 ; Return login vector defw cmnd25 ; Return current disk defw cmnd26 ; Set DMA address defw cmnd27 ; Get address allocation vector defw cmnd28 ; Write protect disk defw cmnd29 ; Get R/O vector defw cmnd30 ; Set file attributes defw cmnd31 ; Get address disk parameter header(dph) defw cmnd32 ; Get/set user code defw cmnd33 ; Read random defw cmnd34 ; Write random defw cmnd35 ; Compute file size defw cmnd36 ; Set random record defw cmnd37 ; Reset multiple drive defw dummy ; Access drive - not implemented defw gfixed ; Get fixed login vector defw cmnd40 ; Write random with zero fill ; --------------------------------- ; Return current fixed drive vector gfixed: ld hl,(fixdrvs) jp cmd24a ; --------------------------------- ; Character Routines ; --------------------------------- ; DOS console input ; ; Read character from console and echo ; if char=cr, lf, tab, ContH or >=space ; RdCon: call getch ; Get character call tstch ; Test if cr,lf,tab,ContH or >=space jr C,exit ; No then exit call wrcon ; Echo character exit: ld (pexit),a ; Return character dummy: ret ; And exit DOS ; ; DOS write console ; bwrcon: ld a,e ; Copy character jr wrcon ; And output it ; ; read reader ; rdrdr: call reader ; Get character from reader jr exit ; And return it to caller ; ; write punch ; wpunch: ld c,e ; Copy character jp punch ; And output it to punch device ; ; Write list ; wlist: ld c,e ; Copy character jp list ; And output it to list device ; ; Direct console input/output ; DCIO: ld c,e ; Copy character inc e ; Test if 0ffh jr Z,dcio0 ; Yes do input inc e ; Test if 0feh jp NZ,ConOut ; No then output character call ConSt ; Get console status and 1 ; Test it jr exit ; And return it to caller DCIO0: call ConSt ; Get console status and 1 ; Test it ret Z ; Exit if no character present call ConIn ; Get character jr exit ; And return it to caller ; ; Get I/O status byte ; giost: ld a,(RamLow+00003h) ; Get I/O byte from ram jr exit ; And return it to caller ; ; Set I/O status byte ; siost: ld a,e ; Copy I/O byte ld (RamLow+00003h),a ; And save it in ram ret ; Exit to caller ; ; Test console status ; tstcs: call gConSt ; Get console status jr exit ; And return it to caller ; ; Output char (control char = ^char) ; outch: call tstch ; Test it cr,lf,tab,ContH or >=space jr NC,wrcon ; Yes then jump push af ; Save character ld a,'^' ; Load a with '^' call wrcon ; Output it pop af ; Get character back push af ; Save it again add a,'A'-1 ; Add offset call wrcon ; Output it pop af ; Get character ret ; Return to caller ; ; Echo cr,lf ; CROut: ld a,cr ; A=carriage return call wrcon ; Output it ld a,lf ; A=line feed ; Fall through to output routine ; ; Write character on console ; wrcon: cp tab ; Test if tab jr NZ,wrcon1 ; No then jump wrcon0: ld a,' ' ; Expand tab with spaces call wrcon ; Write space ld a,(tabcnt) ; Get tab count and 7 ; Test if done jr NZ,wrcon0 ; No then repeat ld a,tab ; Return tab ret ; Return to caller wrcon1: push af ; Save character call gConSt ; Test status and ContS/ContC pop af ; Get character back push af ; Save it again ld c,a ; Copy it call ConOut ; Output it pop af ; Get character back push af ; Save it again ld c,a ; Copy it ld a,(fContP) ; Get printer echo flag or a ; Test it call nz,list ; Non zero => output char to printer ld a,(flags) ; Get flag byte bit 1,a ; Test delay 256 bytes active jr Z,wrcon2 ; No then exit ld hl,delay ; Get delay counter xor a ; A=0 or (hl) ; Test counter=0 jr Z,wrcon2 ; Yes then exit dec (hl) ; Else decrement counter wrcon2: pop af ; Restore character ; Fall through to count routine ; ; Count characters in line ; countc: ld hl,tabcnt ; Get pointer to tab counter inc (hl) ; Increment tab counter cp ' ' ; Test if char >= ' ' ret NC ; Yes, normal character then exit dec (hl) ; Control character, decrement tab count cp ContH ; Test backspace jr NZ,count0 ; No backspace then jump dec (hl) ; Decrement tab counter ret ; And exit count0: cp cr ; Test carriage return jr NZ,count1 ; No then jump ld (hl),0 ; Reset tab count ret ; And exit count1: cp tab ; Test tab character ret NZ ; No then exit push af ; Save character ld a,(hl) ; Get tab count add a,8 ; Advance it 8 position and 0f8h ; Set it to next tab position ld (hl),a ; Save it pop af ; Restore character ret ; And exit ; ; Get character from console ; getch: ld hl,lastch ; Get pointer to last input character ld a,(hl) ; Get character ld (hl),0 ; Reset last character or a ; Test if character present ret NZ ; Return if so jp ConIn ; Else get character ; ; Get console status ; gConSt: ld a,(delay) ; Get 256 bytes delay or a ; Test it jr NZ,gcons0 ; Non zero, delay stil active or disabled call ConSt ; Get console status and 1 ; Test it jr NZ,gcons1 ; Non zero then get character gcons0: ld a,(lastch) ; Get last character or a ; Test it jr NZ,gcons3 ; Non zero then character present call ConSt ; Get console status and 1 ; Test it ret Z ; Return if no character present gcons1: call ConIn ; Get character cp ContS ; Test stop character jr NZ,gcons2 ; Not then exit character call ConIn ; Get next character cp ContC ; Test if user wants to exit jp Z,RamLow+00000h ; Yes then warm boot jr gConSt ; Test again gcons2: ld (lastch),a ; Save character ld a,0ffh ; Set delay counter ld (delay),a ; And save it gcons3: ld a,1 ; Character present code ret ; Return to caller ; ; Test character ; exit carry=0: cr,lf,tab,ContH or >=space ; carry=1: all other characters ; tstch: cp cr ; Test carriage return ret Z ; Return if so cp tab ; Test tab ret Z ; Return if so cp ContH ; Test backspace ret Z ; Return if so cp rubout ret Z cp ' ' ; Test >=space ret ; Return to caller ; ; Write backspace, space, backspace ; wContH: call wcont0 ; Write backspace ld c,' ' ; Load space call ConOut ; And output it wcont0: ld c,ContH ; Load backspace jp ConOut ; And output it ; ; Output message ; mess: ld a,(de) ; Get byte from buffer cp '$' ; Test last byte ret Z ; Yes, then return to caller inc de ; Point to next byte push de ; Save pointer call wrcon ; Output character pop de ; Restore pointer jr mess ; And test again ; again: ld hl,tabcnt ; Get tab count pointer ld a,(tabcx1) ; Get position first character line cp (hl) ; Check it ret Z ; Return if on same position ld a,' ' ; Load space call wrcon ; Output it jr again ; And test again ; ; Delete char ; entry : HL = start buffer - 1 ; B = character counter (always > 0) ; delch: dec b ; Decrement character counter ld a,(tabcnt) ; Get tab counter push af ; Save it push bc ; Save character counter ld a,(tabcx1) ; Get position first character line ld (tabcnt),a ; Save it in tab counter delch0: ld a,b ; Copy character counter or a ; Test if 0 jr Z,delch2 ; Yes then jump dec b ; Decrement it inc hl ; Increment buffer pointer ld a,(hl) ; Get character from buffer push hl ; Save buffer pointer call tstch ; Test if cr,lf,tab,ContH or >=sp jr NC,delch1 ; Yes then jump rra ; Else must be control character call countc ; Count control character twice delch1: call countc ; Count character pop hl ; Get buffer pointer jr delch0 ; And test again delch2: pop bc ; Restore character counter pop af ; And tab counter push hl ; Save buffer pointer push bc ; And character counter ld hl,tabcnt ; Get tab counter pointer sub (hl) ; Calculate difference delch3: dec a ; Decrement it cp 8 ; Compare with 8 jr NC,delch4 ; Jump if >=8 push af ; Save difference call wContH ; Remove character end line pop af ; Restore counter jr delch3 ; Remove more characters delch4: pop bc ; Restore character counter pop hl ; Restore buffer pointer ret ; And return to caller ; ; Read buffer ; rdbuf: ld a,(tabcnt) ; Get current position cursor ld (tabcx1),a ; Save it rdbuf0: push ix ; Save start address buffer pop hl ; Get it in hl ld c,(hl) ; Get maximum line lenght inc hl ; Increment to line lenght position ld b,0 ; Clear line lenght counter push hl ; Save start line - 1 rdbuf1: push hl ; Save registers push bc rdbuf2: call getch ; Get character pop bc ; Restore registers pop hl and 07fh ; Mask character rdbuf3: cp ContH ; Test backspace jr NZ,rdbuf4 ; Not then jump doback: ld a,b ; Test if deleting char from empty line or a jr Z,rdbuf1 ; Yes then get next char pop hl ; Get start line push hl ; And save it again call delch ; Delete character jr rdbuf1 ; Get next character rdbuf4: cp ContP ; Test print enable/disable jr NZ,rdbufC ; Not then jump ld a,(fContP) ; Complement print flag cpl ld (fContP),a rdbufc: cp ContX ; Test delete line jr NZ,rdbufe ; Not then jump rdbufd: pop hl ; Get start line ld a,b ; Test if last character deleted or a jp Z,RDBUF ; Yes start routine again push hl ; Save pointer call delch ; Delete last character line jr rdbufd ; Test last character deleted rdbufe: cp rubout ; Test delete last character jr NZ,rdbuff ; Not then jump jr doback ; Part of delete key fix rdbuff: cp cr ; Test carriage return jr Z,rdbufi ; Yes, then exit inc hl ; Increment pointer ld (hl),a ; And save character inc b ; Increment line counter rdbufg: push hl ; Save registers push bc call outch ; Echo character pop bc ; Restore registers pop hl cp ContC ; Test warm boot ld a,b ; Get line count jr NZ,rdbufh ; No warm boot then jump cp 1 ; Test ContC is first character line jp Z,RamLow+00000h ; Yes then execute warm boot rdbufh: cp c ; Test line length=maximum line length jp NZ,rdbuf1 ; Not then get next character rdbufi: pop hl ; Get start line - 1 ld (hl),b ; Save line counter ld a,cr ; Load carriage return jp wrcon ; And echo it ;--------------------------- ; Error routines ;--------------------------- ; ; Disk changed error ; ChgErr: ld de,mchg ; Load changed error message jr derror ; And display error ; ; Select error ; SelErr: ld de,msel ; Load selected error message jr derror ; And display error ; ; File read only error ; FilRO: ld de,mfilro ; Load file R/O message ld a,0ffh ; Set file R/O message flag jr error ; And display error ; ; Read/Write error ; RWErr: ld de,mrwerr jr derror ; ; Drive read only error ; rdonly: ld de,mro ; Load drive R/O message derror: xor a ; Set no file R/O message ; fall thru ; ; Display error message ; ; "Error message" error on d: ; Function nn ; File filename.typ ; error: ld c,a ; Save file R/O message flag push bc push de ; Save error message pointer call crout ; Display cr/lf pop de call mess ; Display error ld a,(defdrv) ; Get current drive add a,'A' ; Make ASCII ld (mdrive),a ; Save it ld de,mberr ; Load message " error on d:" call mess ; Display message ld de,mbfunc ; Load message "function " call mess ; Display message ld a,(funct) ; Get function number push af ; Save it ld bc,100 ; Display number / 100 call num ld c,10 ; Display number / 10 call num ld bc,101h ; Always display number / 1 call num pop af ; Get function number pop bc ; Get file R/O flag cp 15 ; Test if FCB used in command jr C,error3 ; Commands <16, don't show filename cp 24 jr C,error1 ; Commands 16..23 show file cp 30 jr Z,error1 ; Command 30 show file cp 33 jr C,error3 ; Other commands 24..32 no file cp 37 jr C,error1 ; 33..36 show cp 40 jr NZ,error3 ; 37 don't show error1: push ix ; Display "file =" sub 19 ; Test delete file function jr NZ,error2 ; Not then jump or c ; Test file R/O flag jr Z,error2 ; No file R/O then jump call caldir ; Get FCB from directory buffer ex (sp),hl ; Save it error2: ld de,mfile ; Get message " file =" call mess ; Display message pop hl ; Get pointer FCB ld b,8 ; Display first 8 characters call filenm ld a,'.' ; Load '.' push hl ; Save FCB pointer call wrcon ; Echo it pop hl ; Restore FCB pointer ld b,3 ; Display last 3 characters call filenm ; Absorb any pending characters: error3: call gConSt ; Test if character pending or a jr Z,error4 ; No then jump call getch ; Get character jr error3 ; And test again ; ; Allow retry on read/write errors ; error4: ld a,(retflg) ; Allow retry? or a jr Z,error5 ; No xor a ld (retflg),a ; Reset flag call getch cp ContC ; Control-c entered? ret NZ ; No, retry error5: xor a ; Make sure no use stamp flag is ; around when we warmboot ld (dtime),a jp RamLow+00000h ; Do warm boot ; ; Display number ; num: ld d,0ffh ; Load number -1 num1: inc d ; Increment number sub c ; Divide by c jr NC,num1 ; Not finished then loop add a,c ; Restore last value push af ; Save it ld a,d ; Test if "0" or b ; And if leading zero jr Z,num2 ; Yes, then exit ld b,a ; Set no leading zero ld a,d ; Get number add a,'0' ; Make ASCII push bc ; Save registers call wrcon ; Echo number pop bc ; Restore registers num2: pop af ; Restore number ret ; And exit ; ; Display filename.typ ; filenm: inc hl ; Increment pointer FCB ld a,(hl) ; Get character from FCB and 07fh ; Mask it push hl ; Save registers push bc call wrcon ; Echo character pop bc ; Restore registers pop hl djnz filenm ; Repeat b times ret ; And exit ; ; Error messages ; Made more meaningful--b.h. ; mchg: db 'Dk ch$' ;DISK CHANGED msel: db 'Il dr$' ;ILLEGAL DRIVE mfilro: db 'Fl ' ;FILE mro: db 'RO$' ;READ ONLY mrwerr: db 'Dt$' ; DATA BIOS read/write error mberr: defm ' eron ' ;ERROR ON mdrive: defb 0 defb DrvSep defm '$' mbfunc: defm cr,lf,'Ft',tab,'$' ;FUNCTION mfile: defm cr,lf,'Fi',tab,'$' ;FILE ; END Z80DCHAR.Z80