CRTC 6845 on a CPC 6128 motherboard

This documentation is a work in progress and is far from being complete and error free. Use it at your own risks :)

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.

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.

Amstrad CPC 6128 costdown ASIC, also known as CRTC type 4 Amstrad Plus ASIC, also known as CRTC type 3

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).

Reg. Name Default Type Unit Notes
R0 Horizontal total character number 63 Max counter CharacterDefine the width of a scanline
R1 Horizontal displayed character number 40 Trigger CharacterDefine when DISPEN goes OFF on the scanline (in CRTC-Char)
R2 Position of horizontal sync. pulse 46 Trigger CharacterDefine 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 CharacterDefine the height of a screen
R5 Vertical raster adjust 0 Max Counter ScanlineDefine additionnal scanlines at the end of a screen
R6 Vertical displayed character number 25 Trigger CharacterDefine when DISPEN remains OFF until a new screen starts
R7 Position of vertical sync. pulse 30 Trigger CharacterDefine 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 ScanlineDefine 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.

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

(Illustration)

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

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

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) 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
  • 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 Address Function Data bits 7 to 0
&BC00 Select reg. xxx d d d d d
  • 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
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 numberchardddddddd dddddddd dddddddd dddddddd dddddddd
R1 Horizontal displayed character numberchardddddddd dddddddd dddddddd dddddddd dddddddd
R2 Position of horizontal sync. pulsechardddddddd dddddddd dddddddd dddddddd dddddddd
R3 Width of horizontal/vertical sync. pulsescharV4 H3H2H1H0 H3H2H1H0 H3H2H1H0 V3?? H3H2H1H0 V3 H3H2H1H0
R4 Vertical total Line character numberchar ddddddd ddddddd ddddddd ddddddd ddddddd
R5 Vertical raster adjust line ddddd ddddd ddddd ddddd ddddd
R6 Vertical displayed character numberchar ddddddd dddddd dddddd ddddddd ddddddd
R7 Position of vertical sync. pulsechar ddddddd dddddd dddddd ddddddd ddddddd
R8 Interlaced mode dd U1U0CDTRCI1I0 I1I0 C1C0D1D0 I1I0 dd
R9 Maximum rasterline ddddd ddddd ddddd ddddd ddddd
R10 Cursor start rasterline ddddd B1B0ddddd BPddddd ddddd ddddd
R11 Cursor end line ddddd ddddd ddddd ddddd ddddd
R12 Display Start Address (High) dddddd dddddd dddddd dddddd dddddd
R13 Display Start Address (Low) dddddddd dddddddd dddddddd dddddddd dddddddd
R14 Cursor Address (High) dddddd dddddd dddddd dddddd dddddd
R15 Cursor 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

The status register function is a specific feature of the CRTC Type 1 only.

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 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. zzzzzzzz U L V 00000 zzzzzzzz d d d d d d d d d d d d d d d d
  • 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).

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
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 rasterline ddddd B1B0ddddd BPddddd ddddd ddddd
R11 Cursor end line ddddd ddddd ddddd ddddd ddddd
R12 Display Start Address (High) dddddd 0 0 0 00000 00000000 dddddd dddddd
R13 Display Start Address (Low) dddddddd 0 0 0 00000 00000000 dddddddd dddddddd
R14 Cursor Address (High) dddddd dddddd dddddd dddddd dddddd
R15 Cursor Address (Low) dddddddd dddddddd dddddddd dddddddd dddddddd
R16 Light Pen Address (High) dddddd dddddd dddddd dddddd dddddd
R17 Light 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 8us (R3).
  • YOU MUST program the CRTC to produce a VSync each 19968us.

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!).

If you break any of these rules, I will laught out loud and throw shit at you!
(I'm still not kidding! You've been warned. :)

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).
Picture of a Motorola CRTC 6845P (type 2)

documentations/devices/crtc.txt · Last modified: 2009/03/17 21:46 by grim