;*****************************************************************************
;*			   .-= The ROMOS Project =-.			     *
;* ROM Operating System 1.05 by Martin žeh k (C) 2001-2012; rayer@seznam.cz  *
;* Started: 27.3.2001							     *
;* Last updated: 13.5.2012						     *
;* Tested on: Award BIOS 4.51PG (Octek Rhino II ZX-AT, 64kB ISA ROM image)   *
;*	      Award BIOS 6.00PG (Abit BX133-Raid, 15kB and 64kB ISA ROM img) *
;*	      AMI PnP BIOS 2.53 (ASUS P5LD2, 55kB and 64kB PCI ROM image)    *
;*	      Award BIOS 6.00PG (Gigabyte GA-P31-DS3L 64kB PCI ROM image)    *
;* Compile with NASM (186 code), recommended segment to load: D000h	     *
;* Now able to boot FreeDOS from virtual ROMDISK image, see incbin at EOF    *
;*****************************************************************************
CPU 186 			;code compatability

;%define MAKE_DEBUG_COM 	 ;compile as executable *.COM file / zkompiluje spustitelny *.COM soubor
%define MAKE_PCI_MODULE 	;create PCI ROM module instead ISA ROM module (needed for new BIOSes) / vytvori ROM jako PCI modul misto ISA modulu (nektere nove BIOSy uz nepodporuji ISA)
%define HOOK_INT19H		;hook INT19h firts, finish POST and then boot or if commented boot directly without hooking INT19h / ma-li se napred hooknout INT19h, dokoncit POST a pak az bootovat
ROM_IMAGE_SIZE	EQU 64		;size of ROM image in kB / velikost ROM image v kB
ROMDISK_DRIVE	EQU 1		;0=A: 1=B: 80h=C: ... emulated drive / emulovana jednotka
ROMDISK_CYLS	EQU 7		;number of cylinders of emulated drive [1-255] / pocet cylindru emulovane jednotky
ROMDISK_HEADS	EQU 1		;number of heads of emulated drive [1-255] / pocet hlav emulovane jednotky
ROMDISK_SECPT	EQU 18		;sectors per track of emulated drive [1-63] / pocet sektoru na stopu emulovane jednotky
BS_DRIVE_OFFSET EQU 24h 	;offset in bootsector where boot dive number is stored / pozice v bootsektoru, kde je cislo jednotky
BS_SEGMENT	EQU 0		;address to load bootsector / adresa spousteni bootsectoru
BS_OFFSET	EQU 7C00h
ROMOS_MSG_DELAY EQU 30		;delay of MSG1 show in 55ms ticks / doba zobrazeni MSG1 v 55ms ticich
ROMOS_HOTKEY	EQU 00010000b	;mask for ScrollLock key / maska pro klavesu ScrollLock
;ROMOS_HOTKEY	 EQU 00100000b	 ;mask for NumLock key / maska pro klavesu NumLock
NEW_SS		EQU 04000h	;address of new stack (4000:xxxx should be free for Award BIOS)
NEW_SP		EQU 0FFFEh	;adresa noveho zasobniku (oblast 4000:xxxx by mela byt v Award BIOSu volna)
OLD_INT13H	EQU 85h 	;INT 85h is used for permanent store of old INT 13h vector (should be free) / puvodni vektor INT 13h se ulozi na misto INT 85h (melo by byt volne)

;************** ROM header ***************************************************
%ifdef MAKE_DEBUG_COM
	ORG	100h		;use if compiling .COM file / pouzij pri kompilaci .COM souboru
%else
	ORG	0h		;use if compiling ROM image / pouzij pri kompilaci ROM image
	DW	0AA55h		;ROM header signature / ROM hlavicka
	DB	ROM_IMAGE_SIZE*2;ROM size in 512B blocks, minimum 8 blocks / velikost ROM v 512B blocich, minimum 8 bloku
%endif
	JMP	BEGIN		;jump to begin of code / skok na zacatek kodu
	DB	'CHKSUM=',0	;reserved Byte for checksum / rezerva na korekci checksumu
;************** PCI ROM header ***********************************************
%ifdef MAKE_PCI_MODULE		;need to insert additional PCI headers / je potreba vlozit pridavne hlavicky PCI
	TIMES	18h-($-$$) DB 0 ;padding zeros to offset 18h / zarovnani nulami na offset 18h
	DW	PCIHDR		;pointer to PCI Header / ukazatel na hlavicku PCI (musi byt na offsetu 18h)
	DW	PNPHDR		;pointer to PnP Expansion Header / ukazatel na hlavicku PnP (musi byt na offsetu 20h)

PCIHDR: DB	'PCIR'		;PCI data structure signature / hlavicka PCI data structury
	DW	10ECh		;vendor ID-Realtek (must match real PCI device) / ID vyrobce (musi odpovidat existujicimu PCI zarizeni)
	DW	8168h		;device ID-8168/8111 1Gbit eth. (must match real PCI device) / ID zarizeni (musi odpovidat existujicimu PCI zarizeni)
	DW	0		;pointer to vital product data (0=none) / ukazatel na vital product data (0=nic)
	DW	24		;PCI data structure length [B] / velikost PCI data structury [B]
	DB	0		;PCI data structure revision (0=PCI 2.1)/ revize PCI data structury (0=PCI 2.1)
	DB	2,0,0		;PCI device class code (2=notwork ctrl., 0=eth.) / trida PCI zarizeni (musi odpovidat existujicimu PCI zarizeni)
	DW	ROM_IMAGE_SIZE*2;ROM size in 512B blocks / velikost ROM v 512B blocich
	DW	0		;revision level of code / revize kodu
	DB	0		;code type (0=x86 PC-AT) / typ kodu (0=x86 PC-AT kompatabilni)
	DB	80h		;last image indicator/indikuje posledni image v ROM
	DW	0		;reserved

