-
Notifications
You must be signed in to change notification settings - Fork 500
Accurate EGA/VGA emulation #6190
Copy link
Copy link
Open
Labels
Description
Describe the bug
I think we need to create separate issue for this problem.
- One byte is read/written by GC from/to all 4 planes at the same time at the same address during both CPU LATCH and CRTC LATCH (read only) cycles. Writing to some planes can be masked via Map Mask SC register. This register simply disables sending RAS signal to certain planes. I.e. nothing changes. Data is still written by GC to all 4 planes at the same time at the same address, but some planes are masked, i.e. don't respond to writing operations.
- When Odd/Even mode is enabled in SC - CPU A0 bit controls, if even or odd planes are masked in addition to Map Mask register. When CPU A0 = 0, planes 1 and 3 are masked. When CPU A0 = 1, planes 0 and 2 are masked.
- When Odd/Even mode is enabled in GC Mode register - it affects reading. When CPU read operation is performed, data is read from all 4 planes at the same time. But only one byte from one of GC controllers should be sent to CPU data bus! What data is actually sent to CPU - is controlled by GC read mode (either read or compare) and Read Map register. Bits 1 and 2 of Read Map are compared to Graphic Position register to determine, which GC should respond to read operation. Bit 0 is used to select even or odd plane. In byte mode Read Map register bit 0 decides, data from which plane should be sent to CPU. In Odd/Even mode it's replaced by CPU A0 bit. In this it's CPU, that decides, if data should be read from even plane or odd, not GC.
- When Chain2 mode is enabled in GC Misc register, it affects CPU VRAM addressing. Please note. A0 that goes to SC/GC and A0 that goes to VRAM - are two different things! "Real" CPU A0 goes to SC and GC. I.e. one, taken from ISA slot. But what address actually goes to VRAM - is decided by Chain2 and Chain4 (in case of VGA) modes. Errr. Hard to explain it. CPU A0 is used to control, if even or odd planes should be read/written. But this task is accomplished by SC and GC via "masking" either even or odd planes. So, this A0 bit becomes unused for actual VRAM addressing. And as all VRAM read/write operations are always byte operations, it doesn't matter what this bit is used for - no word alignment is needed. When Chain2 mode is enabled - this VRAM A0 bit is replaced by either MOR PGSEL, CPU A16 or CPU A14 bit (if memory expansion is unavailable). I.e. it's used for Low/High page switching. It doesn't work this way in Chain4 mode. Page switching is unavailable in this case.
- CRTC is used to produce VRAM address for reading data to be shown on screen. CRTC address - is separate address. It doesn't go through all logic described above. It's send directly to VRAM during CRTC LATCH cycles, while CPU address is send during CPU LATCH cycles. Therefore in order for CRTC addressing to match CPU addressing (A0 is replaced by PGSEL/A16), CRTC should be switched to WORD mode. This mode is interesting. As address is rotated left by 1 bit, 2 is added to address every character clock and A0 is replaced by A16 (former A15). What is interesting - is when Shift2 mode is enabled for 64Kb mode. In this case some "real" (CRTC's "real", not CPU's "real") A0 is also used. It's used to divide character clocks by 2. And BYTE PAN bit selects, if this bit is preset to 0 or 1 after previous HSYNC. Problem is - this bit doesn't seem to be exposed as explicit output. How SC odd/even cycles in Shift2 mode are kept in sync with value of this bit - is big mystery. Current guess - it's done via SYNC signal. SYNC - is equivalent of horizontal Display Enable (DE). SC seems to start from even cycle, when it receives this signal. Problem is - in order to keep CRTC in sync with it, DE skew should be set to 0 and BYTE PAN is set to 1 to compensate.
- All things described above affect CPU read/writes and CPU/CRTC addressing only. But nothing above enables Odd/Even displaying mode. During CRTC LATCH mode GC reads data at CRTC address. But what GC reads - are always 4 bytes from all 4 planes. In case of VGA they're read into 32bit shift register. In case of EGA - it's 2x16bit shift registers. One into GC 1 for planes 0/1. Other into GC 2 for planes 2/3. I.e. 4bpp packed pixel isn't possible in case of EGA. Displaying mode is affected by one thing only - how data is shifted out. It's controlled by Shift2 GC bit. Overall idea - all 32 bits should be shifted out during one character clock. As 1 character clock = 8 pixels, then each pixel should be 4bpp (1bpp is emulated via setting all 4 bits to same value or via masking some planes in AC). If Shift2 is off - then 1 bit per pixel clock is shifted out from each plane. If Shift2 is on - two bits per pixel clock are shifted from each 0+1 (GC1) and 2+3 (GC2) pair. These planes are chained together.
- 64Kb modes - are special case. They're 1bpp modes, i.e. 1 bit is shifted out every pixel clock. But they're Odd/Even modes, so planes 0+1 (GC 1) and 2+3 (GC 2) are chained to double VRAM address space size. This mode requires special bits to be set. Shift2 in SC and CRTC. SC sends Shift/Load signal to GC and CRTC address is updated every other character clock. Therefore all 16 bits are shifted out from GC every 2 character clocks, not 1. It's very simple. GC shift registers are 16bit ones. So it's possible to use them as one 16bit value instead of 2x8bit. But they shouldn't be reloaded every character clock then.
- Text modes are special case. GC controls CPU reading/writing in this case, but not displaying. Displaying is performed by AC. And it has it's own hardcoded VRAM read logic. There are two CPU and CRTC addresses. Address A and address B. Address A is for planes 0/1 and address B is for planes 2/3. In case of CPU reading/writing and in Graphic mode they're exactly the same. But AC reading is different. Data reading has two stages. First character code is read at CRTC address A and stored along with row counter in special intermediate latch to form character generator address. Then this address is transferred to CRTC address B. Then AC reads attribute from address A and character generator data from address B.
As you might guess, 8bpp mode in VGA is implemented similarly to how CGA 2bpp mode is implemented in EGA. Only differences:
- There is no Chain4 bit in GC, so, I guess, Chain4 bit in SC (despite of description) sets this mode for both reading and writing. Same as Chain2, but two LSBs are used for switching between planes instead of one.
- GC has Shift256 mode (aka Shift4). 4 bits are shifted out from whole 32bit shift register every pixel clock.
- SC has Shift4 mode. S/L is sent to GC every 4th character clock.
- CRTC has DWORD and DIV4 (aka Shift4) modes. Address is updated every 4th character clock. Unfortunately on standard VGA VRAM size isn't quadrupled. Only 64Kb of VRAM are available in DWORD mode. 3rd party cards can do it.
- AC has 256 color mode, that chains two 4bpp pixels together into 8bpp one. Disabling it should allow 4bpp packed pixel mode.
Funny thing. I haven't realized it before. But there are Shift4 modes in SC and CRTC, that aren't actually used anywhere. For now I don't know any useful implication for them, except may be some sort of 1bpp Chain4 mode.
Extra info about addressing:
- Memory is 4x64Kb planes (Can be 16, 32, 48 in case of EGA). 1 byte is always read/written from/to each plane at exactly the same address - either CPU address or CRTC address. It can be seen as 65536 DWORDs.
- In BYTE mode they're addressed linearly.
- In Odd/Even SC/GC mode VRAM A0 is replaced by either PGSEL, A14 or A16. In WORD CRTC mode address is rotated left by 1 bit (i.e. multiplied by 2) and A0 is replaced by A15, so A15 selects either low or high page. In this case even DWORDs contain low page and odd DWORDs contain high page.
- In Chain4 SG/GC mode A0 = A14 and A1 = A15. In DWORD CRTC mode address is shifted left by 2 bits (i.e. multiplied by 4) and A0 = A12 and A1 = A13. Data is stored in every 4th DWORD. There are 4 pages, 16Kb each. Data is stored in first DWORD in first page, in second DWORD in second page, in third DWORD in third page, in fourth DWORD in fourth page. No page selection available.
- Note difference between CPU and CRTC addressing. CPU uses "real" address and CRTC address is set such way, as if it would be shifted right by 1 bit in WORD mode or by 2 bit in DWORD mode. It's done to save bits. It affects CRTC Start Address register.
- Note, that A13/A14 substitution happens after shifting.
Steps to reproduce the behaviour
Blank
Expected behavior
No response
What operating system(s) this bug have occurred on?
Any
What version(s) of DOSBox-X have this bug?
Any
Used configuration
Output log
Additional information
No response
Have you checked that no similar bug report(s) exist?
- I have searched and didn't find any similar bug report.
Code of Conduct & Contributing Guidelines
- I agree to follow the code of conduct and the contributing guidelines.
Reactions are currently unavailable