;; This example shows how to make a vertical split/rupture. ;; ;; A vertical split/rupture is used to divide the display (in the vertical dimension) ;; into more than one block. Each block spans the entire width of the display, ;; can have a programmable height and it's own start address. ;; Therefore parts of the screen can be scrolled while other parts remain static. ;; The split is another method to make overscan, but the split must be refreshed ;; every frame for the effect to be maintained. The split can also require exact ;; timing. ;; ;; When making a split, be aware of the differences in the CRTC models used by Amstrad. ;; (HD6845S/UM6845 (type 0), UM6845R (type 1), MC6845 (type 2), CPC+ CRTC inside ASIC ;; (type 3), CPC CRTC inside Pre-ASIC in cost-down CPCs (type 4)). ;; You will certainly notice the difference between these CRTCs when you program splits. ;; ;; The split is not a new effect, it has been used in some games (i.e. Mission Genocide, Octoplex ;; Prehistorik 2, Super Cauldron and Snowstrike, to name a few), and many demos. ;; This effect was made popular by demo groups such as Logon System. ;; ;; This method is technical and requires good understanding of the operation ;; of the CRTC. ;; ;; Extensive comments have been included to explain the operation of the split ;; and the reasons for every CRTC register write. ;; ;; Abreviations used: ;; ;; VADJC = internal Vertical Adjust Count register of the CRTC ;; VC = internal Vertical Count register of the CRTC ;; RC = internal Raster Count register of the CRTC ;; HC = internal Horizontal Count register of the CRTC ;; HTOT = Horizontal total register of CRTC (register 0) ;; HDISP = Horizontal displayed register of CRTC (register 1) ;; VTOT = Vertical total register of CRTC (register 4) ;; VSYNCPOS = Vertical sync position register of CRTC (register 7) ;; VSYNC = The vertical sync signal. This can be monitored through PPI port B. ;; HSYNCWIDTH = Horizontal sync width (programmed by register 3 of the CRTC) ;; HSYNCPOS = Horizontal sync position register of CRTC (register 2) ;; HDISP = Horizontal displayed register of CRTC (register 1) ;; VADJ = Vertical adjust register of CRTC (register 5) ;; MR = Maximum raster register of CRTC (register 9) ;; ;; (c) Kevin Thacker, 2002 ;; ;; This code has been released under the GNU Public License V2. org &4000 nolist ;;------------------------------------------------ ;; install a interrupt handler di ;; disable interrupts im 1 ;; interrupt mode 1 (CPU will jump to &0038 when a interrupt occrs) ld hl,&c9fb ;; C9 FB are the bytes for the Z80 opcodes EI:RET ld (&0038),hl ;; setup interrupt handler ;; the interrupt handler we have setup is minimal: ;; ;; EI ;; RET ;; ;; This will re-enable interrupts and then return to program control. ;; ;; We know the CPU time taken for the interrupt handler because we have defined ;; the interrupt handler and the timing of the instructions is known. ;; ei ;; re-enable interrupts ;;-------------------------------------------------------------------------- ;;------------------------------------------------ ;; define the horizontal and vertical sync widths ;; ;; the vertical sync width is programmable on CRTC type 0, type 3 and type 4. ;; the vertical sync width is fixed on CRTC type 1 and type 2. ;; ;; the horizontal sync width is programmable on all CRTC types. ;; ld bc,&bc03 ;; select vertical and horizontal sync register of the CRTC out (c),c ld bc,&bd00+8 ;; set vertical sync width = 16, horizontal sync width = 8 out (c),c ;;------------------------------------------------ ;; define the horizontal sync position ;; ;; With the vertical split, this is used to position the screen horizontally ;; within the display. Increasing this value will move the screen to the left ;; decreasing this value will move the screen to the right. ;; ;; Note that on CRTC type 2, (HSYNCPOS+HSYNCWIDTH)0, instruction will execute in 4us. ;; ld b,127 ;; [2] .wait1 djnz wait1 ;; [3/4] ;; for this loop: ;; ;; (14*4)+3+2 = 513 us ;;----------------------------------------------------------------------------------- ;; set the start address of the *next* split block ;; ;; - for CRTC type 0,2,3 and 4, this start address will take effect at the start ;; of the next split block. ;; - for CRTC type 1, it is possible to reprogram the start address of the current ;; split block if VC=0, otherwise this start address will take effect at the start ;; of the next split block. ;; ;; For compatibility with other CRTC types, attempt to change the start position ;; when VC>0 and VC<(VTOT-1). ;; ;; NOTE: the start address of the first split block is defined at the end of the loop ld hl,&1000 ;; start address in CRTC form (&4000 - &7fff in RAM) ld bc,&bc0c ;; start address high register of CRTC out (c),c ;; select start address high register of CRTC inc b ;; B = &BD out (c),h ;; write data to start address low register ld bc,&bc0d ;; select start address low register of CRTC out (c),c ;; select start address low register of CRTC inc b ;; B = &BD out (c),l ;; write data to start address low register ;----------------------------------------------------------------------------- halt ;; in this example, the CRTC has completed 2 + 52 monitor scanlines ;; since the start of the VSYNC. ;; ;; In this example HTOT and HSYNC remain constant, therefore the amount of time ;; that has passed is: ;; ;; (HTOT+HSYNCPOS)+(HTOT-HSYNCPOS)+(51*HTOT)+HSYNCPOS ;; ;; where (HTOT+HSYNCPOS) is the time to the first interrupt request, ;; (HTOT-HSYNCPOS) is the time from the first interrupt request to the first HTOT ;; after the interrupt request, ;; (51*HTOT)+HSYNCPOS is the time to the second interrupt request. ;; ;; approx 6.75 scanlines ld b,15 .wait2 djnz wait2 ld bc,&bc04 out (c),c ld bc,&bd00+24 out (c),c ;------------------------------------------------------------------------------ ;blk3 halt ;------------------------------------------------------------------------------ halt ld b,15 .wait4 djnz wait4 ld bc,&bc0c out (c),c ld bc,&bd00 out (c),c ld bc,&bc0d out (c),c ld bc,&bd00 out (c),c halt halt ld b,15 .wait6 djnz wait6 ld bc,&bc04 out (c),c ld bc,&bd00+5 ;5+25+6=36 (nearly 39!) out (c),c ld bc,&bc0c out (c),c ld bc,&bd00+%00010000 ;top section of screen out (c),c ld bc,&bc0d out (c),c ld bc,&bd00 out (c),c ;;------------------------------------------------------------- ;; To maintain a steady split we must do the following: ;; - ensure the register writes to the CRTC occur at the same position every frame ;; - force a VSYNC to be generated once per frame, once per 312 complete (64us) scan-lines ;; (once every 19968us) ;; ;; If we want a steady split that will work on every CRTC type: ;; - ensure the register writes to the CRTC occur at a time that is compatible with ;; every CRTC ;; reprogram a new vertical sync position to force a VSYNC to be triggered. ;; ;; We want our VSYNC to start on VC=0, RC=0, HC=0. ;; ;; - If VC<>0 then the VSYNC will be triggered at the start of the next split (VC=0, RC=0, HC=0). ;; - If VC==0, then on some CRTC's a VSYNC will be triggered immediatly (VC=0, RC!=0, HC=??), this ;; could cause a bad split if our split requires that the VSYNC must occur when VC=0, RC=0, HC=0)! ;; ld bc,&bc07 ;; vertical sync position register of the CRTC out (c),c ;; select vertical sync position of the CRTC ld bc,&bd00 ;; vertical sync position = 0 out (c),c ;; set vertical sync position ;;---------------------------------------- ;; continue to loop so that the split is maintained jp main_loop