ZX81 Assembly Listing for pim.asm


ZX81 assembly listing for PICTURE IN MOTION*SLR/2021

PICTURE IN MOTION*SLR/2021 (pim.asm)

This is an updated version of “The Picture” written in assembly using a line drawing routine by Simeon Dwyer. This version uses a double buffer to move the boat.


ASSEMBLY PROGRAM LISTING

;
; Picture in Motion
; v1.00 Steven Reid (c) 2021
; This is an assembly version of my old BASIC drawring routine.
; Trying out a double buffer idea and seeing if I can move the
; boat.
;

        org 16514               ; stored in REM at top
        jr start                ; needed for z80asm

; title and copyright
copy:
        db $00,$27,$3e,$00,$38,$39,$2a,$3b,$2a,$33
        db $00,$37,$2a,$2e,$29,$00,$1e,$1c,$1e,$1d
        db $00,$17,$00,$17,$00,$35,$2e,$28,$39,$3a
        db $37,$2a,$00,$2e,$33,$00,$32,$34,$39,$2e
        db $34,$33,$00,$17,$00,$17,$76,$76
        ;  BY STEVEN REID 2021
        ;  * * PICTURE IN MOTION * *

; macros
kscan:          equ $02bb
findchar:       equ $07bd
stop:           equ $0cdc
slow:           equ $0f2b
printat:        equ $08f5
pause:          equ $0f35

; system vars
frames:         equ 16436
d_file:         equ $400c

; variables
offset:         dw 0
boatoffset:
xoffset:        db 0
yoffset:        db 0
direction:      db 0


;
; Start of program!
;
start:

        ld hl,0                 ; reset offset
        ld (offset),hl
        ld (boatoffset),hl
        ld (yoffset),hl

mainloop:
        call getkeypress        ; delay and get key
        cp $36                  ; pressed 'Q'?
        jp z,done               ; yes, we are done!

        call clearbuffer        ; clear the buffer first

        ld hl,0                 ; reset offset
        ld (offset),hl
        ld hl,picturedata       ; print sun and horizion
        call printpicture


        ld hl,(boatoffset)      ; reset offset
        ld (offset),hl
        ld hl,boatdata          ; print boat
        call printpicture
        call copy2screen

        ld a,(direction)        ; get direction
        and a
        jp nz,down

up:
        ld a,(yoffset)          ; get x offset
        dec a                   ; increment a
        ld (yoffset),a          ; save it back
        cp 256-2                ; is a too high?
        jp nz,mainloop          ; yep, done!

        ; change direction!
        ld a,1
        ld (direction),a
        jp mainloop

down:
        ld a,(yoffset)          ; get x offset
        inc a                   ; increment a
        ld (yoffset),a          ; save it back
        cp 0                    ; is a too high?
        jp nz,mainloop          ; yep, done!

        ; change direction!
        ld a,0
        ld (direction),a
        jp mainloop

done:
        jp stop                 ; all done

printpicture:
        ld a,(hl)               ; check if we are at the end of the array
        cp $ff
        ret z

        ; old way
;        ld de,linecoords        ; coordiantes (to)        
;        ld bc,4                 ; 4 to copy!
;        ldir                    ; copy coordinates

        ; new with offset
        ld b,(hl)               ; grab x0
        ld a,(offset)           ; grab offset
        add a,b                 ; get new x0
        ld (linecoords),a       ; load into linecoords
        inc hl

        ld b,(hl)               ; grab y0
        ld a,(offset+1)         ; grab offset
        add a,b                 ; get new y0
        ld (linecoords+1),a      ; load into linecoords
        inc hl

        ld b,(hl)               ; grab x1
        ld a,(offset)           ; grab offset
        add a,b                 ; get new x1
        ld (linecoords+2),a      ; load into linecoords
        inc hl

        ld b,(hl)               ; grab y1
        ld a,(offset+1)         ; grab offset
        add a,b                 ; get new y1
        ld (linecoords+3),a      ; load into linecoords
        inc hl

        push hl                 ; save hl
        call draw_line          ; and go draw the line!
        pop hl                  ; restore hl

        jp printpicture         ; loop until out of data!

;
; Copy buffer to screen
;
copy2screen:
        ld de,(d_file)
        ld hl,buffer
        ld bc,727
        ldir
        ret
