VOGONS


CGA pseudo-graphic modes

Topic actions

Reply 20 of 36, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

The clock used by the CGA card is the one on the motherboard, so you'd have to overclock the entire system (or make more extensive hardware modifications). It will work as long as every part of the system can cope with the higher clock rate. In an IBM PC 5150 or 5160, for example, the CPU is normally rated for 5MHz but you'd be driving it at 5.333MHz which may or may not work. It may work for a while but be unstable executing certain operations or be temperature dependent. Early PCs also pushed the DRAM technologies of the day close to their limits. Most other parts are likely to work but not guaranteed.

If you'd like to play with a CGA-esque system that has a 16MHz pixel clock, you could try getting hold of a BBC Micro. That also has a video subsystem based on the 6845 but uses a 16MHz crystal (character clock of 2MHz, 1MHz or 500kHz and pixel clock of 16MHz, 8MHz, 4MHz or 2MHz). Then you'd know the system would be stable, and other people could run any games or demos you made that way!

Reply 21 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on 2025-06-10, 10:53:

The clock used by the CGA card is the one on the motherboard, so you'd have to overclock the entire system (or make more extensive hardware modifications). It will work as long as every part of the system can cope with the higher clock rate. In an IBM PC 5150 or 5160, for example, the CPU is normally rated for 5MHz but you'd be driving it at 5.333MHz which may or may not work. It may work for a while but be unstable executing certain operations or be temperature dependent. Early PCs also pushed the DRAM technologies of the day close to their limits. Most other parts are likely to work but not guaranteed.

If you'd like to play with a CGA-esque system that has a 16MHz pixel clock, you could try getting hold of a BBC Micro. That also has a video subsystem based on the 6845 but uses a 16MHz crystal (character clock of 2MHz, 1MHz or 500kHz and pixel clock of 16MHz, 8MHz, 4MHz or 2MHz). Then you'd know the system would be stable, and other people could run any games or demos you made that way!

Thank you very much for the explanation!

Reply 22 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on 2025-06-09, 18:40:

