This chip generates the signals necessary to interface with a raster display (but it does not display any pixels-stuff itself) :
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 :
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.
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 :)
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!
Quite easy eh? We will see about that :)
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. | Name | Default | Type | Unit | Notes |
---|---|---|---|---|---|
R0 | Horizontal total character number | 63 | Max counter | Character | Define the width of a scanline |
R1 | Horizontal displayed character number | 40 | Trigger | Character | Define when DISPEN goes OFF on the scanline (in CRTC-Char) |
R2 | Position of horizontal sync. pulse | 46 | Trigger | Character | Define when the HSync goes ON on the scanline |
R3 | Width of horizontal/vertical sync. pulses | &8E | Trigger | Character | VSync width can only be changed on type 3 and 4 |
R4 | Vertical total Line character number | 38 | Max counter | Character | Define the height of a screen |
R5 | Vertical raster adjust | 0 | Max Counter | Scanline | Define additionnal scanlines at the end of a screen |
R6 | Vertical displayed character number | 25 | Trigger | Character | Define when DISPEN remains OFF until a new screen starts |
R7 | Position of vertical sync. pulse | 30 | Trigger | Character | Define when the VSync goes ON on a screen |
R8 | Interlaced mode | 0 | DATA | Configure various stuff such as interlaced mode, skews,… Results greatly differs between CRTC types |
|
R9 | Maximum raster | 7 | Max Counter | Scanline | Define the height of a CRTC-Char in scanline |
R10 | Cursor start raster | 0 | DATA | Useless on the Amstrad CPC/Plus (text-mode is not wired) | |
R11 | Cursor end | 0 | DATA | Useless on the Amstrad CPC/Plus (text-mode is not wired) | |
R12 | Display Start Address (High) | &20 | DATA | Define the MSB of MA when a CRTC-screen starts | |
R13 | Display Start Address (Low) | &00 | DATA | Define the LSB of MA when a CRTC-screen starts | |
R14 | Cursor Address (High) | 0 | DATA | Useless on the Amstrad CPC/Plus (text-mode is not wired) | |
R15 | Cursor Address (Low) | 0 | DATA | Useless on the Amstrad CPC/Plus (text-mode is not wired) | |
R16 | Light Pen Address (High) | DATA | Hold the MSB of the cursor position when the lightpen was ON | ||
R17 | Light Pen Address (Low) | DATA | Hold the LSB of the cursor position when the lightpen was ON | ||
R31 | Special | 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.
There's basically 3 register-groups:
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.
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.
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).
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).
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.
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.
(Illustration)
The monitor hold it's beam in the top-left corner.
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.
This is a time period when the monitor stop it's electron beam, move it to the top and wait for a VSync signal.
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) | EN | R/W (A9) | RS (A8) | I/O Function | Standard I/O Address | Standard I/O R/W |
---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | Select CRTC Register | &BC00 | Write only |
0 | 1 | 0 | 1 | Write CRTC Register | &BD00 | Write only |
0 | 1 | 1 | 0 | CRTC Status register (type 1 only) | &BE00 | Read only |
0 | 1 | 1 | 1 | Read CRTC Register | &BF00 | Read only |
1 | x | x | x | CRTC is not enabled | ||
x | 0 | x | x | CRTC is not enabled |
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
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.
Type 0,1,2,3 and 4 | |||||||||
---|---|---|---|---|---|---|---|---|---|
I/O Address | Function | Data bits 7 to 0 | |||||||
&BC00 | Select reg. | x | x | x | d | d | d | d | d |
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.
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
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.
Type 0 | Type 1 | Type 2 | Type 3 | Type 4 | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Reg | Description | Unit | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | |||||||||||||||||||||||||||||||||||||||
R0 | Horizontal total character number | char | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | ||||
R1 | Horizontal displayed character number | char | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | ||||
R2 | Position of horizontal sync. pulse | char | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | ||||
R3 | Width of horizontal/vertical sync. pulses | char | V4 | H3 | H2 | H1 | H0 | H3 | H2 | H1 | H0 | H3 | H2 | H1 | H0 | V3 | ? | ? | H3 | H2 | H1 | H0 | V3 | H3 | H2 | H1 | H0 | |||||||||||||||||||
R4 | Vertical total Line character number | char | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||
R5 | Vertical raster adjust | line | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||||||
R6 | Vertical displayed character number | char | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||
R7 | Position of vertical sync. pulse | char | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||
R8 | Interlaced mode | d | d | U1 | U0 | C | D | T | RC | I1 | I0 | I1 | I0 | C1 | C0 | D1 | D0 | I1 | I0 | d | d | |||||||||||||||||||||||||
R9 | Maximum raster | line | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||||||
R10 | Cursor start raster | line | d | d | d | d | d | B1 | B0 | d | d | d | d | d | B | P | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||
R11 | Cursor end | line | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||||||
R12 | Display Start Address (High) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||
R13 | Display Start Address (Low) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||
R14 | Cursor Address (High) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||
R15 | Cursor Address (Low) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d |
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
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 Address | I/O R/W | Function | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | |||||||||||||||||||||||||||||||||||||||
&BE00 | Read | Status reg. | z | z | z | z | z | z | z | z | U | L | V | 0 | 0 | 0 | 0 | 0 | z | z | z | z | z | z | z | z | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d |
Type 0 | Type 1 | Type 2 | Type 3 | Type 4 | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Reg | Description | Unit | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | Data bits 7 to 0 | |||||||||||||||||||||||||||||||||||||||
R10 | Cursor start raster | line | d | d | d | d | d | B1 | B0 | d | d | d | d | d | B | P | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||
R11 | Cursor end | line | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||||||
R12 | Display Start Address (High) | d | d | d | d | d | d | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||
R13 | Display Start Address (Low) | d | d | d | d | d | d | d | d | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||
R14 | Cursor Address (High) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||
R15 | Cursor Address (Low) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||
R16 | Light Pen Address (High) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | |||||||||||||||
R17 | Light Pen Address (Low) | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d | d |
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).
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 :)
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 :
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).
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!).
For advanced timings and electricals informations on the CRTC, check these datasheets.