• Please review our updated Terms and Rules here

New CGA controller IP brainstorming

MicroCoreLabs

Veteran Member
Joined
Feb 12, 2016
Messages
1,186
I am developing an FPGA-based CGA controller and I have a few questions which would steer the design approach. I would appreciate any feedback.

- Is it necessary (or critial) to allow changes to the CRTC (6845) register settings while that scan line is being shifted out on the wire?
- Is it necessary (or critial) to allow changes to the pixel data of a scan line that is currently being shifted out?
- Are there any games or demos which rely on being able to do either or both of the above?

- If not, then can I assume that changes to either of the above would be done as frequenty as in the horizontal retrace period or as infrequently as the vertical retrace?
- How close to the beginning of the horizontal pixel data (visible or not) can I expect changes to be made? (When can I "lock-in" CRTC values and begin using them on that row?)
- For example, if the CRTC start address was changed, do we know how far in advance of the next row it would need to complete before pixels were fetched from memory or CRTC register seting changes were digested?

The IBM CGA card fetches a video data byte just before shifting it out, so I believe changes to the byte data can be made up to that point in time.
- If pixel data is generally not changed in a row that is being shifted out then I was wondering if I could instead get away with asynchronously fetching video data from row n+1 while row n was being shifted out.


Thanks!
 
Last edited:
Another question: Would it make a noticeable difference if I used an RGB to NTSC encoder to generate the composite video rather than digital logic? The encoder chip would generate pure sine waves while the digital logic would generate more unwanted frequency content.
 
And another question: If I sent the composite output as interlaced it would probably result in uncomfortable flicker and maybe some distortion to the pixels.

What if I only sent an interlaced frame one out of every four or eight frames? It would fill in the unused scan lines and have much less noticeable flicker. I wonder how this wold affect the pixels or artifact colors...

I guess there would also need to be a switch for digital RGBI and composite - I dont think RGBI could handle something like this.
 
Are you fundamentally changing the output format to something other than NTSC timing, i.e. VGA or HDMI? Will it support some sort of extended CGA modes (640x400)? If you are sticking with NTSC timing, do you really need an RGBI to composite converter? I do like the flexibility of a device like the A2DVI project to output to a modern LCD panel and simulate NTSC artifacts.
 
Are you fundamentally changing the output format to something other than NTSC timing,
I dont think so. I am curious if I could run interlaced for some percentage of the frames to achieve a fuller picture - try to make use of the unused scan lines.

Will it support some sort of extended CGA modes (640x400)?
Definitely. If the FPGA has 32 KB of RAM then it could at least implement Tandy modes (I believe).

If you are sticking with NTSC timing, do you really need an RGBI to composite converter?
I dont "need" it, but the FPGA will generate digital waveforms for the NTSC frequencies like the IBM CGA card. An NTSC converter chip would generate sine waves which should result in a cleaner image. (In theory, but thats a question I have)
 
Would it make a noticeable difference if I used an RGB to NTSC encoder to generate the composite video rather than digital logic?
Ideally, a display's input would filter out any frequency above what's expected. Assuming that's true, there won't be a difference. If you are really worried about it you can use a video driver, which includes a filter, after the logic. Have a look at the BH76206HFV.

If you are using an FPGA with high speed LVDS IO, you could directly synthesize the composite signal using PDM. The sampling rate would need to be a bit less than 250Mhz for NTSC. Alternatively, you could implement a two-bit R2R DAC at ~125Mhz with normal IO. Since you only have a limited palette, you can pre-calculate what the pattern should be for each color and store it in a lookup table, rather than calculate the output on the fly.

The encoder chip would generate pure sine waves while the digital logic would generate more unwanted frequency content.
The more important thing it does for you is to create the proper timing and levels of the front/back porch, sync tip and and color burst, something that the 1st gen CGA card does poorly.
 
- Is it necessary (or critial) to allow changes to the CRTC (6845) register settings while that scan line is being shifted out on the wire?

