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
|