Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

3. Inicializace VGA grafiky

Při tvorbě programu VEGASLOT vyjdeme z testovacího programu lineárního zaváděcího sektoru, protože tento sektor nám bude sloužit při zavádění programu VEGASLOT z diskety. Zkopírujte ze složky lineárního zaváděcího sektoru soubory BOOT.BIN, INSTALL.COM a PROGRAM.ASM.

Výstupem programu pro DOS variantu nebude tentokrát program COM ale EXE, protože bude potřeba spouštět program větší než 64 KB. Program bude překládán jako program COM, ale bude obsahovat hlavičku souboru EXE a na konec souboru bude přikopírován obrázek grafiky. Připravte si proto povelový soubor s následujícím obsahem, který bude používán k překladu programu a k připojení obrázku grafiky s rozlišením 320x200:

NASM16.EXE -d DOS -o PROGRAM.DAT PROGRAM.ASM
if not exist PROGRAM.DAT goto ERROR1
copy /b PROGRAM.DAT + 320X200.BMP PROGRAM.EXE > nul
del PROGRAM.DAT
:ERROR1

NASM16.EXE -o PROGRAM.DAT PROGRAM.ASM
if not exist PROGRAM.DAT goto ERROR2
copy /b PROGRAM.DAT + 320X200.BMP PROGRAM.BIN > nul
del PROGRAM.DAT
:ERROR2

Obsah souboru PROGRAM.ASM:


StackSize	equ	0x2000		; stack size (paragraph aligned)
BMPHead		equ	54		; size of head of BMP picture
BMPPal		equ	256		; number of palettes in BMP picture
BMPPalSize	equ	BMPPal*4	; size of palettes in BMP file
BMPData		equ	BMPHead+BMPPalSize ; start of data in BMP file
BMPSize		equ	(320*200+BMPData+3)&(~3) ; BMP picture size
DataSize	equ	(BMPSize+15)&(~15) ; size of graphics

SECTION		.text
		org	0
%ifdef DOS
EXEStart:	db	4Dh,5Ah		; EXE file signature
		dw	AllocSize % 512
		dw	(AllocSize + 511) / 512
		dw	0		; number of relocation entries
		dw	EXEHead/16	; header size in paragraphs
		dw	StackSize/16+4	; min extra memory
		dw	StackSize/16+4	; max extra memory
		dw	AllocSize/16	; initial SS
		dw	StackSize	; initial SP
		dw	0		; checksum
		dw	Start		; initial IP
		dw	-EXEHead/16	; initial CS
		dw	0		; file offset of the relocation table
		dw	0		; overlay number
		align	16,db 0
EXEEnd:
EXEHead		equ	(EXEEnd - EXEStart) ; EXE head size
%else
EXEHead		equ	0
%endif

; ----------------------------------------------------------------------------
;             Start of program at 0080:0000 (or CS:0020 in case of EXE program)
; ----------------------------------------------------------------------------

; ------------- Identification

Start:		jmp	Init

Ident		dw	8A25h		; identification word

; ------------- Init segments

Init:		cli			; disable interrupts
		mov	ax,cs		; AX <- program segment
		mov	ds,ax		; DS <- program segment
		add	ax,(Graphics - Start + EXEHead)/16 ; add code size
		mov	[GraphSeg],ax	; segment with VGA graphics
		mov	word [GraphOff],BMPData ; offset with VGA graphics
		add	ax,DataSize/16	; add graphics size
		mov	ss,ax		; SS <- stack segment
		mov	sp,StackSize	; SP <- end of stack
		sti			; enable interrupts

; ------------- Push old videomode

		mov	ah,0fh		; AH <- function code
		call	Int10		; call Int 10h interrupt
		mov	[OldVMode],al	; store old video mode

; ------------- Set VGA videomode

		mov	ax,13h		; AH <- function, AL <- videomode
		call	Int10		; call Int 10h interrupt

; ------------- Check, if videomode is set OK
		
		mov	ah,0fh		; AH <- function code
		call	Int10		; call Int 10h interrupt
		cmp	al,13h		; is videomode OK?
		jne	InitError	; error

; ------------- Set palettes

		call	SetPalettes	; set palettes

; ------------- Transfer picture to videomemory

		push	ds
		mov	si,[GraphOff]	; SI <- offset of graphics
		mov	ds,[GraphSeg]	; DS <- segment of graphics
		mov	ax,0a000h	; AX <- segment of videomemory
		mov	es,ax		; ES <- segment of videomemory
		xor	di,di		; DI <- offset of videomemory
		mov	cx,320*200/2	; CX <- length of picture
		cld			; direction up
		rep	movsw		; transfer picture to videomemory
		pop	ds

; ------------- Wait for a key press

		mov	ah,10h		; AH <- function code
		int	16h		; input character

; ------------- Return videomode

		mov	ah,0		; AH <- function code
		mov	al,[OldVMode]	; AL <- old video mode
		call	Int10		; call Int 10h interrupt
		jmp	short Quit	; quit the program

; ------------- Error, quit program

InitError:	mov	ah,0		; AH <- function code
		mov	al,[OldVMode]	; AL <- old video mode
		call	Int10		; call Int 10h interrupt

; ------------- No VGA, display error message

		mov	si,ErrorNoVGA	; error text - cannot find VGA card
		call	DispText	; display error message

; ------------- Wait for a key press

		mov	ah,10h		; AH <- function code
		int	16h		; input character

; ------------- End program/Repeat booting
Quit:
%ifdef	DOS
		mov	ax,4C00h
		int	21h
%else
		int	19h		; repeat booting
%endif

; ----------------------------------------------------------------------------
;                              Set palettes
; ----------------------------------------------------------------------------

