/*************************************************************************/
/** This is the virtual PC's Bios (F000:0 .. F000:FFFF)                 **/
/**                                                                     **/
/** We must compile this with as86/ld86 as follows:                     **/
/**   gcc -E  bios.S | tools/tools86 -E >bios.s                         **/
/**   as86 -0 -w -g -o bios.o bios.s                                    **/
/**   ld86 -0 -r -o bios bios.o                                         **/
/**   tools/tools86 bios                                                **/
/**   mv -f bios bios.o                                                 **/
/**                                                                     **/
/** We also need to use the macro JMPL (label) if we want have a 16-bit **/
/** displacement. As86 is not able to do so without the -j switch,      **/
/** and the -j switch also make all conditional jmp's 5 byte long.      **/
/** See file macros86.h for details.                                    **/
/**                                                                     **/
/** NOTE: be careful with overlapping ".org",                           **/
/**       or ld86 will then reach your disk quotas !                    **/
/**                                                                     **/
/** Memory Map:                                                         **/
/**   0xFC000-0xFCFFF  4K protected HLT block for transfer functions    **/
/**   0xFD000-0xFDFFF  4K unprotected data segment, put those           **/
/**                    BIOS/Dosemu transfer buffers in this region      **/
/**   0xFE000-0xFFFFF  8K protected code section.  contains everything  **/
/**                    else                                             **/
/*************************************************************************/

#define __ASM__
#include "config.h"
#include "base/bios_entry.h"
#include "macros86.h"
#include <linux/linkage.h>

/* some other useful definitions */

#define BIOS_DATA		0x40
#define KEYBUF_READ_PTR		0x1a
#define KEYBUF_WRITE_PTR	0x1c
#define KEYBUFFER_START		0x80
#define KEYBUFFER_END		0x82
#define KEYSHIFT_FLAGS		0x17
#define KEYBOARD_STATUS_3	0x96
#define INT2F_XMS_MAGIC		0x43

.text
	.globl	CISH(bios_f000)
CISH(bios_f000):

/*
 * This is where we print the banner and boot all the mapped BIOS code
 */

/******************************************************************
 * HLT real-protected mode transfer BLOCK                         *
 ******************************************************************/
.org	0xc000
	FILL_OPCODE(4096,hlt)

/******************************************************************
 * DATA BLOCK                                                     *
 ******************************************************************/

.org	ROM_Mouse_Handler
mouse_handler:
	dw	ROM_Mouse_ROUTINE_OFF, BIOSSEG
int10_handler:
	dd	0x00000000
lastscan:
	dw	0

/******************************************************************
 * BIOS CODE BLOCK                                                *
 ******************************************************************/

.org    0xe000
	.ascii	"..............IBM..............."
	.ascii	"DOSEMU Custom BIOS r0.00, Copyri"
	.ascii	"ght 1995..............."
offset_0040:
	dw 0x0040			/* easy way to put 0x0040 -> DS */
offset_0000:
	dw 0x0000			/* easy way to put 0x0000 -> DS */

/*
 * This is where we jump to when the power comes on.
 */
.org	ROM_BIOS_SELFTEST
;	Disable interrupts
	cli				/* Disable interrupts */

;	Test CPU registers (skipped)
;	Checksum ROM BIOS (skipped)
;	Initialize DMA (skipped)
;	Read/write test first 32K (skipped)
;	Initialize the PIC (skipped)
;	Set interrupt vectors

	xor	di,di
	mov	es,di			; ES:DI -> 0000:0000
	mov	ax,cs
	mov	ds,ax
	mov	si,#ROM_BIOS_INITINTS	; DS:SI -> interrupt table
	mov	bx,#ROM_BIOS_IRET
	mov	cx,#0x78
bootup_int1:
	mov	ax,bx
	stosw
	mov	ax,cs
	stosw
	loop	bootup_int1		; Store F000:FF53 for 0x00-0x78
	mov	cx,#0x82
	xor	ax,ax
bootup_int2:
	stosw
	stosw
	loop	bootup_int2		; Store 0000:0000 for 0x78-0xff
	mov	di,#0x0020
	mov	cx,#0x0018