You can change R9 at any point and it will take effect the next time that current row address equals R9 (probably at some specific point on the scanline - I'm not sure which one offhand). So you don't need a full CRTC restart like you do if you're making more than 128 rows or want to change the start address independently on different areas of the screen. Instead you just need to change R9 on the correct scanlines (I suggest doing it on scanline 0 of the rows that you want to be a different height from the row above). So for this arrangement you'd want 6 scanlines of adjust, 64 scanlines of 8-scanline rows, and 192 scanlines of 3-scanline rows. So that's a vertical total of 8+64 = 72 (R4 = 0x47). The vertical sync position should be on scanline 224 but that is now row 68 so R7 = 0x44. Everything else remains the same except that you set R9 = 2 on scanline 8 and R9 = 7 on scanline 200.

By the way, in this case you can switch R9 also with a regular call of the INT 8 interrupt handler. For this, it is better to make the total number of lines equal to 264. Then R4 = 0x48, R5 = 0, R6 = 0x42 and R7 = 0x44 (or R4 = 0x47, R5 = 0x8). Then the number of scan lines of the area with the height of 3 is equal to 64*3 = 192. Then 192/264 = 8/11; 264/11 = 24. Then the divider for the timer is equal to 24*114*8/12 = 1824, and the frequency is ~654.15 Hz. That is, the timer is configured as follows:
------------------------------------
mov al,34h
out 43h,al
mov ax,1824
out 40h,al
mov al,ah
out 40h,al
------------------------------------
The period is 11 ticks: 8 ticks - character height 3 and 3 ticks - character height 8. I just don't know how to synchronize the timer with the CRTC.

Last edited by SoftCat on 2025-06-11, 12:20. Edited 1 time in total.

Reply 23 of 36, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

Synchronizing the timer with the CRTC should be as simple as: wait for vsync, wait for display enable, program PIT mode and count. There is another way if you need more accuracy but that's more complicated.

I'd like to suggest not being afraid of non-regular IRQ0s - it's quite simple, all you need to do is use PIT mode 2 and write the new count to port 0x40 (without a write to port 0x43) in your IRQ0 handler. Then at the next IRQ0 (when the timer finishes its current count and loads the new count) it will start counting down from the value you just programmed. So if you want IRQ0s at scanline 8 and scanline 200, you'd program a count of 70*76 in the scanline 8 handler routine and 192*76 in the scanline 200 handler routine.

I'd also like to advise against using non-standard hsync and vsync rates unless there's a really good reason. Yes, 264 scanlines total will probably work fine on any CRT but some other displays (and particularly capture devices) may be more fussy. And even with CRTs you're running certain analogue components outside of their normal parameters for extended periods of time so if something is going to break then it's more likely to happen when using 264 scanlines than when using 262. You don't want people to be afraid to run your code on their irreplaceable systems because it causes their monitor to make an unusual squealing sound...

Finally, using 262 scanlines and 2 non-regular IRQ0s instead of 11 regular IRQ0s will save you CPU time that you can use to make your demo or game more impressive in other ways!

Reply 24 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on Yesterday, 09:12:
Synchronizing the timer with the CRTC should be as simple as: wait for vsync, wait for display enable, program PIT mode and coun […]
Show full quote

Synchronizing the timer with the CRTC should be as simple as: wait for vsync, wait for display enable, program PIT mode and count. There is another way if you need more accuracy but that's more complicated.

I'd like to suggest not being afraid of non-regular IRQ0s - it's quite simple, all you need to do is use PIT mode 2 and write the new count to port 0x40 (without a write to port 0x43) in your IRQ0 handler. Then at the next IRQ0 (when the timer finishes its current count and loads the new count) it will start counting down from the value you just programmed. So if you want IRQ0s at scanline 8 and scanline 200, you'd program a count of 70*76 in the scanline 8 handler routine and 192*76 in the scanline 200 handler routine.

I'd also like to advise against using non-standard hsync and vsync rates unless there's a really good reason. Yes, 264 scanlines total will probably work fine on any CRT but some other displays (and particularly capture devices) may be more fussy. And even with CRTs you're running certain analogue components outside of their normal parameters for extended periods of time so if something is going to break then it's more likely to happen when using 264 scanlines than when using 262. You don't want people to be afraid to run your code on their irreplaceable systems because it causes their monitor to make an unusual squealing sound...

Finally, using 262 scanlines and 2 non-regular IRQ0s instead of 11 regular IRQ0s will save you CPU time that you can use to make your demo or game more impressive in other ways!

Thank you very much!
And if R6 = 0, then the number of visible lines will be 0 or 128*(R9 + 1)?
By default, channel 0 of the timer seems to be programmed for mode 3. But in my case, I need mode 2, and mode 3 is not suitable?

Reply 25 of 36, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
SoftCat wrote on Yesterday, 14:47:

And if R6 = 0, then the number of visible lines will be 0 or 128*(R9 + 1)?

I'm not sure. It might be different between CRTC variants. Is there a particular reason you want to use R6=0? It'd probably be better to avoid it if you can (unless you want to try every variant that's ever been seen on a CGA card).

SoftCat wrote on Yesterday, 14:47:

By default, channel 0 of the timer seems to be programmed for mode 3. But in my case, I need mode 2, and mode 3 is not suitable?

Mode 2 works better for this purpose because in mode 3 the counter is reloaded halfway through the count. It'll probably reload using the new value, which makes it more complicated to figure out the correct values to program. And again it might depend on the PIT variant in the machine.

Reply 26 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on Yesterday, 15:07:

Is there a particular reason you want to use R6=0? It'd probably be better to avoid it if you can (unless you want to try every variant that's ever been seen on a CGA card).

Thank you very much for your answer!
I want to make a 256x128 16-color mode (with R9 = 0), which would work both on real CGA and in DOSBox. There will be a separate code for DOSBox. But the thing is that tricks with CRTC do not work at all in this emulator and it is unlikely that the developers will make support for these tricks. But they can make 128 visible lines with R6 = R9 = 0, if I prove that this corresponds to real CGA.

Reply 27 of 36, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

Ok, on my CGA card with Motorola MC6845, then R4=0x7f, R6=0 and R9=0 seems to give 128 active scanlines. However, R7 has got to be set to something and whatever it is set to then at least one of the active scanlines will be blanked due to the vsync pulse from the CRTC. So you can't actually get exactly 128 visible active scanlines that way.

I suspect that trying to use DOSBox for this is going to cause you more problems than it solves - having separate code for DOSBox will be a maintenance headache and may mislead you about the hardware's capabilities (snow for one thing - since it sounds like you'll be using +HRES). Why not use MartyPC instead, since that is designed for doing this sort of trickery? Or if you really want to use DOSBox for development you could make your own modified version of it which ignores the CRTC writes and outputs the screen layout that you want.

Reply 28 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on Yesterday, 16:40:

Ok, on my CGA card with Motorola MC6845, then R4=0x7f, R6=0 and R9=0 seems to give 128 active scanlines. However, R7 has got to be set to something and whatever it is set to then at least one of the active scanlines will be blanked due to the vsync pulse from the CRTC. So you can't actually get exactly 128 visible active scanlines that way.

I suspect that trying to use DOSBox for this is going to cause you more problems than it solves - having separate code for DOSBox will be a maintenance headache and may mislead you about the hardware's capabilities (snow for one thing - since it sounds like you'll be using +HRES). Why not use MartyPC instead, since that is designed for doing this sort of trickery? Or if you really want to use DOSBox for development you could make your own modified version of it which ignores the CRTC writes and outputs the screen layout that you want.

Got it, thanks!
I really like MartyPC, but it works very slowly for me. I can't debug the game on it. Maybe there is some option to speed it up without losing the CRTC tricks?

Reply 29 of 36, by GloriousCow

User metadata
Rank Member
Rank
Member
SoftCat wrote:

I really like MartyPC, but it works very slowly for me. I can't debug the game on it. Maybe there is some option to speed it up without losing the CRTC tricks?

What are the specs of your computer, particularly your cpu?

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 31 of 36, by GloriousCow