;
; Copy screen to buffer
;
copy2buffer:
        ld de,buffer
        ld hl,(d_file)
        ld bc,727
        ldir
        ret

;
; Clear buffer
;
clearbuffer:
        ld de,emptyline-33
        ld hl,emptyline
        ld a,22
cbloop:
        ld bc,33
        lddr
        dec a
        jp nz,cbloop
        ret

;waitloop:
;        ld   bc,1000
;        call pause
;        jp start

;        jp z,stop               ; all done

rval:   db 10                   ; range value storage
rnd:
        ld bc,0			; get the pointer in ROM
        ld (rval),a             ; save seed into rval
	ld hl,(frames)		; for randomness get framecounter
	add hl,bc		; add framecounter
	dec hl			; when framecounter is unchanged make sure a change is done
	ld a,h			; H can have any value, but ROM is #0000-#1FFF
	and $0f			; only #0000-#0f00 is what we use
	ld h,a			; set pointer back within ROM
	ld (rnd+1),hl		; save current pointer (selfmodifying code!!!)
        ld a,(rval)             ; grab range value
        ld b,a                  ; put in b
	ld a,(hl)		; get value in ROM
rrange:	sub b			; we need 0-rval only
	jr nc,rrange
	adc a,b		        ; undo last subtraction, range 1-rval
	ret			; back to mainprogram

getkeypress:
        call delay              ; call delay

        call kscan              ; get key press?
        ld b,h
        ld c,l
        ld d,c
        inc d                   ; this is what we'll test
        ld a,1                  ; ld a with 1
        ret z                   ; return if no key press

        call findchar           ; yep, grab character pressed
        ld a,(hl)

        ret                     ; return

delay:          ; delay loop
        ld a,90
        call rnd
        dec a
        ld b,a
        ld c,0
;        ld bc,9000          ; a timed delay. Altering the
lpdel:  dec bc              ; initial value of BC changes
        nop
        ld a,b
        or c
        jr nz,lpdel
        ret

; End of loop!
;

        ;x can be 0 to 63
        ;y can be 0 to 45

picturedata:   ; start x1,y1 and end x2,y2 - 4 bytes per line
        db 0,22,38,22   ; horizon
        db 53,22,64,22

        db 4,4,9,4      ; sun
        db 8,4,10,5
        db 9,5,9,7
        db 9,6,7,8
        db 8,8,4,8
        db 4,8,2,7
        db 2,7,2,6
        db 2,6,4,5
        db $ff          ; array done!

boatdata:
        db 25,38,61,38  ; boat bottom
        db 60,38,55,41
        db 55,41,30,41
        db 30,41,25,39

        db 48,38,48,8   ; mast

        db 48,8,45,11   ; flag
        db 45,11,48,11

        db 48,12,26,35  ; sails
        db 26,35,60,35
        db 59,35,48,12
        db $ff          ; array done!

;
; Routines
;

;start code line

zxplot:
        ;alter pixel nominated by plotx and ploty
        ;plotmodes are flag2 bit 1. 0 = plot, 1 = unplot
        ;x can be 0 to 63
        ;y can be 0 to 45

        call calculate_origin


nozxplotcolour:
        ld a,(flag2)
        bit 1,a
        jp nz,unplot_pixel
        call plot_pixel

        ret
; end zxplot


calculate_origin:
        ; work out what square on the screen the pixel appears at
        ld a,(plotx)
        bit 7,a
        ret nz
        sub 64
        ret p

        ld a,(ploty)
        bit 7,a
        ret nz
        sub 46
        ret p

        ld a,$00
        ld (plotsector),a

        ld a,(plotx)
        srl a
        ld (plotx),a
        jr nc,pixelleft
        ld a,$01
        ld (plotsector),a  ;pixel is in right half

pixelleft:
        ld a,(ploty)
        srl a
        ld (ploty),a
        jr nc,pixelup
        ld a,(plotsector)
        set 1,a
        ld (plotsector),a  ;pixel is in lower half

pixelup:
        ;now find the correct screen position

;        ld hl,(d_file)
        ld hl,buffer
        inc hl
        ld de,33
        ld a,(ploty)
        cp $0
        jr z,findx
        ld b,a

findy:
        add hl,de
        djnz findy

