CPC Guide - CRTC6845Cathode Ray Tube Controller (CRTC6845) Programming the CRTC The CRTC has 18 registers (0-17) which are used to control the screen, screen cursor, and to sense a light pen/gun. To access these registers, the CRTC has 3 control ports. One port to select a register, one port to write data into the register and one port to read data from the register. Port address Read/Write Function/Use &BCxx W Select CRTC register &BDxx W Write data to selected CRTC register &BFxx R Read data from selected CRTC register NOTE: Due to differences in CRTC's, some of the information described here may not work. Where differences occur (that are known), they will be listed. If you intend to use special effects, ensure they work with all CRTC types, or you specify which CRTC types the effect works on. Thankyou to David Long (dave@kechb.demon.co.uk) for the following information. The CRTC's can be destinguished by the manufacturers identification number printed on the top. HD6845 (Hitachi) - Type 0 UM6845 (UMC) - Type 1 (but some can act like Type 0) MC6845 (Motorola) - Type 2 Selecting a register A register is selected by sending the register number (in the range 0-17) to port &BCxx. This register will remain selected until another is selected. This means you can write to the same register many times, without having to re-select the register each time. Writing to a register Once a register has been selected using the method above, the user can write data into it. Data can be written into the register by sending the data to port &BDxx. If the selected register cannot be written to, there will be no effect. Reading a register Once a register has been selected, it can be read from. The data in the register can be read from port &BFxx. If the register cannot be read, a value of &FF will be returned. NOTE: On certain CRTC types this is not possible. CRTC Status Register Over to Mark Rison: Here's a translation of what `Le Livre de l'Amstrad' says about the status register of the 6845: " In addition to the 18 registers described above, the S version of the 6845 has an extra register called the status register. This read-only register only has 3 active bits: b7: 1 if the CRTC is accessible b6: 0 if R16 and R17 have been read by the processor, 1 if the light-pen signal has been detected b5: Blanking indicator. 0 if the spot is being displayed, 1 if it is in flyback This register not being very useful except for light pens, it will no longer be discussed. " And some comments from Pierre Guerrier: "So this register contains one bit (if you are reading it, then the CRTC is accessible) one redundant bit (b5 is on the PIO also) and one flip-flop for firmwares too stupid to remember if they have sensed the light pen in the frame... As it uses only the upper 3 bits, and the pointer register is only 5 bits, and they have the same position (same value of RS pin), it's probably two parts of one byte with different I/O directions. The information seems to be relevant only to the HD6845 S and not other chips." Register Functions - and normal values Register Read/ Register Title Normal values Number Write PAL SECAM NTSC 0 W Horizontal Total 63 63 63 1 W Horizontal Displayed 40 40 40 2 W Horizontal Sync Position 46 46 46 3 W Sync Width &8E &8E &8E 4 W Vertical Total 38 38 31 5 W Vertical Total Adjust 0 0 6 6 W Vertical Displayed 25 25 25 7 W Vertical Sync Position 30 30 27 8 W Interlace and Skew 0 0 0 9 W Maximum Raster Address 7 7 7 *10 W Cursor Start Raster X X X *11 W Cursor End Raster X X X 12 R/W Start Address (High) X X X 13 R/W Start Address (Low) X X X *14 R/W Cursor (High) X X X *15 R/W Cursor (Low) X X X 16 R Light Pen (High) X X X 17 R Light Pen (Low) X X X * - These registers are not used on the CPC. R - Read only W - Write only R/W - Both Read and Write X indicates the values of these registers may vary during normal operation. Register 10,11,14 and 15 are not used on the CPC. The CPC doesnt use the hardware cursor of the CRTC. It uses a software cursor. I will not document these registers because they are not used. Register 16 and 17 are used to sense the Light pen position. On CRTC2 it is not possible to read the CRTC registers, so I dont think it is possible to use a Light Pen on this CRTC. NOTE: Experimenting with the registers can produce interesting effects. You will not do any harm by doing this. Just switch the computer off and then on, and everything will be ok again. Register sizes This defines the number of bits used in each register. It is mainly of use to emulator authors. Register Name 7 6 5 4 3 2 1 0 AR Address Register . . . x x x x x 0 Horizontal Total x x x x x x x x 1 Horizontal Displayed x x x x x x x x 2 Horizontal Sync Pos. x x x x x x x x 3 Sync Width . . . . x x x x x x x x x x x x ('S') 4 Vertical Total . x x x x x x x 5 Vertical Total Adjust . . . x x x x x 6 Vertical Displayed . x x x x x x x 7 Vertical Sync Pos . x x x x x x x 8 Interlace and Skew x x x x . . x x ('S') . . . . . . x x 9 Max Raster Address . . . x x x x x 10 Cursor Start raster . x x x x x x x 11 Cursor Stop raster . . . x x x x x 12 Start Address (H) . . x x x x x x (can read on 'S' cannot on non-'S') 13 Start Address (L) x x x x x x x x 14 Cursor (H) . . x x x x x x 15 Cursor (L) x x x x x x x x 16 Light Pen (H) . . x x x x x x 17 Light Pen (L) x x x x x x x x Note: AR is the address register, or the register of the CRTC to use. "." means this bit is not used, and x means the bit is used. Register usage Certain registers can be used for various things. Here is a list of registers and their common usage. Register 0: Horizontal splitting (changing of screen address/mode accross line). Register 1: Width of screen Register 2: a) Horizontal positioning of screen b) Screen distorting (when changed as beam scans screen) Register 3: Smooth left-right hardware scroll Register 4: Rupture/Vertical Splitting (allowing screen address to be changed on any line Register 5: Very smooth vertical scrolling Register 6: Height of screen Register 7: Setting up the rupture/splitting and vertical position of screen Register 8: - Register 9: - Register 10: NOT USED Register 11: NOT USED Register 12: Setting screen address + Overscan + Hardware scrolling Register 13: Hardware scrolling Register 14: NOT USED Register 15: NOT USED Register 16: Light pen address Register 17: Light pen address Register 1 - Horizontal Displayed This register is used to define the width of the screen. The width is calculated in mode 1 character sized steps. i.e. the number of characters accross the screen in mode 1, is the same as the number programmed into this register. Therefore, the width of the screen may be increased or decreased, to get the desired screen width. If the value programmed is increased, the width of the screen will increase, if the value programmed is decreased, the width of the screen will decrease. The normal width of the screen is 40 characters. The width of the monitor screen is 50 characters. (The number of bytes displayed on a line=value programmed to register 1*2) Register 2 - Horizontal Sync Position This register defines the horizontal position of the screen within the monitor screen. If the programmed value is increased, the screen will shift to the left, if the programmed value is decreased, the screen will shift to the right. So, using this register, the user can put the screen to any horizontal position they want. Register 5 - Vertical total adjust This register allows the vertical position of the screen to be positioned to any pixel offset from the current vertical position defined in register 7. If the value is increased, the picture will shift down by a pixel line, if it is decreased the picture will shift up by one pixel line. This register used in conjunction with register 12 and 13, can be used to get perfect pixel by pixel vertical scrolling. Register 6 - Vertical displayed This register defines the height of the screen in character sized units. If the value programmed is increased, the height of the screen will increase, if the value programmed is decreased, the height of the screen will decrease. The normal value programmed is 25. The height of the monitor screen is 35 characters. NOTE: We can find the height of the screen in pixel lines, by multiplying this by the value in register 9 plus 1. Height of screen = register 6 value*(register 9 value+1) Register 7 - Vertical sync position This register defines the vertical position of the screen within the monitor screen. If the programmed value is increased, the screen will shift upwards, if the programmed value is decreased, the screen will shift downwards. Therefore, using this register and register 2, it is possible to position the picture to any position on the monitor screen. Register 12 - Start Address (High) This register specifys where the screen will start in memory and how much memory is to be used to display the screen. Together with register 13, it allows the user to scroll the screen. Bit 5 and Bit 4 determine which 16k block the screen is located, in the following way: Bit 5 Bit 4 Memory block ---------------------------- 0 0 &0000-&3FFF 0 1 &4000-&8000 1 0 &8000-&C000 1 1 &C000-&FFFF In this way, the screen can be positioned almost anywhere in memory. The screen address is only changed when a VSYNC occurs. So, if you attempt to change the screen address, as the electron beam is drawing the screen, only one screen will be shown. (To change the screen address more than once a special technic called "rupture" or "hardware splitting" is needed. This special effect was developed by many coders individually (credits go to Logon System, NWC, Paul Shirley (Mission Genocide).) The CRTC cannot access the extra memory, so it will only display screens which are located in memory blocks 0-3 only, regardless of any ram configuration. (i.e. it will only display screens in the first bank of 64k). If you change the ram configuration, so that a different 16k block is switched into the area which holds the screen there will be no effect on the picture. Bit 3 and 2 determine how much memory the CRTC can use for the screen. The CRTC is capable of displaying 16k or 32k screens. Bits 3 and 2 are defined in the following way: Bit 3 Bit 2 Screen memory ----------------------------- 0 0 16k 1 0 16k 0 1 16k 1 1 32k When the CRTC is accessing 32k, you can expand the screen size so that you can have a picture which covers the borders! (overscan) When 32k is selected, the first and second screens occupy the following range of addressess: First screen Second screen ----------------------------- &0000-&3FFF &4000-&7FFF &4000-&7FFF &8000-&BFFF &8000-&BFFF &C000-&FFFF &C000-&FFFF &0000-&3FFF Bit 1 and 0 are used with register 13 to do hardware scrolling. Register 13 contains the lower 8 bits of the offset and bit 1 and 0 contain the upper 2 bits of the offset. The offset is 10 bits and defines the position of the screen within the 16k block specified in bits 5 and 4. So, by changing the value contained in register 13, and bits 1 and 0 of register 12, the screen can be scrolled. This effect is called hardware scrolling. Summary: Bit 7: Not used. Bit 6: Not used. Bit 5: } Memory block of start of screen Bit 4: } Bit 3: } Screen memory Bit 2: } Bit 1: } Offset (upper 2 bits of offset value - lower 8 bits defined Bit 0: } by register 13). Register 13 - Start Address (Low) This register defines the lower 8 bits of the offset within the selected 16k block. This register is used in conjunction with register 12 to perform hardware scrolling. Programming examples a) Programming the CRTC 1) Selecting a CRTC register, ld bc,&bc00+xx out (c),c Where xx is the register number required. e.g. To select register 12, ld bc,&bc00+12 out (c),c 2) Writing to a CRTC register, LD bc,&bd00+xx out (c),c where xx is the data to be put into the currently selected register. e.g. To put 128 into register 12, ;; select CRTC register 12 ld bc,&bc00+12 out (c),c ;; write to register 12 ld bc,&bd00+128 out (c),c 3) Reading from a CRTC register, This will not work on all CRTC types. ld bc,&bf00 in a,(c) where, the data in the register would be returned in register A e.g. ;; select CRTC register 12 ld bc,&bc00+12 out (c),c ;; read data in register 12 ld bc,&bf00 in a,(c) b) Overscan, Overscan is the effect where the screen is expanded to fill the whole monitor screen, So there are no borders remaining. It is a simple effect to use, but working out screen addressess becomes more difficult. (especially where the first screen ends and the second screen starts). To expand the screen, we use registers 1, 6, 2 and 7. Register 1 is used to set the width of the screen, register 6 the height of the screen, register 2 the horizontal position of the screen and register 7, the vertical position of the screen. When this is done, we can see that parts of the screen repeat. To overcome this, we tell the CRTC to use 32k instead of 16k. NOTE: On some CRTC types, the screen width must not exceed 48 characters otherwise it will not work. So to maintain compatibility keep the width of the screen below 48. (Aplies to CRTC type 2). The code for overscan is. ;; **** set width of screen **** ld bc,&bc00+1 out (c),c ld bc,&bd00+48 ;48 characters wide out (c),c ;; **** set height of screen **** ld bc,&bc00+6 out (c),c ld bc,&bd00+35 ;35 characters tall out (c),c ;; **** set horizontal position of screen to lefthand side **** ld bc,&bc00+2 out (c),c ld bc,&bd00+50 ;leftmost edge of screen out (c),c ;; **** set vertical position of screen to top **** ld bc,&bc00+7 out (c),c ld bc,&bd00+35 ;topmost position of screen out (c),c ;; **** tell the CRTC to use 32k for screen display **** ;; **** (also define screen memory range to be &c000-&ffff) **** ;; **** giving us the screen memory taking up &C000-&3FFF **** ld bc,&bc00+12 out (c),c ld bc,&bd00+%00111100 out (c),c So now, you should have a large screen covering the borders. It is just a matter of plotting graphics on the screen. c) Hardware scrolling Hardware scrolling is achieved by using registers 12 and 13. The effect works by changing the start address of the screen. (There is no shifting or moving of data). By doing this we can make it look like the screen is scrolling. It is important to note, that only a 16k screen can be fully scrolled. If a 32k screen is scrolled too much, it splits into a 16k screen which repeats. The screen is scrolled in character sized chunks. This produces very fast smooth hardware scrolling. However it is often too fast. Therefore, it is possible to have slower hardware scrolling by using register 3 for smoother horizontal scrolling, and register 5 for smoother vertical scrolling. It is important to note that when the screen is hardware scrolled, all sprites plotted on it will be scrolled also. So the position of sprites on the screen must be updated, the screen scrolled, and then replotted. Making the screen scroll The offset is constructed from bits 0 and 1 of register 12, and register 13. This forms a 10 bit number. (8 bits from register 13, and 2 from register 12). (&0000-&03FF) By changing the value of the offset, we scroll the screen. To scroll the screen UP, ADD the value programmed to register 1 to the offset. To scroll the screen DOWN, SUBTRACT the value programmed to register 1 from the offset. To scroll the screen RIGHT, ADD one to the offset. To scroll the screen LEFT, SUBTRACT one from the offset. In all cases we must ensure the offset remains in the range &0000- &03FF. Setting the screen offset .set_screen_offset ld hl,(scroll_offset) ;&0000-&03FF ld a,h or %00xx0000 ;where xx is the memory block the ;screen is located in. ld bc,&bc00+12 ;CRTC register 12 out (c),c ;select CRTC register 12 ld b,&bd out (c),a ;send top 2 bits of offset and memory ;block screen is located in ld bc,&bc00+13 ;CRTC register 13 out (c),c ;select CRTC register 13 ld b,&bd out (c),l ;send lower 8 bits of offset ret .scroll_offset defw 0 ;reserve 2 bytes for offset Scroll the screen to the right .scroll_right ld hl,(scroll_offset) inc hl ;add 1 ld a,h and &03 ;ensure scroll_offset is in range ;&0000-&03ff ld h,a ld (scroll_offset),hl ret Scroll the screen to the left .scroll_left ld hl,(scroll_offset) dec hl ld a,h and &03 ld h,a ld (scroll_offset),hl ret Scroll the screen up .scroll_up ld hl,(scroll_offset) ld bc,40 ;value programmed to register 1 add hl,bc ld a,h and &03 ld h,a ld (scroll_offset),hl ret Scroll the screen down .scroll_down ld hl,(scroll_offset) ld bc,40 or a sbc hl,bc ld a,h and &03 ld h,a ld (scroll_offset),hl ret d) Rupture technic/Vertical splitting THIS TECHNIQUE WAS FOUND BY MANY PEOPLE. IT IS NOT KNOWN WHO WAS THE FIRST TO FIND THIS. THERE ARE 5 GAMES I KNOW WHICH HAVE SPLITTING (MISSION GENOCIDE (Paul Shirley), ENLIGHTMENT: DRUID 2 (Firebird), SUPER CAULDRON & PREHISTORIK (Titus)). MANY DEMO PROGRAM MERS STARTED TO USE THESE EFFECTS, THESE INCLUDE LOGON DEMO TEAM AND NWC. ALL CREDITS TO THESE PEOPLE. This technic is used widely in demos. Normally the screen address can only be changed once. The CRTC only allows the screen address to be changed when a VSYNC occurs, i.e. when the beam has finished drawing the screen and moves back to the top-left again, so that it can start again. This technic fools the CRTC into thinking a VSYNC has occured, so that you can change the screen address. So you can change the screen address anywhere on the screen. This allows you to do amazing things. e.g. the top part of the screen scrolling (using hardware), whilst the lower part is stationary. (As seen in Super Cauldron and Prehistorik II). Both of the sections of the screen can start at a different memory location. So this technic is very flexible. But it is not an easy technic to do. Many times, the screen will flicker and look wrong, but persever and it will work. Also, once you do get it to work, check it on different CRTC types. (You can find out a CRTC type, by running a demo which has CRTC detection in it - like VOYAGE 93 by BENG!). Also, you can achieve overscan by using this technic. To set-up the split is easy enough. a) First the interrupt vector must be set so that it does nothing. b) Then every frame-flyback/VYSNC, put &ff into register 7 of CRTC c) Then put in split values to seperate screen up. d) Then in bottom of screen, put &00 into register 7 of CRTC. The interrupts effectively split the screen into 6 blocks. So we can easily wait for an interrupt to occur by using a HALT instruction, then we can program the split values. (This code can be found in the file splitshell.s). Since we change the interrupt vector to something different, the keyboard will not be scanned or anything done, so all this has to be done, by programming the hardware directly. Now to actually setup the splits, we use register &4 of CRTC. Simply program the height of the block you want (in character sized units)-1. Then before the block will end, program a new block height. The total height of the screen is 38 characters tall. So, all the blocks heights should add up to 38. So lets say, we want the screen split in half. We want, two blocks of height 19 characters, top block using memory at &4000-&8000, the second using memory at &C000-&FFFF. The code would be: (Here is another example of splitting split.s) org &4000 di ;change interrupt vector ld hl,&c9fb ld (&0038),hl ei ;;splitting part .main_loop ld b,&f5 ;wait for frame flyback/VSYNC .no_VSYNC in a,(c) rra jp nc,no_VSYNC ld bc,&bc00+7 out (c),c ld bc,&bdff out (c),c ;INITIALISE SPLIT **IMPORTANT** ld bc,&bc04 out (c),c ld bc,&bd00+19-1 ;height of first block out (c),c halt ;wait 6.5 lines ld bc,&bc00+12 ;screen address to &C000-&FFFF out (c),c ld bc,&bd00+%00110000 out (c),c ld bc,&bc00+13 out (c),c ld bc,&bd00 out (c),c halt ;wait 6.5 lines halt ld b,15 ;allow compatibility .wait djnz wait ;with other CRTCs ld bc,&bc04 out (c),c ld bc,&bd00+20-1 ;height of second block out (c),c halt halt halt ld bc,&bc00+7 ;also for initialisation of split out (c),c ;** IMPORTANT ** ld bc,&bd00 out (c),c ld bc,&bc00+12 out (c),c ld bc,&bd00+%00010000 ;screen address to &4000 out (c),c ld bc,&bc00+13 out (c),c ld bc,&bd00 out (c),c jp main_loop (Split modified by Pierre Guerrier)