It is if you want 8088MPH and Area 5150 to work.

- Is it necessary (or critical) to allow changes to the pixel data of a scan line that is currently being shifted out?

Probably, the Kefrens effect in 8088MPH is basically beam-racing.

- If not, then can I assume that changes to either of the above would be done as frequenty as in the horizontal retrace period or as infrequently as the vertical retrace?
- How close to the beginning of the horizontal pixel data (visible or not) can I expect changes to be made? (When can I "lock-in" CRTC values and begin using them on that row?)

The yellow lines indicate where Area 5150 performs writes to the CRTC during the final "Lake" effect. As you can see it is basically writing all the time.

1769996588533.png
- For example, if the CRTC start address was changed, do we know how far in advance of the next row it would need to complete before pixels were fetched from memory or CRTC register seting changes were digested?
The start address is only latched at the end of a frame, not every row, so that's not too troublesome.

The IBM CGA card fetches a video data byte just before shifting it out, so I believe changes to the byte data can be made up to that point in time.
- If pixel data is generally not changed in a row that is being shifted out then I was wondering if I could instead get away with asynchronously fetching video data from row n+1 while row n was being shifted out.

I guess this depends on your goal. If you are trying to make a "better CGA" - things like palette registers would be nice, then maybe 100% accuracy with a CGA may not be entirely required. Original CGA cards are not exactly scarce if people want them to run demos on.
 
Last edited:
What if I only sent an interlaced frame one out of every four or eight frames? It would fill in the unused scan lines and have much less noticeable flicker.

This doesn’t make any sense? What would this accomplish?

A progressive (“240P”) NTSC signal like CGA has a vertical sync period that’s an integer number of horizontal syncs long. This results in each line of the new frame retracing over the sweep of the last frame. (This means any particular pixel gets “re-lit” 60 times per second, which with typical TV tube phosphors is often enough to avoid visible flicker.) Strictly speaking there are no "unused" scanlines other than the vertical margins; you're getting 60 fully used frames per second that just happen to be composed of scanlines that, on typically sized CRT screens, are thin enough that there's black space between them. I mean, sure, I get that this is a nitpicky distinction, but it also seems kind of important.

An interlaced signal, by contrast, has a non-integer vertical refresh period; there is a half-length HSYNC pulse that “changes sides” with each half-frame. (technically an interlaced frame is two TV frames woven on top of each other; unless you want gross artifacts you should only modify the contents of the frame every 1/30th of a second instead of every 1/60th.) Remember, on a real CRT the horizontal scan lines are not actually horizontal: the sweep is always “slanting down”; the beam is moving *continuously* from top to bottom in 1/60th of a second in a sloped path, the Hsync just cuts that slope into 250-something little slices when it kicks the beam from right to left. On the periods in an interlaced picture where the half-length sync is at the top of the frame that “early kick” in the middle of the line resets the beam to the left margin when it’s halfway the vertical distance of a full line down; this causes the rest of that frame to be offset into what would have been the empty black scanlines of a progressive frame with the same number of lines, resulting in the tradeoff of offering twice the (potential) vertical resolution but at a frame rate likely to cause flicker for any feature that’s small enough to only exist on one of the half frames.
(… and that is kind of the point here as to why interlacing works fine for TV but is problematic for computer displays. A TV is usually displaying continuous toned photographs where there aren’t really distinct pixels, and those contents are always moving and changing. You don’t have the problem of someone sitting there staring at a fixed grid of letters where individual features vital for telling one glyph from another are strobing in place.)