findx:
        ld de,$00
        ld a,(plotx)
        ld e,a
        add hl,de

        ld (plot_origin), hl

        ret

plot_pixel:
; plot the pixel in the co-ord from plot_origin (square on screen) and
; plotsector (actual pixel)
;   0= top left, 1 = top right, 2 = bottom left, 3 = bottom right

        ld hl,(plot_origin)

        ld a,(plotsector)
        cp $00
        jr z,plottl
        cp $01
        jr z,plottr
        cp $02
        jr z,plotbl
        cp $03
        jr z,plotbr

        ret


plottl: ;top left quadrant
        ld a,(hl)

plottlok:
        bit 7,a
        jr nz,tlinvert
        set 0,a
        ld (hl),a
        ret

tlinvert:
        res 0,a
        ld (hl),a
        ret

plottr: ;top right quadrant
        ld a,(hl)

plottrok:
        bit 7,a
        jr nz,trinvert
        set 1,a
        ld (hl),a
        ret

trinvert:
        res 1,a
        ld (hl),a
        ret

plotbl: ;bottom left quadrant
        ld a,(hl)

plotblok:
        bit 7,a
        jr nz,blinvert
        set 2,a
        ld (hl),a
        ret

blinvert:
        res 2,a
        ld (hl),a
        ret


plotbr: ;bottom right quadrant
        ld a,(hl)
        bit 7,a   ;collision detect
        ret nz

;plotbrok:
        set 7,a
        xor $07 ;invert all other bits
        ld (hl),a

ret  ; plot pixel

unplot_pixel:
        ; unplot the pixel in the co-ord from plot_origin (square on screen) and
        ; plotsector (actual pixel)
        ;  0= top left, 1 = top right, 2 = bottom left, 3 = bottom right
        ld hl,(plot_origin)

        ld a,(plotsector)
        cp $00
        jr z,uplottl
        cp $01
        jr z,uplottr
        cp $02
        jr z,uplotbl
        cp $03
        jr z,uplotbr

        ret

uplottl: ;top left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,utlinvert
        res 0,a
        ld (hl),a
        ret

utlinvert:
        set 0,a
        ld (hl),a
        ret

uplottr: ;top right quadrant
        ld a,(hl)
        bit 7,a
        jr nz,utrinvert
        res 1,a
        ld (hl),a
        ret

utrinvert:
        set 1,a
        ld (hl),a
        ret


uplotbl: ;bottom left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,ublinvert
        res 2,a
        ld (hl),a
        ret

ublinvert:
        set 2,a
        ld (hl),a
        ret


uplotbr: ;bottom right quadrant
        ld a,(hl)
        bit 7,a
        ret z
        res 7,a
        xor $07 ;invert all other bits
        ld (hl),a
        ret

        ret ;unplot pixel

draw_line_high:
        ; bresenham's algorithm
        ; for up down lines

        ld a,(x0p) ;dx = x1 - x0
        ld b,a
        ld a,(x1p)
        sub b
        ld (dx),a


        ld a,(y0p) ;dy = y1 - y0
        ld b,a
        ld a,(y1p)
        sub b
        ld (dy),a


        ld hl,xi ;xi =1
        ld (hl),$1

        ld a,(dx)
        bit 7,a ;if dx<0?

        jr z,dx_not_negh

        ;dx is < 0
        ld a,$ff   ;xi =-1
        ld (xi),a
        ld a,(dx) ; dx = -dx
        neg
        ld (dx),a

dx_not_negh:

        ld a,(dy) ;dis = (2 * dx) - dy
        ld b,a
        ld a,(dx)
        sla a ;dx*2
        sub b
        ld (dis),a

        ;x = x0
        ld a,(x0p)
        ld (x),a

        ld a,(y0p)  ;for y from y0 to y1
        ld (y),a
        ld b,a
        ld a,(y1p)
        sub b
        jr z,zero_line ;just plot the origin if line length is zero
        ld b,a ;b contains y1-y0


draw_line_looph:
        push bc

        ld a,(y)
        ld (ploty),a
        inc a
        ld (y),a

        ld a,(x)
        ld (plotx),a

        call zxplot  ;ploy x,y

        ;call single_step

        ld a,(dis)  ;if dis > 0
        bit 7,a
        jr nz,dis_lt0h


        ;x = x + xi
        ld a,(xi)
        ld b,a
        ld a,(x)
        add a,b
        ld (x),a

        ;dis = dis + (2 * (dx - dy))
        ld a,(dy)
        ld b,a
        ld a,(dx)
        sub b
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a

        jr end_draw_line_looph

