12

The Amstrad CPC had three official screen modes:

  • Mode 0: 160x200, 16 colours, 4 bits per colour, 2 wide pixels per byte, bit-interleaved
  • Mode 1: 320x200, 4 colours, 2 bits per colour, 4 square pixels per byte, bit-interleaved
  • Mode 2: 640x200, 2 colours, 1 bit per colour, 8 narrow pixels per byte, non-bit-interleaved

Each mode occupied 16kB of RAM, of which 16 000 bytes were displayed at any one time, with the remaining 384 bytes being off-screen. Scrolling was accomplished by moving the memory offset of the start of the screen instead of by physically moving the data around.

There was also an unofficial Mode 3 that combined the worst features of Modes 0 & 1: 160x200, 4 colours, 2 bits per colour, 2 wide pixels per byte, bit-interleaved, 4 bits unused per byte. The only way I know of switching to Mode 3 is to muck around with the alternate registers of the CPU directly since the current screen mode is permanently stored there.

Looking at the bit patterns and considering that due to the limited memory available (16kB ROMs, etc.) you'd expect that Mode 3 would be a mixture of Modes 1 & 2. What was it actually doing under the hood to get such a weird mixture of features?

12

As you can see from the schematic, the Armstrad uses a 6845 compatible display controller together with a custom-made Gate Array or ASIC for video output. The Gate Array also controls the screen modes using two bits of a register.

We'll never know exactly what happens until someone reverse engineers the Gate Array, and while it has been decapped and photographed in April 2016, so far I don't know of any available schematics.

But to illustrate the principle, we can design our own gate array for Modes 0 to 2, and then see what happens if we switch to Mode 3.

To design a gate array, we need to write down boolean equations for the part we are interested in and convert them to disjunctive or conjunctive normal form while at the same time simplifying them, ignoring inputs we don't care about. The simplified equations then form the basis for programming the gate array.

The 6845 produces the RAM address of each data byte d we want to display in turn, and it's our task to convert this data into a pen-table index p, depending on the mode m. With max. 8 pixels per byte, let's use an internal 3-bit counter b for the bit position in the byte. We'll just look at the first nibble, the second nibble works in the same way. Here are tables for our 3 modes:

Counter      Mode 0        Mode 1        Mode 2  
b2 b1 b0   p3 p2 p1 p0   p3 p2 p1 p0   p3 p2 p1 p0   
--------   -----------   -----------   -----------   
 0  0  0   d3 d2 d1 d0    0  0 d1 d0    0  0  0 d0   
 0  0  1   d3 d2 d1 d0    0  0 d1 d0    0  0  0 d1   
 0  1  0   d3 d2 d1 d0    0  0 d3 d2    0  0  0 d2   
 0  1  1   d3 d2 d1 d0    0  0 d3 d2    0  0  0 d3

So in Mode 0 we use always the same 4 bits for the pen index for a single wide pixel, while in Mode 2 we use each bit of the nibble in turn for four narrow pixels.

Writing / for "not", * for "and" and + for "or", we can read off the simplified equations in DNF:

p3 = d3 *             /m0 * /m1   # d3 in mode 0
p2 = d2 *             /m0 * /m1   # d2 in mode 0
p1 = d1 * /b1             * /m1   # d1 for b=0,1 in mode 0 & 1
   + d1 *  b1       * /m0 * /m1   # d1 for b=2,3 in mode 0
   + d3 *  b1       *  m0         # d3 for b=2,3 in mode 1
p0 = d0 * /b1 * /b0               # d0 for b=0  
   + d0 *           * /m0 * /m1   # d0 for mode 0
   + d1 * /b1 *  b0 * /m0 *  m1   # d1 for b=1 in mode 2
   + d2 *  b1       *  m0 * /m1   # d2 for b=2,3 in mode 1
   + d2 *  b1 * /b0 * /m0 *  m1   # d2 for b=2 in mode 2
   + d3 *  b1 *  b0 * /m0 *  m1   # d3 for b=3 in mode 3

Now let's set m0=1 and m1=1, and see what happens in Mode 3:

Counter     Mode 3
b2 b1 b0   p3 p2 p1 p0
--------   -----------
 0  0  0    0  0  0 d0
 0  0  1    0  0  0 d0
 0  1  0    0  0 d3  0
 0  1  1    0  0 d3  0

So for our implementation, Mode 3 is 320x200 with 2 colors, using bits d0, d3, d4 and d7 to select the pen for the color. (I've probably made a mistake somewhere, but it still illustrates the principle).

Now the real Gate Array uses a different design: Maybe a shift register instead of a counter, or CNF instead of DNF, or internally negated values, or ... But the effect is the same: Simplifying the boolean equations leads to an unintended mode that "sort of, but not really" does something useful.

(BTW, a similar thing happens for the "undocumented" opcodes of the 6502).

7

As stated, mode 3 is an unofficial mode and thus a side effect of hardware implementation, so the circuit is designed to handle only three modes (bit values 00, 01 and 10). This means that bit combination 11 is interpreted as some other combination of bits.

From the list of modes' features it looks like there are three circuits that read video mode value: one responsible for display resolution and pixel format, one that works with color and one that controls interleaving. There are many ways to electrically implement what I am describing, but on logical level this is roughly what happens:

Resolution / pixels per byte: it tests if the bits are not equal (01 or 10) and only then tests which of them is on. Otherwise (00 or 11) it defaults to 160x200.

In pseudocode it would look like this:

if(bit0!=bit1)
   if(bit0==1) 320x200, 4 pixels/byte
   else        640x200, 8 pixels/byte
else           160x200, 2 pixels/byte

Color / bits per color: if bit 0 is on (?1) it immediately assumes mode 1 and tests bit 1 only if bit 0 is zero (so further circuit always assumes it has ?0 value)

Pseudocode:

if(bit0==1)      4  colors, 2 bits/pixel
else if(bit1==1) 2  colors, 1 bit/pixel
     else        16 colors, 4 bits/pixel

Interleaved mode: only mode 2 is not bit-interleaved, so this pattern (10) is the only value it tests for.

Pseudocode:

if(bit0==0&&bit1==1)      do not interleave
else                      interleave

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.