joncampbell123 / dosbox-x

DOSBox-X fork of the DOSBox project
GNU General Public License v2.0
2.53k stars 369 forks source link

EGA VPTable provides wrong register values #5046

Closed MrMadguy64 closed 1 week ago

MrMadguy64 commented 2 weeks ago

Describe the bug

I'm not sure about other values, but CRTC MCR value for mode 0x10 is definitely wrong. MCR values for other modes also don't look good. All I try - is to modify bit 7 and write value back to register. Here is result. Bug Overall rule - VPTable should be used to program registers on real hardware. So, application can be sure, that default register values are exactly the same, as ones stored in VPTable. But it isn't true for DOSBox. Yeah, it doesn't matter, what values things like blanking and sync pulses have. But at least control registers should have proper values.

It's needed for two purposes: 1) To overcome write-only nature of almost all registers on EGA 2) To provide mode modification functionality, similar to Int 1Dh for CGA/MDA. And as DOSBox doesn't take timings from VPTable - any application, that relies on this feature would fail to work.

Steps to reproduce the behaviour

New version of my program is still work in progress, so: 1) Set machine=ega 2) Switch to mode 0x10 3) Draw something on screen 4) Read env table address from 0040:00A8 5) Video parameters table address is first 4 bytes of env table 6) Choose table entry for mode 0x10 (>64Kb VRAM) - it's №18, size of every entry is 64 bytes , MCR offset is 33, so offset should be 0x04A1. 7) Write CTRC MCR value to corresponding CRTC port - imagine, that we want to modify it and then write back 8) See what happens

P.S. New version of my program is released - you can reproduce this problem via selecting 320x350x4 mode for EGA.drv. Behavior has changed for 640x350x4 mode! Standard mode should stay standard!

Expected behavior

No bug

What operating system(s) this bug have occurred on?

Windows

What version(s) of DOSBox-X have this bug?

Current

Used configuration

No response

Output log

No response

Additional information

No response

Have you checked that no similar bug report(s) exist?

Code of Conduct & Contributing Guidelines

joncampbell123 commented 2 weeks ago

I managed to find an IBM EGA card on eBay. If I plug it in and dump what the actual table looks like and implement that in DOSBox-X maybe that will help.

Alternatively a quicker way might be to take the table from the EGA BIOS listing: https://ibmmuseum.com/Adapters/Video/EGA/IBM_EGA_Manual.pdf

MrMadguy64 commented 2 weeks ago

Ehh. You've answered before I could edit my initial post.

There are more problems with DOSBox: 1) I'm not sure, if it would be good idea to just dump real IBM EGA registers, as DOSBox's EGA isn't real EGA - it's more like "EGA on VGA". VGA uses different pixel clocks for example. Via using IBM EGA register values you would fix CRTC MCR, but break MOR instead. Be very careful! It actually doesn't matter, what values VPTable would have and would they be real EGA ones or not. Only rule - they should match ones, that are actually programmed to registers. So, easy solution - just dump all DOSBox registers for all EGA modes and put their values to VPTable. 2) DOSBox doesn't emulate Int 1Dh behavior for VPTable. My application uses direct CRTC reprogramming as workaround, but real software can rely on this feature, cuz it would allow it to avoid extra overhead. I don't know any such software though.

MrMadguy64 commented 2 weeks ago

And also. You can use my program for testing. It falls back to IBM EGA VPTable, if 0040:00A8 = 0000:0000 or VPTable = 0000:0000 or first byte of VPTable entry is 0 (number of cols, if I remember correctly). It doesn't use all registers though. Only ones, it needs to change.

MrMadguy64 commented 2 weeks ago

I've forgotten, that 640x350 mode behavior has changed in latest version of my program. No registers are reprogrammed for standard modes exactly to avoid such problems. Standard modes should stay standard. Use 320x350 mode instead. Don't forget to set compatibility filter to "Standard timings", if you would disable VPTable in DOSBox. Garbled screen in case of unsupported mode - is HX problem. Not DOSBox or my program's problem.

joncampbell123 commented 1 week ago

It's very important for egaonly to emulate the EGA as best as possible, including register values set according to the official EGA VP table.

That's why it was just as important to find an actual EGA card on eBay as well, to confirm behavior.

I think the issue here is that you're trying to program the EGA into the poorly documented 640x350 4-color mode, which is the only way 640x350 can be done on EGA cards that only have 64KB of RAM.

As I understand it, if the planar memory layout were as straightforward as normal 640x350 16-color mode, each bitplane would still take too much memory (28KB which is >= 16KB per bitplane) even for just two bitplanes in the 4-color mode. When I tried to add support for it, I figured it must involve something with odd/even mode to "fold" the two 28KB bitplanes across four 14KB bitplanes, but I wasn't successful at it.

Looking at the VPTable published by IBM, the registers confirm the odd/even mode. Not much uses the 4-color mode but I do think it might be nice for DOSBox-X to emulate it just the same.