dis_lt0h:
        ;dis = dis + 2*dx
        ld a,(dx)
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a


end_draw_line_looph:
        pop bc

        djnz draw_line_looph

        ld hl,flag2
        res 1,(hl)

        ret ;draw_line_high

zero_line:
        ld a,(x0)
        ld (plotx),a

        ld a,(y0)
        ld (ploty),a

        call zxplot

        ret ;zero_line



draw_line_low:
        ; bresenham's algorithm

        ld a,(x0p) ;dx = x1 - x0
        ld b,a
        ld a,(x1p)
        sub b
        ld (dx),a


        ld a,(y0p) ;dy = y1 - y0
        ld b,a
        ld a,(y1p)
        sub b
        ld (dy),a


        ld hl,yi ;yi =1
        ld (hl),1

        bit 7,a ;if dy<0?

        jr z,dy_not_neg

        ;dy is < 0
        ld a,$ff   ;yi =-1
        ld (yi),a
        ld a,(dy) ; dy = -dy
        neg
        ld (dy),a

dy_not_neg:
        ld a,(dx) ;dis = (2 * dy) - dx
        ld b,a
        ld a,(dy)
        sla a ;dy*2
        sub b
        ld (dis),a

        ;y = y0
        ld a,(y0p)
        ld (y),a

        ld a,(x0p)  ;for x from x0 to x1
        ld (x),a
        ld b,a
        ld a,(x1p)
        sub b
        jr z,zero_line ;just plot the origin if line length is zero
        ld b,a ;b contains x1-x0


draw_line_loop:
        push bc

        ld a,(x)
        ld (plotx),a
        inc a
        ld (x),a

        ld a,(y)
        ld (ploty),a

        call zxplot  ;ploy x,y

        ld a,(dis)  ;if dis > 0
        bit 7,a
        jr nz,dis_lt0

        ;call print_star

        ;y = y + yi
        ld a,(yi)
        ld b,a
        ld a,(y)
        add a,b
        ld (y),a

        ;dis = dis + (2 * (dy - dx))
        ld a,(dx)
        ld b,a
        ld a,(dy)
        sub b
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a

        jr end_draw_line_loop

dis_lt0:
        ;dis = dis + 2*dy
        ld a,(dy)
        sla a
        ld b,a
        ld a,(dis)
        add a,b
        ld (dis),a

end_draw_line_loop:
        pop bc

        djnz draw_line_loop

        ld hl,flag2
        res 1,(hl)

        ret ;draw_line_low


undraw_line:
        ld hl,flag2
        set 1,(hl)


draw_line:
        ;will abort if both start and end are the same

        ld a,(x0)
        ld (x0p),a

        ld a,(x1)
        ld (x1p),a

        ld a,(y0)
        ld (y0p),a

        ld a,(y1)
        ld (y1p),a

        ;work out what configuration of the algorithm
        ;is correct to draw the line

        ;if abs(y1 - y0) < abs(x1 - x0)

        ld a,(y0)
        ld b,a
        ld a,(y1)
        sub b   ;a= y1-y0
        jr nc,y1gty0 ;nc = (y1-y0) >0
        neg ;change to abs value

y1gty0:
        ld c,a ;c = abs(y1 - y0)  ;works so far

        ld a,(x0)
        ld b,a
        ld a,(x1)
        sub b
        jr nc,x1gtx0
        neg

x1gtx0:
        ;a = abs(x1 - x0)

        sub c ;c = abs(y1 - y0)


        jr c,check_drawlinehigh ;abs(y1 - y0) < abs(x1 - x0) so use draw line high
        ;if x0 > x1 ;draw line low, else swap x0,y0 and x1,y1

        ld a,(x1)
        ld b,a
        ld a,(x0)
        sub b
        jp c,draw_line_low

        ;x1 > x0 so swap x0,x1 and y0,y1
        call swap_x0_x1_y0_y1

        jp draw_line_low


