Přístup k fyzické paměti
-=-=-=-=-=-=-=-=-=-=-=-=-=
"Virtual" means never knowing where your next byte is coming from.
Pokud potřebujete přístup k nějaké fyzické paměti (třeba
videoram), není nic jednoduššího, než požádat DPMI, aby ji dalo
do adresovatelného prostoru Vašeho programu. Naneštěstí toto je
funkce DPMI 1.0 a vyšší a tak ji hodně DPMI serverů nepodporuje.
Proto musí začít magie.
I v protected módu existují segmenty a offsety. Segmenty jsou
tak velké (celá adresovatelná paměť), že se používá jenom jeden
segment. V DPMI ale program běží uvnitř jednoho segmentu, zatímco
fyzická paměť je v jiném segmentu. Proto lze použít segmentace pro
přístup do vnější paměti.
Segment dosu je uložen v proměne _dos_ds a existuje funkce
_farpoke* a _farpeek* které umožňují přistupovat na tyto vzdálené
ukazatele (_farpokeb přistupuje k bajtu, _farpokel k wordu atd.):
extern __inline__ void
_farpokeb(unsigned short selector,
unsigned long offset,
unsigned char value)
{
__asm__ __volatile__ ("movw %w0,%%fs\n"
" .byte 0x64 \n"
" movb %b1,(%k2)"
:
: "rm" (selector), "qi" (value), "r" (offset));
}
extern __inline__ void
_farpokew(unsigned short selector,
unsigned long offset,
unsigned short value)
{
__asm__ __volatile__ ("movw %w0,%%fs \n"
" .byte 0x64 \n"
" movw %w1,(%k2)"
:
: "rm" (selector), "ri" (value), "r" (offset));
}
Těch lze použít pro adresaci videoram asi takto:
#include <go32.h>
#include <dpmi.h>
#include <sys/farptr.h>
#define putpixel(x,y,c) _farpokeb(_dos_ds, 0xA0000 + (y)*320 + (x), (c))
To sice funguje, ale zbytečně se pokaždé nastavuje fs.
Jednodušší je ho nastavit jednou na začátku. K tomu slouží funkce
_farsetsel a _farnspoke*.
Na začátek vykresolvací smyčky dáte: _farsetsel(_dos_ds) a potom
kreslíte pomocí _farnspokeb(0xA0000 + y*320 + x, color);
Toto je asi nejčastěji používaná metoda pro přístup k paměti.
Funguje pod každým DPMI a je docela rychlá. Existují také far verze
pro kopírování paměti, takže když neco nakreslíte do framebufferu,
neni probém to potom zkopírovat do VRAM. To lze také dělat hned dvěma
způsoby:
dosmemput(doublebuffer, 320*200, videoptr);
movedata(_my_ds(), doublebuffer, _dos_ds, videoptr, sizeof(*doublebuffer))
Další metoda je zpřístupnění celé dosové paměti. To naprosto
vypne veškerou ochranu paměti a proto se to nedoporučuje. Pokud ale
potřebujete opravdu rychle no RAM, je to jedna z možností. Vypadá
to asi takto:
#include <go32.h>
#include <dpmi.h>
#include <sys/nearptr.h>
unsigned char *videoptr = (unsigned char *)0xA0000;
__djgpp_nearptr_enable();
videoptr[y*320 + x + __djgpp_conventional_base] = color;
__djgpp_nearptr_disable();
Je ještě nutné si pamatovat, že __djgpp_conventional_base je
proměná a může se měnit po každém zavolání alokace paměti.
výheň