VOGONS


IBM VGA BIOS initialization

Topic actions

Reply 20 of 29, by bananaboy

User metadata
Rank Newbie
Rank
Newbie
superfury wrote on 2023-01-02, 12:28:
Past active display doesn't toggle display enable. So when it reaches horizontal retrace of vertical display end, it doesn't fli […]
Show full quote

Past active display doesn't toggle display enable. So when it reaches horizontal retrace of vertical display end, it doesn't flip back until the next frame starts with horizontal&vertical counters reset and horizontal display skew clocks after that.

So with 640x400 active display, what software sees:
1. 400 times horixontal retrace. The 400th 'retrace' gets stuck a long time.
2. During that long time being stuck, vertical retrace flips on and off (usually, can happen anytime though).
3. Bit 0 clears and a new frame is rendering at horizontal display skew.
4. Back to step 1.

Thanks for the reply! I don't think that's correct that the horizontal retrace gets stuck a long time, at least on the VGA. I've attached a test program which is the exact code the IBM VGA BIOS uses to count the scanlines (I've written it using Open Watcom 2.0 but it should work in other compilers with minimal changes). You'll see that it counts 400 active display scanlines. If the horizontal retrace got stuck, you would see the "extra scanlines" value would not match "active scanlines" (it's always one more than active scanlines due to the loop counting one more when vertical retrace is detected).

I think I understand why counting up to the vertical retrace works now, however. I had initially assumed that it would also count the bottom overscan and blanking areas which occur before vertical sync. But it looks like during overscan and blanking, the DD bit is never set, and I'm assuming it's because the "display enable" signal is on for that duration. Then when it hits the vertical retrace start time, DD is set (and "display enable" signal is low).

Here's a very interesting thing though. The text you quoted (which looks like it's from the FreeVGA docs but the official IBM VGA/XGA Technical Reference has basically the same) mentions that the bit is the "real-time status of the inverted 'display enable' signal". I did some digging through the CGA circuit diagram (available in the official IBM CGA pdf manual). Indeed, bit 0 is driven directly by the display enable pin on the 6845 (via a NOT gate). Also the VSYNC pin on the 6845 drives bit 3 (although via a latch). If you look at the timing diagram for the 6845 attached (DISPTMG is the DE pin), notice that the DISPTMG signal goes low when Nvd (end of the active display) is hit! There's an overscan area between Nvd and Nvsp (Nvsp is the vertical sync position). The 6845 calls that entire duration "vertical retrace period" and the DE (DISPTMG) signal is low for that entire time, so on CGA it seems like what you said would be correct!

Cheers,
Sam

Attachments

  • Filename
    6845_vsync_timing.png
    File size
    9.46 KiB
    Downloads
    No downloads
    File license
    Public domain
  • Filename
    scanline.c
    File size
    1.23 KiB
    Downloads
    43 downloads
    File license
    Public domain

Reply 21 of 29, by superfury

User metadata
Rank l33t++
Rank
l33t++
bananaboy wrote on 2023-01-05, 11:21:
Thanks for the reply! I don't think that's correct that the horizontal retrace gets stuck a long time, at least on the VGA. I've […]
Show full quote
superfury wrote on 2023-01-02, 12:28:
Past active display doesn't toggle display enable. So when it reaches horizontal retrace of vertical display end, it doesn't fli […]
Show full quote

Past active display doesn't toggle display enable. So when it reaches horizontal retrace of vertical display end, it doesn't flip back until the next frame starts with horizontal&vertical counters reset and horizontal display skew clocks after that.

So with 640x400 active display, what software sees:
1. 400 times horixontal retrace. The 400th 'retrace' gets stuck a long time.
2. During that long time being stuck, vertical retrace flips on and off (usually, can happen anytime though).
3. Bit 0 clears and a new frame is rendering at horizontal display skew.
4. Back to step 1.

Thanks for the reply! I don't think that's correct that the horizontal retrace gets stuck a long time, at least on the VGA. I've attached a test program which is the exact code the IBM VGA BIOS uses to count the scanlines (I've written it using Open Watcom 2.0 but it should work in other compilers with minimal changes). You'll see that it counts 400 active display scanlines. If the horizontal retrace got stuck, you would see the "extra scanlines" value would not match "active scanlines" (it's always one more than active scanlines due to the loop counting one more when vertical retrace is detected).

I think I understand why counting up to the vertical retrace works now, however. I had initially assumed that it would also count the bottom overscan and blanking areas which occur before vertical sync. But it looks like during overscan and blanking, the DD bit is never set, and I'm assuming it's because the "display enable" signal is on for that duration. Then when it hits the vertical retrace start time, DD is set (and "display enable" signal is low).

