home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
sysutl
/
bios_asm.arc
/
BIOS.ASM
next >
Wrap
Assembly Source File
|
1988-01-18
|
179KB
|
3,798 lines
Date: Wed, 13 Jan 88 04:26 PST
From: <MULTI%TRIUMFCL.BITNET@CUNYVM.CUNY.EDU>
Subject: BIOS.ASM update INFO-IBMPC librarys
To: hicks@walker-emh.arpa
Page 80,132
Title BIOS - For Intel 8088 or NEC "V20" turbo motherboards. Use MASM 4.0
;
; This bios will work on IBM-PC/xt and many other compatibles that share a
; similar design concept. You do not need to have a turbo motherboard to
; use this bios, but if you do, then use the following key sequence
; CTRL ALT -
; to toggle the computer speed between fast and slow (=IBM compatible)
;
; This BIOS can produce the following error messages at IPL time
;
ER_BIOS equ 01h ; Bad ROM bios checksum, patch last byte
ER_RAM equ 02h ; Bad RAM in main memory, replace
ER_CRT equ 04h ; Bad RAM in video card, replace
ER_MEM equ 10h ; Bad RAM in vector area, replace
ER_ROM equ 20h ; Bad ROM in expansion area, bad checksum
;
; The last two bytes have to be patched with DEBUG as follows
;
; FFFF 00.xx ( avoid ER_BIOS on bootstrap ) --------------------
; FFFE 00.FE ( leaves IBM-PC/xt signature ) ----------------- |
; | |
; where "xx" results in a zero checksum for the whole BIOS rom, for ex | |
; | |
; masm BIOS; ( Assemble BIOS source code) | |
; link BIOS; ( Link the BIOS object code) | |
; debug BIOS.EXE ( Exe2bin BIOS binary code) | |
; -nBIOS.BIN ( Name of the output binary) | |
; -eCS:FFFE ( Opens BIOS signature byte) | |
; .FE ( Leave IBM-PC/xt signature) <-- |
; -eCS:FFFF ( Opens BIOS checksum byte) |
;; -------> .DC ( Force ROM checksum = zero) <-----
;; -rBX ( Opens hi order byte count)
;; :0 ( ... must be 0 bytes long)
;; -rCX ( Opens lo order byte count)
;; :2000 ( ... BIOS 2000 bytes long)
;; -wCS:E000 ( Output to BIOS.BIN file)
;; -q
;;
;; You must correct the checksum by manually patching the last byte so as the
;; the entire 2764-2 eprom sums to zero. I wish DEBUG could checksum blocks.
;
; ************************Miscellaneous definitions************************
; *
MAX_MEMORY =704 ; Maximum kilobytes of memory allowed *
;SLOW_FLOPPY =1 ; Define to run floppy always at 4.77 mHz *
; *
; ************************Miscellaneous definitions************************
;
entry macro x
pad =BANNER - $ + x - 0E000h
if pad LT 0
.err
%out 'No room for ENTRY point'
endif
if pad GT 0
db pad DUP(0FFh)
endif
endm
;
jmpf macro x,y
db 0EAh;
dw y,x
endm
;
retf macro x
ifb <x>
db 0CBh
else
db 0CAh
dw x
endif
endm
;
LF equ 0Ah
CR equ 0Dh
;
.SALL ; Suppress Macro Expansions
.LFCOND ; List False Conditionals
;
ASSUME DS:code, SS:code, CS:code, ES:code
data SEGMENT at 40h ; IBM compatible data structure
dw 4 dup(?) ; 40:00 ; RS232 com. ports - up to four
dw 4 dup(?) ; 40:08 ; Printer ports - up to four
dw ? ; 40:10 ; Equipment present word
; + (1 iff floppies) * 1.
; + (# 64K sys ram ) * 4.
; + (init crt mode ) * 16.
; + (# of floppies ) * 64.
; + (# serial ports) * 512.
; + (1 iff toy port) * 4096.
; + (# parallel LPT) * 16384.
db ? ; 40:12 ; MFG test flags, unused by us
dw ? ; 40:13 ; Memory size, kilobytes
db ? ; 40:15 ; IPL errors<-table/scratchpad
db ? ; ...unused
;---------------[Keyboard data area]------------;
db ?,? ; 40:17 ; Shift/Alt/etc. keyboard flags
db ? ; 40:19 ; Alt-KEYPAD char. goes here
dw ? ; 40:1A ; --> keyboard buffer head
dw ? ; 40:1C ; --> keyboard buffer tail
dw 16 dup(?) ; 40:1E ; Keyboard Buffer (Scan,Value)
;---------------[Diskette data area]------------;
db ? ; 40:3E ; Drive Calibration bits 0 - 3
db ? ; 40:3F ; Drive Motor(s) on 0-3,7=write
db ? ; 40:40 ; Ticks (18/sec) til motor off
db ? ; 40:41 ; Floppy return code stat byte
; 1 = bad ic 765 command req.
; 2 = address mark not found
; 3 = write to protected disk
; 4 = sector not found
; 8 = data late (DMA overrun)
; 9 = DMA failed 64K page end
; 16 = bad CRC on floppy read
; 32 = bad NEC 765 controller
; 64 = seek operation failed
;128 = disk drive timed out
db 7 dup(?) ; 40:42 ; Status bytes from NEC 765
;---------------[Video display area]------------;
db ? ; 40:49 ; Current CRT mode (software)
; 0 = 40 x 25 text (no color)
; 1 = 40 x 25 text (16 color)
; 2 = 80 x 25 text (no color)
; 3 = 80 x 25 text (16 color)
; 4 = 320 x 200 grafix 4 color
; 5 = 320 x 200 grafix 0 color
; 6 = 640 x 200 grafix 0 color
; 7 = 80 x 25 text (mono card)
dw ? ; 40:4A ; Columns on CRT screen
dw ? ; 40:4C ; Bytes in the regen region
dw ? ; 40:4E ; Byte offset in regen region
dw 8 dup(?) ; 40:50 ; Cursor pos for up to 8 pages
dw ? ; 40:60 ; Current cursor mode setting
db ? ; 40:62 ; Current page on display
dw ? ; 40:63 ; Base addres (B000h or B800h)
db ? ; 40:65 ; ic 6845 mode reg. (hardware)
db ? ; 40:66 ; Current CGA palette
;---------------[Used to setup ROM]-------------;
dw ?,? ; 40:67 ; Eprom base Offset,Segment
db ? ; 40:6B ; Last spurious interrupt IRQ
;---------------[Timer data area]---------------;
dw ? ; 40:6C ; Ticks since midnite (lo)
dw ? ; 40:6E ; Ticks since midnite (hi)
db ? ; 40:70 ; Non-zero if new day
;---------------[System data area]--------------;
db ? ; 40:71 ; Sign bit set iff break
dw ? ; 40:72 ; Warm boot iff 1234h value
;---------------[Hard disk scratchpad]----------;
dw ?,? ; 40:74 ;
;---------------[Timout areas/PRT/LPT]----------;
db 4 dup(?) ; 40:78 ; Ticks for LPT 1-4 timeouts
db 4 dup(?) ; 40:7C ; Ticks for COM 1-4 timeouts
;---------------[Keyboard buf start/nd]---------;
dw ? ; 40:80 ; Contains 1Eh, buffer start
dw ? ; 40:82 ; Contains 3Eh, buffer end
data ENDS
dosdir SEGMENT at 50h ; Boot disk directory from IPL
xerox label byte ; 0 if Print Screen idle
; 1 if PrtSc xeroxing screen
;255 if PrtSc error in xerox
; ...non-grafix PrtSc in bios
db 200h dup(?) ; PC-DOS bootstrap procedure
; ...IBMBIO.COM buffers the
; ...directory of the boot
; ...device here at IPL time
; ...when locating the guts
; ...of the operating system
; ...filename "IBMDOS.COM"
dosdir ends
dosseg SEGMENT at 70h ; "Kernel" of PC-DOS op sys
;IBMBIO.COM file loaded by boot block. Device Drivers/Bootstrap. CONTIGUOUS<---
;IBMDOS.COM operating system nucleus immediately follows IBMBIO.COM and |
; doesn`t have to be contiguous. The IBMDOS operating system nucleus |
; binary image is loaded by transient code in IBMBIO binary image |
dosseg ends ; |
iplseg SEGMENT at 0h ; Segment for boot block |
;The following boot block is loaded with 512. bytes on the first sector of |
;the bootable device by code resident in the ROM-resident bios. Control is |
;then transferred to the first word 0000:7C00 of the disk-resident bootstrap |
ORG 07C00h ; ..offset for boot block |
boot db 200h dup(?) ; ..start disk resident boot--
iplseg ends
code SEGMENT
ORG 0E000h
BANNER db ' Generic Turbo XT Bios 1987',CR,LF
db ' for 8088 or V20 cpu',CR,LF
db ' (c)Anonymous',CR,LF
db LF,0
LPTRS dw 03BCh,0378h,0278h ; Possible line printer ports
ENTRY 0E05Bh ; IBM restart entry point
COLD: MOV AX,40h ; Entered by POWER_ON/RESET
MOV DS,AX
MOV Word ptr DS:72h,0 ; Show data areas not init
WARM: CLI ; Begin FLAG test of CPU
XOR AX,AX
JB HALT
JO HALT
JS HALT
JNZ HALT
JPO HALT
ADD AX,1
JZ HALT
JPE HALT
SUB AX,8002h
JS HALT
INC AX
JNO HALT
SHL AX,1
JNB HALT
JNZ HALT
SHL AX,1
JB HALT
MOV BX,0101010101010101b ; Begin REGISTER test of CPU
CPUTST: MOV BP,BX
MOV CX,BP
MOV SP,CX
MOV DX,SP
MOV SS,DX
MOV SI,SS
MOV ES,SI
MOV DI,ES
MOV DS,DI
MOV AX,DS
CMP AX,0101010101010101b
JNZ CPU1
NOT AX
MOV BX,AX
JMP CPUTST
CPU1: XOR AX,1010101010101010b
JZ CPU_OK
HALT: HLT
CPU_OK: CLD
MOV AL,0 ; Prepare to initialize
OUT 0A0h,AL ; ...no NMI interrupts
MOV DX,3D8h ; Load Color Graphic port
OUT DX,AL ; ...no video display
MOV DX,3B8h ; Load Monochrome port
INC AL ; ...no video display
OUT DX,AL ; ...write it out
MOV AL,10011001b ; Program 8255 PIA chip
OUT 63h,AL ; ...Ports A & C, inputs
MOV AL,10100101b ; Set (non)turbo mode
OUT 61h,AL ; ...on main board
MOV AL,01010100b ; ic 8253 inits memory refresh
OUT 43h,AL ; ...chan 1 pulses ic 8237 to
MOV AL,12h ; ...dma every 12h clock ticks
OUT 41h,AL ; ...64K done in 1 millisecond
MOV AL,01000000b ; Latch value 12h in 8253 clock
OUT 43h,AL ; ...chip channel 1 counter
IC8237: MOV AL,0 ; Do some initialization
OUT 81h,AL ; ...dma page reg, chan 2
OUT 82h,AL ; ...dma page reg, chan 3
OUT 83h,AL ; ...dma page reg, chan 0,1
OUT 0Dh,AL ; Stop DMA on 8237 chip
MOV AL,01011000b ; Refresh auto-init dummy read
OUT 0Bh,AL ; ...on channel 0 of DMA chip
MOV AL,01000001b ; Block verify
OUT 0Bh,AL ; ...on channel 1 of DMA chip
MOV AL,01000010b ; Block verify
OUT 0Bh,AL ; ...on channel 2 of DMA chip
MOV AL,01000011b ; Block verify
OUT 0Bh,AL ; ...on channel 3 of DMA chip
MOV AL,0FFh ; Refresh byte count
OUT 1,AL ; ...send lo order
OUT 1,AL ; ...send hi order
MOV AL,0 ; Initialize 8237 command reg
OUT 8,AL ; ...with zero
OUT 0Ah,AL ; Enable DMA on all channels
MOV AL,00110110b ; Set up 8253 timer chip
OUT 43h,AL ; ...chan 0 is time of day
MOV AL,0 ; Request a divide by
OUT 40h,AL ; ...65536 decimal
OUT 40h,AL ; ...0000h or 18.2 tick/sec
MOV DX,213h ; Expansion unit port
MOV AL,1 ; ...enable it
OUT DX,AL ; ...do the enable
MOV AX,40h ; Get bios impure segment
MOV DS,AX ; ...into DS register
MOV SI,DS:72h ; Save reset flag in SI reg
XOR AX,AX ; ...cause memory check
MOV BP,AX ; ...will clobber the flag
MOV BX,AX ; Start at segment 0000h
MOV DX,55AAh ; ...get pattern
CLD ; Strings auto-increment
MEMSIZ: XOR DI,DI ; Location XXXX:0
MOV ES,BX ; ...load segment
MOV ES:[DI],DX ; ...write pattern
CMP DX,ES:[DI] ; ...compare
JNZ MEM_ND ; ...failed, memory end
MOV CX,2000h ; Else zero 16 kilobytes
REPZ STOSW ; ...with instruction
ADD BH,4 ; ...get next 16K bytes
ifdef MAX_MEMORY
CMP BH,MAX_MEMORY SHR 2 ; Found max legal user ram?
else
CMP BH,0A0h ; Found max legal IBM ram?
endif
JNZ MEMSIZ ; ...no, then check more
MEM_ND: MOV DS:72h,SI ; Save pointer
XOR AX,AX
MOV ES,AX ; ES = vector segment
MOV AX,80h
MOV SS,AX ; Set up temporary stack at
MOV SP,100h ; 0080:0100 for memory check
PUSH BP
PUSH BX
MOV BP,2
CALL MEMTST ; Memory check ES:0 - ES:0400
POP AX
MOV CL,6
SHR AX,CL
MOV DS:13h,AX
POP AX
JNB MEM_01
OR AL,ER_MEM ; Show vector area bad
MEM_01: MOV DS:15h,AL ; Save IPL error code
XOR AX,AX
PUSH AX
PUSH AX
PUSH AX
PUSH AX
PUSH AX
MOV AX,30h ; Set up IBM-compatible stack
MOV SS,AX ; ...segment 0030h
MOV SP,100h ; ...offset 0100h
PUSH DS
MOV BX,0E000h ; Check BIOS eprom
PUSH CS
POP DS ; ...at F000:E000
MOV AH,1
CALL CHKSUM ; ...for valid checksum
POP DS ; ...restore impure<-DS
JZ IC8259
OR Byte ptr DS:15h,ER_BIOS ; Checksum error BIOS eprom
IC8259: CLI ; Init interrupt controller
MOV AL,13h
OUT 20h,AL
MOV AL,8
OUT 21h,AL
MOV AL,9
OUT 21h,AL
MOV AL,0FFh
OUT 21h,AL
PUSH DS
XOR AX,AX ; 8 nonsense vectors begin table
MOV ES,AX ; ...at segment 0000h
PUSH CS
POP DS
MOV CX,8 ; Vectors 00h - 07h unused
XOR DI,DI ; ...we start at vec 00h
LO_VEC: MOV AX,offset IGNORE ; Nonsense interrupt from RSX
STOSW
MOV AX,CS ; ...bios ROM segment
STOSW
LOOP LO_VEC
MOV SI,offset VECTORS ; SI --> Vector address table
MOV CX,18h ; ... vectors 08h - 1Fh busy
HI_VEC: MOVSW ; Get INTERRUPT bios ROM offset
MOV AX,CS
STOSW ; ...INTERRUPT bios ROM segment
LOOP HI_VEC
MOV AX,0F600h ; AX --> Rom basic segment
MOV DS,AX ; DS --> " " "
XOR BX,BX ; BX = Rom basic offset
MOV AH,4 ; Four basic roms to check
MOV BP,SP ; Save the stack pointer
PUSH CS ; ...push code segment
MOV DX,offset SKIP ; Save the code offset
PUSH DX ; ...for RAM_PATCH subroutine
MOV DX,0EA90h ; Mov DX,'NOP,JMP_FAR'
PUSH DX ; ...save it on stack
MOV DX,0178Bh ; Mov DX,'MOV DX,[BX]'
PUSH DX ; ...save it on stack
PUSH SS ; Save stack segment
MOV DX,SP ; ...get the stack offset
ADD DX,02h ; ...calculate xfer addr.
PUSH DX ; ...save it on the stack
;
RETF ; Test for BASIC rom
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; MOV DX,[BX] ; Executes off the stack ;
; JMPF 0F000h,SKIP ; ...in RAM space ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SKIP: MOV SP,BP ; Restore the stack pointer
CMP DL,DH ; ...compare 1st and 2nd byte
JE kosher ; ...perfection. No piracy
B_ROM: CALL CHKSUM ; Scan for BASIC roms
JNZ kosher ; ...bad basic rom
DEC AH ; Continue
JNZ B_ROM ; ...yes, more
POP DS ; Else valid basic
MOV DI,60h ; ...install basic
XOR AX,AX ; ...zero BASIC interrupt
STOSW ; ...offset
MOV AX,0F600h ; ...F600h BASIC interrupt
STOSW ; ...segment
PUSH DS
kosher: POP DS ; Setup special low vectors
MOV Word ptr ES:8,offset int_2 ; ...NMI interrupt
MOV Word ptr ES:14h,offset int_5 ; ...print screen interrupt
MOV Word ptr ES:7Ch,0 ; No special graphics chars.
MOV Word ptr ES:7Eh,0 ; ...so zero vector 1Fh
MOV DX,61h
IN AL,DX ; Read machine flags
OR AL,00110000b ; ...clear old parity error
OUT DX,AL ; Write them back to reset
AND AL,11001111b ; ...enable parity
OUT DX,AL ; Write back, parity enabled
MOV AL,80h ; ...allow NMI interrupts
OUT 0A0h,AL
MOV AX,0000000000110000b ; Assume monochrome video
MOV DS:10h,AX ; ...card has been installed
INT 10h ; ...initialize if present
MOV AX,0000000000100000b ; Assume color/graphics video
MOV DS:10h,AX ; ...card has been installed
INT 10h ; ...initialize if present
IN AL,62h ; Get memory size (64K bytes)
AND AL,00001111b ; ...in bits 2,3 lo nibble
MOV AH,AL ; Save memory size nibble
MOV AL,10101101b
OUT 61h,AL
IN AL,62h ; Get no. of floppies (0-3)
MOV CL,4 ; ...and init. video mode
SHL AL,CL ; ...shift in hi nibble
OR AL,AH
MOV AH,0
MOV DS:10h,AX ; Start building Equipment Flag
AND AL,00110000b ; ...if video card, mode set
JNZ LE232 ; ...found video interface
MOV AX,offset DUMMY ; No hardware, DUMMY: becomes
MOV ES:40h,AX ; ...INT_10 video service
JMP short LE235
LE232: CALL V_INIT ; Setup video
LE235: MOV AL,00001000b ; Read low switches
OUT 61h,AL
MOV CX,2956h
WAIT_1: LOOP WAIT_1
MOV AL,11001000b ; Keyboard acknowledge
OUT 61h,AL ; ...send the request
XOR AL,10000000b ; Toggle to enable
OUT 61h,AL ; ...send key enable
MOV AX,1Eh ; Offset to buffer start
MOV DS:1Ah,AX ; Buffer head pointer
MOV DS:1Ch,AX ; Buffer tail pointer
MOV DS:80h,AX ; Buffer start
ADD AX,20h ; ...size
MOV DS:82h,AX ; Buffer end
JMP short V_CONT
FAO: MOV DL,AL ; Formatted ascii output
FAO_1: MOV AX,BX ; Get position for
CALL LOCATE ; ...cursor routine
PUSH SI ; Get string address
CALL PRINT ; ...print string
MOV AX,ES:[BP+0] ; Get port # to print
CALL BIGNUM ; ...four digits
POP SI ; Restore string address
INC BP ; ...Address of port
INC BP ; ...is two bytes long
INC BH ; ...down one line
DEC DL ; Decrement device count
JNZ FAO_1 ; ...back for more
RET
K_BYTE: CLC ; Say no error
MOV AL,DL ; ...size "checked"
INC AL ; ...show more
DAA
MOV DL,AL
JNB KBY_01
MOV AL,DH ; ...do carry
ADC AL,0
DAA
MOV DH,AL
KBY_01: MOV AL,DH
CALL DIGIT ; Print hex digit
MOV AL,DL
MOV CL,4
ROR AL,CL
CALL DIGIT ; Print hex digit
MOV AL,DL
CALL DIGIT ; Print hex digit
RET
TIMER: MOV DX,241h ; Check for timer #2 port
CLI
IN AL,DX ; ..read BCD seconds/100
STI
CMP AL,99h ; Are BCD digits in range?
JBE SER_01 ; ...yes, port exists
;
MOV DX,341h ; Check for timer #1 port
CLI
IN AL,DX ; ..read BCD seconds/100
STI
CMP AL,99h ; Are BCD digits in range?
JBE SER_01 ; ...yes, port exists
;
STC ; No hardware, ports 0FFh
RET
SER_01: CLC ; Found timer(s) answering
RET
V_CONT: MOV BP,4 ; Assume monochrome, 4K memory
MOV BX,0B000h ; ...segment in BX
MOV AL,DS:49h ; Get the video mode
CMP AL,7 ; ...was it mono?
JZ M_SEG ; ...yes, skip
MOV BP,10h ; Else CGA, has 16K memory
MOV BX,0B800h ; ...segment in BX
M_SEG: PUSH BX ; Load video seg in ES
POP ES
MOV AL,DS:65h ; Get CRT hardware mode
AND AL,11110111b ; ...disable video
MOV DX,DS:63h ; Get 6845 index port
ADD DX,4 ; ...add offset for
OUT DX,AL ; 6845 controller port
CRTRAM: CALL MEMTST ; Memory check ES:0 - ES:0400
DEC BP
JNZ CRTRAM ; Loop until CRT RAM checked
JNB LE2F5
OR Byte ptr DS:15h,ER_CRT ; Set CRT RAM error in status
LE2F5: CALL V_INIT
MOV AX,1414h ; Time-out value seconds
MOV DS:78h,AX ; ...LPT1
MOV DS:7Ah,AX ; ...LPT2
MOV AX,101h ; Time-out value seconds
MOV DS:7Ch,AX ; ...COM1
MOV DS:7Eh,AX ; ...COM2
MOV SI,offset LPTRS ; SI --> LPTR port table
XOR DI,DI ; ...offset into data seg
MOV CX,3 ; ...number of printers
NXTPRT: MOV DX,CS:[SI] ; Get LPTR port
MOV AL,10101010b ; ...write value
OUT DX,AL ; ...to the LPTR
MOV AL,11111111b ; Dummy data value
OUT 0C0h,AL ; ...on the bus
IN AL,DX ; Read code back
CMP AL,10101010b ; ...check code
JNZ NO_LPT ; ...no printer found
MOV [DI+8],DX ; Save printer port
INC DI
INC DI
NO_LPT: INC SI
INC SI
LOOP NXTPRT
MOV AX,DI ; Number of printers * 2
MOV CL,3 ; ...get shift count
ROR AL,CL ; ...divide by eight
MOV DS:11h,AL ; ...save in equip. flag
XOR DI,DI ; com port(s) at 40:00 (hex)
COM_1: MOV DX,3FBh ; COM #1 line control reg.
MOV AL,00011010b ; ...7 bits, even parity
OUT DX,AL ; Reset COM #1 line cont. reg
MOV AL,11111111b ; ...noise pattern
OUT 0C0h,AL ; Write pattern on data buss
IN AL,DX ; ...read result from COM #1
CMP AL,00011010b ; Check if serial port exists
JNZ COM_2 ; ...skip if no COM #1 port
MOV Word ptr [DI],3F8h ; Else save port # in impure
INC DI ; ...potential COM #2 port
INC DI ; ...is at 40:02 (hex)
COM_2: MOV DX,2FBh ; COM #2 line control reg
MOV AL,00011010b ; ...7 bits, even parity
OUT DX,AL ; Reset COM #2 line cont. reg
MOV AL,11111111b ; ...noise pattern
OUT 0C0h,AL ; Write pattern on data buss
IN AL,DX ; ...read results from COM #2
CMP AL,00011010b ; Check if serial port exists
JNZ COM_CT ; ...skip if no COM #2 port
MOV word ptr [DI],2F8h ; Else save port # in impure
INC DI ; ...total number of serial
INC DI ; ...interfaces times two
COM_CT: MOV AX,DI ; Get serial interface count
OR DS:11h,AL ; ...equip. flag
MOV DX,201h
IN AL,DX ; Read game controller
TEST AL,0Fh ; ...anything there?
JNZ NOGAME ; ...yes, invalid
OR Byte ptr DS:11h,00010000b ; Else game port present
NOGAME: MOV DX,0C000h ; ROM segment start
PUSH DS
FNDROM: MOV DS,DX ; Load ROM segment
XOR BX,BX ; ...ID offset
MOV AX,[BX] ; Read the ROM id
CMP AX,0AA55h
JNZ NXTROM ; ...not valid ROM
MOV AX,40h
MOV ES,AX
MOV AH,0
MOV AL,[BX+2] ; Get ROM size (bytes * 512)
MOV CL,5
SHL AX,CL ; Now ROM size in segments
ADD DX,AX ; ...add base segment
MOV CL,4
SHL AX,CL ; ROM address in bytes
MOV CX,AX ; ...checksum requires CX
CALL CHK_01 ; Find ROM checksum
JNZ BADROM ; ...bad ROM
PUSH DX
MOV Word ptr ES:67h,3 ; Offset for ROM being setup
MOV ES:69h,DS ; Segment for ROM being setup
CALL Dword ptr ES:67h ; ...call ROM initialization
POP DX
JMP short FND_01
BADROM: OR Byte ptr ES:15h,ER_ROM ; ROM present, bad checksum
NXTROM: ADD DX,80h ; Segment for next ROM
FND_01: CMP DX,0F600h ; End of ROM space
JL FNDROM ; ...no, continue
POP DS
IN AL,21h ; Read ic 8259 interrupt mask
AND AL,10111100b ; ...enable IRQ (0,1,6) ints
OUT 21h,AL ; (tod_clock,key,floppy_disk)
MOV AH,1
MOV CH,0F0h
INT 10h ; Set cursor type
CALL BLANK ; ...clear display
PUSH DS
PUSH CS
POP DS
POP ES
TEST Byte ptr ES:10h,1 ; Floppy disk present?
JZ FND_02 ; ...no
CMP Word ptr ES:72h,1234h ; Bios setup before?
JNZ CONFIG ; ...no
FND_02: JMP RESET ; Else skip memory check
CONFIG: MOV AX,41Ah ; Where to move cursor
MOV SI,offset STUF ; ...equipment message
CALL LOCATE ; ...position cursor
CALL PRINT ; ...and print string
MOV AX,51Bh ; New cursor position
MOV SI,offset STUF_1 ; ...CR/LF
CALL Locate ; ...position cursor
CALL PRINT ; ...and print string
TEST Byte ptr ES:15h,11111111b ; Any error so far?
JZ VALID ; ...no, skip
CALL PRINT ; Print string
MOV AL,ES:15h ; ...get error number
CALL NUMBER ; ...print hex value
CALL PRINT ; ...print prompt
MOV BL,4 ; ...long beep
CALL BEEP
CALL GETCH ; Wait for keypress
PUSH AX ; ...save answer
CALL OUTCHR ; ...echo answer
POP AX ; ...get answer
CMP AL,'Y' ; Was it "Y"
JZ FND_02 ; ...ok, continue
CMP AL,'y' ; Was it "y"
JZ FND_02 ; ...ok, continue
JMPF 0F000h,COLD ; Else cold reset
VALID: MOV SI,offset STUF_2 ; No errors found, load banner
CALL PRINT ; ...and print string
MOV AX,81Eh ; Where to move cursor
CALL LOCATE ; ...position cursor
CALL PRINT ; ...and print string
MOV AX,91Ch ; Where to move cursor
CALL LOCATE ; ...position cursor
MOV BL,17h ; Character count
FENCE: MOV AL,'-' ; Load ascii minus
CALL OUTCHR ; ...and print it
DEC BL
JNZ FENCE
MOV AX,0A21h ; Where to move cursor
CALL LOCATE ; ...position cursor
MOV AL,ES:49h ; Get CRT mode
CMP AL,7
JZ FEN_01 ; ...monochrome
MOV SI,offset STUF_3 ; ...color/graphics
FEN_01: CALL PRINT ; Print the string
MOV BX,0B21h
MOV AL,ES:11h ; Get equipment byte
PUSH AX
MOV CL,6
ROR AL,CL
AND AL,3 ; Number of printers
JZ FEN_02
MOV BP,8
MOV SI,offset STUF_4
CALL FAO ; Formatted ascii output
FEN_02: POP AX ; Equipment byte restore
MOV SI,offset STUF_5 ; ...game controller
PUSH AX ; Save a copy of equip. byte
TEST AL,00010000b
JZ NO_TOY ; Jump if no game controller
MOV AX,BX
CALL LOCATE ; Position cursor
CALL PRINT ; ...and print string
INC BH ; ...scroll line
NO_TOY: CALL TIMER ; Timer devices?
JB NO_TIM ; ...skip if none
MOV AX,BX
CALL LOCATE ; Position cursor
INC BH
MOV SI,offset STUF_8
CALL PRINT
NO_TIM: POP AX
MOV SI,offset STUF_6
ROR AL,1 ; Check for COM port
AND AL,3
JZ NO_COM ; ...skip if no com
XOR BP,BP
CALL FAO ; Formatted ascii output
NO_COM: MOV AX,121Ch ; Where to position cursor
CALL LOCATE ; ...position cursor
MOV SI,offset STUF_7 ; Memory size string
CALL PRINT ; ...print string
PUSH ES
MOV BP,ES:13h ; Memory size (1 K blocks)
DEC BP
DEC BP
MOV SI,2
MOV DX,SI
MOV AX,80h
MOV ES,AX
CUTE: MOV AX,122Bh ; Cursory check of memory
CALL LOCATE ; ...position cursor
CALL K_BYTE ; ...print size in K
CALL MEMTST ; Memory check ES:0 - ES:0400
JB BADRAM ; ...bad RAM found (How ???)
DEC BP
JNZ CUTE
POP ES
RESET: MOV BL,2 ; Do a warm boot
CALL BEEP ; ...short beep
CALL BLANK ; ...clear display
MOV Word ptr ES:72h,1234h ; Show cold start done
MOV AH,1
MOV CX,607h ; Set underline cursor
INT 10h
MOV SI,offset BANNER ; Load banner address
CALL PRINT ; ...and print string
INT 19h ; Boot the machine
BADRAM: POP ES
OR Byte ptr ES:15h,ER_RAM ; Show "Bad Ram" error
JMP CONFIG
STUF db ' Generic Turbo XT Bios 1987',0
STUF_1 db CR,LF,0,'System error #',0,', Continue?',0
STUF_2 db ' ',0,'Interface card list',0,'Monochrome',0
STUF_3 db 'Color/Graphics',0
STUF_4 db 'Printer #',0
STUF_5 db 'Game controller',0
STUF_6 db 'Async. commu. #',0
STUF_7 db 'RAM Testing .. 000 KB',0
STUF_8 db 'Timer',0
ENTRY 0E600h ; Not necessary to IPL here..
IPL: STI ; Called to reboot computer
XOR AX,AX
MOV DS,AX
MOV Word ptr DS:78h,offset INT_1E ; Get disk parameter table
MOV DS:7Ah,CS ; ...save segment
MOV AX,4 ; Try up to four times
RETRY: PUSH AX ; Save retry count
MOV AH,0 ; ...reset
INT 13h ; ...floppy
JB FAILED
MOV AL,1 ; One sector
MOV AH,2 ; ...read
XOR DX,DX ; ...from drive 0, head 0
MOV ES,DX ; ...segment 0
MOV BX,7C00h ; ...offset 7C00
MOV CL,1 ; ...sector 1
MOV CH,0 ; ...track 0
INT 13h ; ...floppy
JB FAILED
JMPF 0000h,7C00h ; Call the boot block
;
FAILED: POP AX ; Get retries
DEC AL ; ...one less
JNZ RETRY
NODISK: OR AH,AH ; Disk present?
JNZ DERROR ; ...yes
CALL BLANK ; Clear display
PUSH CS
POP DS
MOV SI,offset DSKMSG ; Load disk message
CALL PRINT ; ...and print string
CALL GETCH ; ...wait for keypress
CALL BLANK ; ...clear display
MOV AX,0FF04h ; Reset retry count
JMP RETRY ; ...and retry
DERROR: XOR AX,AX ; Error from NEC 765
MOV DS,AX
LES AX,Dword ptr DS:60h ; ROM basic vector ES:AX
MOV BX,ES ; ...get ROM basic segment
CMP AX,0
MOV AX,0
JNZ NODISK ; No ROM basic found
CMP BX,0F600h
JNZ NODISK ; Invalid ROM basic segment
INT 18h ; ...else call ROM basic
DSKMSG db 'Insert diskette in DRIVE A.',CR,LF
db ' Press any key.',0
ENTRY 0E6F2h ; IBM entry point for INT 19h
INT_19: JMP IPL ; Warm boot
ENTRY 0E729h ; IBM entry point for INT 14h
BAUD dw 0417h ; 110 baud clock divisor
dw 0300h ; 150 baud clock divisor
dw 0180h ; 300 baud clock divisor
dw 00C0h ; 600 baud clock divisor
dw 0060h ; 1200 baud clock divisor
dw 0030h ; 2400 baud clock divisor
dw 0018h ; 4800 baud clock divisor
dw 000Ch ; 9600 baud clock divisor
INT_14: STI ; Serial com. RS232 services
PUSH DS ; ...thru IC 8250 uart (ugh)
PUSH DX ; ...DX = COM device (0 - 3)
PUSH SI
PUSH DI
PUSH CX
PUSH BX
MOV BX,40h
MOV DS,BX
MOV DI,DX ;
MOV BX,DX ; RS232 serial COM index (0-3)
SHL BX,1 ; ...index by bytes
MOV DX,[BX] ; Convert index to port number
OR DX,DX ; ...by indexing 40:0
JZ COM_ND ; ...no such COM device, exit
OR AH,AH ; Init on AH=0
JZ COMINI
DEC AH
JZ COMSND ; Send on AH=1
DEC AH
JZ COMGET ; Rcvd on AH=2
DEC AH
JZ COMSTS ; Stat on AH=3
COM_ND: POP BX ; End of COM service
POP CX
POP DI
POP SI
POP DX
POP DS
IRET
COMINI: PUSH AX ; Init COM port. AL has data
; = (Word Length in Bits - 5)
; +(1 iff two stop bits) * 4
; +(1 iff parity enable) * 8
; +(1 iff parity even ) * 16
; +(BAUD: select 0-7 ) * 32
MOV BL,AL
ADD DX,3 ; Line Control Register (LCR)
MOV AL,80h ; ...index RS232_BASE + 3
OUT DX,AL ; Tell LCR to set (latch) baud
MOV CL,4
ROL BL,CL ; Baud rate selects by words
AND BX,00001110b ; ...mask off extraneous
MOV AX,Word ptr CS:[BX+BAUD] ; Clock divisor in AX
SUB DX,3 ; Load in lo order baud rate
OUT DX,AL ; ...index RS232_BASE + 0
INC DX ; Load in hi order baud rate
MOV AL,AH
OUT DX,AL ; ...index RS232_BASE + 1
POP AX
INC DX ; Find Line Control Register
INC DX ; ...index RS232_BASE + 3
AND AL,00011111b ; Mask out the baud rate
OUT DX,AL ; ...set (censored) init stat
MOV AL,0
DEC DX ; Interrupt Enable Reg. (IER)
DEC DX ; ...index RS232_BASE + 1
OUT DX,AL ; Interrupt is disabled
DEC DX
JMP short COMSTS ; Return current status
COMSND: PUSH AX ; Send AL thru COM port
MOV AL,3
MOV BH,00110000b ;(Data Set Ready,Clear To Send)
MOV BL,00100000b ; ..(Data Terminal Ready) wait
CALL WAITFR ; Wait for transmitter to idle
JNZ HUNG ; ...time-out error
SUB DX,5 ; ...(xmit) index RS232_BASE
POP CX ; Restore char to CL register
MOV AL,CL ; ...get copy to load in uart
OUT DX,AL ; ...transmit char to IC 8250
JMP COM_ND ; ...AH register has status
HUNG: POP CX ; Transmit error, restore char
MOV AL,CL ; ...in AL for compatibility
; ...fall thru to gen. error
HUNGG: OR AH,80h ; Set error (=sign) bit in AH
JMP COM_ND ; ...common exit
COMGET: MOV AL,1 ; Get char. from COM port
MOV BH,00100000b ; Wait on DSR (Data Set Ready)
MOV BL,00000001b ; Wait on DTR (Data Term.Ready)
CALL WAITFR ; ...wait for character
JNZ HUNGG ; ...time-out error
AND AH,00011110b ; Mask AH for error bits
SUB DX,5 ; ...(rcvr) index RS232_BASE
IN AL,DX ; Read the character
JMP COM_ND ; ...AH register has status
COMSTS: ADD DX,5 ; Calculate line control stat
IN AL,DX ; ...index RS232_BASE + 5
MOV AH,AL ; ...save high order status
INC DX ; Calculate modem stat. reg.
IN AL,DX ; ...index RS232_BASE + 6
JMP COM_ND ; ...save low order status
;AX=(DEL Clear_To_Send) * 1
; (DEL Data_Set_ready)* 2
; (Trailing_Ring_Det.)* 4
; (DEL Carrier_Detect)* 8
; ( Clear_To_Send )* 16
; ( Data_Set_Ready)* 32
; ( Ring_Indicator)* 64
; ( Carrier_Detect)* 128
; **************
; ( Char received)* 256
; ( Char smothered)* 512
; ( Parity error )* 1024
; ( Framing error )* 2048
; ( Break detected)* 4096
; ( Able to xmit )* 8192
; ( Transmit idle )*16384
; ( Time out error)*32768
POLL: MOV BL,byte ptr [DI+7Ch] ; Wait on BH in status or error
POLL_1: SUB CX,CX ; Outer delay loop
POLL_2: IN AL,DX ; ... inner loop
MOV AH,AL
AND AL,BH ; And status with user BH mask
CMP AL,BH
JZ POLLXT ; ... jump if mask set
LOOP POLL_2 ; Else try again
DEC BL
JNZ POLL_1
OR BH,BH ; Clear mask to show timeout
POLLXT: RET ; Exit AH reg. Z flag status
WAITFR: ADD DX,4 ; Reset the Modem Control Reg.
OUT DX,AL ; ...index RS232_BASE + 4
INC DX ; Calculate Modem Status Reg.
INC DX ; ...index RS232_BASE + 6
PUSH BX ; Save masks (BH=MSR,BL=LSR)
CALL POLL ; ...wait on MSR modem status
POP BX ; ...restore wait masks BH,BL
JNZ WAITF1 ; ..."Error Somewhere" by DEC
DEC DX ; Calculate Line Status Reg.
MOV BH,BL ; ...index RS232_BASE + 5
CALL POLL ; ...wait on LSR line status
WAITF1: RET ; Status in AH reg. and Z flag
ENTRY 0E82Eh ; IBM entry, key bios service
INT_16: STI ; Keyboard bios services
PUSH DS
PUSH BX
MOV BX,40h
MOV DS,BX ; Load work segment
OR AH,AH
JZ KPD_RD ; Read keyboard buffer, AH=0
DEC AH
JZ KPD_WT ; Set Z if char ready, AH=1
DEC AH
JZ KPD_SH ; Return shift in AL , AH=2
KPD_XT: POP BX ; Exit INT_16 keypad service
POP DS
IRET
KPD_RD: CLI ; No interrupts, alters buffer
MOV BX,DS:1Ah ; ...point to buffer head
CMP BX,DS:1Ch ; If not equal to buffer tail
JNZ KPD_R1 ; ...char waiting to be read
STI ; Else allow interrupts
JMP KPD_RD ; ...wait for him to type
KPD_R1: MOV AX,[BX] ; Fetch the character
INC BX ; ...point to next character
INC BX ; ...char = scan code + shift
MOV DS:1Ah,BX ; Save position in head
CMP BX,DS:82h ; ...buffer overflowed?
JNZ KPD_XT ; ...no, done
MOV BX,DS:80h ; Else reset to point at start
MOV DS:1Ah,BX ; ...and correct head position
JMP KPD_XT
KPD_WT: CLI ; No interrupts, critical code
MOV BX,DS:1Ah ; ...point to buffer head
CMP BX,DS:1Ch ; ...equal buffer tail?
MOV AX,[BX] ; (fetch, look ahead)
STI ; Enable interrupts
POP BX
POP DS
RETF 2 ; Do IRET, preserve flags
KPD_SH: MOV AL,DS:17h ; Read keypad shift status
JMP KPD_XT
ENTRY 0E885h ; Align INT_9 at correct place
ASCII db 000h,037h,02Eh,020h ; Scan -> Ascii. Sign bit set
db 02Fh,030h,031h,021h ; ...if further work needed
db 032h,033h,034h,035h
db 022h,036h,038h,03Eh
db 011h,017h,005h,012h
db 014h,019h,015h,009h
db 00Fh,010h,039h,03Ah
db 03Bh,084h,001h,013h
db 004h,006h,007h,008h
db 00Ah,00Bh,00Ch,03Fh
db 040h,041h,082h,03Ch
db 01Ah,018h,003h,016h
db 002h,00Eh,00Dh,042h
db 043h,044h,081h,03Dh
db 088h,02Dh,0C0h,023h
db 024h,025h,026h,027h
db 028h,029h,02Ah,02Bh
db 02Ch,0A0h,090h
NOALFA db 032h,036h,02Dh,0BBh ; Non-Alphabetic secondary
db 0BCh,0BDh,0BEh,0BFh ; ...translation table
db 0C0h,0C1h,0C2h,0C3h
db 0C4h,020h,031h,033h
db 034h,035h,037h,038h
db 039h,030h,03Dh,01Bh
db 008h,05Bh,05Dh,00Dh
db 05Ch,02Ah,009h,03Bh
db 027h,060h,02Ch,02Eh
db 02Fh
CTRLUP db 040h,05Eh,05Fh,0D4h ; CTRL uppercase secondary
db 0D5h,0D6h,0D7h,0D8h ; ...translation table
db 0D9h,0DAh,0DBh,0DCh ; ...for non-ASCII control
db 0DDh,020h,021h,023h
db 024h,025h,026h,02Ah
db 028h,029h,02Bh,01Bh
db 008h,07Bh,07Dh,00Dh
db 07Ch,005h,08Fh,03Ah
db 022h,07Eh,03Ch,03Eh
db 03Fh
CTRLLO db 003h,01Eh,01Fh,0DEh ; CTRL lowercase secondary
db 0DFh,0E0h,0E1h,0E2h ; ...translation table
db 0E3h,0E4h,0E5h,0E6h ; ...for non-ASCII control
db 0E7h,020h,005h,005h
db 005h,005h,005h,005h
db 005h,005h,005h,01Bh
db 07Fh,01Bh,01Dh,00Ah
db 01Ch,0F2h,005h,005h
db 005h,005h,005h,005h
db 005h
ALTKEY db 0F9h,0FDh,002h,0E8h ; ALT key secondary
db 0E9h,0EAh,0EBh,0ECh ; ...translation table
db 0EDh,0EEh,0EFh,0F0h
db 0F1h,020h,0F8h,0FAh
db 0FBh,0FCh,0FEh,0FFh
db 000h,001h,003h,005h
db 005h,005h,005h,005h
db 005h,005h,005h,005h
db 005h,005h,005h,005h
db 005h
NUMPAD db '789-456+1230.' ; Keypad secondary tralsator
NUMCTR db 0F7h,005h,004h,005h ; Numeric keypad CTRL sec.
db 0F3h,005h,0F4h,005h ; ...translation table
db 0F5h,005h,0F6h,005h
db 005h
NUMUPP db 0C7h,0C8h,0C9h,02Dh ; Numeric keypad SHIFT sec.
db 0CBh,005h,0CDh,02Bh ; ...translation table
db 0CFh,0D0h,0D1h,0D2h
db 0D3h
INT_9: STI ; Key press hardware interrupt
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
CLD
MOV AX,40h
MOV DS,AX
IN AL,60h ; Read the scan code data
PUSH AX ; ...save it
IN AL,61h ; Get control port status
PUSH AX ; ...save it
OR AL,10000000b ; Set "latch" bit to
OUT 61h,AL ; ...acknowledge data
POP AX ; Restore control status
OUT 61h,AL ; ...to enable keyboard
POP AX ; ...restore scan code
MOV AH,AL ; Save copy of scan code
CMP AL,11111111b ; ...check for overrun
JNZ KY_01 ; ...no, OK
JMP KY_BEP ; Else beep bell on overrun
KY_EOI: MOV AL,20h ; Send end_of_interrupt code
OUT 20h,AL ; ...to 8259 interrupt chip
KY_XIT: POP ES ; Exit the interrupt
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
IRET
KY_01: AND AL,01111111b ; Valid scan code, no break
CMP AL,46h
JBE KY_02
JMP KY_CT8
KY_02: MOV BX,offset ASCII ; Table for ESC thru Scroll Lck
XLAT CS:[BX] ; ...translate to Ascii
OR AL,AL ; Sign flags "Shift" type key
JS KY_FLG ; ...shift,caps,num,scroll etc
OR AH,AH ; Invalid scan code?
JS KY_EOI ; ...exit if so
JMP short KY_ASC ; Else normal character
KY_FLG: AND AL,01111111b ; Remove sign flag bit
OR AH,AH ; ...check scan code
JS KY_SUP ; ...negative, key released
CMP AL,10h ; Is it a "toggle" type key?
JNB KY_TOG ; ...yes
OR DS:17h,AL ; Else set bit in "flag" byte
JMP KY_EOI ; ...and exit
KY_TOG: TEST Byte ptr DS:17h,00000100b ; Control key pressed?
JNZ KY_ASC ; ...yes, skip
TEST AL,DS:18h ; Else check "CAPS, NUM, SCRL"
JNZ KY_EOI ; ...set, invalid, exit
OR DS:18h,AL ; Show set in "flag_1" byte
XOR DS:17h,AL ; ...flip bits in "flag" byte
JMP KY_EOI
KY_SUP: CMP AL,10h ; Released - is it "toggle" key
JNB KY_TUP ; ...skip if so
NOT AL ; Else form two's complement
AND DS:17h,AL ; ...to do BIT_CLEAR "flags"
CMP AL,11110111b ; ALT key release special case
JNZ KY_EOI ; ...no, exit
MOV AL,DS:19h ; Else get ALT-keypad character
MOV AH,0 ; ...pretend null scan code
MOV DS:19h,AH ; ...zero ALT-keypad character
CMP AL,AH ; Was there a valid ALT-keypad?
JZ KY_EOI ; ...no, ignore, exit
JMP KY_NUL ; Else stuff it in ASCII buffer
KY_TUP: NOT AL ; Form complement of toggle key
AND DS:18h,AL ; ...to do BIT_CLEAR "flag_1"
JMP KY_EOI
KY_ASC: TEST Byte ptr DS:18h,00001000b ; Scroll lock pressed?
JZ KY_NLK ; ...no
CMP AH,45h ; Is this a NUM LOCK character?
JZ KY_03 ; ...no
AND Byte ptr DS:18h,11110111b ; Else clear bits in "flag_1"
KY_03: JMP KY_EOI ; ...and exit
KY_NLK: TEST Byte ptr DS:17h,00001000b ; ALT key pressed?
JNZ KY_ALT ; ...yes
TEST Byte ptr DS:17h,00000100b ; CTRL key pressed?
JNZ KY_CTL ; ...yes
TEST Byte ptr DS:17h,00000011b ; Either shift key pressed?
JNZ KSHIFT ; ...yes
KY_LC: CMP AL,1Ah ; Alphabetic character?
JA KY_LC1 ; ...no
ADD AL,'a'-1 ; Else add lower case base
JMP KY_COM
KY_LC1: MOV BX,offset NOALFA ; Non-alphabetic character
SUB AL,20h
XLAT CS:[BX] ; ...do the xlate
JMP KY_COM
KY_ALT: CMP AL,1Ah ; Control key pressed?
JA KY_AGN ; ...no, skip
MOV AL,0 ; Else illegal key press
JMP KY_BFR
KY_AGN: MOV BX,offset ALTKEY ; Load ALT key translation
SUB AL,20h ; ...bias to printing char.
XLAT CS:[BX] ; ...do the translation
JMP KY_COM
KY_CTL: CMP AH,46h ; Scroll lock key?
JNZ KY_CT1 ; ...no, skip
MOV Byte ptr DS:71h,10000000b ; Else CTRL-"Scroll" = break
MOV AX,DS:80h ; ...get key buffer start
MOV DS:1Ch,AX ; ...get key tail to start
MOV DS:1Ah,AX ; ...get key head to start
INT 1Bh ; Issue a "Break" interrupt
SUB AX,AX
JMP KY_CO2
KY_CT1: CMP AH,45h ; Num lock key?
JNZ KY_CT2 ; ...no, skip
OR Byte ptr DS:18h,00001000b ; Else show scroll lock
MOV AL,20h ; ...send end_of_interrupt
OUT 20h,AL ; ...to 8259 int. controller
CMP Byte ptr DS:49h,7 ; Monochrome monitor?
JZ KY_POL ; ...yes, skip
MOV DX,3D8h ; Else reset mode
MOV AL,DS:65h ; ...for the
OUT DX,AL ; ...CGA color card
KY_POL: TEST Byte ptr DS:18h,00001000b ; Wait for him to type
JNZ KY_POL ; ...not yet
JMP KY_XIT
KY_CT2: CMP AH,3 ; Is it a Control @ (null) ?
JNZ KY_CT3 ; ...no
MOV AL,0 ; Else force a null
KY_CT4: JMP KY_BFR ; ...save in buffer
KY_CT3: CMP AL,1Ah ; Is it a control character?
JBE KY_CT4 ; ...yes
MOV BX,offset CTRLLO ; Else non-ascii control
SUB AL,20h ; ...lower case
XLAT CS:[BX] ; ...translation
JMP KY_COM
KSHIFT: CMP AH,37h ; Print_Screen pressed?
JNZ KY_CT5
MOV AL,20h ; Yes, send end_of_interrupt
OUT 20h,AL ; ...to 8259 interrupt chip
INT 5 ; Request print_screen service
JMP KY_XIT ; ...and exit key service
KY_CT5: CMP AL,1Ah ; Alphabetic char?
JA KY_CT6 ; ...no
ADD AL,'A'-1 ; Yes, add base for alphabet
JMP KY_COM
KY_CT6: MOV BX,offset CTRLUP ; Non-ascii control
SUB AL,20h ; ...upper case
XLAT CS:[BX] ; ...translation
JMP KY_COM
KY_CT8: SUB AL,47h ; Keypad key, convert origin
MOV BL,DS:17h ; ...get "flag" byte
TEST BL,00001000b ; Look for ALT keypad entry
JNZ KB_NUM ; ...do special entry thing
TEST BL,00000100b ; CTRL key pressed?
JNZ KY_CTR ; ...skip if so
TEST BL,00100000b ; Toggle "Num Lock" ?
JZ KY_CT9 ; ...no, continue
TEST BL,00000011b ; Shift keys hit?
JNZ KY_CTA ; ...no, check "INS"
JMP KY_CTD ; Else xlat keypad char.
KY_CT9: TEST BL,00000011b ; Shift keys hit?
JZ KY_CTA ; ...no, check "INS" key
JMP KY_CTD ; Else xlat keypad char.
KB_NUM: OR AH,AH ; ALT-keypad entry, scan code
JS KY_EO1 ; ...out of range
TEST Byte ptr DS:17h,00000100b ; Else check CTRL state
JZ KY_PAD ; ...not pressed, ALT keypad
KY_PAT: CMP AH,53h ; Patch for CTRL ALT - toggle
JNZ KY_PA1 ; ...not a DEL (reset)
MOV Word ptr DS:72h,1234h ; Ctrl-Alt-Del, set init flag
JMP WARM ; ...do a warm reboot
KY_PA1: CMP AH,4Ah ; Is it a keypad "-" ?
JNZ KY_PAD ; ...no, skip
PUSH AX
PUSH BX
PUSH CX
IN AL,61h ; Read equipment flags
XOR AL,00001100b ; ...toggle speed
OUT 61h,AL ; Write new flags back
MOV AH,1 ; Video func=Set cursor type
MOV CX,607h ; ...start at 6, end at 7
AND AL,4 ; Is turbo mode set?
JZ KY_CUR ; ...no, keep big cursor
MOV CH,0 ; Else set tiny cursor
KY_CUR: INT 10h ; Set cursor type service
MOV BX,DS:80h ; ...get start of key buf
MOV DS:1Ah,BX ; ...set head to start
MOV DS:1Ch,BX ; ...set tail to start
POP CX
POP BX
POP AX
KY_PAD: MOV BX,offset NUMPAD ; Get keypad translation table
XLAT CS:[BX] ; ...convert to number
CMP AL,'0' ; Is it a valid ASCII digit?
JB KY_EO1 ; ...no, ignore it
SUB AL,30h ; Else convert to number
MOV BL,AL ; ...save a copy
MOV AL,DS:19h ; Get partial ALT-keypad sum
MOV AH,0Ah ; ...times 10 (decimal)
MUL AH
ADD AL,BL ; Add in new digit to sum
MOV DS:19h,AL ; ...save as new ALT entry
KY_EO1: JMP KY_EOI ; End_of_interrupt, exit
KY_CTR: OR AH,AH ; Key released?
JS KY_EO1 ; ...ignore if so
MOV BX,offset NUMCTR ; Else Numeric Keypad Control
XLAT CS:[BX] ; ...secondary translate
JMP short KY_COM ; ...and save it
KY_CTA: CMP AH,0D2h ; Was "INS" key released?
JNZ KY_CTB
AND Byte ptr DS:18h,01111111b ; Yes, clear "INS" in "FLAG_1"
JMP short KY_EO1
KY_CTB: OR AH,AH ; Key released?
JS KY_EO1 ; ...ignore if so
CMP AH,52h ; Else check for "INS" press
JNZ KY_CTC ; ...not "INS" press
TEST Byte ptr DS:18h,10000000b ; Was INS key in effect?
JNZ KY_EO1 ; ...yes, ignore
XOR Byte ptr DS:17h,10000000b ; Else tog "INS" in "FLAG" byte
OR Byte ptr DS:18h,10000000b ; ...set "INS" in "FLAG_1" byte
KY_CTC: MOV BX,offset NUMUPP ; Numeric Keypad Upper Case
XLAT CS:[BX] ; ...secondary translation
JMP short KY_COM
KY_CTD: OR AH,AH ; Was the key released?
JS KY_EO1 ; ...yes, ignore
MOV BX,offset NUMPAD ; Load translation table
XLAT CS:[BX] ; ...do translate
JMP short KY_COM
KY_COM: CMP AL,5 ; Common entry, char in AL
JZ KY_EO2 ; ...Control E, ignore
CMP AL,4
JA KY_CO1 ; Above Control D
OR AL,10000000b ; Else set sign flag
JMP short KY_CO2
KY_CO1: TEST AL,10000000b ; Is sign bit set?
JZ KY_CO3 ; ...skip if so
AND AL,01111111b ; Else mask sign off
KY_CO2: MOV AH,AL ; Save in high order byte
MOV AL,0 ; ...set scan code to zero
KY_CO3: TEST Byte ptr DS:17h,01000000b ; Test for "CAPS LOCK" state
JZ KY_BFR ; ...no, skip
TEST Byte ptr DS:17h,00000011b ; Test for SHIFT key
JZ KY_CO4 ; ...skip if no shift
CMP AL,'A' ; Check for alphabetic key
JB KY_BFR ; ...not SHIFT_able
CMP AL,'Z' ; Check for alphabetic key
JA KY_BFR ; ...not SHIFT_able
ADD AL,20h ; Else do the shift
JMP short KY_BFR
KY_CO4: CMP AL,'a' ; Check for alphabetic key
JB KY_BFR ; ...not SHIFT_able
CMP AL,'z' ; Check for Alphabetic key
JA KY_BFR ; ...not SHIFT_able
SUB AL,20h ; Else do the shift
KY_BFR: MOV BX,DS:1Ch ; BX = tail of buffer
MOV DI,BX ; ...save it
INC BX ; ...advance
INC BX ; ...by word
CMP BX,DS:82h ; End of buffer reached?
JNZ KY_CHK ; ...no, skip
MOV BX,DS:80h ; Else BX = beginning of buffer
KY_CHK: CMP BX,DS:1Ah ; BX = Buffer Head ?
JNZ KY_STF ; ...no, OK
JMP short KY_BEP ; Else buffer overrun, beep
KY_STF: MOV [DI],AX ; Stuff scan code, char in bfr
MOV DS:1Ch,BX ; ...and update bfr tail
KY_EO2: JMP KY_EOI
KY_BEP: MOV AL,20h ; Keyboard beeper routine
OUT 20h,AL ; ...send end_of_interrupt
MOV BX,80h ; Cycles in beep
IN AL,61h ; ...get status
PUSH AX ; ...save copy
KY_BE1: AND AL,11111100b ; Mask off speaker bits
OUT 61h,AL ; ...disable speaker
KY_BE2: MOV CX,64h ; Constant for pitch
KY_BE3: LOOP KY_BE3 ; ...delay, speaker off
XOR AL,00000010b
OUT 61h,AL ; Toggle speaker position
TEST AL,00000010b ; Full cycle done yet?
JZ KY_BE2 ; ...no, do other half cycle
DEC BX ; Else show cycle sent
JNZ KY_BE1 ; ...more cycles to send
POP AX
OUT 61h,AL ; Restore flags
MOV CX,32h ; Silence counter
KY_BE4: LOOP KY_BE4 ; Send nothing for while
JMP KY_XIT
KY_NUL: MOV AH,38h ; ALT key pressed, released
JMP KY_BFR ; ...for no logical reason
ENTRY 0EC59h ; IBM entry point for floppy
INT_13: STI ; Floppy disk services
PUSH BP
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BX
MOV DI,AX ; Request type in DI, for index
XOR AX,AX
MOV DS,AX
LES SI,Dword ptr DS:78h ; Get disk parameter table
MOV AX,40h
MOV DS,AX
MOV BX,5
MOV AX,ES:[BX+SI] ; Get (Gap Length, DTL) in AX
PUSH AX ; ...save it
DEC BX
DEC BX
MOV AX,ES:[BX+SI] ; Get (Bytes/sector,EOT) in AX
PUSH AX ; ...save it
XCHG CL,DH
XCHG DL,CL
PUSH DX ; Push (Head,Drive) swapped
PUSH CX
PUSH DI
MOV BP,SP ; Mark bottom of stack frame
ifdef SLOW_FLOPPY
CALL FD_SPD ; ...execute request lo speed
else
CALL FD_XQT ; ...execute at current speed
endif
MOV AH,ES:[SI+2] ; Get new motor count
MOV DS:40h,AH ; ...and save it
MOV AH,DS:41h ; Get completion status
CMP AH,1 ; ...check for write protect
CMC ; ...was write protect error
POP BX
POP CX
POP DX
XCHG DL,CL
XCHG CL,DH
POP BX ; Clean
POP BX ; ...up
POP BX ; ...stack
POP ES
POP DS
POP DI
POP SI
POP BP
RETF 2
FD_XQT: MOV AL,[BP+1] ; Get floppy service number
OR AL,AL
JZ FD_RST ; ...reset, AH=0
DEC AL
JZ FD_XQ3 ; ...read status, AH=1
CMP Byte ptr [BP+2],3 ; For track number above 3?
JA FD_XQ1 ; ...yes
CMP AL,5 ; Service within range?
JBE FD_XQ2 ; ...yes
FD_XQ1: MOV Byte ptr DS:41h,1 ; Say write protect error
RET
FD_XQ2: JMP FD_001 ; Execute legal service
FD_XQ3: MOV AL,DS:41h ; Return NEC status byte
RET
FD_RST: MOV DX,3F2h ; Reset the floppy disk system
CLI
AND Byte ptr DS:3Fh,00001111b ; Clear "write in progress"
MOV AL,DS:3Fh ; ...find out busy drives
MOV CL,4
SHL AL,CL
TEST AL,00100000b
JNZ FD_RS1 ; Drive #1 active
TEST AL,01000000b
JNZ FD_RS2 ; Drive #2 active
TEST AL,10000000b
JZ FD_RS0 ; Drive #3 idle
FD_RS3: INC AL
FD_RS2: INC AL
FD_RS1: INC AL
FD_RS0: MOV Byte ptr DS:3Eh,0 ; All drives need recalibrate
MOV Byte ptr DS:41h,0 ; ...no completion status
OR AL,00001000b ; Interrupt ON in command word
OUT DX,AL ; ...send word to controller
OR AL,00000100b ; "Reset" in command word
OUT DX,AL ; ...send word to controller
STI
CALL NC_BSY ; Wait for completion
CALL NC_STS ; ...read result block
MOV AL,DS:42h
CMP AL,0C0h ; Did the reset work
JZ FD_RS4 ; ...yes
MOV Byte ptr DS:41h,20h ; Else set controller error
JMP short FD_RS5 ; ...return
FD_RS4: MOV AL,3 ; Specify command to NEC
CALL NEC765 ; ...send it
MOV AL,ES:[SI] ; First byte in param block
CALL NEC765 ; ...send it
MOV AL,ES:[SI+1] ; Secnd byte in param block
CALL NEC765 ; ...send it
FD_RS5: RET
NECFUN db 003h,000h,0E6h,0C5h,0E6h,04Dh ; NEC function table lookup
NECDMA db 000h,000h,046h,04Ah,042h,04Ah ; DMA modes for 8237
NECWRT db 000h,000h,000h,080h,000h,080h ; Write flag table lookup
NECDRV db 1,2,4,8 ; Drive number table lookup
NECERR db 80h,20h,10h,4,2,1 ; Error code table lookup
NECSTS db 04h,10h,08h,04h,03h,02h,20h ; Disk status table lookup
FD_001: CLI ; Normal (non-reset) commands
MOV Byte ptr DS:41h,0 ; ...reset status
MOV AL,[BP+1] ; Get command word
MOV AH,0
MOV DI,AX ; Save copy, zero-extended
OUT 0Ch,AL ; ...diddle LSB/MSB flip-flop
MOV AL,CS:[DI+NECDMA] ; Fetch DMA mode
OUT 0Bh,AL ; ...send it to IC8237
MOV AX,[BP+0Ch] ; Get segment address
MOV CL,4 ; ...convert
ROL AX,CL ; ...to (offset, 64K page no)
MOV CH,AL ; Extract page number (0-15.)
AND CH,00001111b ; ...for 8237 dma controller
AND AL,11110000b ; Extract implicit page offset
ADD AX,[BP+0Ah] ; ...add explicit user offset
ADC CH,0 ; ...(page number overflowed)
MOV DX,AX ; Now save lo 16 bits of addr.
OUT 4,AL ; ...send lowest 8 bits " "
MOV AL,AH
OUT 4,AL ; ...send next 8 bits " "
MOV AL,CH
OUT 81h,AL ; 64K page no to DMA page reg
MOV AH,[BP+0]
MOV AL,0
SHR AX,1 ; Sector cnt * 128
MOV CL,[BP+6] ; Track count
SHL AX,CL ; * sector count
DEC AX ; - 1
OUT 5,AL ; Send 1/2 of the word count
XCHG AL,AH
OUT 5,AL ; Send 2/2 of the word count
XCHG AL,AH
ADD AX,DX ; Compute final address
JNB FD_002 ; ...ok
STI
MOV Byte ptr DS:41h,9h ; Else wrapped around 64K byte
JMP FD_64K ; ...page register
FD_002: MOV AL,2 ; Disable floppy disk dma
OUT 0Ah,AL
MOV Byte ptr DS:40h,0FFh ; Set large motor timeout
MOV BL,[BP+2] ; ...get drive number
MOV BH,0
MOV AL,CS:[BX+NECDRV] ; Table lookup bit position
MOV CH,AL ; ...save mask
MOV CL,4
SHL AL,CL ; Shift mask into place
OR AL,BL ; ...or in drive select
OR AL,0Ch ; ...or in DMA and NO RESET
MOV DX,3F2h
OUT DX,AL ; Send to floppy control port
STI
MOV AL,CS:[DI+NECWRT] ; Table lookup for write flag
OR DS:3Fh,AL ; ...set write flag if active
OR AL,AL
JNS FD_003 ; ...skip if non-write
MOV AH,ES:[SI+0Ah] ; Motor start from param blk
OR AH,AH
JZ FD_003 ; ...none specified
TEST CH,DS:3Fh ; Was this drive motor running?
JNZ FD_003 ; ...skip if so
CALL FD_WT1 ; Else delay for motor start
FD_003: OR DS:3Fh,CH ; Show this motor is running
TEST CH,DS:3Eh ; Drive recalibration needed?
JNZ FD_004 ; ...no, skip
OR DS:3Eh,CH ; Else show recalibrated
MOV AL,7 ; Send RECAL command
CALL NEC765 ; ...to NEC 765 chip
MOV AL,BL
CALL NEC765 ; ...drive number
CALL NC_BSY ; Wait for completion of RECAL
CALL NEC_04 ; ...dummy call to RET
FD_004: MOV AL,0Fh ; Request a seek
CALL NEC765 ; ...from the NEC 765
MOV AL,BL
CALL NEC765 ; Drive number
MOV AL,[BP+3]
CALL NEC765 ; Cylinder number
CALL NC_BSY ; ...wait for completion
CALL NC_STS ; ...read results
MOV AL,ES:[SI+9] ; Get head settle time
OR AL,AL ; ...none specified?
JZ FD_005 ; ...if none, skip
FD_STL: MOV CX,226h ; Delay time for head settle
FD_STZ: LOOP FD_STZ ; ...timed wait
DEC AL ; ...delay in millisec
JNZ FD_STL ; ...wait some more
FD_005: MOV AL,CS:[DI+NECFUN] ; Translate user service, then
CALL NEC765 ; ...and send as NEC func
MOV AL,[BP+4] ;
AND AL,1
SHL AL,1
SHL AL,1
OR AL,BL
CALL NEC765
CMP Byte ptr [BP+1],5 ; Is this a format request?
JNZ FD_006 ; ...skip if not
MOV AL,[BP+6] ; Else use user bytes/sector
CALL NEC765
MOV AL,[BP+7] ; ... user EOT
CALL NEC765
MOV AL,ES:[SI+7] ; Disk table format gap length
CALL NEC765
MOV AL,ES:[SI+8] ; Disk table format fill byte
CALL NEC765
JMP short FD_008
FD_006: MOV CX,7 ; Else lookup bytes * 512/sec
MOV DI,3 ; ...from disk table
FD_007: MOV AL,[BP+DI] ; AL has bytes/sector * 512
CALL NEC765
INC DI ; ...get next item for table
LOOP FD_007 ; ...also (EOT,GAP,DTL...)
FD_008: CALL NC_BSY ; Wait on floppy i/o completion
CALL NC_ST1 ; ...get NEC status
MOV AL,DS:42h ; ...into AL
AND AL,11000000b ; Isolate errors
JZ FD_012 ; ...no errors
CMP AL,40h ; Test direction bit
JZ FD_ERR
MOV Byte ptr DS:41h,20h ; Set if bad controller
JMP short FD_012 ; ...return error
FD_ERR: MOV AL,DS:43h ; Read return code from block
MOV CX,6 ; ...number of error types
XOR BX,BX ; Start at error type 0
FD_009: TEST AL,CS:[BX+NECERR] ; Has error type BX occured?
JNZ FD_010 ; ...yes
INC BX ; Else try next error type
LOOP FD_009 ; ...until done
FD_010: MOV AL,CS:[BX+NECSTS] ; Translate error code again
MOV DS:41h,AL ; ...store it as disk status
FD_012: MOV AL,DS:45h ; Get bytes read
CMP AL,[BP+3] ; ...compare with requested
MOV AL,DS:47h ; Read sectors requested
JZ FD_013 ; ...return if all read
MOV AL,[BP+7] ; Else read sectors requested
INC AL ; ...add one for luck
FD_013: SUB AL,[BP+5] ; Subtract stectors read
RET
FD_64K: MOV AL,0 ; Overflowed 64K page boundary
RET ; ...show no sectors read
NC_BSY: STI ; Wait for operation to finish
XOR CX,CX ; ...zero lo order delay
MOV AL,2 ; Load hi order delay
NC_BS1: TEST Byte ptr DS:3Eh,10000000b ; Has interrupt set the flag?
CLC ; ...hack to slow CPU
JNZ NC_BS2 ; ...yes
LOOP NC_BS1 ; Else back for more
DEC AL
JNZ NC_BS1
MOV Byte ptr DS:41h,80h ; Time-out, say it completed
POP AX
MOV AL,0 ; ...return time out code
STC ; ...error status
RET
NC_BS2: AND Byte ptr DS:3Eh,01111111b ; Mask off completion status
RET ; ...return carry clear
NC_RDY: PUSH CX ; Wait for NEC ready for comand
XOR CX,CX
MOV DX,3F4h ; ...NEC status port
NC_RD1: IN AL,DX ; Read status of NEC 765 chip
OR AL,AL
JS NC_RD2 ; ...able to accept command
LOOP NC_RD1
MOV Byte ptr DS:41h,80h ; Else show timeout error
JMP short NC_RD3
NC_RD2: TEST AL,01000000b ; Test the direction bit
JNZ NC_RD4
MOV Byte ptr DS:41h,20h ; ...clear iff controller err
NC_RD3: POP CX
STC
RET
NC_RD4: INC DX ; Load NEC data port
IN AL,DX ; ...read it
PUSH AX
MOV CX,0Ah ; Short delay
NC_RD5: LOOP NC_RD5
DEC DX ; Load NEC status port
IN AL,DX ; ...read status
TEST AL,00010000b ; ...set Z flag if done
CLC ; ...return success
POP AX
POP CX
RET
FD_WT1: PUSH CX ; Millisecond delay in AH
FD_WT2: XOR CX,CX
FD_WT3: LOOP FD_WT3
DEC AH
JNZ FD_WT2
POP CX
RET
ifdef SLOW_FLOPPY ; Run floppy at SLOWEST speed
FD_SPD: IN AL,61h ; Toggle speed on Floppy Disk
PUSH AX ; ...save old clock rate
AND AL,11110011b ; ...load slowest clock rate
OUT 61h,AL ; ...slow down to 4.77 mHz
CALL FD_XQT ; Execute the i/o request
POP AX ; ...restore old clock rate
OUT 61h,AL ; ...from saved clock byte
RET
endif
ENTRY 0EF57h ; Disk interrupt entry
INT_E: STI ; Floppy disk attention
PUSH DS
PUSH AX
MOV AX,40h
MOV DS,AX
OR Byte ptr DS:3Eh,10000000b ; Raise "attention" flag
MOV AL,20h ; Send end_of_interrupt code
OUT 20h,AL ; ...to 8259 interrupt chip
POP AX
POP DS
IRET
NC_STS: MOV AL,8 ; Send a "Request status"
CALL NEC765 ; ...to the NEC 765 chip
NC_ST1: PUSH BX ; Alternate entry point
PUSH CX
MOV CX,7
XOR BX,BX
NC_ST2: CALL NC_RDY ; Wait for NEC 765 ready
JB NC_ST3 ; ...NEC 765 error
MOV [BX+42h],AL ; Save status in BIOS block
JZ NC_ST4 ; ...NEC 765 ready
INC BX ; Count more
LOOP NC_ST2
MOV Byte ptr DS:41h,20h ; NEC 765 controller error
NC_ST3: STC ; Set error condition
POP CX
POP BX
POP AX
MOV AL,0
RET
NC_ST4: POP CX ; Successful return
POP BX
RET
NEC765: PUSH CX ; Send control to NEC 765 chip
PUSH DX
PUSH AX
XOR CX,CX
MOV DX,3F4h ; Load NEC 765 status port
NEC_01: IN AL,DX ; Read NEC 765 status
OR AL,AL
JS NEC_02 ; ...done
LOOP NEC_01
MOV Byte ptr DS:41h,80h ; Set time out status
JMP short NEC_05
NEC_02: TEST AL,40h ; Check data direction
JZ NEC_03
MOV Byte ptr DS:41h,20h ; ...NEC 765 is gimped
JMP short NEC_05
NEC_03: INC DX ; Load NEC 765 data port
POP AX
OUT DX,AL ; ...write user's parameter
CLC
POP DX
POP CX
NEC_04: RET
NEC_05: POP AX ; Common error return
POP DX
POP CX
POP AX
MOV AL,0
STC
RET
ENTRY 0EFC7h ; IBM entry for disk param
INT_1E: db 11001111b ; Disk parameter table
db 2
db 25h
db 2
db 8
db 2Ah
db 0FFh
db 50h
db 0F6h
db 19h
db 4
ENTRY 0EFD2h ; IBM entry for parallel LPT
INT_17: STI ; Parallel printer services
PUSH DS
PUSH BX
PUSH CX
PUSH DX
MOV BX,40h
MOV DS,BX
MOV BX,DX ; DX is printer index (0 - 3)
SHL BX,1 ; ...word index
MOV DX,[BX+8] ; Load printer port
OR DX,DX
JZ LP_01 ; Goes to black hole
OR AH,AH
JZ LP_02 ; Function is print, AH=0
DEC AH
JZ LP_INI ; Function is init , AH=1
DEC AH
JZ LP_STS ; Get the status , AH=2
LP_01: POP DX
POP CX
POP BX
POP DS
IRET
LP_02: OUT DX,AL ; Char --> data lines 0-7
INC DX ; Printer status port
MOV BH,[BX+78h] ; Load time out parameter
MOV AH,AL
LP_05: XOR CX,CX ; Clear lo order time out
LP_POL: IN AL,DX ; Get line printer status
OR AL,AL ; ...ready?
JS LP_DON ; ...done if so
LOOP LP_POL
DEC BH ; Decrement hi order time out
JNZ LP_05
OR AL,00000001b ; Set timeout in Status Byte
AND AL,11111001b ; ...bits returned to caller
JMP short LP_TOG
LP_DON: INC DX ; Printer control port
MOV AL,00001101b ; Set output strobe hi
OUT DX,AL ; ...data lines 0-7 valid
LP_STR: MOV AL,00001100b ; Set output strobe lo
OUT DX,AL ; ...data lines 0-7 ?????
DEC DX ; Printer status port
JMP short LP_ST1 ; ...get line printer status
LP_STS: MOV AH,AL ; Save copy of character
INC DX ; Printer status port
LP_ST1: IN AL,DX ; Read printer status
AND AL,11111000b ; ...bits returned to caller
LP_TOG: XOR AL,01001000b ; ...toggle ERROR,ACKNOWLEDGE
XCHG AL,AH
JMP LP_01 ; Exit, AH=Status,AL=character
LP_INI: MOV AH,AL ; Initialize the line printer
INC DX
INC DX
MOV AL,00001000b
OUT DX,AL ; Request initialize
MOV CX,5DCh ; ...delay
LP_DLY: LOOP LP_DLY
JMP LP_STR ; Strobe the line printer
ENTRY 0F045h ; IBM entry point for table
V_TABLE dw CRT_0 ; Set mode
dw CRT_1 ; Set cursor type
dw CRT_2 ; Set cursor position
dw CRT_3 ; Get cursor position
dw CRT_4 ; Read light pen position
dw CRT_5 ; Set active display page
dw CRT_6 ; Scroll active page up
dw CRT_7 ; Scroll active page down
dw CRT_8 ; Read attribute/character
dw CRT_9 ; Write attribute/character
dw CRT_10 ; Read character only
dw CRT_11 ; Set color
dw CRT_12 ; Write pixel
dw CRT_13 ; Read pixel
dw CRT_14 ; Write teletype
dw CRT_15 ; Return current video state
ENTRY 0F065h ; IBM entry, video bios service
INT_10: STI ; Video bios service AH=(0-15.)
CLD ; ...strings auto-increment
PUSH BP
PUSH ES
PUSH DS
PUSH SI
PUSH DI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
MOV BX,40h
MOV DS,BX
MOV BL,DS:10h ; Get equipment byte
AND BL,00110000b ; ...isolate video mode
CMP BL,00110000b ; Check for monochrome card
MOV BX,0B800h
JNZ C_01 ; ...not there, BX --> CGA
MOV BX,0B000h ; Else BX --> MONO
C_01: PUSH BX ; Save video buffer address
MOV BP,SP ; ...start of stack frame
CALL C_02 ; ...then do the function
POP SI
POP AX
POP BX
POP CX
POP DX
POP DI
POP SI
POP DS
POP ES
POP BP
IRET
MAPBYT: PUSH DX ; Mul AL by BX, CX --> buf
MOV AH,0
MUL BX ; Position in AX
POP DX
MOV CX,[BP+0] ; CX --> video buffer
RET
ENTRY 0F0A4h ; IBM entry, SET_MODE tables
INT_1D: db 38h,28h,2Dh,0Ah,1Fh,6,19h ; Init string for 40 x 25
db 1Ch,2,7,6,7
db 0,0,0,0
db 71h,50h,5Ah,0Ah,1Fh,6,19h ; Init string for 80 x 25 col
db 1Ch,2,7,6,7
db 0,0,0,0
db 38h,28h,2Dh,0Ah,7Fh,6,64h ; Init string for GRAPHIX
db 70h,2,1,6,7
db 0,0,0,0
db 61h,50h,52h,0Fh,19h,6,19h ; Init string for 80 x 25 b/w
db 19h,2,0Dh,0Bh,0Ch
db 0,0,0,0
REGENL dw 0800h ; Regen len, 40 x 25
dw 1000h ; 80 x 25
dw 4000h ; GRAPHIX
dw 4000h
MAXCOL db 28h,28h,50h,50h,28h,28h,50h,50h ; Maximum columns
MODES db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh,29h ; Table of mode sets
TABMUL db 00h,00h,10h,10h,20h,20h,20h,30h ; Table lookup for multiply
C_02: CMP AH,0Fh ; Is AH a legal video command?
JBE C_03
RET ; ...error return if not
C_03: SHL AH,1 ; Make word value
MOV BL,AH ; ...then set up BX
MOV BH,0
JMP Word ptr CS:[BX+V_TABLE] ; ...vector to routines
CRT_0: MOV AL,DS:10h ; Set mode of CRT
MOV DX,3B4h ; ...mono port
AND AL,00110000b ; ...get display type
CMP AL,00110000b ; ...equal if mono
MOV AL,1 ; Assume mono display
MOV BL,7 ; ...mode is 7
JZ C0_01 ; ...Skip if mono, else CGA
MOV BL,[BP+2] ; BL = mode number (user AL)
MOV DL,0D4h ; 3D4 is CGA port
DEC AL
C0_01: MOV DS:63h,DX ; Save cur. CRT display port
ADD DL,4
OUT DX,AL ; Reset the video
MOV DS:49h,BL ; ...save cur. CRT mode
PUSH DS
XOR AX,AX
MOV DS,AX
LES SI,Dword ptr DS:74h ; SI --> INT_1D video param
POP DS
MOV BH,0
PUSH BX
MOV BL,CS:[BX+TABMUL] ; Get BL for index into INT_1D
ADD SI,BX
MOV CX,10h ; Sixteen values to send
C0_02: MOV AL,ES:[SI] ; Value to send in SI
CALL SENDAX ; ...send it
INC AH ; ...bump count
INC SI ; ...point to next
LOOP C0_02 ; ...loop until done
MOV BX,[BP+0] ; BX --> regen buffer
MOV ES,BX ; ...into ES segment
XOR DI,DI
CALL MODCHK ; Set flags acc. to mode
MOV CX,2000h ; ...assume CGA
MOV AX,0 ; ...and graphics
JB C0_04 ; ...do graphics fill
JNZ C0_03 ; ...Alphanumeric fill
MOV CX,800h ; ...mono card
C0_03: MOV AX,7*100h+' ' ; Word for text fill
C0_04: REPZ STOSW ; ...fill regen buffer
MOV DX,DS:63h ; Get the port
ADD DL,4
POP BX
MOV AL,CS:[BX+MODES] ; Load data to set for mode
OUT DX,AL ; ...and send it
MOV DS:65h,AL ; ...then save active data
INC DX
MOV AL,30h ; Assume not 640 x 200 b/w
CMP BL,6 ; ...correct?
JNZ C0_05
MOV AL,3Fh ; Palette for 640 x 200 b/w
C0_05: MOV DS:66h,AL ; ...save palette
OUT DX,AL ; ...send palette
XOR AX,AX
MOV DS:4Eh,AX ; Start at beg. of 1st page
MOV DS:62h,AL ; ...active page=page 0
MOV CX,8 ; Do 8 pages of cursor data
MOV DI,50h ; Page cursor data at 40:50
C0_06: MOV [DI],AX ; Cursor at upper left of page
INC DI ; ...next page
LOOP C0_06
MOV Word ptr DS:60h,0607h ; Cursor: Line 6 thru Line 7
MOV AL,CS:[BX+MAXCOL] ; Get display width
MOV DS:4Ah,AX ; ...save it
AND BL,11111110b
MOV AX,Word ptr CS:[BX+REGENL] ; Get video regen length
MOV DS:4Ch,AX ; ...save it
RET
CRT_1: MOV CX,[BP+6] ; Set cursor type, from CX
MOV DS:60h,CX ; ...save it
MOV AH,0Ah ; CRT index register 0Ah
CALL OT6845 ; ...send CH,CL to CRT reg
RET
CRT_2: MOV BL,[BP+5] ; Set cursor position, page BH
SHL BL,1 ; ...(our BL)
MOV BH,0
MOV AX,[BP+8] ; Position in user DX (our AX)
MOV [BX+50h],AX ; ...remember cursor position
JMP SETCUR ; ...set 6845 cursor hardware
CRT_3: MOV BL,[BP+5] ; Get cursor position, page BH
SHL BL,1
MOV BH,0
MOV AX,[BX+50h]
MOV [BP+8],AX ; ...return position in user DX
MOV AX,DS:60h ; Get cursor mode
MOV [BP+6],AX ; ...return in user CX
RET
PENOFF: db 3,3,5,5,3,3,3,4 ; Light pen offset table
CRT_4: MOV DX,DS:63h ; Read light pen position
ADD DL,6
MOV Byte ptr [BP+3],0 ; AH=0, assume not triggered
IN AL,DX
TEST AL,00000100b
JZ C4_05 ; Skip, reset if pen not set
TEST AL,00000010b
JNZ C4_01 ; Skip if pen triggered
RET ; ...return, do not reset
C4_01: MOV AH,10h ; Offset to pen port is 10h
CALL PENXY ; ...read into CH,CL
MOV BL,DS:49h ; Get CRT mode data word
MOV CL,BL
MOV BH,0
MOV BL,Byte ptr CS:[BX+PENOFF] ; Load offset for subtraction
SUB CX,BX
JNS C4_02 ; ...did not overflow
XOR AX,AX ; Else fudge a zero
C4_02: CALL MODCHK ; Set flags on display type
JNB C4_03 ; ...text mode, skip
MOV CH,28h
DIV DL
MOV BL,AH
MOV BH,0
MOV CL,3
SHL BX,CL
MOV CH,AL
SHL CH,1
MOV DL,AH
MOV DH,AL
SHR DH,1
SHR DH,1
CMP Byte ptr DS:49h,6 ; Mode 640 x 200 b/w?
JNZ C4_04 ; ...no, skip
SHL DL,1
SHL BX,1
JMP short C4_04
C4_03: DIV Byte ptr DS:4Ah ; Divide by columns in screen
XCHG AL,AH ; ...as this is text mode
MOV DX,AX
MOV CL,3
SHL AH,CL
MOV CH,AH
MOV BL,AL
MOV BH,0
SHL BX,CL
C4_04: MOV Byte ptr [BP+3],1 ; Return AH=1, light pen read
MOV [BP+8],DX ; ...row, column in user DX
MOV [BP+4],BX ; ...pixel column in user BX
MOV [BP+7],CH ; ...raster line in user CH
C4_05: MOV DX,DS:63h ; Get port of active CRT card
ADD DX,7
OUT DX,AL ; ...reset the light pen
RET
CRT_5: MOV AL,[BP+2] ; Set active display page to AL
MOV DS:62h,AL ; ...save new active page
MOV AH,0 ; ...clear hi order
PUSH AX
MOV BX,DS:4Ch ; Get size of regen. buffer
MUL BX ; ...times number of pages
MOV DS:4Eh,AX ; Now AX = CRT offset, save
SHR AX,1 ; ...now word offset
MOV CX,AX ; ...save a copy
MOV AH,0Ch ; CRT index register 0Ch
CALL OT6845 ; ...send CH,CL thru CRT reg
POP BX
CALL MOVCUR ; Save new parameters
RET
CRT_6: ; Scroll active page up
CRT_7: CALL MODCHK ; Scroll active page down
JNB SCR_01
JMP SCG_01 ; Graphics scroll
SCR_01: CLD ; Strings go upward
CMP Byte ptr DS:49h,2
JB SCR_03 ; ...no retrace wait needed
CMP Byte ptr DS:49h,3
JA SCR_03 ; ...no retrace wait needed
MOV DX,3DAh ; Else 80 x 25, do the kludge
SCR_02: IN AL,DX ; Read CGA status register
TEST AL,00001000b ; ...vertical retrace?
JZ SCR_02 ; ...wait until it is
MOV DX,3D8h ; Then go and
MOV AL,25h ; ...turn the display
OUT DX,AL ; ...off to avoid snow
SCR_03: MOV AX,[BP+8] ; Get row,column of upper left
PUSH AX
CMP Byte ptr [BP+3],7 ; Check for scroll down
JZ SCR_04 ; ...yes, skip if so
MOV AX,[BP+6] ; Get row,column of lowr right
SCR_04: CALL RC2COL ; Get byte offset in CRT buf
ADD AX,DS:4Eh ; ...add base for CRT buf
MOV SI,AX
MOV DI,AX
POP DX
SUB DX,[BP+6] ; Subtract (row,col) lwr rhgt
ADD DX,101h ; ...width of one char
MOV BX,DS:4Ah ; Get columns in display
SHL BX,1 ; ...bytes in row of display
PUSH DS
MOV AL,[BP+2] ; Get scroll fill character
CALL MAPBYT ; ...calculate offset
MOV ES,CX ; CX --> byte in buffer
MOV DS,CX
CMP Byte ptr [BP+3],6 ; Scroll up?
JZ SCR_05 ; ...skip if so
NEG AX
NEG BX
STD ; Else start at top of page
SCR_05: MOV CL,[BP+2] ; Get count of lines to scroll
OR CL,CL
JZ SCR_07 ; ...nothing to do
ADD SI,AX
SUB DH,[BP+2]
SCR_06: MOV CH,0 ; Clear hi order word count
MOV CL,DL ; ...load lo order word count
PUSH DI
PUSH SI
REPZ MOVSW ; Do the scroll
POP SI
POP DI
ADD SI,BX ; Move one line in direction
ADD DI,BX ; "" ""
DEC DH ; One less line to scroll
JNZ SCR_06
MOV DH,[BP+2] ; Now get number of rows
SCR_07: MOV CH,0 ; Clear hi order word count
MOV AH,[BP+5] ; ...get fill attribute
MOV AL,' ' ; ...fill character
SCR_08: MOV CL,DL ; Get characters to scroll
PUSH DI
REPZ STOSW ; ...store fill attr/char
POP DI
ADD DI,BX ; Show row was filled
DEC DH
JNZ SCR_08 ; ...more rows are left
POP DS
CALL MODCHK ; Check for monochrome card
JZ SCR_09 ; ...skip if so
MOV AL,DS:65h ; Get the mode data byte
MOV DX,3D8h ; ...load active CRT card port
OUT DX,AL ; ...and unblank the screen
SCR_09: RET
SCG_01: CLD ; Assume GRAFIX scroll up
MOV AX,[BP+8] ; (Row,Col) of lower right
PUSH AX
CMP Byte ptr [BP+3],7 ; Scroll down?
JZ SCG_02 ; ...skip if so
MOV AX,[BP+6] ; (Row,Col) of upper left
SCG_02: CALL GRAMAP ; Convert (Row,Col) -> Chars
MOV DI,AX
POP DX
SUB DX,[BP+6] ; Chars to copy over
ADD DX,101h ; ...width of one char
SHL DH,1
SHL DH,1
MOV AL,[BP+3] ; Get command type
CMP Byte ptr DS:49h,6 ; ...is this 640 x 200?
JZ SCG_03 ; ...skip if so
SHL DL,1 ; Else bigger characters
SHL DI,1
CMP AL,7 ; Is this scroll down?
JNZ SCG_03 ; ...skip if not so
INC DI
SCG_03: CMP AL,7 ; Is this scroll down?
JNZ SCG_04 ; ...skip if not so
ADD DI,0F0h
SCG_04: MOV BL,[BP+2] ; Number of rows to blank
SHL BL,1
SHL BL,1
PUSH BX
SUB DH,BL ; Subtract from row count
MOV AL,50h
MUL BL
MOV BX,1FB0h
CMP Byte ptr [BP+3],6 ; Is this scroll up?
JZ SCG_05 ; ...skip if so
NEG AX ; Else do it
MOV BX,2050h
STD ; ...in reverse
SCG_05: MOV SI,DI ; End of area
ADD SI,AX ; ...start
POP AX
OR AL,AL
MOV CX,[BP+0]
MOV DS,CX
MOV ES,CX
JZ SCG_07 ; No rows to scroll
PUSH AX
SCG_06: MOV CH,0 ; Zero hi order byte count
MOV CL,DL ; ...bytes in row
PUSH SI
PUSH DI
REPZ MOVSB ; Copy one plane
POP DI
POP SI
ADD SI,2000h ; Load other grafix
ADD DI,2000h ; ...video plane
MOV CL,DL
PUSH SI
PUSH DI
REPZ MOVSB ; Copy other plane
POP DI
POP SI
SUB SI,BX
SUB DI,BX
DEC DH ; One less row to scroll
JNZ SCG_06 ; ...loop if more to do
POP AX
MOV DH,AL ; Load rows to blank
SCG_07: MOV AL,[BP+5] ; Get fill attribute
MOV CH,0
SCG_08: MOV CL,DL ; Get bytes per row
PUSH DI
REPZ STOSB ; Load row with fill attr.
POP DI
ADD DI,2000h ; Do other grafix video plane
MOV CL,DL
PUSH DI
REPZ STOSB ; Load row with fill attr.
POP DI
SUB DI,BX
DEC DH ; Show one less row to blank
JNZ SCG_08 ; ...loop if more to do
RET
CRT_8: ; Read attribute/character
CRT_9: ; Write attribute/character
CRT_10: CALL MODCHK ; Write character only
JB CG8_01 ; ... graphics operation
MOV BL,[BP+5] ; Get the display page
MOV BH,0
PUSH BX
CALL MPRC2C ; Convert Row,Col,Page -> Col
MOV DI,AX ; ...offset in DI
POP AX
MUL Word ptr DS:4Ch ; Page length X page number
ADD DI,AX ; ...current char. position
MOV SI,DI ; ...move into si
MOV DX,DS:63h ; Display port into DX
ADD DX,6 ; ...get status port
PUSH DS
MOV BX,[BP+0] ; BX --> regen. buffer
MOV DS,BX
MOV ES,BX
MOV AL,[BP+3] ; Get user (AH) func request
CMP AL,8
JNZ C9_01 ; ...skip if not read attr
C8_01: IN AL,DX ; Read CRT display status
TEST AL,00000001b ; ...test for hor. retrace
JNZ C8_01 ; Yes, wait for display on
CLI ; ...no interrupts now
C8_02: IN AL,DX ; Read CRT display status
TEST AL,00000001b ; ...test for hor. retrace
JZ C8_02 ; ...not yet, wait for it
LODSW ; Read character/attribute
POP DS
MOV [BP+2],AL ; Return character
MOV [BP+3],AH ; ..and attribute
RET
C9_01: MOV BL,[BP+2] ; Get char. to write
MOV BH,[BP+4] ; ...attribute
MOV CX,[BP+6] ; ...character count
CMP AL,0Ah ; Write char. only?
JZ CA_01 ; ...skip if so
C9_02: IN AL,DX ; Read CRT display status
TEST AL,00000001b ; ...test for hor. retrace
JNZ C9_02 ; Yes, wait for display on
CLI ; ...no interrupts now
C9_03: IN AL,DX ; Read CRT display status
TEST AL,00000001b ; ...test for hor. retrace
JZ C9_03 ; ...not yet, wait for it
MOV AX,BX ; Get char/attribute
STOSW ; ...write it
LOOP C9_02 ; ...loop for char. count
POP DS
RET
CA_01: IN AL,DX ; Read CRT display status
TEST AL,00000001b ; ...test for hor. retrace
JNZ CA_01 ; ...not yet, wait for it
CLI ; ...no interrupts now
CA_02: IN AL,DX ; Read CRT display status
TEST AL,00000001b ; ...test for hor. retrace
JZ CA_02 ; ...not yet, wait for it
MOV AL,BL ; Get character
STOSB ; ...write it
INC DI ; ...skip attribute
LOOP CA_01 ; ...loop for char. count
POP DS
RET
CG8_01: CMP Byte ptr [BP+3],8 ; Read graphics char/attr. ?
JNZ CG9_01 ; ...no, must be write
JMP CGR_01 ; Else read char/attr.
CG9_01: MOV AX,DS:50h ; Get cursor position
CALL GRAMAP ; ...convert (row,col) -> col
MOV DI,AX ; Save in displacement register
PUSH DS
MOV AL,[BP+2] ; Get character to write
MOV AH,0
OR AL,AL ; Is it user character set?
JS CG9_02 ; ...skip if so
MOV DX,CS ; Else use ROM character set
MOV SI,offset GRAFIX ; ...offset GRAFIX into SI
JMP short CG9_03
CG9_02: AND AL,7Fh ; Origin to zero
XOR BX,BX ; ...then go load
MOV DS,BX ; ...user grafix
LDS SI,Dword ptr DS:7Ch ; ...vector, offset in SI
MOV DX,DS ; ...segment into DX
CG9_03: POP DS ; Restore data segment
MOV CL,3 ; ...char 8 pixels wide
SHL AX,CL
ADD SI,AX ; Add regen. buffer base addr.
MOV AX,[BP+0] ; ...get regen buffer addr.
MOV ES,AX ; ...into ES
MOV CX,[BP+6] ; ...load char. count
CMP Byte ptr DS:49h,6 ; Is the mode 640 x 200 b/w?
PUSH DS
MOV DS,DX
JZ CG8_02 ; ...skip if so
SHL DI,1
MOV AL,[BP+4] ; Get char. attribute
AND AX,3
MOV BX,5555h
MUL BX
MOV DX,AX
MOV BL,[BP+4]
CG9_04: MOV BH,8 ; Char 8 pixels wide
PUSH DI
PUSH SI
CG9_05: LODSB ; Read the screen
PUSH CX
PUSH BX
XOR BX,BX
MOV CX,8
CG9_06: SHR AL,1 ; Shift bits thru byte
RCR BX,1
SAR BX,1
LOOP CG9_06
MOV AX,BX ; Result into AX
POP BX
POP CX
AND AX,DX
XCHG AH,AL
OR BL,BL
JNS CG9_07
XOR AX,ES:[DI]
CG9_07: MOV ES:[DI],AX ; Write new word
XOR DI,2000h
TEST DI,2000h ; Is this other plane?
JNZ CG9_08 ; ...nope
ADD DI,50h ; Else advance character
CG9_08: DEC BH ; Show another char written
JNZ CG9_05 ; ...more to go
POP SI
POP DI
INC DI
INC DI
LOOP CG9_04
POP DS
RET
CG8_02: MOV BL,[BP+4] ; Get display page
MOV DX,2000h ; ...size of grafix plane
CG8_03: MOV BH,8 ; Pixel count to write
PUSH DI
PUSH SI
CG8_04: LODSB ; Read from one plane
OR BL,BL ; ...done both planes?
JNS CG8_05 ; ...skip if not
XOR AL,ES:[DI] ; Else load attribute
CG8_05: MOV ES:[DI],AL ; Write out attribute
XOR DI,DX ; ...get other plane
TEST DI,DX ; Done both planes?
JNZ CG8_06 ; ...skip if not
ADD DI,50h ; Else position for now char
CG8_06: DEC BH ; Show row of pixels read
JNZ CG8_04 ; ...not done all of them
POP SI
POP DI
INC DI
LOOP CG8_03
POP DS
RET
CGR_01: CLD ; Increment upwards
MOV AX,DS:50h ; ...get cursor position
CALL GRAMAP ; Convert (row,col) -> columns
MOV SI,AX ; ...save in SI
SUB SP,8 ; Grab 8 bytes temp storage
MOV DI,SP ; ...save base in DI
CMP Byte ptr DS:49h,6 ; Mode 640 x 200 b/w?
MOV AX,[BP+0] ; ...AX --> CRT regen buffer
PUSH DS
PUSH DI
MOV DS,AX
JZ CGR_06 ; Mode is 640 x 200 b/w - skip
MOV DH,8 ; Eight pixels high/char
SHL SI,1
MOV BX,2000h ; Bytes per video plane
CGR_02: MOV AX,[SI] ; Read existing word
XCHG AH,AL
MOV CX,0C000h ; Attributes to scan for
MOV DL,0
CGR_03: TEST AX,CX ; Look for attributes
CLC
JZ CGR_04 ; ...set, skip
STC ; Else show not set
CGR_04: RCL DL,1
SHR CX,1
SHR CX,1
JNB CGR_03 ; ...more shifts to go
MOV SS:[DI],DL
INC DI
XOR SI,BX ; Do other video plane
TEST SI,BX ; ...done both planes?
JNZ CGR_05 ; ...no, skip
ADD SI,50h ; Else advance pointer
CGR_05: DEC DH ; Show another pixel row done
JNZ CGR_02 ; ...more rows to do
JMP short CGR_08
CGR_06: MOV DH,4 ; Mode 640 x 200 b/w - special
CGR_07: MOV AH,[SI] ; Read pixels from one plane
MOV SS:[DI],AH ; ...save on stack
INC DI ; ...advance
MOV AH,[SI+2000h] ; Read pixels from other plane
MOV SS:[DI],AH ; Save pixels on stack
INC DI ; ...advance
ADD SI,50h ; Total pixels in char
DEC DH ; ...another row processed
JNZ CGR_07 ; ...more to do
CGR_08: MOV DX,CS ; Load segment of grafix char
MOV DI,offset GRAFIX ; ...and offset
MOV ES,DX ; ...save offset in ES
MOV DX,SS
MOV DS,DX
POP SI
MOV AL,0
CGR_09: MOV DX,80h ; Number of char. in grafix set
CGR_10: PUSH SI
PUSH DI
MOV CX,8 ; Bytes to compare for char
REPZ CMPSB ; ...do compare
POP DI
POP SI
JZ CGR_11 ; Found grafix character
INC AL ; ...else show another char
ADD DI,8 ; ...advance one row
DEC DX ; ...one less char to scan
JNZ CGR_10 ; Loop if more char left
OR AL,AL ; User grafix character set?
JZ CGR_11 ; ...no, not found
XOR BX,BX
MOV DS,BX
LES DI,Dword ptr DS:7Ch ; Else load user grafix char
MOV BX,ES
OR BX,DI
JZ CGR_11 ; ...not found
JMP short CGR_09 ; Try using user grafix char
CGR_11: MOV [BP+2],AL ; Return char in user AL
POP DS
ADD SP,8 ; ...return temp storage
RET
CRT_11: MOV DX,DS:63h ; Set color, get CGA card port
ADD DX,5 ; ...color select register
MOV AL,DS:66h ; Get CRT palette
MOV AH,[BP+5] ; ...new palette ID, user BH
OR AH,AH
MOV AH,[BP+4] ; ...new palette color, user BL
JNZ C_PAL1 ; Palette ID specified, skip
AND AL,0E0h
AND AH,1Fh ; Null ID = ID 01Fh
OR AL,AH ; ...set in color
JMP short C_PAL2
C_PAL1: AND AL,0DFh
TEST AH,1
JZ C_PAL2
OR AL,20h
C_PAL2: MOV DS:66h,AL ; Save new palette
OUT DX,AL ; ...tell CGA about it
RET
CRT_12: MOV AX,[BP+0] ; Write pixel
MOV ES,AX
MOV DX,[BP+8] ; Load row from user DX
MOV CX,[BP+6] ; ... col from user CX
CALL LOCDOT ; Find dot offset
JNZ WD_01 ; ...valid
MOV AL,[BP+2] ; Load user color
MOV BL,AL
AND AL,1
ROR AL,1
MOV AH,7Fh
JMP short WD_02
WD_01: SHL CL,1
MOV AL,[BP+2]
MOV BL,AL
AND AL,3
ROR AL,1
ROR AL,1
MOV AH,3Fh
WD_02: ROR AH,CL
SHR AL,CL
MOV CL,ES:[SI] ; Read the char with the dot
OR BL,BL
JNS WD_03
XOR CL,AL ; Exclusive or existing color
JMP short WD_04
WD_03: AND CL,AH ; Set new color for dot
OR CL,AL
WD_04: MOV ES:[SI],CL ; Write out char with the dot
RET
CRT_13: MOV AX,[BP+0] ; AX --> video regen buffer
MOV ES,AX ; ...into ES segment
MOV DX,[BP+8] ; Load row from user DX
MOV CX,[BP+6] ; ... col from user CX
CALL LOCDOT ; Calculate dot offset
MOV AL,ES:[SI] ; ...read dot
JNZ RD_01 ; ...was there
SHL AL,CL
ROL AL,1
AND AL,1
JMP short RD_02
RD_01: SHL CL,1 ; Calculate offset in char
SHL AL,CL
ROL AL,1
ROL AL,1
AND AL,3
RD_02: MOV [BP+2],AL ; Return dot pos in user AL
RET
CRT_14: MOV BL,DS:62h ; Get active video page (0-7)
SHL BL,1 ; ...as word index
MOV BH,0 ; ...clear hi order
MOV DX,[BX+50h] ; Index into cursor position
MOV AL,[BP+2] ; Get char. to write
CMP AL,8 ; ...back space?
JZ TTY_BS ; ...skip if so
CMP AL,LF ; Is it a carriage return
JZ TTY_LF ; ...skip if so
CMP AL,7 ; Print a bell?
JZ BLIP ; ...do beep
CMP AL,CR ; Is it a line feed?
JZ TTY_CR ; ...skip if so
MOV BL,[BP+4] ; Else write at cur pos
MOV AH,0Ah
MOV CX,1 ; ...one time
INT 10h
INC DL ; Advance cursor
CMP DL,DS:4Ah ; ...check for line overflow
JNZ TTYPOS
MOV DL,0 ; Overflowed, then fake
JMP short TTY_LF ; ...new line
TTY_BS: CMP DL,0 ; At start of line?
JZ TTYPOS ; ...skip if so
DEC DL ; Else back up
JMP short TTYPOS ; ...join common code
BLIP: MOV BL,2 ; Do a short
CALL BEEP ; ...beep
RET
TTY_CR: MOV DL,0 ; Position to start of line
; JMP short TTYPOS
TTYPOS: MOV BL,DS:62h ; Get active video page (0-7)
SHL BL,1 ; ...as word index
MOV BH,0 ; ...clear hi order
MOV [BX+50h],DX ; Remember the cursor position
JMP SETCUR ; ...set 6845 cursor hardware
TTY_LF: CMP DH,18h ; Done all 24 lines on page?
JZ TTY_L1 ; ...yes, scroll
INC DH ; Else advance line
JNZ TTYPOS
TTY_L1: MOV AH,2 ; Position cursor at line start
INT 10h
CALL MODCHK ; Is this text mode?
MOV BH,0
JB TTY_L2 ; Skip if text mode
MOV AH,8
INT 10h ; ...else read attribute
MOV BH,AH
TTY_L2: MOV AH,6 ; Now prepare to
MOV AL,1 ; ...scroll
XOR CX,CX ; ...the
MOV DH,18h ; ...page
MOV DL,DS:4Ah ; ...up
DEC DL
INT 10h
RET
CRT_15: MOV AL,DS:4Ah ; Get current video state
MOV [BP+3],AL ; ...columns
MOV AL,DS:49h
MOV [BP+2],AL ; ...mode
MOV AL,DS:62h
MOV [BP+5],AL ; ...page
RET
MODCHK: PUSH AX ; Set flags acc. to cur. mode
MOV AL,DS:49h ; ...get mode
CMP AL,7 ; ...EQU if mono
JZ MODCH1
CMP AL,4
CMC
JNB MODCH1 ; ...carry set on graphix
SBB AL,AL
STC
MODCH1: POP AX
RET
LOCDOT: MOV AL,50h ; Dots in char. position
XOR SI,SI
SHR DL,1 ; Two bytes/char. position
JNB LOCDO1 ; ...not overflow
MOV SI,2000h ; Else on other video plane
LOCDO1: MUL DL ; Multiply position by row
ADD SI,AX ; ...add in column position
MOV DX,CX ; Copy column position
MOV CX,302h ; ...regular char size
CMP Byte ptr DS:49h,6 ; Mode 640 x 200, b/w?
PUSHF
JNZ LOCDO2 ; ...skip if not
MOV CX,703h ; Else special char. size
LOCDO2: AND CH,DL
SHR DX,CL
ADD SI,DX
XCHG CL,CH
POPF
RET
PENXY: CALL PENXY1 ; Read light pen position HI
MOV CH,AL ; ...save in CH
INC AH
CALL PENXY1 ; Read light pen position LO
MOV CL,AL ; ...save in CL
RET
PENXY1: PUSH DX ; Read CRT register offset AL
MOV DX,DS:63h ; ...get active CRT port
XCHG AL,AH
OUT DX,AL ; Send initialization byte
INC DL ; ...increment
IN AL,DX ; Read pen position byte back
POP DX
RET
MPRC2C: MOV BH,0 ; Convert Row,Col,Page -> Col
SHL BX,1 ; ...two bytes/column
MOV AX,[BX+50h] ; Get page number in AX
; ...join common code
RC2COL: PUSH BX ; Map (AH=row,AL=COL) to COL
MOV BL,AL
MOV AL,AH
MUL Byte ptr DS:4Ah ; Multiply ROW x (Row/Column)
MOV BH,0
ADD AX,BX ; ...add in existing COL
SHL AX,1 ; ...times 2 cause 2 bytes/col
POP BX
RET
GRAMAP: PUSH BX ; Convert (row,col) -> col
MOV BL,AL ; ...save column
MOV AL,AH ; ...get row
MUL Byte ptr DS:4Ah ; Multiply by columns/row
SHL AX,1
SHL AX,1
MOV BH,0
ADD AX,BX ; Add in columns
POP BX
RET
SETCUR: SHR BL,1 ; Sets 6845 cursor position
CMP DS:62h,BL ; ...is this page visible?
JNZ SEND01 ; No, do nothing in hardware
MOVCUR: CALL MPRC2C ; Map row,col,page to col
ADD AX,DS:4Eh ; + byte offset, regen reg.
SHR AX,1
MOV CX,AX
MOV AH,0Eh ; Tell 6845 video controller
; ...to position the cursor
OT6845: MOV AL,CH ; Send CH,CL thru CRT reg AH
CALL SENDAX ; ...send CH
INC AH ; ...increment
MOV AL,CL ; ...send CL
SENDAX: PUSH DX
MOV DX,DS:63h ; Load active video port
XCHG AL,AH
OUT DX,AL ; Send hi order
XCHG AL,AH
INC DL
OUT DX,AL ; ... lo order
POP DX
SEND01: RET
ENTRY 0F841h ; IBM entry for memory size
INT_12: STI ; Kbytes of memory present
PUSH DS
MOV AX,40h
MOV DS,AX
MOV AX,DS:13h ; AX = memory size, kilobytes
POP DS
IRET
ENTRY 0F84Dh ; IBM entry for equipment check
INT_11: STI ; Equipment present
PUSH DS
MOV AX,40h
MOV DS,AX
MOV AX,DS:10h ; AX = equipment byte contents
POP DS
IRET
ENTRY 0F859h ; IBM entry for cassette int.
INT_15: STC ; Cassette service (error ret)
MOV AH,86h
RETF 2
ENTRY 0F85Fh ; IBM non-maskable int. entry
INT_2: PUSH AX ; Non-maskable interrupt
IN AL,62h
TEST AL,11000000b ; Get cause of interrupt
JNZ PAR_01 ; ...parity error
JMP PAR_07 ; ...math coprocessor (?)
PAR_01: PUSH BX ; Parity error bomb
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
PUSH DS
PUSH ES
MOV AX,40h ; Load data segment
MOV DS,AX
CALL V_INIT ; ...clear/init screen
PUSH DS
PUSH CS ; Point DS at ROM
POP DS
MOV SI,offset BOMB_1 ; SI --> Parity message
CALL PRINT ; ...print
POP DS ; ...restore DS
MOV AX,11h ; Back cursor over ? marks
CALL LOCATE ; ...with call
MOV AL,0
OUT 0A0h,AL ; ...disable NMI interrupts
MOV DX,61h
IN AL,DX ; Get machine flags
OR AL,00110000b ; ...disable parity int.
OUT DX,AL ; Put out new flags
AND AL,11001111b ; ...enable parity int.
OUT DX,AL ; Put out new flags
MOV CL,6
MOV BX,DS:13h ; Get memory size (K bytes)
SHL BX,CL
INC DX ; ...now paragraphs
XOR AX,AX
MOV DS,AX
PAR_02: MOV CX,10h ; Iterations to check
XOR SI,SI
PAR_03: MOV AH,[SI] ; Read the byte (dummy)
IN AL,DX ; ...and read status
TEST AL,11000000b ; ...to see what happened
JNZ PAR_04 ; Read caused parity error
INC SI ; ...else advance pointer
LOOP PAR_03 ; ...and try next byte
MOV AX,DS
INC AX ; ...next paragraph
MOV DS,AX
CMP AX,BX
JNZ PAR_02 ; More paragraphs to check
JMP short PAR_05 ; ...else flakey error
PAR_04: MOV [SI],AH ; Save offset in paragraph
MOV AX,DS
CALL BIGNUM ; Print segment
MOV AX,SI
CALL DIGIT ; Print offset
PAR_05: MOV AX,16h ; Where to position cursor
CALL LOCATE ; ...position cursor
PUSH DS
PUSH CS
POP DS
MOV SI,offset BOMB_2 ; Continue ?
CALL PRINT ; ...ask the user
POP DS
IN AL,21h ; Get interrupt masks
PUSH AX ; ...save them
MOV AL,11111100b
OUT 21h,AL ; Disable all but keyboard
STI ; ...enable interrupt system
CALL GETCH ; Get keyboard character
PUSH AX ; ...save it
CALL OUTCHR ; Print ascii character
POP AX ; ...restore
CMP AL,'Y' ; User wants to continue
JZ PAR_06 ; ...stupid answer
CMP AL,'y' ; Look for little case "y"
JZ PAR_06 ; ...stupid answer
JMP COLD ; Retry on cold reboot
PAR_06: CALL BLANK ; Clear display
POP AX
OUT 21h,AL ; Restore interrupt system state
MOV DX,61h ; Dismiss the NMI interrupt
IN AL,DX ; ...read in machine flags
OR AL,00110000b
OUT DX,AL ; Write out, parity disabled
AND AL,11001111b ; ...clears parity error
OUT DX,AL ; Write out, parity enabled
MOV AL,80h
OUT 0A0h,AL ; Enable NMI interrupts
POP ES
POP DS
POP BP
POP DI
POP SI
POP DX
POP CX
POP BX
PAR_07: POP AX
IRET
BOMB_1 db 'Parity error at: ?????',0
BOMB_2 db ' Cont?',0
NUMBER: PUSH AX ; Save number
MOV CL,4
SHR AL,CL
CALL DIGIT ; Out first digit
POP AX
CALL DIGIT ; Out second digit
RET
BIGNUM: PUSH AX ; Unsigned word
MOV AL,AH
CALL NUMBER
POP AX
CALL NUMBER
RET
OUTCHR: PUSH BX
PUSH AX
MOV AH,0Eh ; Teletype print service
MOV BL,7 ; ...normal intensity
INT 10h
POP AX
POP BX
RET
DIGIT: PUSH AX ; Print hex digit in AL
AND AL,0Fh
CMP AL,9
JBE D_01
ADD AL,'A'-'9'-1
D_01: ADD AL,'0' ; Make ascii digit
CALL OUTCHR ; ...print it
POP AX
RET
MOV AL,CR ; Print carriage return
CALL OUTCHR ; ...on screen
MOV AL,LF ; Print line feed
CALL OUTCHR ; ...on screen
RET
GETCH: MOV AH,0 ; Read keyboard key
INT 16h
RET
PRINT: LODSB ; Print zero terminated string
OR AL,AL
JNZ PRINT1 ; ...not terminator in AX
RET
PRINT1: CALL OUTCHR ; Print character in AX
JMP PRINT ; ...back for more
BEEP: PUSH AX
PUSH CX
MOV AL,10110110b ; Timer ic 8253 square waves
OUT 43h,AL ; ...channel 2, speaker
MOV AX,528h ; Get countdown constant word
OUT 42h,AL ; ...send lo order
MOV AL,AH ; ...load hi order
OUT 42h,AL ; ...send hi order
IN AL,61h ; Read ic 8255 machine status
PUSH AX
OR AL,00000011b
OUT 61h,AL ; Turn speaker on
XOR CX,CX
BEEP_1: LOOP BEEP_1
DEC BL
JNZ BEEP_1
POP AX
OUT 61h,AL ; Turn speaker off
POP CX
POP AX
RET
V_INIT: MOV AH,DS:10h ; Get equipment byte
AND AH,00110000b ; ...extract CRT
MOV AL,0 ; ...null lo
CMP AH,00110000b ; Monochrome?
JZ LF9D9 ; ...yes
MOV AL,1 ; CGA 40 x 25?
CMP AH,00010000b ; ...yes
JZ LF9D9 ; CGA 80 x 25?
MOV AL,3 ; ...yes
LF9D9: MOV AH,0 ; Setup subfunction
INT 10h ; ...to video
RET
BLANK: MOV DX,184Fh ; Lower right corner of scroll
XOR CX,CX ; Upper left corner of scroll
MOV AX,600h ; Blank entire window
MOV BH,7 ; Set regular cursor
INT 10h ; Call video service scroll
MOV AH,2 ; Set cursor position
XOR DX,DX ; ...upper left corner
MOV BH,0 ; ...page 0
INT 10h ; ...call video service
RET
LOCATE: PUSH DX
PUSH BX
MOV DX,AX ; Get position for cursor
MOV AH,2
MOV BH,0 ; ...page 0
INT 10h
POP BX
POP DX
RET
CHKSUM: MOV CX,2000h ; Bytes in 2764 eprom
CHK_01: MOV AL,0 ; ...zero checksum
ADDBYT: ADD AL,[BX] ; Add byte to checksum
INC BX ; ...BX --> next byte
LOOP ADDBYT ; ...loop until done
OR AL,AL ; Set condition codes
RET ; ...and return
MEMTST: MOV BX,0400h ; Load bytes to test
MOV AL,55h
;
PAT_1: XOR DI,DI ; Pattern #1, 55h bytes
MOV CX,BX
REPZ STOSB ; Fill memory, pattern #1
XOR DI,DI
MOV CX,BX
REPZ SCASB ; Scan memory for NOT pattern #1
JCXZ PAT_2
STC ; ...flunked
RET
PAT_2: XOR DI,DI ; Pattern #2 - 0AAh bytes
MOV CX,BX
NOT AL
REPZ STOSB ; Fill memory, pattern #2
XOR DI,DI
MOV CX,BX
REPZ SCASB ; Scan memory for NOT pattern #2
JCXZ PAT_3
STC ; ...flunked
RET
PAT_3: XOR DI,DI ; Pattern #3 - 01h bytes
MOV CX,BX
MOV AL,1
REPZ STOSB ; Fill memory, pattern #3
XOR DI,DI
MOV CX,BX
REPZ SCASB ; Scan memory for NOT pattern #3
JCXZ PAT_4
STC ; ...flunked
RET
PAT_4: XOR DI,DI ; Pattern #4 - 0h bytes
MOV CX,BX
DEC AL
REPZ STOSB ; Fill memory, pattern #4
XOR DI,DI
MOV CX,BX
REPZ SCASB ; Scan memory for NOT pattern #4
JCXZ LFA59
STC ; ...flunked
RET
LFA59: MOV AX,ES
ADD AX,40h ; Add 40h to segment number
MOV ES,AX
RET ; ...passed
ENTRY 0FA6Eh ; IBM graphics char set entry
GRAFIX db 000h,000h,000h,000h ; Graphics character set
db 000h,000h,000h,000h
db 07Eh,081h,0A5h,081h
db 0BDh,099h,081h,07Eh
db 07Eh,0FFh,0DBh,0FFh
db 0C3h,0E7h,0FFh,07Eh
db 06Ch,0FEh,0FEh,0FEh
db 07Ch,038h,010h,000h
db 010h,038h,07Ch,0FEh
db 07Ch,038h,010h,000h
db 038h,07Ch,038h,0FEh
db 0FEh,07Ch,038h,07Ch
db 010h,010h,038h,07Ch
db 0FEh,07Ch,038h,07Ch
db 000h,000h,018h,03Ch
db 03Ch,018h,000h,000h
db 0FFh,0FFh,0E7h,0C3h
db 0C3h,0E7h,0FFh,0FFh
db 000h,03Ch,066h,042h
db 042h,066h,03Ch,000h
db 0FFh,0C3h,099h,0BDh
db 0BDh,099h,0C3h,0FFh
db 00Fh,007h,00Fh,07Dh
db 0CCh,0CCh,0CCh,078h
db 03Ch,066h,066h,066h
db 03Ch,018h,07Eh,018h
db 03Fh,033h,03Fh,030h
db 030h,070h,0F0h,0E0h
db 07Fh,063h,07Fh,063h
db 063h,067h,0E6h,0C0h
db 099h,05Ah,03Ch,0E7h
db 0E7h,03Ch,05Ah,099h
db 080h,0E0h,0F8h,0FEh
db 0F8h,0E0h,080h,000h
db 002h,00Eh,03Eh,0FEh
db 03Eh,00Eh,002h,000h
db 018h,03Ch,07Eh,018h
db 018h,07Eh,03Ch,018h
db 066h,066h,066h,066h
db 066h,000h,066h,000h
db 07Fh,0DBh,0DBh,07Bh
db 01Bh,01Bh,01Bh,000h
db 03Eh,063h,038h,06Ch
db 06Ch,038h,0CCh,078h
db 000h,000h,000h,000h
db 07Eh,07Eh,07Eh,000h
db 018h,03Ch,07Eh,018h
db 07Eh,03Ch,018h,0FFh
db 018h,03Ch,07Eh,018h
db 018h,018h,018h,000h
db 018h,018h,018h,018h
db 07Eh,03Ch,018h,000h
db 000h,018h,00Ch,0FEh
db 00Ch,018h,000h,000h
db 000h,030h,060h,0FEh
db 060h,030h,000h,000h
db 000h,000h,0C0h,0C0h
db 0C0h,0FEh,000h,000h
db 000h,024h,066h,0FFh
db 066h,024h,000h,000h
db 000h,018h,03Ch,07Eh
db 0FFh,0FFh,000h,000h
db 000h,0FFh,0FFh,07Eh
db 03Ch,018h,000h,000h
db 000h,000h,000h,000h
db 000h,000h,000h,000h
db 030h,078h,078h,030h
db 030h,000h,030h,000h
db 06Ch,06Ch,06Ch,000h
db 000h,000h,000h,000h
db 06Ch,06Ch,0FEh,06Ch
db 0FEh,06Ch,06Ch,000h
db 030h,07Ch,0C0h,078h
db 00Ch,0F8h,030h,000h
db 000h,0C6h,0CCh,018h
db 030h,066h,0C6h,000h
db 038h,06Ch,038h,076h
db 0DCh,0CCh,076h,000h
db 060h,060h,0C0h,000h
db 000h,000h,000h,000h
db 018h,030h,060h,060h
db 060h,030h,018h,000h
db 060h,030h,018h,018h
db 018h,030h,060h,000h
db 000h,066h,03Ch,0FFh
db 03Ch,066h,000h,000h
db 000h,030h,030h,0FCh
db 030h,030h,000h,000h
db 000h,000h,000h,000h
db 000h,030h,030h,060h
db 000h,000h,000h,0FCh
db 000h,000h,000h,000h
db 000h,000h,000h,000h
db 000h,030h,030h,000h
db 006h,00Ch,018h,030h
db 060h,0C0h,080h,000h
db 07Ch,0C6h,0CEh,0DEh
db 0F6h,0E6h,07Ch,000h
db 030h,070h,030h,030h
db 030h,030h,0FCh,000h
db 078h,0CCh,00Ch,038h
db 060h,0CCh,0FCh,000h
db 078h,0CCh,00Ch,038h
db 00Ch,0CCh,078h,000h
db 01Ch,03Ch,06Ch,0CCh
db 0FEh,00Ch,01Eh,000h
db 0FCh,0C0h,0F8h,00Ch
db 00Ch,0CCh,078h,000h
db 038h,060h,0C0h,0F8h
db 0CCh,0CCh,078h,000h
db 0FCh,0CCh,00Ch,018h
db 030h,030h,030h,000h
db 078h,0CCh,0CCh,078h
db 0CCh,0CCh,078h,000h
db 078h,0CCh,0CCh,07Ch
db 00Ch,018h,070h,000h
db 000h,030h,030h,000h
db 000h,030h,030h,000h
db 000h,030h,030h,000h
db 000h,030h,030h,060h
db 018h,030h,060h,0C0h
db 060h,030h,018h,000h
db 000h,000h,0FCh,000h
db 000h,0FCh,000h,000h
db 060h,030h,018h,00Ch
db 018h,030h,060h,000h
db 078h,0CCh,00Ch,018h
db 030h,000h,030h,000h
db 07Ch,0C6h,0DEh,0DEh
db 0DEh,0C0h,078h,000h
db 030h,078h,0CCh,0CCh
db 0FCh,0CCh,0CCh,000h
db 0FCh,066h,066h,07Ch
db 066h,066h,0FCh,000h
db 03Ch,066h,0C0h,0C0h
db 0C0h,066h,03Ch,000h
db 0F8h,06Ch,066h,066h
db 066h,06Ch,0F8h,000h
db 0FEh,062h,068h,078h
db 068h,062h,0FEh,000h
db 0FEh,062h,068h,078h
db 068h,060h,0F0h,000h
db 03Ch,066h,0C0h,0C0h
db 0CEh,066h,03Eh,000h
db 0CCh,0CCh,0CCh,0FCh
db 0CCh,0CCh,0CCh,000h
db 078h,030h,030h,030h
db 030h,030h,078h,000h
db 01Eh,00Ch,00Ch,00Ch
db 0CCh,0CCh,078h,000h
db 0E6h,066h,06Ch,078h
db 06Ch,066h,0E6h,000h
db 0F0h,060h,060h,060h
db 062h,066h,0FEh,000h
db 0C6h,0EEh,0FEh,0FEh
db 0D6h,0C6h,0C6h,000h
db 0C6h,0E6h,0F6h,0DEh
db 0CEh,0C6h,0C6h,000h
db 038h,06Ch,0C6h,0C6h
db 0C6h,06Ch,038h,000h
db 0FCh,066h,066h,07Ch
db 060h,060h,0F0h,000h
db 078h,0CCh,0CCh,0CCh
db 0DCh,078h,01Ch,000h
db 0FCh,066h,066h,07Ch
db 06Ch,066h,0E6h,000h
db 078h,0CCh,0E0h,070h
db 01Ch,0CCh,078h,000h
db 0FCh,0B4h,030h,030h
db 030h,030h,078h,000h
db 0CCh,0CCh,0CCh,0CCh
db 0CCh,0CCh,0FCh,000h
db 0CCh,0CCh,0CCh,0CCh
db 0CCH,078h,030h,000h
db 0C6h,0C6h,0C6h,0D6h
db 0FEh,0EEh,0C6h,000h
db 0C6h,0C6h,06Ch,038h
db 038h,06Ch,0C6h,000h
db 0CCh,0CCh,0CCh,078h
db 030h,030h,078h,000h
db 0FEh,0C6h,08Ch,018h
db 032h,066h,0FEh,000h
db 078h,060h,060h,060h
db 060h,060h,078h,000h
db 0C0h,060h,030h,018h
db 00Ch,006h,002h,000h
db 078h,018h,018h,018h
db 018h,018h,078h,000h
db 010h,038h,06Ch,0C6h
db 000h,000h,000h,000h
db 000h,000h,000h,000h
db 000h,000h,000h,0FFh
db 030h,030h,018h,000h
db 000h,000h,000h,000h
db 000h,000h,078h,00Ch
db 07Ch,0CCh,076h,000h
db 0E0h,060h,060h,07Ch
db 066h,066h,0DCh,000h
db 000h,000h,078h,0CCh
db 0C0h,0CCh,078h,000h
db 01Ch,00Ch,00Ch,07Ch
db 0CCh,0CCh,076h,000h
db 000h,000h,078h,0CCh
db 0FCh,0C0h,078h,000h
db 038h,06Ch,060h,0F0h
db 060h,060h,0F0h,000h
db 000h,000h,076h,0CCh
db 0CCh,07Ch,00Ch,0F8h
db 0E0h,060h,06Ch,076h
db 066h,066h,0E6h,000h
db 030h,000h,070h,030h
db 030h,030h,078h,000h
db 00Ch,000h,00Ch,00Ch
db 00Ch,0CCh,0CCh,078h
db 0E0h,060h,066h,06Ch
db 078h,06Ch,0E6h,000h
db 070h,030h,030h,030h
db 030h,030h,078h,000h
db 000h,000h,0CCh,0FEh
db 0FEh,0D6h,0C6h,000h
db 000h,000h,0F8h,0CCh
db 0CCh,0CCh,0CCh,000h
db 000h,000h,078h,0CCh
db 0CCh,0CCh,078h,000h
db 000h,000h,0DCh,066h
db 066h,07Ch,060h,0F0h
db 000h,000h,076h,0CCh
db 0CCh,07Ch,00Ch,01Eh
db 000h,000h,0DCh,076h
db 066h,060h,0F0h,000h
db 000h,000h,07Ch,0C0h
db 078h,00Ch,0F8h,000h
db 010h,030h,07Ch,030h
db 030h,034h,018h,000h
db 000h,000h,0CCh,0CCh
db 0CCh,0CCh,076h,000h
db 000h,000h,0CCh,0CCh
db 0CCh,078h,030h,000h
db 000h,000h,0C6h,0D6h
db 0FEh,0FEh,06Ch,000h
db 000h,000h,0C6h,06Ch
db 038h,06Ch,0C6h,000h
db 000h,000h,0CCh,0CCh
db 0CCh,07Ch,00Ch,0F8h
db 000h,000h,0FCh,098h
db 030h,064h,0FCh,000h
db 01Ch,030h,030h,0E0h
db 030h,030h,01Ch,000h
db 018h,018h,018h,000h
db 018h,018h,018h,000h
db 0E0h,030h,030h,01Ch
db 030h,030h,0E0h,000h
db 076h,0DCh,000h,000h
db 000h,000h,000h,000h
db 000h,010h,038h,06Ch
db 0C6h,0C6h,0FEh,000h
ENTRY 0FE6Eh ; IBM entry, time_of_day clock
INT_1A: STI ; User time_of_day bios service
PUSH DS
PUSH AX
MOV AX,40h
MOV DS,AX
POP AX ; Get request type
CLI ; ...freeze clock
OR AH,AH
JZ TD_01 ; Read time, AH=0
DEC AH
JNZ TD_02 ; ...invalid request
MOV DS:6Ch,DX ; Set time, AH=1
MOV DS:6Eh,CX ; ...set time hi
MOV Byte ptr DS:70h,0 ; ...not a new day
JMP short TD_02
TD_01: MOV CX,DS:6Eh ; Read lo order time
MOV DX,DS:6Ch ; ... hi order time
CALL TD_03 ; Read resets overflow
TD_02: STI ; Unfreeze clock
POP DS
IRET
TD_03: MOV AL,DS:70h ; Zero the overflow and return
XOR DS:70h,AL ; ...previous status in flags
RET
ENTRY 0FEA5h ; IBM entry, hardware clock
INT_8: STI ; Routine services clock tick
PUSH DS
PUSH DX
PUSH AX
MOV AX,40h
MOV DS,AX
DEC Byte ptr DS:40h ; Decrement motor count
JNZ TI_01 ; ...not time to shut off
AND Byte ptr DS:3Fh,11110000b ; Else show motor off
MOV AL,0Ch ; ...send motor off
MOV DX,3F2h ; ...to the floppy
OUT DX,AL ; ...disk controller
TI_01: INC Word ptr DS:6Ch ; Bump lo order time of day
JNZ TI_02 ; ...no carry
INC Word ptr DS:6Eh ; Bump hi order time of day
TI_02: CMP Word ptr DS:6Eh,18h ; Is it midnight yet?
JNZ TI_03 ; ...no
CMP Word ptr DS:6Ch,0B0h ; Possibly, check lo order
JNZ TI_03 ; ...not midnight
MOV Word ptr DS:6Eh,0 ; Midnight, reset hi order
MOV Word ptr DS:6Ch,0 ; ...lo order ticks
MOV Byte ptr DS:70h,1 ; Show new day since last read
TI_03: INT 1Ch ; Execute user clock service
MOV AL,20h ; ...send end_of_interrupt
OUT 20h,AL ; ...to 8259 interrupt chip
POP AX
POP DX
POP DS
IRET
ENTRY 0FEF3h ; IBM entry, time_of_day clock
VECTORS dw int_8 ; Timer tick
dw int_9 ; Key attention
dw IGNORE ; Reserved
dw IGNORE ; Reserved for COM2 serial i/o
dw IGNORE ; Reserved for COM1 serial i/o
dw IGNORE ; Reserved for hard disk attn.
dw int_e ; Floppy disk attention
dw IGNORE ; Reserved for parallel printer
dw int_10 ; Video bios services
dw int_11 ; Equipment present
dw int_12 ; Memories present
dw int_13 ; Disk bios services
dw int_14 ; Serial com. services
dw int_15 ; Cassette bios services
dw int_16 ; Keyboard bios services
dw int_17 ; Parallel printer services
dw IGNORE ; rom Basic (setup later)
dw int_19 ; Bootstrap
dw int_1a ; Timer bios services
dw DUMMY ; Keyboard break user service
dw DUMMY ; System tick user service
dw int_1d ; Video parameter table
dw int_1e ; Disk parameter table
dw ? ; Graphic charactr table ptr
ENTRY 0FF23h ; IBM entry, nonsense interrupt
IGNORE: PUSH DS ; Unexpected interrupts go here
PUSH DX
PUSH AX
MOV AX,40h
MOV DS,AX
MOV AL,0Bh ; What IRQ caused this?
OUT 20h,AL
NOP
IN AL,20h ; ...(read IRQ level)
MOV AH,AL
OR AL,AL
JNZ DU_1
MOV AL,0FFh ; Not hardware, say 0FFh IRQ
JMP short DU_2
DU_1: IN AL,21h ; Clear the IRQ
OR AL,AH
OUT 21h,AL
MOV AL,20h ; Send end_of_interrupt code
OUT 20h,AL ; ...to 8259 interrupt chip
DU_2: MOV DS:6Bh,AH ; Save last nonsense interrupt
POP AX
POP DX
POP DS
IRET
ENTRY 0FF53h ; IBM entry, dummy interrupts
;INT_1B: ; Keyboard break user service
;INT_1C: ; Clock tick user service
DUMMY: IRET
ENTRY 0FF54h ; IBM entry, print screen
INT_5: STI ; Print screen service
PUSH DS
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AX,40h
MOV DS,AX
CMP Byte ptr DS:100h,1 ; Print screen in progress?
JZ PS_5 ; ...yes, ignore
MOV Byte ptr DS:100h,1 ; Flag print screen in progress
CALL P_CRLF ; ...begin new line
MOV AH,0Fh
INT 10h ; Get current video state
PUSH AX ; ...save it
MOV AH,3
INT 10h ; Read cursor position
POP AX ; ...retrieve video state
PUSH DX ; ...save cursor position
MOV CH,19h ; Do 25 rows
MOV CL,AH ; ...columns in current mode
XOR DX,DX ; Start printing from (0,0)
PS_1: MOV AH,2 ; Set cursor to position
INT 10h
MOV AH,8 ; ...and read character
INT 10h
OR AL,AL ; Nulls are special case
JNZ PS_2
MOV AL,' ' ; ...convert to spaces
PS_2: PUSH DX
XOR DX,DX
MOV AH,DL ; Function=Print character
INT 17h
POP DX
TEST AH,00100101b ; Successful print
JZ PS_3
MOV Byte ptr DS:100h,0FFh ; No, error in Print Screen
JMP short PS_4
PS_3: INC DL ; Increment column count
CMP CL,DL
JNZ PS_1 ; ...in range, continue
MOV DL,0
CALL P_CRLF ; Else print new line
INC DH ; ...add another row
CMP DH,CH ; Done all 25 rows?
JNZ PS_1 ; ...no, continue
MOV Byte ptr DS:100h,0 ; Show done Print Screen OK
PS_4: POP DX ; Get saved cursor position
MOV AH,2
INT 10h ; ...restore it
PS_5: POP DX
POP CX
POP BX
POP AX
POP DS
IRET
ENTRY 0FFCBh ; IBM entry, display CR, LF
P_CRLF: PUSH DX ; Print CR, LF, on line printer
XOR DX,DX
MOV AH,DL ; Function=print
MOV AL,LF ; LF
INT 17h
MOV AH,0
MOV AL,CR ; CR
INT 17h
POP DX
RET
;******************************************************************************
ENTRY 0FFF0h ; Hardware power reset entry *
PUBLIC POWER ; ...ic "8088" or "V20" *
POWER: JMPF 0F000h,COLD ; ...begins here on power up *
;******************************************************************************
ENTRY 0FFF5h ; Release date, Yankee style
db "08/23/87" ; ...MM/DD/YY (not logical)
ENTRY 0FFFEh
db 0FEh ; Computer type (XT)
; db ? ; Checksum byte
code ENDS
;
END