bootup_int3:
	lodsw				; Get the offset & store it
	stosw
	or	ax,ax
	jz	bootup_int3_sto
	mov	ax,cs			; Store F000:xxxx
bootup_int3_sto:
	stosw				; Store 0000:0000 or F000:xxxx
	loop	bootup_int3		; Transfer the table vals for 0x08-0x1f
	mov	di,#0x01c0
	mov	cx,#0x0008
	mov	ax,cs
bootup_int4:
	movsw				; Transfer the offset
	stosw				; Store F000 (the segment)
	loop	bootup_int4		; Transfer the irq's 0x70-0x77
	mov	di,#0x0008
	ESEG
	mov	[di],#ROM_BIOS_NMI	; Set the NMI interrupt
	mov	di,#0x0014
	ESEG
	mov	[di],#ROM_BIOS_INT05	; Set the print screen interrupt

;	Determine the configuration (done for us)
;	Test the PIT (skipped)
;	Reset & test the keyboard controller (skipped)
;	Test for expansion box & additional RAM (skipped)
;	Read/write memory above 32K (unless 1234 in reset word) (skipped)
;	Scan C000:0000-F400:0000 in 2K blocks for more BIOS

	mov	si,#0xC000		; Start address
	mov	cx,#0xF400		; Ending address
bootup_rom:
	mov	ds,si
	push	cx
	push	ds
	mov	si,#0x0080
	cmp	word ptr [0],#0xAA55	; valid ROM?
	jne	bootup_rom2
	mov	ch,#0x80
	mov	ax,ds
	cmp	ax,#0xE000
	jne	bootup_rom1
	mov	ch,byte ptr [2]
bootup_rom1:
	xor	cl,cl
	mov	si,cx
	shr	si,3			; SI = # of paragraphs of ROM
	push	si
	shl	cx,1			; CX = # of bytes of ROM
	xor	ah,ah			; Compute checksum in AH
	xor	si,si
bootup_csum:
	lodsb
	add	ah,al
	loop	bootup_csum		; Loop over all bytes in ROM
	pop	si
	jne	bootup_csum_err
	xor	ax,ax
	mov	es,ax			; Gonna write the BIOS data
	ESEG
	mov	word ptr [0x0467],#3
	ESEG
	mov	word ptr [0x0469],ds
	xor	bp,bp
	out	0xED,al
	in	al,0x21
	push	si
	push	ax
	push	dx
	call	#0xFC00:#0x0F00		/* BIOS init enter */
	ESEG
	call	far [0x0467]
	call	#0xFC00:#0x0F01		/* BIOS init exit */
	pop	dx
	pop	ax
	out	0x21,al
	pop	si
	add	si,#0x007F
	and	si,#0xFF80
bootup_rom2:
bootup_csum_err:
	pop	cx
	add	si,cx
	pop	cx
	cmp	si,cx
	jb	bootup_rom
bootup_rom3:

;	Test for diskette drives
;	Test printer & RS-232 ports
;	NMI interrupts enabled
	sti

;	-- Splatter our banner all over the screen
	call	#0xFC00:#0x0F02

;	Perform INT19
	int	0x19

;	jump to 7C00:0000
	jmp	#0x0000:#0x7C00

/*
 * IRQ 8-14     TODO: reality check
 */
.org	ROM_BIOS_IRQ_HI
	push	ax
	mov	al,#0x20
	out	#0xa0,al
	out	#0x20,al
	pop	ax
	iret

/*
 * NMI -- what do we do here?
 */
.org	ROM_BIOS_NMI
	db	0xcd, 0x03		/* What happens now? */
	iret

/*
 * Internal mouse handler code  (32 bytes reserved)
 */

.org	ROM_Mouse_OFF
	call	far [mouse_handler]
	pop	es
	pop	ds
	popa
	iret

.org	ROM_Mouse_ROUTINE_OFF
	push	ax
	mov	al,#0x20
	out	#0x20,al
	pop	ax
	iret

/*
 * XMS handler  (15 bytes reserved)
 */
.org	ROM_XMSControl_OFF
	jmp	(*+2+3)		/* jmp short forward 3 */
	nop
	nop
	nop
	hlt			/* trap to the emulator */
	db	INT2F_XMS_MAGIC /* an info byte reserved for later */
	retf