Here's a very interesting thing though. The text you quoted (which looks like it's from the FreeVGA docs but the official IBM VGA/XGA Technical Reference has basically the same) mentions that the bit is the "real-time status of the inverted 'display enable' signal". I did some digging through the CGA circuit diagram (available in the official IBM CGA pdf manual). Indeed, bit 0 is driven directly by the display enable pin on the 6845 (via a NOT gate). Also the VSYNC pin on the 6845 drives bit 3 (although via a latch). If you look at the timing diagram for the 6845 attached (DISPTMG is the DE pin), notice that the DISPTMG signal goes low when Nvd (end of the active display) is hit! There's an overscan area between Nvd and Nvsp (Nvsp is the vertical sync position). The 6845 calls that entire duration "vertical retrace period" and the DE (DISPTMG) signal is low for that entire time, so on CGA it seems like what you said would be correct!

Cheers,
Sam

That's true for the VGA as well afaik, not just CGA.
Also interesting to note is the differing latch positions of the new frame's start address and byte panning. On VGA it's at vertical retrace start, at CGA/MDA at vertical total instead. Although they are applied after vertical total in both cases (from the latched value).
Preset row scan and character height seem to be latched at vertical total like on a CGA.

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

Reply 22 of 29, by bananaboy

User metadata
Rank Newbie
Rank
Newbie

Hm I don't see how that can be given the results of my test program (and the VGA BIOS where I got the code from) though. Btw I ran it in your emulator with an XT machine configured and the Super PC/Turbo XT BIOS ROMs and videocard set to pure VGA and it prints out 200/201 not 400/401.

Cheers,
Sam

Reply 23 of 29, by superfury

User metadata
Rank l33t++
Rank
l33t++
bananaboy wrote on 2023-01-06, 11:23:

Hm I don't see how that can be given the results of my test program (and the VGA BIOS where I got the code from) though. Btw I ran it in your emulator with an XT machine configured and the Super PC/Turbo XT BIOS ROMs and videocard set to pure VGA and it prints out 200/201 not 400/401.

Cheers,
Sam

Just ran the latest build on Android for a quick check and dumped the VGA state while it was counting memory (Turbo XT BIOS v3.0). It's clearly rendering 400 lines there....
Edit: Just updated the BIOS to v3.1. Same results.
It should be triggering horizontal retrace 400 times during POST.
Edit: Same after 80x25 set by XTIDE BIOS...
Unchanged by MS-DOS 3.3...

Are you running a VGA or CGA/MDA adapter? CGA used 200 lines.
You should be able to dump VGA state from the video submenu in the settings menu. VGA.log should contain the used timings.
The processing of those are very simple: all horizontal timings column(top to bottom) for each vertical timing(top to bottom). Basically it ORs those two bitfields together for the result at any time for the current scanline and horizontal counter, like two rulers when drawing a schematic with the rulers on horizontal and vertical sliders. The rulers in question being those two tables.
So: horizontal[curhorizontalclock]|vertical[curverticalclock]
curverticalclock being influenced by horizontal total and vertical total only to either increase or reset it.

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

Reply 24 of 29, by bananaboy

User metadata
Rank Newbie
Rank
Newbie

I'm running VGA. I attached my VGA.log and SETTINGS.INI in case that's helpful.

Attachments

  • Filename
    SETTINGS.INI
    File size
    92.34 KiB
    Downloads
    38 downloads
    File license
    Public domain
  • Filename
    VGA.log
    File size
    88.87 KiB
    Downloads
    40 downloads
    File license
    Public domain

Reply 25 of 29, by superfury

User metadata
Rank l33t++
Rank
l33t++
bananaboy wrote on 2023-01-07, 04:33:

I'm running VGA. I attached my VGA.log and SETTINGS.INI in case that's helpful.

Just took a look at them. From the VGA dump it looks like a proper 720x400 line mode. So 400 horizontal retraces until the display enable clears (the 400th containing the vertical retrace). The horizontal retrace should still happen 400 times from what the timings tell.

