CODING ★ THE MIGHTY CRTC 6845

The mighty CRTC 6845

The mighty CRTC 6845

This chip generates the signals necessary to interface with a raster display (but it does not display any pixels-stuff itself) :

  • HSync : Horizontal Synchronisation.
  • VSync : Vertical Synchronisation.
  • DISPEN : Display enable (BORDER is displayed with DISPEN is low)
  • MA : The 16Bits Memory Address where are the data which should be displayed on the screen (when DISPEN is high).

And that's all!

The HSync, VSync and DISPEN are two states signals (ON/OFF, 1/0 or high/low, you get the idea :) sent to the GateArray, which will read, every microsecond, two consecutive bytes in the base 64Kb RAM at the MA address. Then the Gate Array will produce all the video signals required by the monitor (Red, Green, Blue, HSync and VSync).

The CRTC has a total of 18 8-bit registers controlling all aspects of the video timings. It's clock frequency on the Amstrad CPC/Plus is 1MHz (so the CRTC updates itself every microsecond).

Four I/O ports are assigned to it :

  • &BC00 (Write only) : to select an internal register.
  • &BD00 (Write only) : to write to the currently selected internal register.
  • &BE00 (Read only) : to read the Status register (only available on CRTC type 1).
  • &BF00 (Read only) : to read the value of the currently selected internal register (but not all of them can be read).

CRTC Types

There's at least five CRTC types known on the Amstrad CPC/Plus. All of them are based on the same design (originally by Motorola) but have a different implementation, introducing differents behaviours in some situations or provide specific features. These CRTC types were defined by Longshot from the Logon System in the early days of the CPC demoscene (1989/1991) and are still widely used at this time by demosceners.

  • Type 0 (Hitachi HD6845S, UMC UM6845)
  • Type 1 (UMC UM6845R)
  • Type 2 (Motorola MC6845)
  • Type 3 (Amstrad Plus ASIC - Emulated CRTC)
  • Type 4 (Amstrad CPC preASIC - Emulated CRTC)

The CRTC Type 2, beside being the original one, is the “worse” type (according to the low democoders standards :) because most of the simple tricks used to do splitscreens or other demo-effects does not work with it.

The CRTC Type 3 and 4 are CRTC emulated by an ASIC in the Plus and CPC respectively. These are not real chips soldered on the motherboard like the type 0,1 and 2 are. The type 4 has been manufactured in the very last CPC produced by Amstrad (to reduce the cost and probably to test this technology before the Plus range) and is less common, that's why it was discovered only after the type 3 (of the Amstrad Plus range) although it was released before.

I recently came across a CRTC from Hitachi which seems to be a type 0 but slightly differs in some contexts (I'm still studying this atm) from others type 0 I have, so there's maybe more than 5 CRTC types :)

How it works

To fully understand how to control the video output of the CPC, you have to know how the CRTC is working internally (and little knowledge of the Gate Array is recommended too for all the colors and graphics mode related stuff).

So here it is, the key of the understanding of the CRTC is : it's just a bunch of counters and triggers!

  • Counters counts from 0 to a specified value (and then loop to zero).
  • Triggers are associated to a counter and when it match a specified value, it trigger an action (like incrementing another counter, switch a signal ON/OFF, …).

Quite easy eh? We will see about that :)

Internal Registers

Here are the 18 internal registers we can play with to affect the video-timings produced by the CRTC. Most of them are Write-Only (you can only set their value but not read it back), some of them are Read Only (eg. offset registers related to the lightpen) and finally, very few of them are Read/Write. But it depends on the CRTC type (We will see that later).

Here are the 18 internal registers we can play with to affect the video-timings produced by the CRTC. Most of them are Write-Only (you can only set their value but not read it back), some of them are Read Only (eg. offset registers related to the lightpen) and finally, very few of them are Read/Write. But it depends on the CRTC type (We will see that later).

 

Reg.NameDefaultTypeUnitNotes
R0Horizontal total character number63Max counterCharacterDefine the width of a scanline
R1Horizontal displayed character number40TriggerCharacterDefine when DISPEN goes OFF on the scanline (in CRTC-Char)
R2Position of horizontal sync. pulse46TriggerCharacterDefine when the HSync goes ON on the scanline
R3Width of horizontal/vertical sync. pulses&8ETriggerCharacterVSync width can only be changed on type 3 and 4
 
