Code: Select all
;
; Example Pixel Scrolling Attribute Blocks Code
;
; by: Jason J Railton
; for: Spectrum Computing
;
; dated: February 2024
; license: Free use by anyone.
;
;Macros and Definitions
;----------------------
START_ADDRESS EQU 32768
SCREEN EQU 16384
SCREEN_SIZE EQU 6144
ATTRS EQU 22528
ATTRS_SIZE EQU 768
INTERRUPT_I EQU 254
INTERRUPT_TABLE EQU 254*256
INTERRUPT_V EQU 253
INTERRUPT_VECTOR EQU 253*257
STACK_POINTER EQU 65536
MACRO PAGE_ALIGN
defs (65536-$)AND 255
ENDM
MACRO WAIT_VBL
ei
halt
ENDM
;------------------------------------
;Initial entry point
;------------------------------------
ORG START_ADDRESS
entry_point
;Initialise
;----------
di
ld sp,STACK_POINTER
xor a
out (254),a
ld a,0
call cls
call memory_prep
;Prepare landscape
;-----------------
ld ix,landscape
ld iy,landscape
ld hl,spare_mem
; Do 24 rows:
ld c,24
prep_attrs_loop_1
; Copy 31 bytes, moving the colour of a cell up to PAPER
; in the attribute byte, then OR the next cell colour
; as INK, then set BRIGHT bit:
ld b,31
prep_attrs_loop_2
ld a,(ix)
rlca
rlca
rlca
or (ix+1)
or 64
ld (hl),a
inc ix
inc hl
djnz prep_attrs_loop_2
; The 32nd byte must wrap-around with the first one:
ld a,(ix)
rlca
rlca
rlca
or (ix-31)
or 64
ld (hl),a
inc ix
inc hl
; Now repeat, so the cached landscape is actual 64 bytes wide:
ld b,31
prep_attrs_loop_3
ld a,(iy)
rlca
rlca
rlca
or (iy+1)
or 64
ld (hl),a
inc iy
inc hl
djnz prep_attrs_loop_3
ld a,(iy)
rlca
rlca
rlca
or (iy-31)
or 64
ld (hl),a
inc iy
inc hl
dec c
jp nz,prep_attrs_loop_1
;Main Program
;------------
ld ixl,0 ; Scroll position, 0-255 pixels
ld iyl,0 ; Scroll speed, just increases
repeat_forever
WAIT_VBL
ld (restore_sp_1),sp ; Write stack pointer into code at its restore point
ld a,0
out (254),a ; Timing marker
; Work out where in the landscape cache to copy from.
; Scroll position IXL is shifted down 3 bits,
; dividing by 8:
ld hl,spare_mem
ld a,ixl
rrca
rrca
rrca
and 31
ld b,0
ld c,a
add hl,bc
; Copy the attributes from the landscape cache,
; 26 bytes at a time, leaving 3 characters either
; side of the screen unused:
ld de,ATTRS+64+3
ld a,22
copy_attrs_loop
REPT 26
ldi
ENDM
ld bc,64-26
add hl,bc
ex de,hl
ld c,32-26
add hl,bc
ex de,hl
dec a
jp nz,copy_attrs_loop
ld hl,scroll_list
ld a,ixl
and 7
ld b,0
ld c,a
add hl,bc
ld b,(hl)
ld c,(hl)
; Now push a pre-shifted pixel pattern over the
; attribute area. As pixels slide into each character
; cell from the right, so the INK colour takes over,
; and the colour block from the right appears to
; move over:
ld de,push_line_table+32
ld a,176
pixel_row_loop
ex af,af'
ld a,(de)
ld l,a
inc de
ld a,(de)
ld h,a
inc de
ld sp,hl
REPT 13
push bc
ENDM
ex af,af'
dec a
jp nz,pixel_row_loop
;And that's it. Now just tidy up:
restore_sp_1 EQU $+1
ld sp,0000 ; Restore stack pointer
ld a,1
out (254),a ; Timing marker
; Increment scroll speed:
inc iyl
; Divide by 16. Then it can only be from 0..15:
ld a,iyl
rrca
rrca
rrca
rrca
and 15
cp 8
jp c,no_tweak
; If in the range 8..15, subtract 15 and negate.
; This means the number ramps up from 0 to 7,
; then ramps down to 0 again:
sub 15
neg
no_tweak
; Add the scroll speed to the scroll position, which
; will wrap around at 256 pixels and return to 0 again:
add a,ixl
ld ixl,a
jp repeat_forever
; Prepared scroll data. Just solid pixels rolling in
; to a byte from the right:
scroll_list
defb 00000000b
defb 00000001b
defb 00000011b
defb 00000111b
defb 00001111b
defb 00011111b
defb 00111111b
defb 01111111b
;------------------------------------
; Interrupt handler routine
;------------------------------------
interrupt_handler
ret
;------------------------------------
; Initialise memory, interrupts, etc.
;------------------------------------
memory_prep
;Setup Interrupts
;----------------
ld hl,INTERRUPT_TABLE
ld de,INTERRUPT_TABLE+1
ld bc,256
ld (hl),INTERRUPT_V
ldir
ld a,$C3 ; 'JP'
ld (INTERRUPT_VECTOR),a
ld hl,interrupt_handler
ld (INTERRUPT_VECTOR+1),hl ; JP jump address filled-in
ld a,INTERRUPT_I
ld i,a
im 2
ret
;------------------------------------
; Standard Functions:
;------------------------------------
;Screen Clear
;------------
cls
ld hl,ATTRS
ld de,ATTRS+1
ld bc,ATTRS_SIZE-1
ld (hl),a
ldir
ld hl,SCREEN
ld de,SCREEN+1
ld bc,SCREEN_SIZE-1
ld (hl),0
ldir
ret
;------------------------------------
;Screen Address Tables
;------------------------------------
push_line_table
REPT 3,pixel_line_third
REPT 8,pixel_line_char
REPT 8,pixel_line_each
defw SCREEN+(pixel_line_third*2048)+(pixel_line_char*32)+(pixel_line_each*256)+29
ENDM
ENDM
ENDM
;------------------------------------
landscape
DEFB 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,4,4,4,4, 4,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5
DEFB 5,5,5,4,4,4,0,4, 4,4,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5
DEFB 5,5,5,4,4,0,6,0, 4,4,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,4,4,4,4
DEFB 5,5,5,4,4,4,0,4, 4,4,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,4,1,4,1
DEFB 5,5,5,4,5,4,6,4, 5,4,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,3,6,3,6
DEFB 5,5,5,5,5,5,0,5, 5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, 5,5,5,5,7,3,6,2
DEFB 5,5,5,5,5,5,6,5, 5,5,5,5,5,5,5,5, 4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,0,5, 5,5,5,5,5,5,5,5, 4,1,4,1,4,1,4,1, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,6,5, 5,5,5,5,5,5,5,5, 3,6,3,6,3,6,3,6, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,0,5, 5,5,5,5,5,5,5,5, 7,3,6,3,6,3,6,2, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,6,5, 5,5,5,5,4,4,4,4, 4,4,4,4,3,6,3,6, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,0,5, 5,5,5,5,4,1,4,1, 4,1,4,1,6,3,6,2, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,6,5, 5,5,5,5,3,6,3,6, 3,6,3,6,3,6,3,6, 5,5,5,5,5,5,5,5
DEFB 5,5,5,5,5,5,0,5, 5,5,5,5,7,3,6,3, 6,3,6,2,6,3,6,2, 5,5,5,5,5,5,5,5
DEFB 4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4
DEFB 4,1,4,1,4,1,4,1, 4,1,4,1,4,1,4,1, 4,1,4,1,4,1,4,1, 4,1,4,1,4,1,4,1
DEFB 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6
DEFB 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3
DEFB 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6
DEFB 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3
DEFB 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6, 3,6,3,6,3,6,3,6
DEFB 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3, 6,3,6,3,6,3,6,3
spare_mem
;------------------------------------
end entry_point
;------------------------------------
For a game, you'd probably want to be just behind the raster, so you can add sprites once the landscape is drawn. And, once past the 4-pixel position, invert the attributes so that a character square is always dominated by its PAPER colour, for when you draw sprites on top and lose some of the scroll block pixels.