User metadata
Rank Member
Rank
Member
SoftCat wrote on Yesterday, 19:01:
GloriousCow wrote on Yesterday, 17:58:

What are the specs of your computer, particularly your cpu?

Intel(R) Core(TM) i5-2520M 2.50 GHz
6 GB RAM

Yeah, sorry. That CPU is 14 years old. Modern phones are faster.

I know upgrading your computer is not a luxury everyone has. But there's only so much I can do. I will continue to try to optimize things, but I don't expect any miracles.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 32 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on 2025-06-10, 10:53:

The clock used by the CGA card is the one on the motherboard, so you'd have to overclock the entire system (or make more extensive hardware modifications). It will work as long as every part of the system can cope with the higher clock rate. In an IBM PC 5150 or 5160, for example, the CPU is normally rated for 5MHz but you'd be driving it at 5.333MHz which may or may not work. It may work for a while but be unstable executing certain operations or be temperature dependent. Early PCs also pushed the DRAM technologies of the day close to their limits. Most other parts are likely to work but not guaranteed.

If you'd like to play with a CGA-esque system that has a 16MHz pixel clock, you could try getting hold of a BBC Micro. That also has a video subsystem based on the 6845 but uses a 16MHz crystal (character clock of 2MHz, 1MHz or 500kHz and pixel clock of 16MHz, 8MHz, 4MHz or 2MHz). Then you'd know the system would be stable, and other people could run any games or demos you made that way!

By the way, there is a CGA-like video card Compaq CNT75M525, which has a quartz crystal at 18.981 MHz. Photo here:
https://drive.google.com/drive/folders/11x0_- … ?usp=drive_link

Reply 33 of 36, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

I can't find much online about this card (except for XT hardware questions ), but between the 32kB of RAM, the onboard ROM, the lack of a 6845 and the 18.981MHz crystal it doesn't seem very CGA-ish apart from the connectors (which were also used for EGA).

Reply 34 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on Today, 08:47:

I can't find much online about this card (except for XT hardware questions ), but between the 32kB of RAM, the onboard ROM, the lack of a 6845 and the 18.981MHz crystal it doesn't seem very CGA-ish apart from the connectors (which were also used for EGA).

On the other hand, 32 kB of RAM is not enough for EGA.

Based on the 40x25 text mode, a 16-color pseudo-graphic mode of 160x204 can be made on CGA. This means that all games on the AGI engine (Leisure Suit Larry, etc.), as well as Montezuma's Revenge, could be 16-color on CGA.
In connection with this, an idea arose to make a driver for CGA that adds three additional 16-color modes to int 10h: 160x204, 320x102, and 256x128. Since this will be done via int 8, it is desirable to somehow take into account the system time.
Yes, I also know interesting non-standard modes (which are not in Michael Abrash's books) for EGA and VGA.

Reply 35 of 36, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

That does sound like an interesting project!

You can update the system time by keeping your own count of how many 1.193MHz PIT cycles have passed, and when that (as a 16-bit number) wraps (i.e. JC/JNC) do a jump back to the system interrupt 8 handler (make sure that you don't execute the EOI sequence in this case).

I've tried doing something like this before (adding interlaced 40x50 and 80x50 text modes) but it's unfortunate that there seems to be a lot of software (including hardware drivers and BIOS extensions) out there which leaves interrupts disabled for an extended period of time, messing up the effect. This can be mitigated somewhat by firing your IRQ0 earlier than you really need it and then waiting for the correct time to do your CRTC updates (so that if your IRQ0 is late it doesn't matter). But there's a tradeoff between increased reliability and slowing down the system. For at least one test system, it proved to be prohibitively expensive and I haven't debugged to figure out what's causing the delays. So it's definitely easier to do this in games and demos (where TSRs, drivers and unneeded IRQs can be disabled) than in software that can run in the background.

Reply 36 of 36, by SoftCat

User metadata
Rank Member
Rank
Member
reenigne wrote on Today, 12:04:

That does sound like an interesting project!

You can update the system time by keeping your own count of how many 1.193MHz PIT cycles have passed, and when that (as a 16-bit number) wraps (i.e. JC/JNC) do a jump back to the system interrupt 8 handler (make sure that you don't execute the EOI sequence in this case).

I've tried doing something like this before (adding interlaced 40x50 and 80x50 text modes) but it's unfortunate that there seems to be a lot of software (including hardware drivers and BIOS extensions) out there which leaves interrupts disabled for an extended period of time, messing up the effect. This can be mitigated somewhat by firing your IRQ0 earlier than you really need it and then waiting for the correct time to do your CRTC updates (so that if your IRQ0 is late it doesn't matter). But there's a tradeoff between increased reliability and slowing down the system. For at least one test system, it proved to be prohibitively expensive and I haven't debugged to figure out what's causing the delays. So it's definitely easier to do this in games and demos (where TSRs, drivers and unneeded IRQs can be disabled) than in software that can run in the background.

Got it, thanks for the info!
I've already done time tracking in a WAV player via PC Speaker using PWM in INT 8. I did it using an integer algorithm similar to Bresenham's line drawing algorithm. My INT 8 calls were regular, but that's not important for an integer algorithm.