VOGONS


CGA Timings

Topic actions

First post, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Hi,

I am trying to figure out correct CGA timings for my emulator. Information that I am looking for this is

1) How long does it take to draw 1 line (for the beam to move from one side to the other of the screen)
2) How long does it take to horizontally retrace
3) How long does it take to vertically retrace

According to the minuszerodegrees.net It takes 63.7us (15.7KHz) of which 4us (250Khz) are positive. Does it mean it takes 4us to draw and 59us for the beam to come back to the next line?

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 1 of 9, by Scali

User metadata
Rank l33t
Rank
l33t

The CGA card gets its clock timings from the ISA bus, so it runs off the same 14.32 MHz base crystal as the motherboard (standard NTSC frequency generators).
This means it is also in sync with the CPU and PIT.

A scanline takes exactly 76 PIT cycles, or 304 CPU cycles.
An entire frame is 262 scanlines, so 262*76 = 19912 PIT cycles or 79648 CPU cycles.

You can find the CGA manual here: www.minuszerodegrees.net/oa/OA%20-%20IB ... 0(CGA).pdf
It contains the default values of the registers for all modes.
These values are the 6845 CRTC's internal registers: http://www.classiccmp.org/dunfield/r/6845.pdf

In graphics mode, you can see the following:
Vertical total: 7Fh (127)
Vertical total adjust: 06h (6)
Vertical displayed: 64h (100)
Vertical sync position: 70h (112)

All these values (except total adjust) should be multiplied by 2 in graphics mode, since CGA works with pairs of even/odd scanlines as 'character rows'.
Vertical total should also be adjusted by one, because 1 row (2 scanlines) is the minimum height of a screen, so vertical total 0 means 1 row.
Vertical sync position should also be adjusted by one
So, if we interpret these values correctly, we get:
Vertical total: 256 scanlines.
Vertical total adjust: 6 scanlines.
Vertical displayed: 200 scanlines.
Vertical sync position: 226.

This gives us a total of 262 scanlines, of which 200 scanlines are visible, and vsync starts at 226.
On the original 6845, vsync is fixed to 16 scanlines. On later ones it can be reprogrammed from 1-15 (taken from the top 4 bits of the horizontal sync width register), but by default the value is 0, which translates to 16 scanlines.
So vsync would be from 226 to 242.
Then a new screen starts, and you have lines 242 to 262 as the 'top border', then it starts displaying the first scanline.

You can do more or less the same for the horizontal case:
Horizontal total: 38h (56)
Horizontal displayed: 28h (40)
Horizontal sync position: 2Dh (45)
Horizontal sync width: 0Ah (10)

These values are in character columns, and in graphics mode you have 8 pixels per column (which is 2 bytes).
So the sync push is 10 columns large, starting at column 45.
Given the clock signal, you should be able to work out the timings in absolute times.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 2 of 9, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Thank you Scali, that is exactly what I was looking for. The only last piece of information I am missing is when is the last bit of the status register (at 0x3DA) 1, so that the CPU knows it can alter data on the CGA memory? This is used by 8088MPH (I assume to either sync stuff or just modify data in video memory).

My guess is that during vertical retrace that is true (3DA bit 0 is 1), but is it true during horizontal retrace as well?

The adapter manual says: "A 1 indicates that a regen-buffer memory access can be made without interfering with the display." I looked at the 6845 manual and I think somewhere in there they explain where it is ok for the bus to access data but I could not find it (3DA is an adapter register not 6845 register).

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 3 of 9, by Scali

User metadata
Rank l33t
Rank
l33t
vladstamate wrote:

Thank you Scali, that is exactly what I was looking for. The only last piece of information I am missing is when is the last bit of the status register (at 0x3DA) 1, so that the CPU knows it can alter data on the CGA memory? This is used by 8088MPH (I assume to either sync stuff or just modify data in video memory).

Yes, this is to avoid CGA snow in 80 column textmode.

vladstamate wrote:

My guess is that during vertical retrace that is true (3DA bit 0 is 1), but is it true during horizontal retrace as well?

Yes, basically whenever the CGA card is not generating pixels on the screen, and as such is not reading video memory. So in all border areas, both horizontally and vertically.
The plasma effect in 8088 MPH uses this to draw a few pixels at the end of every scanline, and the rest during the vblank period.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 4 of 9, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

That bit is the inverted DE signal coming from 6845, and it is active only during active screen addressing. So it will go high between scanlines and is high during nonvideo scanlines, including vertical retrace. I don't know the exact timing detail on CGA and how it relates to border area. Maybe the datasheet can tell something about DE.

Reply 5 of 9, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

So...looks like Scali and Jepael were right all along. This is where "lets draw one scan line at a time" as an atomic operation fails. Now that I have accurate timings (and correct scanlines) the moment bit 0 of 0x3DA is toggled properly a lot of stuff is slow. That is because all INT 10h draw string functions wait for that bit to turn before writing anything and that bit will only turn once a frame, for a certain number of scanlines.

I NEED to account for horizontal retrace, so I cannot draw the whole scanline wholesale. I NEED to account for horizontal displayed != horizontal total so that 3DAh bit 0 is toggled on/off even during a scanline.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 6 of 9, by Scali

User metadata
Rank l33t
Rank
l33t

You can never draw a whole scanline at a time anyway, because things like palette changes can also occur anywhere on a scanline.
This is abused, especially on C64, for an effect called 'splitraster', where changing the background colour multiple times on a scanline is used to draw multiple rasterbars side-by-side.
Here is an example of the effect, done on VIC-20: https://youtu.be/AA9g7v6oajM
You could do the same on PC.

CGA waitstates/CGA snow also need to be evaluated along the scanline.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 7 of 9, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
Scali wrote:

Vertical sync position should also be adjusted by one

Minor correction - vsync position is not adjusted, so vsync starts on scanline 224. It doesn't make a lot of difference for most purposes, but I do have some code which messes with CRTC registers in the vicinity of the vsync and may confuse the CRTC if vsync doesn't start at the same time.

The vsync pulse generated by the CRTC (and reflected in port 0x3da) is 16 scanlines long (fixed by the CRTC), but the vsync pulse sent to the monitor is only 3 scanlines long (adjusted by the CGA to match NTSC specifications).

Reply 8 of 9, by Scali

User metadata
Rank l33t
Rank
l33t
reenigne wrote:

The vsync pulse generated by the CRTC (and reflected in port 0x3da) is 16 scanlines long (fixed by the CRTC), but the vsync pulse sent to the monitor is only 3 scanlines long (adjusted by the CGA to match NTSC specifications).

Ah yes, the same can also be said for hsync I suppose. If you set a hsync width of 16, that is not the hsync pulse alone, but the whole period of horizontal blank, front porch, hsync pulse, back porch, and the colorburst.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 9 of 9, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
Scali wrote:

Ah yes, the same can also be said for hsync I suppose. If you set a hsync width of 16, that is not the hsync pulse alone, but the whole period of horizontal blank, front porch, hsync pulse, back porch, and the colorburst.

Right. The actual hsync pulse sent to the monitor starts 32 hdots after the hsync pulse from the CRTC, and is 64 hdots wide (if not truncated).