1402 lines
36 KiB
NASM
1402 lines
36 KiB
NASM
|
; SCCSID = @(#)uf.bios4.asm 1.10 7/3/95 Copyright Insignia Solutions Ltd.
|
||
|
; Author: J. Box (copied from Williams xt original)
|
||
|
; J. Kramskoy (added 1.disk parameter tables required for fixed disk.
|
||
|
; 2.ROM BASIC entry point.
|
||
|
; 3.Configuration parameters.)
|
||
|
; J. Koprowski (added two 2.88Mb Floppy table entries.)
|
||
|
;
|
||
|
; Purpose:
|
||
|
; provides Intel AT BIOS
|
||
|
;
|
||
|
; DUE TO LIMITATIONS IN EXE2BIN, we define
|
||
|
; the region 0 - 0xdfff (segment 0xf000) in file 'bios1.asm'
|
||
|
; and the region 0xe000 - 0xffff in this file
|
||
|
;
|
||
|
; each file should be SEPARATELY put through
|
||
|
; MASM,LINK, and EXE2BIN to produce 2 binary image files
|
||
|
; which get loaded into the appropriate regions during
|
||
|
; SoftPC startup.
|
||
|
ORG2 MACRO trueOffset
|
||
|
ORG trueOffset-0e000h
|
||
|
ENDM
|
||
|
|
||
|
TRACE_BOP MACRO text
|
||
|
LOCAL over_the_name
|
||
|
BOP 0f8h
|
||
|
jmp SHORT over_the_name
|
||
|
db '&text&'
|
||
|
db 10, 0
|
||
|
over_the_name:
|
||
|
ENDM
|
||
|
|
||
|
|
||
|
MODEL_BYTE = 0fch
|
||
|
SUB_MODEL_BYTE = 1
|
||
|
BIOS_LEVEL = 0
|
||
|
|
||
|
; INT & BOP numbers
|
||
|
BIOS_RESET = 0
|
||
|
BIOS_PRINT_SCREEN = 5
|
||
|
BIOS_ILL_OP_INT = 6
|
||
|
BIOS_TIMER_INT = 8
|
||
|
BIOS_KB_INT = 9
|
||
|
BIOS_DISK_INT = 0Dh
|
||
|
BIOS_DISKETTE_INT = 0Eh
|
||
|
BIOS_VIDEO_IO = 10h
|
||
|
BIOS_EQUIPMENT = 11h
|
||
|
BIOS_MEMORY_SIZE = 12h
|
||
|
BIOS_DISK_IO = 13h
|
||
|
BIOS_RS232_IO = 14h
|
||
|
BIOS_CASSETTE_IO = 15h
|
||
|
BIOS_KEYBOARD_IO = 16h
|
||
|
BIOS_PRINTER_IO = 17h
|
||
|
BIOS_ROM_BASIC = 18h
|
||
|
BIOS_BOOT_STRAP = 19h
|
||
|
BIOS_TIME_OF_DAY = 1Ah
|
||
|
BIOS_KEYBOARD_BREAK = 1Bh
|
||
|
BIOS_USER_TIMER = 1Ch
|
||
|
BIOS_IDLE_POLL = 1Dh
|
||
|
BIOS_DISKETTE_IO = 40h
|
||
|
|
||
|
; BOPs
|
||
|
BIOS_BOOTSTRAP_1 = 90h
|
||
|
BIOS_BOOTSTRAP_2 = 91h
|
||
|
BIOS_BOOTSTRAP_3 = 92h
|
||
|
|
||
|
BIOS_FL_OPERATION_1 = 0A0h
|
||
|
BIOS_FL_OPERATION_2 = 0A1h
|
||
|
BIOS_FL_OPERATION_3 = 0A2h
|
||
|
BIOS_FL_RESET_2 = 0A3h
|
||
|
|
||
|
|
||
|
BIOS_MOUSE_INT1 = 0BAh
|
||
|
BIOS_MOUSE_INT2 = 0BBh
|
||
|
BIOS_MOUSE_IO_LANGUAGE = 0BCh
|
||
|
BIOS_MOUSE_IO_INTERRUPT = 0BDh
|
||
|
BIOS_MOUSE_VIDEO_IO = 0BEh
|
||
|
|
||
|
BIOS_CPU_QUIT = 0FEh
|
||
|
|
||
|
; addresses
|
||
|
DOS_SEGMENT = 0
|
||
|
DOS_OFFSET = 7C00h
|
||
|
|
||
|
BIOS_ROM_SEGMENT = 0f000h
|
||
|
DUMMY_INT_OFFSET = 0FF4Bh
|
||
|
|
||
|
BIOS_PASTE_OFFSET = 0FF4Ch
|
||
|
|
||
|
KB_INT_OFFSET = 0E987h
|
||
|
KEYBOARD_IO_OFFSET = 0E82Eh
|
||
|
RCPU_POLL_OFFSET = 0e850h
|
||
|
RCPU_NOP_OFFSET = 0e950h
|
||
|
RCPU_INT15_OFFSET = 0e970h
|
||
|
RCPU_WAIT_INT_OFFSET = 00CE0h
|
||
|
CASSETTE_IO_OFFSET = 0F859h
|
||
|
TIMER_INT_OFFSET = 0FEA5h
|
||
|
OLD_TIMER_INT_OFFSET = 0FF00h
|
||
|
ILL_OP_INT_OFFSET = 0FF30h
|
||
|
KEYBOARD_BREAK_INT_OFFSET = 0FF35h
|
||
|
PRINT_SCREEN_INT_OFFSET = 0FF3Bh
|
||
|
USER_TIMER_INT_OFFSET = 0FF41h
|
||
|
RESET_OFFSET = 0E05Bh
|
||
|
START_OFFSET = 0FFF0h
|
||
|
PRINTER_IO_OFFSET = 0EFD2h
|
||
|
|
||
|
|
||
|
; useful stuff
|
||
|
CR = 0Dh
|
||
|
LF = 0Ah
|
||
|
|
||
|
; keyboard constants
|
||
|
; bits in kb_flag
|
||
|
RIGHT_SHIFT = 1
|
||
|
LEFT_SHIFT = 2
|
||
|
CTL_SHIFT = 4
|
||
|
ALT_SHIFT = 8
|
||
|
|
||
|
|
||
|
|
||
|
; bit in kb_flag_1
|
||
|
HOLD_STATE = 8
|
||
|
SCROLL_SHIFT = 10h
|
||
|
NUM_SHIFT = 20h
|
||
|
CAPS_SHIFT = 40h
|
||
|
INS_SHIFT = 80h
|
||
|
|
||
|
; IBM scan codes
|
||
|
CTL_KEY = 29
|
||
|
LEFT_SHIFTKEY = 42
|
||
|
RIGHT_SHIFTKEY = 54
|
||
|
ALT_KEY = 56
|
||
|
CAPS_KEY = 58
|
||
|
NUM_KEY = 69
|
||
|
SCROLL_KEY = 70
|
||
|
INS_KEY = 82
|
||
|
|
||
|
; CMOS registers
|
||
|
CMOS_addr = 070h
|
||
|
CMOS_data = 071h
|
||
|
NMI_DISABLE = 080h
|
||
|
CMOS_StatusA = NMI_DISABLE + 0Ah
|
||
|
CMOS_StatusB = NMI_DISABLE + 0Bh
|
||
|
CMOS_StatusC = NMI_DISABLE + 0Ch
|
||
|
CMOS_Shutdown = 0Fh
|
||
|
; CMOS constants (bits in StatusB or StatusC)
|
||
|
CMOS_PI = 01000000b ; Periodic interrupt
|
||
|
CMOS_AI = 00100000b ; Alarm interrupt
|
||
|
; microseconds at 1024Hz
|
||
|
CMOS_PERIOD_USECS = 976
|
||
|
|
||
|
; ICA registers
|
||
|
ICA_MASTER_CMD = 020h
|
||
|
ICA_MASTER_IMR = 021h
|
||
|
ICA_SLAVE_CMD = 0A0h
|
||
|
ICA_SLAVE_IMR = 0A1h
|
||
|
; and commands
|
||
|
ICA_EOI = 020h
|
||
|
|
||
|
; BIOS variables area
|
||
|
BIOS_VAR_SEGMENT SEGMENT at 40h
|
||
|
|
||
|
ORG 17h
|
||
|
|
||
|
kb_flag DB ? ; 17
|
||
|
kb_flag_1 DB ? ; 18
|
||
|
|
||
|
ORG 03fh
|
||
|
|
||
|
MOTOR_STATUS DB ? ; 3f
|
||
|
MOTOR_COUNT DB ? ; 40
|
||
|
|
||
|
ORG 06ch
|
||
|
TIMER_COUNT DD ? ; 6c
|
||
|
TIMER_OVFL DB ? ; 70
|
||
|
|
||
|
ORG 098h
|
||
|
rtc_user_flag DD ? ; 98
|
||
|
rtc_micro_secs DD ? ; 9c
|
||
|
rtc_wait_flag DB ? ; a0
|
||
|
|
||
|
BIOS_VAR_SEGMENT ENDS
|
||
|
|
||
|
; Segment we jump to after booting
|
||
|
DOS_seg SEGMENT at DOS_SEGMENT
|
||
|
ORG DOS_OFFSET
|
||
|
DOS_boot LABEL FAR
|
||
|
DOS_seg ENDS
|
||
|
|
||
|
; To keep the binary file down to a sensible size, the code segment
|
||
|
; is at fe00 instead of f000. Far jumps are correctly assembled by
|
||
|
; using a second 'fake' segment, that just contains labels, and DOES
|
||
|
; start at f000.
|
||
|
ref SEGMENT at 0F000h
|
||
|
;
|
||
|
; NB. the following addresses are allocated to SUN for DOS Windows 3.0.
|
||
|
; They are not to be used by anyone else.
|
||
|
; THIS AREA IS SUN PROPERTY - TRESPASSERS WILL BE PROSECUTED
|
||
|
; However please note that only the ranges below are reserved.
|
||
|
; Bios2 gets loaded at 0xfe00, so the following does not have any real
|
||
|
; effect other than to act as a warning.
|
||
|
;
|
||
|
ORG 0
|
||
|
sunroms_1 LABEL FAR
|
||
|
db 1024 dup (0) ; reserved
|
||
|
ORG 04000h
|
||
|
sunroms_2 LABEL FAR
|
||
|
db 512 dup (0) ; reserved
|
||
|
ORG 05000h
|
||
|
sunroms_3 LABEL FAR
|
||
|
db 512 dup (0) ; reserved
|
||
|
;
|
||
|
; BACK TO INSIGNIA
|
||
|
;
|
||
|
ORG RESET_OFFSET
|
||
|
reset_ref LABEL FAR; Must match reset
|
||
|
ref ENDS
|
||
|
|
||
|
code SEGMENT
|
||
|
ASSUME cs:code,ds:BIOS_VAR_SEGMENT
|
||
|
ORG 0
|
||
|
copyright:
|
||
|
ifndef SOFTWINDOWS
|
||
|
DB "4504512 SoftPC 4.00 (C)Copyright Insignia Solutions Inc. 1995"
|
||
|
else
|
||
|
DB "4504512 SoftWindows 2 (C)Copyright Insignia Solutions Inc. 1995"
|
||
|
endif ; SOFTWINDOWS
|
||
|
|
||
|
include bebop.inc
|
||
|
|
||
|
|
||
|
ORG 40h
|
||
|
DB 00h, 01h ; rom serial number
|
||
|
|
||
|
ORG 5Bh
|
||
|
reset LABEL FAR ; Must match reset_ref
|
||
|
BOP %BIOS_RESET
|
||
|
PRINT_MESSAGES
|
||
|
INT 19h
|
||
|
|
||
|
|
||
|
; space to insert customer specific startup message
|
||
|
ORG 80h
|
||
|
oem_msg:
|
||
|
DB " "
|
||
|
ORG 100h
|
||
|
serial_number:
|
||
|
DB "(c) Insignia Inc"
|
||
|
DB 15h, 3eh, 5fh, 20h
|
||
|
; this is a cunning encryption, do not change at all
|
||
|
|
||
|
ORG 150h
|
||
|
hfx_ifs_hdr:
|
||
|
DB 0ffh, 0ffh, 0ffh, 0ffh
|
||
|
DB "HFXREDIR"
|
||
|
DB 00h, 02ch
|
||
|
DB 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h
|
||
|
; this is a fake IFS header to make DOS 4.01
|
||
|
; happy with HFX. Do not move/alter.
|
||
|
|
||
|
;
|
||
|
; Special host_unsimulate BOP to enable DEC code to do an IRET to this
|
||
|
; location. In this way SoftPC can crunch some Intel and DEC can use
|
||
|
; the same code that works on PCs, i.e. they don't need to change the IRET
|
||
|
; instructions.
|
||
|
;
|
||
|
ORG 170h
|
||
|
pcsa:
|
||
|
INT 72h
|
||
|
BOP BIOS_CPU_QUIT
|
||
|
|
||
|
signatures:
|
||
|
DB CR,LF
|
||
|
;
|
||
|
; signatures removed because Microsoft don't like to find Insignia credits.
|
||
|
;
|
||
|
ORG 401h
|
||
|
|
||
|
; 23/7/93 MG WinSleuth must have the first two entries of the standard PC
|
||
|
; BIOS at the beginning of the table, otherwise it will fall
|
||
|
; over !
|
||
|
|
||
|
disktab:
|
||
|
|
||
|
; Drive Type 1
|
||
|
|
||
|
dw 0306
|
||
|
db 04
|
||
|
dw 0
|
||
|
dw 0128
|
||
|
db 0
|
||
|
db 0
|
||
|
db 0,0,0
|
||
|
dw 0305
|
||
|
db 17
|
||
|
db 0
|
||
|
|
||
|
; Drive Type 2
|
||
|
|
||
|
dw 615
|
||
|
db 4
|
||
|
dw 0
|
||
|
dw 300
|
||
|
db 0
|
||
|
db 0
|
||
|
db 0,0,0
|
||
|
dw 615
|
||
|
db 17
|
||
|
db 0
|
||
|
|
||
|
; Drive Type 3
|
||
|
|
||
|
dw 0 ; DISK PARAMETER BLOCK for drive type 3 (Our C: drive ALWAYS)
|
||
|
; (the #.of cylinders available gets patched in by fdisk_ioattach()
|
||
|
; in fdisk.c)
|
||
|
db 4 ; 4 heads (for now)
|
||
|
db 11 dup (0)
|
||
|
db 17 ; 17 sectors per track
|
||
|
db 0
|
||
|
|
||
|
; Drive Type 4
|
||
|
|
||
|
dw 0 ; DISK PARAMETER BLOCK for drive type 4 (Our D: drive
|
||
|
; (if configured))
|
||
|
db 4 ; 4 heads (for now)
|
||
|
db 11 dup (0)
|
||
|
db 17 ; 17 sectors per track
|
||
|
db 0
|
||
|
; 45 unused blocks
|
||
|
db 45*16 dup (0)
|
||
|
|
||
|
ORG 06F2h
|
||
|
boot_strap:
|
||
|
jmp boot_strap_1
|
||
|
|
||
|
ORG 06f5h
|
||
|
; CONFIGURATION PARAMETERS as defined in '86 BIOS.
|
||
|
; used for cassette i/o function
|
||
|
conf_table:
|
||
|
db 8 ; length of following table
|
||
|
db 0 ; Pad on length above
|
||
|
db MODEL_BYTE ; system model byte
|
||
|
db SUB_MODEL_BYTE ; system model type
|
||
|
db BIOS_LEVEL ; bios revision level
|
||
|
db 70h ; 80 = DMA channel 3 used by bios
|
||
|
; 40 = cascaded interrupt level 2
|
||
|
; 20 = real time clock available
|
||
|
; 10 = kybd scan code hook 1Ah
|
||
|
db 4 dup (0) ; reserved
|
||
|
|
||
|
|
||
|
org 0700h
|
||
|
boot_strap_1:
|
||
|
BOP BIOS_BOOT_STRAP
|
||
|
INT BIOS_DISK_IO
|
||
|
BOP BIOS_BOOTSTRAP_1
|
||
|
INT BIOS_DISK_IO
|
||
|
BOP BIOS_BOOTSTRAP_2
|
||
|
INT BIOS_DISK_IO
|
||
|
BOP BIOS_BOOTSTRAP_3
|
||
|
JMP DOS_boot ; To MessyDOS
|
||
|
|
||
|
ORG 0739h
|
||
|
rs232_io:
|
||
|
BOP BIOS_RS232_IO
|
||
|
IRET
|
||
|
|
||
|
ORG2 KEYBOARD_IO_OFFSET
|
||
|
keyboard_io:
|
||
|
CMP AH, 1 ; Is it a "test if char available" call ?
|
||
|
JZ nerd ; if so - to the nerd
|
||
|
CMP AH, 11h ; Is it a "extended test if char available" call ?
|
||
|
JZ nerd ; if so - to the nerd
|
||
|
|
||
|
BOP BIOS_KEYBOARD_IO ; call BIOS keyboard function
|
||
|
IRET ; Int return, restoring old status flags
|
||
|
nerd:
|
||
|
BOP BIOS_KEYBOARD_IO ; call BIOS keyboard function
|
||
|
RETF 2 ; Return without trampling on the status flags
|
||
|
|
||
|
|
||
|
; loop to wait for a keyboard int - called as a recursive CPU
|
||
|
ORG2 RCPU_POLL_OFFSET
|
||
|
sti
|
||
|
push ds
|
||
|
mov ax,BIOS_VAR_SEGMENT
|
||
|
mov ds,ax
|
||
|
kw1: bop %BIOS_IDLE_POLL
|
||
|
mov ax,WORD PTR DS:[1ah] ; bios kb buffer head
|
||
|
cmp ax,WORD PTR DS:[1ch] ; bios kb buffer tail
|
||
|
jz kw1
|
||
|
pop ds
|
||
|
bop %BIOS_CPU_QUIT
|
||
|
|
||
|
ORG 087Eh
|
||
|
shift_keys:
|
||
|
DB INS_KEY,CAPS_KEY,NUM_KEY,SCROLL_KEY
|
||
|
DB ALT_KEY,CTL_KEY,LEFT_SHIFTKEY,RIGHT_SHIFTKEY; K6
|
||
|
shift_masks:
|
||
|
DB INS_SHIFT,CAPS_SHIFT,NUM_SHIFT,SCROLL_SHIFT
|
||
|
DB ALT_SHIFT,CTL_SHIFT,LEFT_SHIFT,RIGHT_SHIFT; K7
|
||
|
ctl_n_table:
|
||
|
DB 27, -1, 0, -1, -1, -1, 30, -1
|
||
|
DB -1, -1, -1, 31, -1, 127, 148, 17
|
||
|
DB 23, 5, 18, 20, 25, 21, 9, 15
|
||
|
DB 16, 27, 29, 10, -1, 1, 19, 4
|
||
|
DB 6, 7, 8, 10, 11, 12, -1, -1
|
||
|
DB -1, -1, 28, 26, 24, 3, 22, 2
|
||
|
DB 14, 13, -1, -1, -1, -1, 150, -1
|
||
|
DB ' ', -1; K8
|
||
|
ctl_f_table:
|
||
|
DB 94, 95, 96, 97, 98, 99, 100, 101
|
||
|
DB 102, 103, -1, -1, 119, 141, 132, 142
|
||
|
DB 115, 143, 116, 144, 117, 145, 118, 146
|
||
|
DB 147, -1, -1, -1, 137, 138; K9
|
||
|
lowercase:
|
||
|
DB 27, '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
||
|
DB '0', '-', '=', 8, 9, 'q', 'w', 'e', 'r', 't'
|
||
|
DB 'y', 'u', 'i', 'o', 'p', '[', ']', 13, -1, 'a'
|
||
|
DB 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39
|
||
|
DB 96, -1, 92, 'z', 'x', 'c', 'v', 'b', 'n', 'm'
|
||
|
DB ',', '.', '/', -1, '*', -1, ' ', -1; K10
|
||
|
lc_tbl_scan:
|
||
|
DB 59, 60, 61, 62, 63, 64, 65, 66, 67, 68
|
||
|
DB -1, -1
|
||
|
base_case:
|
||
|
DB 71, 72, 73, -1, 75, -1, 77, -1, 79, 80, 81, 82, 83
|
||
|
DB -1, -1, 92, 133, 134; K15
|
||
|
|
||
|
ORG 0940h
|
||
|
kb_int_1:
|
||
|
sti
|
||
|
push ax
|
||
|
bop %BIOS_KB_INT
|
||
|
pop ax
|
||
|
iret
|
||
|
|
||
|
; intel instructions for recursive CPU to read keyboard interrupts
|
||
|
; this is used something like this:
|
||
|
; while(!somecondition)
|
||
|
; host_simulate();
|
||
|
; or
|
||
|
; while((!somecondition)&&(!timout())
|
||
|
; host_simulate();
|
||
|
; The conditions can only be met by something (like a keyboard event)
|
||
|
; in the real world being put on the event queue and being processed.
|
||
|
; BUT
|
||
|
; we only process events when timer ticks go off, which only happens
|
||
|
; if the CPU executes for >20ms. So we sit in a loop waiting.
|
||
|
; We could exit the intel code on a particular flag, but to make this
|
||
|
; code less specific, we exit when the low order timer byte changes
|
||
|
; (Eg a timer tick has gone off). The C calling code from the base
|
||
|
; therefore
|
||
|
; a) does the real checking to see if conditions are met.
|
||
|
; b) doesn't need changing in a host specific manner.
|
||
|
;
|
||
|
; We can't just sit in C code waiting for keyboard events because then
|
||
|
; timer specific stuff (comms etc) wouldn't happen.
|
||
|
; We can't just do a short call to the recursive CPU because
|
||
|
; the API for timer ticks won't handle it well, Eg if we just say
|
||
|
; NOP
|
||
|
; NOP
|
||
|
; BOP %BIOS_CPU_QUIT
|
||
|
; the recursive CPU doesn't execute long enough for the timer tick
|
||
|
; to go off.
|
||
|
|
||
|
ORG2 RCPU_NOP_OFFSET ; this just allows the CPU to handle an interrupt
|
||
|
sti
|
||
|
push ax
|
||
|
push es
|
||
|
mov ax,0
|
||
|
mov es,ax
|
||
|
mov ax,es:[46ch] ; read low order timer byte from 0x46c
|
||
|
L1: cmp ax,es:[46ch] ; if its changed exit from recursive cpu
|
||
|
je L1
|
||
|
pop es
|
||
|
pop ax
|
||
|
bop %BIOS_CPU_QUIT
|
||
|
|
||
|
ORG2 RCPU_INT15_OFFSET ; this specifically calls INT15
|
||
|
int 15h
|
||
|
jmp w1
|
||
|
w3: bop %BIOS_CPU_QUIT
|
||
|
w2: jmp w3
|
||
|
w1: jmp w2
|
||
|
|
||
|
ORG2 KB_INT_OFFSET
|
||
|
jmp kb_int_1
|
||
|
|
||
|
ORG 098Ah
|
||
|
uppercase:
|
||
|
DB 27, '!', '@', '#', '$', '%', '^', '&', '*', '('
|
||
|
DB ')', '_', '+', 8, 0, 'Q', 'W', 'E', 'R', 'T'
|
||
|
DB 'Y', 'U', 'I', 'O', 'P', '{', '}', 13, -1, 'A'
|
||
|
DB 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"'
|
||
|
DB 126, -1, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M'
|
||
|
DB '<', '>', '?', -1, 0, -1, ' ', -1; K11
|
||
|
ucase_scan:
|
||
|
DB 84, 85, 86, 87, 88, 89, 90, 91, 92, 93
|
||
|
DB -1, -1
|
||
|
num_state:
|
||
|
DB '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.'
|
||
|
DB -1, -1, 124, 135, 136; K14
|
||
|
|
||
|
ORG 0A87h
|
||
|
alt_table:
|
||
|
DB 82, 79, 80, 81, 75, 76, 77, 71, 72, 73
|
||
|
DB 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
||
|
DB 30, 31, 32, 33, 34, 35, 36, 37, 38, 44
|
||
|
DB 45, 46, 47, 48, 49, 50 ; K30
|
||
|
|
||
|
; definitions used in diskette BIOS
|
||
|
MOTOR_WAIT = 25h
|
||
|
WRONG_MEDIA = 80h
|
||
|
RS_500 = 00h
|
||
|
RS_300 = 40h
|
||
|
RS_250 = 80h
|
||
|
RS_1000 = 0C0h
|
||
|
|
||
|
|
||
|
ORG 0C00h
|
||
|
rom_basic:
|
||
|
BOP %BIOS_ROM_BASIC
|
||
|
IRET
|
||
|
|
||
|
ORG 0C49h
|
||
|
diskette_io:
|
||
|
BOP %BIOS_DISKETTE_IO
|
||
|
RETF 2 ; exit, keeping flags
|
||
|
|
||
|
ORG 0C50h
|
||
|
dr_type:
|
||
|
DB 01
|
||
|
DW OFFSET md_tbl1
|
||
|
DB 02 + WRONG_MEDIA
|
||
|
DW OFFSET md_tbl2
|
||
|
DB 02
|
||
|
DW OFFSET md_tbl3
|
||
|
DB 03
|
||
|
DW OFFSET md_tbl4
|
||
|
DB 04 + WRONG_MEDIA
|
||
|
DW OFFSET md_tbl5
|
||
|
DB 04
|
||
|
DW OFFSET md_tbl6
|
||
|
DB 05 + WRONG_MEDIA
|
||
|
DW OFFSET md_tbl7
|
||
|
DB 05 + WRONG_MEDIA
|
||
|
DW OFFSET md_tbl8
|
||
|
DB 05
|
||
|
DW OFFSET md_tbl9
|
||
|
|
||
|
ORG 0C6Bh
|
||
|
md_tbl1:
|
||
|
; MEDIA = 40 track low data rate; DRIVE = 40 track low data rate
|
||
|
DB 0DFh ; 1st specify byte
|
||
|
DB 2 ; 2nd specify byte
|
||
|
DB MOTOR_WAIT ; motor off wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 9 ; sectors/track
|
||
|
DB 02Ah ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 050h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 39 ; maximum track number
|
||
|
DB RS_250 ; transfer rate
|
||
|
|
||
|
ORG 0C78h
|
||
|
md_tbl2:
|
||
|
; MEDIA = 40 track low data rate; DRIVE = 80 track high data rate
|
||
|
DB 0DFh ; 1st specify byte
|
||
|
DB 2 ; 2nd specify byte
|
||
|
DB MOTOR_WAIT ; motor off wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 9 ; sectors/track
|
||
|
DB 02Ah ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 050h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 39 ; maximum track number
|
||
|
DB RS_300 ; transfer rate
|
||
|
|
||
|
ORG 0C85h
|
||
|
md_tbl3:
|
||
|
; MEDIA = 80 track high data rate; DRIVE = 80 track high data rate
|
||
|
DB 0DFh ; 1st specify byte
|
||
|
DB 2 ; 2nd specify byte
|
||
|
DB MOTOR_WAIT ; motor off wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 15 ; sectors/track
|
||
|
DB 01Bh ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 054h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 79 ; maximum track number
|
||
|
DB RS_500 ; transfer rate
|
||
|
|
||
|
ORG 0C92h
|
||
|
md_tbl4:
|
||
|
; MEDIA = 80 track low data rate; DRIVE = 80 track low data rate
|
||
|
DB 0DFh ; 1st specify byte
|
||
|
DB 2 ; 2nd specify byte
|
||
|
DB MOTOR_WAIT ; motor off wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 9 ; sectors/track
|
||
|
DB 02Ah ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 050h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 79 ; maximum track number
|
||
|
DB RS_250 ; transfer rate
|
||
|
|
||
|
ORG 0C9Fh
|
||
|
md_tbl5:
|
||
|
; MEDIA = 80 track low data rate; DRIVE = 80 track high data rate
|
||
|
DB 0DFh ; 1st specify byte
|
||
|
DB 2 ; 2nd specify byte
|
||
|
DB MOTOR_WAIT ; motor off wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 9 ; sectors/track
|
||
|
DB 02Ah ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 050h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 79 ; maximum track number
|
||
|
DB RS_250 ; transfer rate
|
||
|
|
||
|
ORG 0CACh
|
||
|
md_tbl6:
|
||
|
; MEDIA = 80 track high data rate; DRIVE = 80 track high data rate
|
||
|
DB 0AFh ; 1st specify byte
|
||
|
DB 2 ; 2nd specify byte
|
||
|
DB MOTOR_WAIT ; motor off wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 18 ; sectors/track
|
||
|
DB 01Bh ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 06Ch ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 79 ; maximum track number
|
||
|
DB RS_500 ; transfer rate
|
||
|
|
||
|
; new for 2.88M floppies
|
||
|
ORG 0CB9h
|
||
|
md_tbl7:
|
||
|
; MEDIA = 80 track low data rate; DRIVE = 80 track ext data rate
|
||
|
DB 0AFh
|
||
|
DB 2 ; 2nd specify byte (guessed from 1.4)
|
||
|
DB MOTOR_WAIT ; motor wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 9 ; sectors/track
|
||
|
DB 01Bh ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 053h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 79 ; maximum track number
|
||
|
DB RS_250 ; transfer rate (guessed from 1.4)
|
||
|
|
||
|
ORG 0CC6h
|
||
|
md_tbl8:
|
||
|
; MEDIA = 80 track high data rate; DRIVE = 80 track ext data rate
|
||
|
DB 0AFh
|
||
|
DB 2 ; 2nd specify byte (guessed from 1.4)
|
||
|
DB MOTOR_WAIT ; motor wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 18 ; sectors/track
|
||
|
DB 01Bh ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 053h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 79 ; maximum track number
|
||
|
DB RS_500 ; transfer rate (guessed from 1.4)
|
||
|
|
||
|
ORG 0CD3h
|
||
|
md_tbl9:
|
||
|
; MEDIA = 80 track ext data rate; DRIVE = 80 track ext data rate
|
||
|
DB 0AFh ; 1st specify byte (guessed from 1.4)
|
||
|
DB 2 ; 2nd specify byte (guessed from 1.4)
|
||
|
DB MOTOR_WAIT ; motor wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 36 ; sectors/track
|
||
|
DB 01Bh ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 053h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 15 ; head settle time/ms
|
||
|
DB 8 ; ie 1s motor start time
|
||
|
DB 79 ; maximum track number
|
||
|
DB RS_1000 ; transfer rate (guessed from 1.4)
|
||
|
|
||
|
ORG RCPU_WAIT_INT_OFFSET
|
||
|
wait_int:
|
||
|
PUSH DS
|
||
|
PUSH CX
|
||
|
MOV CX, BIOS_VAR_SEGMENT
|
||
|
MOV DS, CX
|
||
|
MOV CX, 0100H ; sufficient to take multiple interrupts
|
||
|
wait_int_0:
|
||
|
TEST byte ptr DS:[3EH], 80h
|
||
|
LOOPZ wait_int_0
|
||
|
POP CX
|
||
|
POP DS
|
||
|
BOP %BIOS_CPU_QUIT
|
||
|
|
||
|
ORG 0D00h
|
||
|
mouse_io:
|
||
|
JMP hopover
|
||
|
BOP %BIOS_MOUSE_IO_LANGUAGE
|
||
|
RETF 8
|
||
|
hopover:
|
||
|
BOP %BIOS_MOUSE_IO_INTERRUPT
|
||
|
IRET
|
||
|
|
||
|
ORG 0D20h
|
||
|
mouse_version: ; dummy, for compatibility
|
||
|
DB 042h,042h,00h,00h
|
||
|
|
||
|
ORG 0D40h
|
||
|
mouse_copyright: ; dummy, for compatibility
|
||
|
DB "Copyright 1987 Insignia Solutions Inc"
|
||
|
|
||
|
ORG 0D80h
|
||
|
mouse_video_io:
|
||
|
BOP %BIOS_MOUSE_VIDEO_IO
|
||
|
IRET
|
||
|
|
||
|
ORG 0E00h
|
||
|
mouse_int1:
|
||
|
BOP %BIOS_MOUSE_INT1
|
||
|
IRET
|
||
|
|
||
|
ORG 0E80h
|
||
|
mouse_int2:
|
||
|
BOP %BIOS_MOUSE_INT2
|
||
|
IRET
|
||
|
|
||
|
ORG 0F57h
|
||
|
diskette_int:
|
||
|
BOP %BIOS_DISKETTE_INT
|
||
|
IRET
|
||
|
|
||
|
ORG 0FC7h
|
||
|
disk_base:
|
||
|
DB 0CFh ; 1st specify byte
|
||
|
DB 2 ; 2nd specify byte
|
||
|
DB MOTOR_WAIT ; motor off wait time
|
||
|
DB 2 ; ie 2 bytes/sector
|
||
|
DB 18 ; sectors/track
|
||
|
DB 02Ah ; gap length
|
||
|
DB 0FFh ; data length
|
||
|
DB 050h ; gap length for format
|
||
|
DB 0F6h ; fill byte for format
|
||
|
DB 25 ; head settle time/ms
|
||
|
DB 4 ; ie 1/2s motor start time
|
||
|
|
||
|
ORG2 PRINTER_IO_OFFSET
|
||
|
printer_io:
|
||
|
BOP %BIOS_PRINTER_IO
|
||
|
IRET
|
||
|
|
||
|
ORG 1065h
|
||
|
video_io:
|
||
|
BOP %BIOS_VIDEO_IO
|
||
|
IRET
|
||
|
|
||
|
ORG 106ch
|
||
|
INT 10h ; allows video handler to be recursive
|
||
|
BOP %BIOS_CPU_QUIT
|
||
|
|
||
|
ORG 10A4h
|
||
|
vid_parm_setup:
|
||
|
; 40*25
|
||
|
DB 038h, 028h, 02Dh, 0Ah, 01Fh, 6, 019h, 01Ch,2, 7, 6, 7,0,0,0,0
|
||
|
; 80*25
|
||
|
DB 071h, 050h, 05Ah, 0Ah, 01Fh, 6, 019h, 01Ch,2, 7, 6, 7,0,0,0,0
|
||
|
; graphics
|
||
|
DB 038h, 028h, 02Dh, 0Ah, 07Fh, 6, 064h, 070h,2, 1, 6, 7,0,0,0,0
|
||
|
; 80*25 BW
|
||
|
DB 061h, 050h, 052h, 0Fh, 019h, 6, 019h, 019h,2,0Dh,0Bh,0Ch,0,0,0,0
|
||
|
vid_len_setup:
|
||
|
DW 2048 ; 40*25 screen size
|
||
|
DW 4096 ; 80*25 screen size
|
||
|
DW 16384; graphics
|
||
|
DW 16384; graphics
|
||
|
vid_col_setup:
|
||
|
DB 40, 40, 80 , 80, 40, 40, 80, 80 ; screen columns
|
||
|
vid_mode_setup:
|
||
|
DB 2Ch, 28h, 2Dh, 29h, 2Ah, 2Eh, 1Eh, 29h ;mode register?
|
||
|
|
||
|
ORG 1841h
|
||
|
memory_size:
|
||
|
BOP %BIOS_MEMORY_SIZE
|
||
|
IRET
|
||
|
|
||
|
ORG 184Dh
|
||
|
equipment:
|
||
|
BOP %BIOS_EQUIPMENT
|
||
|
IRET
|
||
|
|
||
|
;;=======================================================================
|
||
|
;; INT 15h "Cassette IO" e.g. miscellaneous functions
|
||
|
;;
|
||
|
|
||
|
ORG2 CASSETTE_IO_OFFSET
|
||
|
cassette_io:
|
||
|
sti
|
||
|
cmp ah, 4fh ; Check frequent case (keyboard) first
|
||
|
jne int15_not_kb
|
||
|
mov ah, 86h ; AH = INVALID option code
|
||
|
int15_fail: stc ; CF = 1, implies not OK
|
||
|
retf 2
|
||
|
|
||
|
|
||
|
; Int 15h function 83h (other than the frequent kb enquiry)
|
||
|
;
|
||
|
int15_not_kb: cmp ah, 83h ; INT15_EVENT_WAIT
|
||
|
je int15_83
|
||
|
cmp ah, 86h ; INT15_WAIT
|
||
|
.386
|
||
|
je int15_86
|
||
|
cmp ah, 89h ; switch to protected mode
|
||
|
je int15_89
|
||
|
.286
|
||
|
|
||
|
;; Handle other cases in tape_io.c
|
||
|
|
||
|
or ax, ax ; clear CF
|
||
|
bop %BIOS_CASSETTE_IO
|
||
|
retf 2
|
||
|
|
||
|
|
||
|
; Int 15h function 83h
|
||
|
;
|
||
|
; Change bit7 of byte at es:[bx] when cx::dx micro-seconds has passed.
|
||
|
;
|
||
|
int15_83: cmp al, 0
|
||
|
jnz int15_83_stop
|
||
|
|
||
|
push ds
|
||
|
mov ax, BIOS_VAR_SEGMENT
|
||
|
mov ds, ax ; load up DS to point to BIOS data
|
||
|
|
||
|
test rtc_wait_flag, 1 ; Test timer-in-use ?
|
||
|
jnz int15_83_inuse
|
||
|
|
||
|
;; Set up address of user's flag byte
|
||
|
|
||
|
mov word ptr ds:[rtc_user_flag], bx
|
||
|
mov word ptr ds:[rtc_user_flag+2], es
|
||
|
|
||
|
;; Save mSec count to decrement
|
||
|
|
||
|
mov word ptr ds:[rtc_micro_secs], dx
|
||
|
mov word ptr ds:[rtc_micro_secs+2], cx
|
||
|
|
||
|
;; Produce a trace message if time "large", i.e. > 1,000,000 uS
|
||
|
|
||
|
cmp cx, 0Fh ; 1000000. == 000F4240
|
||
|
jb int15_83_small
|
||
|
TRACE_BOP <int15/83: #cx #dx>
|
||
|
int15_83_small:
|
||
|
|
||
|
;; Program the RTC to periodically interrupt at 1024Hz
|
||
|
|
||
|
cli
|
||
|
|
||
|
;; Make sure PIC line for RTC is not masked
|
||
|
|
||
|
in al, ICA_SLAVE_IMR
|
||
|
and al, 11111110b ; RTC is slave line 0
|
||
|
out ICA_SLAVE_IMR, al
|
||
|
|
||
|
;; Set time-of-day to 32768 Hz and periodic frequency 1024 Hz
|
||
|
|
||
|
mov al, CMOS_StatusA
|
||
|
out CMOS_addr, al
|
||
|
mov al, 00100110b
|
||
|
out CMOS_data, al
|
||
|
|
||
|
;; Enable PI interrupt in CMOS
|
||
|
|
||
|
mov al, CMOS_StatusB
|
||
|
out CMOS_addr, al
|
||
|
in al, CMOS_data
|
||
|
or al, 01000000b ; Enable PI interrupt
|
||
|
out CMOS_data, al
|
||
|
|
||
|
;; Mark timer-in-use flag active
|
||
|
|
||
|
mov rtc_wait_flag, 1; Show wait is active
|
||
|
|
||
|
;; All OK, return, enabling interrupts
|
||
|
|
||
|
pop ds
|
||
|
xor ah, ah ; AH = 0, CF = OK
|
||
|
sti
|
||
|
retf 2
|
||
|
|
||
|
int15_83_stop: cli
|
||
|
|
||
|
;; Disable PI interrupt in CMOS
|
||
|
|
||
|
mov al, CMOS_StatusB
|
||
|
out CMOS_addr, al
|
||
|
in al, CMOS_data
|
||
|
and al, 10111111b ; Disable PI interrupt
|
||
|
out CMOS_data, al
|
||
|
|
||
|
;; Clear the in-use flag, undocumented PC notes that
|
||
|
;; things will go horribly wrong if this call is used
|
||
|
;; at the wrong time!
|
||
|
|
||
|
mov rtc_wait_flag, 0
|
||
|
|
||
|
sti
|
||
|
xor ax, ax ; and CF=0
|
||
|
retf 2
|
||
|
|
||
|
int15_83_inuse: pop ds
|
||
|
jmp int15_fail
|
||
|
|
||
|
;
|
||
|
; Int 15h function 86h
|
||
|
; Wait given number of uSeconds. Quick events will change
|
||
|
; rtc_wait_flag when done...
|
||
|
;
|
||
|
int15_86: push ds
|
||
|
push es
|
||
|
push bx
|
||
|
mov ax, BIOS_VAR_SEGMENT
|
||
|
mov ds, ax ; load up DS to point to BIOS data
|
||
|
|
||
|
;; We use the INT 15/83 function to update our rtc_wait_flag
|
||
|
;; when the requested number of micro-seconds has elapsed
|
||
|
|
||
|
mov bx, OFFSET rtc_wait_flag
|
||
|
mov ax, BIOS_VAR_SEGMENT
|
||
|
mov es, ax
|
||
|
|
||
|
mov ax, 8300h
|
||
|
push ax ; Push fake flags
|
||
|
push cs
|
||
|
call int15_83 ; Do INT15/83
|
||
|
jc int15_86_inuse ; Wait not available
|
||
|
|
||
|
|
||
|
;; Loop until rtc interrupt routine updates bit7 of
|
||
|
;; our supplied user flag.
|
||
|
|
||
|
int15_wait: test rtc_wait_flag, 080h ; check for end of wait
|
||
|
jz int15_wait
|
||
|
|
||
|
;; Clear the in-use flag
|
||
|
|
||
|
mov rtc_wait_flag, 0
|
||
|
|
||
|
;; And return CF=0 (from test) to show completed OK
|
||
|
|
||
|
pop bx
|
||
|
pop es
|
||
|
pop ds
|
||
|
retf 2
|
||
|
|
||
|
;; Error exit, return with CF=1 (from jc)
|
||
|
|
||
|
int15_86_inuse: pop bx
|
||
|
pop es
|
||
|
pop ds
|
||
|
retf 2
|
||
|
|
||
|
;
|
||
|
; Int 15h function 89h
|
||
|
; Switch to virtual (protected) mode
|
||
|
; See At Tech ref BIOS1 listing (11/15/85) p 5-173 and following
|
||
|
;
|
||
|
int15_89:
|
||
|
BOP %BIOS_CASSETTE_IO ; handles ica and a20 line
|
||
|
jc int15_89_exit ; no prot mode
|
||
|
MOV word ptr [SI+38h],0ffffh ; seg limit
|
||
|
MOV byte ptr [SI+3ch],0fh ; cs seg hi
|
||
|
MOV word ptr [SI+3ah],0 ; cs seg lo
|
||
|
MOV byte ptr [SI+3dh],10011011b ; cpl0 code access code
|
||
|
MOV word ptr [SI+3eh],0 ; reserved
|
||
|
;LGDT [SI+8]
|
||
|
DB 0fh,1,54h,8
|
||
|
;LIDT [SI+16]
|
||
|
DB 0fh,1,5ch,16
|
||
|
MOV AX,1
|
||
|
;LMSW AX
|
||
|
DB 0fh,1,0f0h
|
||
|
DB 0eah
|
||
|
; jump far to prot cs:vmode...
|
||
|
DW offset vmode+0e000h
|
||
|
DW 38h
|
||
|
vmode:
|
||
|
MOV AX,18h
|
||
|
MOV DS,AX
|
||
|
MOV AX,20h
|
||
|
MOV ES,AX
|
||
|
MOV AX,28h
|
||
|
MOV SS,AX
|
||
|
POP BX ; get return address
|
||
|
ADD SP,4 ; get rid of cs and flags
|
||
|
db 6ah,30h ; push new (prot mode) cs
|
||
|
PUSH BX ; push return offset
|
||
|
RETF
|
||
|
|
||
|
int15_89_exit:
|
||
|
retf 2
|
||
|
|
||
|
|
||
|
ifndef GISP_SVGA
|
||
|
ORG 1A6Eh
|
||
|
crt_char_gen:
|
||
|
DB 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ; /* 0 */
|
||
|
DB 07Eh, 081h, 0A5h, 081h, 0BDh, 099h, 081h, 07Eh ; /* 1 */
|
||
|
DB 07Eh, 0FFh, 0DBh, 0FFh, 0C3h, 0E7h, 0FFh, 07Eh ; /* 2 */
|
||
|
DB 06Ch, 0FEh, 0FEh, 0FEh, 07Ch, 038h, 010h, 000h ; /* 3 */
|
||
|
DB 010h, 038h, 07Ch, 0FEh, 07Ch, 038h, 010h, 000h ; /* 4 */
|
||
|
DB 038h, 07Ch, 038h, 0FEh, 0FEh, 07Ch, 038h, 07Ch ; /* 5 */
|
||
|
DB 010h, 010h, 038h, 07Ch, 0FEh, 07Ch, 038h, 07Ch ; /* 6 */
|
||
|
DB 000h, 000h, 018h, 03Ch, 03Ch, 018h, 000h, 000h ; /* 7 */
|
||
|
DB 0FFh, 0FFh, 0E7h, 0C3h, 0C3h, 0E7h, 0FFh, 0FFh ; /* 8 */
|
||
|
DB 000h, 03Ch, 066h, 042h, 042h, 066h, 03Ch, 000h ; /* 9 */
|
||
|
DB 0FFh, 0C3h, 099h, 0BDh, 0BDh, 099h, 0C3h, 0FFh ; /* 10 */
|
||
|
DB 00Fh, 007h, 00Fh, 07Dh, 0CCh, 0CCh, 0CCh, 078h ; /* 11 */
|
||
|
DB 03Ch, 066h, 066h, 066h, 03Ch, 018h, 07Eh, 018h ; /* 12 */
|
||
|
DB 03Fh, 033h, 03Fh, 030h, 030h, 030h, 070h, 0F0h ; /* 13 */
|
||
|
DB 07Fh, 063h, 07Fh, 063h, 063h, 067h, 0E6h, 0C0h ; /* 14 */
|
||
|
DB 099h, 05Ah, 03Ch, 0E7h, 0E7h, 03Ch, 05Ah, 099h ; /* 15 */
|
||
|
DB 080h, 0E0h, 0F8h, 0FEh, 0F8h, 0E0h, 080h, 000h ; /* 16 */
|
||
|
DB 002h, 00Eh, 03Eh, 0FEh, 03Eh, 00Eh, 002h, 000h ; /* 17 */
|
||
|
DB 018h, 03Ch, 07Eh, 018h, 018h, 07Eh, 03Ch, 018h ; /* 18 */
|
||
|
DB 066h, 066h, 066h, 066h, 066h, 000h, 066h, 000h ; /* 19 */
|
||
|
DB 07Fh, 0DBh, 0DBh, 07Bh, 01Bh, 01Bh, 01Bh, 000h ; /* 20 */
|
||
|
DB 03Eh, 063h, 038h, 06Ch, 06Ch, 038h, 0CCh, 078h ; /* 21 */
|
||
|
DB 000h, 000h, 000h, 000h, 07Eh, 07Eh, 07Eh, 000h ; /* 22 */
|
||
|
DB 018h, 03Ch, 07Eh, 018h, 07Eh, 03Ch, 018h, 0FFh ; /* 23 */
|
||
|
DB 018h, 03Ch, 07Eh, 018h, 018h, 018h, 018h, 000h ; /* 24 */
|
||
|
DB 018h, 018h, 018h, 018h, 07Eh, 03Ch, 018h, 000h ; /* 25 */
|
||
|
DB 000h, 018h, 00Ch, 0FEh, 00Ch, 018h, 000h, 000h ; /* 26 */
|
||
|
DB 000h, 030h, 060h, 0FEh, 060h, 030h, 000h, 000h ; /* 27 */
|
||
|
DB 000h, 000h, 0C0h, 0C0h, 0C0h, 0FEh, 000h, 000h ; /* 28 */
|
||
|
DB 000h, 024h, 066h, 0FFh, 066h, 024h, 000h, 000h ; /* 29 */
|
||
|
DB 000h, 018h, 03Ch, 07Eh, 0FFh, 0FFh, 000h, 000h ; /* 30 */
|
||
|
DB 000h, 0FFh, 0FFh, 07Eh, 03Ch, 018h, 000h, 000h ; /* 31 */
|
||
|
DB 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h ; /* space */
|
||
|
DB 030h, 078h, 078h, 030h, 030h, 000h, 030h, 000h ; /* ! */
|
||
|
DB 06Ch, 06Ch, 06Ch, 000h, 000h, 000h, 000h, 000h ; /* " */
|
||
|
DB 06Ch, 06Ch, 0FEh, 06Ch, 0FEh, 06Ch, 06Ch, 000h ; /* # */
|
||
|
DB 030h, 07Ch, 0C0h, 078h, 00Ch, 0F8h, 030h, 000h ; /* $ */
|
||
|
DB 000h, 0C6h, 0CCh, 018h, 030h, 066h, 0C6h, 000h ; /* % */
|
||
|
DB 038h, 06Ch, 038h, 076h, 0DCh, 0CCh, 076h, 000h ; /* & */
|
||
|
DB 060h, 060h, 0C0h, 000h, 000h, 000h, 000h, 000h ; /* ' */
|
||
|
DB 018h, 030h, 060h, 060h, 060h, 030h, 018h, 000h ; /* ( */
|
||
|
DB 060h, 030h, 018h, 018h, 018h, 030h, 060h, 000h ; /* ) */
|
||
|
DB 000h, 066h, 03Ch, 0FFh, 03Ch, 066h, 000h, 000h ; /* * */
|
||
|
DB 000h, 030h, 030h, 0FCh, 030h, 030h, 000h, 000h ; /* + */
|
||
|
DB 000h, 000h, 000h, 000h, 000h, 030h, 030h, 060h ; /* , */
|
||
|
DB 000h, 000h, 000h, 0FCh, 000h, 000h, 000h, 000h ; /* - */
|
||
|
DB 000h, 000h, 000h, 000h, 000h, 030h, 030h, 000h ; /* . */
|
||
|
DB 006h, 00Ch, 018h, 030h, 060h, 0C0h, 080h, 000h ; /* / */
|
||
|
DB 07Ch, 0C6h, 0CEh, 0DEh, 0F6h, 0E6h, 07Ch, 000h ; /* 0 */
|
||
|
DB 030h, 070h, 030h, 030h, 030h, 030h, 0FCh, 000h ; /* 1 */
|
||
|
DB 078h, 0CCh, 00Ch, 038h, 060h, 0CCh, 0FCh, 000h ; /* 2 */
|
||
|
DB 078h, 0CCh, 00Ch, 038h, 00Ch, 0CCh, 078h, 000h ; /* 3 */
|
||
|
DB 01Ch, 03Ch, 06Ch, 0CCh, 0FEh, 00Ch, 01Eh, 000h ; /* 4 */
|
||
|
DB 0FCh, 0C0h, 0F8h, 00Ch, 00Ch, 0CCh, 078h, 000h ; /* 5 */
|
||
|
DB 038h, 060h, 0C0h, 0F8h, 0CCh, 0CCh, 078h, 000h ; /* 6 */
|
||
|
DB 0FCh, 0CCh, 00Ch, 018h, 030h, 030h, 030h, 000h ; /* 7 */
|
||
|
DB 078h, 0CCh, 0CCh, 078h, 0CCh, 0CCh, 078h, 000h ; /* 8 */
|
||
|
DB 078h, 0CCh, 0CCh, 07Ch, 00Ch, 018h, 070h, 000h ; /* 9 */
|
||
|
DB 000h, 030h, 030h, 000h, 000h, 030h, 030h, 000h ; /* : */
|
||
|
DB 000h, 030h, 030h, 000h, 000h, 030h, 030h, 060h ; /* ; */
|
||
|
DB 018h, 030h, 060h, 0C0h, 060h, 030h, 018h, 000h ; /* < */
|
||
|
DB 000h, 000h, 0FCh, 000h, 000h, 0FCh, 000h, 000h ; /* = */
|
||
|
DB 060h, 030h, 018h, 00Ch, 018h, 030h, 060h, 000h ; /* > */
|
||
|
DB 078h, 0CCh, 00Ch, 018h, 030h, 000h, 030h, 000h ; /* ? */
|
||
|
DB 07Ch, 0C6h, 0DEh, 0DEh, 0DEh, 0C0h, 078h, 000h ; /* @ */
|
||
|
DB 030h, 078h, 0CCh, 0CCh, 0FCh, 0CCh, 0CCh, 000h ; /* A */
|
||
|
DB 0FCh, 066h, 066h, 07Ch, 066h, 066h, 0FCh, 000h ; /* B */
|
||
|
DB 03Ch, 066h, 0C0h, 0C0h, 0C0h, 066h, 03Ch, 000h ; /* C */
|
||
|
DB 0F8h, 06Ch, 066h, 066h, 066h, 06Ch, 0F8h, 000h ; /* D */
|
||
|
DB 0FEh, 062h, 068h, 078h, 068h, 062h, 0FEh, 000h ; /* E */
|
||
|
DB 0FEh, 062h, 068h, 078h, 068h, 060h, 0F0h, 000h ; /* F */
|
||
|
DB 03Ch, 066h, 0C0h, 0C0h, 0CEh, 066h, 03Eh, 000h ; /* G */
|
||
|
DB 0CCh, 0CCh, 0CCh, 0FCh, 0CCh, 0CCh, 0CCh, 000h ; /* H */
|
||
|
DB 078h, 030h, 030h, 030h, 030h, 030h, 078h, 000h ; /* I */
|
||
|
DB 01Eh, 00Ch, 00Ch, 00Ch, 0CCh, 0CCh, 078h, 000h ; /* J */
|
||
|
DB 0E6h, 066h, 06Ch, 078h, 06Ch, 066h, 0E6h, 000h ; /* K */
|
||
|
DB 0F0h, 060h, 060h, 060h, 062h, 066h, 0FEh, 000h ; /* L */
|
||
|
DB 0C6h, 0EEh, 0FEh, 0FEh, 0D6h, 0C6h, 0C6h, 000h ; /* M */
|
||
|
DB 0C6h, 0E6h, 0F6h, 0DEh, 0CEh, 0C6h, 0C6h, 000h ; /* N */
|
||
|
DB 038h, 06Ch, 0C6h, 0C6h, 0C6h, 06Ch, 038h, 000h ; /* O */
|
||
|
DB 0FCh, 066h, 066h, 07Ch, 060h, 060h, 0F0h, 000h ; /* P */
|
||
|
DB 078h, 0CCh, 0CCh, 0CCh, 0DCh, 078h, 01Ch, 000h ; /* Q */
|
||
|
DB 0FCh, 066h, 066h, 07Ch, 06Ch, 066h, 0E6h, 000h ; /* R */
|
||
|
DB 078h, 0CCh, 0E0h, 070h, 01Ch, 0CCh, 078h, 000h ; /* S */
|
||
|
DB 0FCh, 0B4h, 030h, 030h, 030h, 030h, 078h, 000h ; /* T */
|
||
|
DB 0CCh, 0CCh, 0CCh, 0CCh, 0CCh, 0CCh, 0FCh, 000h ; /* U */
|
||
|
DB 0CCh, 0CCh, 0CCh, 0CCh, 0CCh, 078h, 030h, 000h ; /* V */
|
||
|
DB 0C6h, 0C6h, 0C6h, 0D6h, 0FEh, 0EEh, 0C6h, 000h ; /* W */
|
||
|
DB 0C6h, 0C6h, 06Ch, 038h, 038h, 06Ch, 0C6h, 000h ; /* X */
|
||
|
DB 0CCh, 0CCh, 0CCh, 078h, 030h, 030h, 078h, 000h ; /* Y */
|
||
|
DB 0FEh, 0C6h, 08Ch, 018h, 032h, 066h, 0FEh, 000h ; /* Z */
|
||
|
DB 078h, 060h, 060h, 060h, 060h, 060h, 078h, 000h ; /* [ */
|
||
|
DB 0C0h, 060h, 030h, 018h, 00Ch, 006h, 002h, 000h ; /* \ */
|
||
|
DB 078h, 018h, 018h, 018h, 018h, 018h, 078h, 000h ; /* ] */
|
||
|
DB 010h, 038h, 06Ch, 0C6h, 000h, 000h, 000h, 000h ; /* ^ */
|
||
|
DB 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0FFh ; /* _ */
|
||
|
DB 030h, 030h, 018h, 000h, 000h, 000h, 000h, 000h ; /* ` */
|
||
|
DB 000h, 000h, 078h, 00Ch, 07Ch, 0CCh, 076h, 000h ; /* a */
|
||
|
DB 0E0h, 060h, 060h, 07Ch, 066h, 066h, 0DCh, 000h ; /* b */
|
||
|
DB 000h, 000h, 078h, 0CCh, 0C0h, 0CCh, 078h, 000h ; /* c */
|
||
|
DB 01Ch, 00Ch, 00Ch, 07Ch, 0CCh, 0CCh, 076h, 000h ; /* d */
|
||
|
DB 000h, 000h, 078h, 0CCh, 0FCh, 0C0h, 078h, 000h ; /* e */
|
||
|
DB 038h, 06Ch, 060h, 0F0h, 060h, 060h, 0F0h, 000h ; /* f */
|
||
|
DB 000h, 000h, 076h, 0CCh, 0CCh, 07Ch, 00Ch, 0F8h ; /* g */
|
||
|
DB 0E0h, 060h, 06Ch, 076h, 066h, 066h, 0E6h, 000h ; /* h */
|
||
|
DB 030h, 000h, 070h, 030h, 030h, 030h, 078h, 000h ; /* i */
|
||
|
DB 00Ch, 000h, 00Ch, 00Ch, 00Ch, 0CCh, 0CCh, 078h ; /* j */
|
||
|
DB 0E0h, 060h, 066h, 06Ch, 078h, 06Ch, 0E6h, 000h ; /* k */
|
||
|
DB 070h, 030h, 030h, 030h, 030h, 030h, 078h, 000h ; /* l */
|
||
|
DB 000h, 000h, 0CCh, 0FEh, 0FEh, 0D6h, 0C6h, 000h ; /* m */
|
||
|
DB 000h, 000h, 0F8h, 0CCh, 0CCh, 0CCh, 0CCh, 000h ; /* n */
|
||
|
DB 000h, 000h, 078h, 0CCh, 0CCh, 0CCh, 078h, 000h ; /* o */
|
||
|
DB 000h, 000h, 0DCh, 066h, 066h, 07Ch, 060h, 0F0h ; /* p */
|
||
|
DB 000h, 000h, 076h, 0CCh, 0CCh, 07Ch, 00Ch, 01Eh ; /* q */
|
||
|
DB 000h, 000h, 0DCh, 076h, 066h, 060h, 0F0h, 000h ; /* r */
|
||
|
DB 000h, 000h, 07Ch, 0C0h, 078h, 00Ch, 0F8h, 000h ; /* s */
|
||
|
DB 010h, 030h, 07Ch, 030h, 030h, 034h, 018h, 000h ; /* t */
|
||
|
DB 000h, 000h, 0CCh, 0CCh, 0CCh, 0CCh, 076h, 000h ; /* u */
|
||
|
DB 000h, 000h, 0CCh, 0CCh, 0CCh, 078h, 030h, 000h ; /* v */
|
||
|
DB 000h, 000h, 0C6h, 0D6h, 0FEh, 0FEh, 06Ch, 000h ; /* w */
|
||
|
DB 000h, 000h, 0C6h, 06Ch, 038h, 06Ch, 0C6h, 000h ; /* x */
|
||
|
DB 000h, 000h, 0CCh, 0CCh, 0CCh, 07Ch, 00Ch, 0F8h ; /* y */
|
||
|
DB 000h, 000h, 0FCh, 098h, 030h, 064h, 0FCh, 000h ; /* z */
|
||
|
DB 01Ch, 030h, 030h, 0E0h, 030h, 030h, 01Ch, 000h ; /* { */
|
||
|
DB 018h, 018h, 018h, 000h, 018h, 018h, 018h, 000h ; /* | */
|
||
|
DB 0E0h, 030h, 030h, 01Ch, 030h, 030h, 0E0h, 000h ; /* } */
|
||
|
DB 076h, 0DCh, 000h, 000h, 000h, 000h, 000h, 000h ; /* ~ */
|
||
|
DB 000h, 010h, 038h, 06Ch, 0C6h, 0C6h, 0FEh, 000h ; /* Delta */
|
||
|
endif ; GISP_SVGA
|
||
|
|
||
|
ORG 1E6Eh
|
||
|
time_of_day:
|
||
|
BOP %BIOS_TIME_OF_DAY
|
||
|
IRET
|
||
|
|
||
|
ORG2 TIMER_INT_OFFSET
|
||
|
; The usual int8 handler modified for optimum performance.
|
||
|
; - stays in Intel code (no BOP)
|
||
|
; - keeps interrupts off when not needed
|
||
|
; - calls int 1c directly
|
||
|
;
|
||
|
push ds ; save some registers
|
||
|
push ax
|
||
|
|
||
|
mov ax, BIOS_VAR_SEGMENT
|
||
|
mov ds, ax
|
||
|
|
||
|
; inc time counters
|
||
|
; check for 24 hours, wrap point
|
||
|
|
||
|
.386
|
||
|
inc dword ptr ds:[TIMER_COUNT]
|
||
|
cmp dword ptr ds:[TIMER_COUNT], 0001800b0h
|
||
|
.286
|
||
|
jz i8v1
|
||
|
|
||
|
; check for floppy motor
|
||
|
|
||
|
dec byte ptr ds:[MOTOR_COUNT]
|
||
|
jz i8v2 ; costly outb happens 1/256 timer tics...
|
||
|
|
||
|
; Check for dummy_int in int1c vector
|
||
|
|
||
|
.386
|
||
|
cmp dword ptr ds:[BIOS_USER_TIMER*4], (BIOS_ROM_SEGMENT*10000h)+DUMMY_INT_OFFSET
|
||
|
.286
|
||
|
jnz i8v3
|
||
|
|
||
|
i8v0: ; send eoi
|
||
|
|
||
|
mov al, ICA_EOI
|
||
|
out ICA_MASTER_CMD, al
|
||
|
|
||
|
; restore the stack and return
|
||
|
|
||
|
pop ax
|
||
|
pop ds
|
||
|
iret
|
||
|
|
||
|
; handle 24-hour wrap
|
||
|
|
||
|
i8v1: .386
|
||
|
mov dword ptr ds:[TIMER_COUNT], 0
|
||
|
.286
|
||
|
mov byte ptr ds:[TIMER_OVFL], 1 ; 24 hour wrap, set OVFL bit
|
||
|
|
||
|
; handle the floppy motor stuff
|
||
|
|
||
|
i8v2: and byte ptr ds:[MOTOR_STATUS], 0f0h
|
||
|
mov al, 0ch
|
||
|
push dx
|
||
|
mov dx, 03f2h
|
||
|
out dx, al
|
||
|
jmp i8v4 ; n.b. dx already pushed
|
||
|
|
||
|
; Call user's timer handler (rare)
|
||
|
|
||
|
i8v3: push dx
|
||
|
i8v4: int BIOS_USER_TIMER
|
||
|
pop dx
|
||
|
|
||
|
jmp i8v0
|
||
|
|
||
|
|
||
|
;For old SoftPC's (that dont like 486 instructions) we put the old slow code
|
||
|
; in as well, and they use the BOP
|
||
|
|
||
|
ORG2 OLD_TIMER_INT_OFFSET
|
||
|
STI ;to let timer interrupt itself.
|
||
|
;Save current state just like the real thing, so that
|
||
|
;user timer routines know exactly which registers are
|
||
|
;saved and which aren't.
|
||
|
PUSH DS
|
||
|
PUSH AX
|
||
|
PUSH DX
|
||
|
;Now off to our code
|
||
|
BOP %BIOS_TIMER_INT
|
||
|
CLI ;to prevent interrupts until the IRET.
|
||
|
;Non Specific End-Of-Interrupt
|
||
|
MOV AL,20h
|
||
|
OUT 20h,AL
|
||
|
;Restore saved state
|
||
|
POP DX
|
||
|
POP AX
|
||
|
POP DS
|
||
|
;Any lower priority interrupts should occur before the IRET
|
||
|
IRET
|
||
|
|
||
|
|
||
|
;; The illegal Intel instruction handler
|
||
|
ORG2 ILL_OP_INT_OFFSET
|
||
|
BOP %BIOS_ILL_OP_INT
|
||
|
IRET
|
||
|
|
||
|
;Software int's called from base, keyboard break, print screen, timer int
|
||
|
; If one of the following three ORG's are changed, then SAS.H must also be
|
||
|
; changed to reflect the new values.
|
||
|
|
||
|
ORG2 KEYBOARD_BREAK_INT_OFFSET
|
||
|
INT BIOS_KEYBOARD_BREAK
|
||
|
BOP %BIOS_CPU_QUIT
|
||
|
|
||
|
ORG2 PRINT_SCREEN_INT_OFFSET
|
||
|
INT BIOS_PRINT_SCREEN
|
||
|
BOP %BIOS_CPU_QUIT
|
||
|
|
||
|
ORG2 USER_TIMER_INT_OFFSET
|
||
|
INT BIOS_USER_TIMER
|
||
|
BOP %BIOS_CPU_QUIT
|
||
|
|
||
|
ORG2 DUMMY_INT_OFFSET
|
||
|
IRET
|
||
|
|
||
|
; Called by the macintosh host to paste into the keyboard type-ahead buffer.
|
||
|
; Called with AH=5, CL=scan code, and CH=ascii character.
|
||
|
|
||
|
ORG2 BIOS_PASTE_OFFSET
|
||
|
INT BIOS_KEYBOARD_IO ; call BIOS keyboard function
|
||
|
BOP %BIOS_CPU_QUIT
|
||
|
|
||
|
|
||
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Print screen
|
||
|
|
||
|
ORG 1f54h
|
||
|
print_screen:
|
||
|
STI
|
||
|
PUSH AX
|
||
|
PUSH BX
|
||
|
PUSH CX
|
||
|
PUSH DX
|
||
|
PUSH DS
|
||
|
;::::::::::::::::::::::::::::::::: Setup DS to point to BIOS data area
|
||
|
MOV AX,BIOS_VAR_SEGMENT
|
||
|
MOV DS,AX
|
||
|
;::::::::::::::::::::::::::::::: Print screen already in progress ????
|
||
|
CMP BYTE PTR DS:[100H],1
|
||
|
JE end_print
|
||
|
;::::::::::::::::::::::::::::::::::::::::::::::: Set print screen busy
|
||
|
MOV BYTE PTR DS:[100h],1
|
||
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::: Get video status
|
||
|
MOV AH,15
|
||
|
INT 10H
|
||
|
MOV CH,AH ;No of columns
|
||
|
;:::::::::::::::::::::::::::::::::: Setup no. of columns/rows to print
|
||
|
MOV CL,BYTE PTR DS:[084h] ; No. of rows to print is rows in current mode
|
||
|
;::::::::::::::::::::::::::::::::::: Print line feed / carriage return
|
||
|
CALL print_crlf
|
||
|
;:::::::::::::::::::::::::::::::::::::::::: Get current cursor postion
|
||
|
PUSH CX
|
||
|
MOV AH,3
|
||
|
INT 10H
|
||
|
POP CX
|
||
|
;::::::::::::::::::::::::::::::::::::::::::::::::: Save cursor postion
|
||
|
PUSH DX ;save current cursor postion
|
||
|
XOR DH,DH ;current row being processed
|
||
|
start_print_col:
|
||
|
XOR DL,DL ;current column being processed
|
||
|
;::::::::::::::::::::::::::::::::::::::::::::::: Start printing screen
|
||
|
start_print_row:
|
||
|
;:::::::::::::::::::::::::::::::::::::::::::::::::: Set cursor postion
|
||
|
PUSH DX ;save current row,column
|
||
|
MOV AH,2
|
||
|
INT 10H
|
||
|
;::::::::::::::::::::::::::::::::::: Read character at current postion
|
||
|
MOV AH,8
|
||
|
INT 10H
|
||
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::: Print character
|
||
|
OR al,al
|
||
|
JNZ print_char
|
||
|
MOV AL,20H
|
||
|
print_char:
|
||
|
XOR DX,DX
|
||
|
XOR AH,AH
|
||
|
INT 17H
|
||
|
;:::::::::::::::::::::::::::::::::::::::::::: Check for printer errors
|
||
|
POP DX ;Restore current row,column
|
||
|
AND AH,25H
|
||
|
JZ cont2
|
||
|
MOV BYTE PTR DS:[100H],0FFH
|
||
|
JMP short exit_print
|
||
|
;::::::::::::::::::::::::::::::::::::::::::: Move to mext print column
|
||
|
cont2:
|
||
|
INC DL ;Inc current column
|
||
|
CMP DL,CH ;Current col compared to no. of cols
|
||
|
JB start_print_row
|
||
|
;:::::::::::::::::::::::::::::::::::::::::: End of column, print CR/LF
|
||
|
CALL print_crlf
|
||
|
;:::::::::::::::::::::::::::::::::::::::::::::::::: More rows to print
|
||
|
INC DH ;Inc current row
|
||
|
CMP DH,CL ;Current row compared to no. of rows
|
||
|
JBE start_print_col
|
||
|
MOV BYTE PTR DS:[0100H],0
|
||
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Exit print
|
||
|
exit_print:
|
||
|
;:::::::::::::::::::::::::::::::::::::; Restore orginal cursor postion
|
||
|
POP DX
|
||
|
MOV AH,2
|
||
|
INT 10H
|
||
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::: Tidy up and exit
|
||
|
end_print:
|
||
|
POP DS
|
||
|
POP DX
|
||
|
POP CX
|
||
|
POP BX
|
||
|
POP AX
|
||
|
IRET
|
||
|
|
||
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Print CR/LF
|
||
|
print_crlf:
|
||
|
PUSH DX
|
||
|
XOR DX,DX
|
||
|
MOV AX,0DH
|
||
|
INT 17H
|
||
|
XOR DX,DX
|
||
|
MOV AX,0AH
|
||
|
INT 17H
|
||
|
POP DX
|
||
|
RET
|
||
|
|
||
|
|
||
|
ORG2 START_OFFSET
|
||
|
start_addr:
|
||
|
JMP reset_ref
|
||
|
date:
|
||
|
DB "07/03/95"
|
||
|
|
||
|
org 01ffeh
|
||
|
bios_tail:
|
||
|
DB MODEL_BYTE
|
||
|
code ENDS
|
||
|
END
|
||
|
|
||
|
|