R4Vertical total Line character number38Max counterCharacterDefine the height of a screen
R5Vertical raster adjust0Max CounterScanlineDefine additionnal scanlines at the end of a screen
R6Vertical displayed character number25TriggerCharacterDefine when DISPEN remains OFF until a new screen starts
R7Position of vertical sync. pulse30TriggerCharacterDefine when the VSync goes ON on a screen
R8Interlaced mode0DATA Configure various stuff such as interlaced mode, skews,…
Results greatly differs between CRTC types
R9Maximum raster7Max CounterScanlineDefine the height of a CRTC-Char in scanline
 
R10Cursor start raster0DATA Useless on the Amstrad CPC/Plus (text-mode is not wired)
R11Cursor end0DATA Useless on the Amstrad CPC/Plus (text-mode is not wired)
R12Display Start Address (High)&20DATA Define the MSB of MA when a CRTC-screen starts
R13Display Start Address (Low)&00DATA Define the LSB of MA when a CRTC-screen starts
R14Cursor Address (High)0DATA Useless on the Amstrad CPC/Plus (text-mode is not wired)
R15Cursor Address (Low)0DATA Useless on the Amstrad CPC/Plus (text-mode is not wired)
R16Light Pen Address (High) DATA Hold the MSB of the cursor position when the lightpen was ON
R17Light Pen Address (Low) DATA Hold the LSB of the cursor position when the lightpen was ON
R31Special DATA Nothing special here :)

The defaults values given here are those programmed by the firmware ROM after a cold/warm boot of the CPC/Plus. 

Register-groups

There's basically 3 register-groups:

  • Horizontal Timing register-group: R0, R1,R2 and R3.
  • Vertical Timing register-group: R4,R5,R6,R7,R8 and R9.
  • Offset register-group: R10 to R17.

Units & Lexicon

  • Rasterline (Monitor)

    A rasterline is a single horizontal line of pixel on the monitor, from left to right.
    It is useful because it's a fixed visual unit, it can't be modified (unlike the scanline). Most coders use it to measure the execution time of their routine (ex: “My YM player takes 6 rasterlines! Yay!”).
    A PAL 50Hz video-frame on the Amstrad is 312 rasterlines.

  • Scanline (CRTC)

    A scanline is a one pixel height horizontal line from the CRTC point of view. R0 define the scanline's lenght. You can get more than one scanline per rasterline by doing splitscreen.

  • Character (CRTC)

    The CRTC is a character based display device and many of it's internal registers use character as unit. A character is 1us wide (2 bytes) and usually 8 scanlines height (but it can be modified with the R9 register).

  • Screen (CRTC)

    When I refer to a screen, I'm not talking about the monitor (the bulky hardware device plugged to your CPC displaying images), but a screen from the CRTC point of view. With an usual CRTC configuration, there's only one screen to deal with. Splitscreen is a technic to get two or many more screens on a single video-frame (We will see that a bit later).

Video-frame timings

A video frame is made of differents signals generated by the CRTC and Gate Array in order to produce something shiny (or not :) on the monitor. You can (almost) do whatever you want with the CRTC, really. However, if you expect to get something watchable on the monitor plugged to your CPC then your CRTC configuration must comply to some rules : the monitor timings!

Very briefly, for a monitor to display a stable and clean image, it requires that the HSync and VSync signals from the CRTC/Gate Array are within it's allowed Horizontal and Vertical refresh-rate range. Otherwise, the monitor will, at best, display a distorted and/or rolling image and may also produce a weird high-pitched noise.

That's why hacking with the CRTC is sometime confusing. You have to deal with two video devices at the same time: the CRTC iteself but also the monitor. Both having their own rules. So whatever you want to do with the screen, just keep it mind that their is a monitor behind and if you mess with the synchronization signals, the monitor won't like it.

Monitor

The standard monitors on the Amstrad (GT6x, CTM64x, CM14 or even TV) have a 50Hz Vertical refresh rate (meaning that a VSync pulse must appear every ~20ms, 19968μs exactly) and a 15625Hz Horizontal refresh rate (an HSync pulse every 64μs). Of course they can usually tolerate some slight variations of these timings but each monitor has it's own limitations.

