; ============================================================================
;
; MicroDOS - Int 21h services
;
; ============================================================================
; ------------- Table of Int 21h functions
Int21Fnc: dw Int2100 ; 00h terminate program
dw Int2101 ; 01h get char. from STDIN with echo
dw Int2102 ; 02h put character to STDOUT
dw Int2103 ; 03h get character from STDAUX
dw Int2104 ; 04h output character to STDAUX
dw Int2105 ; 05h output character to STDPRN
dw Int2106 ; 06h direct STDIO - kbd to screen
dw Int2107 ; 07h char from STDIO, no echo
dw Int2108 ; 08h char from STDIO, no echo, ^C
dw Int2109 ; 09h display a string to STDOUT
dw Int210A ; 0Ah buffered keyboard input
dw Int210B ; 0Bh check STDIN status
dw Int210C ; 0Ch clear+invoke keyboard function
dw Int210D ; 0Dh flush all disk buffers
dw Int210E ; 0Eh select disk
dw Int210F ; 0Fh open file with FCB
dw Int2110 ; 10h close file opened with FCB
dw Int2111 ; 11h search for first file entry
dw Int2112 ; 12h search for next file entry
dw Int2113 ; 13h delete file specified by FCB
dw Int2114 ; 14h sequential read from file FCB
dw Int2115 ; 15h sequential write to file FCB
dw Int2116 ; 16h find or create firectory entry
dw Int2117 ; 17h rename file FCB
dw Int2118 ; 18h unknown
dw Int2119 ; 19h return current disk drive
dw Int211A ; 1Ah set disk transfer area (DTA)
dw Int211B ; 1Bh get current disk drive FAT
dw Int211C ; 1Ch get disk FAT for any drive
dw Int211D ; 1Dh unknown
dw Int211E ; 1Eh unknown
dw Int211F ; 1Fh read DOS disk block
dw Int2120 ; 20h unknown
dw Int2121 ; 21h random read from file FCB
dw Int2122 ; 22h random write to file FCB
dw Int2123 ; 23h return number of records in FCB
dw Int2124 ; 24h set file record size FCB
dw Int2125 ; 25h set interrupt vector
dw Int2126 ; 26h create new PSP
dw Int2127 ; 27h random file block read from FCB
dw Int2128 ; 28h random file block write to FCB
dw Int2129 ; 29h parse the command line
dw Int212A ; 2Ah get the system date
dw Int212B ; 2Bh set the system date
dw Int212C ; 2Ch get the system time
dw Int212D ; 2Dh set the system time
Int21Num EQU ($-Int21Fnc)/2 ; number of Int 21h functions
; ----------------------------------------------------------------------------
; Unsupported Int 21h functions
; ----------------------------------------------------------------------------
Int2105:
Int210E:
Int2111:
Int2112:
Int2118:
Int2119:
Int211A:
Int211B:
Int211C:
Int211D:
Int211E:
Int211F:
Int2120:
Int2121:
Int2122:
Int2123:
Int2124:
Int2125:
Int2126:
Int2127:
Int2128:
Int2129:
mov al,0 ; AL <- 0 (unsupported function)
ret
; ----------------------------------------------------------------------------
; Int 20h service (terminate program)
; ----------------------------------------------------------------------------
MyInt20: mov ah,0 ; AH <- 0 function code
jmp short MyInt211
; ----------------------------------------------------------------------------
; Int 21h service
; ----------------------------------------------------------------------------
; ------------- Register offsets of Int 21h service (in stack)
REG21F EQU 22 ; Int 21h flaags register in stack
REG21CS EQU 20 ; Int 21h CS register in stack
REG21IP EQU 18 ; Int 21h IP register in stack
REG21ES EQU 16 ; Int 21h ES register in stack
REG21DS EQU 14 ; Int 21h DS register in stack
REG21BP EQU 12 ; Int 21h BP register in stack
REG21DI EQU 10 ; Int 21h DI register in stack
REG21SI EQU 8 ; Int 21h SI register in stack
REG21DX EQU 6 ; Int 21h DX register in stack
REG21CX EQU 4 ; Int 21h CX register in stack
REG21BX EQU 2 ; Int 21h BX register in stack
REG21AX EQU 0 ; Int 21h AX register in stack
; ------------- Check function number
MyInt21: cmp ah,Int21Num ; check function number
jb MyInt211 ; function number is OK
MyInt210: mov al,0 ; error code - unsupported function
MyInt23:
MyInt24:
iret
; ----------------------------------------------------------------------------
; Old style (CALL 5) DOS service
; ----------------------------------------------------------------------------
; - user call this with "call near 5" instruction (only in COM program)
; - PSP:5 addres contains "call far 0000:00c0h" instruction
; - address 0000:00c0h (=address of int 30h) contains "jump far" instruction
; ----------------------------------------------------------------------------
; ------------- Store return address
OldDOS: pop ax ; destroy offset of return address
pop ax ; AX <- segment of PSP
pop word [cs:OldStack]; store offset of return address
; ------------- Simulate Int 21h call
pushf ; push flags to simulate Int 21h
push ax ; push segment of PSP
push word [cs:OldStack]; restore offset of return address
cli ; disable interrupts
; ------------- Check function number
cmp cl,24h ; check maximal number of function
ja MyInt210 ; invalid function number
mov ah,cl ; AH <- function code
; ------------- Push registers (at this point interrupt is disabled)
MyInt211: call PushAll ; push all registers
; ------------- Push DS:BX registers
mov [cs:PushDSBX+2],ds ; push DS
push cs ; push CS
pop ds ; DS <- CS
mov [PushDSBX],bx ; push BX
; ------------- Push stack pointer
mov [OldStack],sp ; push SP
mov [OldStack+2],ss ; push SS
; ------------- Init Int 21h stack
mov sp,cs ; SP <- CS
mov ss,sp ; SS <- CS
mov sp,Int21Stack1 ; stack for Int 21h
; ------------- Console functions use own internal stack
or ah,ah ; function 00h (program end)
jz MyInt212 ; internal stack 1
cmp ah,0Ch ; character functions ?
ja MyInt212 ; no character functions
mov sp,Int21Stack2 ; stack for console functions
MyInt212: sti ; enable interrupts
; ------------- Prepare return address from service (simulates CALL NEAR)
mov bx,MyInt21Ret ; BX <- return address
push bx ; prepare return address
; ------------- Prepare jump address of service
mov bh,0 ; BH <- 0
mov bl,ah ; BL <- function code
shl bx,1 ; BX = function code * 2
push word [Int21Fnc+bx] ; push address of service
; ------------- Pop DS:BX registers and jump to the service
lds bx,[PushDSBX] ; pop DS:BX registers
ret ; junp to the service
; ------------- Return from service (here is AL = return code)
MyInt21Ret: cli ; disable interrupts
; ------------- Return old stack pointer
mov sp,[cs:OldStack]; SP <- old SP
mov ss,[cs:OldStack+2]; SS <- old SS
; ------------- Set AL register (return code)
mov bp,sp ; BP <- stack pointer
mov [bp+REG21AX],al ; store AL return code
; ------------- Pop registers
call PopAll ; pop all registers
iret
; ----------------------------------------------------------------------------
; Get register pointer
; ----------------------------------------------------------------------------
; OUTPUT: DS:SI = registers in call stack (offset RE21AX...REG21F)
; ----------------------------------------------------------------------------
GetReg: lds si,[cs:OldStack] ; DS:DI <- old stack
ret
; ----------------------------------------------------------------------------
; Set output register AX
; ----------------------------------------------------------------------------
; INPUT: AX = output register AX
; ----------------------------------------------------------------------------
SetRegAX: push ds ; push DS
push si ; push SI
call GetReg ; get register pointer
mov [si+REG21AX],ax ; store output register AX
pop si ; pop SI
pop ds ; pop DS
ret
; ----------------------------------------------------------------------------
; Set output register BX
; ----------------------------------------------------------------------------
; INPUT: BX = output register BX
; ----------------------------------------------------------------------------
SetRegBX: push ds ; push DS
push si ; push SI
call GetReg ; get register pointer
mov [si+REG21BX],bx ; store output register BX
pop si ; pop SI
pop ds ; pop DS
ret
; ----------------------------------------------------------------------------
; Set output register CX
; ----------------------------------------------------------------------------
; INPUT: CX = output register CX
; ----------------------------------------------------------------------------
SetRegCX: push ds ; push DS
push si ; push SI
call GetReg ; get register pointer
mov [si+REG21CX],cx ; store output register CX
pop si ; pop SI
pop ds ; pop DS
ret
; ----------------------------------------------------------------------------
; Set output register DX
; ----------------------------------------------------------------------------
; INPUT: DX = output register DX
; ----------------------------------------------------------------------------
SetRegDX: push ds ; push DS
push si ; push SI
call GetReg ; get register pointer
mov [si+REG21DX],dx ; store output register DX
pop si ; pop SI
pop ds ; pop DS
ret
; ----------------------------------------------------------------------------
; Set DOS result error flag (and AH <- 0)
; ----------------------------------------------------------------------------
DOSError: mov ah,0 ; AH <- 0
push ds ; push DS
push si ; push SI
call GetReg ; get register pointer
or byte [si+REG21F],1 ; set error flag
pop si ; pop SI
pop ds ; pop DS
ret
; ----------------------------------------------------------------------------
; Reset DOS result error flag
; ----------------------------------------------------------------------------
DOSOK: push ds ; push DS
push si ; push SI
call GetReg ; get register pointer
and byte [si+REG21F],~1 ; reset error flag
pop si ; pop SI
pop ds ; pop DS
ret
; ----------------------------------------------------------------------------
; Push all registers
; ----------------------------------------------------------------------------
PushAll: pop word [cs:PushAllRet] ; store return address
push es ; 16: push ES
push ds ; 14: push DS
push bp ; 12: push BP
push di ; 10: push DI
push si ; 8: push SI
push dx ; 6: push DX
push cx ; 4: push CX
push bx ; 2: push BX
push ax ; 0: push AX
PushAll2: jmp [cs:PushAllRet] ; return
; ----------------------------------------------------------------------------
; Pop all registers
; ----------------------------------------------------------------------------
PopAll: pop word [cs:PushAllRet] ; store return address
pop ax ; pop AX
pop bx ; pop BX
pop cx ; pop CX
pop dx ; pop DX
pop si ; pop SI
pop di ; pop DI
pop bp ; pop BP
pop ds ; pop DS
pop es ; pop ES
jmp short PushAll2 ; return
; ----------------------------------------------------------------------------
; Push registers AX, BX, CX, DX, DI
; ----------------------------------------------------------------------------
PushABCDI: pop word [cs:PushAllRet] ; store return address
push ax ; push AX
push bx ; push BX
push cx ; push CX
push dx ; push DX
push di ; push DI
PushABCDI2: jmp [cs:PushAllRet] ; return
; ----------------------------------------------------------------------------
; Pop registers AX, BX, CX, DX, DI
; ----------------------------------------------------------------------------
PopABCDI: pop word [cs:PushAllRet] ; store return address
pop di ; pop DI
pop dx ; pop DX
pop cx ; pop CX
pop bx ; pop BX
pop ax ; pop AX
jmp short PushABCDI2; return
; ----------------------------------------------------------------------------
; Data
; ----------------------------------------------------------------------------
PushAllRet: dw 0 ; push return address
PushDSBX: dd 0 ; push DS:BX in 21h call
OldStack: dd 0 ; push old stack pointer
|