PNPHDR: DB	'$PnP'		;PnP data structure signature / hlavicka PnP data structury (PnP BIOS spec. 1.0a str. 17)
	DB	1		;PnP structure revision / revize PnP struktury
	DB	2		;PnP structure length (in 16B blocks) / velikost PnP struktury v 16B blocich
	DW	0		;offset to next header (0-none) / offset na dalsi hlavicku
	DB	0		;reserved
	DB	33h		;PnP structure checksum / kontrolni soucet PnP struktury
	DD	0		;device identifier / identifikator zarizeni
	DW	0		;pointer to manufacturer string / ukazatel na retezec vyrobce
	DW	0		;pointer to productname string / ukazatel na retezec zarizeni
	DB	2,0,0		;device class code (2=notwork ctrl., 0=eth.) / trida PCI zarizeni (musi odpovidat existujicimu PCI zarizeni)
	DB	64h		;device indicators (64h - shadowable,cacheable,not only for boot,IPL device)
	DW	0		;boot connection vector (0-none)
	DW	0		;disconnect vector (0-none)
	DW	0		;bootstrap entry vector (0-none)
	DW	0		;reserved
	DW	0		;static resource info vector (0-none)
%endif

;************** Constants / Konstanty ****************************************
MSG1	DB	'Press [ScrollLock] to boot ROMOS !',0
%ifdef MAKE_PCI_MODULE
%ifdef HOOK_INT19H
MSG2	DB	'Welcome to ROMOS ver. 1.05 PCI by Martin Rehak (C) 2001-2012',0
%else
MSG2	DB	'Welcome to ROMOS ver. 1.05 PCI by Martin Rehak (C) 2001-2012; rayer@seznam.cz',0
%endif				; HOOK_INT19H
%else
MSG2	DB	'Welcome to ROMOS ver. 1.05 by Martin Rehak (C) 2001-2012; rayer@seznam.cz',0
%endif				; MAKE_PCI_MODULE
MSG3	DB	'ROMOS has installed virtual ROM DISK drive.',0
MSG4	DB	'Bootsector loaded at ',0
MSG5	DB	'Booting!',0

;************** Subroutines / Procedury **************************************
DELAY:				;pause, put number of 55ms idle ticks in AH / pauza, do AH vloz pocet 55ms idle tiku
	STI			;enable interrupts otherwise timer will not be updated / povol preruseni, jinak se neaktualizuje casovac
	PUSHF			;store flags / uloz flagy
	PUSH	AX		;store / uloz AX
	PUSH	ES		;store / uloz ES
	PUSH	BYTE 0		;segment of timer / segment casovace 0000 (opcode 6A 00 misto 68 00 00)
	POP	ES		;ikdyz jsme pushli jen Byte, popne se cely Word (vyssi Byte je vzdy 0)
	ADD	AH,[ES:046Ch]	;add ticks to required delay / k pozadovane pauze pricti aktualni pocet tiku z adresy casovace 046C
@DLY1:	CMP	AH,[ES:046Ch]	;compare current and required value / rovnaji se pozadovane a aktualni ?
	JNE	@DLY1		;if not then repeat / kdyz ne, opakuj
	POP	ES		;restore ES / obnov ES
	POP	AX		;restore AX / obnov AX
	POPF			;restore flags / obnov flagy
	RET			;return / navrat

;*****************************************************************************
GOTOXY: PUSH	AX		;set cursor [x,y] position given in [DL,DH] / nastavi kurzor na pozici [x,y] danou [DL,DH]
	PUSH	BX		;[0,0] is top-left corner / [0,0] je levy horni roh
	MOV	AH,2		;function number 2 / funkce cislo 2
	MOV	BH,0		;videopage / videostranka
	INT	10h		;execute / proved
	POP	BX
	POP	AX
	RET			;return / navrat

;*****************************************************************************
WHEREXY:
	PUSH	AX		;get cursor [x,y] position into [DL,DH] / precte pozici kurzoru [x,y] do [DL,DH]
	PUSH	BX
	PUSH	CX
	MOV	AH,3		;function number 3 / funkce cislo 3
	MOV	BH,0		;videopage / videostranka
	INT	10h		;execute / proved
	POP	CX		;waste information about cursor size / zahod informaci o velikosti kurzoru
	POP	BX
	POP	AX
	RET			;return / navrat

;*****************************************************************************
WRITE:	PUSHA			;write zero-terminated string from CS:SI pointer / vypis 0-ukonceny retezec z CS:SI atributem v BL
	PUSHF			;with every character repeated BH-times (low 7bit) / a opakovanim jednotlivych znaku BH-krat
	PUSH	BX		;and write CRLF if MSB of BH is 1 / a odradkuj pokud MSB BH je 1
	CALL	WHEREXY 	;read cursor position to [DL,DH] / precti pozici kurzoru [DL,DH]
	MOV	AH,9		;function write char 9h (BH=scr_num, AL=char, CX=repeat, BL=attrib) / funkce na vypis znaku 9h
	XOR	CX,CX		;set CH=0, CL=0
	XCHG	CL,BH		;repeat char. BH-times CH=0, CL=BH, BH=0 / opakovani znaku BH-krat
	AND	CL,7Fh		;set MSB=0, accept only 7-bit value / snuluj MSB, akceptujeme pouze 7-bit hodnotu