Edit: Now trying to compile your scanline.c app in Borland C++ 5. After some fixup of the code (for some reason UniPCemu's cursor key section fails with it, but luckily the numpad section works fine (instead of generating infinity sign characters). They work fine in TASM setup tho.). Now installing TASM because it's seemingly needed (perhaps for the asm statements).
Edit: After that, managed to finally compile it.
active=146, extra=147?
The CPU is running at 300kIPS speed.

Edit: Hmmm... The VGA is triggering retrace etc. like it should.
scanline.c is functioning correctly after all.

The main issue there is that with 300kIPS speed, scanline.c somehow can't detect all horizontal retraces because they happen faster than the CPU is running. So it misses them.
Default speed: 163/164
300kIPS: 146/147.
400kIPS: 382/383.
500kIPS: 328/329.
548kIPS: hovering between correct and slightly lower.
549kIPS: lower hovering between 398-400 lines of active display (and the extra always being one more).
550kIPS and higher:400/401.

So the basic issue is that the default speed in UniPCemu (315 cycles) is too slow for the program to count individual lines correctly (skipping lines by not correctly detecting the flipping bits, as the horizontal one goes faster than it can count).

At 550kIPS, it's finally going fast enough to count all scanlines without error (thus counting the horizontal retraces fast enough).

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

Reply 26 of 29, by bananaboy

User metadata
Rank Newbie
Rank
Newbie

Ah gotcha, makes sense. Where do I set 550kIPS? Is that the `cpuspeed` setting? Do I set it to 550000?

Also I'm confused about your statement "the 400th containing the vertical retrace". In 80x25 (720x400 line) the vertical display end is at 400 but vertical retrace starts at scanline 412 and ends at 414. Between 400 and 412 is the overscan and blanking areas.

Reply 27 of 29, by superfury

User metadata
Rank l33t++
Rank
l33t++
bananaboy wrote on 2023-01-08, 02:41:

Ah gotcha, makes sense. Where do I set 550kIPS? Is that the `cpuspeed` setting? Do I set it to 550000?

Also I'm confused about your statement "the 400th containing the vertical retrace". In 80x25 (720x400 line) the vertical display end is at 400 but vertical retrace starts at scanline 412 and ends at 414. Between 400 and 412 is the overscan and blanking areas.

Just set it to 550. The units is in x1000(1K) cycles after all (a value of 550 results in a 550000 IPS cycle speed).

If you set it to a value of 550000, it'll result in a huge speed of 550MIPS instead (very CPU heavy, afaik no current CPU can handle that speed normally). It's basically the same as the speed setting in Dosbox cycles.

What I mean is at the end of the 400th active display (when it goes into overscan until horizontal total) the display enable becomes 0(flipped). While it's 0, the vertical retrace will eventually start(set) and stop(clear) a few scanlines later. Only after that, once vertical total is reached and the counters are reset and any horizontal skew is processed, the display enable starts to become 1 again (as active display is starting to be accessed to render active display pixels again).

So the status registers will change like this directly after the last active display pixel is rendered:
1. Status=01h: Overscan of scanline 399(0-based) is entered and VRAM isn't accessed anymore.
(some scanlines including more horizontal retraces are rendered until vertical retrace starts, but that isn't reported other than the status register 1 not changing, being stuck at 01h. Each scanline processed is still htotal character clocks in length)
2. Status=09h: Vertical retrace is started at the programmed scanline
Some HTotal scanlines are waited until the vertical retrace end matches.
3. Status=01h: Vertical retrace is ended some scanlines later.
4. Any remaining displayed rows of blanking and/or overscan are rendered (if a gap exists in this place).
5. VTotal is reached. The scanline counter is cleared. Horizontal timing starts counting the horizontal skew clocks.
6. Horizontal skew ends. Active display starts rendering again, thus clearing the input status register 01h to 00h.

Of course I only mentioned the values of bits 0 and 3 above (basically result of AND AL,9 after reading the port), not other (un)documented bits in said register.

The blanking works in parallel to the other timings. It just forces the pixel to render (if not retracing) to RGB(0,0,0) instead of active display or overscan (active display always has priority over overscan, determined by the end registers and skew etc.). Basically it's probably just masking the RGB outputs from the other stages to become cleared when active (masking red/green/blue with FFh in the DAC itself when inactive or something like that. Basically an XOR of the input signal(blank signal being set to clear output) then driven onto all RGB binary input bits for the mask).

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

Reply 28 of 29, by bananaboy

User metadata
Rank Newbie
Rank
Newbie

Right thanks. And thanks very much for that detailed breakdown. I looked closer at what the VGA BIOS code is doing (and my scanline counter program) and I was completely mistaken in how it worked! I must have been asleep every time I looked at it so thanks very much for persisting with me! It loops waiting for the status bit 0 to go low and then detects the vertical retrace, so of course what you said must be correct! God I'm an idiot, thanks again!

Reply 29 of 29, by superfury

User metadata
Rank l33t++
Rank
l33t++
bananaboy wrote on 2023-01-08, 10:31:

Right thanks. And thanks very much for that detailed breakdown. I looked closer at what the VGA BIOS code is doing (and my scanline counter program) and I was completely mistaken in how it worked! I must have been asleep every time I looked at it so thanks very much for persisting with me! It loops waiting for the status bit 0 to go low and then detects the vertical retrace, so of course what you said must be correct! God I'm an idiot, thanks again!

Basically the documentation on the FreeVGA got it right, but also made mistakes.
Bit 0 is 1 during retrace, but also before/after it if there's non-active display enable surrounding it. So it's basically a mix:
1. It's set when display enable is 0.
2. It's also set when retracing horizontally and/or vertically.
Probably case 2 is true simply because retrace disables the display enable (unlike blanking). So that's actually the undocumented part.

Did need to adjust some things like putting labels outside the asm statements and adding a "typedef int uint16_t;" as well as including stdlib.h instead of the stdint.h of scanline.c to get it compiled though (using the last Turbo C compiler from Borland (editor being tc.exe) I think. It doesn't have stdint.h).

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