rderooy commented 1 week ago

Early Windows 1.0x versions had several EGA display options, perhaps one of them corresponds to this mode. e.g. for Windows 1.04 (not the special IBM OEM release, as that changes a bunch of options): image

Likewise for Windows 2.x (depending on exact version): image

joncampbell123 commented 1 week ago

I just added fresh code to correct the incorrect rendering of EGA 16-color odd/even mode, especially 640x350 4-color mode as well as a few other things related to it.

Are you able to compile the latest commit or perhaps eventually use the latest nightly build?

MrMadguy64 commented 1 week ago

I think the issue here is that you're trying to program the EGA into the poorly documented 640x350 4-color mode, which is the only way 640x350 can be done on EGA cards that only have 64KB of RAM.

Why do you think, I do? I don't do it. If I would - I wouldn't see any picture at all. Why? Because EGA VPTable has two copies of mode 10h. One for <64Kb and one for >64Kb. <64Kb one has all 0 in DOSBox VPTable. Trying to use it wouldn't give anything. Problem is caused by >64Kb mode in EGA VPTable having wrong values. Some mix of 320x200 and 640x350 ones.

My symptoms are: If I use DOSBox VPTable - I have problem. If I hardcode BIOS VPTable to return nullptr and use standard EGA VPTable instead - no problems.

And again. It doesn't matter, if VPTable values are real or not. They should match ones programmed to registers, so application would be able to modify them without messing things up. They exist for 2 purposes: 1) To overcome "read-only" problem 2) To be able to override standard VPTable with one with modified values. Similar to how Int 1Dh works. And DOSBox doesn't even emulate proper Int 1Dh-like behavior now. If it would - you would notice problem much earlier. For now VPTable is just dummy info. In order to provide proper behavior, you actually need to do following thing - instead of programming values directly to EGA registers, you need to store them for all modes in VPTable first. And then use VPTable ones to program register values. In this case application would be able to override VPTable the same way, it would do it for Int 1Dh.

P.S. At the end it's your choice. You can implement EGA to be emulated similarly to how MDA/CGA/etc are implemented. I.e. do, what real BIOS does. Just load values from VPTable. But for now EGA is emulated via unified int10_modes.cpp. I don't think, that real software would ever rely on VPTable having real standard EGA values. Real software would use it to determine what values are programmed to registers now in order to modify them properly. Or to combine timings from different modes to produce non-standard ones. Like 320x350 for example.

MrMadguy64 commented 1 week ago

If I'm still not clear enough. This thing on EGA serves exactly the same purpose, as this thing on MDA/CGA/etc. See this code and this one.

iamgreaser commented 1 week ago

Not much uses the 4-color mode but I do think it might be nice for DOSBox-X to emulate it just the same.

It's been a while since I've touched that code in 86Box but I do recall getting it working despite not having the hardware. Reading the schematic carefully is required in this case as the documentation lies about the high/low page select bit (or alternatively the CHIPS clone datasheet has a table... but the register description still has the same lie).

This affects both mono 64K and 4-colour 64K.

Also, for mono modes, you need a mono monitor, it's not like VGA in that regard.

I tried doing this off the top of my head but I had to look some stuff up anyway, so:

Speaking of the mono mode, you also have to deal with graphics blink mode (there's a decent chance you've done this already but this part can be easy to miss). The best documentation of this I've seen is in SVGA chipset datasheets. The Matrox MGA-G200 specification datasheet describes this really well, and is probably how it actually works on the original chipsets:

And after some quick testing with 86Box (which uses the actual video BIOS image), the default palette for 4-colour 640x350 mode is the high-intensity black-cyan-magenta-white CGA palette. GW-BASIC SCREEN 9 makes checking for this case easy... EDIT: MrMadguy64 confirms this is incorrect, GW-BASIC changes the palette probably for consistency.

MrMadguy64 commented 1 week ago

Well, side-by-side comparison of <64Kb and >64Kb modes show following differences for <64K modes: 1) Shift load bit is set in seq register 0x01. <64Kb modes are only modes, that use this setting. 2) Odd/Even mode is set via seq register 0x04 3) Extended memory is disabled via seq register 0x04 4) Some things, connected to horizontal display enable and retrace skews/delays happen. It's hard to understand them. They're different for different modes. For example text modes have different values, than graphic ones. 5) Display enable skew = 0 instead of 1. 6) Start horizontal retrace happens 2 cycles earlier 7) Odd start address is selected. Only <64Kb modes use this option by default. 8) Horizontal retrace delay is set to 1. Only 640x350 text modes also have this value >0. 9) Horizontal retrace end is 0x1A instead of 0x00. 10) Offset is 1/2, cuz we switch to word mode 11) Count by two is enabled. Only <64Kb modes use this option. 12) Word mode is selected. Used in text and CGA graphic modes. 13) Address wrap is switched to MA0 = MA13 mode. Only <64Kb modes use this option. 14) Odd/Even mode is set in graphic controller. Used in text and CGA graphic modes. 15) Chain odd maps to even mode is enabled. Set for Odd/Even modes. 16) Enable only planes 0 and 2 in attr controller

