|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Июн 28, 2003 16:51:00 · Поправил: Безпощадный даос Ну знатоки ассемблера, выручайте. Имеется програмка. Переделана с Зубкова под фасм - эффект огня через LFB. Вроде работает, и нормально, да вот есть 2 глюка: 1) ИНОГДА (1/10) происходит фигня: прога запускается не на полный экран, винда орет как угорелая что мол восстановление не возможно(на полный экран) а в это время прога спокойненько рисуе пламя прямо в винде - в смысле над рабочим столом! 2) Странный глюк переменных, для которым мы только отводим место: если они (в частности buffer - буфер для экрана) не идут последними, то занимают полный обьем. +300kb к программе как-то не хочется. Если их поместить в конец, но изначально они не пустые! т.е. в них записан какой-то хлам.(наглядно видно на экране в начале программы.) Заранее благодарен всем. Собсно прога
------------------CUT----------------
; fasm example of writing 32-bit program using DPMI
; requires DPMI host installed in system
format MZ
heap 0 ; no additional memory
segment loader use16
push cs
pop ds
mov ax,1687h
int 2Fh
or ax,ax ; DPMI installed?
jnz DPMI_error2
test bl,1 ; 32-bit programs supported?
jz DPMI_error2
mov word [mode_switch],di
mov word [mode_switch+2],es
mov bx,si ; allocate memory for DPMI data
mov ah,48h
int 21h
jc DPMI_error2
mov es,ax
mov ax,1
call far [mode_switch] ; switch to protected mode
jc DPMI_error2
mov cx,1
xor ax,ax
int 31h ; allocate descriptor for code
mov si,ax
xor ax,ax
int 31h ; allocate descriptor for data
mov di,ax
mov dx,cs
lar cx,dx
shr cx,8
or cx,0C000h
mov bx,si
mov ax,9
int 31h ; set code descriptor access rights
mov dx,ds
lar cx,dx
shr cx,8
or cx,0C000h
mov bx,di
int 31h ; set data descriptor access rights
mov ecx,main
shl ecx,4
mov dx,cx
shr ecx,16
mov ax,7 ; set descriptor base address
int 31h
mov bx,si
int 31h
mov cx,0FFFFh
mov dx,0FFFFh
mov ax,8 ; set segment limit to 4 GB
int 31h
mov bx,di
int 31h
mov ds,di
mov es,di
mov fs,di
mov gs,di
push si
push dword start
retfd
DPMI_error2: ; ошибка при выполнении одной из функций DPMI
mov ax,03h ; восстановить текстовый режим
int 10h
lea edx,[DPMI_error_msg2]
mov ah,9
int 21h ; вывести сообщение об ошибке
mov ax,4C00h ; AH = 4Ch
int 21h ; выход из программы под расширителем DOS
DPMI_error_msg2 db 'DPMI error or not installed Cant contiue$'
mode_switch dd ?
segment main use32
start:
mov ax,0100h ; функция DPMI 0100h
mov bx,100h ; размер в 16-байтных параграфах
int 31h ; выделить блок памяти ниже 1 Мб
jc DPMI_error
mov fs,dx ; FS - селектор для выделенного блока
mov dword [fs:0],'2EBV' ; сигнатура VBE2 в начало блока
mov word ptr v86_eax,4F00h ; функция VBE 00h
mov word ptr v86_es,ax ; сегмент, выделенный DPMI
mov ax,0300h ; функция DPMI 300h
mov bx,0010h ; эмуляция прерывания 10h
xor ecx,ecx
lea edi,[v86_regs]
push ds
pop es ; ES:EDI - структура v86_regs
int 31h ; получить общую информацию VBE2
jc DPMI_error
cmp byte ptr v86_eax,4Fh ; проверка поддержки VBE
jne VBE_error
movzx ebp,word [fs:18] ; объем SVGA-памяти в EBP
shl ebp,6
mov word ptr v86_eax,4F01h ; номер функции INT 10h
mov word ptr v86_ecx,101h ; режим 101h - 640x480x256
; ES:EDI те же самые
mov ax,0300h ; функция DPMI 300h - эмуляция прерывания
mov bx,0010h ; INT 10h
xor ecx,ecx
int 31h ; получить данные о режиме
jc DPMI_error
cmp byte ptr v86_eax,4Fh
jne VBE_error
test byte [fs:0],80h ; бит 7 байта атрибутов = 1 - LFB есть
jz LFB_error
mov eax,ebp ; видеопамять в килобайтах
shl eax,10 ; теперь в байтах
dec eax ; лимит = размер - 1
shr eax,12 ; лимит в 4-килобайтных единицах
mov word ptr videodsc+0,ax ; записать биты 15 - 0 лимита
shr eax,8
and ah,0Fh
or byte ptr videodsc+6,ah ; и биты 19 - 16 лимита
mov eax,ebp ; видеопамять в килобайтах
shl eax,10 ; в байтах
mov edx,dword [fs:40] ; физический адрес LFB
mov cx,dx
shld ebx,edx,16 ; поместить его в CX:DX,
mov di,ax
shld eax,eax,16 ; а размер - в SI:DI
mov esi,eax
mov ax,800h ; и вызвать функцию DPMI 0800h
int 31h ; отобразить физический адрес в линейный
jc DPMI_error
shrd edx,ebx,16 ; перенести полученный линейный адрес
mov dx,cx ; из BS:CX в EDX
mov word ptr videodsc+2,dx ; и записать биты 15 - 0 базы
shr edx,16
mov byte ptr videodsc+4,dl ; биты 23 - 16
mov byte ptr videodsc+7,dh ; и биты 31 - 24
mov bx,cs
lar cx,bx ; прочитать права нашего сегмента
and cx,6000h ; и перенести биты DPL
or byte ptr videodsc+5,ch ; в строящийся дескриптор
mov cx,1 ; получить один новый дескриптор
mov ax,0 ; у DPMI
int 31h
jc DPMI_error
mov word ptr videosel,ax ; записать его селектор
push ds
pop es
lea ebx,[videodsc] ; ES:EDI - адрес нашего дескриптора
mov edi,ebx
mov bx,ax ; BX - выданный нам селектор
mov ax,0Ch ; функция DPMI 0Ch
int 31h ; загрузить дескриптор в LDT
jc DPMI_error ; теперь в videosel лежит селектор на LFB
mov word ptr v86_eax,4F02h ; 4F02h - установить SVGA-режим
mov word ptr v86_ebx,4101h ; режим 4101h = 101h + LFB
lea eax,[v86_regs] ; ES:EDI - структура v86_regs
mov edi,eax
mov ax,0300h ; функция DPMI 300h
mov bx,0010h ; эмуляция прерывания 10h
xor ecx,ecx
int 31h
mov ax,word ptr videosel ; AX - наш селектор
enter_flame: ; сюда придет управление с селектором в ax на A000h:0000,
; если произошла ошибка в любой VBE-функции
mov es,ax ; ES - селектор видеопамяти или LFB
; отсюда начинается процедура генерации пламени
; генерация палитры для пламени
xor edi,edi ; начать писать палитру с адреса ES:0000
xor ecx,ecx
palette_gen:
xor eax,eax ; цвета начинаются с 0, 0, 0
mov cl,63 ; число значений для одной компоненты
palette_l1:
stosb ; записать байт
inc eax ; увеличить компоненту
cmpsw ; пропустить два байта
loop palette_l1 ; и так 64 раза
push edi
mov cl,192
palette_l2:
stosw ; записать два байта
inc di ; и пропустить один
loop palette_l2 ; и так 192 раза (до конца палитры)
pop edi ; восстановить EDI
inc di
jns palette_gen
; палитра сгенерирована, записать ее в регистры VGA DAC
mov al,0 ; начать с регистра 0
mov dx,03C8h ; индексный регистр на запись
out dx,al
push es
push ds ; поменять местами ES и DS
pop es
pop ds
xor esi,esi
mov ecx,256*3 ; писать все 256 регистров
mov edx,03C9h ; в порт данных VGA DAC
rep outsb
push es
push ds ; поменять местами ES и DS
pop es
pop ds
; основной цикл - анимация пламени, пока не будет нажата любая клавиша,
xor edx,edx ; должен быть равен нулю
mov ebp,1111h ; любое число
mov ecx,scr_width ; ширина экрана
main_loop:
push es ; сохранить ES
push ds
pop es ; ES = DS - мы работаем только с буфером
; анимация пламени (классический алгоритм)
inc ecx
lea edi,[buffer]
mov ebx,dword ptr scr_height
shr ebx,1
dec ebx
mov esi,[scr_width]
animate_flame:
mov ax,[edi+esi*2-1] ; вычислить среднее значение цвета
add al,ah ; в данной точке (EDI) из значений
setc ah ; цвета в точке слева и на две строки
;mov dl,[edi+esi*2+1] ; вниз, справа и на две строки вниз
add ax,dx
mov dl,[edi+esi*4] ; и на четыре строки вниз,
add ax,dx ; причем первое значение
shr ax,2 ; модифицировать
jz already_zero ; уменьшить яркость цвета
dec ax
already_zero:
stosb ; записать новый цвет в буфер
add eax,edx
shr eax,1
mov byte [edi+esi-1],al
loop animate_flame
mov ecx,esi
add edi,ecx
dec ebx
jnz animate_flame
; псевдослучайная полоска внизу экрана, которая служит генератором пламени
generator_bar:
xadd bp,ax
stosw
stosw
loop generator_bar
pop es ; восстановить ES для вывода на экран
; вывод пламени на экран
; ES:EDI - LFB
push esi
xor edi,edi
lea ecx,[buffer] ; DS:ESI - буфер
add esi,ecx
mov ecx,dword [scr_size] ; размер буфера в двойных словах
sub ecx,640*2
rep movsd ; скопировать буфер на экран
pop esi
mov ah,1 ; если не была нажата
int 16h ; никакая клавиша,
jz main_loop ; продолжить основной цикл,
mov ah,0 ; иначе -
int 16h ; считать эту клавишу
exit_all:
mov ax,03h ; восстановить текстовый режим
int 10h
mov ax,4C00h ; AH = 4Ch
int 21h ; выход из программы под расширителем DOS
; различные обработчики ошибок
DPMI_error: ; ошибка при выполнении одной из функций DPMI
lea edx,[DPMI_error_msg]
mov ah,9
int 21h ; вывести сообщение об ошибке
jmp near exit_all ; и выйти
VBE_error: ; не поддерживается VBE
lea edx,[VBE_error_msg]
mov ah,9
int 21h ; вывести сообщение об ошибке
jmp near start_with_vga2 ; и использовать VGA
LFB_error: ; не поддерживается LFB
lea edx,[LFB_error_msg]
mov ah,9 ; вывести сообщение об ошибке
int 21h
start_with_vga2:
mov ah,0 ; подождать нажатия любой клавиши
int 16h
mov ax,13h ; переключиться в видеорежим 13h
int 10h ; 320x200x256
mov ax,2 ; функция DPMI 0002h
mov bx,0A000h ; построить дескриптор для реального
int 31h ; сегмента
mov dword ptr scr_width,320 ; установить параметры
mov dword ptr scr_height,200 ; режима
mov dword ptr scr_size,320*200/4
jmp enter_flame ; и перейти к пламени
; .data
; различные сообщения об ошибках
VBE_error_msg db 'VBE 2.0 error',0Dh,0Ah
db 'Will use VGA 320x200 mode'
db 0Dh,0Ah,'$'
DPMI_error_msg db 'DPMI error$'
LFB_error_msg db 'Linear Framebuffer not '
db 'availiable',0Dh,0Ah
db 'Will use VGA 320x200 mode'
db 0Dh,0Ah,'$'
; параметры видеорежима
scr_width dd 640
scr_height dd 480
scr_size dd 640*480/4
; структура, используемая функцией DPMI 0300h
label v86_regs
v86_edi rd 1
v86_esi rd 1
v86_ebp rd 1
v86_res rd 1
v86_ebx rd 1
v86_edx rd 1
v86_ecx rd 1
v86_eax rd 1
v86_flags rw 1
v86_es rw 1
v86_ds rw 1
v86_fs rw 1
v86_gs rw 1
v86_ip rw 1
v86_cs rw 1
v86_sp rw 1
v86_ss rw 1
; дескриптор сегмента, соответствующего LFB
videodsc dw 0 ; биты 15 - 0 лимита
dw 0 ; биты 15 - 0 базы
db 0 ; биты 16 - 23 базы
db 10010010b ; доступ
db 10000000b ; биты 16 - 19 лимита и другие биты
db 0 ; биты 24 - 31 базы
; селектор сегмента, описывающего LFB
videosel dw 0
;; буфер для экрана
hello db 'Hello from protected mode!',0Dh,0Ah,0
MemDesk dw 0
buffer rb 640*480
;wMemDesk dw 0
------------------CUT----------------
|
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.089 |