/*
 * IPX code.  (32 bytes reserved)
 * TODO:  can we call fake_pusha in the code and replace the pop
 *        statements w/popa, please?  Then we could make this 16 bytes
 */

.org	ROM_IPX
	push	ax	/* FarCallHandler removes this before returning */
	call	#0xFC00:#0x0FF0		/* IPX Helper */
	retf

	.globl	CISH(bios_IPX_PopRegistersReturn)
CISH(bios_IPX_PopRegistersReturn):
	pop	es
	pop	ds
	pop	bp
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	retf
	.globl	CISH(bios_IPX_PopRegistersIRet)
CISH(bios_IPX_PopRegistersIRet):
	pop	es
	pop	ds
	pop	bp
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	iret

/*
 * Code having to do with FCB's & MFS (I think...)  (16 bytes reserved)
 */

.org	ROM_FCB_Handler
	push	es
	push	di
	push	ax
	mov	ax,#0x120c
	int	0x2f
	pop	ax
	pop	di
	pop	es
	retf


/*
 * Code installed after the video init when the internal mouse driver is
 * in use.  It watches for mouse set commands and resets the mouse driver
 * when it sees one.
 */

.org	ROM_INT10_Watcher
	or	ah,ah
	jz	Wtch_setmode	/* normal mode set */
	cmp	ax,#0x4F02
	je	Wtch_setmode	/* svga mode set */
	CSEG
	jmp	far [int10_handler]
Wtch_setmode:
	push	ax
	push	bx
	mov	bx,#0xf0
	call	#0xFC00:#0x0FF5	/* mouse helper -- start video mode set */
	pop	bx
	pop ax
	pushf			/* do int10 interrupt */
	CSEG
	call	far [int10_handler]
	push	ax
	push	bx		/* restore the context */
	mov	bx,#0xf1
	call	#0xFC00:#0x0FF5	/* mouse helper -- end video mode set */
	pop	bx
	pop	ax
	retf	#2

/*
 * Int 13 Hard drive services
 */
.org	ROM_BIOS_INT13HARD - 6
int13_srvs:
	int	0x13
	retf	#2

.org	ROM_BIOS_INT13HARD
	JMPL	(int13_srvs)

/*
 * This table is only half correct.  That is to say that
 * the first half of the values are okay and the second
 * half are just a copy of the first half (copyrights, you
 * know.)
 */