Anyway, so with that said… what are you talking about with having an “interlace for some percentage of frames”? What does that even mean? First off, there’s a technical issue here; modern televisions (and by “modern” I mean even CRT sets from the 1980’s) use ICs that use timing information to determine if you want interlacing; randomly chucking a short Hsync into a stream of progressive frames will probably just glitch the display instead of giving you a proper interlace. (You might have more luck doing it on an old dumb CRT, but those are their own bag of hurt; sometimes you can’t get interlacing to work without implementing proper equalizing pulses and other obscure bits.) Getting a clean properly interlaced signal that works on all displays is a PITA, which is why most 70's and 80's vintage computers and video games didn't bother with it. (There were also the advantages of higher effective refresh rate, etc, but the increased complexity of interlace was definitely a factor.) Secondly, even if you can get it it work… what does it accomplish, exactly? Why are you enabling interlace in the first place?

If the intention here is to keep displaying 240 lines (IE, 200 active for CGA) then A: why bother, or B: if you really want it you can just turn on interlace all the time and it probably *wont* induce much noticeable flicker; it’ll just make the display look a little different. IE, if each interlaced frame has the same contents (IE, you’re basically “double-scanning” at 30 hz) no elements will be “going away” every other 60 hz, you’ll just get them redrawn offset into what was the black scanlines between rows. Effectively any given lit pixel will be “dimmer” because the lit area will be twice as large but completely refreshed twice as often, which across the whole screen averages out. Visually this version of CGA will look like CGA modes displayed on VGA, but, sure, more flickery-er-y. (Mostly because of tearing effects when framebuffer contents are updated.) If the display in question is an LCD (or something else with an upscaler) then actually it *will* be basically indistinguishable from CGA modes on VGA other than having wider margins, because an upscaler will get rid of any flicker from the interlace.

Lets say you *do* have a monitor that's willing to take a weird sync rhythm that makes it offset an update into the interlaced "gutters" between the normal scanlines every four or eight frames: what exactly does this accomplish? Instead of being black the scanlines will all turn into strobe lights that have 1/4 or 1/8th of the frequency of the normal updates... and the normally updated space will be black when the scanlines are flashing. Why would you want this? Unless you were displaying on a very long-persistence phospher monitor the offset updates might not be perceptable as anything other than an annoying glitch in your peripheral vision; worse case it might make the whole display appear to shimmer slightly. This doesn't seem like an improvement over normal progressive display.

On the flip side: If you want interlace *because* you want to actually do some kind of enhanced CGA that supports 400 lines instead of 200 then your idea of only inserting random interlaced frames is obviously a complete dealbreaker; the additional resolution you add will be completely unusable if it's only updating a couple times per second as a ghostly flicker in the otherwise black scanlines. If you want higher resolution then you need to just implement interlace properly and accept it's going to be flickery on a color CRT unless it has a line doubler. IE, it'll look just like an Amiga in 400 line mode. Which apparently some people were fine with; it makes me mildly homicidal, personally, but some people can tolerate it. And on a long-persistence green monitor 400 line interlaced can look perfectly fine; I've posted some screenshots of the homebrew video dingus I built a few years ago that can do interlaced monochrome displays of 512x384 or greater resolution and it looks basically like a slightly lo-fi Macintosh on a green monitor or through a composite-to-HDMI scaler. If you want to support Interlaced because you want to try to implement, say, compatibility with the AT&T 6300/Olivetti's 640x400 mode on an NTSC frequency monitor instead of the 25Khz monitor they used then by all means go to town.(*)

(*Weird note: The Tandy 1000 EX/HX/SX/TX's "Big Blue" ASIC has an embedded 6845 implementation that supports a mostly undocumented/nobody ever used it interlace flag. There's a couple demos out there that give me a headache, but it does kind of make me wish someone had actually written A GEM/PC Paintbrush/something driver that used it. Again, on a mono monitor it *would* actually be useable.)

... So, am I missing something here? Because I really can't wrap my head around this idea of just randomly shifting gears between interlaced and non-interlaced.

EDIT: FWIW, there is *one* good argument for implementing the "double-scanned interlaced" thing, at least as an option: the composite input ports on some modern LCD scalers hate the "progressive mode" and don't render it correctly. You mostly see this on those cheap little monitors that they sell on Amazon/AliExpress/etc that use a scaler more suitable for car infotainment and backup cameras than computer input. On these displays a "progressive" NTSC displays wobbles and flickers and otherwise looks like trash. I discovered with my homebrew experiements that double-scanned Interlace is a legit fix for this.
 