@WRI1:	MOV	AL,[CS:SI]	;load char. from zero-terminated string / nacti znak z retezce ukonceneho 0
	CMP	AL,0		;if it is 0 / je-li konec - 0
	JE	@WRI2		;then end / tak konec
	INT	10h		;execute / proved
	INC	SI		;increment string index / inkrementuj index znaku ve vete
	INC	DL		;increment X-cursor position / inkrementuj X-ovou pozizi kurzoru
	CALL	GOTOXY		;set cursor to [DL,DH] (need to do myself) / nastav kurzor na [DL,DH] (musim to delat rucne)
	JMP	SHORT @WRI1	;repeat / opakuj
@WRI2:	POP	BX		;restore BX / obnov BX
	CMP	BH,80h		;if BH<80h (MSB=0) skip / pokud je BH<80h (MSB=0)
	JS	@WRI3		;jump to end / preskoc na konec
	POPF			;else write newline / jinak odradkuj
	POPA			;restore regs because WCRLF store them again / obnov registry protoze WCRLF je opet uklada
WCRLF:	PUSHA			;write CRLF = newline / vypis CRLF = novy radek
	PUSHF			;this subfunc. can be called out of WRITE func. / tato podfunkce muze byt volana i mimo fci WRITE
	MOV	AX,0E0Dh	;function 0E - write char as TTY, CR / funkce 0E - pis TTY znak, znak CR
	XOR	BL,BL		;paper color=0 / barva papiru=0
	INT	10h		;execute / proved
	MOV	AL,0Ah		;char LF / znak LF
	INT	10h		;execute / proved

@WRI3:	POPF			;restore flags (2B) / obnov flagy
	POPA			;restore regs DI,SI,BP,SP,BX,DX,CX,AX (16B)
	RET			;return / navrat

;*****************************************************************************
WHEXPTR:PUSH	BX		;write hexa pointer DX:AX / vypis hexa pointer DX:AX
	PUSH	DX		;store BX,DX / uloz BX,DX
	XOR	BL,BL		;paper color=0 / barva papiru=0
	XCHG	DX,AX		;swap DX-AX / prohod AX-AX
	CALL	WHEXW		;write segment from AX / vypis segment z AX
	MOV	AX,0E3Ah	;write char ':' / vypis znak ':'
	INT	10h		;via BIOS / pres BIOS
	POP	AX		;restore segment to AX /obnov segment do AX
	XCHG	DX,AX		;swap back DX-AX / prohod DX-AX tak jak byly puvodne
	CALL	WHEXW		;write offset from AX / vypis offset z AX
	POP	BX		;restore BX / obnov BX
	RET			;return / navrat

;*****************************************************************************
WHEXW:	XCHG	AH,AL		;write hexa word from DX / vypis hexa word z DX
	CALL	WHEXB		;call WHEXB to write upper Byte / zavolej WHEXB na vypis horniho Byte
	XCHG	AH,AL		;swap AH-AL / prohod AH-AL
	CALL	WHEXB		;call WHEXB to write lower Byte / zavolej WHEXB na vypis dolniho Byte
	RET			;return / navrat

;*****************************************************************************
WHEXB:	PUSHF			;write hexa Byte from AL / vypis hexa Byte z AL
	PUSH	AX		;store flags,AX / uloz flagy,AX
	MOV	AH,0Eh		;video BIOS service / sluzba video BIOSu
	PUSH	AX		;store AX again / uloz AX jeste jednou
	SHR	AL,4		;prepare high nibble / priprav vyssi nibble
	CALL	@WHB1		;write high nibble / vypis vyssi nibble
	POP	AX		;restore AX / obnov AX
	AND	AL,0Fh		;prepare low nibble / priprav nizsi nibble
	CALL	@WHB1		;write low nibble / vypis nizsi nibble
	POP	AX		;restore AX / obnov AX
	POPF			;restore flags / obnov flagy
	RET			;return / navrat
@WHB1:	CMP	AL,10		;if x<10, set CF=1
	SBB	AL,69h		;0-9: 96h..9Fh, A-F: A1h..A6h; 0-9: subtr. 66h -> 30h-39h
	DAS			;A-F: subtr. 60h -> 41h..46h
	INT	10h		;write char via BIOS / vypis znak pres BIOS
	RET			;return / navrat

;*****************************************************************************
WREGS:	PUSHA			;write register dump line and CRLF / vypis na radku registry a odradkuj
	PUSH	DS		;prepare all regs to stack / priprav vsechny registry do zasobniku
	PUSH	ES		;AX,CX,DX,BX,SP,BP,SI,DI, DS,ES,SS,CS, F
	PUSH	SS
	PUSH	CS
	PUSHF

	MOV	CX,9		;loop counter-9x repeat / pocitadlo smycky-9x oparuj
	MOV	SI,REGSTR	;prepare reg name / priprav jmeno registru
	MOV	BP,SP		;set BP=SP for indexing stored regs / priprav BP=SP pro indexaci ulozenych registru
