CODE segment
assume cs:CODE, ds:CODE, es:CODE, ss:CODE
.186 ; команда outsw
org 100h
Start:
mov ax, 0003h ; MODE (80x25) его будем менять
int 10h
mov dx, 03CCh ; регистр вывода на чтение
in al, dx
mov dx, 03C2h ; регистр вывода на запись
or al, 00C0h ; установить полярность 1, 1 для 480 строк
out dx, al
mov dx, 03D4h ; порт CRT
mov si, offset Crt480 ; DS:SI адресс таблицы данных для CRT
mov cx, nCrt480_l ; её длинна
rep outsw ; 03D4h - 03D5h порты
push 0040h
pop es ; BIOS rewrite
mov byte ptr es:[84h], 29 ; 0040:0084 - число строк (тута в биосе находиться информация о режиме)
ret
Crt480 dw 0C11h ; 11h - 7 бит разрешает писать в другие регистры
dw 0B06h, 3E07h, 0EA10h, 0DF12h, 0E715h, 0416h ; сами регистры
nCrt480_l = ($ - Crt480) / 2
CODE ends
end Start
ports+videomode+640x480x16+tiny - интересно...
Ассемблер изучаю недолго (неделя), предупреждаю всразу, поэтому на глупые вопросы не обращайте внимания ))
Вопрос намбер 1:
Как при помощи портов запрограммировать видеоадаптер на режим 640x480x16, без использования прерываний, низкоуровнево как только можно представить с подробным описанием, есть идеи по поводу записи в регистры CRT:
(установка режима 80x30)
Код:
но это всё на что меня хватило, притом это мы уже меняем режим, и я не в курсе можно ли устанавливать режимы с высоким разрешением, если кто то захочет разобраться вместе могу предоставить подробное описание CRT регистров.
Вопрос намбер 2 & 3:
При работе с VESA приходиться часто вызывать прерывание смены банка видеопамяти, что очень ресурсоёмко (при режиме 640x480x16 = 614400 байт если это поделить на FFFFh что составляет один сегмент то получается 10 банков!, это получается что за кадр приходится вызывать функцию 10 раз, причём процедура расчёта банка и смещения тоже получается немаленькая:
Код:
; AX - x, BX - y
; . . . . . . .
PutPixel:
push ax
xor dx, dx
mov ax, 640 * 2
mul bx
mov word ptr nLineAddr, ax
mov word ptr nLineAddr [2], dx
pop ax
shl ax, 1
add word ptr nLineAddr, ax
adc word ptr nLineAddr [2], 0
mov dx, word ptr nLineAddr [2]
cmp dx, nCurrentBank ; сравниваем с текущим банком
jne BankSwitch ; если не тот, то прыгаем на переключение
Switched:
mov di, word ptr nLineAddr
mov word ptr es:[di], 1111100000000000b ; рисуем точку 1111100000000000 - цвет (красный)
pop di
pop ax
ret
BankSwitch:
push bx
mov nCurrentBank, dx
xor bx, bx
call dword ptr [lpVbeModeInfo + 0Ch] ; вызываем ту самую функцию переключения банков, номер банка в DX,
;в lpVbeModeInfo + 0Ch содержиться сегмент:смещение кторое мы получили при вызове функции AX=4F01h прерывания int 10h (кому интересно могу выложить подробную информацию)
pop bx
jmp short Switched
; . . . . . . .
nCurrentBank dw 0
nLineAddr dw 0, 0
lpVbeModeInfo:
CODE ends
end Start
; . . . . . . .
PutPixel:
push ax
xor dx, dx
mov ax, 640 * 2
mul bx
mov word ptr nLineAddr, ax
mov word ptr nLineAddr [2], dx
pop ax
shl ax, 1
add word ptr nLineAddr, ax
adc word ptr nLineAddr [2], 0
mov dx, word ptr nLineAddr [2]
cmp dx, nCurrentBank ; сравниваем с текущим банком
jne BankSwitch ; если не тот, то прыгаем на переключение
Switched:
mov di, word ptr nLineAddr
mov word ptr es:[di], 1111100000000000b ; рисуем точку 1111100000000000 - цвет (красный)
pop di
pop ax
ret
BankSwitch:
push bx
mov nCurrentBank, dx
xor bx, bx
call dword ptr [lpVbeModeInfo + 0Ch] ; вызываем ту самую функцию переключения банков, номер банка в DX,
;в lpVbeModeInfo + 0Ch содержиться сегмент:смещение кторое мы получили при вызове функции AX=4F01h прерывания int 10h (кому интересно могу выложить подробную информацию)
pop bx
jmp short Switched
; . . . . . . .
nCurrentBank dw 0
nLineAddr dw 0, 0
lpVbeModeInfo:
CODE ends
end Start
Я намеренно не пользуюсь 32 регистрами, так как вся задумка в этом что бы использовать 16 битные, хотя если хорошо подумать... ))
Получая физический адресс LFB (Line Frame Buffer) незнаю что с ним делать ))))))))
Есть инфа как программировать LFB, но это в модели flat, где размер сегмента может достигать 4Гб, а в tiny у меня всео 64Кб, и я не могу расположить буфер вывода в сегменте данных и выводить его в LFB так как он в 10 раз больше файла ))))), причём там использовались расширения DPMI...
Есть идеи: выделить память при помощи EMS/XMS (EMS у меня почему то не заработал) размером в видео буффер (XMS выделяет память блоками по 64К, что опять вводит меня в ступор, хотя если они идут последовательно друг за другом, то проблем с сегментами не будет) и выводить в память а после всего получить физический адресс видюхи и туда его или в тот же LFB, только в этом вся загвоздка...
ИТОГ:
1. При помощи портов запрограммировать видеокарту на режим 640х480х16, и получить физический адресс...
2. Выделить динамическую память и выводить туда линейно, опять же както извратившись с 16 битной адрессации памяти
3. После завершения вывода в буффер, дождаться обратного вертикального хода луча (в это время на экран ничего не выводится) и из буффера скопировать в видеопамять.
Оооооооооййййййй )))))))))))
Всем принимающим в этом участие буду ооооооооооооооооооочень благодарен!
И ооооочень прошу отозваться всех кто располагает хоть какой нибудь информацией об этом, а то самому мне в этом разобраться будет туго.
Всем заранее большое СПАСИБО!
Не знаю зачем тебе понадобилось через порты писать, оставил бы через прерывания. Так как у тебя есть описания вот по ниму и делай. В принцапи на этом сайте есть подробное описание. Но на твое я бы взглянул. =)
Я так и не понял(запускать не стал), работает у тебя пример или нет?
По мойму ошибки в этих строчках.
Код:
mov dx, 03D4h ; порт CRT
mov si, offset Crt480 ; DS:SI адресс таблицы данных для CRT
mov cx, nCrt480_l ; её длинна
rep outsw ; 03D4h - 03D5h порты
mov si, offset Crt480 ; DS:SI адресс таблицы данных для CRT
mov cx, nCrt480_l ; её длинна
rep outsw ; 03D4h - 03D5h порты
Объясняю ошибки в порт 03D4h нужно занести номер (0,1,2...)регистр а потом в порт 03D5h данные.
03D4h -служит для выбора регистра CRxx (везде по разному обзывают регистры).
03D5h - служит для записи или четения регистра которого мы выбрали.
outsw - занисет двойное слово только вот занисет он это двойное слово в один порт (DX=03D4h). А не в в два как бы ты не хотел.
Так как у тебя стоит перфик rep то в порт 03D4h занесется CX двойных слов.
outsB - заносит байт в порт
outsW - заносит Слово в порт
outsD - заносит Двойное Слово в порт
Аналогично
out DX,AL
out DX,AX
out DX,EAX
Crt480 dw 0C11h ; 11h - 7 бит разрешает писать в другие регистры
dw 0B06h, 3E07h, 0EA10h, 0DF12h, 0E715h, 0416h ; сами регистры
Тут тоже какойто бред по крайней мере скажи от куда взял данные?
Биты принета нумировать от 0 по этому если мы установим 7 бит то число должно быть больше или равно 80h
2. Вобще мрак. Но нас же некто не остановит.
Тут уже нет стандартных портов и все вендор зависимая информация. Другими словами номера портов и регистров зависит от производителя. Так что для установки видео режима только Int .
Что касается LFB.
А нет погодь.
640х480х16бит (указывать надо, что 16 бит а не 16 цветов)
А почему бы не использовать 32 разрядные регистры тогда проблем не будет с LFB. Ну допустим я знаю, как можно загнать LFB в меньшие адресса. Но этож не удобно все равно тебе придется расчитывать сегмент и смещение.
И зачем DPMI сам переходи в защищенный режим и выводи в видео прямо по LFB адрессу.
PS Написанно грамотно. Но всетаки надо тебя отправить почитать, как правильно задовать вопросы. Как прочтешь мне расскажешь, а тоя не умею. =)
Попробуй в Нереальном режиме. Там все прерывания доступны, можно лепить COM проги и адресация 32 бит...
Но опять же если ты хочешь именно 16 бит и сегменты по 64 кб, то PM и Нереальный режим не катят.
640x480x16 бит - это уже SVGA-режим. Программирование SVGA-режимов на уровне портов различается для разных видеокарт. При использовании таких режимов допускается с помощью портов управлять лишь VGA-палитрой и определять факт выполнения сигналов вертикального и горизонтального обратного хода луча.
Я когда-то писал программы, которые использовали VESA-режимы высокого разрешения и при этом только стандартные возможности реального режима. С переключением банков было много возни, но если локализовать участки кода, где может понадобиться выполнять переключение, вызывать подпрограмму переключения банков напрямую, а не через интерфейс BIOS, и т.д. и т.п., то можно все неплохо сделать...
А может BIG REAL MODE испробовать... хоть не защищенный режим... но могет адресовать всю видеопамать и картинка 800x600x32бита... ляпота...
Допустим вот кусок кода, где использование переключения банков, урезанно до минимума (10 раз за кадр)
Код:
Fill:
pusha
mov dx, 9 ; с 9 - 0 банк
NextBank:
xor bx, bx
call dword ptr [lpVbeModeInfo + 0Ch] ; непосредственно функция смены банка в dx - номер банка, lpVbeModeInfo - определили заранее
mov cx, 8000h ; FFFFh - у нас максимальное значение сегмента, так как записываем по слову, то делим на два...
xor di, di
NextPixel:
mov word ptr es:[di], 0 ; всё черным
add di, 2
loop NextPixel
dec dx
jns NextBank
mov word ptr nCurrentBank, 0
popa
ret
pusha
mov dx, 9 ; с 9 - 0 банк
NextBank:
xor bx, bx
call dword ptr [lpVbeModeInfo + 0Ch] ; непосредственно функция смены банка в dx - номер банка, lpVbeModeInfo - определили заранее
mov cx, 8000h ; FFFFh - у нас максимальное значение сегмента, так как записываем по слову, то делим на два...
xor di, di
NextPixel:
mov word ptr es:[di], 0 ; всё черным
add di, 2
loop NextPixel
dec dx
jns NextBank
mov word ptr nCurrentBank, 0
popa
ret
Вот эта функция до не приличия, дооооооолго выводит картинку на экран (на вид fps наверное 10 - 15), если Fill засунуть в цикл, и что бы каждую новую итерацию был другой цвет, то станет всё ясно...
И как тогда с банками вообще работать? Если 640х480х16 использует всего 10 банков то 1024х768х32 уже 180 ((((
Если я что то неправильно сделал или понял объясни, пожалуйста, и если не лень то с примерами = буду очень благодарен!
И что такое нереальный режим?
И что такое нереальный режим?[/QUOTE]
"Нереальный" режим - это сленг, которым можно обозвать режимы работы процессора, кроме реального (защищенный режим, защищенный с включенной страничной транслацией)... И какая разница какую модель памяти использует компилятор??? А BIG REAL MODE - это такая фишка... типа берешь переключаешься в защищенный режим, загружаешь в один из селекторов (DS, ES, FS или GS) дескриптор, который описывает видеобуфер для SVGA режима (адрес буфера можно узнать с помощью функции VBE, где AL = 01h), потом сразу же переходишь обратно в реальный режим, а кэш дескриптора в теневой части селектора остается, и таким образом можно адресовать хоть все 4Гб адресного пространства... С помощью этой фишки можно адресовать видеопамять напрямую и не пользоваться банками (я лично обычно так и делаю, чтоб не маяться с переключением банков). Ради примера вот код подпрограммы, которая позволяет с помощью сегментного регистра gs адресовать видеопамать к примеру... :
Код:
loadselector:
cs mov word [desc_size],cx
shr ecx,16
and cl,0fh
cs and byte [desc_hi_type],0f0h
cs or byte [desc_hi_type],cl
cs mov word [desc_base],bx
shr ebx,16
cs mov byte [desc_lo_base],bl
cs mov byte [desc_hi_base],bh
xor ebx,ebx
mov bx,cs
sal ebx,4
add ebx,desc
cs mov dword [psevdo_base],ebx
cs lgdt pword [psevdo]
mov ebx,cr0
or ebx,1
cli
mov cr0,ebx
push 1000b
pop gs
and ebx,0fffffffeh
mov cr0,ebx
sti
retn
desc:
desc_void dq 0
desc_size dw 0
desc_base dw 0
desc_lo_base db 0
desc_lo_type db 10010010b
desc_hi_type db 10000000b
desc_hi_base db 0
psevdo:
psevdo_size dw 15
psevdo_base dd 0
cs mov word [desc_size],cx
shr ecx,16
and cl,0fh
cs and byte [desc_hi_type],0f0h
cs or byte [desc_hi_type],cl
cs mov word [desc_base],bx
shr ebx,16
cs mov byte [desc_lo_base],bl
cs mov byte [desc_hi_base],bh
xor ebx,ebx
mov bx,cs
sal ebx,4
add ebx,desc
cs mov dword [psevdo_base],ebx
cs lgdt pword [psevdo]
mov ebx,cr0
or ebx,1
cli
mov cr0,ebx
push 1000b
pop gs
and ebx,0fffffffeh
mov cr0,ebx
sti
retn
desc:
desc_void dq 0
desc_size dw 0
desc_base dw 0
desc_lo_base db 0
desc_lo_type db 10010010b
desc_hi_type db 10000000b
desc_hi_base db 0
psevdo:
psevdo_size dw 15
psevdo_base dd 0
Подпрограмма использует значения в регистра EBX - база участка памяти, ECX - размер участка в страницах (участках по 4096 байт), после выполнения подпрограммы GS адрезует заданный участок памяти....
Попробуй в Нереальном режиме. Там все прерывания доступны, можно лепить COM проги и адресация 32 бит...
Но опять же если ты хочешь именно 16 бит и сегменты по 64 кб, то PM и Нереальный режим не катят.[/QUOTE]
ЕПРСТ.... ты могешь объяснить что ты имел ввиду под словом "нереальный" может ты имел ввиду работать с сервером DPMI???
Насчет скорости работы скажу так: программы, в которых у меня переключались банки, очень быстро работали на 486-х и на Пентиумах. Конечно, я там видео не воспроизводил, но последовательно отображал картинки из bmp-файлов, окошки со сложным содержимым, мышка бегала по всему экрану (считай, это переключение банков в произвольном порядке) достаточно быстро и без мерцаний, без тормозов пролистывался текст, отображаемый на весь экран, причем каждый символ я декодтровал из сжатого формата и сразу отображал в видеопамяти (кто не в курсе, это считается не самым быстрым способом вывода графики) и т.д. и т.п.
Раньше у меня была матерь EP-8K3AE с процом Athlon XP 1600+, там был один небольшой глюк, при работе в реальном режиме старшие адресные линии не блокировались: загружаешь например в EDI 32 битный линейный адрес видеобуфера, а в один из сегментных регистров 0, и можно адресовать всю видеопамять в несколько мегабайт :-)
Если честно сам им никогда не пользовался.
Плюсы есть доступно все что наработанно под дос. Плюс можно задействовать все адрестное пространство памяти. А вобще я за Защищенный режим.
To Phantom-84 У тебя по 486 были мелкии разрешения и там с банками еще можно было смериться. А вобще если оптимально расходовать ресурсы, то можно и банки использовать. Хотя у меня на старой видео карте i740 на больших разрешениях переключение банков не действовало. А на одной TNT2 вообще все в раскорячку выводилось,точка 0,0 была где-то примерно 0.35,0.15(1 размер экрана ). Так я и не понял почему.
Ну вот я писал выше пример переключения банков... и результат не впечатляет, если ты это реализвавывал как то по другому, то пожалуйста объясни...
2 InfernoDiablo (плохой ник)
Спасибо, тока я мало чего понял ))
Это можно юзать под всё, или тока под дос?
NextPixel:
mov word ptr es:[di], 0 ; всё черным
add di, 2
loop NextPixel
Не проще ли будет вот так:
xor ax, ax
rep stosw
Но в принципе тормозить не должно и твое... Всего 9 переключений. И еще... ты уверен что замедляет работу именно переключение банков, а не то, что просто сама система не очень высокопроизводительная?
BIG REAL MODE можно юзать только из под ОС реального режима, т.к. в ОС защищенного режима (типа WINDOWS) защита не позволяет создавать программе дескрипторные таблицы, и переключать режимы работы процессора... если ты загрузил в теневую часть сегментного регистра соответствующий кэш дескриптора, то перезагружать этот регистр, или сохранять нельзя, т.к. кэш при перезагрузке сегментного регистра аннуляется
И, кстати, тормозит отображение не из-за того что оччееень медленно работает, а, возможно, из-за того что данные, которые ты пишешь в видеопамять, кэшируются, т.е. сначала находяться в кэш памяти и только потом попадают в оперативную....
поэтому я не думаю что проблемы в железе, а решил я так, потому что вывод в границе одного банка, выводится моментально, и мерцание то видно тоже на границах банка...
Код:
push cs
pop ds
mov eax,cr0
test al,1
jz no_V86
mov dx,offset v86_msg
err_exit:
mov ah,9
int 21h
mov ah,4Ch
int 21h
v86_msg db "Error!Bad mode in v86!$"
win_msg db "Error!Windows is runing!$"
no_V86:
mov ax,1600h
int 2Fh
test al,al
jz no_windows
mov dx,offset win_msg
jmp err_exit
no_windows:
xor eax,eax
mov ax,cs
shl eax,4
add ax,offset GDT
mov gdt_base,eax
lgdt fword ptr gdtr
cli
mov eax,cr0
or al,1
mov cr0,eax
jmp start_PM
start_PM:
mov ax,8
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov eax,cr0
and al,0FEh
mov cr0,eax
jmp exit_PM
exit_PM:
xor ax,ax
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
sti
mov ax,cs
mov ds,ax
;Вот и всё, теперь мы BIG REAL MODE
;Область данных:
GDT label byte
db 8 dup(0)
db 0FFh,0FFh,0,0,0,10010010b,11001111b,0
gdtr dw 16
gdt_base dd ?
pop ds
mov eax,cr0
test al,1
jz no_V86
mov dx,offset v86_msg
err_exit:
mov ah,9
int 21h
mov ah,4Ch
int 21h
v86_msg db "Error!Bad mode in v86!$"
win_msg db "Error!Windows is runing!$"
no_V86:
mov ax,1600h
int 2Fh
test al,al
jz no_windows
mov dx,offset win_msg
jmp err_exit
no_windows:
xor eax,eax
mov ax,cs
shl eax,4
add ax,offset GDT
mov gdt_base,eax
lgdt fword ptr gdtr
cli
mov eax,cr0
or al,1
mov cr0,eax
jmp start_PM
start_PM:
mov ax,8
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov eax,cr0
and al,0FEh
mov cr0,eax
jmp exit_PM
exit_PM:
xor ax,ax
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
sti
mov ax,cs
mov ds,ax
;Вот и всё, теперь мы BIG REAL MODE
;Область данных:
GDT label byte
db 8 dup(0)
db 0FFh,0FFh,0,0,0,10010010b,11001111b,0
gdtr dw 16
gdt_base dd ?
Вот собственно и всё... Прям как у Зубкова =)
Только он в описании дескриптора ошибся...
По поводу кэширования скажу так. При использовании "Нереального режима" используются параметры кэширования, установленные в BIOS. BIOS отлично понимает, что LFB - это не оперативная память, поэтому не кэширует соотв. участок адресного пространства. Другое дело, что по моим и не только моим предположениям при создании "Нереального режима" можно включить страничную адресацию и сделать таблицу страниц в защищенном режиме, после чего вернуться обратно в (не)реальный режим, но страничная адресация продолжит нормально работать. В этой, очень специфической ситуации, может быть и можно добиться кэширования видеопамяти, но чтобы это все вообще заработало, нужно ой как сильно постараться, поэтому мы этот вариант рассматривать не будем :)
Для тех, кто пишет свою ОСь, это обстоятельство (возможность нежелательного кэширования) следует учитывать, все же остальные с этим не столкнутся, потому что VBE писали не олени, а следовательно LFB кэшироваться не будет :)
На счте тормознутости на новых видюхах. С последними ATI-шными не сталкивался, а вот то Nvidia видюхи без дров просто вешаются особенно при такой задаче как плавная прокрутка части экрана. Так что думаю стоит опробывать код на старом железе.
Просто у меня такая, я на ней и с банками работал и прокрутку делал, имеется ввиду через int 10h. Всё вроде нормально.
Я тут подумал, что для чистоты эксперимента нужно программы запускать в DOS. Там точно функционирование ОС никак не отражается на скорости переключения банков и вывода в видеопамять. Я практически на 100% уверен в том, что запущенная в виндах программа будет осуществлять переключение банков и отображение данных значительно медленнее, чем если бы она была запущена из под чистой DOS.
Без LFB,
без 32-битных регистров,
без всего хорошего...
Использовано переключение видеобанков и и смена видеостраниц, что бы не выводил побанково ))
Посматрите плз, и скажите у кого с какой скоростью отрисовывается...
В связи с этим вопрос, как мне измерить FPS...
Без LFB,
без 32-битных регистров,
без всего хорошего...
Использовано переключение видеобанков и и смена видеостраниц, что бы не выводил побанково ))
Посматрите плз, и скажите у кого с какой скоростью отрисовывается...
В связи с этим вопрос, как мне измерить FPS...[/QUOTE]
Измерить fps, по-моему удобнее с помощью таймера. Типа такая последовательность
- Устанавливаешь таймер, который прервет работу программы через секунду
- В программе ведешь счетчик фреймов (кадров)
- Когда таймер прерывает работу программы, смотришь сколько кадров вышло, это и будет fps....
мне бы пример...
Это счетчик таймера значение переменной обновляется кажды 1193180/65536=18,2 раз в секунду, при условии что таймер никто не перепрограммировал.
Запоминаем значение в начале. Считаем число кадров. После
Число кадров делем на время которое прошло.
Это счетчик таймера значение переменной обновляется кажды 1193180/65536=18,2 раз в секунду, при условии что таймер никто не перепрограммировал.
Запоминаем значение в начале. Считаем число кадров. После
Число кадров делем на время которое прошло.[/QUOTE]
А не лучше ли перехватывать прерывания от таймера???