Dosbox-x: CGA accuracy improvements

Created on 17 Apr 2017  路  53Comments  路  Source: joncampbell123/dosbox-x

I just pulled out an old IBM PC with a CGA. I'm going to use it to poke at how a CGA card actually responds to I/O and memory. This is a "new" CGA if the test in 8088MPH is correct. These notes will be used to improve emulation accuracy in DOSBox-X.

enhancement video

Most helpful comment

All 53 comments

Poking at I/O ports 3D0h through 3DFh results:

3D0h through 3D7h all map to the CRTC controller. 3D4h is aliased at 3D0h, 3D2h, 3D6h. 3D5h is aliased to 3D1h, 3D3h, 3D5h, 3D7h.

You can read CRTC registers from 3D5h, apparently. Reading port 3D4h returns 0xFF.

Port 3D8h writing works as documented. Reading port 3D8h has odd undocumented effects such as causing the CGA to render 80x25 text mode to repeat only the two top scanlines of each text cell.

(I wonder if it's that it takes whatever was latched onto the bus as a write during a read and uses that...?)

Port 3D9h writing works as documented, reading returns 0xFF.

Reading port 3DAh works as documented. Common return values are 0xF6 and 0xF7. Writing has no effect.

Ports 3DBh and 3DCh are documented to be related to the light pen interface. On my card, reading these ports returns 0xFF and writing does nothing.

Ports 3DDh to 3DFh return 0xFF. I have no way to verify whether they don't exist or whether they are just aliases of 3DBh and 3DCh.

Update: Now, reading port 3D8h just blanks the screen? It seems random.

Writing to light pen ports 3DBh and 3DCh appears to change bits 1-2 in port 3DAh, which matches documentation that they relate to the light pen interface. Instead of returning F6h/F7h I am now reading F4h/F5h.

The CGA appears to decode only the lowest 10 bits. Port 7DAh, 13DAh, etc. alias to 3DAh.

The 16KB of RAM on the board is repeated twice between 0xB8000-0xBFFFF.

0xBC000-0xBFFFF is an alias of 0xB8000-0xBBFFF.

Only CRTC registers 14 (0Eh) and up are readable. Registers 00h thru 0Dh return 0x00 when read. This contradicts documentation that says 0Ch and 0Dh (Video RAM start) should be readable.

EDIT: This is confirmed from the 6845 datasheet that only registers 0Eh and up are readable.

Speaking of I/O port aliasing...

I/O ports 10h-1Fh are an alias of I/O ports 00h-0Fh (DMA controller).
Real port = (IOport & 0xF)

I/O ports 22h-3Fh are an alias of I/O ports 20h-21h (PIC)
Real port = (IOport & 0x1)

I/O ports 44h-5Fh are an alias of I/O ports 40h-43h (PIT)
Real port = (IOport & 0x3)

I/O ports 64h-7Fh are an alias of I/O ports 60h-63h (keyboard/speaker/dip switches/etc)
Real port = (IOport & 0x3)

All motherboard I/O ports alias every 400h ports (10-bit decode).

CGA "snow" notes:

  • If the CRTC is in the active picture area, and you write a byte value to VRAM, your byte value (regardless what it should have read from VRAM) becomes the byte that the circuitry at that time uses to lookup the character in ROM and serialize to DAC. I am able to confirm this by the fact that the CGA snow test in DOSLIB hw/vga/test.c is able to cause enough CGA snow to make the character being rendered recognizable. For example, if I hammer the CGA VRAM with ascii character 0x04 (diamond), a recognizable diamond shape can be seen in the specks of snow flickering on the screen.
  • Apparently, it also affects the attribute byte used by the CGA to render as well. It doesn't matter whether the conflicting VRAM write is to character or attribute RAM, it affects both character and attribute data used by the circuitry at that point in time. Writing byte value 0x70 will create a visible inverted 'p' in the specks of snow.
  • As the "snow" data is handled like any other character+attribute data, writing byte values with bit 7 set will make snow that is subject to the Mode Select Register's "blink" setting, making either bright white snow or snow that visibly "blinks".
  • The best way to make CGA snow it seems is to blast 16-bit writes to it. The 8088 will break the 16-bit write down into two rapid 8-bit writes.
  • CGA snow only seems to affect only the even columns of 80x25 text mode (columns 0, 2, 4, etc. starting from the left). I did not see any snow on odd columns.

cgasnow_doslib_test

DOSLIB's CGA snow routine is able to generate a lot of snow, as you can see.

I recall reading that snow doesn't happen in 40脳25 text mode, I'm assuming it only needs half the bandwidth there so it could in theory use the freed up time to do the writes. How true is this? I'd be surprised if they bothered to add hardware explicitly to make that mode snowless.

Of course, it's possible they made all writes to fall into the points where 40脳25 would not read from memory, and just let it "fail" (i.e. show snow) on every other mode at those points.

It's true that 40x25 text doesn't have this problem. Oddly, neither does 640x200 2-color mode, even though the dot clock is the same as 80x25. Perhaps fetching the character bitmap from ROM takes long enough for the CPU to interfere in this way?

Testing

  • How big are the video RAM start address and cursor address registers? Since the CGA has 16KB of RAM onboard, what happens if the video RAM start address is close enough that the display wraps around 16KB, or set to start past it? Supposedly 8088MPH uses VRAM wraparound during the Delorean takeoff scene (scrolling).

    EDIT: According to the datasheet, cursor and start address are 14-bit. The address counter is probably 14-bit as well.

    Result: The register is handled as if a 14-bit register. Bits 14-15 have no effect. But the CGA is apparently wired in such a way that bit 13 is also not used, therefore start addresses repeat every 0x2000 bytes. Setting Start Address to 0x2000 will show the same display contents as 0x0000.

    However, the 6845 is still using all 14 bits to compare the address against the cursor. So if bit 13 of the start address and bit 13 of the cursor address don't match, the cursor won't appear even though the display contents will.

  • What happens if the cursor address is at or past 16KB? EDIT: According to the datasheet, you can't put it past 16KB.

    Result: The register is 14 bits wide, therefore cannot be put beyond 16KB. The cursor will only show up if all 14 bits match between display address and cursor address.

  • Exactly which CRTC registers can be read back?

    Result: It seems that contrary to 6845 documentation, registers 12-13 (Start Address) cannot be read back. On my CGA, the light pen registers are write only or not present, don't read anything back.

  • How many bits from port 3D4h are actually used to select the register? I'm guessing either 16 (0x10) registers, or if the light pen registers are there at register 16, probably 32 (0x20) registers. EDIT: According to the datasheet, 5 bits, therefore mask by 0x1F.

    Result: Indeed, only the low 5 bits select the register.

  • The CRTC datasheet only defines registers 00h through 11h. What happens if you try to select 12h through 1Fh?

    Result: Writing doesn't seem to do anything. Reading returns 0x00 (nothing). No effects as far as I know.

  • What happens exactly if you program the "max scanline" register to a value larger than 8? How big is that register? When the CGA steps into the 8th scanline of a character, does it start reading into the next character in ROM or wrap back around to the first scanline of the character it's supposed to display?

    EDIT: According to the datasheet, the max scanline / character height register is also 5 bits wide. The only question left is how the CGA is wired to combine the address and row counter into an address to read from ROM (text mode) or from memory (graphics mode).

    Result: The register is indeed 5 bits wide. It's a bit difficult to view the result on a monitor, because character height also controls active display and total display (and therefore drastically reduces the vertical sync rate), but it indeed appears that the CGA will repeat the same character from the ROM font. Which means that the CGA probably just takes the lowest 3 bits of the row counter and feeds it into the ROM address bits.

  • What happens if you change "max scanline" in the graphics modes? How does it affect the interlacing?

    "Video timing on the CGA is provided by the Motorola 6845 video controller. This integrated circuit was originally designed only for character-based alphanumeric (text) displays and can only address a maximum of 128 character rows. To realize graphics modes with 200 scanlines on the CGA, the MC6845 is programmed with 100 character rows per picture and two scanlines per character row. Because the video memory address output by the MC6845 is identical for each scanline within a character row, the CGA must use the MC6845's "row address" output (i.e. the scanline within the character row) as an additional address bit to fetch raster data from video memory." https://en.wikipedia.org/wiki/Color_Graphics_Adapter

    Result: If you set the max scanline register to zero, the row counter never advances beyond zero. The CGA will rapidly scan through the first 8K and then repeat the 8K throughout the active display. The second 8K will only be displayed if bit 0 of the row counter is nonzero. If you're willing to drastically shrink the active display area to 8K or less, this is a great way to obtain a CGA graphics mode with a linear (non-interleaved) framebuffer.

    If the max scanline register is any value greater than 2, then the interlaced scanlines from each 8K bank (selected by bit 0 of the row counter) will repeat until the 6845 advances to the next row in VRAM. Bits 1-4 of the row counter have no effect on where the CGA fetches display data from in graphics modes. For example setting the max scanline register to 3 will cause the two interleaved scanlines to be displayed twice (interleaved) before advancing to the next scan line in memory.

    So, the CGA does not use bit 13 of the 6845's address counter when fetching from RAM. It's either held to zero in alphanumeric modes, or tied to bit 0 of the row counter in graphics modes.

EDIT: Hey, this might help testing: http://www.classiccmp.org/dunfield/r/6845.pdf

Wait, is 320脳200 affected by snow? It should have the same access patterns as 640脳200 (exact same amount of bits read per scanline and in the same order, the only difference is how many bits they use up before changing to the next color). Having snow only on 80脳25 text mode would be certainly amusing.

And of course this doesn't count the "old CGA" cards which may be more prone to showing snow. I recall that the CGA BIOS waits for vblank before trying to draw pixels.

320x200 is not affected by snow either. It's only 80x25 for some reason.

My theory is that 80x25 text mode runs the dot clock fast enough that the extra time it takes to read a character from VRAM then read the character bitmap from ROM is probably giving the CPU enough time to overwrite the data through the single-ported RAM on the CGA, while 40x25 runs too slow for that to happen. 640x200 and 320x200 just send the bits directly to the DAC without character lookup, therefore no problem.

EDIT: Well, no, that wouldn't explain why it affects only every other column....

I'll add something to the DOSLIB test program to blast data to VRAM in CGA graphics modes and see if any glitches show up, just to be sure. I don't remember seeing any snow in CGA graphics modes when I used to play with graphics draw commands on an old IBM "luggable" back in the day.

EDIT: As far as I know all two of my CGA cards are the newer version. I don't have the older version, so I can't test it.

Just tested the CGA against DOSLIB's CGA snow routine. 40x25 text, 320x200 and 640x200 graphics do not have snow problems no matter how much my program writes VRAM.

EDIT: However it seems that somewhere along the test the CGA now puts the snow on odd columns, but only in mode 3 (80x25 color). Calling INT 10h to set the video mode can change whether the snow happens on odd or even columns, apparently.

Noted values for port 3D8h:

  • 40x25 text mode (b/w): 0x2C
  • 40x25 text mode (color): 0x28
  • 80x25 text mode (b/w): 0x2D
  • 80x25 text mode (color): 0x29
  • 320x200 graphics (b/w): 0x2E
  • 320x200 graphics (color): 0x2A
  • 640x200 graphics (b/w): 0x1E
  • 640x200 graphics (colorburst enabled): 0x1A

Notice that 80x25 text mode is the ONLY mode that sets bit 0 of port 3D8h (selecting 80 column mode). Setting the bit in any other mode (including 640x200 mode) only doubles the horizontal scan rate because the CRTC values are configured with timings for 40x25 text mode.

If I hack the 80x25 mode by switching on graphics and 80 column mode, 640 pixel graphics, it looks like a valid variant of 640x200 graphics mode, but with the same snow problem when you write to it. I can also hack it to make an 80-column 320x200 4-color graphics mode, which then also has the same snow problem.

So whatever is involved in 80-column text mode, is also related to the CGA snow.

Tests:

  • The 6845 is documented to advance to the next display row in memory and reset the row counter ONLY if the row counter matches the max scanline / character height register. Does that mean if software manipulates the value of the register such that it never reaches the max value, the CGA will always re-scan the same scanline until the 5-bit row counter eventually matches?

    Answer: Yes. Just like EGA/VGA, the CRTC will not advance to the next row and will increment the row counter until the row counter matches EXACTLY the value in "max scanline address" register.

    If you wait for a scanline where the row counter would be 2, but change "max scanline" to a lesser value before the CRTC hits the end of the scanline, the CRTC will continue onto row 3 and count all the way up to 31, then wrap to 0 and eventually hit the max scanline value. Unless of course, you change it again to prevent it from matching.

    Only bit zero of the row counter is used in graphics modes, so if the CRTC counts through 31 and back around, the graphics mode will still alternate between the CGA interleaved lines during that time. Text mode will repeat the same 8-line char during that time.

  • As far as I know, the CGA does not have a separate register to control the bytes between scanlines unlike the EGA/VGA. Is it based entirely on the active display columns, or is there another register that affects how many bytes per scanline it advances?

    Answer: No such register. Horizontal Displayed determines the change in address between rows.

  • The 6845 datasheet mentions a cursor skew register. Does the CGA have that too? Does it work? What exactly is the effect?

    Result: Display and cursor skew seem to have no effect.

  • The start address testing was only done in text mode, where bit 13 of the address is apparently kept at zero (thus text modes alias every 0x2000 according to the start address). What happens with the start address in graphics modes?

    Answer: From the 6845's point of view, feeding the CGA hardware addresses, text mode repeats every 0x2000 address bytes and graphics mode repeats every 0x1000 address bytes. But the CGA's wiring doubles the 6845's address (addr << 1) to enable starting anywhere within the entire 16KB for text and anywhere within the first 8KB for graphics.

  • If you draw text on the screen, and then switch to graphics mode, how does the character and attribute data appear? This would reveal how the CGA stores text mode vs graphics modes.

    Result: If you clear all VRAM in text mode, draw a normal console, then suddenly switch to graphics mode, it's clear from the garbled pixels on the screen that all text data is just reinterpreted as graphics and that character and attribute data are interleaved together, character first, attribute second, in the same order that is visible to the CPU. Most text is rendered within the first 8KB, so it becomes the even (0, 2, 4, 6...) scan lines. Anything written to the last 8KB in text mode becomes the odd (1, 3, 5, 7...) scan lines.

  • Does the CGA let you change the mode register mid-display, and can it handle it? Can you switch between 320x200 4-color and 640x200 2-color mid-display? Can you switch between graphics and 40-column text mid-display?

    Result: Apparently, yes. The CGA mode select is not buffered in any way. If you change the mode mid-display, it takes effect immediately. That includes how the mode handles the border color, apparently.

  • Can I trigger the 6845 to reset it's address counter and row counter by changing the end of active display early, waiting for the raster to hit it, then changing the end active display back to the original value to make it restart from start of display address? That would allow for CGA "splitscreen" effects if so (something normally associated with EGA/VGA).

    Result: Yes! You can wait for vertical retrace, then program in the 6845 row counters for the "top half" of the splitscreen, making sure that vertical total is the split point and that the blank/sync points are "out of range". Then trace the raster down to that point and reprogram the CGA again with normal blank/sync points in a way that allows the CGA to complete the raster normally. At the split point, the 6845 will reset the address to Start Address. CGAFX5.C is proof of this (it moves the hardware cursor to the top to help prove it's not just copying the text screen in software, so that you see two hardware cursors).

    Notes: Make sure for the top half that the vertical display value is out of range (maximum value) so that the 6845 will not attempt to start blanking at the split point. If you set the vertical display value to exactly the split point, odd "blanking flashing" may occur if the split point is at certain rows of the display, for some odd reason. For obvious reasons, you cannot let vertical sync trigger as well, or else that will throw off the picture and cause it to roll with the effect.

  • Is it possible to enable the 6845 hardware cursor in graphics modes? Or does the CGA gate that signal off if not text?

    Result: Programming the cursor start/end and cursor address registers will not show a hardware cursor in graphics modes. It's like the CGA gates it off in graphics mode. But if you set it up while in graphics mode, the cursor will suddenly appear the instant you program the mode select register to text mode.

Playing with the "interlace mode register" shows that the CGA actually follows along with the 6845's interlace addressing well, though the CGA isn't designed to support it.

  • Normal sync mode (R8 I=0 or I=2), composite output is 240p as usual.
  • I=1 interlaced sync mode. CGA 240p output is rendered with a half-scanline like normal NTSC 480i output. Text may visibly "judder" slightly as a result.
  • I=3 interlaced sync and video. The CGA's output doubles vertically in resolution. 80x25 text will fill the upper half of the screen instead of the full screen. This may have potential if one wants to do a 480i 80x50 text mode on a television set (high resolution, though flickery, text mode)

Also noted: Interlaced sync and video has odd effects with the hardware cursor. 6845 documentation (rightfully) mentions that cursor start and end have additional restrictions in this mode, for obvious reasons.

Results are the same for all text and graphics modes.

Despite the 32KB region between B8000-BFFFF, the 16KB repeats at BC000 in all modes.

The CGA in text mode maps: RAM address = (6845 address & 0x1FFF) << 1. This is why CPU-visible RAM repeats every 0x4000 bytes yet the visible part of RAM on the screen repeats every 0x2000 bytes from the 6845's point of view (bit 13 is discarded). But this allows the 6845 to start from text stored anywhere in the 16KB of CGA RAM (enabling 8 pages of 40x25 text or 4 pages of 80x25 text).

In graphics modes, the CGA maps: RAM address = (6845 address & 0x0FFF) << 1. CPU-visible RAM repeats every 0x4000 bytes yet the visible part of RAM on the screen repeats every 0x1000 bytes from the 6845's point of view (bits 12-13 are discarded). Bit 0 of the 6845 row counter is used as RAM address bit 13, which is why lines 0, 2, 4, 6... count from 0x0000 and lines 1, 3, 5, 7... count from 0x2000.

The 6845 datasheet does not mention this, though most knew of it back then, but setting cursor start > cursor end results in an "inverted" cursor.

Setting start == end results in a cursor that is one scanline thick.

Setting start == end + 1 results in a solid block cursor.

Setting start == end + 2 results in a solid block cursor with one scanline missing.

Odd CGA cursor blink behavior that deviates from the 6845 documentation:

Bits 5-6 of the cursor start register control blink and appearance of the cursor.
What differs on the CGA is what the bits actually do:

  • 00 = cursor blinks as normal, 1/16 field rate (6845 docs say it should not blink)
  • 01 = cursor does not display (matches 6845 docs)
  • 10 = cursor blinks as normal, 1/16 field rate (matches 6845 docs). However, changing between 10 and 00 seems to reset the blink cycle (I think...?)
  • 11 = cursor blink pattern, at 1/16 field rate, becomes: 10001000... instead of 10101010... (very different from 6845 docs that say it should blink at 1/32 field rate)

Very odd.

So, it turns out that you can change the mode select register during active display to cause raster effects. Here's a screenshot of the DOSLIB VGA test program, changing the video mode to 640x200 2-color mode momentarily for 30 scanlines in the middle of 40-column text mode.

cgaraster1

Perhaps the best explanation for why CGA has interleaved scanlines is that the graphics modes have 200 lines, but the 6845 only supports vertical timing values up to 7 bits wide. This means without interleaving, graphics mode can only go up to 128 lines. So obviously, to double the scanlines possible IBM's engineers chose to route bit 0 of the row counter to the next highest address bit.

Theory: If the CGA programs a 100-line mode with 2 scanlines/row to the 6845 to get 200 line graphics, do Hercules graphics cards do the same trick to program an 87-line (87*4 = 348) mode with 4 scanlines/row to get a 348-line graphics mode? They're both based on the 6845, correct?

EDIT: Holy crap, looking at the raw CRTC values copied down into hw/vga/herc.c shows I'm right!

/* HGC values for HGC graphics */
const unsigned char hgc_graphics_crtc[12] = {
    0x35,0x2D,0x2E,0x07,
    0x5B,0x02,0x57,0x57,
    0x02,0x03,0x00,0x00
};

hgc_graphics_crtc[10] = Max scanline address = 0x03 (4 lines per row)
hgc_graphics_crtc[9] = Non-interlaced mode
hgc_graphics_crtc[6] = Vertical displayed = 0x57 (87 character rows)

So future testing with Hercules graphics cards (like the one coming in off eBay now) should reveal same or similar address mapping.

Yeah, pretty sure the 7-bit counter is the main reason why CGA uses interleaved graphics. If IBM had chosen a power of two width, they could have avoided even the interleaving and just rearranged the address lines. I guess they cared more about the higher resolution.

Here's step two of my evil CGA hackery.

You can change the Mode Select (3D8h) mid-screen, and you can change the max scan line register to match mid-screen. The more difficult part is keeping the picture stable on your monitor because the CGA's vertical timing (through the 6845) is heavily tied to character rows, not scanlines.

This is a screenshot of CGAFX2.EXE on an 8088 CGA. The bar is an 8-line region where the video mode is briefly changed to 640x200 2-color mode, with 2 character lines per character, before returning to 8 lines per character text. In this implementation, picture stability is maintained (and sync with 6845 row counter) by starting and stopping the bar on 8-line boundaries.

cgafx2

Here's a video of the demo in action:

https://youtu.be/OatDkmBYNKA

If you don't want to waste CPU time, some trick would be to use the PIT to time an interrupt to around where the desired scanline is located (program the interrupt on every vblank). It's not 100% perfect, but it means you don't have to busy loop through the whole frame, making raster effects a tad more useful. Some Kellog's platformer game uses this for a water raster effect.

Not sure if you're doing that already.

I'm not. This is the source code:

https://github.com/joncampbell123/doslib/blob/master/hw/vga/cgafx2.c

I'll try that in cgafx3.c later on.

TODO: Future CGAFX5.C development:

Fix bug that falsely counts the blanking area from vertical retrace to active display as one scan line. Bit 3 is set when vertical retrace happens. Bit 0 is blanking (including hsync, horizontal and vertical blanking). The code as written now mistakenly counts the time between end of vertical retrace and end of blanking as one scan line. DONE

The new code should synchronize with vertical retrace, then set PIT timer 0 to a delay that should fire an interrupt at the proper scanline. Other I/O devices should not be an issue, since IRQ 0 has highest priority (right?).

There's a property with original IBM PC hardware that the CGA dot clock, CPU, and PIT all have a fixed relationship to one clock, the 14.318181MHz ISA bus clock, that would help us as well.

  • bus clock = NTSC color subcarrier x 4 = 315/88 MHz x 1000000 MHz/Hz = 14.318181MHz
  • CGA dot clock = bus clock (14.318181MHz)
  • CPU clock = bus clock / 3 (4.772727MHz)
  • PIT clock = bus clock / 12 (1.193181MHz)

So logically, the PIT timer has enough precision to fire somewhere within 12 pixels on the screen.

It would be easiest if the code were to wait for vertical retrace to end, then blanking, and then reprogram the PIT to reset the countdown to the desired delay. Or if the blanking period is known, to just wait for retrace to end and then reprogram the PIT. The delay value would have to factor in blanking as well as active display.

The next question: When PIT 0 fires an interrupt, how long does it take to go to the PIC, and then to the CPU, and then the CPU to process the interrupt and execute the timer interrupt? How long from the time PIT 0 fires an interrupt to when the 8088 begins executing the first instruction pointed to by interrupt vector 0x08? That delay will also affect the position of the raster effect.

The problem with this raster effect is that it requires precision within a raster scanline because it affects the row counter on the 6845 and the vertical timing. Character rows are integral to vertical timing and blanking on the 6845, so adjustments have to be made. This isn't like copper bars where it doesn't matter if the effect is off a scanline or two. This demo effect if it's off a scanline will cause a change in the vertical refresh rate, the memory address the graphics are rendered from, and possibly, cause the 6845 to miss the end of the row and count off 32 scanlines (through all 5 bits of the row counter) before beginning the next row.

This hackery is pretty difficult to work on, so the next thing I want to work on in CGAFX5.C is whether or not it is possible to get the 6845 to reset the address counter mid-screen.

There are several reasons to do this. One would enable splitscreen effects on the CGA. If we can get the CGA to reload the start address as if vertical blanking has ended, and program the start address right before that point, we can do splitscreen effects and start the split from any memory location we want. Another would combine the splitscreen with the mid-screen graphics mode change so that the graphics can be put offscreen (away from the text), and then reset the address back to where the text should be at that scanline to continue the text mode.

Another question is whether or not tricking the 6845 in this manner resets the row scanline counter or not (probably not). But resetting the row scanline counter may be possible anyway if we can predict ahead of time what it will be, and set the register to that value on that scan line so that all 5 bits match and the 6845 acts as if the character row has ended, resetting it to zero so that we can better control the raster and character height hacks.

Edit: Looking at the timing diagrams in the 6845 datasheet, we might be able to reset the address it scans from if we can manipulate the vertical total+adj registers to reset the 6845 to row 0 mid-screen, which might cause it to reload the address from the Start Address register.

Disclaimer: some of this may not pan out or may reveal other unexpected behavior. I don't know yet, this is stuff yet to try. Results may vary.

CGA4C.EXE, this time with proof of concept code to trick the 6845 into finishing a character row before and after the 16-scanline row of graphics in the middle of text. The raster bar is no longer restricted to 8-scanline boundaries.

cgafx4c

https://www.youtube.com/watch?v=TvN3oHtC24U

To explain CGA4C.C, as long as you can count the scanlines accurately, you can make the 6845 start another character row at any time by writing to the character height register your prediction of what the row scanline counter is. When all 5 bits of the row scanline match the character height register, the 6845 starts another row and resets the row scanline to zero.

According to the 6845 datasheet,

On horizontal retrace, when the horizontal display begins again at column zero, the address either increments up to the first byte of the next row, or resets to the first byte of the current row. I'm guessing this means that when blanking begins, the address stops incrementing.

On vertical retrace, when vertical display begins at row zero, the address is set to the Start Address and counts upward from there. The diagram shows that the address continues to increment as if non-blanking during the blanking and retrace periods.

CGAFX5.C is working. CGA splitscreen is possible! Just needs refinement to start at any arbitrary scanline instead of text rows.

You can tell it's splitscreen by the way the hardware cursor is duplicated.

cgafx5

This just gives me the wild idea of having part of the screen as graphics and part as text. No idea how usable such a thing would be.

Yes! That's the idea!

Also unlike the simple EGA/VGA split this hack will let you direct the splitscreen to any memory address. It tricks the 6845 into starting the screen again, which means it should reload from the Start Address registers. Therefore, the graphics portion could be from a location "offscreen" from text mode.

And here is CGAFX6B.C, proof that you can do EGA/VGA-like splitscreen on a CGA.

https://www.youtube.com/watch?v=Uu7bCk3omL8

Just for notes, the MDA is said to have the same aliasing for port 3B4h and 3B5h and similar mode control bits (but not the same).

http://www.seasip.info/VintagePC/mda.html

DOSBox-X should incorporate the 8x8 CGA font from the bitmap on this page. I'm assuming it's a proper dump of the CGA ROM.

http://www.seasip.info/VintagePC/cga.html

While this is about the CPC rather than PC, it's still relevant since it's about the 6845:
http://www.grimware.org/doku.php/documentations/devices/crtc

Different 6845 models from different manufacturers have significantly different behaviors (enough to affect the very kind of tests done here). You probably want to document exactly which 6845 is being used by that card you're testing on. If anything seems to contradict the datasheet no matter how you look at it, this may explain the differences.

This may also mean having to find an "old" CGA to double check how that one behaves. Easier said than done, I imagine.

Good point. This is on a "new" CGA according to 8088MPH. I'll take a photo of the CGA card when I get some free time today.

Here you go:

It's an "HD46505RP HD6845P" on the board.

img_20170430_134004260

Edit: So according to that site, this is a Hitachi chipset. Given that chipset on my CGA, I've switched on the interlaced mode and it seems to produce a signal that my TV set is perfectly OK with.

Hey, just noticed from photos on a site that the MDA and old CGA use a very similar 6845 chipset. If I can't get a hold of an old CGA, perhaps I can pull out my old MDA cards and test with those.

http://www.minuszerodegrees.net/oa/oa.htm

I will be able to test the "old" CGA soon. I just found one on eBay. I can tell from the picture that it's the old CGA by the green circuitboard and that it has an MC6845 instead of an HD6845.

EDIT: Perhaps I should just say that it looks just like the old CGA in the pictures on the minuszerodegrees website I linked to earlier.

So assuming my reading comprehension is working:

  • Old CGA = Motorola 6845
  • New CGA = Hitachi 6845

And interlaced mode seems to bring in the most significant differences (again, according to that page about the CPC), so yeah it's probably a good idea to redo all the tests. Is the plan to provide a toggle to choose which one to emulate or just stick to one of them?

As far as I can tell, yes. Those are the main differences in old CGA vs new CGA.

It will be a toggle, of course. But at first, only new CGA emulation.

The old CGA just arrived.
oldcga

All the videos seem to be gone? (sucks since I wanted to show them to some people)

I had them up for awhile but took many videos down since they weren't all that great quality to begin with.

I should recapture the output again, now that I have a CGA to VGA converter and a capture card.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

joncampbell123 picture joncampbell123  路  7Comments

sduensin picture sduensin  路  7Comments

sduensin picture sduensin  路  10Comments

Corak667 picture Corak667  路  8Comments

almeath picture almeath  路  18Comments