@WREGS1:MOV	BX,0107h	;seda barva, opakovani 1x
	CALL	WRITE		;write reg name / vypis jmeno registru
	MOV	AX,0E3Dh	;write char function, char '=' / funkce vypisu znaku, znak '='
	XOR	BL,BL		;paper color=0 / barva papiru=0
	INT	10h		;write '=' via BIOS / vypis '=' pres BIOS
	MOV	AX,[SS:BP]	;load reg from stack to AX / nacti registr ze zasobniku do AX
	CALL	WHEXW		;write AX hexa value / vypis hexa hodnotu AX
	MOV	AX,0E20h	;;write char function, char ' ' / funkce vypisu znaku, znak ' '
	INT	10h		;via BIOS / pres BIOS
	INC	BP		;go up through the stack data / jdi v zasobniku na dalsi registr
	INC	BP
	INC	SI		;reg name pointer+=3 / nastav pointer na dalsi jmeno registru (+3)
	INC	SI
	INC	SI
	LOOP	@WREGS1 	;repeat until CX is nonzero / opakuj dokud je CX nenulove
	CALL	WCRLF		;newline / odradkuj

	POPF			;restore regs and flag / obnov registry a flag
	POP	DS		;POP DS instead CS because it crashed under BOCHS
	POP	SS		;anyway CS was not changed during this routine
	POP	ES
	POP	DS
	POPA
	RET			;return / navrat
REGSTR: DB	'F',0,0 	;strings with regs names (all must be 3 bytes long) / retezce s nazvy registru (kazdy musi byt dlouhy 3 byte)
	DB	'CS',0
	DB	'SS',0
	DB	'ES',0
	DB	'DS',0
	DB	'DI',0
	DB	'SI',0
	DB	'BP',0
	DB	'SP',0

;************** New INT 13h handler emulating virtual ROM disk, now supports functions 2,3,8
;************** Nova obsluha INT 13h emulujici virtualni ROM disk, nyni podporuje sluzby 2,3,8
NEW_INT13H:			;INT XX do PUSHF, clear IF,TF, PUSH CS,IP (6B) / INT XX provadi..., SP=x-6
	PUSHF			;store flags (2B) / uloz flagy (2B), SP=x-8
	CMP	DL,ROMDISK_DRIVE;related to our disk ? / tyka se to naseho disku?
	JE	@NEW_INT13H_HUB ;if yes continue below else / pokud ano, pokracuj nize, jinak
	POPF			;restore flags (2B) / obnov flagy (2B), SP=x-6
	INT	OLD_INT13H	;call old INT 13h handler / zavolej puvodni preruseni INT 13h, SP=x-6
	PUSH	BP		;store BP (2B) / uloz BP (2B), SP=x-8
	MOV	BP,SP		;set BP to current SP / nastav BP na aktualni SP, BP=SP=x-8
	PUSH	AX		;store AX (2B) / uloz AX (2B), SP=x-10
	LAHF			;load flags[7:0] to AH that was returned by old INT 13h handler / vlozi do AH LSB flagu 7:0, ktere vratila puvodni obsluha INT 13h, SP=x-10
	MOV	[BP+6],AH	;replace previously saved flags[7:0] of INT caller on stack by current flags (SS is implicit) / prepis flagy[7:0] v zasobniku, ktere ulozil program volajici INT aktualnimi flagy (SS je implicitni), SP=x-10
	POP	AX		;restore AX (2B) / obnov AX (2B), SP=x-8
	POP	BP		;restore BP (2B) / obnov BP (2B), SP=x-6
	IRET			;return from ISR, do POP IP,CS,F (6B) / navrat z obsluhy preruseni provadi..., SP=x-0

@NEW_INT13H_HUB:		;subfunction hub / rozcestnik podfunkci
	PUSHA			;store regs AX,CX,DX,BX,SP,BP,SI,DI (16B) / uloz registry...
	PUSH	DS		;store DS (2B) / uloz DS (2B)
	CMP	AH,02h		;function ?= 2h - read sectors / sluzba ?= 2h - cti sektory
	JE	@NEW_INT13H_02H
	CMP	AH,03h		;function ?= 3h - write sectors / sluzba ?= 3h - pis sektory
	JE	@NEW_INT13H_03H
	CMP	AH,08h		;function ?= 8h - get drive params / sluzba ?= 8h - vrat parametry disku
	JE	@NEW_INT13H_08H
	CMP	AH,15h		;function ?= 15h - get disk type / sluzba ?= 15h - vrat typ disku
	JE	@NEW_INT13H_15H
	ADD	AH,'A'		;infoflag of unhandled function (cislo 0=A, 1=B,...) / priznak neobslouzeni funkce
	JMP	@NEW_INT13HEND1 ;other? jump to end and let me know / jina? preskoc na konec a dej o tom vedet

