;; This example shows how to scroll the screen horizonatally using the ;; CPC+ "soft" hardware scroll. This scroll is smooth because it will scroll ;; a pixel at a time. ;; ;; This example will only work on the CPC+. ;; ;; The scroll is made by changing the start of the screen using the CRTC, ;; (which will scroll the screen vertically by the number of scanlines defined by register 9), ;; and a scan-line adjustment defined using the CPC+ "soft" hardware scroll register. ;; Scroll a mode 0 screen by mode 2 pixel scroll amount ;; The location of this code is important. It must not be located ;; between &4000-&7fff. org &8000 nolist scr_set_mode equ &bc0e txt_output equ &bb5a scr_initialise equ &bbff ;; reset colours call scr_initialise xor a call scr_set_mode ld bc,24*20 ld d,' ' l1: inc d ld a,d cp &7f jr nz,no_char_reset ld d,' ' no_char_reset: ld a,d call txt_output dec bc ld a,b or c jr nz,l1 ;;---------------------------------------------------------------------- ;; unlock asic to gain access to asic registers di ld b,&bc ld hl,sequence ld e,17 .seq ld a,(hl) out (c),a inc hl dec e jr nz,seq ei ;;---------------------------------------------------------------------- ;; install a interrupt handler ;; ;; We install our own interrupt handler for this reason: ;; - To stop the firmware interrupt from being executed, this will ;; ensure that our direct access to the hardware will not be interrupted ;; by the firmware, and that the values we write are not re-written by ;; the firmware. di ;; disable interrupts im 1 ;; set interrupt mode 1 (jump to &0038 when interrupt occurs) ld hl,&c9fb ;; EI:RET ld (&0038),hl ;; &0038 is executed ei ;;---------------------------------------------------------------------- ;; main loop .main_loop ;; wait for start of vsync. This test assumes that the start of the vsync ;; has not yet happened. ld b,&f5 .ml2 in a,(c) rra jr nc,ml2 ;; The vsync has just started, we can safely setup the scroll ;; without the display being effected. ;;----------------------------------------------------------------------- ;; update vertical scan-line scroll adjustment ;; page in ASIC ram ;; ASIC registers will be paged into memory range &4000-&7fff ld bc,&7fb8 out (c),c ;; get scan-line scroll adjustment ld a,(horz_pixel_offset) ;; bits 3..0 define the horizontal pixel scroll offset ;; bits 6..4 define the vertical scanline scroll offset ;; write to "soft" hardware scroll register of CPC+ ld (&6804),a ;; page out ASIC ram ld bc,&7fa0 out (c),c ;;----------------------------------------------------------------------- ;; update CRTC with scroll offset ld hl,(scroll_offset) ;; get scroll offset ld a,h or &30 ;; This defines the "base" of the screen in 16k units. ;; &00 -> screen uses &0000-&3fff ;; &10 -> screen uses &4000-&7fff ;; &20 -> screen uses &8000-&bfff ;; &30 -> screen uses &c000-&ffff ld h,a ld bc,&bc0c ;; select CRTC register 12 out (c),c inc b ;; B = &BD out (c),h ;; write to CRTC register 12 dec b inc c ;; BC = &BC0D out (c),c ;; select CRTC register 13 inc b out (c),l ;; write to CRTC register 13 ;;---------------------------------------------------------------------- ;; we need to wait long enough for the VSYNC signal to finish, so that the ;; test at the beginning of this loop will synchronise with the *start* of the ;; vsync. ;; this first HALT will catch the interrupt that occurs two scanlines from ;; the start of the VSYNC, the second will delay a furthur 52 scanlines. The maximum ;; duration for the VSYNC is 16 scanlines. halt halt ;; update the scroll ready for the next update of the display call scroll_right ;; loop jp main_loop ;;---------------------------------------------------------------------- ;; adjust scroll parameters to scroll the screen right ;; ;; Each CRTC character is 2 bytes. ;; ;; In mode 0 there are 2 pixels per byte, there are 4 pixels for each CRTC character. ;; In mode 1 there are 4 pixels per byte, there are 8 pixels for each CRTC character. ;; In mode 2 there are 8 pixels per byte, there are 16 pixels for each CRTC character. ;; ;; The horizontal pixel scroll offset is defined for mode 2 resolution. ;; Pixels in mode 1 are twice the width of mode 2 pixels. ;; Pixels in mode 0 are four times the width of mode 2 pixels. ;; ;; The horizontal pixel scroll offset is updated for every pixel. ;; The CRTC scroll offset is updated for every CRTC character (every 16 pixels in mode 2 ;; OR every 8 pixels in mode 1 OR every 4 pixels in mode 0). .scroll_right ;; get horizontal pixel scroll offset ld a,(horz_pixel_offset) sub 1 ;; increments for pixel scrolling: ;; 1 for mode 2 ;; 2 for mode 1 ;; 4 for mode 0 and &f ld (horz_pixel_offset),a cp &f ret nz ;; by now we have scrolled through: ;; - 16 pixels in mode 2 ;; - 8 pixels in mode 1 ;; - 4 pixels in mode 0 ;; get the crtc scroll offset ld hl,(scroll_offset) inc hl ;; update offset ld a,h ;; ensure the scroll offset is in the range &300-&3ff and &3 ld h,a ;; store the crtc scroll offset ld (scroll_offset),hl ret ;;---------------------------------------------------------------------- ;; scroll offset of the screen to be written to CRTC register 12 and 13 ;; This value is defined in "CRTC" characters. .scroll_offset defw 0 ;;---------------------------------------------------------------------- ;; holds a number between 0 and 15 which is the pixel offset ;; for the scroll .horz_pixel_offset defb 0 ;;---------------------------------------------------------------------- ;; this is the sequence to unlock the ASIC extra features .sequence defb &ff,&00,&ff,&77,&b3,&51,&a8,&d4,&62,&39,&9c,&46,&2b,&15,&8a,&cd,&ee