For exemple, some monitor will accept a 65Hz Vertical-refresh rate while some other will completly lose synchronization with anything above 50.2Hz vertical refresh-rate. So it's all about reliability. You're free to do weird timings, it may work on -your- monitor but you can be sure it won't work on all monitor. If you stick to the standard 50Hz/15625Hz refresh-rates, all (correctly working) monitors will do fine.

  • Monitor frame-fly

    [!!!NOIMG!!!]

  • Vertical BLanking (VBL)

    This is a time interval during a video-frame required by the electron gun in a CRT monitor to move back up to the top of the tube. While the vertical blank, the electron beam is off, hence no data is displayed on the screen.

    As soon as the electron gun is back to the top, the monitor will hold it there until a VSync appears to indicate the start of a new frame. If no VSync appears, the monitor will release the gun by itself after some time (depending on it's VHold) and will usually produce a rolling/jumping image because the monitor vertical synchronisation is no longer done with the CPC video-frame but with the monitor hardware limits (and they won't be the same).

    The VBL is a monitor specific time interval, it can not be software controlled (on the Amstrad), unlike the VSync, which is a signal produced by the CRTC we can control. The monitor expect a VSync at regular interval to produce a stable image.

  • Horitontal BLanking (HBL)

    This is a time period when the monitor stop it's electron beam, move it to the top and wait for a VSync signal.

  • V-Hold

  • H-Hold

    The monitor hold it's beam in the top-left corner.

CRTC

Here is an illustration of the output produced by the CRTC/GA after a warm/cold boot.

  • Horizontal timings

  • Vertical timings

  • Vocabulary

    • VSync

    • HSync

    • Memory Address

    • Dispen

I/O Ports

The CRTC can accessed by the CPU via 4 I/O address. CRTC's I/O decoding use A14, IORD and IORW signals to enable the CRTC (see the figure on the left). A9 and A8 are used to choose one of the 4 CRTC I/O operations (Select, Write, Status and Read register).

/CS (A14)ENR/W (A9)RS (A8)I/O FunctionStandard I/O AddressStandard I/O R/W
0100Select CRTC Register&BC00Write only
0101Write CRTC Register&BD00Write only
0110CRTC Status register (type 1 only)&BE00Read only
0111Read CRTC Register&BF00Read only
1xxxCRTC is not enabled
x0xxCRTC is not enabled

Standard I/O R/W indicate the type of I/O operation you should do, but nothing prevent you to read a write-only register. Doing so may produce unexpected results.

&BC00 : Select register

Z80 Assembler

To select any of the CRTC registers from your Z80 program :

; select CRTC Register 6 (Vertical displayed character number)
ld bc,&BC00 ; Select CRTC register I/O address
ld a,6 ; the CRTC register index = 6
out (c),a ; write 6 at I/O &BC00

Since the I/O decoding design for the CRTC only use few bits of the MSB I/O address (see I/O decoding for more informations), you can save some CPU load and register by using the LSB of the I/O address to store the CRTC register index :

; select CRTC Register 6 (Vertical displayed character number)
ld bc,&BC06 ; B = (MSB I/O addr) Select CRTC register I/O address
; C = (LSB I/O addr) the CRTC register index
out (c),c ; write 6 at I/O &BC00

Locomotive BASIC

To do the same thing from the Locomotive BASIC interpreter :

OUT &BC00,6

Note that the BASIC also modify some CRTC registers to perform some of it's display related commands (e.g. MODE n or when the screen is scrolling after a PRINT instruction), hence the register you've selected may not remain selected depending on what's going on with the BASIC interpreter.

Notes

The register index is 5bit wide (Data bit4 to 0), bit 7 to 5 can be 0 or 1, it doesnt matter. It mean that the CRTC will use: < register index > MODULO 32.
  Type 0,1,2,3 and 4
I/O AddressFunctionData bits 7 to 0
&BC00Select reg.xxxddddd

  • You can select any CRTC registers from 0 to 31, but all the registers above 17 are useless.
  • Because of the I/O decoding design, if you perform a CPU I/O read instruction (IN, INI, etc) on this I/O address, the CPU will expect the CRTC to provide a value on the DATA bus, but it won't because it just don't care if it's a Read or Write CPU I/O operation. As soon as an active I/O request (Read or Write) is active on the Select Register I/O address (&BC00), the CRTC will read whatever is on the data bus and use it. In this case, the DATA bus will be in high impedance state while the CRTC will read it to get a register index to use. The value read on the DATA bus while it is in high impedance state is UNPREDICTABLE, it can be any value from 0 to 255, vary over the time, electrical conditions and/or the peripherals connected to the CPC/Plus!