And default palette isn't CGA one. It's 0, 1, 4, 7. So, BASIC loads it's own most likely.

iamgreaser commented 1 week ago

...right, I assumed GW-BASIC would use the BIOS palette. Yeah that seems like the actual palette from having read the mode tables in the manual.

And a quick test in DEBUG with the same 86Box settings + disk does confirm that it is the palette.

joncampbell123 commented 1 week ago

In the latest commit, I copied the VP table verbatim from IBM EGA and VGA BIOS images.

I also added support for INT 10h to use the VP table when called to set standard EGA/VGA video modes.

MrMadguy64 commented 1 week ago

Nice! Can't wait to test it. I hope, we won't break anything else.

joncampbell123 commented 1 week ago

Nice! Can't wait to test it. I hope, we won't break anything else.

It should be part of the latest nightly build: https://github.com/joncampbell123/dosbox-x/actions

MrMadguy64 commented 1 week ago

It should be part of the latest nightly build: https://github.com/joncampbell123/dosbox-x/actions

Yeah. ~Unfortunately I don't have time to test everything and check how things are implemented right now. But I have immediate problem: everything works as expected in 320x350x4 mode, but exactly the same problem as before persists in 320x350x1 mode. It's strange, because 320x350x1 is based on 320x350x4, i.e. it's not mono mode, that would have different timings, like 18Khz hsync. All I do - mask unused planes and load different palette. Nothing else.~

It was completely my fault - 1bpp implementation wasn't completed, so everything is actually ok.

But. If you wonder about VPTable entries marked as "(FIXME: Again? Why?)" - they aren't actually graphic modes. They're text modes. They're VGA-specific mode 0/1, mode 2/3 and mode 7 - modes with VGA 8x16 font enabled. I.e. VGA VPTable actually has 3 different text mode variants: CGA 8x8, EGA 8x14 and VGA 8x16. And on VGA you should use 8x16. I.e. this code is wrong!

joncampbell123 commented 1 week ago

It should be part of the latest nightly build: https://github.com/joncampbell123/dosbox-x/actions

Yeah. ~Unfortunately I don't have time to test everything and check how things are implemented right now. But I have immediate problem: everything works as expected in 320x350x4 mode, but exactly the same problem as before persists in 320x350x1 mode. It's strange, because 320x350x1 is based on 320x350x4, i.e. it's not mono mode, that would have different timings, like 18Khz hsync. All I do - mask unused planes and load different palette. Nothing else.~

It was completely my fault - 1bpp implementation wasn't completed, so everything is actually ok.

But. If you wonder about VPTable entries marked as "(FIXME: Again? Why?)" - they aren't actually graphic modes. They're text modes. They're VGA-specific mode 0/1, mode 2/3 and mode 7 - modes with VGA 8x16 font enabled. I.e. VGA VPTable actually has 3 different text mode variants: CGA 8x8, EGA 8x14 and VGA 8x16. And on VGA you should use 8x16. I.e. this code is wrong!

It should be part of the latest nightly build: https://github.com/joncampbell123/dosbox-x/actions

Yeah. ~Unfortunately I don't have time to test everything and check how things are implemented right now. But I have immediate problem: everything works as expected in 320x350x4 mode, but exactly the same problem as before persists in 320x350x1 mode. It's strange, because 320x350x1 is based on 320x350x4, i.e. it's not mono mode, that would have different timings, like 18Khz hsync. All I do - mask unused planes and load different palette. Nothing else.~

It was completely my fault - 1bpp implementation wasn't completed, so everything is actually ok.

But. If you wonder about VPTable entries marked as "(FIXME: Again? Why?)" - they aren't actually graphic modes. They're text modes. They're VGA-specific mode 0/1, mode 2/3 and mode 7 - modes with VGA 8x16 font enabled. I.e. VGA VPTable actually has 3 different text mode variants: CGA 8x8, EGA 8x14 and VGA 8x16. And on VGA you should use 8x16. I.e. this code is wrong!

I see. I'll correct the code.

joncampbell123 commented 1 week ago

Ah, looking at the 3 entries I marked, they're clearly modes 0 and 1, modes 2 and 3, and mode 7 VGA style. They're combined because color/mono doesn't matter anymore on VGA hardware. There's no colorburst to enable/disable. The 3rd is clearly mode 7 because in the attribute controller section you can clearly see a monochrome palette mapping (a lot of 0x08, 0x18, etc)

joncampbell123 commented 1 week ago

While I'm at it, I could also copy down this table for machine=cga and machine=mda: https://github.com/philspil66/IBM-PC-BIOS/blob/main/PCBIOSV3.ASM#L3523

http://www.ctyme.com/intr/rb-2444.htm