; ------------- Push registers

SetPalettes:	push	ax		; push AX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	ds		; push DS
		cli			; disable interrupt

; ------------- Address of palettes

		mov	si,[GraphOff]	; SI <- offset of graphics
		sub	si,BMPPalSize	; SI <- offset of palettes
		mov	ds,[GraphSeg]	; DS <- segment of graphics

; ------------- Set palette pointer

		mov	dx,3c8h		; DX <- palette pointer register
		mov	al,0		; AL <- first palette register
		out	dx,al		; set first palette register to 0

; ------------- Set palettes

		cld			; direction up
		inc	dx		; DX <- palette registers
		mov	cx,BMPPal	; CX <- number of palettes
SetPal2:	mov	al,[si+2]	; AL <- load RED from DS:SI+2
		shr	al,1		; AL / 2
		shr	al,1		; AL / 4
		out	dx,al		; set RED color component
                mov	al,[si+1]	; AL <- load GREEN from DS:SI+1
		shr	al,1		; AL / 2
		shr	al,1		; AL / 4
		out	dx,al		; set GREEN color component
		lodsb			; AL <- load BLUE from DS:SI
		shr	al,1		; AL / 2
		shr	al,1		; AL / 4
		out	dx,al		; set BLUE color component
		add	si,3		; shift to next palette
		loop	SetPal2		; set next palette

; ------------- Pop registers

		sti			; enable interrupt
		pop	ds		; pop DS
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                           Display text with BIOS
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = error message ASCIIZ (ends with zero)
; ----------------------------------------------------------------------------

DispText:	push	ax		; push AX
		push	si		; push SI
		cld			; set direction up
DispText2:	lodsb			; AL <- load next character from DS:SI
		or	al,al		; AL == 0? is it end of text?
		jz	DispText3	; it is end of text
		call	DispChar	; display character in AL
		jmp	short DispText2	; next character
DispText3:	pop	si		; pop SI
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                        Display one character with BIOS
; ----------------------------------------------------------------------------
; INPUT:	AL = character to display
; ----------------------------------------------------------------------------

DispChar:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		mov	ah,0eh		; AH <- 0Eh function code
		mov	bx,7		; BL <- color of text, BH <- page 0
		call	Int10		; call Int 10h
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                Call Int 10h interrupt with saving registers
; ----------------------------------------------------------------------------
; Notes: Some BIOSes destroy some registers, so we call it with saving them.
; ----------------------------------------------------------------------------

Int10:		pushf			; push flags
		push	si		; push SI
		push	di		; push DI
		push	bp		; push BP
		push	ds		; push DS
		push	es		; push ES
		int	10h		; call INT 10h
		pop	es		; pop ES
		pop	ds		; pop DS
		pop	bp		; pop BP
		pop	di		; pop DI
		pop	si		; pop SI
		popf			; pop flags
		ret

; ----------------------------------------------------------------------------
;                                    Data
; ----------------------------------------------------------------------------

OldVMode:	db	3		; old video mode
GraphSeg:	dw	0		; segment of graphics
GraphOff:	dw	0		; offset of graphics
ErrorNoVGA:	db	"ERROR: Cannot find VGA graphics card!",13,10
		db	"       Press any key to quit...",13,10,0

		align	16
Graphics:

AllocSize	equ	(Graphics - Start) + DataSize

Program překládaný v DOS módu obsahuje na začátku strukturu o velikosti 32 bajtů simulující formát souboru EXE. Při překladu je startovací adresa na offsetu 20h, při zavádění programu do paměti je to začátek zaváděného bloku programu. Proto je inicializační segment programu nastaven v záhlaví na hodnotu -2 a offset na hodnotu 20h, čímž dojde k vykompenzování offsetu startovací adresy.

K souboru je po kompilaci přikopírován obrázek s grafikou. Tato pozice je v programu označena návěštím "Graphics:", které označuje konec programu zarovnaného na 16 bajtů.

Konstanta AllocSize vyčísluje výslednou velikost programu (bez EXE záhlaví) včetně připojeného grafického souboru. Tato hodnota je použita v záhlaví EXE programu k výpočtu počtu 512-bajtových stránek programu a počtu bajtů v poslední 512-bajtové stránce programu. Dále je v záhlaví EXE pomocí této hodnoty vypočítána hodnota segmentu zásobníku tak, aby zásobník ležel těsně za programem s obrázkem.

Po startu programu je vypočítána a uschována adresa obrázku v paměti. Poté je uschován aktuální videomód a inicializován videomód VGA 320x200/256. Novým dotazem na aktuální videomód je provedeno ověření, zda se podařilo VGA videomód správně inicializovat. Pokud ano, provede se nastavení palet.

Při nastavení palet funkcí SetPalettes se použije tabulka palet obsažená v záhlaví BMP obrázku. Je pevně předpokládáno, že obrázek obsahuje 256 palet. Nastavení palet se provádí postupným načítáním palet ze záhlaví obrázku a nastavováním příslušných paletových registrů grafické karty VGA.

Po nastavení palet se provede kopie dat obrázku do videopaměti a tím jeho zobrazení. Velikost obrázku je 320x200 = 64000, kopie se proto provede jednou instrukcí pro přesun. Po zobrazení obrázku program čeká na stisk klávesy a poté navrátí původní videomód a ukončí se (nebo v BOOT módu pokračuje opakováním zavádění systému).

Po překladu program zkuste spustit jako EXE a také pomocí programu INSTALL.COM vyzkoušejte správnou funkci zavedení programu z diskety.

Download zdrojového kódu inicializace VGA grafiky

Zpět na aplikaci VEGASLOT