.org	ROM_BIOS_HARDPARM
	db	0x32, 0x01, 0x04, 0x00, 0x00, 0x80, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x31, 0x01, 0x11, 0x00
	db	0x67, 0x02, 0x04, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x67, 0x02, 0x11, 0x00
	db	0x67, 0x02, 0x06, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x67, 0x02, 0x11, 0x00
	db	0xac, 0x03, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xac, 0x03, 0x11, 0x00
	db	0xac, 0x03, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xac, 0x03, 0x11, 0x00
	db	0x67, 0x02, 0x04, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x67, 0x02, 0x11, 0x00
	db	0xce, 0x01, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x11, 0x00
	db	0xdd, 0x02, 0x05, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdd, 0x02, 0x11, 0x00
	db	0x84, 0x03, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x08, 0x00, 0x00, 0x00, 0x85, 0x03, 0x11, 0x00
	db	0x34, 0x03, 0x03, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x34, 0x03, 0x11, 0x00
	db	0x57, 0x03, 0x05, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x57, 0x03, 0x11, 0x00
	db	0x57, 0x03, 0x07, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x57, 0x03, 0x11, 0x00
	db	0x32, 0x01, 0x08, 0x00, 0x00, 0x80, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x11, 0x00
	db	0xdd, 0x02, 0x07, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdd, 0x02, 0x11, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x64, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x97, 0x02, 0x11, 0x00
	db	0xd1, 0x03, 0x05, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xd1, 0x03, 0x11, 0x00
	db	0xd1, 0x03, 0x07, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xd1, 0x03, 0x11, 0x00
	db	0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x11, 0x00
	db	0xdd, 0x02, 0x05, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x11, 0x00
	db	0xdd, 0x02, 0x07, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x11, 0x00
	db	0xdd, 0x02, 0x05, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdd, 0x02, 0x11, 0x00
	db	0x32, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x11, 0x00
	db	0x32, 0x01, 0x04, 0x00, 0x00, 0x80, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x31, 0x01, 0x11, 0x00
	db	0x67, 0x02, 0x04, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x67, 0x02, 0x11, 0x00
	db	0x67, 0x02, 0x06, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x67, 0x02, 0x11, 0x00
	db	0xac, 0x03, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xac, 0x03, 0x11, 0x00
	db	0xac, 0x03, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xac, 0x03, 0x11, 0x00
	db	0x67, 0x02, 0x04, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x67, 0x02, 0x11, 0x00
	db	0xce, 0x01, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x11, 0x00
	db	0xdd, 0x02, 0x05, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdd, 0x02, 0x11, 0x00
	db	0x84, 0x03, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x08, 0x00, 0x00, 0x00, 0x85, 0x03, 0x11, 0x00
	db	0x34, 0x03, 0x03, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x34, 0x03, 0x11, 0x00
	db	0x57, 0x03, 0x05, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x57, 0x03, 0x11, 0x00
	db	0x57, 0x03, 0x07, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x57, 0x03, 0x11, 0x00
	db	0x32, 0x01, 0x08, 0x00, 0x00, 0x80, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x11, 0x00
	db	0xdd, 0x02, 0x07, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdd, 0x02, 0x11, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x64, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x97, 0x02, 0x11, 0x00
	db	0xd1, 0x03, 0x05, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xd1, 0x03, 0x11, 0x00
	db	0xd1, 0x03, 0x07, 0x00, 0x00, 0xff, 0xff, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xd1, 0x03, 0x11, 0x00
	db	0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x11, 0x00
	db	0xdd, 0x02, 0x05, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x11, 0x00
	db	0xdd, 0x02, 0x07, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x11, 0x00
	db	0xdd, 0x02, 0x05, 0x00, 0x00, 0x2c, 0x01, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0xdd, 0x02, 0x11, 0x00
	db	0x32, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00
	db	0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x11, 0x00

.org	ROM_BIOS_INT19
	int	0x19
	iret

.org	ROM_BIOS_SYSPARM
	dw	8			/* table size (we'll skip version) */
	db	0xfc			/* model */
	db	0x01			/* submodel */
	db	00			/* bios revision level */
	db	0x74			/* feature byte info */
	db	0,0,0,0			/* reserved */
	.ascii	"DOSEMU 0.61.00 Linux i386"    /* tell who we are */
	db	0			/* EOS character */

.org	ROM_BIOS_BAUDRATE
	db	0x17, 0x04, 0x00, 0x03, 0x80, 0x01, 0xc0, 0x00
	db	0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00

.org	ROM_BIOS_INT14
	int	0x14
	retf	#2

.org	ROM_BIOS_INT16
	push    ds			/* save ds and bx */
	push    bx
        mov     bx,#0x0040		/* set DS to 0x0040 BIOS seg */
	mov	ds,bx

	cmp	ah,#2
	ja	INT16_3			/* >2 */
	je	INT16_2			/* 2 => retn. shift flag stat. */
	jp	INT16_1			/* 1 => return keyboard status */
	jmp	INT16_0			/* 0 => read keyboard */

INT16_0_idle:
	sti
	call	#0xFC00:#0x0F04		/* int16 idler function         */
	cli
INT16_0:				/* 0 => read keyboard */
	mov	bx,[KEYBUF_READ_PTR]    /* get address of next char	*/
	cmp	bx,[KEYBUF_WRITE_PTR]	/* is buffer empty?		*/
	je      INT16_0_idle		/* jump if not empty		*/
INT16_0_a:
	mov	ax,[bx]			/* get last key	*/
	inc     bx			/* advance buffer pointer 2 bytes*/
	inc     bx
	mov	[KEYBUF_READ_PTR],bx	/* save new pointer		*/
	cmp	bx,[KEYBUFFER_END]	/* check for wrap around        */
	jne	INT16_ex		/* no wrap - go return to caller*/
					/* wrap - get buffer start	*/
	mov	bx,[KEYBUFFER_START]
					/* save it as new pointer	*/
	mov     [KEYBUF_READ_PTR],bx
	jmp	INT16_ex		/* return to caller		*/

