MS-DOS/v2.0/source/SKELIO.ASM
2018-09-21 17:53:34 -07:00

1377 lines
44 KiB
NASM
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.

TITLE IO.SYS for the ALTOS ACS-86C.
; I/O system for Version 2.x of MSDOS.
;This BIOS designed to be linked with the SYSINIT module provided by
;Microsoft
BIOSIZ EQU 4096 ;Size of BIOS in bytes.
BIOSIZS EQU 100H ;Size of BIOS in Paragraphs.
ANSI EQU 0 ;Ansi switch.
;Additional Information for the ALTOS machine.
QSIZE EQU 100 ;Input queue size.
BIOSSEG EQU 0C0H ;I/O system segment.
MAX_MEM EQU 4000H ;Memory size in paragraphs.
; Constants for commands in Altos ROM.
ROM_CONSTA EQU 01 ;Return status AL of console selected in CX.
ROM_CONIN EQU 02 ;Get char. from console in CX to AL
ROM_CONOUT EQU 03 ;Write char. in DL to console in CX.
ROM_PMSG EQU 07 ;Write string ES:DX to console in CX.
ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX.
ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX.
;Things needed to communicate with SYSINIT
EXTRN SYSINIT:FAR ;The entry point of SYSINIT
EXTRN CURRENT_DOS_LOCATION:WORD ;Where the DOS is when SYSINIT called
EXTRN FINAL_DOS_LOCATION:WORD ;Where I want SYSINIT to put the DOS
EXTRN DEVICE_LIST:DWORD ;Pointer to the DEVICE list.
EXTRN MEMORY_SIZE:WORD ;Size in paragraphs of Physical memory.
EXTRN DEFAULT_DRIVE:BYTE ;Default Drive to use when system booted
EXTRN BUFFERS:BYTE ;Number of default buffers.
; Leave as is and SYSINIT uses only 2.
CODE SEGMENT
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
ORG 0 ;Starts at an offset of zero.
INIT: JMP HWINIT
PAGE
SUBTTL Device driver tables.
;-----------------------------------------------+
; DWORD pointer to next device | 1 word offset.
; (-1,-1 if last device) | 1 word segement.
;-----------------------------------------------+
; Device attribute WORD ; 1 word.
; Bit 15 = 1 for chacter devices. ;
; 0 for Block devices. ;
; ;
; Charcter devices. (Bit 15=1) ;
; Bit 0 = 1 current sti device. ;
; Bit 1 = 1 current sto device. ;
; Bit 2 = 1 current NUL device. ;
; Bit 3 = 1 current Clock device. ;
; ;
; Bit 13 = 1 for non IBM machines. ;
; 0 for IBM machines only. ;
; Bit 14 = 1 IOCTL control bit. ;
;-----------------------------------------------+
; Device strategy pointer. ; 1 word offset.
;-----------------------------------------------+
; Device interrupt pointer. ; 1 word offset.
;-----------------------------------------------+
; Device name field. ; 8 bytes.
; Character devices are any valid name ;
; left justified, in a space filled ;
; field. ;
; Block devices contain # of units in ;
; the first byte. ;
;-----------------------------------------------+
DEVSTART LABEL WORD
CONDEV: ;Header for device CON
DW AUXDEV,BIOSSEG ;Link to next device
DW 8003H ;Attributes - console input, output device
DW STRATEGY ;Srategy entry point
DW CON_INT ;Interrupt entry point
DB "CON " ;Device name
AUXDEV: ;Header for device AUX
DW PRNDEV,BIOSSEG
DW 8000H
DW STRATEGY
DW AUX_INT
DB "AUX "
PRNDEV: ;Header for device PRN
DW TIMDEV,BIOSSEG
DW 8000H
DW STRATEGY
DW PRN_INT
DB "PRN "
TIMDEV: ;Header for device CLOCK
DW DSKDEV,BIOSSEG
DW 8008H
DW STRATEGY
DW TIM_INT
DB "CLOCK "
DSKDEV: ;Header for disk devices
DW -1,-1 ;Last device
DW 2000H ;Is a block device
DW STRATEGY
DW DSK_INT
DRVMAX DB 1 ;Number of Units
DB 7 DUP (?)
PAGE
SUBTTL Dispatch tables for each device.
DSKTBL: DW DSK_INIT ;0 - Initialize Driver.
DW MEDIAC ;1 - Return current media code.
DW GET_BPB ;2 - Get Bios Parameter Block.
DW CMDERR ;3 - Reserved. (currently returns error)
DW DSK_RED ;4 - Block read.
DW BUS_EXIT ;5 - (Not used, return busy flag)
DW EXIT ;6 - Return status. (Not used)
DW EXIT ;7 - Flush input buffer. (Not used.)
DW DSK_WRT ;8 - Block write.
DW DSK_WRV ;9 - Block write with verify.
DW EXIT ;10 - Return output status.
DW EXIT ;11 - Flush output buffer. (Not used.)
DW EXIT ;12 - IO Control.
CONTBL: DW EXIT ;0 - Init. (Not used)
DW EXIT ;1 - Media check (Not used)
DW EXIT ;2 - Get Bios Parameter Block (Not used)
DW CMDERR ;3 - Reserved. (Currently returns error)
DW CON_READ ;4 - Character read. (Destructive)
DW CON_RDND ;5 - Character read. (Non-destructive)
DW EXIT ;6 - Return status. (Not used)
DW CON_FLSH ;7 - Flush Input buffer.
DW CON_WRIT ;8 - Character write.
DW CON_WRIT ;9 - Character write with Verify.
DW CON_WRST ;10 - Character write status.
DW EXIT ;11 - Flush output buffer. (Not used.)
DW EXIT ;12 - IO Control.
AUXTBL: DW EXIT ;0 - Init. (Not used)
DW EXIT ;1 - Media check (Not used)
DW EXIT ;2 - Get Bios Parameter Block (Not used)
DW CMDERR ;3 - Reserved. (Returns an error)
DW AUX_READ ;4 - Character read. (Destructive)
DW AUX_RDND ;5 - Character read. (Non-destructive)
DW EXIT ;6 - Return status. (Not used)
DW AUX_CLR ;7 - Flush Input buffer.
DW AUX_WRIT ;8 - Character write.
DW AUX_WRIT ;9 - Character write with verify.
DW AUX_WRST ;10 - Character write status.
DW EXIT ;11 - Flush output buffer. (Not used.)
DW EXIT ;12 - IO Control.
TIMTBL: DW EXIT ;0 - Init. (Not used)
DW EXIT ;1 - Media check (Not used)
DW EXIT ;2 - Get Bios Parameter Block (Not used)
DW CMDERR ;3 - Reserved. (Currently returns an error)
DW TIM_RED ;4 - Character read. (Destructive)
DW BUS_EXIT ;5 - (Not used, returns busy flag.)
DW EXIT ;6 - Return status. (Not used)
DW EXIT ;7 - Flush Input buffer. (Not used)
DW TIM_WRT ;8 - Character write.
DW TIM_WRT ;9 - Character write with verify.
DW EXIT ;10 - Character write status. (Not used)
DW EXIT ;11 - Flush output buffer. (Not used)
DW EXIT ;12 - IO Control.
PRNTBL: DW EXIT ;0 - (Not used)
DW EXIT ;1 - (Not used)
DW EXIT ;2 - Block (Not used)
DW CMDERR ;3 - Reserved. (currently returns error)
DW EXIT ;4 - (Not used)
DW BUS_EXIT ;5 - (Not used, returns busy flag.)
DW EXIT ;6 - (Not used)
DW EXIT ;7 - (Not used)
DW PRN_WRT ;8 - Character write.
DW PRN_WRT ;9 - Character write with verify.
DW PRN_STA ;10 - Character write status.
DW EXIT ;11 - (Not used.)
DW EXIT ;12 - IO Control.
PAGE
SUBTTL Strategy and Software Interrupt routines.
;Define offsets for io data packet
IODAT STRUC
CMDLEN DB ? ;LENGTH OF THIS COMMAND
UNIT DB ? ;SUB UNIT SPECIFIER
CMD DB ? ;COMMAND CODE
STATUS DW ? ;STATUS
DB 8 DUP (?)
MEDIA DB ? ;MEDIA DESCRIPTOR
TRANS DD ? ;TRANSFER ADDRESS
COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS
START DW ? ;FIRST BLOCK TO TRANSFER
IODAT ENDS
PTRSAV DD 0 ;Strategy pointer save.
;
; Simplistic Strategy routine for non-multi-Tasking system.
;
; Currently just saves I/O packet pointers in PTRSAV for
; later processing by the individual interrupt routines.
;
STRATP PROC FAR
STRATEGY:
MOV WORD PTR CS:[PTRSAV],BX
MOV WORD PTR CS:[PTRSAV+2],ES
RET
STRATP ENDP
;
; Console interrupt routine for processing I/O packets.
;
CON_INT:
PUSH SI
MOV SI,OFFSET CONTBL
JMP SHORT ENTRY
;
; Auxilary interrupt routine for processing I/O packets.
;
AUX_INT:
PUSH SI
MOV SI,OFFSET AUXTBL
JMP SHORT ENTRY
;
; Printer interrupt routine for processing I/O packets.
;
PRN_INT:
PUSH SI
MOV SI,OFFSET PRNTBL
JMP SHORT ENTRY
;
; Clock interrupt routine for processing I/O packets.
;
TIM_INT:
PUSH SI
MOV SI,OFFSET TIMTBL
JMP SHORT ENTRY
;
; Disk interrupt routine for processing I/O packets.
;
DSK_INT:
PUSH SI
MOV SI,OFFSET DSKTBL
;
; Common program for handling the simplistic I/O packet
; processing scheme in MSDOS 2.0
;
ENTRY: PUSH AX ;Save all nessacary registers.
PUSH CX
PUSH DX
PUSH DI
PUSH BP
PUSH DS
PUSH ES
PUSH BX
LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet.
MOV AL,[BX.UNIT] ;AL = Unit code.
MOV AH,[BX.MEDIA] ;AH = Media descriptor.
MOV CX,[BX.COUNT] ;CX = Contains byte/sector count.
MOV DX,[BX.START] ;DX = Starting Logical sector.
XCHG DI,AX ;Move Unit & Media into DI temporarily.
MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11)
XOR AH,AH ;Clear upper half of AX for calculation.
ADD SI,AX ;Compute entry pointer in dispatch table.
ADD SI,AX
CMP AL,11 ;Verify that not more than 11 commands.
JA CMDERR ;Ah, well, error out.
XCHG AX,DI ;Move Unit & Media back where they belong.
LES DI,[BX.TRANS] ;DI contains addess of Transfer address.
;ES contains segment.
PUSH CS
POP DS ;Data segment same as Code segment.
JMP [SI] ;Perform I/O packet command.
PAGE
SUBTTL Common error and exit points.
BUS_EXIT: ;Device busy exit.
MOV AH,00000011B ;Set busy and done bits.
JMP SHORT EXIT1
CMDERR: MOV AL,3 ;Set unknown command error #.
;
; Common error processing routine.
; AL contains actual error code.
;
; Error # 0 = Write Protect violation.
; 1 = Unkown unit.
; 2 = Drive not ready.
; 3 = Unknown command in I/O packet.
; 4 = CRC error.
; 5 = Bad drive request structure length.
; 6 = Seek error.
; 7 = Unknown media discovered.
; 8 = Sector not found.
; 9 = Printer out of paper.
; 10 = Write fault.
; 11 = Read fault.
; 12 = General failure.
;
ERR_EXIT:
MOV AH,10000001B ;Set error and done bits.
STC ;Set carry bit also.
JMP SHORT EXIT1 ;Quick way out.
EXITP PROC FAR ;Normal exit for device drivers.
EXIT: MOV AH,00000001B ;Set done bit for MSDOS.
EXIT1: LDS BX,CS:[PTRSAV]
MOV [BX.STATUS],AX ;Save operation compete and status.
POP BX ;Restore registers.
POP ES
POP DS
POP BP
POP DI
POP DX
POP CX
POP AX
POP SI
RET ;RESTORE REGS AND RETURN
EXITP ENDP
PAGE
SUBTTL Main console I/O section.
MCON DW 0001H
PCON DW 0002H
ACON DW 0003H
CHAR DB ? ;Small typeahead buffer for now.
;
; Console keyboard handler.
;
CISTAT: PUSH CX ;Save CX pair.
MOV AL,[CHAR]
OR AL,AL
JNZ CISTA9 ;Character still in buffer.
CISTA1: MOV BX,ROM_CONSTA
MOV CX,[MCON]
CALL ROM_CALL ;See if character waiting.
TEST AL,AL
JZ CISTA9
MOV BX,ROM_CONIN
MOV CX,[MCON]
CALL ROM_CALL ;Get character from Rom.
OR AL,AL
JZ CISTA1 ;Got a null character.
MOV [CHAR],AL
CISTA9: POP CX ;Can't lose CX pair.
RET
;
; Get a character from the buffer queue.
;
CINP: CALL CISTAT ;Check for character ready in queue.
JZ CINP ;Cycle until one ready.
MOV [CHAR],0 ;We have character in AL, clear type a head.
RET
;
; Console read non-destructive.
;
CON_RDND:
CALL CISTAT ;See if character ready.
JZ CON_RDN2 ;No, return busy signal.
CON_RDN1:
LDS BX,CS:[PTRSAV]
MOV [BX.MEDIA],AL
JMP EXIT
CON_RDN2:
JMP BUS_EXIT
;
; Console destructive read.
;
CON_READ:
CALL CINP ;Get character.
STOSB ;Save it in users buffer.
LOOP CON_READ ;Loop until CX is exhausted.
JMP EXIT
;
; Console flush routine. (ctrl-c, ctrl-f, or ctrl-s inspired)
;
CON_FLSH:
MOV [CHAR],0 ;Clear small type a head buffer.
JMP EXIT
;
; Console output status routine.
;
CON_WRST:
JMP EXIT ;Yes, normal exit.
;
; Console output routine.
;
CON_WRIT:
MOV SI,DI ;Get destination to source.
CON_WRI1:
LODS BYTE PTR ES:[SI]
PUSH CX
IF ANSI
CALL CONOUT ;Call ansi driver.
ENDIF
IFE ANSI
CALL OUTCHR
ENDIF
POP CX
LOOP CON_WRI1 ;Keep going until user buffer through.
JMP EXIT
;
; Console character output routine.
;
OUTCHR: MOV BX,ROM_CONOUT
MOV CX,[MCON] ;Get current console port.
MOV DL,AL
CALL ROM_CALL
RET
PAGE
IF ANSI
SUBTTL ANSI interface section.
;
;ANSI Info and routines. ANSI driver implemented as a finite state automata
;This ANSI driver translates the ANSI standard escape sequences into the
; Zenith Escape sequences used on the Zenith(Heath) Z(H)-19 terminal.
;This is not a full implementation of ANSI, but rather a minimal implementation
; which implements all of the necessary ANSI functions.
;
ESC EQU 1BH ;Escape character used in this implementation.
STATE DW ST1 ;Current ANSI character state.
PRMPNT DW PARMS ;Current parameter pointer.
PARMS DB 0,0,0,0,0,0,0 ;Allow for up to eight parameters.
LASTPRM DB 0 ;With this being the eight one.
CMDTABL DB 'A' ;Cursor up. "esc","[",#,"A"
DW CUU
DB 'B' ;Cursor down. "esc","[",#,"B"
DW CUD
DB 'C' ;Cursor forward. "esc","[",#,"C"
DW CUF
DB 'D' ;Cursor back. "esc","[",#,"D"
DW CUB
DB 'H' ;Direct cursor posit. "esc","[",x,y,"H"
DW CUP
DB 'J' ;Erase. "esc","[",code,"J"
DW ED
DB 'K' ;Erase in line. "esc","[",code,"K"
DW EL
DB 'f' ;Direct cursor posit. "esc","[",x,y,"f"
DW CUP
DB 'm' ;Special video mode. "esc","[",code,"m"
DW SGR
DB 's' ;Save cursor posit. "esc","[","s"
DW PSCP
DB 'u' ;Move cursor to saved. "esc","[","u"
DW PRCP
DB 00 ;End of table.
;
; ANSI console output driver.
;
CONOUT: MOV DI,OFFSET STATE ;Retrieve current ansi state.
JMP [DI] ;Jump to it.
;
; State one (1).
; Looks for an Escape character.
;
ST1: CMP AL,ESC ;See if this the first character is ESC.
JNZ OUTCHR ;No, treat as regular character output.
MOV WORD PTR [DI],OFFSET ST2 ;Yes, setup state two.
RET
;
; State two (2).
; Looks for the "[" character.
;
ST2: CMP AL,'[' ;See if a valide state two.
JNZ OUTCHR ;No, treat as regular charcter
MOV BX,OFFSET PARMS ;Yes, get parameter pointer.
MOV WORD PTR [PRMPNT],BX ;Setup in pointer index.
MOV WORD PTR [BX],0 ;Clear first entry.
MOV WORD PTR [DI],OFFSET ST3;Setup for state three.
RET
;
; State three (3).
; Entered one or more times for parameter passing.
;
ST3: CMP AL,';' ;Look for decimal # seperator.
JNZ ST3A ;No check phase A.
INC WORD PTR [PRMPNT] ;Yes, incr. pointer to next param.
MOV AX,OFFSET LASTPRM ;Check for outside parameter list.
CMP [PRMPNT],AX
JBE RETST3 ;Yes, proceed with next parameter.
MOV [PRMPNT],AX ;No, treat as extentsion to old.
RETST3: MOV DI,[PRMPNT] ;Setup for next parameter.
MOV BYTE PTR [DI],0 ;Pre-Initialize it to zero.
RET
;
; State three A (3A).
; Check for a ascii digit.
;
ST3A: CMP AL,'0' ;Check for ASCII digit.
JB ST3B ;No, check for seconday command character.
CMP AL,'9' ;Still checking for ASCII digit.
JA ST3B ;No, it must be a secondary.
SUB AL,'0' ;Convert to binary.
MOV DI,[PRMPNT] ;Get the current parameter pointer.
XCHG [DI],AL ;Get existing #.
MOV AH,10 ;Scale by 10.
MUL AH
ADD [DI],AL ;Add to new digit.
RET
;
; State three B (3B).
; Wasn't a ascii digit, so check for secondary command.
;
ST3B: MOV [DI],OFFSET ST1 ;Preset STATE to state 1 just in case.
MOV DI,OFFSET PARMS-1 ;Get pointer to start of parameters.
MOV [PRMPNT],DI ;Save it in Parameter pointer.
MOV DI,OFFSET CMDTABL-3 ;Get start of Secondary command table.
ST3B1: ADD DI,3 ;Update Command table pointer.
CMP BYTE PTR [DI],0 ;Check for end of table.
JNZ ST3B2 ;No, continue processing.
JMP OUTCHR ;Yes, treat as regular character.
ST3B2: CMP AL,[DI] ;Check for valid. command.
JNZ ST3B1 ;No, keep checking.
JMP [DI+1] ;Yes, transfer to that secondary command.
;
; Get binary parameter from storage and return a one if = 0
;
GETONE: CALL GETPARM ;Get parameter form list.
OR AL,AL ;Verify for non-zero.
JNZ GETRET ;Good, then return to caller.
INC AL ;Bad, make it at least a one.
GETRET: CBW ;Sign extend AL.
MOV CX,AX ;Copy of it to CX.
RET
GETPARM:INC WORD PTR [PRMPNT] ;Increment parameter pointer.
GOTPARM:MOV DI,[PRMPNT] ;Get parameter pointer.
MOV AL,[DI] ;Get parameter value.
RET
;
; Send escape, character sequence.
;
OUTESC: MOV AL,ESC ;Send escape character.
CALL OUTCHR
MOV AL,BL ;Send follow character.
JMP OUTCHR
;
; Cursor Positioning routines.
;
CUU: MOV BL,'A' ;Cursor up.
JMP SHORT CURPOS
CUD: MOV BL,'B' ;Cursor down.
JMP SHORT CURPOS
CUF: MOV BL,'C' ;Cursor forward.
JMP SHORT CURPOS
CUB: MOV BL,'D' ;Cursor back.
CURPOS: CALL GETONE ;Get number of positions to move into CX.
MOVCUR: CALL OUTESC ;Send escape, command characters.
LOOP MOVCUR ;Keep moving until done.
RET
;
; Direct cursor positioning routine.
;
CUP: CALL GETONE ;Get X position.
MOV DX,AX ;Save in DX.
CALL GETONE ;Get Y position.
MOV BL,'Y'
CALL OUTESC ;Send escape, "Y" sequence.
MOV AL,DL
ADD AL,' '-1 ;Convert binary to Character.
CALL OUTCHR ;Send X posit.
MOV AL,CL
ADD AL,' '-1 ;Convert binary to Character.
JMP OUTCHR ;Send Y posit.
;
; Erase all/part of screen.
;
ED: CALL GETPARM ;Get trinary command type.
MOV BL,'b'
DEC AL ;See if erase from begining of screen.
JZ ED1 ;Yes, perform ZDS function.
MOV BL,'E'
DEC AL ;See if erase from end of screen.
JZ ED1 ;Yes, perform ZDS function.
MOV BL,'J' ;Now we assume erase whole screen.
ED1: JMP OUTESC
;
; Erase all/part of a line.
;
EL: CALL GETPARM ;Get trinary command type.
MOV BL,'o'
DEC AL ;See if erase from begining of line.
JZ EL1 ;Yes, perform ZDS function.
MOV BL,'l'
DEC AL ;See if erase whole line.
JZ EL1 ;Yes, perform ZDS function.
MOV BL,'K' ;Now we assume erase to end of line.
EL1: JMP OUTESC
;
; Special video modes.
;
SGR: CALL GETPARM ;Get trinary command type.
MOV BL,'p'
CMP AL,7 ;See if enter reverse video mode.
JZ SGR2 ;Yes, perform ZDS function.
MOV BL,'q'
OR AL,AL ;See if exit reverse video mode.
JNZ SGR3 ;No, ignore.
SGR2: CALL OUTESC
SGR3: RET
;
; Save / restore cursor position.
;
PSCP: MOV BL,'j' ;Set save cursor posit. mode.
JMP OUTESC
PRCP: MOV BL,'k' ;Restore last cursor save.
JMP OUTESC
ENDIF
PAGE
SUBTTL Printer buffer handler.
;
; Printer status routine.
;
PRN_STA:
JMP EXIT
;
; Printer write routine.
;
PRN_WRT:MOV SI,DI ;Set source = destination index.
PRN_WR1:LODS BYTE PTR ES:[SI];Get a data byte.
PUSH CX
MOV CX,[PCON]
MOV BX,ROM_CONOUT
MOV DL,AL
CALL ROM_CALL
POP CX
LOOP PRN_WR1
RET
PAGE
SUBTTL Auxilary I/O routines.
AUXCHAR DB 0 ;Temporary AUX ahead storage.
;
; Status routine for Auxilary port.
;
AISTAT: MOV AL,[AUXCHAR]
TEST AL,AL
JNZ AISTA9 ;Character already waiting.
MOV CX,[ACON]
MOV BX,ROM_CONSTA
CALL ROM_CALL
TEST AL,AL
JZ AISTA9 ;Still none waiting.
MOV CX,[ACON]
MOV BX,ROM_CONIN
CALL ROM_CALL
AISTA9: MOV [AUXCHAR],AL
RET
;
; Auxilary port read.
;
AIN: CALL AISTAT ;Get status and/or char.
JZ AIN ;Cycle until one is ready.
MOV [AUXCHAR],0
RET
;
; Write routine for Auxilary port.
;
AOUT: MOV CX,[ACON]
MOV BX,ROM_CONOUT
MOV DL,AL
CALL ROM_CALL
RET
;
; Non-Destructive Auxilary read routine.
;
AUX_RDND:
CALL AISTAT ;Get status and copy of char. waiting if any.
JZ AUX_RDN2 ;No character waiting, exit.
JMP CON_RDN1
AUX_RDN2:
JMP BUS_EXIT
;
; Destructive Auxilary read routine.
;
AUX_READ:
CALL AIN ;Get data character.
STOSB ;Save it through DI.
LOOP AUX_READ ;Cycle until user buffer full.
JMP EXIT
;
; Auxilary clear type a head.
;
AUX_CLR:
MOV [AUXCHAR],0
JMP EXIT
;
; Auxilary write port status.
;
AUX_WRST:
JMP EXIT
;
; Auxilary write.
;
AUX_WRIT:
MOV SI,DI
AUX_WRI1:
LODS BYTE PTR ES:[SI] ;Get char. from users buffer.
CALL AOUT ;Send it to device.
LOOP AUX_WRI1 ;Cycle until all done.
JMP EXIT
PAGE
SUBTTL Date/Time Routines.
TIM_DAYS: DB 2 DUP (?) ;Number of days since 1-1-80.
TIM_MINS: DB ? ;Minutes.
TIM_HRS: DB ? ;Hours.
TIM_HSEC: DB ? ;Hundreths of a second.
TIM_SECS: DB ? ;Seconds.
;
; Time write routine.
;
TIM_WRT:
MOV SI,OFFSET TIM_DAYS
XCHG SI,DI
PUSH ES
MOV AX,DS
POP DS
MOV ES,AX
MOV CX,6
REP MOVSB
MOV AL,0
JMP EXIT
;
; Time read routine.
;
TIM_RED:
MOV SI,OFFSET TIM_DAYS
MOV CX,6
REP MOVSB
MOV AL,0
JMP EXIT
PAGE
SUBTTL 8089 Monitor structure.
;
; Structure to reference 8089 and ROM command table.
;
SIOPB STRUC
DB 4 DUP (?) ;Monitor Use Only
OPCODE DB ? ;I/O operation code.
DRIVE DB ? ;Logical drive spec.
TRACK DW ? ;Logical track number.
HEAD DB ? ;Logical head number.
SECTOR DB ? ;Logical sector to start with.
SCOUNT DB ? ;Number of logical sectors in buffer.
RETCODE DB ? ;Error code after masking.
RETMASK DB ? ;Error mask.
RETRIES DB ? ;Number of retries before error exit.
DMAOFF DW ? ;Buffer offset address.
DMASEG DW ? ;Buffer segment.
SECLENG DW ? ;Sector Length.
DB 6 DUP (?) ;8089 use only.
SIOPB ENDS
IOPB SIOPB <,00H,0,0,0,0,0,0,000H,0,0,0,0,>
PAGE
SUBTTL Drive Tables.
;
; MSDOS drive initialization tables and other what not.
;
; Drive 0 is:
; Single sided, Single density, 77 track with 26
; 128 byte sectors per track. One sector for
; boot and header. (256,128 bytes free, old style).
; or
; Single sided, Single density, 77 track with 26
; 128 byte sectors per track. Four sectors for
; boot and header. (255,744 bytes free).
; or
; Single sided, Double Density, 75 track with 12
; 512 byte sectors per track.
; (460,800 bytes)
; Two hidden single density tracks.
;
DBP STRUC
JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot.
NAMEVER DB 8 DUP (?) ;Name / Version of OS.
;------- Start of Drive Parameter Block.
SECSIZE DW ? ;Sector size in bytes. (dpb)
ALLOC DB ? ;Number of sectors per alloc. block. (dpb)
RESSEC DW ? ;Reserved sectors. (dpb)
FATS DB ? ;Number of FAT's. (dpb)
MAXDIR DW ? ;Number of root directory entries. (dpb)
SECTORS DW ? ;Number of sectors per diskette. (dpb)
MEDIAID DB ? ;Media byte ID. (dpb)
FATSEC DW ? ;Number of FAT Sectors. (dpb)
;------- End of Drive Parameter Block.
SECTRK DW ? ;Number of Sectors per track.
DBP ENDS
LSDRIV1 DBP <,,128,4,1,2,68,2002,0FEH,6,26>
LSDRIV2 DBP <,,128,4,4,2,68,2002,0FDH,6,26>
LDDRIV1 DBP <,,512,1,24,2,128,924,0F8H,3,12>
LDDRIV2 DBP <,,1024,1,16,2,128,616,0F9H,1,8>
DSK_INIT:
MOV AX,1
MOV SI,OFFSET INITTAB
JMP GET_BP5
INITTAB:
DW LDDRIV2.SECSIZE
DSTAT EQU 41H ;1793 status port.
DTRACK EQU 43H ;1793 track port.
DSECTOR EQU 45H ;1793 sector port.
DDATA EQU 47H ;1793 data I/O port.
DDENS EQU 55H ;Density select port.
DDBIT EQU 04H ;Density select bit.
DSELECT EQU 53H ;Drive select port.
CURDRV DB 0
DRVTAB DB 0EH,0DH,0BH,07H
TRKPT DB 0,1,2,3
TRKTAB DB -1,-1,-1,-1
PREDENS DB 0,0,0,0
PAGE
SUBTTL Media check routine
;
; Media check routine.
; On entry:
; AL = disk unit number.
; AH = media byte
; On exit:
;
; [MEDIA FLAG] = -1 (FF hex) if disk is changed.
; [MEDIA FLAG] = 0 if don't know.
; [MEDIA FLAG] = 1 if not changed.
;
; [MEDIA] = 0FEH for Standard single density.
; [MEDIA] = 0FDH for Altos single density.
; [MEDIA] = 0F4H for Altos double density.
;
MEDIAS STRUC
DB 13 DUP(?) ;Static request header.
MEDIAS1 DB ? ;Media byte.
MEDIAS2 DB ? ;Media status byte flag.
MEDIAS ENDS
MEDIAC:
AND AL,03H ;Clear any extraneous bits.
PUSH AX ;Save drive number requested.
MOV AL,0D0H ;Terminate with no interrupt.
CALL DCOM
AND AL,20H ;See if head load bit set.
POP AX
JZ MEDIA2 ;Head not loaded, so see if media changed.
MOV AH,1 ; AH = 1, disk not changed.
JMP SHORT MEDIA1
MEDIA1A:MOV [PREDENS],DL ;Save last density used for read.
MEDIA1: LDS BX,[PTRSAV] ;Udate media section of data block.
MOV [BX.MEDIAS2],AH
MOV AL,0
JMP EXIT
MEDIA2: CALL MEDIA4 ;Unload head if selecting new drive.
MOV CX,2 ;Try each density once.
MOV BX,OFFSET DRVTAB
XLAT ;Convert from drive # to select code.
OUT DSELECT,AL ;Select disk
MOV AH,0 ;Assume that we don't know.
MOV DL,[PREDENS] ;Get last density.
AND DL,DDBIT ;Be sure only Density bit set/clr.
MEDIA3: IN AL,DDENS
AND AL,0FBH ;Clear density bit.
OR AL,DL ;Set/clear density bit.
OUT DDENS,AL ;Select density.
MOV AL,0C4H ;READ ADDRESS command
CALL DCOM
AND AL,98H
IN AL,DDATA ;Eat last byte to reset DRQ
JZ MEDIA1A ;Jump if no error in reading address.
MOV AH,0FFH ; AH = -1 (disk changed) if new density works.
XOR DL,DDBIT ;Flip density bit.
LOOP MEDIA3
MOV AX,2 ;Couldn't read disk at all, AH = 0 for don't
JMP ERR_EXIT ; know if disk changed, AL = error code 2 -
MEDIA4: MOV AH,AL ;Save disk drive number in AH.
XCHG AL,[CURDRV] ;make new drive current, AL = previous
CMP AL,AH ;Changing drives?
JZ MEDIA5 ;No, return to caller.
;
; If changing drives, unload head so the head load delay one-shot
; will fire again. Do it by seeking to same track with the H bit reset.
;
IN AL,DTRACK ;Get current track number
OUT DDATA,AL ;Make it the track to seek to
MOV AL,10H ;Seek and unload head
CALL DCOM
MOV AL,AH ;Restore current drive number
MEDIA5: RET
;
; Short routine to send a command to 1793 diskette controller chip and
; wait for 1793 to complete the command.
;
DCOM: OUT 41H,AL ;Send command to 1793.
MOV CX,10H
DCOM1: LOOP DCOM1 ;Wait a short time for 1793 to digest it.
DCOM2: IN AL,41H ;Get 1793's status.
AND AL,1 ;See if busy.
JNZ DCOM2 ;Yes, keep checking.
IN AL,41H ;Get 1793's status for return
RET
PAGE
SUBTTL Build and return Bios Parameter Block for a diskette.
;
; Build Bios Parameter Blocks.
;
; On entry: ES:DI contains the address of a scratch sector buffer.
; AL = Unit number.
; AH = Current media byte.
;
; On exit: Return a DWORD pointer to the associated BPB
; in the Request packet.
;
BPBS STRUC
DB 13 DUP(?) ;Static request header.
BPB1 DB ? ;Media byte.
BPB2 DW ? ;DWORD transfer address.
DW ?
BPB3 DW ? ;DWORD pointer to BPB
DW ?
BPBS ENDS
GET_BPB:
PUSH ES
PUSH DI
MOV [IOPB.DMASEG],ES
MOV [IOPB.DMAOFF],DI
MOV BYTE PTR[IOPB.SECTOR],1
MOV BYTE PTR[IOPB.SCOUNT],1
MOV BYTE PTR[IOPB.OPCODE],088H
MOV BYTE PTR[IOPB.RETRIES],1
MOV BYTE PTR[IOPB.DRIVE],0
MOV [IOPB.TRACK],0
MOV BYTE PTR[IOPB.HEAD],1
MOV BYTE PTR[IOPB.RETMASK],0DCH
MOV [IOPB.SECLENG],128
MOV BX,ROM_DISKIO
MOV CX,OFFSET IOPB
PUSH CS
POP ES
CALL ROM_CALL ;Read sector zero for information.
PUSH CS
POP DS
POP DI
POP ES
MOV AH,[IOPB.RETCODE]
OR AH,AH
JNZ GET_BP3 ;Disk error, assume old single density.
GET_BP1:MOV AL,ES:[DI.MEDIAID] ;Get diskettes media ID.
MOV SI,OFFSET LSDRIV2
CMP AL,[SI.MEDIAID]
JZ GET_BP4
MOV SI,OFFSET LDDRIV1
CMP AL,[SI.MEDIAID]
JZ GET_BP4
MOV SI,OFFSET LDDRIV2
CMP AL,[SI.MEDIAID]
JZ GET_BP4
GET_BP3:MOV SI,OFFSET LSDRIV1 ;No compares, assume old style for now.
GET_BP4:MOV AL,[SI.MEDIAID]
ADD SI,11 ;Convert to DPB pointer
GET_BP5:LDS BX,[PTRSAV] ;Update I/O data packet.
MOV [BX.BPB1],AL ;Media byte.
MOV [BX.BPB3],SI ;DPB pointer.
MOV [BX.BPB3+2],CS ;Code segment.
OR AH,AH
JNZ GET_BP6
MOV AL,0
JMP EXIT
GET_BP6:MOV AX,7
JMP ERR_EXIT
PAGE
SUBTTL Disk I/O equates.
; Floppy drives
; --------------------------
; Hardware command def.
; --------------------------
;
; Read command = 88 hex.
; Write command = A8 hex.
; Format command = F0 hex.
; Seek command = 1E hex.
; Recal command = 0A hex.
; Set DD mode = 80 hex.
;
; --------------------------
; Status bits:
; --------------------------
;
; Busy = 01 hex.
; (not used) = 02 hex.
; TK0(seek) = 04 hex.
; Lost Data = 04 hex.
; CRC error = 08 hex.
; Seek error = 10 hex.
; Not found = 10 hex.
; Write fault = 20 hex.
; Write protect = 40 hex.
; Not ready = 80 hex.
;
; --------------------------
F_READ EQU 088H ;Floppy read command.
F_WRIT EQU 0A8H ;Floppy write command.
F_FMT EQU 0F0H ;Floppy format command.
F_SEEK EQU 01EH ;Floppy seek command.
F_RECAL EQU 00AH ;Floppy recal. command.
F_DD EQU 080H ;Set Drive double density bit.
PAGE
SUBTTL MSDOS 2.x Disk I/O drivers.
;
; Disk READ/WRITE functions.
;
; On entry:
; AL = Disk I/O driver number
; AH = Media byte.
; ES = Disk transfer segment.
; DI = Disk transfer offset in ES.
; CX = Number of sectors to transfer
; DX = Logical starting sector.
;
; On exit:
; Normal exit through common exit routine.
;
; Abnormal exit through common error routine.
;
DSK_RED:
MOV BX,0DC88H ;Set read mode and Error mask.
JMP SHORT DSK_COM
DSK_WRV:
DSK_WRT:MOV BX,0FCA8H ;Set write mode and Error mask.
DSK_COM:MOV SI,OFFSET LSDRIV1
CMP AH,[SI.MEDIAID]
JE DSK_CO3
MOV SI,OFFSET LSDRIV2
CMP AH,[SI.MEDIAID]
JE DSK_CO3
MOV SI,OFFSET LDDRIV1
CMP AH,[SI.MEDIAID]
JE DSK_CO2
MOV SI,OFFSET LDDRIV2
CMP AH,[SI.MEDIAID]
JE DSK_CO2
MOV AL,7
JMP ERR_EXIT
DSK_CO2:OR AL,F_DD ;Set double density mode.
DSK_CO3:MOV [IOPB.DMASEG],ES ;Setup Buffer segment.
MOV [IOPB.DMAOFF],DI ;Setup buffer offset.
MOV DI,[SI.SECSIZE] ;Get sector size.
MOV [IOPB.SECLENG],DI
MOV [IOPB.RETRIES],1 ;Setup number of retries.
MOV [IOPB.RETMASK],BH ;Operation error mask.
MOV [IOPB.OPCODE],BL ;R/W opcode.
MOV [IOPB.DRIVE],AL ;Drive with density select.
MOV [IOPB.HEAD],1 ;Only one head on floppy drive.
MOV BP,CX ;Save number of sectors to R/W
DSK_CO4:PUSH DX ;Save starting sector.
MOV AX,DX
MOV DX,0 ;32 bit divide coming up.
MOV CX,[SI.SECTRK]
DIV CX ;Get track+head and start sector.
INC DL
MOV [IOPB.SECTOR],DL ;Starting sector.
MOV BL,DL ;Save starting sector for later.
MOV [IOPB.TRACK],AX ;Track to read/write.
MOV AX,[SI.SECTRK] ;Now see how many sectors
INC AL ; we can burst read.
SUB AL,BL ;BL is the starting sector.
MOV AH,0
POP DX ;Retrieve logical sector start.
CMP AX,BP ;See if on last partial track+head.
JG DSK_CO5 ;Yes, on last track+head.
SUB BP,AX ;No, update number of sectors left.
ADD DX,AX ;Update next starting sector.
JMP SHORT DSK_CO6
DSK_CO5:MOV AX,BP ;Only read enough of sector
MOV BP,0 ;to finish buffer and clear # left.
DSK_CO6:MOV [IOPB.SCOUNT],AL
MOV DI,AX ;Save number sectors for later.
MOV BX,ROM_DISKIO
MOV CX,OFFSET IOPB
PUSH CS
POP ES
CALL ROM_CALL ;Do disk operation.
MOV AL,[IOPB.RETCODE] ;Get error code.
OR AL,AL
JNZ DERROR
MOV AX,DI ;Retrieve number of sectors read.
MOV CX,[SI.SECSIZE] ;Number of bytes per sector.
PUSH DX
MUL CX
POP DX
TEST AL,0FH ;Make sure no strange sizes.
JNZ DSK_CO7 ;Illegal sector size found.
MOV CL,4
SHR AX,CL ;Convert number of bytes to para.
ADD AX,[IOPB.DMASEG]
MOV [IOPB.DMASEG],AX
OR BP,BP
JNZ DSK_CO4 ;Still more to do.
MOV AL,0
JMP EXIT ;All done.
DSK_CO7:MOV AL,12
JMP ERR_EXIT
PAGE
SUBTTL Disk Error processing.
;
; Disk error routine.
;
DERROR: LDS BX,CS:[PTRSAV]
MOV [BX.COUNT],0
PUSH CS
POP DS
MOV BL,-1
MOV AH,AL
MOV BH,14 ;Lenght of table.
MOV SI,OFFSET DERRTAB
DERROR2:INC BL ;Increment to next error code.
LODS BYTE PTR CS:[SI]
CMP AH,AL ;See if error code matches disk status.
JZ DERROR3 ;Got the right error, exit.
DEC BH
JNZ DERROR2 ;Keep checking table.
MOV BL,12 ;Set general type of error.
DERROR3:MOV AL,BL ;Now we've got the code.
RET
DERRTAB DB 40H ; 0. Write protect error
DB 00H ; 1. Unknown unit.
DB 80H ; 2. Not ready error.
DB 0FFH ; 3. Unknown command.
DB 08H ; 4. CRC error
DB 00H ; 5. Bad drive request.
DB 02H ; 6. Seek error
DB 00H ; 7. Unknown media.
DB 10H ; 8. Sector not found
DB 00H ; 9. (Not used.)
DB 20H ;10. Write fault.
DB 04H ;11. Read fault.
DB 07H ;12. General type of failure.
PAGE
SUBTTL Common ROM call routine.
;
; Save all registers except CX, BX and AX.
ROMRTN DD 0FE000000H ;Main ROM entry point.
ROM_CALL:
PUSH DI
PUSH SI
PUSH BP
PUSH DX
PUSH ES
CALL CS:DWORD PTR [ROMRTN]
POP ES
POP DX
POP BP
POP SI
POP DI
RET
PAGE
SUBTTL Initalization code and temporary work areas.
;
; Overlayed by MSDOS by SYSINIT.
;
WRKSTK LABEL WORD
DB 100 DUP (?)
HWINIT: XOR BP,BP
MOV SS,BP
MOV SP,OFFSET WRKSTK+98 ;Some nice area for stack.
PUSH CS
POP ES
MOV BX,ROM_INIT
CALL ROM_CALL
MOV AH,0
MOV MCON,AX
MOV AX,SEG SYSINIT
MOV DS,AX
ASSUME DS:SEG SYSINIT
MOV AX,CS
ADD AX,BIOSIZS
MOV DS:[CURRENT_DOS_LOCATION],AX
MOV DS:[MEMORY_SIZE],MAX_MEM
MOV AX,CS
MOV WORD PTR DS:[DEVICE_LIST+2],AX
MOV WORD PTR DS:[DEVICE_LIST],OFFSET DEVSTART
MOV AX,CS
ADD AX,((OFFSET WRKSTK - OFFSET INIT)+50) /16
MOV DS:[FINAL_DOS_LOCATION],AX
JMP SYSINIT
DOSSPOT LABEL WORD
CODE ENDS
END