check_drawlinehigh:
        ;if y0 > y1
        ld a,(y1)
        ld b,a
        ld a,(y0)
        sub b
        jp c,draw_line_high

        ;plotlinehigh(x1, y1, x0, y0)

        ;x1 > x0 so swap x0,x1 and y0,y1

        call swap_x0_x1_y0_y1

        jp draw_line_high

        ;draw_line



swap_x0_x1_y0_y1:
        ld a,(y0)
        ld b,a
        ld a,(y1)
        ld (y0p),a
        ld a,b
        ld (y1p),a

        ld a,(x0)
        ld b,a
        ld a,(x1)
        ld (x0p),a
        ld a,b
        ld (x1p),a

        ret

get_cosine:
        ;same as sine plus 90 degrees
        sub $40


get_sine: ;take value of the a register and return the sine value from table
        ;first, work out what quadrant we're in
        cp $40
        jr nc,sine_quad2

        ;angle is top right quadrant
        ;count angle sine from bottom of table
        ld hl,sine_value_bottom
        ld de,$00
        ld e,a
        add hl,de
        ld a,(hl)

        ret

sine_quad2:
        cp $80
        jr nc,sine_quad3

        ;angle is bottom right quadrant
        ;count angle sine from top of table
        sub $40
        ld hl,sine_value_top
        ld de,$00
        ld e,a
        scf
        ccf
        sbc hl,de
        ld a,(hl)
        ret

sine_quad3:
        cp $c0
        jr nc,sine_quad4

        ;causing problems at $80

        ;angle is bottom left quadrant
        ;count negative angle sine from bottom of table
        sub $80
        ld hl,sine_value_bottom
        ld de,$00
        ld e,a
        add hl,de
        ld a,(hl)
        set 7,a
        ret

sine_quad4:
        ;angle is top left quadrant
        ;count negative angle sine from top of table

        ;causing problems at $ff

        sub $c0
        ld hl,sine_value_top
        ld de,$00
        ld e,a
        scf
        ccf
        sbc hl,de
        ld a,(hl)
        set 7,a
        ret ;get_sine

calculate_scaled_value:
        ;a register contains sine value
        ;multiply line_length by the sine and divide  by 128
        ;to get the displacement

        ld c,a ;preserve original displacement
        res 7,a

        cp $00
        jr z,calculate_zero_value

        ld b,a ;sine value
        ld a,(line_length)

        ld hl,$00

        ld l,a

        push hl
        pop de


        ;now multiply line length by the sine value

mult_sine_loop:
        add hl,de

        djnz mult_sine_loop

        ;divide result in hl register by 128

        ld b,$07

divide_by_128_loop:
        srl l
        srl h

        jr nc,nocarry_l_reg

        set 7,l

nocarry_l_reg:
        djnz divide_by_128_loop

        bit 7,c
        ret z
        ld a,l
        neg

calculate_zero_value:
        ld l,a

        ret ;calculate_scaled_value


;variables

flag2:
        db $00

plotmode:
        db $00

plotx:
        db $00

ploty:
        db $00

plotsector:
        db $00

plot_origin:
        db $00, $00

line_length:
        db $00


;line drawing x and y. variables ending in p are the parameters
;passed to the line draw program

linecoords:
x0:
        db $00

y0:
        db $00

x1:
        db $00

y1:
        db $00

x0p:
        db $00

y0p:
        db $00

x1p:
        db $00

y1p:
        db $00

;used for bresenham's line algorithm

dx:
        db $00

dy:
        db $00

xi:
        db $00

yi:
        db $00

dis:
        db $00

x:
        db $00

y:
        db $00


sine_value_bottom:  ;64 values f0r the sine of a value of 128, so a line of length
             ;128 would have a x length of 3 pixels at an angle of 1 unit of 63

        db $00,$03,$06,$09,$0c,$10,$13,$16,$19,$1c,$1f,$22,$25,$28,$2b
        db $2e,$31,$33,$36,$39,$3c,$3f,$41,$44,$47,$49,$4c,$4e,$51,$53
        db $55,$58,$5a,$5c,$5e,$60,$62,$64,$66,$68,$6a,$6b,$6d,$6f,$70
        db $71,$73,$74,$75,$76,$78,$79,$7a,$7a,$7b,$7c,$7d,$7d,$7e,$7e
        db $7e,$7f,$7f

sine_value_top:
        db $7f

buffer:
        db $76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76
emptyline:
        db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76