INT16_1:
	mov	bx,[KEYBUF_READ_PTR]	/* get address of next char	*/
	cmp	bx,[KEYBUF_WRITE_PTR]	/* set flag if buffer empty	*/
	je	INT16_1_		/* if no key, don't set ax	*/
	mov	ax,[bx]			/* put char into ax		*/
INT16_1_:
	sti
	pop     bx
	pop     ds			/* can't do iret -- it would    */
	retf    #2			/*   change the flags we set    */

INT16_2:				/* RETURN SHIFT FLAG STATUS     */
	mov	al,[KEYSHIFT_FLAGS]	/* get shift flags		*/
	pop     bx			/* return			*/
	pop     ds
	iret

INT16_12:				/* RETURN SHIFT FLAG STATUS     */
	mov	ax,[KEYSHIFT_FLAGS]	/* get shift flags (ah=extended)*/
	and     ah,#0xf3		/* disallow bits 2 & 3		*/
	mov	bh,[KEYBOARD_STATUS_3]	/* bits 2 & 3 come from here	*/
	and     bh,#0xc			/* isolate those bits		*/
	or      ah,bh			/* merge them with flags in ax	*/
	pop     bx			/* return			*/
	pop     ds
	iret   

INT16_3:
	cmp	ah,#5
	je	INT16_5			/*  5 => store key in buffer    */
	jb	INT16_ex		/*  3, 4 */
					/*  3 => set rpt. speed & delay */
					/*  4 => reserved (do nothing)  */
	cmp	ah,#0x10
	je	INT16_0			/* 0x10 => read extended keyboard */
	jb	INT16_ex
	cmp	ah,#0x12
	je	INT16_12		/* 0x12 => retn ext shift flg stat */
	jb	INT16_1			/* 0x11 => retn. ext. keybd. stat.*/
INT16_ex:
	pop     bx			/* do nothing and return	*/
	pop     ds
	iret   

INT16_5:				/* Store key into buffer        */
	mov	bx,[KEYBUF_WRITE_PTR]	/* get buffer "in" pointer	*/
	inc     bx			/* increment "in" pointer	*/
	inc     bx
	cmp	bx,[KEYBUFFER_END]	/* wrap if needed		*/
	jne     INT16_5_a
	mov	bx,[KEYBUFFER_START]
INT16_5_a:
	cmp	bx,[KEYBUF_READ_PTR]	/* is buffer full?              */
	jne     INT16_5_b
	mov     al,#1			/* buffer is full, return error	*/
	pop     bx			/* return			*/
	pop     ds
	iret   
INT16_5_b:
	push    bx			/* buffer is not full - save bx	*/
	mov     bx,[KEYBUF_WRITE_PTR]	/* get "in" pointer again	*/
	mov	[bx],cx			/* put cx into buffer		*/
	mov     al,#0			/* clear error flag		*/
	pop     bx			/* restore incremented pointer	*/
	mov	[KEYBUF_WRITE_PTR],bx	/* save it in bios data area	*/
	pop     bx			/* return			*/
	pop     ds
	iret   

.org	ROM_BIOS_INT09
	push	ax
	CSEG
	mov	ax,[lastscan]		/* "read" keyboard controller	*/
	mov	ah,#0x4f		/* prepare for int 15 func 4f	*/
	clc
	cmc
	int	0x15			/* int 15 func 4f per bios spec	*/
	mov	ah,al			/* move char to ah		*/
	call	#0xFC00:#0x0F03		/* Helper put key into buffer   */
	mov    	al,#0x20
	out     0x20,al			/* tell pic we're done 		*/
	pop	ax			/* restore registers		*/
	iret

.org	ROM_BIOS_INT13FLOP
	int	0x13
	retf	#2

/*
 * The following code handles illegal IRQ's 2-7.
 * These set the "IRQ unhandled" bits in the BIOS area and return
 */

.org	ROM_BIOS_INT0E
	push	ax
	mov	al,#0x40
	jmp	irq_lo

.org	ROM_BIOS_IRQ02
	push	ax
	mov	al,#0x04
	jmp	irq_lo

.org	ROM_BIOS_IRQ03
	push	ax
	mov	al,#0x08
	jmp	irq_lo

.org	ROM_BIOS_IRQ04
	push	ax
	mov	al,#0x10
	jmp	irq_lo