&BD00 : Write register

This CRTC function allow to change the value of any writable CRTC registers. A Write command on a read only (or unused) CRTC register will have no effect.

Z80 Assembler

Once you've selected a CRTC register, you can change it's value by writing it at the I/O address &BD00 :

ld bc,&BD00 ; Write CRTC register I/O address
ld a,&80 ; the new value &80
out (c),a ; write &80 at I/O &BD00

Since the I/O decoding design for the CRTC only use few bits of the MSB I/O address (see I/O decoding for more informations), you can save some CPU load and register by using the LSB of the I/O address to store the new value :

ld bc,&BD80 ; B = (MSB I/O addr) Write CRTC register I/O address
; C = (LSB I/O addr) the new value &80
out (c),c ; write &80 at I/O &BD00

Locomotive BASIC

To do the same thing from the Locomotive BASIC interpreter :

OUT &BD00,&80

This will write the value &80 into the currently selected CRTC register.

Writable CRTC registers table

 Type 0 Type 1 Type 2 Type 3 Type 4
RegDescriptionUnitData bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0
R0Horizontal total character numberchardddddddd dddddddd dddddddd dddddddd dddddddd
R1Horizontal displayed character numberchardddddddd dddddddd dddddddd dddddddd dddddddd
R2Position of horizontal sync. pulsechardddddddd dddddddd dddddddd dddddddd dddddddd
R3Width of horizontal/vertical sync. pulsescharV4   H3H2H1H0     H3H2H1H0     H3H2H1H0 V3?? H3H2H1H0 V3   H3H2H1H0
R4Vertical total Line character numberchar ddddddd  ddddddd  ddddddd  ddddddd  ddddddd
R5Vertical raster adjustline   ddddd    ddddd    ddddd    ddddd    ddddd
R6Vertical displayed character numberchar ddddddd   dddddd   dddddd  ddddddd  ddddddd
R7Position of vertical sync. pulsechar ddddddd   dddddd   dddddd  ddddddd  ddddddd
R8Interlaced mode       dd U1U0CDTRCI1I0       I1I0 C1C0D1D0  I1I0       dd
R9Maximum rasterline   ddddd    ddddd    ddddd    ddddd    ddddd
R10Cursor start rasterline   ddddd  B1B0ddddd  BPddddd    ddddd    ddddd
R11Cursor endline   ddddd    ddddd    ddddd    ddddd    ddddd
R12Display Start Address (High)   dddddd   dddddd   dddddd   dddddd   dddddd
R13Display Start Address (Low) dddddddd dddddddd dddddddd dddddddd dddddddd
R14Cursor Address (High)   dddddd   dddddd   dddddd   dddddd   dddddd
R15Cursor Address (Low) dddddddd dddddddd dddddddd dddddddd dddddddd

Notes :

Because of the I/O decoding design, if you perform a CPU I/O read instruction (IN, INI, etc) on this I/O address, the CPU will expect the CRTC to provide a value on the DATA bus, but it won't because it just don't care if it's a Read or Write CPU I/O operation. As soon as an active I/O request (Read or Write) is active on the Write Register I/O address (&BD00), the CRTC will read whatever is on the data bus and write it into the currently selected CRTC register. In this case, the DATA bus will be in high impedance state while the CRTC will read it. The value read on the DATA bus while it is in high impedance state is UNPREDICTABLE, it can be any value from 0 to 255, vary over the time, electrical conditions and/or the peripherals connected to the CPC/Plus!

&BE00 : Status Register

WARNING: The status register provide 3 informations flags :

U (bit 7) : Update Ready

  • 0 = This bit goes 0 when R31 has been either read or written by the CPU.
  • 1 = This bit goes 1 when an Update Strobe occurs.

L (bit 6) : LPEN Register Full

  • 0 = This bit goes 0 whenever either R16 or R17 is read by the CPU.
  • 1 = This bit goes 1 when a LPEN strobe occurs.