@NEW_INT13H_02H:		;INT 13h: AH=func, DL=drive, DH=H, CH=C, CL=S,
	PUSH	AX		;	  AL=S-CNT, ES:BX=buffer of calling program
	MOV	DI,BX		;prepare destination address ES:BX->ES:DI / priprav cilovou adresu...
	XOR	SI,SI		;we prepare linear address to SI step by step / do SI si postupne pripravime linearni adresu
	AND	CL,03Fh 	;number of sector is only 6-bit / cislo sektoru je jen 6-bitove (cyl<=80 u FD)
	DEC	CL		;BIOS numbers the sectors from starting 1, we need from 0 / BIOS cisluje sektory o 1, my potebujem od 0
	MOV	AX,ROMDISK_SECPT;SI=LINSEC=NH*NS*C + NS*H + (S-1)
	MUL	DH		;AX*DH->AX (NS*H)
	ADD	SI,AX		;add to SI (SI=NS*H) / pricti do SI
	MOV	AX,ROMDISK_HEADS;there's no check of CHS validity / neprovadi se zadna kontrola parametru CHS
	MOV	BL,ROMDISK_SECPT;so when CHS overflow it returns invalid data from memory / takze pri prekroceni adr. rozs. vraci nesmyslna data
	MUL	BL		;AX*BL->AX (NH*NS)
	MUL	CH		;AX*CH->AX (NH*NS*C)
	ADD	SI,AX		;add to SI (SI=NS*H + NH*NS*C) / pricti do SI
	XOR	CH,CH		;prepare S to CX / priprav S v CX
	ADD	SI,CX		;add to SI (SI=NH*NS*C + NS*H + (S-1)) / pricti do SI
	SHL	SI,9		;recalc from sectors to Bytes (SI*512) / prepocti SI ze sektoru na Byty
	ADD	SI,IMG_BEGIN	;prepare source offset (and add offset to image) / priprav zdrojovy offset (jeste pricti offset na image)
	PUSH	CS		;prepare source segment / priprav zdrojovy segment
	POP	DS		;set DS=CS (ROM segment with disk image / segment ROM s image disku)
	POP	CX		;restore number of required sectors to CX / vyber pocet ctenych sektoru do CX
	SHL	CX,9		;recalc number of sectors to number of Bytes (S-CNT*512) / prepocitej pocet sektoru na Byty
	REP	MOVSB		;copy until CX is nonzero / kopiruj dokud CX neni nulove
	JMP	@NEW_INT13HEND	;end without calling original INT 13h handler / konec bez volani puvodni obsluhy INT 13h

@NEW_INT13H_03H:		;ROM disk is read-only so return errorcode AH=3 / ROM disk je read-only, takze vrat chybu AH=3
	MOV	BP,SP		;set BP=SP / nastav BP=SP
	OR	[BP+24],BYTE 1	;nastav CARRY bit ve flags (LSB) na zasobniku (adr=2+16+2+2+2 objem dat v zasob. nad F)
	MOV	[BP+17],BYTE 3	;nastav AH v zasobniku na kod chyby 3 (adr=16+2-1=DS+ALL)
	JMP	@NEW_INT13HEND	;end without calling original INT 13h handler / konec bez volani puvodni obsluhy INT 13h

@NEW_INT13H_08H:		;return CHS info about ROM disk geometry / vrat informace CHS o geometrii ROM disku
	MOV	BP,SP		;set BP=SP / nastav BP=SP
	MOV	CH,ROMDISK_CYLS ;set CH to number of cylinders / nastav CH na pocet cylindru
	MOV	CL,ROMDISK_SECPT;set CL to number of sectors per track / nastav CL na pocet sektoru/stopu
	MOV	[BP+13],BYTE ROMDISK_HEADS ;nastav DH v zasobniku - hlavy (adr=2+16-2-2-1=DS+ALL-AX-CX-DL)
	MOV	[BP+14],CX	;nastav CX v zasobniku (adr=2+16-2-2=DS+ALL-AX-CX)
	JMP	@NEW_INT13HEND	;end without calling original INT 13h handler / konec bez volani puvodni obsluhy INT 13h

@NEW_INT13H_15H:		;ROM disk is like nonchangeable diskette drive / ROM disk je jako nevymenna disketova jednotka
	MOV	BP,SP		;set BP=SP / nastav BP=SP
	MOV	[BP+17],BYTE 1	;nastav AH v zasobniku na kod chyby 0 (adr=16+2-1=DS+ALL)
	MOV	[BP+14],WORD 0	;set CX=0 (total drive sectors high word to 0) / nastav vyssi slovo poctu sektoru na 0
	MOV	[BP+12],WORD ROMDISK_CYLS*ROMDISK_HEADS*ROMDISK_SECPT ;set DX=total drive sectors / nastav DX=celkovy pocet sektoru
	JMP	@NEW_INT13HEND	;end without calling original INT 13h handler / konec bez volani puvodni obsluhy INT 13h

@NEW_INT13HEND: 		;INT 13h watcher (work in textmode only / funguje jen v textovem modu)
	MOV	AH,'*'		;flag of handled function / priznak obslouzeni funkce
@NEW_INT13HEND1:
	PUSH	WORD 0B800h
	POP	DS		;set DS=B800h (segment of textmode VRAM on VGA / segment textove VRAM u VGA)
	MOV	[DS:79*2],AH	;write flag character to top-right corner from AH / do praveho horniho rohu obrazovky vykresli znak z AH
	POP	DS		;restore DS (2B) / obnov DS (2B)
	POPA			;restore regs DI,SI,BP,SP,BX,DX,CX,AX (16B) / obnov registry...
	POPF			;restore flags (2B) / obnov flagy (2B)
	IRET			;return from ISR, do POP IP,CS,F (6B) / navrat z obsluhy preruseni provadi...