.org	ROM_BIOS_IRQ05
	push	ax
	mov	al,#0x20
	jmp	irq_lo

.org	ROM_BIOS_IRQ07
	push	ax
	mov	al,#0x80
irq_lo:
	push	ds
	CSEG
	mov	ds,[offset_0000]
	or	byte ptr [0x046B],al
	pop	ds
	mov	al,#0x20		/* Clear the PIC */
	out	#0x20,al
	pop	ax
	iret

.org	ROM_BIOS_IRQ09
	push	ax
	mov	al,#0x20
	out	#0xa0,al
	pop	ax
	jmp	dword ptr 0x0000:0x0028

.org	ROM_BIOS_FLOPPARM
	db	0xdf, 0x02, 0x25, 0x02, 0x12, 0x1b, 0xff, 0x54
	db	0x56, 0x0f, 0x08

.org	ROM_BIOS_INT17
	int	0x17
	retf	#2

.org	ROM_BIOS_INT10LO
	int	0x10
	retf	#2

.org	ROM_BIOS_INT10
#if 0 /* old code */
	int	0x42  /* this will be overwritten with iret, if no dualmon */
	retf	#2
#else
	int	0x10
	retf	#2
#endif

.org	ROM_BIOS_VIDEOPARM
	db	0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c
	db	0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00
	db	0x71, 0x50, 0x05, 0x0a, 0x1f, 0x06, 0x19, 0x1c
	db	0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00
	db	0x38, 0x28, 0x82, 0x0a, 0x7f, 0x06, 0x64, 0x70
	db	0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00
	db	0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19
	db	0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00
	db	0x00, 0x08, 0x00, 0x10, 0x00, 0x40, 0x00, 0x40
	db	0x28, 0x28, 0x50, 0x50, 0x28, 0x28, 0x50, 0x50
	db	0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29

/*
 * DPMI Start
 */
.org	ROM_DPMI_Offset
	.globl	CISH(DPMI_dummy_start)
CISH(DPMI_dummy_start):
	push	bx
	push	ax
	mov	ah,#0x62
	int	0x21			/* Get PSP */
	pop	ax
	.globl	CISH(DPMI_dpmi_init)
CISH(DPMI_dpmi_init):
	hlt
	pop	bx
	retf
	.globl	CISH(DPMI_return_from_dos)
CISH(DPMI_return_from_dos):
	hlt
	.globl	CISH(DPMI_return_from_dos_exec)
CISH(DPMI_return_from_dos_exec):
	hlt
	.globl	CISH(DPMI_return_from_dosint)
CISH(DPMI_return_from_dosint):
	FILL_OPCODE(256,hlt)
	.globl	CISH(DPMI_return_from_realmode)
CISH(DPMI_return_from_realmode):
	hlt
	.globl	CISH(DPMI_return_from_dos_memory)
CISH(DPMI_return_from_dos_memory):
	hlt
	.globl   CISH(DPMI_realmode_callback)
CISH(DPMI_realmode_callback):
	FILL_OPCODE(0x10,hlt)
	.globl	CISH(DPMI_mouse_callback)
CISH(DPMI_mouse_callback):
	hlt
	retf
	.globl	CISH(DPMI_raw_mode_switch)
CISH(DPMI_raw_mode_switch):
	hlt
	.globl	CISH(DPMI_save_restore)
CISH(DPMI_save_restore):
	hlt
	retf
	.globl	CISH(DPMI_API_extension)
CISH(DPMI_API_extension):
	hlt
	retf
	.globl	CISH(DPMI_return_from_pm)
CISH(DPMI_return_from_pm):
	hlt
	.globl	CISH(DPMI_return_from_exception)
CISH(DPMI_return_from_exception):
	hlt
	.globl	CISH(DPMI_return_from_rm_callback)
CISH(DPMI_return_from_rm_callback):
	hlt
	.globl	CISH(DPMI_return_from_mouse_callback)
CISH(DPMI_return_from_mouse_callback):
	hlt
	.globl	CISH(DPMI_exception)
CISH(DPMI_exception):
	FILL_OPCODE(32,hlt)
	.globl	CISH(DPMI_interrupt)
