More CGA CRTC Glitching: HD6845(R) vs. MC6845

My last blog installment recounted some findings about Motorola's 6845 CRTC and its 'Phantom VSync' glitch.  To summarize:

  • If the Vertical Sync Position register (R7) is reprogrammed during the active raster period, the CRTC may (under certain conditions) output an unintended vsync pulse at the instant of the register update.
  • The visual symptom is a black bar (of blanked video) flashing across the width of the screen.
  • Occurrence depends on a specific correlation between the old and new R7 values and the current character row.
  • Another necessary condition is that the write operation happens at a particular stage of the character clock cycle.
  • Evidently, the chip's temperature also plays a part: as it gets warmer, some glitches may be suppressed.

See the previous post for the full lowdown; it explores a theory which seems to explain why it happens at all, why it's apparently unique to the I/O architecture of the IBM PC and its clones, and how other hardware platforms conveniently side-step the issue.

On the PC side of things, IBM used two variants of the 6845 (interchangeably) in their original MDA and CGA boards: Motorola's MC6845 and Hitachi's HD6845.  We've tested and analyzed this glitch on an IBM CGA board equipped with the MC6845; so what about that other one - how does it stack up?  Is there a meaningful difference?

Which HD6845 is it anyway?

Hitachi HD6845(R)P CRTC chip

First off, let's characterize exactly which chip we're looking at.  Hitachi actually used two different designations for the same CRTC family, '46505' and '6845', and the chip's package is marked with both - at least if the part was produced in ~1981 or later.1  There were two main models, HD6845R and HD6845S.

The "R" variant had the same specifications as Motorola's MC6845, while the "S" increased the maximum character clock rate from 3.0 to 3.7 MHz, and threw in other features like readable start address registers and programmable vertical sync width.2  (Motorola had one with similar specs, the "MC6845-1" or "*1", but I've never seen one myself.)

Here comes the confusing bit: on most "R" parts, the dual marking says 'HD46505R', then just 'HD6845' without the "R".  See the photo above: both part numbers also end with a "P", but this just denotes the packaging type (plastic).  Since that's irrelevant to functionality, I'll refer to this CRTC as the HD6845R - that's what Hitachi's own datasheets call it, even if consistency between the literature and the physical product wasn't their strong suit.

The "R", then, is the only other CRTC (besides the MC6845) known to be present in IBM's CGA/MDA video cards, and that's the one we're looking at now.

HD6845R Test Results

Last time around, after examining the R7 rewrite glitch on the MC6845, I noted that the HD6845 seemed to be affected in the same way.  But that was based on a simple spot-check of test cases, which happened to produce the same behavior on both chips.  Now there's a complete set of HD6485 test results, and the full story it tells is a different one altogether.

I don't have an IBM CGA board with the Hitachi 6845 on it, but our Area 5150 co-conspirator UtterChaos (also the proprietor of PCRetroTech on YouTube) does have one.  Using the same code I put together to get the MC6845 data, he was able to run the full two-pass test on his HD6845R-equipped CGA, so the output could now be compared with that from its Motorola counterpart.

Before we do that, a quick recap of what the automated test does: it keeps reprogramming R7 during the active display time, while iterating through the possible combinations of three variables.  They're all 7-bit numbers, i.e. in the range 0..127:

  • the value of R7 before the rewrite (in short: "From" or f)
  • the new value being written ("To" or t)
  • the CRTC's row count at the moment of the change ("Row" or r)

Unintended vsync pulses are detected with the kindly assistance of the CGA Status Register; for every test case that results in a glitch, the second pass records how many pulses it counts over 40 consecutive frames.

Here's what we got from the HD6845R, alongside the earlier MC6845 results for comparison (the 3D scatterplot data is for use here):

HD6845R: MC6845: Pass 1 results, CSV Pass 1 results, CSV Pass 2 results (full), CSV Pass 2 results (full), CSV Plain-text result list Plain-text result list 3D scatterplot data 3D scatterplot data