;*****************************************************************************
INSTALL_NEW_INT13H:		;install new INT 13h handler / nainstaluj novou obsluhu INT 13h
	PUSHA			;and write message about vector change + CRLF / a vypis hlaseni o zmene vektoru a odradkuj
	PUSH	DS		;store DS / uloz DS
	PUSH	BYTE 0		;push 00
	POP	DS		;pop 0000 (DS=0) / vynuluj DS
	MOV	SI,13h*4	;set SI at INT 13h IVT entry / nastav SI na polozku IVT vektoru INT 13h
	MOV	DI,OLD_INT13H*4 ;set DI at free INT 85h IVT entry / nastav DI na volnou polozku IVT vektoru INT 85h
	MOV	AX,[SI] 	;load original offset of INT 13h handler from IVT to AX (DS is implicit) / nacti do AX offset puvodni obsluhy INT 13h z IVT (DS je implicitni)
	MOV	[DI],AX 	;store it to other safe place in IVT (DS is implicit) / uloz ho na jine bezpecne misto v IVT (DS je implicitni)
	MOV	DX,[SI+2]	;load original segment of INT 13h handler from IVT to DX (DS is implicit) / nacti do DX segment puvodni obsluhy INT 13h z IVT (DS je implicitni)
	MOV	[DI+2],DX	;store it to other safe place in IVT (DS is implicit) / uloz ho na jine bezpecne misto v IVT (DS je implicitni)
	MOV	[SI],WORD NEW_INT13H ;set offset of new INT 13h handler (DS is implicit) / nastav offset nove obsluhy INT 13h (DS je implicitni)
	MOV	[SI+2],CS	;set segment of new INT 13h handler (current-ROM, DS is implicit) / nastav segment nove obsluhy INT 13h (aktualni-ROM, DS je implicitni)
	POP	DS		;restore DS / obnov DS
	MOV	SI,IINTSTR	;write hook INT 13h vector message / vypis zpravu o zmene vektoru INT 13h
	MOV	BX,0107h	;grey color, 1-times / seda barva, opakovani 1x
	CALL	WRITE
	CALL	WHEXPTR 	;write original vector DX:AX / vypis puvodni vektor DX:AX
	MOV	SI,AROWSTR
	CALL	WRITE		;write / vypis ' -> '
	MOV	DX,CS		;current code segment
	MOV	AX,WORD NEW_INT13H
	CALL	WHEXPTR 	;write new vector DX:AX (CS:NEW_INT13H) / vypis novy vektor DX:AX
	CALL	WCRLF		;newline / odradkuj
	POPA			;restore regs DI,SI,BP,SP,BX,DX,CX,AX (16B) / obnov registry...
	RET			;return / navrat
IINTSTR:DB	'INT13h vector has been hooked ',0
AROWSTR:DB	' -> ',0

;************** Initial code - modify carefully! / Pocatecni kod, upravujte s max. opatrnosti!
BEGIN:	PUSHF			;store flags (2B) / uloz flagy (2B)
	PUSHA			;store regs AX,CX,DX,BX,SP,BP,SI,DI (16B) / uloz registry...
	MOV	AX,SS		;set AX=original SS / nastav AX=puvodni SS
	PUSH	NEW_SS		;set new bigger stack (BIOS use default SS=0 SP=0Dxx - small) / nastav novy vetsi zasobnik...
	POP	SS		;segment
	MOV	BX,NEW_SP	;offset
	XCHG	BX,SP		;set BX=original SP / nastav BX=puvodni SP
	PUSH	AX		;store configuration of original stack - SS / uloz konfiguraci stareho zasobniku - SS
	PUSH	BX		;store configuration of original stack - SP / uloz konfiguraci stareho zasobniku - SP
	PUSH	ES		;store ES / uloz ES
	PUSH	DS		;store DS / uloz DS
;TEST FOR 1ST RUN-ROMSCAN/2ND RUN-INT19H CALL
%ifdef HOOK_INT19H		;only if we want to hook INT 19h otherwise skip this / jen pokud chceme hooknout INT 19h
	PUSH	BYTE 0		;push 00
	POP	ES		;pop 0000 (ES=0, segment of IVT) / nastav ES=0, segment IVT
	CMP	[ES:19h*4],WORD BEGIN ;compare if offset match the BEGIN label / porovnej, shoduje-li se offset s labelem BEGIN
	JNE	RUN1ST		;if not it means that's 1st run-ROMSCAN / pokud ne, znamena to, ze bezime poprve-ROMSCAN
	MOV	AX,CS		;set AX=CS (cannot compare CS directly / CS nelze primo porovnavat)
	CMP	[ES:19h*4+2],AX ;compare if segment match the current CS segment / porovnej, shoduje-li se segment s aktualnim CS
	JNE	RUN1ST		;if not it means that's 1st run-ROMSCAN / pokud ne, znamena to, ze bezime poprve-ROMSCAN
	JMP	BOOT		;else continue next phase at BOOT label / jinak pokracuj v dalsi fazi na labelu BOOT
%endif
;ASK FOR BOOT ROMOS
RUN1ST: CALL	WCRLF		;newline / odradkuj
	MOV	SI,MSG1 	;prompt to press HotKey / vyzva ke stisku HotKey
	MOV	BX,810Fh	;white color, 1-times + CRLF / bila barva, opakovani 1x a odradkuj
	CALL	WRITE		;write message / vypis hlasku
	MOV	AH,ROMOS_MSG_DELAY ;wait / pockej
	CALL	DELAY
;TEST FOR SCROLLOCK		;test if HotKey was pressed / otestuj, jestli je stisknuty HotKey
	PUSH	BYTE 0		;push 00
	POP	ES		;pop 0000 (ES=0, segment of keyboard flags / segment flagu klavesnice)
	MOV	AL,[ES:0417h]	;offset of keyboard flags / offset flagu klavesnice 0417h
	MOV	AH,AL		;store loaded value to AH / schovej si nactenou hodnotu do AH
	AND	AL,ROMOS_HOTKEY ;mask the HotKey / vymaskuj HotKey
	CMP	AL,ROMOS_HOTKEY ;if it is turned on then / je-li zaply,
%ifdef HOOK_INT19H		;if we want to hook INT 19h
	JE	EXIT_AND_HOOK_INT19H ;exit and hook INT 19h / skonci a hookni INT 19h
%else				;or if we boot directly without hooking INT 19h / pokud nechcem hooknout INT 19h
	JE BOOT 		;then go to boot ROMOS / pak jdi primo na sekci BOOT