CISH(DPMI_interrupt):
	FILL_OPCODE(256,hlt)

	.globl	CISH(DPMI_dummy_end)
CISH(DPMI_dummy_end):


.org	ROM_BIOS_INT12
	push	ds
	mov	ax,#0x0040		/* point DS to BIOS data */
	mov	ds,ax
	mov	ax,word ptr [0x0013]	/* get memory size */
	pop	ds
	iret

.org	ROM_BIOS_INT11
	push	ds
	mov	ax,#0x0040		/* set DS */
	mov	ds,ax
	mov	ax,word ptr [0x0010]	/* get configuration value */
	pop	ds
	iret

/*
 * int 15 is the system services handler.  for the time being, it's DOSEMU's
 */
.org	ROM_BIOS_INT15
	int	0x15
	retf	#2

/*
 * ordinarily, there should be a table here with the 8x8
 * character map in it.  Unfortunately, comparing AMI BIOS to
 * Pheonix BIOS, there seem to be large differences, so, in
 * order to respect all copyrights, we will just copy this
 * table from your system's BIOS.  I should point out that this
 * won't work on non-IBM machines, but until someone else comes
 * up with a better solution...
 */
.org	ROM_BIOS_8x8FONT
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7
	db	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
	db	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
	db	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
	db	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
	db	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
	db	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57
	db	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
	db	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
	db	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
	db	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
	db	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7
	db	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7
	db	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
	db	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
	db	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7
	db	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7


/*
 * int 1a is the time of day handler.  for the moment, DOSEMU is handling
 * it for us.
 */

.org	ROM_BIOS_INT1A
	int	0x1a
ROM_BIOS_RETF:
	retf	#2

/*
 * This is the timer tick code.  It is called (in theory) 18.2 times/second
 */

.org	ROM_BIOS_INT08
	push	ax
	push	dx
	push	ds
	mov	ax,#0x0040		/* get the BIOS seg */
	mov	ds,ax
	mov	ax,[0x006c]		/* get the current tick value */
	mov	dx,[0x006e]		/* get the current tick value */
	add	ax,#1			/* Increment it */
	adc	dx,#0
	cmp	dx,#0x001b		/* check the day overflow */
	jb	int08_jmp1
	cmp	ax,#0x00b0
	jb	int08_jmp1
	sub	dx,#0x001b		/* adjust the tick day value */
	sub	ax,#0x00b0
	inc	byte ptr [0x0070]	/* increment the overflow */
int08_jmp1:
	mov	[0x006c],ax		/* store the word back */
	mov	[0x006e],dx
	sti				/* allow interrupts */
	int	0x1c			/* generate the 0x1c interrupt */
	mov	al,#0x20		/* reset the PIC */
	out	#0x20,al
	pop	ds
	pop	dx
	pop	ax
	iret

/*
 * This is the array with the list of interrupt handlers for 08-1F & 70-77
 * at startup.
 */

.org	ROM_BIOS_INITINTS
	dw	ROM_BIOS_INT08		/* irq 0: system timer */
	dw	ROM_BIOS_INT09		/* irq 1: keyboard */
	dw	ROM_BIOS_IRQ02
	dw	ROM_BIOS_IRQ03
	dw	ROM_BIOS_IRQ04
	dw	ROM_BIOS_IRQ05
	dw	ROM_BIOS_INT0E		/* irq 6: diskette */
	dw	ROM_BIOS_IRQ07
	dw	ROM_BIOS_INT10		/* video */
	dw	ROM_BIOS_INT11		/* equipment */
	dw	ROM_BIOS_INT12		/* memory */
	dw	ROM_BIOS_INT13		/* direct disk access */
	dw	ROM_BIOS_INT14		/* serial */
	dw	ROM_BIOS_INT15		/* system services */
	dw	ROM_BIOS_INT16		/* keyboard */
	dw	ROM_BIOS_INT17		/* printer */
	dw	ROM_BIOS_IRET		/* basic */
	dw	ROM_BIOS_INT19		/* bootstrap loader */
	dw	ROM_BIOS_INT1A		/* timer services */
	dw	ROM_BIOS_RETF		/* keyboard break */
	dw	ROM_BIOS_RETF		/* user timer tick */
	dw	ROM_BIOS_VIDEOPARM	/* video parameters */
	dw	ROM_BIOS_FLOPPARM	/* floppy parameters */
	dw	0			/* 8x8 font for chars 128-255 */

	dw	ROM_BIOS_IRQ_HI		/* irq 8: realtime clock */
	dw	ROM_BIOS_IRQ09		/* irq 9: cascade to irq 2 */
	dw	ROM_BIOS_IRQ_HI
	dw	ROM_BIOS_IRQ_HI
	dw	ROM_BIOS_IRQ_HI
	dw	ROM_BIOS_IRQ_HI
	dw	ROM_BIOS_IRQ_HI
	dw	ROM_BIOS_IRQ15		/* irq 15: "reserved" ??? */

