computertrick wrote:Hi I am making a x86 emulator I need to clarify certain things for video memory.
First of all from my knowledge I believe video memory is handled by changing memory values not by using IO ports with in, out instructions is this correct?
Second of all does anybody know of any references, datasheets that explain how you decode this memory. I assume the memory will also be different depending on what video mode your in maybe
Thanks
I am also writing a PC emulator and I have learned a lot. I have implemented basic 80x25 text mode (3h), 320x200 256-color mode (13h) and, 320x200x4 color mode (4h) 640x480x16 color mode (12h), so I think I can post what I have learned here (and will probably open other topics from myself to explain the different things that the emulator is, well, emulating).
Now about the question. For x86 PCs and for standard VGAs, you mainly change memory values to change pixels. For different modes the way you use this memory is what changes. And to change palette colors, you use I/O ports.
As we know, the standard video region goes from 0xA0000 to 0xBFFFF. Those are 128 Kilobytes, but nowadays we can consider that all standard VGA cards have up to and exactly 256 Kilobytes, which is the maximum possible given that internally the VGA uses 18-bit addresses. More information about how it works is more complex, and needs more careful explanations, but once understood, it will be easy to explain.
Given that you will know the video base address at all times (be it 0xA0000, 0xB0000 or 0xB8000), the part of the emulator that emulates the VGA must subtract that value to the RAM address it receives so that you can be left with the raw 18-bit the VGA would use internally, and from there you figure out how to handle the different planes, according to the global configuration of the VGA registers.
Since main RAM has only 128 Kilobytes of space and the VGA memory has 256 Kilobytes as a minimum, it will maybe be better to define a separate buffer for video RAM, at least to start with something minimally useable. Then the emulator would read from/write to that mapped buffer instead of main RAM.
For VGA mode 12h 640x480x16 colors, for instance, the 256 Kilobytes is divided into 4 64-Kilobyte areas (since the VGA has 4 memory planes). To set colors, you need to enable or disable writes to those planes (
by using I/O ports, so technically you will need both memory writes and I/O writes for a lot of vital tasks), or use other tricks, like the Set/Reset register.
To implement it, in this mode the buffer would have:
0+(65536*0) == plane 0
0+(65536*1) == plane 1
0+(65536*2) == plane 2
0+(65536*3) == plane 3
The colors are of course set in the palette. But there are actually 2 palettes. The main one is the 256-color palette, which has 6 bits per component. The other palette is the 16-color palette, at the Attribute Controller registers 0 to 15. This 16-color palette is what we use in text mode and in standard VGA mode 12h 640x480x16 colors. Each color in this palette is an index that chooses from the first 64 colors of the 256-color palette.
Then, when you use the 16-color palette, in mode 12h for instance, 1 byte controls 8 contiguous pixels. The highest bit position controls the leftmost pixel, and the lowest bit controls the rightmost pixel.
We need to combine each bit from each plane so that we will have 8 4-bit indexes for 8 16-color, 4-bit pixels.
Bit 0 -- plane 0
Bit 1 -- plane 1
Bit 2 -- plane 2
Bit 3 -- plane 3
And you do that for each pixel of the byte. If all planes are enabled then the same byte is written to the 4 areas, unless you activate other functional registers of the VGA intended specifically to modify or replace the data written by the CPU.
For text mode 3h 80x25x16 colors, I might be wrong (please somebody clarify), but at least in my emulator I have plane 0 mapped to 0xB8000, then plane 1 (where the colors are), at 0x8000 bytes above that address, and plane 2 (where fonts are), at 0x8000*2 bytes above that address. Plane 3 seems not to be used in text mode 3h. Since this mode starts its memory access at 0xB8000, and because of other configuration registers (for which the VGA already has certain built-in behaviors), the planes are forced to be smaller than those of mode 12h for instance, or for most color-rich graphics modes.
For mode 3h, plane 0 (where ASCII characters are) only gets even bytes written, and plane 1 (were background/foreground/blink color and properties are) only gets odd bytes written. Probably it would have been better to implement this mode such that 2 bytes were written only to plane 0 and then interpreted accordingly. It is a little wasteful, but it seems to be how it has been implemented.
This is how I have implemented text mode 3h, but since the documentation says that it has 4 "pages" that we can scroll with an address starting register, it would be better to put each plane at least 32768 bytes apart (since each page uses 8000 bytes in planes 0 and 1).
Or maybe I will determine that I can implement it later always in 65536 planes for all video modes, but as can be seen, it isn't initially a crucial problem for an emulator, and it is reasonably easy to fix.
______________________________
For mode 13h, 320x200x256 colors, the memory, like in mode 12h, is accessed by the CPU at memory address 0xA0000 (A000:0000). But for 256-color mode, as far as the programmer is initially concerned, the memory is just a flat array of 1-byte pixels. The values of those pixels are simple indexes into the 256-color palette (0-255). Then the colors are displayed accordingly.
If you were to emulate this palette color, which has 6 bits per R, G and B component, and if you use a standard 24-bit display color format for the RGB, then you must shift 2 bits left each component to scale the smaller 18-bit color space of the standard VGA into the bigger 24-bit color space of your real hardware. Otherwise the colors will look much darker:
R8 = R6<<2;
G8 = G6<<2;
B8 = B6<<2;
Graphics video mode 4h (320x200x4 colors) starts at 0xB8000, so planes are required to be smaller (8192 bytes each, since there are 32768 bytes from 0xB8000 and 0xBFFFF), although it looks like only 1 plane was effectively used (plane 0). Here, 1 byte controls 4 pixels. Since we use 4 colors, 1 pixel requires 2 bits for its color to be defined. The 2 highest bits control the leftmost pixel, and the 2 lowest bits control the rightmost pixel.
And if you are wondering about how to implement (non-accelerated to begin with) Super VGA modes, since we are emulating the hardware, all we have to do is increase the video buffer from 256 Kilobytes to, say, some 4 Megabytes.
Then it becomes easy to implement modes like 640x480x256 colors, 640x480x16 million colors and 800x600x16 million colors.
I have seen for instance in the Raspberry PI that setting video modes doesn't involve setting as many registers as in the standard VGA, but basically request a video mode resolution.
So why not do the same by implementing a graphics controller register that, when set to a certain value, gets the Super VGA video requested from yet another register(s) from the graphics controller, which would contain the Super VGA mode number (e.g., 101h for 640x480x256 colors, and 115h for 800x600x16 million colors)?
Then most of the standard VGA registers would no longer have any effect in the Super VGA modes, except for the 256-color palette, which we would reuse and maybe make more efficient, and things like the vertical retrace so that we have a standard way to synchronize easily even under our Super VGA modes. And also keep standard registers or implement similar ones that normally are capable of turning on or off (some) monitors, to implement that easily as well.
However, a Super VGA mode requires a 32-bit addressing space and 32-bit registers and instructions (at least under Real Mode or Unreal Mode), so that we can map those 4 Megabytes or more in a higher convenient memory area (using emulated PCI configuration?) and so that we can actually be able to modify the huge on-screen bitmap without having to complicate things even more by having to bank/segment the video memory in smaller but more confusing chunks.
The particularity of this mode is that pixels in even rows start at 0xB8000, and pixels in odd rows start 8192 bytes above (0xB8000+8192). This way of using memory seems to be as wasteful as that of text mode, since we would only be using 4096 bytes from the two 8192-byte chunks instead of using 1 full 8192-byte chunk at 0xB8000, but it seems that this is how it has always been.
Also, there are 8000 bytes visible at a time
_____________________________________________
So that you see, this is what I have been doing and what I plan to discuss and write/explain about:
Source code (public domain): Z86Emu__2013-07-03-jansflame.zip
x86 PC Emulator Test for MCGA Mode 13h (2013-07-03) for running in the latest versions of Firefox/Chrome/maybe Opera
The most recent of what I have done is this (adding basic plane support for mode 12h):
Source code (public domain): Z86Emu_v2013-07-26-10-21.zip
Test for Z86Emu_v2013-07-26-10-21for running in the latest versions of Firefox/Chrome/maybe Opera
(See the
BIOS/booting/debug/Blob_Image.bin file and subdirectories with assembly sources to see what is being run).
Now please let me know what else you would like to know about what is being done or about your original or further questions.