Last edited:
And another question: If I sent the composite output as interlaced it would probably result in uncomfortable flicker and maybe some distortion to the pixels.

What if I only sent an interlaced frame one out of every four or eight frames? It would fill in the unused scan lines and have much less noticeable flicker. I wonder how this wold affect the pixels or artifact colors...

I guess there would also need to be a switch for digital RGBI and composite - I dont think RGBI could handle something like this.

The original IBM CGA doesn't actually output an interlaced signal - the 6845 can be put into interlaced mode, but the field interleave is created by performing vertical flyback in the middle of the last scanline. The 6845 attempts to do so by asserting the vsync pin mid-scanline, but the CGA uses the hsync signal to gate the vsync signal, forcing progressive fields.

1769997650165.png

Clever demoscene folks have figured out how to "fix" interlacing on the CGA by reprogramming the CRTC HSYNC position on that last scanline. the HSYNC is ignored by the monitor as it is 180 degrees outside the PLL phase but it allows the mid-scanline VSYNC to be triggered by U63.

All this stuff is extremely fun to emulate, let me tell you.
 
@Eudimorphodon I need to read your message in more detail but I wanted to respond on why to do it:

I read that the 30 Hz interlaced video with a 50% duty cycle between the two rows is fatiguing to the eyes so I was wondering if shifting the duty cycle would have a more pleasing effect. It would depend on the persistence of the phosphor. 1/8 was one idea but it could be random or with an alternating duty cycle. The goal would be to use all of the screen with minimal flicker.
 
Last edited:
All this stuff is extremely fun to emulate, let me tell you.
It's fun to implement in gates and firmware as well :)

I guess this depends on your goal. If you are trying to make a "better CGA" - things like palette registers would be nice, then maybe 100% accuracy with a CGA may not be entirely required. Original CGA cards are not exactly scarce if people want them to run demos on.
No particular design goal. Being compatible with the bulk of the games and demos seems reasonable. I'm learning what tricks they do so I can tweak my architecture to accommodate them. Beyond that, it may be easy to add additional hardware to support different modes, character ROMs, dithering, interlacing, or other interesting features.

I may also add a MicroSD card because - well, why not. :)
 
The start address is only latched at the end of a frame, not every row, so that's not too troublesome.
Oh.. I thought artifact colors were produced in text mode by shifting out the first two rows of the U and !! characters, and then resetting the start address after two rows are displayed.
 
I read that the 30 Hz interlaced video with a 50% duty cycle between the two rows is fatiguing to the eyes so I was wondering if shifting the duty cycle would have a more pleasing effect. It would depend on the persistence of the phosphor. 1/8 was one idea but it could be random or with an alternating duty cycle. The goal would be to use all of the screen with minimal flicker.

To reiterate: if you’re trying to *use* every line then a 50/50 duty cycle is the *best* you can do, full stop. (!!!!) How would refreshing just *some* of the content be an improvement? I mean, imagine even if you had a long persistence phosphor that absorbed all the flicker: if you filled up the display with white that’s not what you’d get with this idea, you’d get pattern of gray pinstripes. (Which would be randomly shimmering if you randomized the intervals.) It’s a nonsensical idea.

And again, it’s not even a thing with CGA because CGA is progressive scan at 60hz. Other than that edge case I mentioned for LCD scalers that don’t like progressive scan at NTSC rates this means flicker isn’t a problem. Interlace only enters the chat if you want to do something custom, and in those circumstances flicker from the 30hz refresh is just the cost of admission.

(The most common instance of interlace being associated with “CGA” is with specialized video cards like the ATI Wonder series that used it to allow CGA monitors to do tricks like displaying high-res EGA. And it flickers pretty badly on a color monitor. The thing is, though, that it was often used in machines like the IBM 5155 with a monochrome monitor with at least medium persistence phosphors, which would let you get away with it, or at least be more tolerable.)
 