A first glance at the data made it pretty clear that Hitachi's variant is more glitch-prone than Motorola's: the MC6845 evidenced 'phantom' vsync pulses for 3435 different combinations, but the HD6845R upped the count to 8088 cases (a nice little coincidence... still, I'll assume that the designation of the test machine's CPU doesn't really decide the total glitch count).  It would seem that less provocation is required to confuse its internal circuitry into acting on partially-resolved data.

A second look turned up another informative fact: the HD6845R's positive glitch reads are a superset of the MC6845's.  Every single test case that glitched on the Motorola chip was present in the Hitachi data as well - along with a whole host of new ones.

Naturally, that begged the question: what's the underlying pattern behind those extra glitches, and could we express it using bitwise logic, like we've done with the MC6845?  If you recall, the whole impetus behind this investigation was finding a way to consistently avoid the glitch in CGA demo code, so that sort of thing would be just the ticket.

Some Instructive Eye-Candy

We've already seen how the MC6845 results line up into striking Sierpiński triangle shapes when visualized as 2D charts. That conjured up some pretty cool-looking patterns - and more importantly, some helpful clues for puzzling out those bitwise formulas we were after.  Let's see what happens when we do the same with the HD6845R data.

As before, we have three independent variables - "From" (f), "To" (t), and "Row" (r).  To get those 2D views of our data, we assign two variables to the rows and columns, which maps out the pairs (r,f), (r,t), and (f,t).  Each table cell then shows the total glitch count for that pair, summed up across the full range of the third parameter.

Here's what this gets us with the readings from the HD6845; click for the full-sized charts:

VSync position glitch occurence; r (character row) vs. f ('from' value), HD6845R
r (character row) vs. f ('from' value), HD6845R
VSync position glitch occurence; r (character row) vs. t ('to' value), HD6845R
r (character row) vs. t ('to' value), HD6845R
VSync position glitch occurence;  f ('from' value) vs. t ('to' value), HD6845R
f ('from' value) vs. t ('to' value), HD6845R

This paints a rather different picture (excuse the literalism), compared to the ones we got for the MC6845:

VSync position glitch occurence; r (character row) vs. f ('from' value), MC6845
r (character row) vs. f ('from' value), MC6845
VSync position glitch occurence; r (character row) vs. t ('to' value), MC6845
r (character row) vs. t ('to' value), MC6845
VSync position glitch occurence;  f ('from' value) vs. t ('to' value), MC6845
f ('from' value) vs. t ('to' value), MC6845

What you'll notice straight away is that the first chart (r,f) shows the very same pattern for both CRTCs, despite the HD6845R's higher counts.  In other words, the set of glitchy (r,f) pairs is identical to the MC6845's.  That was a fair bit of luck, as far as the testing process went: the first pass yielded the same selection of cases, so there was no need to redefine the rules for the second pass - it could just be run as-is.

The rest is very different.  We see lots more glitches showing up in the other two - the susceptible regions in these charts are more or less similar, but where the MC6845 data showed finer patterns, on the HD6845R they fill out larger subdivisions of the grid.  This brings out smaller patterns within those clusters (tiny Gibson Flying V guitars? Alley Cat's mysteriously self-propelling brooms?  Alas, science may never reach a consensus).

Plainly, this chip also has a well-defined set of conditions where a rewrite of R7 might potentially glitch.  But how do they diverge from those we observed for the MC6845?

Expressions and Exceptions (and Excel)

R7 Glitch
4 high bits of f ("From"):
4 high bits of r ("Row"): 0x110100010000000
 1  = HD6845R behavior diverges from MC6845
 0  = no difference, x = don't-care / N/A

With the Motorola 6845, we found that a change to the value of R7 is liable to glitch if the three parameters (r,t,f) fulfill four specific conditions.  With the Hitachi variant, it was clear that these conditions were relaxed in some fashion; but it wasn't a simple matter of eliminating a restriction or two - doing that didn't get me a match for the observed data, so the difference had to be something more subtle.

After rearranging the results from both CRTCs into a bunch of different spreadsheets, and trying to convincingly stare them down, it emerged that three of the conditions were exactly the same in both cases.  Only the fourth one (r & ~t & 0xf == 0) didn't apply to the HD6845R... or rather, it did - but only for some pairs of (r,f).  For the rest, meeting the other three conditions was enough to permit the R7 glitch.

The task became one of finding which (r,f) pairs exhibited this divergence - and whether or not they formed a coherent pattern, which could be shown to correspond to a logical formula of some kind.

That wasn't all that straightforward to do, because the readings indicated that this was all somewhat 'fuzzy', and the difference wasn't very clear-cut in every case.  But overall, those cases where the HD6845R deviates seemed to form 8×8 clusters on the (r,f) chart.  This meant that the key wasn't in the 3 least-significant bits, and since we're dealing with 7-bit values here, it was the other 4 that had to matter.

Dealing with 4 bits makes things much simpler.  If you look at the table above, it really does form an orderly pattern, and one which is simpler to analyze.  The rule boils down to this - on the HD6845R, condition #4 (r & ~t & 0xf == 0) becomes unnecessary, unless:

  • In f (R7's "From" value), two out of the 4 high bits are "1", and
  • The same two bits are both "0" in r (the row number).

In that case, the behavior matches that of the MC6845.  The conjecture was that a glitch occurs when the CRTC's comparator checks R7 against the current row count, and the four high bits of R7 still aren't completely resolved following the write operation.  It appears that the Hitachi chip has a harder time resolving the state of those bits, but if there's enough of a difference between their old state and that of the corresponding counter bits, that somehow cancels out.


Along with the three other prerequisites (which are identical to the MC6845's), our list of necessary conditions can now be revised.  If the value of R7 is changed from f to t on CRTC character row r, the HD6845R may produce a 'phantom vsync' when all of these are true:

Condition Interpretation
r&7 == f&7 the 3 low bits of r and f are the same
r & ~f & 0x78 == 0 none of the 4 high bits is 1 in r and 0 in f
f & (t^r) & 0x78 == 0 none of the 4 high bits is 1 in f and has opposing states in t vs. r
(r & ~t & 0xf == 0) || (f & ~r & a != a),
for any a in {0x18,0x28,0x30,0x48,0x50,0x60}
if two of the 4 high bits are 1 in f and 0 in r, then none of the 4 low bits can be 1 in r and 0 in t

Where the HD6845R differs is in the emphasized part.  Unfortunately, the verbal definition can't be restated as a neat bitwise expression, because the question of bit counts doesn't really lend itself well to that - you really have to string together the specific values that meet the condition, then OR/AND as appropriate.  But for the purpose of a concise list, the above is about as good as I could make it.

Interactive R7 glitch map, MC6845 vs. HD6845R
Interactive R7 glitch map, MC6845 vs. HD6845R

I've also updated the interactive view which I had put together for the MC6845 results.  The CRTC type can now be selected at the top right, so you can compare the data from the Motorola and Hitachi models.  The respective bitwise conditions are also color-coded; for both variants, the positions where all four of them intersect (light grey) more-or-less match up with the actual glitches recorded (white).

It should go without saying that this is still a rough approximation, and the HD6845 shows the same types of exceptions I noted for the MC6845.  The probability for a glitch likely varies with temperature here as well, which probably explains some of the cases that meet all four conditions but didn't exhibit any 'phantom' vsync reads.

Glitches that the observed bitwise constraints don't account for are indicated in red.  As before, they point out that this model is basically incomplete - in fact there are more of them this time around.  On the other hand, although they break the pattern, they seem to do so in a very specific way.

In fact, you might notice a couple of interesting things about how these exceptions are distributed.  For one, they tend to cluster in well-defined locations - as before, they violate only one of the bitwise rules (namely the fourth one).  But if you compare the data for both CRTCs, another pattern emerges: the MC's exceptions consistently show up in the same regions where the HD's constraints are relaxed; that is, where the observed bitwise conditions diverge.  Where they don't, the MC tends to show few or no exceptions, but the HD has plenty.

This probably means something, but the real significance is still pretty elusive.  It's likely that we're simply dealing with a continuum of fuzzy/marginal behavior, and these two CRTCs are basically showing us the same underlying effect - they're just not equally sensitive to it.

Where to Beware: Determining the Unsafe Character Row

While I was at it, I noticed something else about the data we got from both 6845 variants.  In that 2D plot of (f,t) - the one that tallies up the glitches for each pair of R7 values (old and new) - the total counts recorded top out at 40.  And if you recall, 40 happens to be the number of frames we tested for each combination of (f,t,r).

This seemed to indicate that each (f,t) pair maps to a unique r value.  So I checked the raw numbers, and that's indeed the case for both CRTCs.  Let's do the big emphasis box thing here, because this piece of information can come in very handy:

For a given pair of R7 values (the old value and the new one you're setting), there's only one specific CRTC character row where your write operation may result in a glitch.

We can denote that row as rG.  Since we have a 1-to-1 function, we can easily map out the value of rG for all possible cases:

HD6845R: (f,t) → rG
HD6845R: (f,t) → rG (click for full chart)
MC6845: (f,t) → rG
MC6845: (f,t) → rG (click for full chart)

All row numbers here are hexadecimal.  Of course, the MC6845 and HD6845R don't always glitch for the same R7 value pairs; but when they do, the row number is identical.  So we can derive a simple formula to find the single unsafe row, and it'll hold true for both CRTC types:

rG = (f & t & 0x78) | (f & 7)

That is, to find your vulnerable row index, you AND the 4 high bits of your "From" and "To" values, then add the 3 low bits from the "From" value.  This has the property (which also shows up in the other charts) that, in general, lower row numbers are more liable to glitch than higher ones.  When I originally came across this issue, my code was doing its R7 rewrites on character row 0, which is the worst possible choice.  At least I can Follow The Science and state that it wasn't just rotten luck after all.


  1. See New Hitachi Microprocessor Numbering System in the 8/16 Bit Multi-Chip Microcomputer Data Book [↑]
  2. The full list of differences between the two models is laid out in sordid detail at the end of the HD6845R/HD6845S datasheet (Wayback Machine link) [↑]

No comments

Write a response:

* Required.
Your email address will not be published.