💾 Archived View for uscoffings.net › retro-computing › collection › tandy-2000 › t2k_bios_2.00.00.as… captured on 2024-07-09 at 00:42:24.

View Raw

More Information

⬅️ Previous capture (2023-01-29)

🚧 View Differences

-=-=-=-=-=-=-

; Tandy 2000 HD 2.00.00 BIOS
; Disassembled and documented by Chuck Coffing <clc@alum.mit.edu>
; Last updated 20120102
; Assemble with nasm: nasm -f bin -o t2k_bios.bin t2k_bios.asm
;
; Tags:
; {TRM}		Technical Reference Manual.
; {PR}		Programmer's Reference.
; {?}		Research question for myself.
; {ODD}		Oddity; cruft or bug or unfinished feature?
; {FEAT}	Possible new feature.
; {BUG}		Probably a bug.
;
; Memory map:
; 0040e	{?} segment of indirect area
; 00420	{?} font related
; 00422	Equipment list
; 00424 <<4 to get amount of (reliable) memory
; 00426 0
; 00428 copy of [00424]
; 0042a 0
; 0042c Segment of video buffer
; 00432	System diagnostic failed flags:
;	0x10  bad ROM checksum
;	0x20  bad RAM
; 00442	Boot disk number (0 = FD0, 2 = HD0, ...)
; 00444	Boot offset
; 00446	Boot segment
; 0044a	{?} floppy related
; 00472	0
; 00474	Segment of video buffer
; 00476   16 byte table of pointers to character fonts
; 00486	Address Control Register
; 00487	device power-on / reset byte
; 0048a remaining tries to boot from FD; initially 10
; 0048b remaining tries to boot from HD; initially 10
; 00500	Bottom of boot stack
; 00600	Top of boot stack
; 18000 number of 64k banks of detected good memory
; 18002 0
; 18004 2 byte Checksum of 8k ROM; should be 0
; 18006 failing memory: offset of first bad byte
; 18008 failing memory: segment of first bad byte
; 1800a failing memory: stored/expected byte (stored, read both 0 if ok)
; 1800b failing memory: read/actual byte (stored, read both 0 if ok)
; 1800c first canonical segment beyond end of known-good RAM
; 18020 {? 20 bytes of 0}
; 18040 current cursor position
; 18042 current text character attr
; 18043 current fill (scroll) character attr
; 18050 1000; disk related (maybe number of retries, or timeout?)
; 18060 offset where boot sector was placed
; 18062 segment where boot sector was placed
; 18064 offset where boot sector was placed
; 18066 segment where boot sector was placed
; 19000 FD interrupt handler
; 19002 status of last disk op
; 1902c FD param table
; 1903e {?} IO port indirection?
; 19040 {?} IO port indirection?
; 19042 {?} IO port indirection?
; 19044 {?} IO port indirection?
; 19046	
; 1a000 modified copy of HDROMImage  {?} sum of something (see LFB2)
; 1a002 {?} length of something (see L10f5)
; 1a008
; 1a016
; 1a026 HD0 parameter table
; 1b000 boot sector
; f8000 character generator {TRM 68}
; fe000 - 0xfffff  ROM {TRM 68}.
;
; IO ports:
; 0x00 - 0x7f  PCS0  {TRM 47}
;   0x02  DMA multiplexer  {TRM 49}
;   0x04 terminal count strobe (terminates DMA). FD  {TRM 85}
;   0x30 8272 main status register
;   0x60, 62, 70, 72  interrupt controller {TRM 70}
; PCS2  odd bytes: address control register; event bytes: 9007  {TRM 63}
;
; Things to research:
;
; continue at -------
;
; .isWriteChar - logic/comment seems wrong/  is 0x10 write char, or not?
; 
;
; finish SetUpHDROM; param table; follow boot sector through
;
; doc meanings/offsets of RecordBootParams
; LFB2
; finish font: line 1075
; messages line 811
; comment line 189-   hardware detection
;
; What is ds=0x1a00?
;  Seems to be used as an indirect area.
;
; What is at ds=0x1800?  system status area?
;
; What is at ds=0x1900?   Copy of some portion of BIOS, modified
;
; To verify:
; - High characters (128-255) have same font as low?
;
; Future features:
; - serial boot
; - tool to read revision port of mainboard {TRM 95}
; - tool to read stats of HiRes board {TRM 280}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BITS	16
ORG	0
CPU	186

	; CS = 0xfe00
	; BP = 0x1f6a or 0x1f7a or 0x1f8a or 0x1f9a
StartOfBoot:
	cli					; Disable interrupts during mem test & system diagnostics
						; Re-enabled right before PrintMemoryBanner.
	cld
	jmp	short	start
	nop
	
	; {?} what prints these?
	; Note that strings are terminated with 0xff
	db	'BOOT ROM version 02.00.00', 0x0d, 0x0a
	db	'Copyright 1983,84 Tandy Corp.', 0x0d, 0x0a
	db	'All rights reserved.', 0x0d, 0x0a, 0xff

start:						; L56
	mov		ax, 0x50
	mov		ss, ax
	mov		sp, 0x100		; Stack starts at 0x00600
	
	mov		ax, 0x0
	mov		ds, ax
	mov	word	[0x8], iretInstr	; NMI interrupt vector
	mov		[0xa], cs		;

;; Set up 8237 DMA controller
	mov		al, [cs:bp+0x5]		; in release builds, al <- 0x10
	mov		dx, 0x0
	out		dx, al			; refresh clock gate on {TRM appendix C}
	mov		al, 0xb4
	mov		dx, 0x46
	out		dx, al			; 8253 PIT Load Mode Word {TRM appendix C}
	nop
	nop
	mov		al, 0x1f
	mov		dx, 0x44
	out		dx, al			; 8253 PIT Load Counter 2 {TRM appendix C}
	nop
	nop
	mov		al, 0x0
	mov		dx, 0x44
	out		dx, al			; 8253 PIT Load Counter 2 {TRM appendix C}
	nop
	nop

;; Detect amount of memory
	cld
	mov		bh, 0xe			; At most 14 banks (=896k) supported. TRM says 784k
						; max, but Envision Designs sold a board supporting 896k.
	mov		bl, 0x0			; but zero 64k banks detected so far.
	mov		ax, 0x0
	mov		ds, ax
	mov		si, 0x0
.detectAnother64k:
	mov		ax, 0x5a5a
	mov		[si], ax		; Write 0x5a5a to ds:0
	mov		cx, 0x3e8
.delay1:
	loop		.delay1			; delay 1000*125ns = 125us
	cmp		ax, [si]		; Did memory hold 0x5a5a for 125us?
	jne		.memorySized
	not		ax			; Invert, and test again, to be sure
	mov		[si], ax
	mov		cx, 0x3e8
.delay2:
	loop		.delay2
	cmp		ax, [si]		; Did memory hold 0xa5a5?
	jne		.memorySized
	mov		ax, ds			; Yes, so...
	add		ax, 0x1000		; ...move to next 64k.
	mov		ds, ax
	inc		bl			; Note another bank of RAM.
	cmp		bl, bh			; Have we hit the max supported memory?
	jb		.detectAnother64k
.memorySized:
	cmp		bl, 0x2			; Detected >= 128k?
	jae		.memoryCorrectlySized
	mov		bl, 0x2			; T2K shipped with minimum 128k on mainboard, so assume that.
.memoryCorrectlySized:
	mov		bh, bl			; Remember # installed 64k banks, in BH

;; Memory test
	mov		bl, 0x0
	mov		ax, 0x0
	mov		ds, ax
	mov		si, 0xc			; For first bank, do not
	mov		cx, 0x7ffa		; overwrite first 3 interrupt vectors.
	jmp	short	.setupPattern
.setupNextTest:
	mov		si, 0x0			; All other banks get
	mov		cx, 0x8000		; completely overwritten.
.setupPattern:
	mov		dx, 0x5a5a
.loop:
	mov		[si], dx		; Write 0x5a5a out...
	nop					; ...wait...
	lodsw					; ...load back into AX...
	cmp		ax, dx			; ...and verify.
	jne		.testFailed
	inc		dl			; Vary test pattern high...
	dec		dh			; ...and low.
	nop
	nop
	loop		.loop
	mov		ax, ds			; Success; move to next 64k.
	add		ax, 0x1000
	mov		ds, ax
	inc		bl			; Note another good bank of RAM.
	cmp		bl, bh			; Ran out of banks to test?
	jb		.setupNextTest		; No; test next.
	jmp	short	.done
.testFailed:
	cmp		bl, 0x2			; Failed in first 2 banks?
	jae		.findBadByte
	mov		bl, 0x2			; Oh well... need 128k, so allow and hope.
.findBadByte:
	dec		si			; Back up to failed word.
	mov		cl, dh			;   DX is expected,
	mov		ch, ah			;   AX is actual.
	cmp		al, dl			; Was low byte correct?
	je		.done			; Yes, so high must be bad (SI points, CX compares)
	dec		si			; Low byte is bad; SI points,
	mov		cl, dl			;   CX compares (CL expected, AL actual).
	mov		ch, al			;
.done:
	mov		al, [cs:bp+0x1]		; Hard-coded max # of banks
	cmp		bl, al
	jbe		.doneCapped
	mov		bl, al			; Enforce cap
.doneCapped:
	and		bl, 0xfe		; Clear low bit (upgrades come in 128k, so fail in 128k chunks)
	mov		bh, 0x0			; No longer care about # physical banks.
	mov		di, bx			; DI is final # banks of good RAM (>=2)

;; some hardware init
	mov		ax, [cs:bp+di+0x2]	; Get byte for ACR and device reset
	mov		dx, 0x101
	out		dx, al			; Address Control Register {TRM appendix C, 280}
	mov		al, ah
	mov		dx, 0x0
	out		dx, al			; Power up / reset devices

