Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/86DEV/PCBIOS.A86
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

3995 lines
83 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;*********************************************
;* *
;* IBM-PC Basic I/O System (PCBIOS) *
;* *
;* For CPM-86 v1.1 *
;* *
;*********************************************
;
; 31/12/1998
;
; Code/data yet to comment....
;1. 3fef - setting i/o routines pointer (byte 47e1)
;2. SOSTATC TEST CL,AH
;3. VIDCOM -label calls to
;4. 4980 offset ??
;5. chkcp3 - comment
;6. chkcp4 - comment
;7. 2be5
;8. 3d52
;
; BUGS in original code
; ---------------------
; 1. labeled 'BUG DI' - Incorrectly using DI instead of SI
;
;#rcpmx.xxx
;
; Start End
;139D:0000 139D:47FF
;#l2500,47ff
; Ascii characters
CTRLC EQU 03H
BEL EQU 07H
BS EQU 08H
LF EQU 0AH
CR EQU 0DH
ESC EQU 1BH
; Logical
TRUE EQU 0FFH
FALSE EQU 0
; Addresses
CCP_OFFSET EQU 0000H
BDOS_OFST EQU 0B06H ; BDOS entry point
BIOS_CODE EQU 2500H
;*********************************************
;* *
;* Dummy Data Section *
;* *
;* for Interrupt Vectors *
;* *
;*********************************************
DSEG 0 ; MEMORY ZERO PAGE
ORG 0 ;
ZEROOFF RW 1 ; DIV BY ZERO OFFSET
ZEROSEG RW 1 ; AND SEGMENT
ORG 4*01BH
BREAKOFF RW 1 ; USER BREAK OFFSET
BREAKSEG RW 1 ; AND SEGMENT
TIMEROFF RW 1 ; TIMER INT OFFSET
TIMERSEG RW 1 ; AND SEGMENT
ORG 4*01EH
I1EOFF RW 1 ; DISK PARM POINTER OFFSET
I1ESEG RW 1 ; AND SEGMENT
ORG 4*0E0H
BDOSOFF RW 1 ; BDOS ENTRY OFFSET
BDOSSEG RW 1 ; AND SEGMENT
ORG 4*0E6H
UNDSKOFF RW 1 ; UNKNOWN DISK DRIVE INT OFFSET
UNDSKSEG RW 1 ; AND SEGMENT
;*********************************************
;* *
;* Dummy Data Section *
;* *
;* for Page 0040H *
;* *
;*********************************************
DSEG
ORG 10H
BIOSHDW RB 1 ; BIOS hardware setting
;*********************************************
;* *
;* Dummy Data Section *
;* *
;* for BDOS Data *
;* *
;*********************************************
DSEG
ORG 24A5h
BDOSUSER RB 1 ; USER NUM HIDES HERE
ORG 24AFh
BDOSMODABT RB 1 ; BDOS ABORT MODE
ORG 24B7h
BDOSCURDRV RB 1 ; BDOS CURRENT DRIVE
ORG 24BDh
DHOUR RB 1 ; DECIMAL HOURS
DMINUTE RB 1 ; DECIMAL MINUTES
DSECOND RB 1 ; DECIMAL SECONDS
;
AMONTH RW 1 ; ASCII MONTH
RB 1 ; /
ADAY RW 1 ; ASCII DAY
RB 1 ; /
AYEAR RW 1 ; ASCII YEAR
RB 1 ; ,
AHOUR RW 1 ; ASCII HOURS
RB 1 ; :
AMINUTE RW 1 ; ASCII MINUTES
RB 1 ; :
ASECOND RW 1 ; ASCII SECONDS
RB 1
SYSMESSAGE RB 14 ; SYS STATUS MESSAGE
BDOSCONWID RB 1 ; BDOS CONSOLE WIDTH
;*********************************************
;* *
;* Dummy Code Section *
;* *
;* for CCP entry points *
;* *
;*********************************************
CSEG
ORG ccpoffset
CCP:
;*********************************************
;* *
;* Code Section *
;* *
;* BIOS Jump Vector for Individual Routines *
;* *
;*********************************************
CSEG
ORG bios_code
JMP INIT ; Enter from BOOT ROM or LOADER
JMP WBOOT ; Arrive here from BDOS call 0
JMP CONST ; Return console keyboard status
JMP CONIN ; Return console keyboard char
JMP CONOUT ; Write char to console device
JMP LISTOUT ; Write character to list device
JMP PUNCH ; Write character to punch device
JMP READER ; Return char from reader device
JMP HOME ; Move to trk 00 on cur sel drive
JMP SELDSK ; Select disk for next rd/write
JMP SETTRK ; Set track for next rd/write
JMP SETSEC ; Set sector for next rd/write
JMP SETDMA ; Set offset for user buff (DMA)
JMP READ ; Read a 128 byte sector
JMP WRITE ; Write a 128 byte sector
JMP LISTST ; Return list status
JMP SECTRAN ; Xlate logical->physical sector
JMP SETDMAB ; Set seg base for buff (DMA)
JMP GETSEGT ; Return offset of Mem Desc Table
JMP GETIOB ; Return I/O map byte (IOBYTE)
JMP SETIOB ; Set I/O map byte (IOBYTE)
RS 15 ; Reserved - 5 more JMP's
; Pointers to
DW Offset PFKTABLE ; - Function keys data
DW Offset DISK ; - Disk parameters
DW Offset SER1 ; - Serial port init parameters
DB 010h,033h ; - Device data
DW Offset FIDDSMEM ; - FIDD data
DW Offset CRTMOD ; - Screen data
DB 'Copyright (C) 1983, Digital Research'
;----------------------------------------
; Arrive here from BDOS call 0
;
WBOOT:
MOV Byte Ptr X3A70,0 ; Default drive on startup ?
MOV Byte Ptr X3A6D,0FFh ; Disk error or change ???
JMP CCP+6 ; Jump to cold start entry of CCP
;*********************************************
;* *
;* CP/M Character I/O Interface Routines *
;* *
;*********************************************
; Return console keyboard char
;
; Input: none
; Output: AL:=char AND 07FH
;
CONIN:
MOV AX,Word Ptr SYS_CONI
JMPS XINPUT
;
; Write char to console device
;
; Input: CL:=char
; Output: none
;
CONOUT:
MOV AX,Word Ptr SYS_CONO
JMPS XOUTPUT
;
; Return console keyboard status
;
; Input: none
; Output: IF ready THEN AL:=0FFH
; ELSE AL:=00
;
CONST:
MOV AX,Word Ptr SYS_CONI
MOV CL,01h
JMPS XOSTATUS
;
; Return char from reader device
;
; Input: none
; Output: AL:=char AND 07FH
;
READER:
MOV AX,Word Ptr SYS_AUXI
JMPS XINPUT
;
; Write character to punch device
;
; Input: CL:=char
; Output: none
;
PUNCH:
MOV AX,Word Ptr SYS_AUXO
JMPS XOUTPUT
;
; Write character to list device
;
; Input: CL:=char
; Output: none
;
LISTOUT:
MOV AX,Word Ptr SYS_LST
JMPS XOUTPUT
;
; Return list status
;
; Input: none
; Output: IF ready THEN AL:=0FFH
; ELSE AL:=00
;
LISTST:
MOV AX,Word Ptr SYS_LST
MOV CL,20h
JMPS XOSTATUS
;
; Common character input routine
;
XINPUT: CLD
MOV BX,Offset INROUTINES
MOV CX,11 ; Only 11 possible routines
SUB DX,DX
XINPUT1:
ROR AX,1h
JNB XINPUT2
JMP Word Ptr [BX] ; Transfer to first routine
XINPUT2:
INC BX ; Next routine
INC BX
LOOP XINPUT1
JMP KEYIN ; No more - assume keyboard
;
; Common character output routine
;
XOUTPUT:
CLD
MOV BX,Offset OUTROUTINES
MOV CH,11 ; Only 11 possible routines
XOUTPUT1:
ROR AX,1 ; Is this it
JNB XOUTPUT2 ; No
PUSH AX
PUSH BX
PUSH CX
SUB DX,DX
CALL Word Ptr [BX] ; Transfer to that routine
POP CX
POP BX
POP AX
XOUTPUT2:
INC BX ; Check for next
INC BX
DEC CH ; Any more?
JNZ XOUTPUT1 ; Try again
RET ; Now leave
;
;
; Common input status
;
; Routine to return status of CONSOLE or LIST device
;
XOSTATUS:
MOV BX,Offset OUTSTATUS
MOV CH,0Bh
SUB DX,DX
XOSTAT1:
ROR AL,1
JB XOSTAT2
INC BX
INC BX
DEC CH
JNZ XOSTAT1
MOV AL,0FFh
RET
XOSTAT2:
JMP Word Ptr [BX]
;
;
; Keyboard status
; Exit: AL = 0ffh if char ready
; AL = 0 if not ready
;
KEYSTAT:
PUSH SI
MOV SI,Word Ptr KEYPTR ; Check PFK buffer
MOV AL,[SI] ; Char from buffer
POP SI
TEST AL,AL ; Valid if not zero
JNZ KEYSTAT1 ; Skip if readys
;
MOV AH,01h ; Read keyboard status
INT 16h ; PC ROM BIOS Keyboard Service
MOV AL,0 ; Assume not readys
JZ KEYSTAT2
KEYSTAT1:
MOV AL,0FFh ; Character readys
KEYSTAT2:
RET
;
;
; Keyboard input
; Exit: AL = char
;
KEYIN: PUSH SI
KEYIN1: MOV SI,Word Ptr KEYPTR ; Check key buffer
LODSB ; Get the character
TEST AL,AL ; Return buf char
JZ KEYIN3 ; Else read keyboard
MOV Word Ptr KEYPTR,SI
KEYIN2: POP SI
RET
KEYIN3: SUB AH,AH ; Read char from keyboard
INT 16h ; PC ROM BIOS Keyboard Service
AND AL,7Fh
JNZ KEYIN2 ; Return if ascii
;
; Check for programmable function keys
;
PUSH CX
PUSH DI
PUSH ES
MOV AL,AH ; Get key code
CALL GETPFK ; AX -> pfk entry
JC KEYIN4 ; C set if illegal
;
MOV SI,AX ; Table pointer
MOV DI,Offset KEYBUF
MOV Word Ptr KEYPTR,DI ; Checked at entry
REP MOVSB ; Move to keybuffer
KEYIN4: POP ES
POP DI
POP CX
JMP KEYIN1 ; Start it
;
; Point to PFK entry
; Entry: AL = key code
; Exit: AX = pointer to table entry
; CX = Length of table entry
; Carry = not a legal PFK
;
GETPFK: MOV DI,CS
MOV ES,DI
MOV DI,Offset PFKSCAN ; Function key scancode table ?
MOV CX,20
REPNE SCASB
STC ; Assume illegal
JNZ GETPFK2 ; Exit if not found
;
MOV AX,20
MUL CL
ADD AX,Offset PFKTABLE ; Offset to table entry
MOV CX,20 ; Length of table entry
GETPFK2:
RET
;
;
; Video output routine
;
VIDOUT: JMP Word Ptr STATE
;
;
; Null output routine
;
NULLST:
MOV AL,0FFh
RET
;
; Normal ascii video vector
; Character is in the AL register (CL on entry)
;
VIDNORM:
MOV AL,CL
VIDNORM1:
MOV DX,Word Ptr CURSOR ; Collect cursor position
CMP AL,BS
JZ VIDBS ; Back space
CMP AL,LF
JZ VIDLF ; Line feed
CMP AL,CR
JZ VIDCR ; Carriage return
CMP AL,ESC
JZ VIDESC ; Escape
CMP AL,BEL
JZ VIDBEL ; Beep
;
; Printable ascii characters fall through
;
VIDASCII:
MOV AH,09h ; Write code
MOV BH,0 ; Page 0
MOV CX,1 ; One copy of char
MOV BL,Byte Ptr ATTRIB ; Attribute
CALL VIDCOM ; Write it
;
INC DL ; Next column
CMP DL,Byte Ptr CRTCOL ; Past the edge ?
JB SETCURSOR ; If not, skip
;
; Test for end of line wrap around
;
TEST Byte Ptr WRAPFLAG,TRUE
JZ VIDRETURN ; If no wrap, done
;
CALL VIDCR ; Else, do a return
; Fall into a line feed
;
; Video line feed
;
VIDLF: INC DH ; Next line
CMP DH,18h ; At page end?
JB SETCURSOR ; If not, skip
MOV AX,0601h ; Scroll one line
SUB CX,CX ; Upper left corner
JMP VDASLIN2 ; Do it
;
; Video carriage return
;
VIDCR: MOV DL,0 ; First column
;
SETCURSOR:
MOV Word Ptr CURSOR,DX ; Update our copy
MOV AH,2 ; Set cursor code
MOV BH,0 ; Page 0
CALL VIDCOM
RET
;
; Video back space
;
VIDBS: DEC DL ; Back one column
JNS SETCURSOR ; If pos, no prob
;
TEST Byte Ptr WRAPFLAG,TRUE ; If no wrap around
JZ VIDRETURN ; Then forget it
;
DEC DH ; If top row,
JS VIDRETURN ; Then forget it
MOV DL,Byte Ptr CRTCOL ; Else wrap around
DEC DL
JMPS SETCURSOR
VIDBEL: MOV SI,Offset SNDTBL1
JMP BEEP
;
; Video escape - set up state vector
;
VIDESC: MOV Word Ptr STATE,Offset VIDESC1
;
VIDRETURN:
RET
;
; Character after escape comes here
;
VIDESC1:
CALL VPCOMP ; Clear the STATE incase
DISPATCH:
MOV DX,Word Ptr CURSOR ; Setup the cursor
PUSH DI
PUSH ES
MOV DI,CS
MOV ES,DI
MOV DI,Offset ESCTBL ; Point to search table
MOV AL,CL
MOV CX,0029h
REPNE SCASB ; Search ESC char table
POP ES
POP DI
JZ DISPATCH1 ; Found
JMP VIDASCII ; No, must be printable
DISPATCH1:
MOV BX,Offset ESCJMP ; Point to routine table
ADD CX,CX
SUB BX,CX
JMP Word Ptr [BX] ; Transfer to it
;
; ESC H - home cursor
;
VHOME:
SUB DX,DX ; 0,0 = Top left
SETCUR: JMP SETCURSOR ; For local short
;
; ESC E - erase screen and home cursor
;
VEOSALL:
CALL VHOME ; Get to top left
SUB CX,CX
MOV DH,17h
MOV DL,Byte Ptr CRTCOL
DEC DL
JMP VEOLEND1 ; Erase to end of screen
;
; ESC A - cursor up
;
VUP: DEC DH ; Row = row - 1
JNS SETCUR ; If pos, set cursor
RET ; Else forget it
;
; ESC B - cursor down
;
VDOWN: INC DH ; Row = row + 1
CMP DH,18h ; Too far ?
JB SETCUR ; If not, set cursor
RET ; Else ignore
;
; ESC C - cursor forward (right)
;
VFORW: INC DL ; Col = col + 1
CMP DL,Byte Ptr CRTCOL ; Too far ?
JB SETCUR ; If not, set cursor
RET ; Else ignore
;
; ESC D - cursor back (left)
;
VBACK: DEC DL ; Col = col - 1
JNS SETCUR ; Not to far, set cursor
RET ; Else ignore
;
; ESC I - cursor up (scroll at top)
;
VUPSAT: TEST DH,DH ; Top of screen ?
JNZ VUP ; No, cursor up
JMP VIASLIN ; Yes, insert line and scroll down
;
; ESC j - save cursor position
;
VSAVCUR:
MOV Word Ptr SAVECURSOR,DX ; Stash it
RET
;
; ESC k - restore (saved) cursor position
;
VRSTCUR:
MOV DX,Word Ptr SAVECURSOR ; Get it back
JMP SETCUR ; and set it
;
; ESC Y - set cursor position
;
VSETCUR:
MOV Word Ptr STATE,Offset VSET1
RET ; Look for next char
;
; ESC Y part 1 - set cursor row
;
VSET1: SUB CL,20h ; Correct
JNS VSET1A ; Skip if positive
MOV CL,0 ; Else top row
VSET1A: CMP CL,18h
JB VSET1B ; Skip if ok
MOV CL,17h ; Else page bottom
VSET1B: MOV Byte Ptr CURROW,CL ; Save cursor row
MOV Word Ptr STATE,Offset VSET2
RET ; Ready for column
;
; ESC Y part 2 - set cursor column
;
VSET2: SUB CL,20h ; Correct
JNS VSET2A ; Skip if positive
MOV CL,0 ; Else first col
VSET2A: CMP CL,Byte Ptr CRTCOL
JB VSET2B ; Skip if ok
MOV CL,Byte Ptr CRTCOL ; Else last col
DEC CL
VSET2B: MOV DX,Word Ptr CURSOR ; Get the value
MOV DL,CL ; Update row
CALL VPCOMP ; Reset STATE
JMP SETCURSOR ; Move cursor now
;
; ESC J - erase to end of screen (from cursor)
;
VEOSEND:
PUSH DX ; Save cursor
CALL VEOLEND ; Erase to end of line
POP DX
CMP DH,17h
JB VEOSEND1
RET
;
VEOSEND1:
INC DH
MOV CH,DH
MOV CL,0
MOV DH,17h
MOV DL,Byte Ptr CRTCOL
DEC DL
JMPS VEOLEND1 ; Erase to end of screen
;
; ESC l - Erase current line (all characters)
;
VECLIN:
MOV CH,DH
MOV CL,0
MOV DL,Byte Ptr CRTCOL
DEC DL
JMPS VEOLEND1 ; Erase to end of line
;
; ESC o - erase beginning of line to cursor
;
VEOLBEG:
MOV CH,DH
MOV CL,0
DEC DL
JNS VEOLEND1 ; Erase to end of screen
RET
;
; ESC K - erase to end of line
;
VEOLEND:
MOV CX,DX
MOV DL,Byte Ptr CRTCOL
DEC DL
VEOLEND1:
MOV BH,Byte Ptr ATTRIB
AND BH,Byte Ptr X36B8
MOV AX,0700h
JMP VIDCOM
;
; ESC L - insert line and scroll down
;
VIASLIN:
MOV AX,0701h
JMPS VDASLIN1
;
; ESC M - delete line and scroll up
;
VDASLIN:
MOV AX,0601h
;
VDASLIN1:
CMP DH,17h
JZ VECLIN ; Erase current line (all characters)
MOV CH,DH
MOV CL,0
;
VDASLIN2:
MOV DH,17h
MOV DL,Byte Ptr CRTCOL
DEC DL
MOV BH,Byte Ptr ATTRIB
AND BH,Byte Ptr X36B8
JMP VIDCOM
;
; ESC N - delete character at cursor (moving other charcters to fill gap)
;
VDELCHR:
MOV AL,Byte Ptr CRTCOL
SUB AL,DL
CBW
MOV DI,AX
CALL VSETCUR3
MOV DL,Byte Ptr CRTCOL
DEC DL
MOV SI,0720h
MOV BH,0
MOV CX,0001h
VDELCHR1:
MOV AH,02h
CALL VIDCOM
MOV AH,08h
CALL VIDCOM
XCHG AX,SI
MOV BL,AH
MOV AH,09h
CALL VIDCOM
DEC DL
DEC DI
JNZ VDELCHR1
JMP VRSTCPT ; Restore cursor posn and type
;
; ESC a - set video mode
;
VSETMODE:
MOV Word Ptr STATE,Offset VSETMODE1
RET ; Get next char
;
; ESC a (mode) - set video mode
;
VSETMODE1:
MOV AL,CL ; Required mode
CALL SETCURCRT ; Set current video details
CALL VSETCUR3
PUSH ES
MOV AX,0040h
MOV ES,AX
MOV AL,ES:Byte Ptr BIOSHDW
AND AL,0CFh
OR AL,Byte Ptr CRTBVM ; Set BIOS video mode
MOV ES:Byte Ptr BIOSHDW,AL ; Store BIOS equipment work
POP ES
MOV AL,Byte Ptr CRTMOD ; Mode
MOV AH,0
CALL VIDCOM
CALL VEOSALL ; Erase screen and home cursor
CALL CLRBOS1 ; Clear status line
CALL VRSTCPT ; Restore cursor posn and type
JMP VPCOMP ; Reset STATE
;
; ESC b - set foreground colour
;
VFRGND: MOV Word Ptr STATE,Offset VFRGND1
RET ; Get next char
;
; ESC b (colour) - set foreground colour
;
VFRGND1:
MOV AL,CL
MOV AH,Byte Ptr ATTRIB
JMPS VFGBG ; Common routine
;
; ESC c - set background colour
;
VBKGND: MOV Word Ptr STATE,Offset VBKGND1
RET ; Get next char
;
; ESC c (colour) - set background colour
;
VBKGND1:
MOV AH,CL
MOV CL,04h
ROL AH,CL ; Move to MSB's
MOV AL,Byte Ptr ATTRIB
VFGBG: AND AL,0Fh ; LSB's only
AND AH,0F0h ; MSB's only
OR AL,AH ; Mash 'em
MOV Byte Ptr ATTRIB,AL
JMP VPCOMP ; Reset STATE
;
; ESC d - redirect console input
;
VNEWCONI:
MOV AX,Offset SYS_CONI
JMPS VNEW
;
; ESC e - redirect console output
;
VNEWCONO:
MOV AX,Offset SYS_CONO
JMPS VNEW
;
; ESC f - redirect auxilary input
;
VNEWAUXI:
MOV AX,Offset SYS_AUXI
JMPS VNEW
;
; ESC g - redirect auxilary output
;
VNEWAUXO:
MOV AX,Offset SYS_AUXO
JMPS VNEW
;
; ESC h - redirect list output
;
VNEWLST:
MOV AX,Offset SYS_LST
; ;JMPS VNEW ; Fall through
;
; Redirect any i/o device vector
; Entry: AX -> a particular vector
;
VNEW: MOV Word Ptr DELTAVEC,AX ; Vector to change
MOV Word Ptr STATE,Offset VNEW1
RET ; Wait for next char
;
; Next state
;
VNEW1: MOV Byte Ptr DELTALO,CL
MOV Word Ptr STATE,Offset VNEW2 ; Next time
RET ; Wait for one more
;
; Last state
;
VNEW2: MOV BX,Word Ptr DELTAVEC ; Get the vector to change
MOV AH,CL
MOV AL,Byte Ptr DELTALO
AND AX,7F7Fh ; Mask off
MOV Word Ptr [BX],AX ; Set vector
JMP VPCOMP ; Reset STATE
;
; ESC m - turn cursor on
;
VCURON: MOV CX,Word Ptr CURLON ; Normal lines (on)
JMPS VSETCUR1
;
; ESC n - turn cursor off
;
VCUROFF:
MOV CX,Word Ptr CURLOFF ; Cursor lines (off)
;
VSETCUR1:
MOV Word Ptr CURCUR,CX ; Save current cursor type
VSETCUR2:
MOV AH,1 ; Set cursor type
JMP VIDCOM ; Do it
;
VSETCUR3:
MOV CX,Word Ptr CURLOFF
JMPS VSETCUR2
;
; Restore cursor position and type
;
VRSTCPT:
MOV DX,Word Ptr CURSOR
CALL SETCURSOR
MOV CX,Word Ptr CURCUR ; Current (in use) cursor type
JMPS VSETCUR2
;
; ESC p - reverse video on
;
VREVON: AND Byte Ptr ATTRIB,0F8h ; Black foreground
OR Byte Ptr ATTRIB,070h ; White background
RET
;
; ESC q - reverse video off
;
VREVOFF:
AND Byte Ptr ATTRIB,8Fh
OR Byte Ptr ATTRIB,07h
RET
;
; ESC s - turn blinking text on
;
VBLINKON:
OR Byte Ptr ATTRIB,80h
RET
;
; ESC t - turn blinking text off
;
VBLINKOFF:
AND Byte Ptr ATTRIB,7Fh
RET
;
; ESC r - turn high intensity text on
;
VINTON: MOV AL,0Eh
JMPS VINTCHG
;
; ESC u - turn high intensity text off
;
VINTOFF:
MOV AL,07h
VINTCHG:
AND Byte Ptr ATTRIB,0F0h
OR Byte Ptr ATTRIB,AL
RET
;
; ESC v - text wrap at end of line
;
VWRAP: MOV Byte Ptr WRAPFLAG,TRUE
RET
;
; ESC w - no text wrap at end of line
;
VNOWRAP:
MOV Byte Ptr WRAPFLAG,0
RET
;
; ESC x - set MONO80 mode
;
VMON80:
MOV CL,03h
JMP VSETMODE1
;
; ESC y - set COL80 mode
;
VCOL80:
MOV CL,07h
JMP VSETMODE1
;
; ESC / - perform INT 10h function 0Bh
;
VSETPAL:
MOV Word Ptr STATE,Offset VSETPAL1
RET ; Ready for next char
VSETPAL1:
MOV Byte Ptr VSETPALBH,CL ; Save BH value
MOV Word Ptr STATE,Offset VSETPAL2
RET
VSETPAL2:
MOV BL,CL ; Get BL value
MOV BH,Byte Ptr VSETPALBH ; and BH value
AND BX,7F7Fh
MOV AH,0Bh
CALL VIDCOM
JMP VPCOMP ; Reset STATE and return
;
; ESC : - set programmable function keys
;
;
VPFK: MOV Word Ptr STATE,Offset EPFK1
RET ; Ready for key code
;
; Get key scan code
;
EPFK1: CALL VPCOMP ; Reset STATE (default)
PUSH DI
PUSH ES
MOV AL,CL
CALL GETPFK ; AX -> pfk entry
JC EPFK1A ; C set if illegal
;
MOV Word Ptr EPFKPTR,AX ; Save pointer
MOV Byte Ptr EPFKCOUNT,CL ; Save char count
MOV Word Ptr STATE,Offset EPFK2
EPFK1A: POP ES
POP DI
RET
;
; Get the string
;
EPFK2: MOV BX,Word Ptr EPFKPTR ; Point to entry
MOV Byte Ptr [BX],CL ; Store char
;
DEC Byte Ptr EPFKCOUNT
JZ EPFK2A ; Skip if failed
;
TEST CL,CL ; Or if char = 0
JZ EPFK2A
;
INC BX ; Bump the pointer for next time
MOV Word Ptr EPFKPTR,BX
RET ; Keep VIDSTATE
;
; Process complete
;
EPFK2A: JMPS VPCOMP ; Reset STATE to normalcy
;
; ESC 1 - TURN ON/CLEAR STATUS LINE AT BOTTOM OF SCREEN
;
VBOSON:
MOV AL,Byte Ptr CRTMOD ; Current mode
MUL Byte Ptr CRTTEL
XCHG AX,BX ; Calc offset into SCRMODTBL
MOV AL,Byte Ptr SCRMODTBL+4[BX] ; Get STATLINE available flag
MOV Byte Ptr BOSFLAG,AL ; set as current
RET
;
; ESC 0 - TURN OFF/CLEAR STATUS LINE AT BOTTOM OF SCREEN
;
VBOSOFF:
MOV Byte Ptr BOSFLAG,FALSE
JMP CLRBOS2 ; Clear status line
;
; ESC process complete
;
VPCOMP: MOV Word Ptr STATE,Offset VIDNORM
RET ; To normalacy
;----------------------------------------
;
; Common video i/o routine
;
VIDCOM:
MOV Byte Ptr VIDBSY,TRUE ; Flag Video Busy
INT 10h ; PC ROM BIOS Video Driver Service
CLI
MOV Byte Ptr VIDBSY,FALSE ; Clear Busy Flag
TEST Word Ptr X36F3,8000h
JZ VIDCOM1
INC Word Ptr X36F3
INT 1Ch ; PC ROM BIOS System timer
VIDCOM1:
STI
RET
;----------------------------------------
;
; Printer output - set the device
PRNOUT2:
INC DX
PRNOUT1:
INC DX
PRNOUT0:
;----------------------------------------
;
; Printer character out
; Entry: CL = char
; DX = printer number
;
PRNOUT:
MOV CH,2 ; Retry count
PRNO1: MOV AH,0 ; Write char
MOV AL,CL
INT 17h ; PC ROM BIOS - Printer service
TEST AH,08h ; Not busy ?
JZ PRNOX
;
TEST AH,01h ; Timeout ?
JZ PRNO2
DEC CH
JNZ PRNO1 ; Try again
;
PRNO2: PUSH CX
PUSH DX
MOV SI,Offset PERR ; 'Printer error'
MOV DX,Offset PERRPO ; 'Power off'
TEST AH,80h
JNZ PRNO3
MOV DX,Offset PERROP ; 'Out of paper'
TEST AH,20h
JNZ PRNO3
MOV DX,Offset PERRTO ; 'Time out'
TEST AH,01h
JNZ PRNO3
MOV DX,Offset PERRSP ; space
PRNO3: CALL DSKERR3 ; print errors SI and DX ?
POP DX
POP CX
JZ PRNOUT
JNB PRNOX
JMP ABORT ; We're gone
PRNOX: RET
;----------------------------------------
;
; Printer status - set the device number
;
PRNSTAT2:
INC DX
PRNSTAT1:
INC DX
PRNSTAT0:
;
;----------------------------------------
; Return printer status
; Entry: DX = printer number
; Exit: AL = 0ffh if printer ready
; AL = 0 if printer busy
PRNSTAT:
MOV AH,2 ; Get printr status
INT 17h ; PC ROM BIOS - Printer service
MOV AL,AH
AND AL,0B9h ; Interresting bits
CMP AL,90h ; Ready pattern
MOV AL,0FFh ; Ready response code
JZ PRSRET ; Skip if readys
MOV AL,0 ; not ready
PRSRET: RET
;----------------------------------------
;
; Serial port output
;
SPOUT1:
INC DX
SPOUT0:
;----------------------------------------
; Serial port output
; Entry: CL = char
; DX = serial port number
;
SERIALOUT:
PUSH CX
SERIALOUT1:
MOV CL,20h
CALL SOSTAT
TEST AL,AL
JZ SERIALOUT1
POP CX
SERIALOUT2:
MOV AH,01h ; Write char to port
MOV AL,CL ; char to write
INT 14h ; PC ROM BIOS - Serial Port Service
TEST AH,90h
JNZ SERIALOUT2
RET
;----------------------------------------
;
; Serial in for ports #1 and #0
;
SPIN1:
INC DX
SPIN0:
;
;----------------------------------------
; Serial port input
; Entry: DX = serial port number
; Exit: AL = received char
;
SERIALIN:
MOV AH,02h ; Read char from port
INT 14h ; PC ROM BIOS - Serial Port Service
ROL AH,1h ; Timed out ?
JC SERIALIN ; Yes, try again
ROR AH,1h ; Reset status bits
RET
;----------------------------------------
;
; Serial output status
SOSTAT1:
INC DX
SOSTAT0:
;----------------------------------------
; Serial output port status check
; Entry: DX = serial port number
; AH = status check mask
; Exit: AL = 0ffh if ready
; AL = 0 if not
;
SOSTAT:
CMP CL,20h
JNZ SOSTATC
;
MOV CL,Byte Ptr SERBUFSTS
MOV AH,03h ; Get port status
INT 14h ; PC ROM BIOS - Serial Port Service
;
TEST AL,20h ; Data-set ready ?
JZ SOSTATD ; Yes
;
TEST AH,01h ; data ready ?
JZ SOSTATC ; Yes
;
CALL SERIALIN ; Read char from serial port
CMP AL,13h
JNZ SOSTATA
;
MOV CL,0
SOSTATA:
CMP AL,11h
JNZ SOSTATB
;
MOV CL,20h
SOSTATB:
MOV Byte Ptr SERBUFSTS,CL
SOSTATC:
MOV AH,03h ; Get Port Status
INT 14h ; PC ROM BIOS - Serial Port Service
MOV AL,TRUE
TEST CL,AH
JNZ SORET
SOSTATD:
MOV AL,FALSE
SORET: RET
;----------------------------------------
; Light pen input
;
PENIN:
MOV SI,Word Ptr PENPTR ; Buffer pointer
CMP SI,PENBUFEND ; Reached end?
JNZ PENIN1 ; No, get byte
;
CALL PENRDB ; Read/buffer status info
JZ PENIN2 ; Not ready
;
MOV SI,Word Ptr PENPTR
PENIN1: LODSB ; Get next byte
MOV Word Ptr PENPTR,SI ; Save pointer pointer
ADD AL,20h
RET
PENIN2: MOV Word Ptr BOSMSGPTR,Offset PENERR; 'Waiting for light pen'
CALL CLRBOS1 ; Clear status line
CALL PRNBOS ; Display status line
CALL VRSTCPT ; Restore cursor posn and type
MOV SI,Offset SNDTBL2
CALL BEEP1
;
PENIN3: CALL PENRDB ; Read/buffer status info
JNZ PENIN4 ; Ok
;
MOV AH,1 ; Read keyboard status
INT 16h ; PC ROM BIOS Keyboard Service
JZ PENIN3
MOV AH,0 ; Read char from keyboard
INT 16h ; PC ROM BIOS Keyboard Service
CMP AL,CTRLC ; CNTRL-C pressed ?
JNZ PENIN3 ; No, try again
;
MOV Word Ptr SYS_CONI,1 ; Reset to keyboard input
CALL CLRBOS ; Clear status line
JMP ABORT ; We're gone
;
PENIN4: CALL CLRBOS ; Clear status line
JMP PENIN ; Return input
;
; Read/Buffer light pen status info
;
PENRDB: CALL PENST ; Get status info
JZ PENRDBX ; Not ready
;
MOV SI,Offset PENBUF
MOV Word Ptr PENPTR,SI ; Reset buffer pointer
MOV [SI],DH ; buff+0 = char row
INC SI
MOV [DI],DL ; buff+1 = char col (BUG DI ???)
INC SI
MOV [DI],CH ; buff+2 = pixel row (BUG DI ???)
INC SI
SHL BX,1h
SHL BX,1h
SHR BL,1h
SHR BL,1h
MOV [SI],BH ; buff+3 =
INC SI
MOV [SI],BL ; buff+4 =
PENRDBX:
RET
;----------------------------------------
; Light pen status (and position information)
;
; Exit: AL = 0ffh if ready
; AL = 0 if not
;
PENST: MOV AH,4 ; Read light pen position
INT 10h ; PC ROM BIOS Video Driver Service
;
; AH = 0 = pen not down/triggered
; AH = 1 = pen down/triggered
; DH,DL = row,column of character light pen is on
; CH = pixel row (graphics modes 04h-06h)
; CX = pixel row (graphics modes with >200 rows)
; BX = pixel column
;
RCR AH,1 ; Result: AH=0 -> AL=0 + ZF
SBB AL,AL ; AH=1 -> AL=0FFH + NZF
RET
;----------------------------------------
; Select disk for next rd/write
;
SELDSK: ; select disk given by register CL
;
MOV Byte Ptr DISK,CL
SUB AX,AX ; 0 = Select disk
JMPS XDSKDRV ; Common disk routine
;----------------------------------------
;*********************************************
;* *
;* All disk I/O parameters are setup: *
;* DISK is disk number (SELDSK) *
;* TRK is track number (SETTRK) *
;* SECT is sector number (SETSEC) *
;* DMA_ADR is the DMA offset (SETDMA) *
;* DMA_SEG is the DMA segment (SETDMAB)*
;* READ reads the selected sector to the DMA*
;* address, and WRITE writes the data from *
;* the DMA address to the selected sector *
;* (return 00 if successful, 01 if perm err)*
;* *
;*********************************************
;
; Read a 128 byte sector
;
READ:
;
MOV AX,2 ; 2 = Read
JMPS XDSKDRV ; Common disk routine
;----------------------------------------
; Write a 128 byte sector
;
WRITE:
;
MOV AX,4 ; 4 = Write
JMPS XDSKDRV ; Common disk routine
;----------------------------------------
; Move to trk 00 on cur sel drive
;
HOME:
;
MOV Word Ptr TRK,0
MOV AX,6 ; 6 = Home current disk
; JMPS XDSKDRV ; Common disk routine (fall through)
;
; Common disk routine
;
; Disk routine dependant on disk drive
;
XDSKDRV:
CLD
MOV BL,Byte Ptr DISK
MOV BH,0 ; Select routine
SHL BX,1h ; according
JMP Word Ptr DSKDRVRTN[BX] ; to required disk
;
; Select appropriate disk routine
;
; Entry AX = Function
; BX = Disk number * 2
;
DSKRTNSEL:
XCHG AX,BX
JMP Word Ptr DSKFUNRTN[BX]
;
; Select appropriate memory disk routine
;
; Entry AX = Function
; BX = Disk number * 2
;
MEMRTNSEL:
XCHG AX,BX
JMP Word Ptr MEMFUNRTN[BX]
;----------------------------------------
;
; Routine for invalid disk drives
;
; Entry AX = function 0 = SELDSK
; 1 = READ
; 2 = WRITE
; 3 = HOME
; CL = deblock flag
;
DSKRTNINV:
MOV Byte Ptr DBK_FLG,CL ; deblock flag
MOV DX,DS
MOV BX,Offset DRV_NUM ; unknown drive number
PUSH AX
MOV AL,Byte Ptr DISK
SUB AL,Byte Ptr X3A6C
MOV Byte Ptr [BX],AL
POP AX
INT 0E6h ; unknown disk drive
MOV BX,AX
RET
;----------------------------------------
;
; Unknown disk drive interrupt
;
UNDSKINT:
SUB AX,AX ; not supported at present
IRET
;----------------------------------------
;
; Select physical disk
;
; Entry AX = disk number * 2
;
SELECT_PHYDSK:
MOV SI,AX
SHR SI,1 ; Divide by 2
XCHG AX,BX
MOV BX,Word Ptr DPHTBL[BX]
TEST Byte Ptr X3AB2[SI],80h ; Hard disk drive ?
JNZ SELECT_PHYDSKX ; Yes, skip disk reset
;
TEST DL,1 ; 1st select ?
JNZ SELECT_PHYDSKX ; No, skip disk reset
;
CALL RESET_FLOPPY
;
SELECT_PHYDSKX:
RET
;
; Select memory disk
;
SELECT_MEMDSK:
MOV BX,Offset DPH4
RET
;----------------------------------------
;
; Home current disk [physical or memory disk]
;
HOME_PHYDSK:
HOME_MEMDSK:
RET ; Not supported
;----------------------------------------
; Set track for next rd/write
;
SETTRK:
;
MOV Word Ptr TRK,CX
RET
;
; Set sector for next rd/write
;
SETSEC:
;
MOV Word Ptr SECT,CX
RET
;
; Xlate logical->physical sector
;
SECTRAN:
;
MOV BX,CX ; we assume logical = physical sector
RET
;
; Set offset for user buff (DMA)
;
SETDMA:
;
MOV Word Ptr DMA_ADR,CX
RET
;
; Set seg base for buff (DMA)
;
SETDMAB:
;
MOV Word Ptr DMA_SEG,CX
RET
;
; Return offset of Mem Desc Table
;
GETSEGT:
;
MOV BX,Offset MRT
RET
;
; Return I/O map byte (IOBYTE)
;
; Input: none
; Output: AL:=IOBYTE
;
GETIOB:
;
SUB AL,AL ; Not implemented
RET
;
; Set I/O map byte (IOBYTE)
;
; Input: CL:=IOBYTE
; Output: none
;
SETIOB:
;
RET ; Not implemented
;----------------------------------------
;
; Read physical disk track
;
READ_PHYTRK:
CALL X2C13
JB RPT_RET ; Failed
CALL X2BE5
JMPS DBA_2_DMA ; Disk buffer -> DMA
RPT_RET:
RET
;
; Read memory disk track
;
READ_MEMTRK:
CALL X2BF7
;
; Copy from disk buffer address to dma buffer address
;
DBA_2_DMA:
PUSH DS
PUSH ES
LES DI,DWord Ptr DMAADDR ; Destination [ES:DI]
LDS SI,DWord Ptr DSKBUFADDR ; Source [DS:SI]
REP MOVSW
POP ES
POP DS
MOV AL,0 ; OK return
RET
;
; Write physical disk track
;
WRITE_PHYTRK:
MOV Byte Ptr X3A71,CL
CALL X2C13
JB WPT_RET
CALL X2BE5
CALL DMA_2_DBA ; DMA -> disk buffer
MOV Byte Ptr X3A70,0FFh
DEC Byte Ptr X3A71
JNZ WPT_RET
CALL X2CA3 ; Write disk sector(s) ?
MOV Byte Ptr X3A70,0
WPT_RET:
RET
;
;
; Write memory disk track
;
WRITE_MEMTRK:
CALL X2BF7
;
; Copy from dma buffer address to disk buffer address
;
DMA_2_DBA:
PUSH DS
PUSH ES
LES DI,DWord Ptr DSKBUFADDR ; Destination [ES:DI]
LDS SI,DWord Ptr DMAADDR ; Source [DS:SI]
REP MOVSW
POP ES
POP DS
MOV AL,0
RET
;
X2BE5: MOV AX,Word Ptr X3AA8
CALL X2C08
MOV AX,Offset DSKBUF
ADD Word Ptr DSKBUF_ADR,AX
MOV Word Ptr DSKBUF_SEG,DS
RET
;
X2BF7: MOV AX,Word Ptr TRK
MOV CL,8
SHL AX,CL
ADD AX,Word Ptr MDSKSEG
MOV Word Ptr DSKBUF_SEG,AX
MOV AX,Word Ptr SECT
X2C08: MOV CL,7
SHL AX,CL
MOV Word Ptr DSKBUF_ADR,AX
MOV CX,64 ; Length of memory disk track
RET
X2C13: CALL X2C4D
MOV AX,Word Ptr X3AA6
JZ X2C2A
CMP AX,Word Ptr X3A6E
JNZ X2C2A
MOV AL,Byte Ptr DISK
CMP AL,Byte Ptr X3A6D ; Disk error or change ???
JZ X2C4C
X2C2A: TEST Byte Ptr X3A70,0FFh
JZ X2C36
CALL X2CA3 ; Write disk sector(s) ?
JB X2C4C
X2C36: CALL X2CE3 ; Read disk sector(s) ?
JB X2C4C
MOV AX,Word Ptr X3AA6
MOV Word Ptr X3A6E,AX
MOV AL,Byte Ptr DISK
MOV Byte Ptr X3A6D,AL ; Disk error or change ???
MOV Byte Ptr X3A70,0
X2C4C: RET
;
X2C4D: PUSH BX
MOV AX,Word Ptr SECT
MOV Word Ptr X3AA8,AX
MOV AL,Byte Ptr DISK
CBW
XCHG AX,SI
MOV AX,Word Ptr TRK
TEST Byte Ptr X3AB2[SI],80h ; Hard disk drive ?
JNZ X2C69 ; Yes
MOV Word Ptr X3AA6,AX
DEC AX
JMPS X2C9D
X2C69: SHL SI,1h
MOV BX,Word Ptr X3AB6[SI]
SUB AX,15h[BX]
MUL Word Ptr 8[BX]
ADD AX,Word Ptr SECT
ADC DX,0000h
DIV Word Ptr 1Fh[BX]
MOV Word Ptr X3AA8,DX
LEA DI,27h[BX]
MOV CX,23h[BX]
JCXZ X2C9A
PUSH CS
POP ES
REPNE SCASW
JNZ X2C9A
MOV AX,25h[BX]
SUB AX,23h[BX]
ADD AX,CX
INC AX
X2C9A: MOV Word Ptr X3AA6,AX
X2C9D: OR AX,Word Ptr X3AA8
POP BX
RET
;----------------------------------------
;
; Routine to write disk sectors ?
;
X2CA3: PUSH BX
PUSH DX
X2CA5: MOV CX,4 ; Number of retrys
X2CA8: PUSH CX
MOV AX,Word Ptr X3A6E
MOV DL,Byte Ptr X3A6D ; Disk error or change ???
CALL X2D44
MOV Byte Ptr NOS2WRT,AL ; Number of sectors
MOV AH,03h ; Write disk sector(s)
INT 13h ; PC ROM BIOS Floppy Disk Services
JC X2CCA ; Failed ?
;
TEST Byte Ptr VFLAG,TRUE ; Verify enabled ?
JZ X2CCA ; No, skip
;
MOV AL,Byte Ptr NOS2WRT ; Number of sectors
MOV AH,04h ; Verify disk sector(s)
INT 13h ; PC ROM BIOS Floppy Disk Services
;
X2CCA: POP CX ; Retry count
JNC X2CDE ; Disk operation ok - exit ok
;
PUSH AX
MOV AH,0 ; Reset disk system
INT 13h ; PC ROM BIOS Floppy Disk Services
POP AX
LOOP X2CA8 ; Loop - Retry
CALL DISKERROR ; Report it
JZ X2CA5 ; Try again
MOV AL,01h ; Error - Exit
JC X2CE0
X2CDE: MOV AL,0 ; Ok - Exit
X2CE0: POP DX
POP BX
RET
;----------------------------------------
; Routine to read disk sectors ?
;
X2CE3: PUSH BX
PUSH DX
X2CE5: MOV CX,5 ; retry count
X2CE8: PUSH CX
MOV AX,Word Ptr X3AA6
MOV DL,Byte Ptr DISK ; Drive number
CALL X2D44
MOV AH,02h ; Read sector(s) into memory
INT 13h ; PC ROM BIOS Floppy Disk Services
POP CX
JNC X2D13 ; Ok - exit ok
;
PUSH AX
MOV AH,0 ; Reset disk system
INT 13h ; PC ROM BIOS Floppy Disk Services
POP AX
;
CMP AH,80h ; Timeout (not ready) ?
LOOPNE X2CE8 ; No, loop - retry
;
CALL DISKERROR ; Inform other error
JZ X2CE5 ; Operator 'R'etry
;
MOV Byte Ptr X3A6D,0FFh ; Disk error or change ???
MOV AL,01h ; Error - exit
JB X2D15
X2D13: MOV AL,0 ; Ok - exit
X2D15: POP DX
POP BX
RET
;----------------------------------------
RESET_FLOPPY:
PUSH Word Ptr TRK ; Save current track
MOV Word Ptr TRK,0 ; Home
CALL X2C13
JNB RESET_FLOPPY1
JMP ABORT ; We're gone
;
RESET_FLOPPY1:
MOV Word Ptr 0Ah[BX],Offset DPBK1
PUSH BX
MOV BX,Offset DSKBUF
DEC Byte Ptr 01FFh[BX]
POP BX
JNZ RESET_FLOPPY2
MOV Word Ptr 0Ah[BX],Offset DPBK2
;
RESET_FLOPPY2:
POP Word Ptr TRK ; Restore current track
RET
;----------------------------------------
X2D44: MOV DH,0
MOV SI,DX
TEST Byte Ptr X3AB2[SI],80h ; Hard disk drive ?
JNZ X2D62 ; Yes
MOV CH,AL
CMP CH,28h
JB X2D5C
MOV CH,4Fh
SUB CH,AL
MOV DH,01h
X2D5C: MOV CL,01h
MOV AL,08h
JMPS X2D8F
X2D62: SHL SI,1h
MOV BX,Word Ptr X3AB6[SI]
SHR SI,1h
MOV CX,AX
MOV AX,Word Ptr 1Fh[BX]
DIV Byte Ptr 7h[BX]
CBW
MUL CX
MOV CL,05h[BX]
MOV CH,0
DIV CX
INC DX
PUSH DX
ADD AX,15h[BX]
CWD
MOV CL,04h[BX]
DIV CX
POP CX
CALL X2D99
MOV DH,DL
MOV AL,04h
X2D8F: MOV DL,Byte Ptr X3AB2[SI]
PUSH CS
POP ES
MOV BX,Offset DSKBUF
RET
;----------------------------------------
;
X2D99: MOV CH,AL
SHR AX,1
SHR AX,1
AND AL,0C0h
OR CL,AL
RET
;----------------------------------------
;
; Musical beeps
; Entry SI = sound table offset
; (overridden if sound flag set true)
;
BEEP: TEST Byte Ptr SNDFLG,TRUE ; Use default sound ?
JNZ BEEP1
MOV SI,Offset SNDTBL1 ; Yes
;
BEEP1:
LODSW
TEST AX,AX ; End of table
JZ BEEPX ; Yes, exit
;
XCHG AX,BX
MOV AL,0B6h
OUT 43h,AL
LODSB
OUT 42h,AL
LODSB
OUT 42h,AL
IN AL,61h
MOV AH,AL
OR AL,03h
OUT 61h,AL
BEEP2: MOV CX,2000h
BEEP3: LOOP BEEP3
DEC BX
JNZ BEEP2
MOV AL,AH
OUT 61h,AL
MOV CX,1000h
BEEP4: LOOP BEEP4
JMPS BEEP1
BEEPX: RET
;----------------------------------------
; DISK ERROR HANDLING
; ENTRY: AH = ERROR CODE
; EXIT: ZF = 1 FOR RETRY
; ZF = 0, CF = 0 FOR IGNORE
; ZF = 0, CF = 1 FOR ACCEPT
;
DISKERROR:
PUSH DI
PUSH ES
PUSH AX
MOV AL,Byte Ptr DISK
ADD AL,'A' ; Make drive name
MOV Byte Ptr EDRIVE,AL ; In error message
MOV AX,Word Ptr TRK
MOV DI,Offset ETRACK ; Make track number
PUSH DS
POP ES
CALL X2E8D ; In error message
XCHG AX,DI
SUB AX,Offset ERRDISK
MOV Byte Ptr ERRDISKLEN,AL
POP AX
MOV SI,Offset EDSKTBL
MOV CX,EDSK_CNT ; Number of codes
DSKERR1:
LODSB ; Get the code
CMP AL,AH ; Is this it ?
JZ DSKERR2 ; Skip when found
INC SI ; Past message offset
INC SI
LOOP DSKERR1 ; Unknown fall through
DSKERR2:
MOV DX,[SI] ; DX -> sub message
MOV SI,Offset ERRDISKLEN
JMPS DSKERR4
;
; ERROR HANDLING ROUTINE
; PRINTS MESSAGE, SUB MESSAGE, AND QUESTION
; ON THE BOTTOM LINE, AND GETS USER RESPONSE.
; ENTRY: SI -> ERROR MESSAGE
; DX -> SUB MESSAGE
; EXIT: ZF = 1 FOR RETRY
; ZF = 0 FOR IGNORE OR ACCEPT
;
DSKERR3:
PUSH DI ; Save
PUSH ES
DSKERR4:
PUSH Word Ptr CURCUR ; Current (in use) cursor type
PUSH Word Ptr CURSOR
CLD
PUSH DS
POP ES
MOV DI,Offset DSKMSG+1
MOV CX,40
MOV AX,' '
REP STOSW ; Blank out error message buffer
MOV DI,Offset DSKMSG+1
CALL X2E87
MOV SI,DX
CALL X2E82
MOV SI,Offset ERRQUEST ; 'Retry, ignore, accept?'
CALL X2E82
XCHG AX,DI
MOV DI,Offset DSKMSG
SUB AX,DI
DEC AX
MOV [DI],AL
MOV Word Ptr BOSMSGPTR,DI ; Status line text pointer
CALL PRN_STATUS
MOV SI,Offset SNDTBL3
DSKERR5:
CALL BEEP
;
MOV AH,0 ; Read char from keyboard
INT 16h ; PC ROM BIOS Keyboard Service
CMP AL,3 ; Control-C ?
JZ DSKERR_B ; Back to BDOS
AND AL,0DFh ; Convert upper case
CMP AL,'R' ; Retry ?
JZ DSKERR_R
CMP AL,'I' ; Ignore ?
JZ DSKERR_I
CMP AL,'A' ; Accept
MOV SI,Offset SNDTBL1
JNZ DSKERR5 ; Invalid response
STC ; For accept
DSKERR_I:
INC AX ; ZF=0, ignore, accept
DSKERR_R:
POP Word Ptr CURSOR
POP Word Ptr CURCUR ; Current (in use) cursor type
PUSHF ; Save response flags
CALL CLRBOS ; Clear status line
CALL VRSTCPT ; Restore cursor posn and type
POPF
POP ES
POP DI ; Restore pointer
RET
;
; Abort back to BDOS
;
DSKERR_B:
POP Word Ptr CURSOR
JMP ABORT ; We're gone
;----------------------------------------
X2E82: MOV AX,' '
STOSW
STOSB ; Store 3 space chars
X2E87: LODSB
CBW
XCHG AX,CX
REP MOVSB
RET
;----------------------------------------
X2E8D: SUB DX,DX
DIV Word Ptr TEN
PUSH DX
TEST AX,AX
JZ X2E9B
CALL X2E8D
X2E9B: POP AX
OR AL,30h
STOSB
RET
;----------------------------------------
;
; *** Interrupt handling routines ***
;
; User break interrupt routine
; Entered when user hits CONTROL-BREAK at keyboard
;
BREAKINT:
TEST CS:Byte Ptr BRKFLAG,TRUE; Here already?
JZ BRKINT1 ; Skip if not
IRET ; Do not reenter
BRKINT1:
PUSH AX
PUSH DS
MOV AX,CS ; Get current segment
MOV DS,AX
MOV Word Ptr SPBREAK,SP ; Save stack pointer
MOV Word Ptr SSBREAK,SS ; and segment
MOV SP,Offset BRKSTK ; Our own stack
MOV SS,AX ; In this segment
;
PUSH BX ; now push the works
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES
PUSH Word Ptr BOSMSGPTR ; Status line text pointer
PUSH Word Ptr CURCUR ; Current (in use) cursor type
PUSH Word Ptr CURSOR
;
CLI
MOV AL,20h ; EOI command
OUT 20h,AL ; To int control port
MOV Byte Ptr BRKFLAG,TRUE ; Where here now
STI ; Ok to interrupt
;
MOV Word Ptr BOSMSGPTR,Offset BREAKMES ; 'User program break'
CALL PRN_STATUS
MOV SI,Offset SNDTBL4
BRKINT2:
CALL BEEP
;
MOV AH,0 ; Read char from keyboard
INT 16h ; PC ROM BIOS Keyboard Service
;
CMP AL,CTRLC ; CNTRL-C ?
JZ BRKINT3
AND AL,0DFh ; Force upper case
CMP AL,'Y' ; Back to CP/M ?
JZ BRKINT3
CMP AL,'N' ; Or back to user ?
MOV SI,Offset SNDTBL1
JNZ BRKINT2 ; Try again
;
POP Word Ptr CURSOR
POP Word Ptr CURCUR ; Current (in use) cursor type
POP Word Ptr BOSMSGPTR ; Status line text pointer
CALL CLRBOS1 ; Clear status line
CALL VRSTCPT ; Restore cursor posn and type
POP ES ; Restore registers
POP DI
POP SI
POP DX
POP CX
POP BX
CLI ; Hold the int's
MOV Byte Ptr BRKFLAG,0 ; You may reenter
MOV SP,Word Ptr SPBREAK
MOV SS,Word Ptr SSBREAK
POP DS
POP AX
IRET ; Back to caller
BRKINT3:
MOV Word Ptr SYS_CONI,1
MOV Word Ptr SYS_CONO,2
POP Word Ptr CURSOR
MOV Byte Ptr BRKFLAG,0 ; You may come back
JMP ABORT ; We're gone
;----------------------------------------
;
TIMINTA:
TEST CS:Byte Ptr BDOSMODABT,TRUE ; BDOS abort mode set ?
JZ TIMINTB ; No
INT 0E2h
TIMINTB:
IRET
;
; Timer interrupt routine
; Vector set up in signon
; Consumes about 6 sec per hour
;
TIMERINT:
DEC CS:Word Ptr X36F3
JNS TIMINTA
MOV AL,TRUE
XCHG AL,CS:Byte Ptr VIDBSY ; Set video busy
TEST AL,AL ; Already busy ?
JNZ TIMINTA ; Yes
;
; Come here once every second
;
MOV AX,CS ; Get this segment
MOV DS,AX ; for stack save
MOV Word Ptr SPSAVE,SP ; Save current stack
MOV Word Ptr SSSAVE,SS ; and segment
MOV SS,AX
MOV SP,Offset LCLSTK ; Set up local stack
STI
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES ; And promptly use it
MOV ES,AX
CLD ; For later
MOV AX,0012h
; ADD Word Ptr X36F5,34DC
ADD Word Ptr X36F5,34DCh
ADC AX,0000h
ADD Word Ptr X36F3,AX
;
; Increment ram clocks
;
MOV BX,Offset DSECOND
MOV AH,60h ; For overflow
CALL ADDECIMAL
JC TIMINT2 ; Skip if no overflow
CALL ADDECIMAL
JC TIMINT2
MOV AH,24h ; For hours
CALL ADDECIMAL
TIMINT2:
MOV CX,'00' ; Overflow reset value
MOV BX,Offset ASECOND
MOV DX,'60' ; For overflow check
CALL INCASCII
;
CALL INCASCII ; Increment minutes
;
MOV DX,'24' ; 24 hours
CALL INCASCII
;
CALL LEAP ; Next day, check year
MOV CX,'01' ; Overflow reset value
MOV AX,Word Ptr AMONTH
CALL ASCIINUM ; Convert to number
DEC AX
ADD AX,AX
XCHG AX,BX
MOV DX,MONTHLENGTH[BX]
MOV BX,Offset ADAY
CALL INCASCII ; Next day
;
MOV DX,'13' ; Month too high
CALL INCASCII ; Next month
;
MOV CX,'00' ; Overflow reset value
MOV DX,':0' ; Ascii 100
MOV BX,Offset AYEAR
CALL INCASCII
;
MOV BX,Offset BCENT
CALL INCASCII ; Into the next century
;
; Now set up bottom line display
;
TIMINT3:
MOV AX,Word Ptr ASECOND ; Simple ones first
MOV Word Ptr BSECOND,AX
MOV AX,Word Ptr AMINUTE
MOV Word Ptr BMINUTE,AX
MOV AX,Word Ptr AYEAR
MOV Word Ptr BYEAR,AX
;
MOV AX,Word Ptr AMONTH
CMP AX,Word Ptr CMONTH ; If new month
JNZ TIMINT4 ; then fix it
;
MOV AX,Word Ptr ADAY
CMP AX,Word Ptr CDAY ; If day and month same
JZ TIMINT5 ; then skip it
;
TIMINT4:
MOV AX,Word Ptr ADAY
MOV Word Ptr CDAY,AX ; Update check copy
CALL LZBLANK ; Blank leading zero
MOV Word Ptr BDAY,AX ; Ascii day
;
MOV DI,Offset BMONTH
ADC DI,0000
MOV AX,Word Ptr AMONTH
MOV Word Ptr CMONTH,AX
;
RCR AL,1 ; Check msb
SBB AL,AL ; All ones if carry
AND AX,0F0Ah ; Mask AH, AL = 0 or 10
ADD AL,AH ; AL = month number
;
MOV DL,'.' ; Assume abbreviated month
CMP AL,5 ; May ?
JNZ TIMINT4A
MOV DL,' ' ; Yes, remove dot
;
TIMINT4A:
MOV AH,AL
ADD AL,AL
ADD AL,AH ; AL = 3 * month
MOV AH,0
MOV SI,Offset MONTHNAMES -3
ADD SI,AX
MOV AL,' '
STOSB
MOV CX,3
REP MOVSB ; Month abbrev
MOV [DI],DL
INC DI
STOSB
TIMINT5:
MOV AX,Word Ptr AHOUR
CMP AX,Word Ptr CHOUR ; If same skip
JZ TIMINT8
;
MOV Word Ptr CHOUR,AX ; Update check copy
MOV DX,'00'
MOV CX,'12'
XCHG AH,AL ; Switch AH = msb
CMP AX,CX ; Check am/pm
JB TIMINT6 ; Skip if am
;
MOV Word Ptr BAMPM,'mp' ; 'pm'
JZ TIMINT7 ; If 12, skip minus
SUB AX,CX ; American time
AAS
OR AX,DX ; Back to ascii
JMPS TIMINT7 ; Done
;
TIMINT6:
MOV Word Ptr BAMPM,'ma' ; 'am'
CMP AX,DX
JNZ TIMINT7 ; Skip if not zero
MOV AX,CX ; If zero, make 12
;
TIMINT7:
XCHG AL,AH ; Back to backwards
CALL LZBLANK ; Blank leading zero
MOV Word Ptr BHOUR,AX
;
; Get user number
;
TIMINT8:
MOV AL,Byte Ptr BDOSUSER
CMP AL,Byte Ptr CUSER
JZ TIMINT10 ; Skip if same
MOV Byte Ptr CUSER,AL ; Update check copy
SUB AH,AH
AAA
OR AX,'00' ; Back to ascii
XCHG AL,AH ; Back to backwards
CALL LZBLANK ; Blank leading zero
JNB TIMINT9 ; Skip if no blank
XCHG AL,AH ; Else switch back
TIMINT9:
MOV Word Ptr BUSER,AX ; Status line
;
; Copy system block message up
;
TIMINT10:
MOV SI,Offset SYSMESSAGE
MOV DI,Offset BSYSMES
MOV CX,14 ; Message length
REP MOVSB
;
; Finally update the bottom line
;
CMP Word Ptr BOSMSGPTR,Offset TIMEMSG ; Using standard text ?
JNZ TIMINT11 ; No, skip
TEST Byte Ptr BOSFLAG,TRUE ; Is the line tied up ?
JZ TIMINT11 ; Yes, skip
;
MOV CX,Word Ptr CURLOFF ; Cursor off
MOV AH,1 ; Set cursor type
INT 10h ; PC ROM BIOS Video Driver Service
;
CALL PRNBOS ; Display status line
;
MOV DX,Word Ptr CURSOR
MOV BH,0
MOV AH,02h ; Set cursor position
INT 10h ; PC ROM BIOS Video Driver Service
;
MOV CX,Word Ptr CURCUR ; Current (in use) cursor type
MOV AH,01h ; Set cursor type
INT 10h ; PC ROM BIOS Video Driver Service
TIMINT11:
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
CLI ; For stack switch
MOV Byte Ptr VIDBSY,FALSE
MOV SP,Word Ptr SPSAVE
MOV SS,Word Ptr SSSAVE
IRET
;----------------------------------------
;
; Add one to a decimal number
; Overflow and set carry if no overflow
;
ADDECIMAL:
MOV AL,[BX]
INC AL
DAA ; +1 decimal
CMP AL,AH
JC ADDEC1 ; Skip no overflow
SUB AL,AL ; Else reset, clc
ADDEC1:
MOV [BX],AL ; Restore count
DEC BX ; For next time
RET
;----------------------------------------
;
; Add one to an ascii number
; Entry: BX -> ascii value
; CX = overflow reset value
; DX = one too many
; If no overflow, then routine skips its return
; and jumps straight to TIMINT3
;
INCASCII:
MOV AX,[BX]
XCHG AL,AH ; So that AH = msh
INC AL
AAA ; Inc AH on carry
OR AX,'00' ; Back to ascii
CMP AX,DX ; Check overflow
JC INCA1 ; Skip if none
;
XCHG CL,CH
MOV [BX],CX ; Else reset value
XCHG CL,CH ; Restore CX
SUB BX,3 ; for next time
RET
INCA1:
XCHG AL,AH ; Back to backwards
MOV [BX],AX ; Restore count
POP AX ; Clear the return
JMP TIMINT3 ; Straight to update
;----------------------------------------
;
; Adjust month length table for leap year
;
LEAP:
MOV AX,Word Ptr AYEAR ; Fetch ascii year
CALL ASCIINUM ; Convert to number
TEST AL,AL ; Check for 0
JZ LEAP1
;
TEST AL,03h ; Divisable by 4 ?
JNZ LEAP1 ; If not, skip
;
MOV Word Ptr FEBLENGTH,'30' ; Feb leap year +1
RET
LEAP1:
MOV Word Ptr FEBLENGTH,'29' ; Not leap year +1
RET
;----------------------------------------
;
; Convert an ASCII number to binary
;
ASCIINUM:
AND AX,0F0Fh ; Mask the top nibbles
XCHG AL,AH ; AL=lsb
AAD ; Ascii adjust
RET
;----------------------------------------
;
; Blank ASCII leading zero in AL
; Exit: carry and zero set if blanked
;
LZBLANK:
CMP AL,'0'
JNZ LZB1
MOV AL,' '
STC
LZB1: RET
;----------------------------------------
;
; Divide by zero error trap interrupt
; Displays error and returns to BDOS
;
ZEROINT:
STI
POP SI
POP ES
PUSH CS
POP DS
MOV DI,Offset ZEROMESADR ; seg:addr
CALL PUTHEXLONG ; Make ascii
PUSH Word Ptr CURSOR
MOV Word Ptr BOSMSGPTR,Offset ZEROMES ; 'Divide by zero'
CALL PRN_STATUS
MOV SI,Offset SNDTBL5
CALL BEEP
JMPS INTKEY ; Wait for keypress
; Unexpected interrupt error trap interrupt
; Displays error and returns to BDOS
;
UNEXPINT:
STI
POP SI
POP ES
PUSH CS
POP DS
DEC SI
MOV AL,ES:[SI]
INC SI
MOV DI,Offset INTERMESNUM ; Interrupt no
CALL PUTHEXBYTE
MOV DI,Offset INTERMESADR ; Interrupt Seg:Addr
CALL PUTHEXLONG
PUSH Word Ptr CURSOR
MOV Word Ptr BOSMSGPTR,Offset INTERMES ; 'Unexpected Interrupt'
CALL PRN_STATUS
MOV SI,Offset SNDTBL6
CALL BEEP
;
INTKEY: MOV AH,0 ; Read char from keyboard
INT 16h ; PC ROM BIOS Keyboard Service
POP Word Ptr CURSOR
;
ABORT: MOV Byte Ptr WRAPFLAG,TRUE ; Default wrapflag
MOV Byte Ptr ATTRIB,07h ; Default attribute
MOV Byte Ptr VIDBSY,FALSE
CALL CLRBOS ; Clear status line
CALL RESETIO ; Reset disks and I/O ports
MOV CL,0 ; Reset code
MOV DL,0 ; Free mem
INT 0E0h ; Back to bdos
;----------------------------------------
;
; Put ascii segment:address into string
; Entry ES - segment
; SI - address
; DS:DI - string address
;
; Put hex long word (ES:SI) at DS:DI
;
PUTHEXLONG:
MOV AX,ES ; First ES
CALL PUTHEXWORD
INC DI ; Skip
MOV AX,SI ; Next SI
;
; Put hex word AX at DS:DI
;
PUTHEXWORD:
PUSH AX
MOV AL,AH
CALL PUTHEXBYTE
POP AX
;
; Put hex byte AL at DS:DI
;
PUTHEXBYTE:
PUSH AX
MOV CL,4
SHR AL,CL ; Shift upper to lower nybble
CALL PUTHEXDIGIT
POP AX
;
; Put hex digit AL (lower nybble) at DS:DI
;
PUTHEXDIGIT:
AND AL,0Fh ; Mask off upper nybble
MOV BX,Offset HEXCHARTBL
XLAT AL ; Lookup ascii character
MOV Byte Ptr [DI],AL ; Put in string
INC DI ; Bump string pointer
RET
;----------------------------------------
;
; Display status text
; If not on the bottom of the screen, on the current line
;
PRN_STATUS:
TEST Byte Ptr BOSFLAG,TRUE ; Status line available for use?
JNZ PRN_STATUS3 ; Yes, print at bottom of screen
;
CALL PRN_STATUS1 ; CR + LF
MOV SI,Word Ptr BOSMSGPTR ; Status line text pointer
LODSB ; Get message length
CBW
XCHG AX,CX ; into CX
CALL PRN_STATUS2 ; Display CX characters
;
PRN_STATUS1:
MOV SI,Offset CRLF ; CR + LF
MOV CX,2 ; 2 characters
;
PRN_STATUS2:
LODSB ; Next char
PUSH SI
PUSH CX
MOV CL,AL
CALL VIDNORM1 ; Display char
POP CX
POP SI
LOOP PRN_STATUS2 ; Loop
RET
;
PRN_STATUS3:
CALL CLRBOS1 ; Clear status line
CALL PRNBOS ; Display status line
MOV SI,Word Ptr BOSMSGPTR ; Status line text pointer
MOV DL,[SI]
MOV DH,18h
CALL SETCURSOR
JMP VCURON
;----------------------------------------
;
; Print a message on the status line
;
PRNBOS: PUSH DS
POP ES
MOV DI,Offset BOSLINE
MOV SI,Word Ptr BOSMSGPTR ; Status line text pointer
LODSB ; Get message length
CBW
XCHG AX,CX ; into CX
MOV DX,1800h ; Cursor position [Row:24,Col:00]
MOV BX,000Bh ; Display page 0, char attrib 0b
;
PRNBOS1:
LODSB ; Get character
CMP AL,[DI]
STOSB ; Store in copy status line
JZ PRNBOS2 ; skip display if same
;
PUSH AX
MOV AH,2 ; Set cursor position
INT 10h ; PC ROM BIOS Video Driver Service
POP AX
;
PUSH CX
MOV CX,1 ; only 1 char
MOV AH,9 ; Write attribute and char at cursor
INT 10h ; PC ROM BIOS Video Driver Service
POP CX
;
PRNBOS2:
INC DL ; Bump column position
LOOP PRNBOS1 ; Next character
RET
;----------------------------------------
;
; Clear the message line
;
CLRBOS: MOV Word Ptr BOSMSGPTR,Offset TIMEMSG ; Status line
CLRBOS1:
TEST Byte Ptr BOSFLAG,TRUE ; Line tied up ?
JZ CLRBOSX ; Yes, skip
CLRBOS2:
MOV CX,1800h ; start of line 24
MOV DX,184Fh ; end of line 24
MOV BH,0Bh ; attribute
AND BH,Byte Ptr X36B8
MOV AX,0700h ; Initialize windows
INT 10h ; PC ROM BIOS Video Driver Service
PUSH DS
POP ES
MOV DI,Offset BOSLINE
MOV CX,80
MOV AL,' '
CLD
REP STOSB
CLRBOSX:
RET
;----------------------------------------
;
; Set current video details
;
; Entry = AL = video mode (8 modes as per table SCRMODTBL)
;
; 0 = 40 Column text without status line
; 1 = 40 Column text without status line
; 2 = 80 Column text with status line
; 3 = 80 Column text with status line
; 4 = 40 Column graphics without status line
; 5 = 40 Column graphics without status line
; 6 = 80 Column graphics without status line
; 7 = 80 Column text with status line
;
SETCURCRT:
AND AL,07h
MOV Byte Ptr CRTMOD,AL ; Current mode
MUL Byte Ptr CRTTEL
ADD AX,Offset SCRMODTBL
XCHG AX,SI ; Calc offset into SCRMODTBL
MOV DI,Offset CRTCOL ; Offset of current video details
;
LODSW ; [table ] width and mode
MOV Byte Ptr BDOSCONWID,AL ; Set CPM screen width
STOSW ; [current] width and mode
LODSW ; [table ] "cursor on" shape
STOSW ; [current] "current cursor" shape
STOSW ; [current] "normal cursor" shape
OR AH,20h
STOSW ; [current] "cursor off" shape
LODSW ; [table ] Status line available flag
STOSW ; [current] Status line available flag
RET
;----------------------------------------
;
; Reset disks and I/O ports
;
RESETIO:
MOV DL,0 ; Drive 0 (A:)
MOV AH,0 ; Reset disk system
INT 13h ; PC ROM BIOS Floppy Disk Services
MOV DL,80h ; Hard disks and floppy disks
MOV AH,0 ; Reset disk system
INT 13h ; PC ROM BIOS Floppy Disk Services
MOV DX,2 ; Printer number 2
RSTIO1: MOV AH,1 ; Initialise printer port
INT 17h ; PC ROM BIOS - Printer service
DEC DX
JNS RSTIO1 ; Previous one
;
INC DX
MOV AH,0 ; Init port
MOV AL,Byte Ptr SER1 ; Initialisation parameter (port 1)
INT 14h ; PC ROM BIOS - Serial Port Service
INC DX
MOV AH,0 ; Init port
MOV AL,Byte Ptr SER2 ; Initialisation parameter (port 2)
INT 14h ; PC ROM BIOS - Serial Port Service
;
PUSH DS
MOV CX,2 ; Only reset 2 serial i/o
LDS SI,DWord Ptr SERIOBASE ; -> 1st serial i/o base i/o addr
RSTIO2: LODSW ; Get base i/o address
TEST AX,AX
JZ RSTIOX ; No more serial i/o, exit
;
ADD AX,4 ; point to modem control register
XCHG AX,DX
MOV AL,3
OUT DX,AL ; send it
LOOP RSTIO2 ; Next one
RSTIOX: POP DS
RET
;*********************************************
;* *
;* Data Areas *
;* *
;*********************************************
data_offset EQU offset $
DSEG
ORG data_offset ; contiguous with code
X32CF RS 75 ; ?
SYS_CONI DW 1 ; Console input
SYS_CONO DW 2 ; Console output
SYS_AUXI DW 1 ; Aux input
SYS_AUXO DW 2 ; Aux output
SYS_LST DW 2 ; List input/output
DELTAVEC RW 1 ; For changing vectors
DELTALO RB 1 ;
X3316 DB 0DBh ; ?
;
; Character i/o branch tables
;
INROUTINES DW Offset KEYIN ; Keyboard
DW Offset KEYIN ; Cover screen
DW Offset SPIN0 ; Serial port #0
DW Offset SPIN1 ; Serial port #0
DW Offset KEYIN ; Printer #0
DW Offset KEYIN ; Printer #1
DW Offset KEYIN ; Printer #2
DW Offset KEYIN ; Cassette
DW Offset PENIN ; Light pen
DW Offset KEYIN ; Game
DW Offset KEYIN ; Dummy
;
OUTROUTINES DW Offset VIDOUT ; Normal console output
DW Offset VIDOUT ; Screen (video)
DW Offset SPOUT0 ; Serial port #0 output
DW Offset SPOUT1 ; Serial port #1 output
DW Offset PRNOUT0 ; Printer #0 output
DW Offset PRNOUT1 ; Printer #1 output
DW Offset PRNOUT2 ; Printer #2 output
DW Offset VIDOUT ; Cassette
DW Offset VIDOUT ; Light pen
DW Offset VIDOUT ; Game
DW Offset VIDOUT ; Dummy
OUTSTATUS DW Offset KEYSTAT ; Keyboard
DW Offset NULLST ; Always ready
DW Offset SOSTAT0 ; Serial port #0
DW Offset SOSTAT1 ; Serial port #1
DW Offset PRNSTAT0 ; Printer #0
DW Offset PRNSTAT1 ; Printer #1
DW Offset PRNSTAT2 ; Printer #2
DW Offset NULLST ; Cassette
DW Offset PENST ; Light pen
DW Offset NULLST ; Game
DW Offset NULLST ; Dummy
;----------------------------------------
KEYPTR DW Offset KEYBUF
KEYBUF RS 20 ; 20 bytes long
DB 0 ; Ends with 0
X3377 DB 0DBh ; ?
PFKSCAN DB 'SRQPOMKIHGDCBA@?>=<;'
PFKTABLE DB 'DIR A:',CR,0,'............' ; F1
DB 'DIR B:',CR,0,'............' ; F2
DB 'STAT',CR,0,'..............' ; F3
DB 'STAT ',0,'..............' ; F4
DB 'STAT A:*.*',CR,0,'........' ; F5
DB 'STAT B:*.*',CR,0,'........' ; F6
DB 'ASSIGN',CR,0,'............' ; F7
DB 'CONFIG',CR,0,'............' ; F8
DB 'DSKMAINT',CR,0,'..........' ; F9
DB 'FUNCTION',CR,0,'..........' ; F10
DB ESC,'H',0,'.................' ; HOME
DB ESC,'A',0,'.................' ; UP ARROW
DB ESC,'I',0,'.................' ; PAGE UP
DB ESC,'D',0,'.................' ; CURSOR LEFT
DB ESC,'C',0,'.................' ; CURSOR RIGHT
DB 1Ah,0,'..................' ; END
DB ESC,'B',0,'.................' ; CURSOR DOWN
DB 0Ah,0,'..................' ; PAGE DOWN
DB ESC,'L',0,'.................' ; INSERT
DB 7Fh,0,'..................' ; DELETE
STATE DW Offset VIDNORM ; Current state
CURCOL DB 0 ; Cursor column
CURROW DB 0 ; Cursor row
CURSOR EQU Word Ptr CURCOL
SAVECURSOR DW 0 ; For esc codes
ATTRIB DB 07h ; Default attribute
WRAPFLAG DB TRUE ; End of line wrap
EPFKPTR DW 0
EPFKCOUNT DB 0
VSETPALBH DB 0 ; Set colour palet - BH value
;
; Escape lookup table for IBM CP/M codes subset
;
ESCTBL DB 'HABCDIjkYEJloKLMNabcdefghmnpqstruvwxy/:10'
;
; Escape jump table for IBM CP/M codes subset
;
DW Offset VHOME ; ESC H - home cursor
DW Offset VUP ; ESC A - cursor up
DW Offset VDOWN ; ESC B - cursor down
DW Offset VFORW ; ESC C - cursor forward (right)
DW Offset VBACK ; ESC D - cursor back (left)
DW Offset VUPSAT ; ESC I - cursor up (scroll at top)
DW Offset VSAVCUR ; ESC j - save cursor position
DW Offset VRSTCUR ; ESC k - restore cursor position
DW Offset VSETCUR ; ESC Y - set cursor position
DW Offset VEOSALL ; ESC E - erase screen and home cursor
DW Offset VEOSEND ; ESC J - erase to end of screen
DW Offset VECLIN ; ESC l - erase current line
DW Offset VEOLBEG ; ESC o - erase beginning of line to cursor
DW Offset VEOLEND ; ESC K - erase to end of line
DW Offset VIASLIN ; ESC L - insert line and scroll down
DW Offset VDASLIN ; ESC M - delete line and scroll up
DW Offset VDELCHR ; ESC N - delete character at cursor
DW Offset VSETMODE ; ESC a - set video mode
DW Offset VFRGND ; ESC b - set foreground colour
DW Offset VBKGND ; ESC c - set background colour
DW Offset VNEWCONI ; ESC d - redirect console input
DW Offset VNEWCONO ; ESC e - redirect console output
DW Offset VNEWAUXI ; ESC f - redirect auxilary input
DW Offset VNEWAUXO ; ESC g - redirect auxilary output
DW Offset VNEWLST ; ESC h - redirect list output
DW Offset VCURON ; ESC m - turn cursor on
DW Offset VCUROFF ; ESC n - turn cursor off
DW Offset VREVON ; ESC p - reverse video on
DW Offset VREVOFF ; ESC q - reverse video off
DW Offset VBLINKON ; ESC s - turn blink text on
DW Offset VBLINKOFF ; ESC t - turn blink text off
DW Offset VINTON ; ESC r - turn high intensity text on
DW Offset VINTOFF ; ESC u - turn high intensity text off
DW Offset VWRAP ; ESC v - wrap around at line end
DW Offset VNOWRAP ; ESC w - no wrap at line end
DW Offset VMON80 ; ESC x - set MONO 80 mode
DW Offset VCOL80 ; ESC y - set COL 80 mode
DW Offset VSETPAL ; ESC / - set colour palet
DW Offset VPFK ; ESC : - set programmable function keys
DW Offset VBOSON ; ESC 1 - turn status line on
ESCJMP DW Offset VBOSOFF ; ESC 0 - turn off/clear status line
;
X35A3 DB 0DBh ; ?
;
; Memory region table
;
MRT DB 1 ; One region
MRTSTART RW 1
MRTLEN RW 1
;
RS 28 ;
BRKFLAG DB 0 ;
X35C6 DB 0DBh ; ?
SPBREAK DW 0 ; stack pointer
SSBREAK DW 0 ; stack segment
BREAKMES DB 39h ; length of following text
DB ' *** User Program Break *** '
DB 'Return to CP/M (Y/N)?'
ZEROMES DB 49h ; length of following text
DB ' *** Divide by Zero Error from '
ZEROMESADR DB '0000:0000'
DB ' *** Type any key to continue.'
INTERMES DB 4Dh ; length of following text
DB ' *** Unexpected Interrupt #'
INTERMESNUM DB '00'
DB ' from '
INTERMESADR DB '0000:0000'
DB ' *** Type any key to continue.'
;
HEXCHARTBL DB '0123456789ABCDEF'
;
; Screen data
;
CRTMOD DB 0 ; Screen mode
CRTTEL DB 6h ; Length of entries in SCRMODTBL
CRTCOL DB 0 ; Max column (width)
CRTBVM DB 0 ; BIOS video mode
CURCUR DW 0 ; Current cursor type
CURLON DW 0 ; Cursor lines normal mode
CURLOFF DW 0 ; Cursor lines off code
BOSFLAG DB 0 ; Bottom of screen line flag
X36B8 DB 0 ; ?
;
; Screen mode table detail
; +0 (byte) = Screen width
; +1 (byte) = Video mode for BIOS equipment word
; +2 (word) = "Cursor on" shape
; +4 (byte) = Status line available (0FFh=Yes, 00h=No)
; +5 (byte) = Mode (0FFh=Text, 00h=Graphics)
;
SCRMODTBL DB 28h,10h,07h,06h,00h,0FFh ; 40 Column text
DB 28h,10h,07h,06h,00h,0FFh ; 40 Column text
DB 50h,20h,07h,06h,0FFh,0FFh ; 80 Column text
DB 50h,20h,07h,06h,0FFh,0FFH ; 80 Column text
DB 28h,20h,07h,06h,00h,00h ; 40 Column graphics
DB 28h,20h,07h,06h,00h,00h ; 40 Column graphics
DB 50h,20h,07h,06h,00h,00h ; 80 Column graphics
DB 50h,30h,0Ch,0Bh,0FFh,0FFh ; 80 Column text
;
CRLF DB CR,LF
;
BOSMSGPTR DW Offset TIMEMSG ; pointer to status line text
; (defaults to time message)
;
SPSAVE RW 1 ; Save stack pointer
SSSAVE RW 1 ; Save stack segment
;
X36F1 DB 0DBh ; ?
;
VIDBSY DB 0 ; Video busy flag
X36F3 DB 12h,00h
X36F5 DW 0
CMONTH DW '99' ; Initially impossible
CDAY DW '99'
CHOUR DW '00'
CUSER DB 99
;
X36FE DB 0DBh ; ?
;
TIMEMSG DB 42h
DB ' User '
BUSER RW 1
DB ' '
BHOUR DB ' 0'
DB ':'
BMINUTE RW 1
DB ':'
BSECOND RW 1
DB ' '
BAMPM DW ' '
DB ' '
BMONTH DB ' Dec. '
BDAY RW 1
DB ', '
BCENT DB '19'
BYEAR RW 1
DB ' '
;
BSYSMES RB 14
;
DB 0DBh ; ?
;
BOSLINE RS 80
;
MONTHNAMES DB 'JanFebMarAprMayJun'
DB 'JulAugSepOctNovDec'
;
MONTHLENGTH DW '32'
FEBLENGTH DW '29','32','31','32','31'
DW '32','32','31','32','31','32'
;
;
; Error messages
;
ERRDISKLEN RB 1
ERRDISK DB 'Disk Error Drive '
EDRIVE RB 1
DB ': Track '
ETRACK RB 4
DB 0
TEN DW 10
DEFF DB 0Fh,'Sense Op Failed'
DEBB DB 0Fh,'Undefined Error'
DE80 DB 11h,'Failed to Respond'
DE40 DB 0Bh,'Seek Failed'
DE20 DB 11h,'Controller Failed'
DE11 DB 0Eh,'Data Corrected'
DE10 DB 0Ah,'Data Error'
DE0B DB 10h,'Track Flag Error'
DE09 DB 11h,'DMA Address Error'
DE08 DB 10h,'DMA Chip Failure'
DE07 DB 10h,'Drive Parameters'
DE05 DB 0Ch,'Reset Failed'
DE04 DB 10h,'Sector Not Found'
DE03 DB 0Fh,'Write-Protected'
DE02 DB 11h,'Addr Mark Missing'
DE01 DB 0Fh,'Illegal Command'
DE00 DB 0Dh,'Unknown Error'
;
; Table matching the return code with message
;
EDSKTBL DB 0FFh
DW Offset DEFF ; 'Sense Op Failed'
DB 0BBh
DW Offset DEBB ; 'Undefined Error'
DB 080h
DW Offset DE80 ; 'Failed to Respond'
DB 040h
DW Offset DE40 ; 'Seek Failed'
DB 020h
DW Offset DE20 ; 'Controller Failed'
DB 011h
DW Offset DE11 ; 'Data Corrected'
DB 010h
DW Offset DE10 ; 'Data Error'
DB 0Bh
DW Offset DE0B ; 'Track Flag Error'
DB 09h
DW Offset DE09 ; 'DMA Address Error'
DB 08h
DW Offset DE08 ; 'DMA Chip Failure'
DB 07h
DW Offset DE07 ; 'Drive Parameters'
DB 05h
DW Offset DE05 ; 'Reset Failed'
DB 04h
DW Offset DE04 ; 'Sector Not Found'
DB 03h
DW Offset DE03 ; 'Write-Protected'
DB 02h
DW Offset DE02 ; 'Addr Mark Missing'
DB 01h
DW Offset DE01 ; 'Illegal Command'
EDSK_CNT EQU (Offset $ - Offset EDSKTBL)/3
DW Offset DE00 ; 'Unknown Error'
PERR DB 11h,' Printer Error'
PERRTO DB 08h,'Time Out'
PERROP DB 0Ch,'Out of Paper'
PERRPO DB 09h,'Power Off'
PERRSP DB 01h,' '
ERRQUEST DB 16h,'Retry, Ignore, Accept?'
DSKMSG DB 80 ; Message length
RS 80 ; Disk error message
SNDFLG DB 0FFh
SNDTBL1 DB 04h,00h,74h,04h,00h,00h
SNDTBL2 DB 02h,00h,74h,04h,00h,00h
SNDTBL3 DB 04h,00h,12h,07h,05h,00h,0E8h,08h
DB 04h,00h,4ch,05h,05h,00h,0F2h,05h,00h,00h
SNDTBL4 DB 04h,00h,12h,07h,05h,00h,0E8h,08h,00h,00h
SNDTBL5 DB 0Ch,00h,0E8h,08h,04h,00h,0ACh,06h
DB 04h,00h,0E8h,08h,04h,00h,0ACh,06h,0Ah
DB 00h,4Ch,05h,0Ch,00h,0ACh,06h,00h,00h
SNDTBL6 DB 06h,00h,0E8h,08h,06h,00h,12h,07h
DB 06h,00h,0E8h,08h,06h,00h,0F2h,05h,06h
DB 00h,0E8h,08h,06h,00h,74h,04h,00h,00h
;----------------------------------------
; Serial Port init parm
;
;BITS 7,6,5 4,3 2 1,0
; Baud rate parity stop bits word length (bits)
; 000 = 110 x0 = none 0 = 1 10 = 7
; 001 = 150 01 = odd 1 = 2 11 = 8
; 010 = 300 11 = even
; 100 = 1200
; 101 = 2400
; 110 = 4800
; 111 = 9600
;
SER1 DB 43h ; Serial port 1 init parms
; ; 300 baud
; ; parity none
; ; 1 stop bit
; ; 8 bits
SER2 DB 43h ; Serial port 2 init parms
; ; 300 baud
; ; parity none
; ; 1 stop bit
; ; 8 bits
;
SERBUFSTS DB 20h ; tx hold reg empty code ?
SERIOBASE DW 0000h,0040h ; Segment [40] and offset [0]
; ; of 1st serial i/o port
; ; base i/o address
; ; (filled in by POST)
;
;----------------------------------------
;
PENBUF RS 6
PENBUFEND EQU (Offset $)
PENPTR DW Offset PENBUFEND
PENERR DB 1Fh,' Waiting for Light Pen Input'
;
X3A5A DB 0DBh ; ?
;
;--------------------------------------
;
; Disk parameters
;
DISK DB 0 ; Current/required disk
;
; INT 0E6 (unknown disk drive) parameter table
;
DRV_NUM DB 0 ; drive number (0=1st, 1=2nd...)
DBK_FLG DB 0 ; deblock flag
; 0=normal write
; 1=directory write
; ?=write with no preread)
TRK DW 0 ; Required track
SECT DW 0 ; Required sector
DMA_ADR DW 0 ; Required DMA address
DMA_SEG DW 0 ; Required DMA segment
DMAADDR EQU DWord Ptr DMA_ADR
VFLAG DB FALSE ; Verify (non-zero if verify writes)
;
;
;
X3A67 DB 0DBh ; ?
;
DSKBUF_ADR DW 0 ; Disk buffer address
DSKBUF_SEG DW 0 ; Disk buffer segment
DSKBUFADDR EQU DWord Ptr DSKBUF_ADR
;
X3A6C DB 04h ; ?
X3A6D DB 0FFh ; Disk error or change ???
X3A6E DW 0000h ; ?
X3A70 DB 00h ; ?
X3A71 DB 00h ; ?
MDSKSEG DW 0D000h ; Mdisk segment
MDSKSIZ DW 0000h ; Mdisk size (Kb)
;
; Disk routines - selected by disk
;
DSKDRVRTN DW Offset DSKRTNSEL ; Disk 0 - A
DW Offset DSKRTNSEL ; 1 - B
DW Offset DSKRTNSEL ; 2 - C
DW Offset DSKRTNSEL ; 3 - D
DW Offset DSKRTNINV ; 4 - E
DW Offset DSKRTNINV ; 5 - F
DW Offset DSKRTNINV ; 6 - G
DW Offset DSKRTNINV ; 7 - H
DW Offset DSKRTNINV ; 8 - I
DW Offset DSKRTNINV ; 9 - J
DW Offset DSKRTNINV ; 10 - K
DW Offset DSKRTNINV ; 11 - L
DSKDRVRTNM DW Offset DSKRTNINV ; 12 - M
DW Offset DSKRTNINV ; 13 - N
DW Offset DSKRTNINV ; 14 - O
DW Offset DSKRTNINV ; 15 - P
;
; Disk Function Routines
;
DSKFUNRTN DW Offset SELECT_PHYDSK ; Select disk
DW Offset READ_PHYTRK ; Read track
DW Offset WRITE_PHYTRK ; Write track
DW Offset HOME_PHYDSK ; Home current disk
;
; Memory Disk Function Routines
;
MEMFUNRTN DW Offset SELECT_MEMDSK ; Select disk
DW Offset READ_MEMTRK ; Read track
DW Offset WRITE_MEMTRK ; Write track
DW Offset HOME_MEMDSK ; Home current disk
X3AA6 DW 0000h
X3AA8 DW 0000h
DPHTBL DW Offset DPH0
DW Offset DPH1
DW Offset DPH2
DW Offset DPH3
X3AB2 DB 0,0,0,0 ; Valid drives table [only 4 supported]
X3AB6 DW 0,0,0,0
NOS2WRT DB 0 ; No. sectors to write (ROM BIOS CALL)
X3ABF DB 0DBh ; ?
;
FIDDSMEM DW 0 ; FIDDS (kb) memory
FIDDSSEG DW 0 ; FIDDS (kb) memory segment ?
X3AC4 DW Offset DIRBUF
;
; IBM PC Diskette parameters - used by floppy disk controller
;
DSKPRM DB 0CFh ; bits 7-4 :step rate - Ch=8ms
; bits 3-0 :head unload time - Fh = 240ms
DB 02h ; bits 7-1 :head load time - 2h = 8ms
; bit 0 :non-DMA mode (always 0)
DB 25h ; delay until motor turned off (in clock ticks)
DB 02h ; bytes per sector
; (00h=128, 01h=256, 02h=512, 03h=1024)
DB 08h ; sectors per track
DB 2Ah ; length of gap between sectors
; (2Ah for 5.25", 1Bh for 3.5")
DB 0FFh ; data length
; (ignored if bytes-per-sector field non zero)
DB 50h ; gap length when formatting
; (50h for 5.25", 6Ch for 3.5")
DB 0E5h ; format filler byte
DB 00h ; head settle time in milliseconds
DB 04h ; motor start time in 1/8 second
;
X3AD1 DB 0DBh ; ?
DPBASE EQU $
DPH0 DW 0 ; No translation table
DW 0,0,0 ; reserved
DW Offset DIRBUF ; Directory scratch pad
DPB0 DW 0
DW 0 ; Check vector 0
DW 0 ; Allocation vector 0
;
DPH1 DW 0 ; No translation table
DW 0,0,0 ; reserved
DW Offset DIRBUF ; Directory scratch pad
DPB1 DW 0
DW 0 ; Check vector 0
DW 0 ; Allocation vector 0
;
DPH2 DW 0 ; No translation table
DW 0,0,0 ; reserved
DW Offset DIRBUF ; Directory scratch pad
DPB2 DW 0
DW 0 ; Check vector 0
DW 0 ; Allocation vector 0
;
DPH3 DW 0 ; No translation table
DW 0,0,0 ; reserved
DW Offset DIRBUF ; Directory scratch pad
DPB3 DW 0
DW 0 ; Check vector 0
DW 0 ; Allocation vector 0
;
DPH4 DW 0 ; No translation table
DW 0,0,0 ; reserved
DW Offset DIRBUF ; Directory scratch pad
DPB4 DW 0
DW 0 ; Check vector 0
DW CSV14 ; Allocation vector 4
;
; DPBK1 and DPBK2 Physical disks
;
DPBK1 DW 0020h ; 0032 ; CP/M Sectors per track (SPT)
DB 03h ; 03 ; Block shift factor (BSH)
DB 07h ; 07 ; Block mask (BLM)
DB 00h ; 00 ; Null mask (EXM)
DW 009Bh ; 0155 ; Disk size - 1 (DSM)
DW 003Fh ; 0063 ; Directory max (DRM)
DB 0C0h ; 11000000b ; Alloc 0 (AL0)
DB 00h ; 00000000b ; Alloc 1 (AL1)
DW 0010h ; 0016 ; Check size (CKS)
DW 0001h ; 0001 ; Track offset (OFF)
;
DB 0DBh ; ?
;
DPBK2 DW 0020h ; 0032 ; CP/M Sectors per track (SPT)
DB 04h ; 04 ; Block shift factor (BSH)
DB 0Fh ; 15 ; Block mask (BLM)
DB 01h ; 01 ; Null mask (EXM)
DW 009Dh ; 0157 ; Disk size - 1 (DSM)
DW 003Fh ; 0063 ; Directory max (DRM)
DB 080h ; 10000000b ; Alloc 0 (AL0)
DB 00h ; 00000000b ; Alloc 1 (AL1)
DW 0010h ; 0016 ; Check size (CKS)
DW 0001h ; 0001 ; Track offset (OFF)
;
DB 0DBh ; ?
;
; DPBK3 and DPBK4 Memory disks
DPBK3 DW 0020h ; 0032 ; CP/M Sectors per track (SPT)
DB 03h ; 03 ; Block shift factor (BSH)
DB 07h ; 07 ; Block mask (BLM)
DB 00h ; 00 ; Null mask (EXM)
DW 0000 ; 0000 ; Disk size - 1 (DSM)
DW 003Fh ; 0063 ; Directory max (DRM)
DB 0C0h ; 11000000b ; Alloc 0 (AL0)
DB 00h ; 00000000b ; Alloc 1 (AL1)
DW 0000h ; 0000 ; Check size (CKS)
DW 0000h ; 0000 ; Track offset (OFF)
;
DB 0DBh ; ?
;
DPBK4 DW 0020h ; 0032 ; CP/M Sectors per track (SPT)
DB 04h ; 04 ; Block shift factor (BSH)
DB 0Fh ; 15 ; Block mask (BLM)
DB 01h ; 01 ; Null mask (EXM)
DW 0000h ; 0000 ; Disk size - 1 (DSM)
DW 003Fh ; 0063 ; Directory max (DRM)
DB 080h ; 10000000b ; Alloc 0 (AL0)
DB 00h ; 00000000b ; Alloc 1 (AL1)
DW 0000h ; 0000 ; Check size (CKS)
DW 0000h ; 0000 ; Track offset (OFF)
;
DB 0DBh ; ?
;
RS 64 ; Break interrupt stack
BRKSTK EQU Offset $
;
RS 64 ; Local stack
LCLSTK EQU offset $ ; (for init and timer routines)
;
DSKBUF EQU offset $ ; Disk buffer
;
CSEG
ORG DSKBUF ; code contiguous with data
;
;----------------------------------------
;
; Enter from BOOT ROM or LOADER
;
; Once only INIT code/data occupies the disk buffer.
;
INIT:
MOV AX,CS
MOV SS,AX
MOV SP,Offset LCLSTK
CALL SETISR ; Setup interrupt vectors
MOV AX,CS
MOV DS,AX
MOV ES,AX
MOV Byte Ptr IPLDSK,DL ; Initial program load disk
;
MOV SI,Offset SIGNON ; 'CPM-86 for the PC..'
CALL DISP_STR ; Display string
;
INT 11h ; PC ROM BIOS - Get Equipment List
ADD AX,0040h
AND AX,0FFF3h
PUSH AX
CALL SETINTVID ; Set initial video mode
MOV AH,08h ; Get drive parameters
MOV DL,80h
INT 13h ; PC ROM BIOS Floppy Disk Services
MOV AL,DL ; Number of drives
POP DX
JC INIT1 ; Error ?
;
SHL AL,1h
SHL AL,1h
OR DL,AL
INIT1: MOV SI,Offset SIGNDSK ; 'Diskette Drive(s)'
MOV CX,0706h ; mask + shift factor
CALL DISP_HDWNUM ; Display string and number supported
MOV Byte Ptr X3A6C,AL
MOV Byte Ptr FDDCNT,AL
;
MOV SI,Offset SIGNHDD ; 'Hard Disk Drive(s)'
MOV CX,0302h ; mask + shift factor
CALL DISP_HDWNUM ; Display string and number supported
MOV Byte Ptr HDDCNT,AL ; Save number hard drives
;
PUSH DX
CALL X3EB2
CALL X3D52
POP DX
MOV SI,Offset SIGNPRT ; 'Parallel Printer(s)'
MOV CX,030Eh ; mask + shift factor
CALL DISP_HDWNUM ; Display string and number supported
;
MOV SI,Offset SYS_LST
MOV CX,0010h
CALL X3FEF
MOV SI,Offset SIGNSER ; 'Serial Port(s)'
MOV CX,0709h ; mask + shift factor
CALL DISP_HDWNUM ; Display string and number supported
;
MOV SI,Offset SYS_AUXI
MOV CX,0004h
CALL X3FEF
MOV SI,Offset SYS_AUXO
CALL X3FEF
;
CALL INITMDISK ; Initialize memory disk
CALL SETMDSKDP ; Setup memory disk parameters
MOV SI,Offset SIGNMEM ; 'Memory (Kb)'
CALL DISP_STR8
INT 12h ; PC ROM BIOS - Get Memory Size
; ; Returns AX=Number of kilobytes
;
MOV CL,6 ; 2^6 * 16 =1024
SHL AX,CL ; AX = num paragraphs
MOV DX,Word Ptr MDSKSEG
TEST DX,DX
JZ INIT2
CMP AX,DX
JA INIT3
INIT2: XCHG AX,DX
INIT3: MOV AX,DX
MOV BX,CS
ADD BX,Word Ptr X420E
MOV Word Ptr MRTSTART,BX
SUB DX,BX
MOV Word Ptr MRTLEN,DX
MOV CL,06h
SHR AX,CL
CALL DISP_LRGNUM ; Display large number (AX)
;
MOV CX,Word Ptr MDSKSIZ ; Zero Kb Memory disk ?
JCXZ INIT4 ; Yes, skip it
;
MOV SI,Offset SIGNMDK ; 'M:Disk (Kb)'
CALL DISP_STR8
MOV AX,Word Ptr MDSKSIZ
CALL DISP_LRGNUM ; Display large number (AX)
;
INIT4: CALL SETFIDMEM ; Setup FIDDS memory
CALL DISP_CRLF
MOV AH,03h ; Read cursor position
MOV BH,0 ; Page 0
INT 10h ; PC ROM BIOS Video Driver Service
CMP DH,18h
JB INIT5
MOV DH,17h
MOV AH,02h ; Set cursor position
INT 10h ; PC ROM BIOS Video Driver Service
INIT5: MOV Word Ptr CURSOR,DX
CLD
MOV SI,Offset DEFTOD ; '08/01/83,00:00:00'
MOV DI,Offset AMONTH
MOV CX,0011h
REP MOVSB
INC DI
MOV AL,' '
MOV CX,000Eh
REP STOSB
CALL RESETIO ; Reset disk and I/O ports
CLI
SUB AX,AX
MOV DS,AX ; To address zero page
;
MOV ZEROOFF,Offset ZEROINT ; Divide by zero interrupt
MOV ZEROSEG,CS
;
MOV BREAKOFF,Offset BREAKINT; User Break interrupt
MOV BREAKSEG,CS
;
MOV TIMEROFF,Offset TIMERINT; Timer interrupt
MOV TIMERSEG,CS
;
MOV UNDSKOFF,Offset UNDSKINT; Unknown disk drive interrupt
MOV UNDSKSEG,CS
;
PUSH CS
POP DS
MOV CL,Byte Ptr DEFDRV ; Default drive
MOV Byte Ptr BDOSCURDRV,CL
STI
JMP CCP ; Enter as for warm boot
;
;----------------------------------------
;
; Setup Interrupt Service Routine vectors
;
SETISR: SUB AX,AX
MOV ES,AX
MOV DS,AX
MOV DI,0080h
MOV AX,Offset UNEXPINT ; Unexpected interrupt routine
MOV BX,CS ; and segment
CLD
MOV CX,0040h
SETISR1:
INC DI ; AT PATCH - Originally STOSW instruction
XCHG AX,BX
LOOP SETISR1
;
ADD DI,0008h
MOV CX,017Ch
SETISR2:
INC DI ; AT PATCH - Originally STOSW instruction
XCHG AX,BX
LOOP SETISR2
;
; Set BDOS offset to proper interrupt
;
MOV BDOSOFF,Offset BDOS_OFST
MOV BDOSSEG,CS
;
; Set diskette parameters (pointer at INT-1E vector)
;
MOV I1EOFF,Offset DSKPRM
MOV I1ESEG,CS
RET
;----------------------------------------
X3D52: MOV DI,Offset X3AB2
MOV CX,4
MOV AL,Byte Ptr IPLDSK
MOV DL,AL
REPNE SCASB
NEG CX
ADD CX,3
MOV Byte Ptr DEFDRV,CL ; Set default disk drive
MOV SI,CX
MOV CX,2
TEST AL,80h
JZ X3D7E
SHL SI,1
MOV BX,Word Ptr X3AB6[SI]
MOV AX,[BX]
MOV CL,3
CALL X2D99
X3D7E: MOV DH,0 ; Head 0
MOV BX,Offset X4780 ; ES:BX - data buffer
MOV SI,BX
MOV AX,0201h ; Read Sector(s) - 1 sector
INT 13h ; PC ROM BIOS Floppy Disk Services
CLD
LODSW
CMP AX,0DDB2h
JZ X3D92
RET
X3D92: LODSW
MOV Word Ptr MDSKSEG,AX
LODSB
MOV Byte Ptr VFLAG,AL ; Verify enabled ?
LODSB
MOV Byte Ptr DSKPRM+0,AL ; Update diskette parameters
MOV SI,Offset X4790
MOV DI,Offset KEYBUF
MOV CX,0014h
REP MOVSB
MOV AX,Word Ptr X47B0
MOV Word Ptr FIDDSMEM,AX
MOV AL,Byte Ptr X47C0
MOV Byte Ptr SNDFLG,AL
TEST Byte Ptr X47E0,TRUE
JZ X3DC2
MOV AX,Word Ptr X47E4
MOV Word Ptr SER1,AX ; Serial ports init parms (1 and 2)
X3DC2: TEST Byte Ptr X47E1,TRUE
JZ X3DD4
MOV SI,Offset X47E6
MOV DI,Offset SYS_CONI
MOV CX,5
REP MOVSW
X3DD4: TEST Byte Ptr X47E2,TRUE
JZ X3DE6
MOV SI,Offset X47F0
MOV DI,Offset PFKTABLE ; Function key definition table
MOV CX,200
REP MOVSW
X3DE6: RET
;----------------------------------------
;
; Initialize memory disk (M:)
;
; Validates and initilises memory at
; required segment address
;
INITMDISK:
PUSH DS
PUSH ES
MOV AX,Word Ptr MDSKSEG ; Memory disk segment address
TEST AX,AX ; Specified ?
JZ INITMDSK2 ; No, exit
;
MOV BX,0F5Ah ; Memory test pattern
;
INITMDSK1:
MOV DS,AX
MOV ES,AX ; Select memory disk segment
SUB DI,DI ; Offset zero
;
MOV [DI],BL
CMP [DI],BL ; Byte set correctly ?
JNZ INITMDSK2 ; No, exit
;
MOV [DI],BH
CMP [DI],BH ; Byte set correctly ?
JNZ INITMDSK2 ; No, exit
;
MOV CX,800h ; 2Kb
MOV AX,0E5E5h ; Empty fcb character
REP STOSW ; Fill it
;
ADD CS:Word Ptr MDSKSIZ,4
;
MOV AX,DS
ADD AX,0100h ; Next segment
CMP AX,0A000h ; Upto video RAM ?
JB INITMDSK1 ; No, test and initialise
;
CMP AX,0C000h ; Video RAM ?
JB INITMDSK2 ; Yes, exit
;
CMP AX,0F000h ; Upto BIOS ROM ?
JB INITMDSK1 ; No, test and initialise
;
INITMDSK2:
POP ES
POP DS
RET
;
;----------------------------------------
;
; Setup memory disk parameters
;
SETMDSKDP:
CMP Word Ptr MDSKSIZ,0 ; Zero Kb memory disk ?
JZ SETMDSKDPX ; Yes, exit
;
MOV AX,Word Ptr MDSKSIZ
MOV BX,Offset DPBK3
CMP AX,0100h
JBE SETMDSKDP2
MOV BX,Offset DPBK4
CMP AX,0200h
JBE SETMDSKDP1
MOV Byte Ptr 4[BX],0
;
SETMDSKDP1:
SHR AX,1h
;
SETMDSKDP2:
DEC AX
MOV 05h[BX],AX
MOV Word Ptr DPB4,BX
MOV Word Ptr DSKDRVRTNM,Offset MEMRTNSEL
;
SETMDSKDPX:
RET
;
;----------------------------------------
;
; Setup FIDDS memory segment pointer
;
SETFIDMEM:
MOV AX,Word Ptr FIDDSMEM
TEST AX,AX
JZ SETFIDMEMX ; Zero FIDDS memory required
;
MOV CL,6
SHL AX,CL
MOV DX,Word Ptr MRTLEN
SUB DX,AX
JB SETFIDMEM4
CMP DX,0400h
JB SETFIDMEM4
;
MOV Word Ptr MRTLEN,DX
ADD Word Ptr MRTSTART,AX
MOV AX,CS
ADD AX,Word Ptr X420E
MOV Word Ptr FIDDSSEG,AX
MOV SI,Offset SIGNFID ; 'FIDDS (Kb)'
CALL DISP_STR8
MOV AX,Word Ptr FIDDSMEM
CALL DISP_LRGNUM ; Display large number (AX)
;
SETFIDMEMX:
RET
;
SETFIDMEM4:
MOV Word Ptr FIDDSMEM,0
MOV SI,Offset ERRFD2BIG ; 'FIDDS Mem Request too large'
JMP DISP_CHAR ; Display string
;
;----------------------------------------
;
; Set initial video mode
;
; Entry AL = BIOS equipment value
;
SETINTVID:
AND AL,30h
MOV SI,7 ; 80 col text with status line
CMP AL,30h
JZ SETIV2
MOV SI,3 ; 80 col text with status line
CMP AL,20h
JZ SETIV2
SUB SI,SI ; 40 col text without status line
SETIV2:
XCHG AX,SI
JMP SETCURCRT ; Set current video details
;
;----------------------------------------
;
X3EB2: CALL X3EDD
CALL CHKHDDPAR ; Check HDD's for CPM partitions
MOV AX,Word Ptr X420A
MOV CL,4
SHR AX,CL ; x 16
INC AX
MOV Word Ptr X420E,AX
MOV AL,Byte Ptr X3A6C
CBW
MOV CX,4
SUB CX,AX
JZ X3EDC
SHL AX,1h
ADD AX,Offset DSKDRVRTN
XCHG AX,DI
PUSH CS
POP ES
MOV AX,Offset DSKRTNINV
CLD
REP STOSW
X3EDC: RET
;
;----------------------------------------
;
X3EDD: MOV AL,Byte Ptr FDDCNT ; Number of physical
CBW ; diskette drives.
XCHG AX,CX
SUB BX,BX
JCXZ X3EF3
X3EE6: MOV Byte Ptr X3AB2[BX],BL
MOV SI,Offset DPBK1
CALL CHKCP4
INC BX
LOOP X3EE6
X3EF3: RET
;----------------------------------------
;
; Check each hard drive for a single CPM partition
;
CHKHDDPAR:
TEST Byte Ptr HDDCNT,0FFh ; Hard disk(s) present ?
JZ CHKHPX ; No, skip
;
MOV Byte Ptr HDDCHK,80h ; Set hard disk 0 (first)
CHKHP1: MOV DL,Byte Ptr HDDCHK ; Drive number
MOV DH,0 ; Head 0
MOV CX,0001h ; Cylinder 0, sector 1
MOV BX,Offset HDDBUF ; ES:BX - data buffer
MOV AX,0201h ; Read sector(s) - 1 sector
INT 13h ; PC ROM BIOS Floppy Disk Services
;
CMP Word Ptr HDDBUF+510,0AA55h ; VAlid Master-Boot-Record?
JNZ CHKHP4 ; No, check next drive
;
MOV BX,Offset HDDBUF+446 ; 1st Partition table entry
MOV CX,4 ; 4 entries
;
CHKHP2: CMP Byte Ptr 4[BX],0DBh ; CPM partition ?
JZ CHKHP3 ; Yes
ADD BX,16 ; No, point to next entry
LOOP CHKHP2 ; and test
JMPS CHKHP4 ; Check next drive
;
CHKHP3: CALL CHKCPMPAR ; Check CPM partition
CMP Byte Ptr X3A6C,04h
JNB CHKHPX
;
CHKHP4: INC Byte Ptr HDDCHK ; Next drive (to check)
DEC Byte Ptr HDDCNT
JNZ CHKHP1 ; Test it
;
CHKHPX: RET
;----------------------------------------
;
; Check valid CPM partition
;
; entry - BX = Partition table entry
;
CHKCPMPAR:
MOV DL,Byte Ptr HDDCHK ; Drive number (to check)
MOV DH,0 ; Head 0
MOV CX,02h[BX] ; CX: CH=Cylinder, CL=Sector (1 to 63)
AND CL,0C0h
OR CL,04h
MOV BX,Offset HDDBUF ; ES:BX - sector buffer
MOV AX,0201h ; Read sectors - 1 sector
INT 13h ; PC ROM BIOS Floppy Disk Services
;
; Checksum 1st sector of partition
; Result should be zero
;
CMP Word Ptr HDDBUF+46,0
JZ CHKCP1
MOV CX,256
SUB AX,AX
CHKCP1: ADD AX,[BX]
INC BX
INC BX
LOOP CHKCP1
TEST AX,AX ; Valid checksum ?
JZ CHKCP2 ; Yes
;
MOV SI,Offset ERRCHKSUM ; 'Hard disk label checksum error'
JMP DISP_CHAR ; Display string
;
; Ensure partition not too big for CPM
;
CHKCP2: MOV AL,Byte Ptr HDDBUF+47
MOV AH,0
MOV CL,Byte Ptr HDDBUF+43
SHL AX,CL
TEST AH,AH ; <= 8192 MB ?
JZ CHKCP3 ; Yes
;
MOV SI,Offset ERRHP2BIG ; 'Hard disk partition too big'
CALL DISP_CHAR ; Display string
RET
;
CHKCP3: AND Word Ptr HDDBUF+52,7FFFh
MOV SI,Offset HDDBUF+33
MOV DI,Word Ptr X420A
MOV DX,DI
MOV CX,Word Ptr HDDBUF+68
ADD CX,CX
ADD CX,39
REP MOVSB
MOV Word Ptr X420A,DI
MOV AL,Byte Ptr X3A6C
CBW
MOV SI,AX
MOV AL,Byte Ptr HDDCHK ; HDD (to check)
MOV Byte Ptr X3AB2[SI],AL
SHL SI,1h
MOV Word Ptr X3AB6[SI],DX
INC Byte Ptr X3A6C
MOV SI,DX
ADD SI,0008h
;
CHKCP4: PUSH BX
PUSH CX
MOV BX,Word Ptr X420C
MOV 0Ah[BX],SI
MOV AX,Word Ptr X420A
MOV 0Ch[BX],AX
ADD AX,0Bh[SI]
MOV 0Eh[BX],AX
XCHG AX,BX
MOV AX,05h[SI]
MOV CL,03h
SHR AX,CL
INC AX
ADD AX,BX
MOV Word Ptr X420A,AX
ADD Word Ptr X420C,0010h
POP CX
POP BX
RET
;----------------------------------------
X3FEF: TEST AL,AL
JZ X3FFC
CMP Byte Ptr X47E1,TRUE
JZ X3FFC
MOV [SI],CX
X3FFC: RET
;----------------------------------------
;
; Display null terminated string followd by
; number of hardware units supported
;
; Input: SI:=string offset
; DS:=string segment address
; DX:=hardware configuration
; CL:=shift factor
; CH:=mask
; Output: none
;
DISP_HDWNUM:
MOV AX,DX
SHR AX,CL
AND AL,CH ; Zero devices ?
JZ DISP_HDWNUMX ; Yes, exit
;
PUSH AX
CALL DISP_STR8 ; Display spaces + string SI
POP AX
PUSH AX
CALL DISP_NUM ; Display AL as numeric char
CALL DISP_CRLF
POP AX
DISP_HDWNUMX:
RET
;----------------------------------------
;
; Display 8 spaces followed by null terminated string
;
; Input: SI:=string offset
; DS:=string segment address
; Output: none
;
DISP_STR8:
MOV CX,8
;
DISP_STR8A:
MOV AL,' '
CALL DISP_CHAR ; Display char
LOOP DISP_STR8A
; JMP DISP_STR ; Fall through
;----------------------------------------
;
; Display null terminated string
;
; Input: SI:=string offset
; DS:=string segment address
; Output: none
;
DISP_STR:
CLD
LODSB ; Get char
;
DISP_CHAR1:
CALL DISP_CHAR ; Display it
LODSB ; Get next char
OR AL,AL ; End of string ?
JNZ DISP_CHAR1
RET ; Yes
;----------------------------------------
;
; Display large number AX as numeric chars
;
; Input: AX:=number (largest number accepted = 999)
; Output: none
;
DISP_LRGNUM:
CMP AX,10 ; Less than 10 ?
JB DISP_LRGNUM2 ; Yes, display digit
;
MOV CL,100
DIV CL ; Divide by 100
OR AL,AL ; Any hundreds ?
JZ DISP_LRGNUM1 ; No
;
CALL DISP_NUM ; Display hundreds digit
;
DISP_LRGNUM1:
MOV AL,AH
SUB AH,AH
AAM ; Split AL into tens and units
XCHG AL,AH ; First tens
CALL DISP_NUM ; Display tens digit
MOV AL,AH ; Now units
;
DISP_LRGNUM2:
CALL DISP_NUM ; Display units digit
JMPS DISP_CRLF ; Display CR+Lf then return
;----------------------------------------
;
; Display AL as numeric char
;
; Input: AL:=char (preserved throughout call)
; Output: none
;
DISP_NUM:
PUSH AX
OR AL,30h ; Make numeric ASCII char
CALL DISP_CHAR ; Display char
POP AX
RET
;----------------------------------------
;
; Display carriage return and linefeed
;
DISP_CRLF:
MOV AL,CR
CALL DISP_CHAR ; Display char
MOV AL,LF
; ; Fall through
;----------------------------------------
;
; Display character in teletype mode
;
; Input: AL:=char
; Output: none
;
DISP_CHAR:
PUSH SI
MOV BX,0 ; page zero, foreground colour 0
MOV AH,0Eh ; Write text in teletype mode
INT 10h ; PC ROM BIOS Video Driver Service
POP SI
RET
;
;*********************************************
;* *
;* INIT routine Data Areas *
;* *
;*********************************************
data_offst2 EQU offset $
;
DSEG
ORG data_offst2 ; contiguous with code
;
SIGNON DB cr,lf,lf
DB 'CP/M-86 for the IBM PC and IBM PC XT Version 1.1'
DB cr,lf
DB 'Copyright (C) 1983, Digital Research'
DB cr,lf,lf,lf
DB 'Hardware Supported :'
DB cr,lf,lf,0
;
SIGNDSK DB ' Diskette Drive(s) : ',0
SIGNHDD DB ' Hard Disk Drive(s) : ',0
SIGNPRT DB 'Parallel Printer(s) : ',0
SIGNSER DB ' Serial Port(s) : ',0
SIGNMEM DB ' Memory (Kb) : ',0
SIGNMDK DB ' M:Disk (Kb) : ',0
SIGNFID DB ' FIDDS (Kb) : ',0
;
DEFTOD DB '08/01/83,00:00:00'
;
ERRCHKSUM DB cr,lf
DB 'Hard Disk Label Checksum Error'
DB cr,lf,lf,0
;
ERRHP2BIG DB cr,lf
DB 'Hard Disk Partition is Too Big for CP/M-86'
DB cr,lf,lf,0
;
ERRFD2BIG DB cr,lf
DB 'FIDDS memory request is too large'
DB cr,lf,0
;
HDDCHK DB 0 ; Hard disk drive (to check)
IPLDSK DB 0 ; Initial program load disk
DEFDRV DB 0 ; Default drive (for CCP)
FDDCNT DB 0 ; Number of diskette drives
HDDCNT DB 0 ; Number of Hard disk drives
;
X420A DB 086h,04Ch ; 864C 4C86?
X420C DW Offset DPBASE ;
X420E DW 0 ;
;
RS 1390
DB 0DBh ; ?
DB 00h
;
X4780 RS 16
X4790 RS 32
X47B0 RS 16
X47C0 RS 32
;
X47E0 DB 0
X47E1 DB 0
X47E2 DB 0
X47E3 DB 0
X47E4 DW 0
X47E6 DW 0,0,0,0,0
X47F0 RS 400
;
ORG 4980h
HDDBUF RS 512 ; HDD sector buffer
ORG 4BE2h
DIRBUF RS 128 ; Directory buffer
;
ORG 4C62h
CSV14 EQU $
;*********************************************
; End of PCBIOS.A86 file
END