V (bit 5) : Vertical Blanking

  • 0 = Scan is not currently running in vertical blanking time-span.
  • 1 = Scan currently is in vertical blanking time-span.

Exemple to read the status register:

ld b,&BE ; B = (MSB I/O addr) CRTC status register I/O address
in a,(c) ; Read the status register and store it's value in the CPU register A

Notes

 

The following table shows what data you get if you read this register on the various CRTC type.
   Type 0 Type 1 Type 2 Type 3 Type 4
I/O AddressI/O R/WFunctionData bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0
&BE00ReadStatus reg.zzzzzzzz ULV00000 zzzzzzzz dddddddd dddddddd

  • On type 3 and 4, reading the status register will in fact try to read the value of the currently selected CRTC register, just like &BF00 : Read Register.
  • ceils with a “z” indicate a bit which is read from the databus in high impedance state (it's value is unpredictable).

WARNING: Writing a value at this I/O address (OUT, OUTI, etc) will produce a short-circuit on the DATA bus between the CRTC 6845 and the Z80 CPU since both of them will try to put a value on it for a few microseconds…

&BF00 : Read register

 

Readable CRTC registers table

 Type 0 Type 1 Type 2 Type 3 Type 4
RegDescriptionUnitData bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0 Data bits 7 to 0
R10Cursor start rasterline   ddddd  B1B0ddddd  BPddddd    ddddd    ddddd
R11Cursor endline   ddddd    ddddd    ddddd    ddddd    ddddd
R12Display Start Address (High)   dddddd 00000000 00000000   dddddd   dddddd
R13Display Start Address (Low) dddddddd 00000000 00000000 dddddddd dddddddd
R14Cursor Address (High)   dddddd   dddddd   dddddd   dddddd   dddddd
R15Cursor Address (Low) dddddddd dddddddd dddddddd dddddddd dddddddd
R16Light Pen Address (High)   dddddd   dddddd   dddddd   dddddd   dddddd
R17Light Pen Address (Low) dddddddd dddddddd dddddddd dddddddd dddddddd

Differences between models

Memory Address (MA)

The MA is reloaded with the value from R12 and R13 when VCC=0 and VLC=0 (that's when a new CRTC screen begin). However, CRTC Type 1 keep updating the MA on every new scanline while VCC=0 (and VLC=<R9).

Interlaced video-mode (R8)

The CRTC 6845 can be programmed, via it's register R8, to handle different video mode, interlaced or not interlaced. Unfortunately, this feature is by far the most bugged and very badly supported amongs the various CRTC type found on the Amstrad CPC/Plus, none of them is able to produce a proper interlaced mode! To keep the doc as simple as possible, I will simply skip the details about the interlaced features (for now), it's barely useful and higly incompatible between CRTC type anyway. If you want to read more informations about this feature, I suggest you take a look at the datasheet at the end of this page, switch ON your CPC and do some tests :)

Programming the CRTC 6845

REMEMBER: Be monitor friendly 

No matter what you are doing with the CRTC, from setting up a simple fullscreen to any complex split-screen frame structure, to keep friendly with the monitor :

  • YOU MUST NOT program HSync time-discontinuities (R2).
  • YOU MUST NOT program VSync time-discontinuities (R7).

If you break any of these rules, your program will produce bad video-timings for a short time and will make the monitor display jump and/or distort for some time (depending on it's hardware settings).

  • YOU MUST program the CRTC to produce an HSync each 64us which last for at least 8µs (R3).
  • YOU MUST program the CRTC to produce a VSync each 19968µs.

If you break any of these rules, your program will produce bad video-timings. Some monitor may tolerate it, but some others WILL NOT! (I'm not kidding!).

Simple screen configuration

  • 16Kb screen
  • 32Kb screen
  • Split-screens
  • Simple Splitscreen
  • Horizontal Splitscreen

Datasheet

 

For advanced timings and electricals informations on the CRTC, check these datasheets.

Pictures

Picture of a Motorola CRTC 6845P (type 2).

http://www.grimware.org/

★ YEAR: 2016
★ AUTHOR: GRIM

CPCrulez[Content Management System] v8.7-desktop/cache
Page créée en 855 millisecondes et consultée 58 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.