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?
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
- the new value being written ("To" or
- the CRTC's row count at the moment of the change ("Row" or
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):
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" (
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
(f,t). Each table cell then shows the total
glitch count for that pair, summed up across the full range of the third
Here's what this gets us with the readings from the HD6845; click for the full-sized charts:
This paints a rather different picture (excuse the literalism), compared to the ones we got for the 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
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)
|4 high bits of
|4 high bits of
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:
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
CRTC character row
r, the HD6845R may produce a 'phantom vsync' when all of these
|r&7 == f&7||the 3 low bits of
|r & ~f & 0x78 == 0||none of the 4 high bits is 1 in
|f & (t^r) & 0x78 == 0||none of the 4 high bits is 1 in
|(r & ~t & 0xf == 0) || (f & ~r & a != a),
|if two of the 4 high bits are 1 in
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.
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
This seemed to indicate that each
(f,t) pair maps to a unique
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:
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:
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.