0% found this document useful (0 votes)
7 views

BIOS1

This document provides an update on the BIOS.ASM for Intel 8088 or NEC V20 turbo motherboards, detailing its compatibility with IBM-PC/XT and similar systems. It includes instructions for patching the BIOS, error messages, and memory definitions, as well as assembly code for initializing the BIOS. The document also outlines the structure of the BIOS and the necessary steps for compiling and linking the BIOS source code.

Uploaded by

soufsoftware
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

BIOS1

This document provides an update on the BIOS.ASM for Intel 8088 or NEC V20 turbo motherboards, detailing its compatibility with IBM-PC/XT and similar systems. It includes instructions for patching the BIOS, error messages, and memory definitions, as well as assembly code for initializing the BIOS. The document also outlines the structure of the BIOS and the necessary steps for compiling and linking the BIOS source code.

Uploaded by

soufsoftware
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 78

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

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy