; Z80DOS - Z80 Disk Operating System Nov 15, 1988 ; ; Version 2.31 Fast file lookup lookup for random records fix ; Date: 15 Nov 88 ; Update: Eugene Nolan ; ;----------------------------------------------------------------------- ; ; 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 ; ORG DOS+6 ; Preserve serial number for CP/M ; ; Use the following line for assembly to .ZRL ; ; DB 'Z80D23' ; ;----------------------------------------------------------------------- ; ; 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: DS 0 ; IF RTC DEFW BIOSTIM ; Dummy or address of BIOS routine ; ELSE DEFW 0 ENDIF ; RTC FLAGS: DEFB OPTIONS ; Flag byte for public and ^S interrupt ; ; 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 DUMMY ; Free drive - not implemented DEFW CMND40 ; Write random with zero fill ; ;----------------------------------------------------------------------- ; ; 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 ; ; 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 ; ; 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: JP RAMLOW+00000H ; Do warm boot ; ; Display number ; NUM: LD D,-1 ; 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 ; 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 ;