; Z80DOS - Z80 Disk Operating System ; ; Version 1.0 - 05 Sept. 87 by Carson Wilson ; ; ------------------------------------------------------------------- ; ; Z80DCHAR.Z80 - DOS Entry Points, Character I/O, and Error Routines ; ; ------------------------------------------------------------------- org DOS+6 ; Preserve serial number for CP/M ; ..overlay ; ; Start DOS ; start: jp entry ; Jump to entry point DOS ; ; Error messages DOS - for programs which intercept DOS errors ; defw 0 ; Bad Sector - not implemented StSel: defw SelErr ; Select error stro: defw rdonly ; Drive read only sfilro: defw filro ; File read only ; ; Run-time configurable options: ; timead: defw BIOStim ; Dummy or address of BIOS routine ; ..configurable at run time flags: defb options ; Flag bite ; ; 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 xor a ; Clear a ld (fldrv),a ; Reset drive select done flag ld (rdwr),a ; Reset read/write flag ld (spsave),sp ; Save stack pointer ld sp,DOSs ; 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 ld a,c ; Get function code 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 cp MaxCmd+1 ; Test greater then MaxCmd ret nc ; If so return to caller and do nothing ld hl,ctable ; Load table ld b,0 ; Prepare 16 bit add add hl,bc ; Add add hl,bc ; Add twice to get word value 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 ; 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 ;--------------------------- 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 error message--b.h. ; rderr: ld de,mrderr jr derror ; ; Write error message--b.h. wrterr: ld de,mwrter 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 ; Made more meaningful--b.h. ; msel: defm 'Illegal drive$' mfilro: defm 'File ' mro: defm 'R/O$' mrderr: db 'Read$' mwrter: db 'Write$' mberr: defm ' error on ' mdrive: defb 0 defb DrvSep defm '$' mbfunc: defm cr,lf,'Function', tab, '$' mfile: defm cr,lf,'File', tab, tab, '$' ; END Z80DCHAR.Z80