;********************************************* ;* * ;* 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