VOGONS


First post, by Battler

User metadata
Rank Member
Rank
Member

How do I calculate it correctly? I know that I have to AND it with the mask that depends on GDC register 6 bits 7 and 6, so let's say I have 64k at A000 set, that means I have to do:

address &= 0xffff

Then, assuming this is not chain 2 or chain 4, I have to do:

address <<= 2

But what next? I know I have to somehow take readplane into account, but what is correct? This:

address |= readplane

Or this:

address += readplane

? How exactly is this implemented in the circuitry of a real card?

Reply 1 of 7, by superfury

User metadata
Rank l33t++
Rank
l33t++

It all depends on the read mode, mode 0 or mode 1. Mode 0 will read only one plane(as specified), but mode 1 will read all 4 planes simultaneously(the whole dword), comparing against the color value and giving a set bit if matched, cleared otherwise.

That's one of the things that should accurately be implemented in UniPCemu: https://bitbucket.org/superfury/unipcemu/src/ … e/vga/vga_mmu.c
It starts at line 433 (VGAmemIO_rb function call).

That should roughly be how real hardware implements it more or less. It's all based on a simple mask for the four planes, then handled according to real/write mode.

And yes, (planar address<<2)|plane is the physical location in VRAM of a planar address. The 'planar address' specifying a dword address in VRAM, while the plane is the byte specified inside said dword.

Readplane isn't directly applied like the register's value. Instead, it(like the writing process afaik) is a mask containing 4 bits for all the planes to be read. And the plane selected is simply the lowest bit(bit 0 for plane 0, bit 1 for plane 1, bit 2 for plane 2, bit 3 for plane 3) that's set to select a plane(read map register).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 2 of 7, by Battler

User metadata
Rank Member
Rank
Member

I think you're the only one who has implemented read mode 1 somewhat correctly, though I notice that VGADOC's VGAREGS.TXT says this:

3CEh index  2  (R/W):  Graphics: Color Compare Register
bit 0-3 In Read Mode 1 each pixel at the address of the byte read is compared
to this color and the corresponding bit in the output set to 1 if
they match, 0 if not. The Color Don't Care Register (3CEh index 7)
can exclude bitplanes from the comparison.

How exactly does this work? Your emulator compares the data read from the plane with the lower 4 bits of color compare, but is that correct? It looks to me like it should compare both nibbles of a plane to the same color and set the resulting bit to 1 only if both match.

Reply 3 of 7, by superfury

User metadata
Rank l33t++
Rank
l33t++

Hmmm... https://www.phatcode.net/res/224/files/html/ch28/28-03.html

That seems to imply an even different scheme?

Edit: http://www.osdever.net/FreeVGA/vga/vgamem.htm

That seems to imply a comparision in 1-bit mode against all 4 planes(16-color mode)?
Edit: So it's a planar shift mode-style comparison(see http://www.osdever.net/FreeVGA/vga/vgaseq.htm, http://www.osdever.net/FreeVGA/vga/seqplanr.gif to be exact)?

Edit: So perhaps Dosbox IS correct in one case(planar shift-style version as far as I can see)?

VGA_Latch templatch;
148 templatch.d=(vga.latch.d & FillTable[vga.config.color_dont_care]) ^ FillTable[vga.config.color_compare & vga.config.color_dont_care];
149 return (Bit8u)~(templatch.b[0] | templatch.b[1] | templatch.b[2] | templatch.b[3]);

Edit: Just implemented that in UniPCemu's VGA emulation: https://bitbucket.org/superfury/unipcemu/src/ … e/vga/vga_mmu.c
Edit: Thinking about it, planar addresses should be correct that way, seeing as the write modes also aren't affected by the different rendering modes(which dosbox seems to incorrectly do, seeing as it's read mode 1 isn't performed properly (at all!) in e.g. unchained mode?). The write modes and read modes are clearly based on the methods of planar memory. It's just that the plane selection and offset generation my Memory window Address is done according to the selected mode(the step after the CGA/MDA offset wrapping being applied).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 4 of 7, by Battler

User metadata
Rank Member
Rank
Member

From how I understood (and as of this morning's 86Box commit, implemented!) read mode 1, it does 8 pixels one by one, and for each pixel, compares each bit (which is on a separate plane) with the corresponding plane's bit in the color compare register, and if its corresponding bit in the color don't care register is set, and the compared bits do match, clears the pixel's bit in the returned value (the starting value is 0xff).

Unchained mode is the planar mode, the default mode. The two chained modes are chain 2 (odd/even) and chain 4. And it is a very good question about what happens in those modes, especially if the decoded address is not 4 byte aligned. This is where my question about whether it should be and or or is relevant again.

And it gets even worse in the Cirrus Logic BY8 addressing mode which is like the default unchained mode, but each byte corresponds to 8 bytes rather than 4 - I'm not even sure if it extends all the plane and mask registers, or uses the lower 4 bits for the upper planes as well, or what. The documentation is rather vague on that.

Reply 5 of 7, by superfury

User metadata
Rank l33t++
Rank
l33t++

So, what Dosbox (and UniPCemu now too) does is:
- Take the don't care planes from the latch(where don't care is set). This leaves the latches' planes set for the don't care bits.
- Take the color compare planes to compare(where don't care is set). This generates the color compare planes' comparison bits for the don't care of a plane when set, Clearing color_dont_care will cause the result to always be 0 for said plane, causing the resulting bit to be set to 1. Setting it, on the other hand, makes it compare the latch against the color compare. When it isn't equal, the result will (because of the final bit flip) become cleared. Otherwise, the result will become 1 for said bit.
Then, it's when any of the four planes don't match or the color compare for such a plane is cleared, but otherwise it's set?

So that would make both our implementations correct now?

And indeed, the only remaining thing is to know how the non-planar modes handle it.

I suspect that UniPCemu's ways of doing it is the correct one now. Since the read and write modes seem unaffected by the access method(odd/even vs chain-4 vs planar), said plane/offset generation must be in a seperated part of logic from the read/write modes themselves.
I can also in not a single documentation see that the two are having any effect on each other. The plane/offset generation is documented. The plane/offset using read/write modes are documented. So it only makes sense that the two are fully seperated parts on the (S)VGA chip, their modes having no direct effect on the other(e.g. 256 color shift(as Dosbox implements it) having not a single direct effect on the read/write mode transformation).

The whole process is likely about the same way UniPCemu implements it. The MA is converted to a plane and a memory address, according to the offset transformation setting(odd/even, planar or chain-4). The next step is taking the generated planes and offset and transforms it onto/from VRAM using the selected read/write mode.

So, what Dosbox does(handling read modes/write modes different in Chain 4 vs odd/even vs planar modes) is incorrect. The two-step translation(1. MA -> plane&offset, 2. plane&offset=>VRAM/latch) is very likely the way a VGA card also handles it. Although maybe intergrated on a single chip nowadays, and perhaps seperated on die on the VGA chips itself.

Your thoughts?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 6 of 7, by Battler

User metadata
Rank Member
Rank
Member

Whatever plane has its bit clear in the colour no care register, will be always assumed to match even if it does not, so if all 4 planes are clear in that register, then you will read a 0xFF as everything will be assumed to match.

But yeah, aside from that, your implementation is correct now.

Reply 7 of 7, by superfury

User metadata
Rank l33t++
Rank
l33t++
Battler wrote:

Whatever plane has its bit clear in the colour no care register, will be always assumed to match even if it does not, so if all 4 planes are clear in that register, then you will read a 0xFF as everything will be assumed to match.

But yeah, aside from that, your implementation is correct now.

Yay! 😁 Another bug bits the dust! 🤣

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io