;; Save memory diags, etc
	mov		dx, ds
	mov		ax, 0x1800
	mov		ds, ax
	mov		ax, 0x0
	mov		es, ax
	mov		al, [cs:bp+0x0]		; Index of hardware profile; usually 3
	mov		[es:0x420], al		; Save hardware profile index for later; configures fonts
	mov		bh, 0x0			; {ODD BH is already 0}
	mov		[0x0], bx		; [0x18000] <- # good 64k banks
	mov		di, bx			; {ODD DI is already # good banks}
	mov		ax, [cs:bp+di+0x2]	; Get byte for ACR again
	mov		[es:0x486], al		; Address Control Register
	mov		[es:0x487], ah
	mov	word	[es:0x432], 0x0		; System diagnostic defaults to good.
	mov		[0x6], si		; Offset of byte of bad memory
	mov		[0x8], dx		; Segment of byte of bad memory
	mov		[0xa], cl		; stored/expected byte (no bad mem? cl=ch=0)
	mov		[0xb], ch		; read/actual byte (no bad mem? cl=ch=0)
	mov		ax, si
	shr		ax, 0x4
	add		ax, dx
	mov		[0xc], ax		; Canonical segment of first address beyond known-good RAM
	cmp		ax, 0x2000
	jae		.enoughGoodRam
	mov		ax, 0x2000
	jmp	short	.badRam
.enoughGoodRam:
	test		ax, 0x1fff
	jz		.multipleOf128KOk
	and		ax, 0xe000		; Round down to prior multiple of 128k
	jmp	short	.badRam
.multipleOf128KOk:
	cmp		si, byte +0x0		; {BUG si==0 is not the most correct test of all mem good}
	jz		.goodRam
.badRam:
	or	word	[es:0x432], 0x20	; Fail system diagnostic due to bad RAM in lowest 128k
.goodRam:
	mov		[es:0x424], ax		; Amount of (reliable) memory (>>4)
	mov	word	[es:0x426], 0x0
	mov		[es:0x428], ax
	sub		ax, 0x140		; -5k
	mov	word	[es:0x472], 0x0		; 
	mov		[es:0x474], ax		; Video segment buffer
	mov	word	[es:0x42a], 0x0
	mov		[es:0x42c], ax

;; Checksum the ROM
	mov		si, 0x0
	mov		cx, 0x1000
	xor		ax, ax
.loopChecksum:
	add		al, [cs:si]
	inc		si
	add		ah, [cs:si]
	inc		si
	loop		.loopChecksum
	mov		[0x4], ax		; [0x18004] = checksum of all 8k of ROM
	or		ax, ax
	jz		.finishedRomChecksum	; {? is there a byte somewhere to compensate, to make it 0?}
	or	word	[es:0x432], 0x10	; Fail system diagnostic due to nonzero checksum of ROM
.finishedRomChecksum:

;; Detect hi-res board
	mov		ax, 0x0
	mov		ds, ax
	mov		dx, 0x180
	in		al, dx			; Hi-res board status {TRM 281}
	mov		cl, 0x28		; Default equipment list: {PR 233}
	mov		ch, 0x21		;	FD1, reserved, BW monitor, joysticks
	cmp		al, 0xff		; No response on this IO port?
	je		.doneDetectingHiRes
	test		al, 0x1			; have HiRes board? (0=yes)
	jz		.configHiResPalette
	or		cl, 0x1			; no HiRes: monochrome graphics option {PR 233}
	or		ch, 0x4			; reserved {PR 233}
	jmp	short	.doneDetectingHiRes
.configHiResPalette:
	push		ax			; See {TRM 280}
	mov		dx, 0x198		; low-intensity background:
	mov		al, 0x0			;	black
	out		dx, al
	mov		dx, 0x19a		; low-intensity character:
	mov		al, 0xf			;	white
	out		dx, al
	mov		dx, 0x19c		; hi-intensity background:
	mov		al, 0x0			;	black
	out		dx, al
	mov		dx, 0x19e		; hi-intensity character:
	mov		al, 0x7			;	white
	out		dx, al
	pop		ax
	test		al, 0x20		; HiRes status bit: "future use" {TRM 281}
	jnz		.hiResFutureBit
	test		al, 0x2			; HiRes status bit:
	jnz		.plane0Only		;	3 planes installed?
	or		cl, 0x2			;	monochrome graphics option {PR 233} {ODD}
	jmp	short	.doneProbingHiRes
.plane0Only:
	or		cl, 0x4			;	mono with color option {PR 233}
	jmp	short	.doneProbingHiRes
.hiResFutureBit:
	or		cl, 0x6			;	mono + mono with color {PR 233}
.doneProbingHiRes:
	or		ch, 0x2			;	color {PR 233}
.doneDetectingHiRes:
	mov		[0x422], cx		; Set equipment list

;; Default all remaining interrupts to be ignored
	mov		ax, cs
	mov		ds, ax
	mov		ax, 0x0
	mov		es, ax
	cld
	mov		di, 0xc			; First 3 are already set.
	mov		cx, 0xfd
.setDefaultIntHandlers:
	mov		ax, iretInstr
	stosw
	mov		ax, 0xfe00
	stosw
	loop		.setDefaultIntHandlers

;; Patch up interrupts from patch table
	mov		si, IntPatchTable
	nop
.patchInts:
	lodsw					; Load offset to change in IDT
	cmp		ax, 0xffff
	jz		.donePatchingInts
	mov		di, ax
	movsw					; Patch IDT with offset of handler
	jmp	short	.patchInts
.donePatchingInts:

;; Init some hardware
	mov		ax, cs
	mov		ds, ax
	mov		si, ProgramFoo1
	nop
	call		OutPorts
	mov		si, ProgramFoo2
	nop
	call		OutPorts
	mov		si, ProgramFoo3
	nop
	call		OutPorts

;; Load character fonts
	mov		ax, cs
	mov		es, ax
	mov		bx, CharSet8x8		; 128 chars * 8x8 cells = 1024 = 0x400 bytes
	nop
	mov		al, 0x1			; Set char font, for 0-127 8x8
	mov		ah, 0x10		; Get/set char font
	int		82			; Video interrupt
	mov		bx, CharSet8x8
	nop
	mov		al, 0x3			; Set char font, for 128-255 8x8
	mov		ah, 0x10		; Get/set char font
	int		82			; Video interrupt
	mov		bx, CharSet8x16		; 128 chars * 8x16 cells = 2048 = 0x800 bytes
	nop
	mov		al, 0x5			; Set char font, for 0-127 8x16
	mov		ah, 0x10		; Get/set char font
	int		82			; Video interrupt
	mov		bx, CharSet8x16
	nop
	mov		al, 0x7			; Set char font, for 128-255 8x16
	mov		ah, 0x10		; Get/set char font
	int		82			; Video interrupt

;; Clear screen
	mov		ax, 0x1800
	mov		ds, ax
	mov		bl, 0xa			; foreground color
	call		PrintFormFeed

;; Program the video card
	mov		ax, cs
	mov		ds, ax
	mov		si, Program9007
	nop
	call		OutPorts

;;
	cld
	mov		ax, cs
	mov		ds, ax			; {ODD useless to set DS for stosw; DS also set below}
	mov		ax, 0x1800
	mov		es, ax
	mov		ax, 0x0
	mov		di, 0x20
	mov		cx, 0xa			; Zero out ten words:
rep	stosw					;   memset(0x18020, 0, 20)

;;
	sti
	call		PrintMemoryBanner

;;
	call		Delay			; {? Probably gives HD more time to spin up}
	mov		ax, 0x1800
	mov		ds, ax
	mov		ax, 0x0
	mov		es, ax
	mov	word	[0x2], 0x0		; [18002] <- 0x0
	mov	byte	[es:0x48a], 0xa		; 10 retries to read from FD at boot
	mov	byte	[es:0x48b], 0xa		; 10 retries to read from HD at boot
	push		ds
	push		es
	call		BootFromFD
	pop		es
	pop		ds
	jc		.fdFailedTryHd
	mov		al, 0x0			; booted from FD0
	call		.goodBoot
.fdFailedTryHd:
	push		ds
	push		es
	call		BootFromHD
	pop		es
	pop		ds
	jc		.hang
	mov		al, 0x2			; booted from HD0
	call		.goodBoot
.hang:						; {FEAT print failure to explain hang}
	jmp	short	.hang
.goodBoot:
	push		ds
	push		es
	mov		[es:0x442], al		; Note FD vs HD boot
	mov		ax, [0x64]		; Get offset of boot sector
	mov		[es:0x444], ax		; ...save to standard BIOS area.
	mov		ax, [0x66]		; Get segment of boot sector (0x1b00)
	mov		[es:0x446], ax		; ...save to standard BIOS area.
	mov		es, ax
	call	far	[0x64]			; Call bootsector.  Will hang if it returns.
	pop		es			; {FEAT print failure to explain hang}
	pop		ds
	ret

errRet:						; L331
	jmp	short	stcAndRet		; {ODD What's the point of this?}
stcAndRet:					; L333
	stc
	jmp	short	andRet
clcAndRet:					; L336
	clc
andRet:
	ret

	; Note: DS = 0x1800
RecordBootParams:
	mov		[0x50], cx		; {ODD nothing uses this?}
	mov		[0x52], cx		; {ODD nothing uses this?}
	mov	word	[0x64], 0x0		; Offset of boot sector
	mov	word	[0x66], 0x1b00		; Segment of boot sector
	mov	word	[0x60], 0x0		; Offset of boot sector {ODD BootFromFD sets 60 but .goodBoot reads 64}
	mov	word	[0x62], 0x1b00		; Segment of boot sector
	ret

BootFromFD:					; L359
	mov		cx, 0x3e8		; {ODD stuffed into [0x50] but not used}
	call		RecordBootParams
	call		SetUpFDROM
.retry:
	mov		dl, 0x0			; use FD not HD
	mov		ah, 0x0			; Reset floppy disk
	int		86			; Int86FDHD
	or		ah, ah
	jnz		.checkError
	mov		dh, 0x0			; head 0
	mov		dl, 0x0			; use FD not HD; FD#0
	mov		ch, 0x0			; cylinder 0
	mov		cl, 0x1			; sector 1
	mov		al, 0x1			; 1 sector
	les		bx, [0x60]		; Where to put data
	mov		ah, 0x2			; Read sector(s) from floppy disk
	int		86			; Int86FDHD
	or		ah, ah			; read ok?
	jz		.ok
	dec	byte	[es:0x48a]		; consumed a retry
	jnz		.retry
	jmp	short	.badRead
	nop
.ok:
	cmp		al, 0x1			; read the 1 sector requested?
	jnz		.badRead
	jmp	short	clcAndRet
.checkError:
	test		ah, 0x7f
	jnz		.badRead		; ok?
	jmp	short	stcAndRet		; error!
.badRead:
	jmp	short	errRet

BootFromHD:					; L39B
	mov		cx, 0x3e8		; {ODD stuffed into [0x50] but not used}
	call		RecordBootParams
	call		SetUpHDROM
.retry:
	mov		dl, 0x80		; use HD not FD
	mov		ah, 0x0			; Reset
	int		86			; Int86FDHD
	or		ah, ah
	jnz		.fail
	mov		dh, 0x0			; head 0
	mov		dl, 0x80		; use HD not FD
	mov		ch, 0x0			; cylinder 0
	mov		cl, 0x1			; sector 1
	mov		al, 0x1			; read 1 sector
	les		bx, [0x60]		; Where to put data
	mov		ah, 0x2			; Read sector(s)
	int		86			; Int86FDHD
	or		ah, ah
	jz		.ok
	dec	byte	[es:0x48b]		; consumed a retry
	jnz		.retry
	jmp	short	.fail
	nop
.ok:
	cmp		al, 0x1			; Expect al == 1, or...
	jnz		.fail			;	error!
	jmp		clcAndRet		; success
	jmp		stcAndRet		; {ODD how can anything get here?} error!
.fail:
	jmp		errRet
iretInstr:					; L3DB
	iret

	;; Common interrupt handling routines; see patch table at L82C
;L3DC:						; {? unused?}
	push		ax
	mov		ax, 0x1
	jmp	short	L3FE
Int0DivideError:				; L3E2
	push		ax
	mov		ax, 0x2
	jmp	short	L3FE
IntSystemTimer:					; L3E8
	push		ax
	mov		ax, 0x4
	jmp	short	L3FE
L3EE:						; {? unused?}
	push		ax
	mov		ax, 0x8
	jmp	short	L3FE
L3F4:
	push		ax
	mov		ax, 0x40
	jmp	short	L3FE
L3FA:
	push		ax
	mov		ax, 0x80
L3FE:
	push		ds
	push		bx
	mov		bx, 0x0
	mov		ds, bx
	or		[0x432], ax		; {? setting system diagnostic flag, because
						;	unexpected int during boot?}
	pop		bx
	pop		ds
	pop		ax
	iret

;-----------
	sti
	push		ds
	pusha
	call		L487
	popa
	pop		ds
	iret

	sti
	push		ds
	pusha
	call		L48E
	popa
	pop		ds
	iret

	sti
	push		ds
	pusha
	mov		si, 0x20
	call		L474
	jz		L42A
L42A:
	call		L49F
	popa
	pop		ds
	iret

	sti
	push		ds
	pusha
	mov		si, 0x28
	call		L474
	jz		L43B
L43B:
	call		L487
	popa
	pop		ds
	iret

Int118:						; L441
	sti
	push		ds
	pusha
	mov		si, 0x2c
	call		L474
	jz		L44C
L44C:
	call		L487
	popa
	pop		ds
	iret

Int120:						; L452
	sti
	push		ds
	pusha
	mov		si, 0x30
	call		L474
	jz		L45D
L45D:
	call		L48E
	popa
	pop		ds
	iret

Int121:						; L463
	sti
	push		ds
	pusha
	mov		si, 0x32
	call		L474
	jz		L46E
L46E:
	call		L48E
	popa
	pop		ds
	iret

	; {? Seems like this is a common handler for ints; si differs}
L474:
	mov		ax, 0x1800
	mov		ds, ax
	mov		ax, 0xffff
	jmp	short	.L481
	mov		ax, 0x0
.L481:
	nop
	nop
	nop
	or		ax, ax
	ret

L487:
	mov		dx, 0x60		; {TRM appendix C} 8259A-2 write command words
	mov		al, 0x20
	jmp	short	L493
L48E:
	mov		dx, 0x70A		; {TRM appendix C} 8259A-2 write command words
	mov		al, 0x20
L493:
	cli
	out		dx, al			; {TRM appendix C} 8259A-2 write command words
	mov		al, 0xb
	out		dx, al			; {TRM appendix C} 8259A-2 write command words
	nop
	nop
	in		al, dx
	or		al, al
	jnz		L4A7
L49F:
	cli
	mov		dx, 0xff22		; {? seems like a common way to finish ints?}
	mov		ax, 0x8000
	out		dx, ax
L4A7:
	sti
	ret

Delay:						; L4AC
	mov		bx, 0x3e8
.top:
	call		.delay62us		; call 1000 times; ~62+ ms?
	dec		bx
	jnz		.top
	ret
	out		dx, al			; {ODD Never executed?}
.delay62us:
	mov		cx, 0x1f4		; 500 cycles * 125 nsec = ~62us
.delay:
	loop		.delay
	ret

OutPorts:
	lodsb					; load length byte into al
	or		al, al			; zero length?  nevermind.
	jz	short	.done
.one:
	dec		al			
	jnz		.two
	lodsw
	mov		dx, ax			; dx <- IO port
	lodsb					; al <- data for port
	out		dx, al
	jmp	short	OutPorts
.two:
	lodsw
	mov		dx, ax			; dx <- IO port
	lodsw					; ax <- data for port
	out		dx, ax
	jmp	short	OutPorts
.done:
	ret

	; length of data, 16-bit IO port, data
ProgramFoo1:
	db 0x02, 0x28, 0xFF, 0xC0, 0x00
	db 0x02, 0x2A, 0xFF, 0x07, 0x00
	db 0x02, 0x38, 0xFF, 0x60, 0x00
	db 0x02, 0x3A, 0xFF, 0x65, 0x00
	db 0x02, 0x34, 0xFF, 0x02, 0x00
	db 0x02, 0x36, 0xFF, 0x03, 0x00
	db 0x02, 0x32, 0xFF, 0x07, 0x00
	db 0x00
ProgramFoo2:
	db 0x01, 0x60, 0x00, 0x13		; 8259A-2 / write command / 
	db 0x01, 0x62, 0x00, 0x70
	db 0x01, 0x62, 0x00, 0x0D
	db 0x01, 0x62, 0x00, 0xEB
	db 0x00
ProgramFoo3:
	db 0x01, 0x70, 0x00, 0x13		; 8259A-2 / write command /
	db 0x01, 0x72, 0x00, 0x78
	db 0x01, 0x72, 0x00, 0x0d
	db 0x01, 0x72, 0x00, 0xfc
	db 0x00
Program9007:
	db 0x01, 0x2c, 0x01, 0x00		; 9007 / R16 /
	db 0x01, 0x2c, 0x01, 0x00		; 9007 / R16 /
	db 0x01, 0x2c, 0x01, 0x00		; 9007 / R16 /
	db 0x01, 0x2c, 0x01, 0x00		; 9007 / R16 /
	db 0x01, 0x00, 0x01, 0x6a		; 9007 / R00 /
	db 0x01, 0x02, 0x01, 0x4f
	db 0x01, 0x04, 0x01, 0x10
	db 0x01, 0x06, 0x01, 0x08
	db 0x01, 0x08, 0x01, 0x08
	db 0x01, 0x0a, 0x01, 0x21
	db 0x01, 0x0c, 0x01, 0x52
	db 0x01, 0x0e, 0x01, 0x18
	db 0x01, 0x10, 0x01, 0x2f
	db 0x01, 0x12, 0x01, 0xb8
	db 0x01, 0x14, 0x01, 0x6a
	db 0x01, 0x16, 0x01, 0x02
	db 0x01, 0x18, 0x01, 0x00
	db 0x01, 0x1a, 0x01, 0x36
	db 0x01, 0x1c, 0x01, 0x00
	db 0x01, 0x1e, 0x01, 0x00
	db 0x01, 0x20, 0x01, 0xfe
	db 0x01, 0x22, 0x01, 0xfe
	db 0x01, 0x24, 0x01, 0xfe
	db 0x01, 0x26, 0x01, 0x00
	db 0x01, 0x28, 0x01, 0x00
	db 0x01, 0x2e, 0x01, 0x00
	db 0x01, 0x30, 0x01, 0x00
	db 0x01, 0x32, 0x01, 0x00
	db 0x01, 0x34, 0x01, 0x00
	db 0x01, 0x2a, 0x01, 0x00
	db 0x01, 0x2a, 0x01, 0x00
	db 0x01, 0x2a, 0x01, 0x00
	db 0x01, 0x2a, 0x01, 0x00
	db 0x00

PrintMemoryBanner:
	push		ds
	push		es
	mov		ax, 0x1800
	mov		ds, ax
	mov		ax, 0x0
	mov		es, ax
	mov		ax, [es:0x432]		; Get system diagnostic (0 is good)
	or		ax, ax
	jnz		.badDiag
	mov		bl, 0xa			; light green
	call		PrintEmptyChar
	mov		si, sMemorySize
	nop
	call		PrintString
	mov		si, [0x0]		; 0x18000 number 64k banks detected good
	sub		si, byte +0x2
	add		si, si
	add		si, s128k
	call		PrintString		; Print memory size
	mov		si, sKilobyteLabel
	nop
	call		PrintString
	call		PrintCRLFBeep
	jmp	short	.done
.badDiag:
	mov		bl, 0xa			; light green
	call		PrintEmptyChar
	mov		si, sSystemFailsDiag
	nop
	call		PrintString
	call		PrintCRLFBeep
.lockup:
	jmp	short	.lockup
.done:
	pop		es
	pop		ds
	ret

PrintCRLFBeep:
	mov		bl, 0xa			; light green
	call		PrintEmptyChar
	mov		si, sCRLF
	nop
	jmp	short	PrintString
	mov		si, sBeep
	nop
	jmp	short	PrintString

;	{ODD How to get here?}
	mov		si, s2Spaces
	nop

PrintString:					; L602
	push		ax
	push		bx
	mov		bl, 0xf			; Foreground color white
.nextChar:
	mov		al, [cs:si]
	inc		si
	cmp		al, 0xff		; string terminator?
	jz		.endOfString
	call		PrintChar
	jmp	short	.nextChar
.endOfString:
	pop		bx
	pop		ax
	ret

PrintEmptyChar:					; L616
	push		ax
	mov		al, 0x0			; {ODD Why print ascii 0 vs space?}
	call		PrintChar
	pop		ax
	ret

PrintFormFeed:					; L61E
	mov		al, 0xc			; formfeed
PrintChar:					; L620
	push		ax
	mov		ah, 0xe			; Write TTY
	int		82			; Video interrupt
	pop		ax
	ret

; {? how to get here?}
	mov		al, bh
	call		.L62E
	mov		al, bl
.L62E:
	push		ax
	shr		al, 0x4
	call		.L636
	pop		ax
.L636:
	and		al, 0xf
	cmp		al, 0xa
	jc		.L63E
	add		al, 0x7
.L63E:
	add		al, 0x30
	push		bx
	mov		bl, 0xf
	call		PrintChar
	pop		bx
	ret

sCRLF:    					; L648
	db		0x0d, 0x0a, 0xff
sBeep:
	db		0x07, 0xff
s2Spaces:
	db		0x20, 0x20, 0xff
sMemorySize:					; L650
	db		'Memory Size = ', 0xff
s128k:
	db		'128', 0xff
	db		'256', 0xff
	db		'384', 0xff
	db		'512', 0xff
	db		'640', 0xff
	db		'768', 0xff
	; {FEAT} Support 896k, as offered by the Evince board
sKilobyteLabel:
	db		'K', 0xff
sSystemFailsDiag:				; L679
	db		'System Fails Diagnostic Test', 0xff

; ax = 0xe
;	bl  foreground color
Int82Video:					; L696
	push		ds
	push		es
	pusha
	mov		bp, sp
	cmp		ah, 0xe			; Write TTY?
	jne		.isWriteChar
	call		.writeTTY
	jmp	short	.done
.isWriteChar:
	cmp		ah, 0x10		; Write Character?
	jne		.done
	call		GetSetCharFont
.done:
	popa
	pop		es
	pop		ds
	iret

.writeTTY:
	mov		cx, 0x0
	mov		ds, cx
	mov		es, [0x474]		; get video buffer segment
	mov		cx, 0x1800
	mov		ds, cx
	mov		ah, bl			; bl = foreground color
	and		ah, 0xf
	cmp		ah, 0xa
	jne		.notFormFeed
	mov		[0x42], bl		; save color
	cmp		al, 0xc			; is form feed?
	jnz		.notFormFeed
	mov		[0x43], bl		; save fill color
.notFormFeed:					; L6D5
	mov		ah, [0x42]		; get color
	mov		bx, [0x40]		; get cursor position
	cmp		al, 0x20
	jnc		.writeSpace
	cmp		al, 0x7
	je		.writeBell
	cmp		al, 0x8
	je		.writeBackspace
	cmp		al, 0x9
	je		.writeTab
	cmp		al, 0xa
	je		.writeLineFeed
	cmp		al, 0xc
	je		.writeFormFeed
	cmp		al, 0xd
	je		.writeCarriageReturn
.L6F9:
	jmp	short	.ret
	nop
.writeSpace:
	call		CalcRowColOffsetDi
	stosw
	inc		bl
	jmp	short	.doneWriting
.writeBell:
	call		Bell
	jmp	short	.L6F9
.writeBackspace:
	cmp		bl, 0x0
	jz		.L6F9
	dec		bl
	jmp	short	.doneWriting
.writeTab:
	add		bl, 0x8
	and		bl, 0xf8
	jmp	short	.doneWriting
.writeLineFeed:
	inc		bh
	jmp	short	.doneWriting
.writeFormFeed:
	mov		bx, 0x0
	call		CalcRowColOffsetDi
	mov		cx, 0x7d0		; 25 rows * 80 cols
	mov		al, 0x20		; space
	mov		ah, [0x43]		; get fill color
rep	stosw
	jmp	short	.doneWriting
.writeCarriageReturn:
	mov		bl, 0x0
.doneWriting:
	call		CheckWrap
	mov		[0x40], bx		; save new cursor position
	mov		al, bh
	mov		dx, 0x130
	out		dx, al			; {TRM appendix C} 9007 R18
	mov		al, bl
	mov		dx, 0x132		; {TRM appendix C} 9007 R19
	out		dx, al
.ret:						; L746
	ret

CalcRowColOffsetDi:				; L747
	push		ax
	push		bx
	mov		di, 0x0
	mov		al, 0x50
	mul		bh			; ax = row *= 80
	mov		bh, 0x0
	add		ax, bx			; add column offset
	add		ax, ax			; double due to character attrs
	add		di, ax
	pop		bx
	pop		ax
	ret

CheckWrap:					; L75B
	cmp		bl, 0x50		; Hit the 80th column?
	jc		.checkRow
	mov		bl, 0x0			; Yes, back to 0 column,
	inc		bh			;	and down a line.
.checkRow:
	cmp		bh, 0x19		; Hit the 25th row?
	jc		.noScroll
	mov		bh, 0x18		; Yes, but stay where you are;
	call		ScrollScreenUp		;	and scroll.
.noScroll:
	ret

ScrollScreenUp:
	push		ds
	push		bx
	push		es
	pop		ds
	mov		bl, 0x0
	mov		bh, 0x1
	call		CalcRowColOffsetDi
	mov		si, di			; offset of 1, 0
	mov		bh, 0x0	
	call		CalcRowColOffsetDi
	mov		cx, 0x780		; 24*80*2
rep	movsw					; Copy from 1,0 to 0,0
	mov		cx, 0x50
	mov		al, 0x20
	mov		ah, [0x43]		; get fill color
rep	stosw					; fill last line
	pop		bx
	pop		ds
	ret

Bell:
	; {FEAT: umm... perhaps beep?}
	ret

; If setting, ES:BX points to character font
; If getting, ES:BX is set to current character font
; al bit 0: setting?
; al bits 1,2: which set
GetSetCharFont:					; L795
	mov		cx, 0x0
	mov		ds, cx
	mov		si, 0x476
	push		ax
	and		ax, 0x6
	add		ax, ax
	add		si, ax			; 0x476: 0-127 8x8, 0x47a: 128-255 8x8, 0x47c: 0-127 8x16, 0x480: 128-255 8x16
	pop		ax
	test		al, 0x1			; Change pointer to new character set?
	jnz		.writePointerToChar
	mov		bx, [si]
	mov		es, [si+0x2]		; es:bx now points to character font
	mov		[bp+0x8], bx
	mov		[bp+0x10], es
	jmp	short	.out
	nop
.writePointerToChar:				; L7B8
	mov		[si], bx
	mov		[si+0x2], es		; save caller's es:bs pointer to character font
	test		al, 0x4			; 8x16 cell?
	jnz		.is8x8Font
	jmp	short	.out
	nop
.is8x8Font:					; L7C4
	mov		ah, [0x420]		; {?} video feature flags? determines where to put font
	mov		si, bx
	mov		bx, es
	mov		ds, bx
	mov		bx, 0xf800		; ROM for fonts
	mov		es, bx
	mov		di, 0x0
	mov		cx, 0x800
	cmp		ah, 0x1
	ja		.L7E0
	jz		.L7EF
.L7E0:
	test		al, 0x2
	jz		.L7E8
	add		di, 0x1000
.L7E8:
	movsb
	inc		di
	loop		.L7E8
	jmp	short	.out
	nop
.L7EF:
	test		al, 0x2
	jz		.L7F7
	add		di, 0x2000
.L7F7:
	push		cx
	lodsb
	xor		dl, dl
	mov		cx, 0x8
.L7FE:
	shr		al, 1
	adc		dl, dl
	loop		.L7FE
	mov		ax, di
	and		ax, 0x3c
	shr		ax, 0x2
	xor		bx, bx
	mov		cx, 0x4
.L811:
	shr		ax, 1
	adc		bx, bx
	loop		.L811
	shl		bx, 0x2
	mov		ax, di
	and		ax, 0xffc3
	or		bx, ax
	mov		[es:bx], dl
	pop		cx
	add		di, byte +0x4
	loop		.L7F7
.out:
	ret

	; {?  Seems unused}
	iret

;; Patch table to fix up interrupt handling:
;; Words are alternating offset of IDT and offset of call in ROM
IntPatchTable:					; L82C:
	db 0x00, 0x00, 0xe2, 0x03		; 0: divide error L3E2
	db 0x04, 0x00, 0xe2, 0x03		; 1: single step L3E2
	db 0x08, 0x00, 0xdb, 0x03		; 2: NMI:  iret L3DB
	db 0x0c, 0x00, 0xe2, 0x03		; 3: breakpoint L3E2
	db 0x10, 0x00, 0xe2, 0x03		; 4: overflow L3E2
	db 0x14, 0x00, 0xE2, 0x03		; 5: print screen L3E2
	db 0x18, 0x00, 0xE2, 0x03		; 6: invalid op code L3E2
	db 0x1C, 0x00, 0xE2, 0x03		; 7: processor extention not available L3E2
	db 0x28, 0x00, 0x49, 0x0D		; 9: hard disk?  (or lpt2?  vertical retrace?) LD49
	db 0x2C, 0x00, 0x5E, 0x0D		; 10: COM2 LD5E
	db 0x20, 0x00, 0xE8, 0x03		; 8: system timer L3E8
	db 0x48, 0x00, 0xE8, 0x03		; 18: Memory size {PR 234} L3E8
	db 0x4C, 0x00, 0xE8, 0x03		; 19:
	db 0xC8, 0x01, 0xE8, 0x03		; 114:
	db 0xCC, 0x01, 0xE8, 0x03		; 115:
	db 0xD0, 0x01, 0x16, 0x0C		; 116:
	db 0xD4, 0x01, 0x16, 0x0C		; 117:
	db 0xD8, 0x01, 0x41, 0x04		; 118:
	db 0xDC, 0x01, 0xE8, 0x03		; 119:
	db 0xE0, 0x01, 0x52, 0x04		; 120:
	db 0xE4, 0x01, 0x63, 0x04		; 121:
	db 0xE8, 0x01, 0xE8, 0x03		; 122:
	db 0xEC, 0x01, 0xE8, 0x03		; 123:
	db 0x48, 0x01, 0x96, 0x06		; 82: video display Int82Video L696
	db 0x40, 0x00, 0x96, 0x06		; 16: video display Int82Video L696
	db 0x58, 0x01, 0x1B, 0x09		; 86: floppy disk {PR 194} Int86FDHD L91B
	db 0x4C, 0x00, 0x1B, 0x09		; 19: floppy and hard disk {PR 194} Int86FDHD L91B
	db 0xFF, 0xFF				; marker for end of patch table

SetUpFDROM:					; L89D
	pusha
	push		ds
	mov		ax, 0x1900		; write to disk area...
	mov		es, ax
	mov		ax, 0xfe00		; ...from ROM.
	mov		ds, ax
	mov		si, FDIntHandler
	nop
	mov		di, 0x0
	mov		cx, 0x48		; Copy int handler and param table.
	nop
	cld
rep	movsb					; Do the copy.
	mov		ax, 0x0
	mov		ds, ax
	mov	word	[0x78], 0x2c		; int 1e: Update floppy disk parameter pointer {PR 194}
	mov	word	[0x7a], 0x1900
	mov		al, 0x0
	out		0x2, al			; DMA control port: disable all {TRM appendix C}
	mov		[0x44a], al		;
	mov		[es:0x46], al
	pop		ds
	popa
	ret

FDIntHandler:					; L8D3
	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00
	db 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xa2, 0x00, 0x00, 0x04
	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x16
FDParamTable:					; {Ralf Brown, Int 1E, Table 0929}
	db 0xe0, 0x8c, 0x00, 0x02, 0x09, 0x2a, 0xff, 0x50, 0xf6, 0x19, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00
	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

; dl: FD or HD
; ah: command
Int86FDHD:					; L91B
	sti
	push		ds
	push		es
	push		bx
	push		cx
	push		ds
	push		si
	push		di
	push		bp
	push		dx
	mov		bp, sp
	mov		si, 0x1900
	mov		ds, si
	call		.doDiskOp
	mov		ah, [0x2]		; Get status of last disk op
	cmp		ah, 0x1
	cmc					; carry flag implies failure {PR 220}
	pop		dx
	pop		bp
	pop		di
	pop		si
	pop		ds
	pop		cx
	pop		bx
	pop		es
	pop		ds
	retf		0x2

.doDiskOp:
	mov		dh, al
	or		ah, ah
	jz		.resetDisks
	cmp		ah, 0x1
	jz		.getLastDiskOpStatus
	mov	byte	[0x2], 0x0		; Assume disk op will be successful
	cmp		dl, 0x2
	jnc		.readSectorsFromHD	; {?} what is dl?
	cmp		ah, 0x2
	jnz		.readSectorsFromHD
	jmp		otherDiskOps
.readSectorsFromHD:
	mov	byte	[0x2], 0x1		; status of last disk op: Bad command
	ret
.getLastDiskOpStatus:
	mov		al, [0x2]
	ret
.resetDisks:
	push		ds
	mov		ax, 0x0
	mov		ds, ax
	mov		al, [0x487]		;
	pop		ds
	and		al, 0xdf		; mask off Refresh Clock Gate
	out		0x0, al			; {TRM appendix C} everything on
	mov		cx, 0x14
.resetDisksDelay:
	loop		.resetDisksDelay
	or		al, 0x20
	out		0x0, al			; {TRM appendix C} FDC reset
	mov		al, 0x5
.L983:
	mov		cx, 0x0
.resetDisksDelay2:
	loop		.resetDisksDelay2
	dec		al
	jnz		.L983
	mov	byte	[0x2], 0x0		; last disk op: success
	mov		cx, 0x3c
.L994:
	call		LBD8
	mov	byte	[0x0], 0x0
	jnc		.L9A4
.L99E:
	or	byte	[0x2], 0x20		; last disk op: CRC error
	ret
.L9A4:
	mov		al, [0x37]
	cmp		al, 0x80
	jz		.L9C3
	test		al, 0x2
	jnz		.L994
	test		al, 0x1
	jnz		.L9BA
	xor	byte	[0x3], 0xff
	jmp	short	.L9BF
.L9BA:
	xor	byte	[0x5], 0xff
.L9BF:
	loop		.L994
	jmp	short	.L99E
.L9C3:
	mov		ah, 0x3
	call		LB08
	mov		bx, 0x1
	call		LB36
	mov		bx, 0x3
	call		LB36
	and	byte	[0x0], 0xfc
	mov		dl, 0x0
	mov		ch, 0xa
	call		LB4A
	jc		.LA20
	and	byte	[0x0], 0xfc
	mov		ch, 0x0
	call		LB4A
	jc		.LA20
	mov		ah, 0x4
	call		LB08
	mov		ah, 0x1
	call		LB08
	call		LC29
	jc		.LA20
	mov		ah, [0x37]
	and		ah, 0x20
	jz		.LA17
	mov		dl, 0x1
	mov		ch, 0xa
	call		LB4A
	and	byte	[0x0], 0xfc
	mov		ch, 0x0
	call		LB4A
.LA17:
	mov		dl, 0x0
	mov		ch, 0x2
	call		LB4A
	jnc		.LA26
.LA20:
	or	byte	[0x2], 0x40		; last disk op: FDC failure
	ret
.LA26:
	mov		ah, 0x4a
	call		LB08
	mov		ah, 0x0
	call		LB08
	call		LBF4
	jnc		.LA38
	jmp		.L99E
.LA38:
	call		LC29
	jnc		LA40
	jmp		.L99E
LA40:
	cmp	byte	[0x3a], 0x2
	jz		LA4D
	mov	byte	[0x4], 0xff
	ret
LA4D:
	mov	byte	[0x4], 0x0
	ret

otherDiskOps:
	call		LBAB
	jnc		LA60
	mov	byte	[0x2], 0x9		; {?} last disk op
	mov		al, 0x0
	ret

LA60:
	call		LB4A
	mov		dh, 0x0
	jc		LAB9
	push	word	0xab9
	nop
	mov		ah, 0x66
	call		LB08
	mov		ah, [bp+0x1]
	shl		ah, 0x2
	and		ah, 0x4
	or		ah, dl
	call		LB08
	mov		ah, ch
	call		LB08
	mov		ah, [bp+0x1]
	call		LB08
	mov		ah, cl
	call		LB08
	mov		bx, 0x7
	call		LB36
	mov		bx, 0x9
	call		LB36
	mov		bx, 0xb
	call		LB36
	mov		bx, 0xd
	call		LB36
	mov		bx, si
	pop		si
	call		LCDF
	jnc		LAB6
	or	byte	[0x2], 0x8		; last disk op: DMA overrun
	jmp	short	LAFE
	nop
LAB6:
	call		LBF4
LAB9:
	jc		LAFE
	call		LC29
	jc		LAFD
	cld
	mov		si, 0x37
	lodsb
	and		al, 0xc0
	jz		LB02
	cmp		al, 0x40
	jnz		LAF4
	lodsb
	shl		al, 1
	mov		ah, 0x4
	jc		LAF6
	shl		al, 0x2
	mov		ah, 0x10
	jc		LAF6
	shl		al, 1
	mov		ah, 0x8
	jc		LAF6
	shl		al, 0x2
	mov		ah, 0x4
	jc		LAF6
	shl		al, 1
	mov		ah, 0x3
	jc		LAF6
	shl		al, 1
	mov		ah, 0x2
	jc		LAF6
LAF4:
	mov		ah, 0x20
LAF6:
	or		[0x2], ah		; last disk op:
	call		LC67
LAFD:
	ret
LAFE:
	call		LC29
	ret
LB02:
	call		LC67
	xor		ah, ah
	ret

; {? FDC writing?}
; Writes ah to floppy
LB08:
	push		cx
	mov		cl, 0x20
.delay:
	dec		cl
	jnz		.delay			; {? why not loop? why delay at all?}
	mov		cx, 0x0
.notReadyToWrite:
	in		al, 0x30		; Read FDC status {TRM 85}
	and		al, 0x40		; I/O direction;  1 = FDC to CPU; 0 = CPU to FDC
	jz		.readyToWrite
	loop		.notReadyToWrite
.timeout:
	or	byte	[0x2], 0x80		; last disk op: timeout error
	stc
	pop		cx
	pop		ax
	ret
.readyToWrite:
	mov		cx, 0x0
.notReadyForData:
	in		al, 0x30		; Read FDC status {TRM 85}
	and		al, 0x80		; data ready?
	jnz		.readyForData
	loop		.notReadyForData
	jmp	short	.timeout
.readyForData:
	mov		al, ah
	out		0x32, al		; Write to FDC data register {TRM 85}
	pop		cx
	ret

LB36:
	push		ds
	mov		ax, 0x0
	mov		ds, ax
	push		si
	lds		si, [0x78]		; Floppy Disk Parameter Pointer {PR 194}
	shr		bx, 1
	mov		ah, [bx+si]		; {?} Load ? from a table?
	pop		si
	pop		ds
	jc		LB08
	ret

LB4A:
	mov		al, 0x1
	push		cx
	mov		cl, dl
	shl		al, cl
	pop		cx
	test		[0x0], al
	jnz		LB78
	or		[0x0], al
	mov		ah, 0x7
	call		LB08
	mov		ah, dl
	call		LB08
	call		LBD3
	mov		ah, 0x7
	call		LB08
	mov		ah, dl
	call		LB08
	call		LBD3
	jc		LBAA
LB78:
	mov		ah, 0xf
	call		LB08
	mov		ah, dl
	call		LB08
	mov		ah, ch
	or	byte	[0x4], 0x0
	jz		LB8D
	shl		ah, 1
LB8D:
	call		LB08
	call		LBD3
	pushf
	mov		bx, 0x12
	call		LB36
	push		cx
LB9B:
	mov		cx, 0x226
	or		ah, ah
	jz		LBA8
LBA2:
	loop		LBA2
	dec		ah
	jmp	short	LB9B
LBA8:
	pop		cx
	popf
LBAA:
	ret

LBAB:
	mov		si, 0x8
	mov		[si+0xc], es
	mov		[si+0xa], bx
	mov		ah, dh
	xor		al, al
	shr		ax, 1
	push		ax
	mov		bx, 0x6
	call		LB36
	mov		bl, ah
	pop		ax
.LBC4:
	shl		ax, 1
	dec		bl
	jnz		.LBC4
	mov		bx, si
	mov		[bx+0xe], ax
	call		LC7E
	ret

LBD3:
	call		LBF4
	jc		LBEC
LBD8:
	mov		ah, 0x8
	call		LB08
	call		LC29
	jc		LBEC
	mov		al, [0x37]
	and		al, 0x60
	cmp		al, 0x60
	jz		LBED
	clc
LBEC:
	ret
LBED:
	or	byte	[0x2], 0x40		; last disk op: seek error
	stc
	ret
LBF4:
	sti
	pusha
	mov		bl, 0xf
	xor		cx, cx
LBFA:
	test	byte	[0x0], 0x80
	jnz		LC0D
	loop		LBFA
	dec		bl
	jnz		LBFA
	or	byte	[0x2], 0x80		; last disk op: timeout error
	stc
LC0D:
	pushf
	and	byte	[0x0], 0x7f
	popf
	popa
	ret
	sti

Int116_117:					; LC16
	push		ds
	pusha
	mov		ax, 0x1900
	mov		ds, ax
	or	byte	[0x0], 0x80
	call		L487
	popa
	pop		ds
	iret

; {? FDC reading?}
LC29:
	mov		di, 0x37
	cld
	pusha
	mov		bl, 0x7			; 
LC30:
	xor		cx, cx			; Retry loop 64k times!
	mov		dx, 0x30
.loop:
	in		al, dx			; Read FDC status {TRM 85}
	test		al, 0x80		; data ready ready for IO?
	jnz		DataReady		; ready?
	loop		.loop
	or	byte	[0x2], 0x80		; last disk op: timeout error
LC41:
	stc
	popa
	ret
DataReady:					; LC44
	in		al, dx
	test		al, 0x40		; I/O direction;  1 = FDC to CPU; 0 = CPU to FDC
	jnz		DataReadyFdcToCpu
LC49:
	or	byte	[0x2], 0x20		; last disk op: FDC failure
	jmp	short	LC41
DataReadyFdcToCpu:
	in		al, 0x32		; Read FDC data register {TRM appendix C}
	mov		[di], al
	inc		di
	mov		cx, 0xf			; FDC must be serviced every 26 usec {TRM 86}
.LC58:
	loop		.LC58
	in		al, dx			; Read FDC status {TRM appendix C, 85}
	test		al, 0x10		; FDC read or write command in progress?
	jnz		.LC61
	popa
	ret
.LC61:
	dec		bl
	jnz		LC30
	jmp	short	LC49
LC67:
	mov		al, [0x3a]
	cmp		al, ch
	mov		al, [0x3c]
	jz		LC7B
	mov		bx, 0x8
	call		LB36
	mov		al, ah
	inc		al
LC7B:
	sub		al, cl
	ret

LC7E:
	push		es
	pusha
	call		LD30
	call		LD73
	jnz		LCFE
	mov		cx, [bx+0x8]
	mov		ax, [bx+0x6]
	call		LD19
	jnz		LCFE
	out		dx, ax
	mov		ax, cx
	inc		dx
	inc		dx
	out		dx, ax
	mov		cx, [bx+0xc]
	mov		ax, [bx+0xa]
	call		LD19
	jnz		LCFE
	inc		dx
	inc		dx
	out		dx, ax
	mov		ax, cx
	inc		dx
	inc		dx
	out		dx, ax
	mov		ax, [bx+0xe]
	inc		dx
	inc		dx
	out		dx, ax
	mov		ax, 0x1900
	mov		es, ax
	test	byte	[bx], 0xff
	jz		.setupHdPorts
	mov		[es:0x42], bx
	mov		[es:0x44], ds
	jmp	short	LCD5
.setupHdPorts:
	mov		[es:0x3e], bx
	mov		[es:0x40], ds
	call		LD3C
LCD5:
	mov		ax, [bx+0x10]
	inc		dx
	inc		dx
	out		dx, ax
	or		al, al
	jmp	short	LD16
LCDF:
	push		es
	pusha
	call		LD3C
	call		LD30
	add		dx, byte +0x8
	mov		al, 0xa
LCEC:
	mov		cx, 0xffff
LCEF:
	push		ax
	in		ax, dx
	or		ax, ax
	pop		ax
	jz		LD0D
	mov		ah, [bx]
	loop		LCEF
	dec		al
	jnz		LCEC
LCFE:
	stc
	pushf
	call		LD30
	add		dx, byte +0xa
	in		ax, dx
	and		al, 0xfd
	or		al, 0x4
	out		dx, ax
	popf
LD0D:
	pushf
	mov		dx, [bx+0x2]
	in		al, dx
	call		LDDF
	popf
LD16:
	popa
	pop		es
	ret

LD19:
	push		dx
	mov		dx, cx
	mov		cx, ax
	mov		ax, 0x10
	mul		dx
	add		ax, cx
	mov		cx, dx
	pop		dx
	jnc		.LD2B
	inc		cx
.LD2B:
	test		cx, 0xfff0
	ret

LD30:
	test	byte	[bx], 0xff
	mov		dx, 0xffc0
	jz		.LD3B
	mov		dx, 0xffd0
.LD3B:
	ret

LD3C:
	push		dx
	push		ax
	mov		dx, 0xff30
	in		ax, dx
	and		ah, 0x7f
	out		dx, ax
	pop		ax
	pop		dx
	ret

LD49:						; {?}  hard disk interrupt handler?
	pusha
	push		ds
	mov		ax, 0x1900
	mov		ds, ax
	lds		si, [0x3e]
	mov		dx, [si+0x2]
	in		al, dx
	call		L49F
	pop		ds
	popa
	iret

Int10:						; LD5E
	pusha
	push		ds
	mov		ax, 0x1900
	mov		ds, ax
	lds		si, [0x42]
	mov		dx, [si+0x2]
	in		al, dx
	call		L49F
	pop		ds
	popa
	iret

LD73:
	push		es
	pusha
	mov		ax, 0x1900
	mov		es, ax
	mov		cx, 0xffff
LD7D:
	push		cx
	mov		cx, 0x4
	clc
	xor		ah, ah
	mov		al, [es:0x46]
LD88:
	rcr		al, 1
	jnc		LD8E
	inc		ah
LD8E:
	loop		LD88
	cmp		ah, 0x2
	jl		LD9D
	pop		cx
	loop		LD7D
	dec		cl
	jmp	short	LDDC
	nop
LD9D:
	pop		cx
	mov		cx, 0xffff
LDA1:
	mov		al, [bx+0x1]
	and		al, 0xf
	test		[es:0x46], al
	jz		LDB4
	loop		LDA1
	dec		cl
	jmp	short	LDDC
	nop
LDB4:
	mov		ah, al
	rol		ah, 0x4
	test	byte	[bx], 0xff
	jnz		LDC8
	not		ah
	and		[es:0x46], ah
	jmp	short	LDCA
	nop
LDC8:
	or		al, ah
LDCA:
	or		[es:0x46], al
	mov		al, [es:0x46]
	out		0x2, al			; {TRM appendix C} DMA
	xor		al, al
	or		al, [es:0x47]
LDDC:
	popa
	pop		es
	ret

LDDF:
	push		es
	push		ax
	pushf
	mov		ax, 0x1900
	mov		es, ax
	test	byte	[bx+0x10], 0xc0
	jz		.LDFF
	mov		al, [bx+0x1]
	and		al, 0xf
	not		al
	and		al, [es:0x46]
	mov		[es:0x46], al
	out		0x2, al			; {TRM appendix C} DMA
.LDFF:
	popf
	pop		ax
	pop		es
	ret

	push		ds
	pusha
	mov		ax, 0x1900
	mov		ds, ax
	mov	byte	[0x47], 0xff
	call		L48E
	popa
	pop		ds
	iret

SetUpHDROM:
	push		ds
	push		bx
	push		cx
	push		dx
	mov		ax, 0x0
	mov		ds, ax
	cli
	mov	word	[0x1d8], IRet		; {?} int 118
	mov		[0x1da], cs
	mov	word	[0x40e], 0x1a00		; {?}
	mov	word	[0x4c], IntFD		; int 19: floppy and hard disk
	mov		[0x4e], cs
	mov	word	[0x158], IntFD		; int 86: floppy and hard disk
	mov		[0x15a], cs
	mov	word	[0x104], 0x26		; Hard disk parameter pointer {PR 194}
	mov		[0x106], cs		; {BUG but CS seems wrong; should be 0x1a00}

	mov		ax, 0x1a00		; Copying 0x48 bytes ROM -> RAM
	mov		ds, ax
	mov		cx, 0x48
	nop
	mov		si, HDROMImage
	nop
	mov		di, 0x0
.copyBytes:
	mov		al, [cs:si]
	mov		[di], al
	inc		si
	inc		di
	loop		.copyBytes
	sti
	mov		dx, [0x16]		; Get IO port for Cylinder LSB {TRM 189}
	mov		ax, 0x55aa
	out		dx, al
	mov		cx, 0xa			; 10 cycles * 125ns = 1.25us
.delay1:
	loop		.delay1
	in		al, dx			; {?} Verify the IO port retained the cylinder?
	cmp		al, 0xaa
	jnz		.badResponse
	mov		al, ah
	out		dx, al			;
	mov		cx, 0xa			; 10 cycles * 125ns = 1.25us
.delay2:
	loop		.delay2
	in		al, dx
	cmp		al, 0x55		; {?} Verify the IO port retained the cylinder?
	jz		.goodResponse
.badResponse:
	jmp	short	badResponseOut
	nop
.goodResponse:
	mov		cx, 0x17
LE8C:
	push		cx
	mov		cx, 0x0
LE90:
	push		cx
	mov		dx, [0xa]		; Get IO port for Software Reset of WD1010 {TRM 188}
	in		al, dx			; Do software reset of WD1010
	mov		cx, 0xa
.delay:
	loop		.delay
	mov		dx, [0x1a]		; Get IO port for SDH register of WD1010 {TRM 189}
	mov		al, 0x20		; Set HD0, 512 byte sectors
	out		dx, al
	mov		dx, [0x1c]		; {?} IO port 27E of WD1010 seems undefined
	in		al, dx
	and		al, 0xf0
	cmp		al, 0x50
	pop		cx
	jz		LEB6
	loop		LE90
	pop		cx
	loop		LE8C
	jmp	short	badResponseOut
	nop
LEB6:
	pop		cx
	mov		dx, 0x80		; HD not FD
	call		SetUpHDROMHelper
	jc		setUpHDROMOut		; error?
	mov		dx, 0x80
	call		SetUpHDROMHelper1
	jc		setUpHDROMOut		; error?
	call		SetUpHDROMHelper2
	jc		setUpHDROMOut		; error?
	call		SetUpHDROMHelper1
	jc		setUpHDROMOut		; error?
	mov	byte	[0x3], 0x1		; {?} set some success flag?
	jmp	short	setUpHDROMOut

	nop
SetUpHDROMHelper1:
	mov		ax, 0x1101		; {?}
	mov		cx, 0x1
	int		86			; Int86FDHD
	ret

SetUpHDROMHelper2:
	mov		cx, 0x501
	mov		ax, 0xc01		; {?}
	int		86			; Int86FDHD
	ret

badResponseOut:
	mov		ah, 0x7			; {?}
	stc					; Set carry to denote error
	jmp	short	setUpHDROMOut
; {?} perhaps success route?  from where?
	nop
	sub		ah, ah
setUpHDROMOut:
	pop		dx
	pop		cx
	pop		bx
	pop		ds
	ret

SetUpHDROMHelper:
	mov		ax, 0x0			; reset {?}
	mov		cx, 0x1			; {?}
	int		86			; Int86FDHD
	ret

; {?}	8	tmp
; indirects for HD IO ports
HDROMImage:					; LF01
	db       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x02, 0x70, 0x02, 0x72
LF10:
	db 0x02, 0x72, 0x02, 0x74, 0x02, 0x76, 0x02, 0x78, 0x02, 0x7A, 0x02, 0x7C, 0x02, 0x7E, 0x02, 0x7E
LF20:
	db 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x32, 0x01, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
LF30:
	db 0x02, 0x02, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x32, 0x01, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00
LF40:
	db 0x00, 0x02, 0x02, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x00


LF49:
	db 0x15, 0x00, 0xB2, 0x0F,		; {?} LFB2
	db 0xFF, 0x0F, 0x75, 0x10,
LF51:
	db 0x1B, 0x10, 0x75, 0x10, 0x75, 0x10, 0x75, 0x10, 0x75, 0x10, 0x75, 0x10, 0x75, 0x10, 0x75
LF60:
	db 0x10, 0x75, 0x10, 0x75, 0x10, 0x4B, 0x10, 0x75, 0x10, 0x75, 0x10, 0x75, 0x10, 0x75, 0x10, 0x60
LF70:
	db 0x10, 0x75, 0x10, 0x75, 0x10, 0x75, 0x10

IntFD:
        cmp		dl, 0x80
        jz		.wantFloppy		; Not requesting hard disk?
        mov		ah, 0x1			; Wanted HD, but not supported!
        stc
        ret		0x2
.wantFloppy:
	push		di
	mov		di, 0xf49
	sti
	push		ds			; .LF87
	push		es
	pusha
	cmp		ah, [cs:di]
	jnc		LFA8
	mov		bp, sp
	cld
	push		ax
	call		near	[cs:di+0x2]
	pop		ax
	push		ax
	mov		al, ah
	xor		ah, ah
	add		ax, ax
	add		di, ax
	pop		ax
	call		near	[cs:di+0x4]
	jmp	short	LFAD
LFA8:
	mov		al, 0x1
	mov		[bp+0xf], al
LFAD:
	popa
	pop		es
	pop		ds
	pop		di
	iret

LFB2:		; {?} possibly called via offset from chunk at LF01.  disk related.
	push		ax
	mov		ax, 0x1a00		; Switch DS to 0x1a00
	mov		ds, ax
	pop		ax
	mov		[0x8], bx		; {?} who calls, and what is bx?
	mov		[0x20], al		; {?} who calls, and what is al?
	mov		al, cl
	and		al, 0xc0
	shr		al, 0x6			; {?} get bit 0xc0
	mov		[0x23], al
	and		cl, 0x3f
	mov		[0x21], cl
	mov		[0x22], ch
	mov		al, [0x24]
	and		al, 0x60
	and		dl, 0x1
	mov		[0x2], dl
	mov		cl, 0x3
	shl		dl, cl
	or		dl, dh
	or		al, dl
	mov		[0x24], al
	mov	byte	[0x25], 0x0
	mov		al, [0x2]
	call		L10f5
	mov		[0x0], si		; [0x1a000] is sum of ?
	call		L10DC
	ret

	mov		dx, [0xa]
	in		al, dx
	mov		cx, 0xa
.L1007:
	loop		.L1007
	mov		dx, [0x1c]
	in		al, dx
	and		al, 0xf0
	cmp		al, 0x50
	jz		L1018
	mov		ah, 0x5
	stc
	ret
L1018:
	sub		ah, ah
	ret

	mov	byte	[0x25], 0x20
	mov		ch, 0x0
	mov		cl, [0x20]
L1026:
	call		L1119
	mov		si, [0x0]
	mov		bl, [si+0x9]
	call		L1133
	jc		L1040
	call		L10A1
	jc		L1048
	inc	byte	[0x21]
	loop		L1026
L1040:
	mov		al, [0x20]
	sub		al, cl
	mov		[bp+0xe], al
L1048:
	jmp	short	.L107F
	nop
	mov	byte	[0x25], 0x70
	call		L1119
	mov		si, [0x0]
	mov		bl, [si+0x9]
	call		L1133
	jmp	short	.L107F
	nop
	mov	byte	[0x25], 0x10
	call		L1119
	mov		si, [0x0]
	mov		bl, [si+0xb]
	call		L1133
	jmp	short	.L107F
	nop
	mov		ah, 0x1
	jmp	short	.L107F
	nop
	mov		ah, 0x0
	jmp	short	.L107F
	nop
.L107F:
	mov		[0x5], ah
	mov		[bp+0xf], ah
	or		ah, ah
	jz		L1097
	call		L110A
	stc
	lahf
	mov		[bp+0x1a], ah
	mov		ah, [0x5]
	ret
L1097:
	clc
	lahf
	mov		[bp+0x1a], ah
	mov		ah, [0x5]
	ret
L10A1:
	push		cx
	push		dx
	mov		cx, 0x0
	mov		dx, [0x1c]
L10AA:
	in		al, dx
	test		al, 0x8
	jnz		L10B7
	loop		L10AA
	mov		ah, 0x80
	stc
	jmp	short	L10D9
	nop
L10B7:
	mov		cx, 0x200
	mov		dx, [0xc]
	mov		bx, [0x8]
	cld
L10C3:
	in		al, dx
	mov		[es:bx], al
	inc		bx
	jnz		L10D1
	mov		ax, es
	add		ax, 0x1000
	mov		es, ax
L10D1:
	loop		L10C3
	mov		[0x8], bx
	sub		ah, ah
L10D9:
	pop		dx
	pop		cx
	ret

	; ds is 0x1a00
L10DC:						; {? perhaps HD reset}
	push		ax
	push		dx
	mov		al, [0x24]
	mov		dx, [0x1a]		; 27C; set SDH register of WD1010; {TRM 189}
	out		dx, al
	mov		si, [0x0]
	mov		ax, [si+0x5]
	mov		dx, [0x10]		; 272; write precomp {TRM 188}
	out		dx, al
	pop		dx
	pop		ax
	ret

	; DS is 0x1a000
L10f5:
	mov		cl, [0x2]
	mov		al, cl
	mov		ch, 0x0
	mov		si, 0x26
	or		cl, cl
	jz		.done
.L1104:
	add		si, byte +0x11
	loop		.L1104
.done:
	ret

L110A:
	push		ax
	push		dx
	mov		dx, [0xa]
	in		al, dx
	mov		cx, 0xa
.L1114:
	loop		.L1114
	pop		dx
	pop		ax
	ret
L1119:
	push		ax
	push		cx
	push		dx
	push		si
	mov		cx, 0x6
	mov		si, 0x20
	mov		dx, [0x12]
	cld
.L1128:
	lodsb
	out		dx, al
	inc		dx
	inc		dx
	loop		.L1128
	pop		si
	pop		dx
	pop		cx
	pop		ax
	ret

L1133:
	push		cx
	push		dx
	mov		dx, [0x1c]
	sub		cx, cx
.L113B:
	in		al, dx
	mov		ah, al
	in		al, dx
	cmp		ah, al
	jnz		.L113B
	and		al, 0xf0
	cmp		al, 0x50
	jz		.L1154
	loop		.L113B
	dec		bl
	jnz		.L113B
	mov		ah, 0x80
	jmp	short	.L1164
	nop
.L1154:
	mov		al, ah
	test		al, 0x1
	jz		.L1167
	mov		dx, [0xe]
	in		al, dx
	and		al, 0xd6
	call		L116C
.L1164:
	stc
	jmp	short	.L1169
.L1167:
	sub		ah, ah
.L1169:
	pop		dx
	pop		cx
	ret

L116C:
	test		al, 0x1
	jz		.L1173
	mov		ah, 0x2
	ret
.L1173:
	test		al, 0x2
	jz		.L117A
	mov		ah, 0x40
	ret
.L117A:
	test		al, 0x4
	jz		.L1181
	mov		ah, 0x1
	ret
.L1181:
	test		al, 0x10
	jz		.L1188
	mov		ah, 0x4
	ret
.L1188:
	test		al, 0x40
	jz		.L118F
	mov		ah, 0x10
	ret
.L118F:
	test		al, 0x80
	jz		.L1196
	mov		ah, 0xb
	ret
.L1196:
	mov		ah, 0xbb
	ret

IRet:
	iret

;; padding
L119a:	db                                                             0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L11a0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L11b0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L11c0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L11d0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L11e0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L11f0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1200:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1210:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1220:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1230:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1240:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1250:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1260:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1270:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1280:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1290:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L12a0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L12b0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L12c0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L12d0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L12e0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L12f0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

; Character set
CharSet8x8:
L1300:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0xa5, 0x81, 0xa5, 0x99, 0x42, 0x3c
L1310:	db 0xc3, 0xbd, 0x5a, 0x7e, 0x5a, 0x66, 0xbd, 0xc3, 0x22, 0x77, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00
L1320:	db 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x1c, 0x08, 0x49, 0x7f, 0x49, 0x08, 0x3e, 0x00
L1330:	db 0x08, 0x1c, 0x3e, 0x7f, 0x2a, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00
L1340:	db 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00
L1350:	db 0xff, 0xc3, 0xbd, 0xbd, 0xbd, 0xc3, 0xff, 0xff, 0x0f, 0x03, 0x05, 0x38, 0x44, 0x44, 0x38, 0x00
L1360:	db 0x1c, 0x22, 0x22, 0x1c, 0x08, 0x3e, 0x08, 0x00, 0x1f, 0x11, 0x11, 0x1f, 0x10, 0x30, 0x70, 0x00
L1370:	db 0x3f, 0x21, 0x21, 0x3f, 0x21, 0x22, 0x40, 0x00, 0x49, 0x2a, 0x36, 0x63, 0x36, 0x2a, 0x49, 0x00
L1380:	db 0x40, 0x70, 0x7c, 0x7f, 0x7c, 0x70, 0x40, 0x00, 0x01, 0x07, 0x1f, 0x7f, 0x1f, 0x07, 0x01, 0x00
L1390:	db 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x2a, 0x1c, 0x08, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x24, 0x00
L13a0:	db 0x3f, 0x49, 0x49, 0x49, 0x39, 0x09, 0x09, 0x00, 0x18, 0x20, 0x1c, 0x22, 0x1c, 0x02, 0x0c, 0x00
L13b0:	db 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, 0x08, 0x1c, 0x2a, 0x08, 0x2a, 0x1c, 0x08, 0xff
L13c0:	db 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08
L13d0:	db 0x00, 0x04, 0x02, 0xff, 0x02, 0x04, 0x00, 0x00, 0x00, 0x20, 0x40, 0xff, 0x40, 0x20, 0x00, 0x00
L13e0:	db 0x00, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00
L13f0:	db 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00
L1400:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00
L1410:	db 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00
L1420:	db 0x08, 0x1e, 0x28, 0x1c, 0x0a, 0x3c, 0x08, 0x00, 0x00, 0x62, 0x64, 0x08, 0x10, 0x26, 0x46, 0x00
L1430:	db 0x30, 0x48, 0x48, 0x30, 0x4a, 0x44, 0x3a, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00
L1440:	db 0x04, 0x08, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00
L1450:	db 0x00, 0x22, 0x14, 0x3e, 0x14, 0x22, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00
L1460:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00
L1470:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00
L1480:	db 0x3e, 0x43, 0x45, 0x49, 0x51, 0x61, 0x3e, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x3e, 0x00
L1490:	db 0x3e, 0x41, 0x06, 0x18, 0x20, 0x40, 0x7f, 0x00, 0x3e, 0x41, 0x01, 0x1e, 0x01, 0x41, 0x3e, 0x00
L14a0:	db 0x06, 0x0a, 0x12, 0x22, 0x7f, 0x02, 0x02, 0x00, 0x7e, 0x40, 0x7c, 0x02, 0x01, 0x42, 0x3c, 0x00
L14b0:	db 0x18, 0x20, 0x40, 0x7e, 0x41, 0x41, 0x3e, 0x00, 0x7f, 0x41, 0x02, 0x04, 0x08, 0x08, 0x08, 0x00
L14c0:	db 0x3e, 0x41, 0x41, 0x3e, 0x41, 0x41, 0x3e, 0x00, 0x3e, 0x41, 0x41, 0x3f, 0x01, 0x02, 0x0c, 0x00
L14d0:	db 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10
L14e0:	db 0x00, 0x04, 0x08, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00
L14f0:	db 0x00, 0x10, 0x08, 0x04, 0x08, 0x10, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x0c, 0x10, 0x00, 0x10, 0x00
L1500:	db 0x1e, 0x21, 0x4d, 0x55, 0x4e, 0x20, 0x1e, 0x00, 0x08, 0x14, 0x22, 0x41, 0x7f, 0x41, 0x41, 0x00
L1510:	db 0x7e, 0x21, 0x21, 0x3e, 0x21, 0x21, 0x7e, 0x00, 0x1e, 0x21, 0x40, 0x40, 0x40, 0x21, 0x1e, 0x00
L1520:	db 0x7c, 0x22, 0x21, 0x21, 0x21, 0x22, 0x7c, 0x00, 0x7f, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x7f, 0x00
L1530:	db 0x7f, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x00, 0x1e, 0x21, 0x40, 0x4f, 0x41, 0x21, 0x1e, 0x00
L1540:	db 0x41, 0x41, 0x41, 0x7f, 0x41, 0x41, 0x41, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00
L1550:	db 0x0e, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, 0x00, 0x41, 0x42, 0x44, 0x78, 0x44, 0x42, 0x41, 0x00
L1560:	db 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7f, 0x00, 0x41, 0x63, 0x55, 0x49, 0x41, 0x41, 0x41, 0x00
L1570:	db 0x41, 0x61, 0x51, 0x49, 0x45, 0x43, 0x41, 0x00, 0x3e, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3e, 0x00
L1580:	db 0x7e, 0x41, 0x41, 0x7e, 0x40, 0x40, 0x40, 0x00, 0x3e, 0x41, 0x41, 0x41, 0x45, 0x42, 0x3d, 0x00
L1590:	db 0x7e, 0x41, 0x41, 0x7e, 0x44, 0x42, 0x41, 0x00, 0x3e, 0x41, 0x40, 0x3e, 0x01, 0x41, 0x3e, 0x00
L15a0:	db 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3e, 0x00
L15b0:	db 0x41, 0x41, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x41, 0x41, 0x49, 0x49, 0x55, 0x63, 0x22, 0x00
L15c0:	db 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00
L15d0:	db 0x7f, 0x02, 0x04, 0x08, 0x10, 0x20, 0x7f, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00
L15e0:	db 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00
L15f0:	db 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff
L1600:	db 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x3d, 0x00
L1610:	db 0x40, 0x40, 0x5c, 0x62, 0x42, 0x62, 0x5c, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x42, 0x3c, 0x00
L1620:	db 0x02, 0x02, 0x3a, 0x46, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x3c, 0x00
L1630:	db 0x04, 0x0a, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x46, 0x3a, 0x02, 0x3c
L1640:	db 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1c, 0x00
L1650:	db 0x04, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x24, 0x18, 0x20, 0x20, 0x22, 0x24, 0x28, 0x34, 0x22, 0x00
L1660:	db 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x76, 0x49, 0x49, 0x49, 0x49, 0x00
L1670:	db 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00
L1680:	db 0x00, 0x00, 0x5c, 0x62, 0x62, 0x5c, 0x40, 0x40, 0x00, 0x00, 0x3a, 0x46, 0x46, 0x3a, 0x02, 0x02
L1690:	db 0x00, 0x00, 0x5c, 0x62, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x3c, 0x02, 0x7c, 0x00
L16a0:	db 0x10, 0x10, 0x7c, 0x10, 0x10, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00
L16b0:	db 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x41, 0x49, 0x55, 0x63, 0x22, 0x00
L16c0:	db 0x00, 0x00, 0x42, 0x24, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x3c
L16d0:	db 0x00, 0x00, 0x3e, 0x04, 0x08, 0x10, 0x3e, 0x00, 0x0c, 0x10, 0x10, 0x20, 0x10, 0x10, 0x0c, 0x00
L16e0:	db 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x08, 0x08, 0x04, 0x08, 0x08, 0x30, 0x00
L16f0:	db 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x7f, 0x00

; Character set
CharSet8x16:
L1700:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	; 0: null
L1710:	db 0x00, 0x3c, 0x42, 0x81, 0xa5, 0x81, 0xa5, 0x99, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	; 1: smiley
L1720:	db 0x00, 0xc3, 0xbd, 0x7e, 0x5a, 0x7e, 0x5a, 0x66, 0xbd, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	; 2: inverse smiley
L1730:	db 0x00, 0x00, 0x22, 0x77, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1740:	db 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1750:	db 0x00, 0x00, 0x1c, 0x08, 0x49, 0x7f, 0x49, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1760:	db 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x2a, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1770:	db 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1780:	db 0x00, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1790:	db 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L17a0:	db 0x00, 0xff, 0xff, 0xc3, 0xbd, 0xbd, 0xbd, 0xc3, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L17b0:	db 0x00, 0x0f, 0x03, 0x05, 0x39, 0x44, 0x82, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L17c0:	db 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x22, 0x1c, 0x08, 0x3e, 0x08, 0x00, 0x00, 0x00
L17d0:	db 0x00, 0x00, 0x1f, 0x11, 0x11, 0x1f, 0x10, 0x10, 0x10, 0x30, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00
L17e0:	db 0x00, 0x00, 0x3f, 0x21, 0x21, 0x3f, 0x21, 0x21, 0x21, 0x22, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00
L17f0:	db 0x00, 0x00, 0x49, 0x2a, 0x36, 0x63, 0x36, 0x2a, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1800:	db 0x00, 0x00, 0x40, 0x70, 0x7c, 0x7f, 0x7c, 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1810:	db 0x00, 0x00, 0x01, 0x07, 0x1f, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1820:	db 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08
L1830:	db 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1840:	db 0x00, 0x00, 0x3f, 0x49, 0x49, 0x49, 0x49, 0x39, 0x09, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1850:	db 0x00, 0x00, 0x1e, 0x21, 0x1c, 0x22, 0x22, 0x1c, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1860:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1870:	db 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08, 0xff
L1880:	db 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
L1890:	db 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08
L18a0:	db 0x00, 0x00, 0x00, 0x04, 0x02, 0xff, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L18b0:	db 0x00, 0x00, 0x00, 0x20, 0x40, 0xff, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L18c0:	db 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L18d0:	db 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L18e0:	db 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L18f0:	db 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1900:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1910:	db 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1920:	db 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1930:	db 0x00, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1940:	db 0x00, 0x08, 0x3f, 0x48, 0x48, 0x3e, 0x09, 0x09, 0x7e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1950:	db 0x00, 0x20, 0x51, 0x22, 0x04, 0x08, 0x10, 0x22, 0x45, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1960:	db 0x00, 0x10, 0x28, 0x28, 0x10, 0x28, 0x44, 0x45, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1970:	db 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1980:	db 0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1990:	db 0x00, 0x10, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L19a0:	db 0x00, 0x00, 0x00, 0x24, 0x18, 0x7e, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L19b0:	db 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L19c0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00
L19d0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L19e0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L19f0:	db 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a00:	db 0x00, 0x3e, 0x41, 0x43, 0x45, 0x49, 0x51, 0x61, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a10:	db 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a20:	db 0x00, 0x3e, 0x41, 0x01, 0x02, 0x0c, 0x30, 0x40, 0x40, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a30:	db 0x00, 0x3e, 0x41, 0x01, 0x01, 0x1e, 0x01, 0x01, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a40:	db 0x00, 0x02, 0x06, 0x0a, 0x12, 0x22, 0x7f, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a50:	db 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, 0x01, 0x01, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a60:	db 0x00, 0x0c, 0x10, 0x20, 0x40, 0x7c, 0x42, 0x41, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a70:	db 0x00, 0x7f, 0x41, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a80:	db 0x00, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1a90:	db 0x00, 0x3e, 0x41, 0x41, 0x41, 0x3f, 0x01, 0x02, 0x04, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1aa0:	db 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ab0:	db 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00
L1ac0:	db 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ad0:	db 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ae0:	db 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1af0:	db 0x00, 0x3c, 0x42, 0x02, 0x04, 0x08, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b00:	db 0x00, 0x1e, 0x21, 0x4d, 0x55, 0x51, 0x4e, 0x40, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b10:	db 0x00, 0x08, 0x14, 0x22, 0x41, 0x41, 0x7f, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b20:	db 0x00, 0x7e, 0x41, 0x41, 0x41, 0x7e, 0x41, 0x41, 0x41, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b30:	db 0x00, 0x3e, 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b40:	db 0x00, 0x7c, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b50:	db 0x00, 0x7f, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b60:	db 0x00, 0x7f, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b70:	db 0x00, 0x1e, 0x21, 0x40, 0x40, 0x4f, 0x41, 0x41, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b80:	db 0x00, 0x41, 0x41, 0x41, 0x41, 0x7f, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1b90:	db 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ba0:	db 0x00, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1bb0:	db 0x00, 0x41, 0x42, 0x44, 0x48, 0x50, 0x68, 0x44, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1bc0:	db 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1bd0:	db 0x00, 0x41, 0x63, 0x55, 0x49, 0x49, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1be0:	db 0x00, 0x41, 0x41, 0x61, 0x51, 0x49, 0x45, 0x43, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1bf0:	db 0x00, 0x3e, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c00:	db 0x00, 0x7e, 0x41, 0x41, 0x41, 0x7e, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c10:	db 0x00, 0x3e, 0x41, 0x41, 0x41, 0x41, 0x49, 0x45, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c20:	db 0x00, 0x7e, 0x41, 0x41, 0x41, 0x7e, 0x48, 0x44, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c30:	db 0x00, 0x3e, 0x41, 0x40, 0x40, 0x3e, 0x01, 0x01, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c40:	db 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c50:	db 0x00, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c60:	db 0x00, 0x41, 0x41, 0x41, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c70:	db 0x00, 0x41, 0x41, 0x41, 0x41, 0x49, 0x49, 0x55, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c80:	db 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1c90:	db 0x00, 0x41, 0x41, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ca0:	db 0x00, 0x7f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1cb0:	db 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1cc0:	db 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1cd0:	db 0x00, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ce0:	db 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1cf0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00
L1d00:	db 0x00, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d10:	db 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d20:	db 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x62, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d30:	db 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d40:	db 0x00, 0x02, 0x02, 0x02, 0x3a, 0x46, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d50:	db 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d60:	db 0x00, 0x0c, 0x12, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d70:	db 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x02, 0x1c, 0x00, 0x00
L1d80:	db 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1d90:	db 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1da0:	db 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x48, 0x30, 0x00, 0x00
L1db0:	db 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, 0x68, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1dc0:	db 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1dd0:	db 0x00, 0x00, 0x00, 0x00, 0x76, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1de0:	db 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1df0:	db 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e00:	db 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00
L1e10:	db 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00
L1e20:	db 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e30:	db 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x30, 0x0c, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e40:	db 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e50:	db 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e60:	db 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e70:	db 0x00, 0x00, 0x00, 0x00, 0x41, 0x49, 0x49, 0x55, 0x63, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e80:	db 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1e90:	db 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x02, 0x1c, 0x00, 0x00
L1ea0:	db 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1eb0:	db 0x00, 0x0c, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ec0:	db 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ed0:	db 0x00, 0x30, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ee0:	db 0x00, 0x30, 0x49, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1ef0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

;; Power on: CS=0xff0, IP=0
PowerOn:					; L1f00
	mov ax, 0xff
	mov dx, 0xfffe				; {? port 0xfffe}
	out dx, ax
	mov bx, ax				; bx = 0xff
	not ax					; ax = 0
	mov dx, 0xfffe
	in ax, dx
	xor ax, bx
	and ax, 0xdfff				; {? what is reading from port 0xfffe telling us?)
	jz .continue
.hang:
	jmp short .hang
.continue:					; L1f18
	mov ax, 0xc0be
	mov dx, 0xffa8
	out dx, ax				; {? port 0xffa8}
	mov ax, 0x1f8
	mov dx, 0xffa6
	out dx, ax
	mov ax, 0x3e
	mov dx, 0xffa4
	out dx, ax
	mov al, 0x0
	mov dx, 0x0
	out dx, al				; {TRM appendix C, turn off devices}
	mov al, 0xc0
	mov dx, 0x101
	out dx, al				; {TRM appendix C, video: 800x400, bus not 9007}
	mov dx, 0x56
	mov al, 0xaa
	out dx, al				; {? port 0x56}
	nop
	nop
	mov dx, 0x54
	mov al, 0x5
	out dx, al				; {TRM appendix C, 8255 direction, read keyboard}
	mov al, 0x3
	mov dx, 0x52
%ifdef DEBUG
	in	al, dx				; {?} Guessing something like this may have been in original
						; source.  Allows selection of different hardware setup.
%else
	nop					; Release builds always leave al=3
%endif
	mov bp, 0x1f6a
	nop
.checkProfile:
	cmp al, [cs:bp+0x0]
	je .foundProfile
	add bp, byte +0x10
	jmp short .checkProfile
.foundProfile:		;L1f5c:
	mov ax, [cs:bp+0x2]
	mov dx, 0xffa0
	out dx, ax
	jmp word 0xfe00:0x0			; Jump to StartOfBoot
	nop

; Hardware Profiles (or so I call them)
; cs:bp is set (in PowerOn) to point to one of these 4 16-byte blocks.  Describes hardware.
; Maybe for debug vs production, or hardware revisions?
; 0	index (influences font setup)
; 1	max allowed 64k banks of RAM
; 2	is written to IO port 0xffa0 {? why?}
; 3
; 4	Address Control Register {TRM appendix C} when 128k installed
; 5	Device power-on, reset, DMA 8237, etc
L1f6a:	db 0x00, 0x08, 0x3f, 0xe0, 0x44, 0x00, 0x48, 0x00, 0x50, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00
L1f7a:	db 0x01, 0x08, 0x3b, 0xe0, 0xc4, 0x00, 0xc8, 0x00, 0xd0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00
L1f8a:	db 0x02, 0x0c, 0x3f, 0xf8, 0xc3, 0x00, 0xc7, 0x00, 0xcb, 0x00, 0xcf, 0x00, 0xd3, 0x00, 0xd7, 0x00
L1f9a:	db 0x03, 0x0c, 0x3f, 0xf8, 0xc3, 0x10, 0xc7, 0x10, 0xcb, 0x10, 0xcf, 0x10, 0xd3, 0x10, 0xd7, 0x10

L1faa:	db                                                             0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1fb0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1fc0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1fd0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
L1fe0:	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x3a
L1ff0:	db 0xea, 0x00, 0x1f, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00