%endif				;if we don't want to run ROMOS then
	MOV	[CS:0],ES	;erase 55AAxx (ES=0) ROM header, then BIOS will free this area for UMB / smaz hlavicku ROM 55AAxx (ES=0)...
	JMP	EXIT		;end without hook of INT 19h / skonci bez hooknuti INT 19h

;************** Terminating and restoring, returning controll back to BIOS ***
;************** Ukonceni, obnoveni stavu a predani rizeni zpet BIOSu *********
EXIT_AND_HOOK_INT19H:
%ifdef HOOK_INT19H		;only if we want to hook INT 19h otherwise skip this / jen pokud chceme hooknout INT 19h
;here you can place a code which should be executed on 1st run-during ROMSCAN
;zde je jeste mozno pridat kod, ktery se ma provest pri prvnim spusteni-ROMSCAN
	MOV	AL,ROMOS_HOTKEY ;load HotKey bit mask / nacti bitovou masku HotKey
	NOT	AL		;negate HotKey bit mask / zneguj bitovou masku HotKey
	AND	AH,AL		;turn off the HotKey / zhasni HotKey
	MOV	[ES:0417h],AH	;write keyboard flag (ES=0, see above) / zapis flag klavesnice
;HOOK INT 19h
	MOV	[ES:19h*4],WORD BEGIN ;put ROM module address here / vlozime tam adresu ROM modulu,
	MOV	[ES:19h*4+2],CS ;offset first, then segment / napred offset a pak segment
%endif
EXIT:
	POP	DS		;restore DS (2B) / obnov DS (2B)
	POP	ES		;restore ES (2B) / obnov ES (2B)
	POP	BX		;get BX=original SP / nacti BX=puvodni SP
	POP	SS		;restore SS=original SS / obnov SS=puvodni SS
	MOV	SP,BX		;restore SP=original SP / obnov SP=puvodni SP
	POPA			;restore regs DI,SI,BP,SP,BX,DX,CX,AX (16B) / obnov registry...
	POPF			;restore flags (2B) / obnov flagy (2B)

%ifdef MAKE_DEBUG_COM
	INT	20h		;use if compiling *.COM file / pouzij pri kompilaci .COM souboru
%else
	RETF			;CBh - FAR RET
%endif

;************** Here you can place your code without risks - it can be skipped when booting
;************** Zde uz je mozno psat kod bez obav, lze ho pri bootu preskocit
BOOT:				;this code is executed after POST is finished / tento kod se uz provadi po ukonceni POST
				;when INT 19h is invoked ROM area is write protected / pri volani INT19h, ROM pamet je zamcena pro zapis
	CALL	WCRLF		;newline / odradkuj
	MOV	SI,MSG2
	MOV	BX,810Eh	;yellow color, 1-times + CRLF / zluta barva, opakovani 1x a odradkuj
	CALL	WRITE		;write welcome message / vypis welcome
	MOV	AH,20		;20*55ms delay / pauza
	CALL	DELAY

	CALL	INSTALL_NEW_INT13H ;install new INT 13h handler / nainstaluj novou obsluhu INT 13h
	CALL	DELAY		;for accessing virtual ROM disk / pro pristup k virtual ROM disku

	MOV	SI,MSG3
	MOV	BX,8107h	;grey color, 1-times + CRLF / seda barva, opakovani 1x a odradkuj
	CALL	WRITE		;write isntall ROMDISK message / vypis isntall ROMDISK
	CALL	DELAY

	CALL	WCRLF		;newline / odradkuj
	CALL	WREGS		;write registers dump / vypis registry
	CALL	DELAY

	MOV	SI,MSG4
	MOV	BX,0107h	;grey color, 1-times / seda barva, opakovani 1x
	CALL	WRITE		;write Bootsector loaded at message / vypis Bootsector loaded at
	MOV	DX,BS_SEGMENT	;prepare segment to DX / priprav segment do DX
	MOV	AX,BS_OFFSET	;prepare offset to AX / priprav offset do AX
	CALL	WHEXPTR 	;write pointer / vypis pointer
	CALL	WCRLF		;newline / odradkuj

	MOV	SI,MSG5
	MOV	BX,810Fh	;white color, 1-times + CRLF / bila barva, opakovani 1x a odradkuj
	CALL	WRITE		;write Booting! message / vypis Booting!
	MOV	AH,10		;10*55ms delay / pauza
	CALL	DELAY

;************** Copy bootsector from virtual ROM disk at starting address ****
;************** Prekopiruje bootsector z virtual ROM disku na spousteci adresu
	PUSH	BYTE 0		;push 00
	POP	ES		;pop 0000 (ES=0, segment BIOS data)
	MOV	SI,0410h	;prepare address of equipment Byte (INT11h) / priprav adresu Bytu vybaveni (INT11h)
	MOV	AL,[ES:SI]	;two top bits means number of drives-1 / horni dva bity udavaji pocet mechanik-1
	MOV	AH,BYTE ROMDISK_DRIVE ;so: any=00, A:=00, A:+B:=01 / tedy: zadna=00, A:=00, A:+B:=01
	CMP	AH,1		;if we have to emulate B: drive / pokud mame emulovat jednotku B:
	JNE	SKIP_DRVNUPD	;else leave / jinak nech bejt
	OR	AL,01000000b	;number of drives is needed to be increased / je potreba zvysit pocet mechanik
	MOV	[ES:SI],AL	;write updated equipment Byte / zapis aktualizovany Byte vybaveni
