Programming:Hardware scrolling the screen horizontally byte-by-byte using the CRTC
From CPCWiki - THE Amstrad CPC encyclopedia!
;; Smooth horizontal scroll ;; ;; This code demonstrates a method to scroll the screen, using the hardware, ;; in byte size units. ;; ;; This is equivalent to: ;; - 2 pixels in mode 0, ;; - 4 pixels in mode 1, ;; - 8 pixels in mode 2. ;; ;; The standard hardware scroll method, using register 12 and 13 alone, will ;; scroll the screen in 2 byte units (the width of a CRTC character). ;; ;; This is equivalent to: ;; - 4 pixels in mode 0, ;; - 8 pixels in mode 1, ;; - 16 pixels in mode 2. ;; ;; So this method provides a method for smoother scroll in the horizontal ;; direction. ;; ;; The effect relies on the reaction of the monitor to the horizontal sync from ;; the CRTC so it is only guaranteed to work properly on a real Amstrad CPC ;; with an Amstrad monitor. ;; ;; At best, this method will result in a smooth scroll, but at worse the scroll ;; will be far from smooth. The parameters may need adjusting for other CRTC ;; models. ;; ;; Use O and P to scroll the screen left and right. ;; ;; This scroll method can be used on CPC,CPC+ and KC Compact. ;; the position of this code is not important org &4000 .km_read_key equ &bb1b .mc_wait_flyback equ &bd19 .scr_set_mode equ &bc0e .txt_output equ &bb5a ;; set the screen mode ld a,1 call scr_set_mode ;; display a message (so we can see how the screen is scrolling; by the movement ;; of the message) ld hl,message call display_message .loop ;; wait for vsync ;; ;; (synchronises scroll with the screen refresh; as a result it ;; updates at a constant rate and is smooth) call mc_wait_flyback ;; write scroll parameters to hardware call update_scroll ;; check if any keys are pressed (they will update the scroll offset) call check_keys ;; delay long enough for the vsync to become inactive ;; so that mc_wait_flyback will synchronise with the start of the ;; vsync. halt halt ;; loop jp loop ;;---------------------------------------------------------------------- .check_keys ;; test if any key has been pressed call km_read_key ret nc ;; A = code of the key that has been pressed ;; ;; check the codes we are using and handle appropiatly. cp 'O' ; O jp z,scroll_left cp 'P' ; P jp z,scroll_right ret ;;---------------------------------------------------------------------- .scroll_left ld a,(scroll_adjustment) xor 1 ;; 0->1->0... ld (scroll_adjustment),a or a ret z ;; get current scroll offset ld hl,(scroll_offset) ;; update it dec hl ;; ensure scroll offset is in range &000-&3ff ld a,h and &3 ld h,a ;; store new scroll offset. It is now ready to be written to the CRTC. ld (scroll_offset),hl ret ;;---------------------------------------------------------------------- .scroll_right ld a,(scroll_adjustment) xor 1 ;; 0->1->0... ld (scroll_adjustment),a or a ret z ;; get current scroll offset ld hl,(scroll_offset) ;; update it inc hl ;; ensure scroll offset is in range &000-&3ff ld a,h and &3 ld h,a ;; store new scroll offset. It is now ready to be written to the CRTC. ld (scroll_offset),hl ret ;;-------------------------------------------------------------------------------------------- .update_scroll ;; write scroll adjustment ld a,(scroll_adjustment) add &f5 ;; This value alternates between &F5 and &F6 ;; and controls the horizontal position of the visible ;; area on the monitor display. The effect these ;; values have on the position relies on the reaction ;; of the monitor to the horizontal sync output of ;; the CRTC. So for some monitors this may not result ;; in a smooth scroll as we want. This value may need ;; adjustment for your monitor and CRTC variant. ;; ;; From BASIC try the following two lines to see the ;; screen move, which is the basis of this effect: ;; ;; OUT &BC00,3:OUT &BD00,&F5 and ;; OUT &BC00,3:OUT &BD00,&F6 ld bc,&bc03 ;; select CRTC register 3 (horizontal sync width) out (c),c inc b out (c),a ;; set vertical and horizontal sync widths ld hl,(scroll_offset) ;; write scroll offset (in CRTC character width units) ld bc,&bc0c ;; select CRTC register 12 out (c),c ld b,&bd ;; B = I/O address for CRTC register write ;; combine with scroll base ld a,(scroll_base) or h out (c),a ld bc,&bc0d ;; select CRTC register 13 out (c),c ld b,&bd ;; B = I/O address for CRTC register write out (c),l ret ;;---------------------------------------------------------------------- ;; scroll parameters .scroll_adjustment defb 0 ;; high byte of the screen base address ;; &00 -> screen uses &0000-&3fff ;; &10 -> screen uses &4000-&7fff ;; &20 -> screen uses &8000-&bfff ;; &30 -> screen uses &c000-&ffff .scroll_base defb &30 ;; the scroll offset in CRTC character units .scroll_offset defw 0