Oh.. I thought artifact colors were produced in text mode by shifting out the first two rows of the U and !! characters, and then resetting the start address after two rows are displayed.

both are true - the CRTC frame itself is defined to be two scanlines tall to allow the start address to be repeatedly latched every other scanline. But if we're not counting ridiculous demos, you essentially have all day long to latch the start address.
 
To reiterate: if you’re trying to *use* every line then a 50/50 duty cycle is the *best* you can do, full stop. (!!!!) How would refreshing just *some* of the content be an improvement? I mean, imagine even if you had a long persistence phosphor that absorbed all the flicker: if you filled up the display with white that’s not what you’d get with this idea, you’d get pattern of gray pinstripes. (Which would be randomly shimmering if you randomized the intervals.) It’s a nonsensical idea.
Well, what you are obviously failing to recognize is. Um.. well.. nothing I guess. At the time the idea seemed to have some promise but it probably would be visibly worse.
 
the CRTC frame itself is defined to be two scanlines tall to allow the start address to be repeatedly latched every other scanline.
Is this to support interlaced frames? Im a bit confused... Does this mean that the 6845 start addresses is only recognized one every scan line, or every even (or odd) scan line?

My other question is: Do you know specifically where in the scan line the 6845 register(s) are latched in?
 
Ideally, a display's input would filter out any frequency above what's expected. Assuming that's true, there won't be a difference. If you are really worried about it you can use a video driver, which includes a filter, after the logic. Have a look at the BH76206HFV.

If you are using an FPGA with high speed LVDS IO, you could directly synthesize the composite signal using PDM. The sampling rate would need to be a bit less than 250Mhz for NTSC. Alternatively, you could implement a two-bit R2R DAC at ~125Mhz with normal IO. Since you only have a limited palette, you can pre-calculate what the pattern should be for each color and store it in a lookup table, rather than calculate the output on the fly.
I was thinking of using something like the AD724 or MC1377 to convert the digital RGB (would need a solution for I) into NTSC sine waves and provide the video line driver.

The FPGA could definitely generate the different phases, but ultimately the output would be 3.3V digital (with fast edges thanks to modern FPGA IOs) and it would still need an external line driver. I thought a dedicated chip would be easier to use and do a better job.
 
Is this to support interlaced frames? Im a bit confused... Does this mean that the 6845 start addresses is only recognized one every scan line, or every even (or odd) scan line?

My other question is: Do you know specifically where in the scan line the 6845 register(s) are latched in?

I gave a talk explaining this so in the interest of clarity i will refer to it -

Skip ahead to 21 minutes if you just want the CRTC explanation.
 
Is this to support interlaced frames? Im a bit confused... Does this mean that the 6845 start addresses is only recognized one every scan line, or every even (or odd) scan line?

I’m wondering if you might be confusing ntsc interlacing with the *memory* interlacing that *is* a thing with CGA.

I’m sure @GloriousCow’s video will cover all this, but I think the TLDR is this: the 6845 CRTC was designed for *character displays*, not arbitrary size bitmap displays, and thus it measures most dimensions in *character cells*, not lines or pixels. It actually has no idea how many pixels characters are across horizontally, it’s clocked at character rate, not pixel clock.Vertically it knows how many scan lines tall a character is, up to 32, and there’s a special fraction register, also five bits, so it can account for if the video system’s total number of lines isn’t an even number of characters tall.

So… in CRTC math the maximum number of “lines”, meaning lines of characters, is a seven bits number, or 128. So unless you’re using a 6845 to drive some strange super low res monitor a character line is at least two pixels tall. Which means every two (at minimum) consecutive lines address the same chunk of memory, at least as denoted by the “main” address lines, and the only thing that changes is the number on the *row* address lines. Look at the CGA schematic to see what it does with the RA lines and some things about CGA will become more clear.
 
Back
Top