/*
 * irq 15 -- XXX what is this IRQ for, anyway?
 */
.org	ROM_BIOS_IRQ15
	push	ax
	mov	al,#0x20
	out	#0xa0,al
	out	#0x20,al
	pop	ax
	iret


.org	ROM_BIOS_IRET
	iret

/*
 * INT 05 is invoked on <shift> <print-screen>
 * We could just let DOSEMU handle this because it would be a tad faster,
 * but the code would be a pain to write (video modes), and this code
 * is hardly ever called anyway.  So it doesn't need to be blindingly fast.
 */

.org	ROM_BIOS_INT05
	pusha
	push	dx			/* save all the registers */
	mov	ax,#0x0040
	mov	ds,ax			/* get the BIOS segment in DS */
	mov	al,#01
	xchg	byte ptr [0x0100],al	/* are we currently printing? */
	dec	al
	je	int05_abort		/* if so, quit */
	sti				/* reenable interrupts */
	xor	di,di			/* DI = printer to print to */
	xor	dx,dx			/* DX = current screen offset */
	mov	cx,#0xff		/* CL = error (just in case) */
	mov	ah,#0x02		/* query the printer... */
	int	0x17
	jc	int05_abort_cli		/* DOSEMU returns a non-standard */
					/* int17 value, I think (CARRY = no */
					/* such printer) */
	xor	ah,#0x80		/* in case that changes, check the */
	test	ah,#0xa9		/* real printer status */
	jne	int05_abort_cli
	mov	cl,byte ptr [0x0084]	/* CX = number of lines */
	mov	ah,#0x0f		/* get screen mode */
	int	0x10			/* BH = screen page */
	xchg	dx,si			/* SI = current cursor position */
	mov	bl,ah			/* BL = number of columns */
int05_loop:
	mov	ah,#0x02		/* set cursor position (val in DX) */
	int	0x10
	mov	ah,#0x0f		/* read character */
	int	0x10
	xchg	dx,di			/* get printer */
	xor	ah,ah			/* print character */
	int	0x17
	xchg	dx,di			/* restore cursor pos in dx */
	inc	dl			/* cursor.x++ */
	cmp	bl,dl
	jne	int05_loop		/* if cursor.x<number of cols, loop */
	mov	dl,#0x00		/* cursor.x = 0 */
	inc	dh			/* cursor.y++ */
	xchg	dx,di			/* get printer */
	mov	ax,#0x000d		/* print <cr><lf> */
	int	0x17
	mov	ax,#0x000a
	int	0x17
	xchg	dx,di			/* restore cursor */
	loop	int05_loop		/* do this CX (# of lines) times */
	xchg	dx,si			/* restore cursor position */
	mov	ah,#0x02
	int	0x10
int05_abort_cli:
	cli
	xchg	byte ptr [0x0100],cl	/* swap back the byte */
int05_abort:
	pop	ds			/* restore registers */
	popa
	iret				/* and return */

/*
 * This is the code invoked at bootup
 */

.org	ROM_BIOS_POWERON
	call	#0xFC00:#0x0FFE		/* Power on reset */

/*
 * This is a date string for the BIOS -- anyone got a good suggestion?
 */
	.ascii	"01/01/90"		/* ASCII ROM date */

/*
 * This is the SYSTEM ID byte, which should be the same as in
 * the config table at 0xfe6f5
 */
	db	0xff			/* nothing */
	db	0xfc, 0x00		/* System model id */

	.globl  CISH(bios_f000_end)
CISH(bios_f000_end):