SKIP_DRVNUPD:
	PUSH	WORD BS_SEGMENT ;prepare destination segment for bootsector / priprav cilovy segment pro nahrani bootsectoru
	POP	ES		;set ES=BS_SEGMENT / nastav ES=BS_SEGMENT
	MOV	DI,BS_OFFSET	;prepare destination offset for bootsector / priprav cilovy offset pro nahrani bootsectoru
	PUSH	CS		;prepare source segment / priprav zdrojovy segment
	POP	DS		;set DS=CS / nastav DS=CS
	MOV	SI,IMG_BEGIN	;prepare source offset - beginning of the ROMDISK image / priprav zdrojovy offset-zacatek ROMDISK image
	MOV	CX,512		;1 sector=512B
	REP	MOVSB		;copy until CX is nonzero / kopiruj dokud CX neni nulove
	MOV	[ES:BS_OFFSET+BS_DRIVE_OFFSET], BYTE ROMDISK_DRIVE ;patch bootsector by drive number / patch bootsectoru podle c. drive
	MOV	DL,BYTE ROMDISK_DRIVE ;set bootdrive for bootsector / nastav bootdrive pro bootsector
	JMP	BS_SEGMENT:BS_OFFSET  ;jump to beginning of bootsector copy / skoc na zacatek kopie bootsectoru


;************** Include VIRTUAL ROMDISK image / Vloz VIRTUAL ROMDISK image
IMG_BEGIN:			;append binary file of romdisk image at the end / nakonec pripoj binarni soubor image disku
;	 incbin "romd15kb.img"	 ;FAT12 (1x), C:2, H:1, S:18, S/CL:1, ROOTE:16
;	 incbin "romd54kb.img"	 ;FAT12 (1x), C:6, H:1, S:18, S/CL:1, ROOTE:16
	incbin "romd64kb.img"	;FAT12 (1x), C:7, H:1, S:18, S/CL:1, ROOTE:16
;	 incbin "romdusb.img"	 ;FAT12 (1x), C:7, H:1, S:18, S/CL:1, ROOTE:16
IMG_END:
TIMES ROM_IMAGE_SIZE*1024-($-$$) db 0 ;zero padding to required length / zarovnani nulami na danou velikost
END:

;************** Block diagram for HOOK_INT19H option enabled *****************
;				(BEGIN)
;			___________|____________
;		       |store regs, old stack...|
;			~~~~~~~~~~~|~~~~~~~~~~~~
;			  _________|_________
;    ___________________/'    running 1st?   `\
;   |  go to BOOT    Y `\ (called by ROMSCAN) /'
;   |			 ~~~~~~~~N~|~~~~~~~~~~
;   |				   | RUN1ST:
;   |			 __________|___________
;   |			|display HotKey message|
;   |			 ~~~~~~~~~~|~~~~~~~~~~~
;   |			      _____|_____
;   |			    /' was HotKey`\_________________________________
;   |			    \	pressed?  /  Y	go to EXIT_AND_HOOK_INT19H  |
;   |			     ~~~~~~|~N~~~~				    |
;   |			 __________|___________ 			    |
;   |			|delete 55AA ROM header|			    |
;   |			 ~~~~~~~~~~|~~~~~~~~~~~ 			    |
;   |				   |		     ,----------------------'
;   |				   |		     | EXIT_AND_HOOK_INT19H:
;   |				   |	  ___________|____________
;   |				   |	 |     disable hotkey	  |
;   |				   |	 |(exec some 1st-run code)|
;   |				   |	 |  hook INT 19h to ROM   |
;   |				   |	  ~~~~~~~~~~~|~~~~~~~~~~~~
;   |				   `-----------------| EXIT:
;   |					 ____________|_____________
;   |					|restore regs, old stack...|
;   |					|     and RETF to BIOS	   |
;   |					 ~~~~~~~~~~~~~~~~~~~~~~~~~~
;   `------------->----------------,
;				   | BOOT: (note: this is right place for user code)
;		   ________________|_________________
;		  |	 display some messages	     |
;		  |    install new INT13h handler    |
;		  |	 look for number of FDDs     |
;		  |copy bootsector from image to RAM |
;		  |patch bootdrive Byte in bootsector|
;		  |jump to bootsector (never return) |
;		   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
;************** Block diagram for HOOK_INT19H option disabled ****************
;				(BEGIN)
;			___________|____________
;		       |store regs, old stack...|
;			~~~~~~~~~~~|~~~~~~~~~~~~
;			 __________|___________
;			|display HotKey message|
;			 ~~~~~~~~~~|~~~~~~~~~~~
;			      _____|_____
;		    ________/' was HotKey`\
;		   |	  Y \	pressed?  /
;		   |	     ~~~~~~|~N~~~~
;		   |	 __________|___________
;		   |	|delete 55AA ROM header|
;		   |	 ~~~~~~~~~~|~~~~~~~~~~~
;		   |		   | EXIT:
;		   |   ____________|_____________
;		   |  |restore regs, old stack...|
;		   |  |     and RETF to BIOS	 |
;		   |   ~~~~~~~~~~~~~~~~~~~~~~~~~~
;		   |
;		   `------->-------,
;				   | BOOT: (note: this is right place for user code)
;		   ________________|_________________
;		  |	 display some messages	     |
;		  |    install new INT13h handler    |
;		  |	 look for number of FDDs     |
;		  |copy bootsector from image to RAM |
;		  |patch bootdrive Byte in bootsector|
;		  |jump to bootsector (never return) |
;		   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
