6502-emulator/sample/draw.s

270 lines
6.3 KiB
ArmAsm
Raw Normal View History

2019-04-26 15:40:23 +00:00
; simple program that paints cycling colours to the screen using the keyboard curor keys and will max out your
; CPU in the process!
;
; Esc - ends the process
;
; Del - clears the screen - this is HORRIBLY SLOW! There is no clock emulation and so it's not possible within
; assembly to slow things down, i.e. to prevent painting to screen at lightning speed, meaning you have no real control.
; In order approximate this a delay of 20ms has been put into the terminal between rendering each pixel change. Since
; clearing the screen effectively redraws each pixel this means it takes around 64 * 64 * 20ms, so ~82 seconds!!
; While waiting for this process to complete the program won't respond to you pressing the Esc key.
2019-04-26 01:23:50 +00:00
;
; The emulator loads programs at 0x600 so make sure to assemble with text segment at this address.
2019-04-26 15:40:23 +00:00
;
2019-04-26 01:23:50 +00:00
; Compile with xa using command:
; xa draw.s -v -bt 1536
; buffer for last key pressed
key_addr = $f001
2019-04-26 15:40:23 +00:00
video_bottom_lb = $00
video_bottom_hb = $e0
video_top_lb = $00
video_top_hb = $f0
video_memory_ptr_lb = $00
video_memory_ptr_hb = $01
2019-04-26 01:23:50 +00:00
; address that holds the current colour to draw with
2019-04-26 15:40:23 +00:00
draw_colour_addr = $03
is_clearing_addr = $04
rubber_colour = $00
2019-04-26 01:23:50 +00:00
left_key_code = $50
right_key_code = $4f
up_key_code = $52
down_key_code = $51
2019-04-26 15:40:23 +00:00
esc_key_code = $29
del_key_code = $4c
; draw position
ldx #video_bottom_lb
stx video_memory_ptr_lb ; starting draw position low
ldx #video_bottom_hb
stx video_memory_ptr_hb ; starting draw position high
2019-04-26 01:23:50 +00:00
; main program loop
loop
jsr read_key
; if we didn't read a key loop back round
2019-04-26 15:40:23 +00:00
cmp #0
2019-04-26 01:23:50 +00:00
beq loop
cmp #left_key_code
bne not_left
jsr move_left
jmp loop
not_left
cmp #right_key_code
bne not_right
jsr move_right
jmp loop
not_right
cmp #up_key_code
bne not_up
jsr move_up
jmp loop
not_up
cmp #down_key_code
2019-04-26 15:40:23 +00:00
bne not_down
2019-04-26 01:23:50 +00:00
jsr move_down
jmp loop
2019-04-26 15:40:23 +00:00
not_down
cmp #del_key_code
bne not_del
jsr clear_screen
jmp loop
not_del
cmp #esc_key_code
bne loop
jmp exit
2019-04-26 01:23:50 +00:00
jmp loop
read_key
lda key_addr
; clear the key press buffer so we don't read same key press twice
2019-04-26 15:40:23 +00:00
ldx #0
2019-04-26 01:23:50 +00:00
stx key_addr
rts
move_right
2019-04-26 15:40:23 +00:00
lda video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
; if we're at $ff then we need to increment the high byte before rendering
cmp #$ff
bne do_right_render
; if we're at $efff then we have to stop because we'd start writing outside of video memory
2019-04-26 15:40:23 +00:00
lda video_memory_ptr_hb
cmp #$ef
2019-04-26 01:23:50 +00:00
bcs after_right_render
; increment high byte and reset the low one
2019-04-26 15:40:23 +00:00
inc video_memory_ptr_hb
ldx #0
stx video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
do_right_render
2019-04-26 15:40:23 +00:00
inc video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
jsr render_dot
after_right_render
rts
; comments for "move_right" also apply here but direction is obviously reversed
move_left
2019-04-26 15:40:23 +00:00
lda video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
2019-04-26 15:40:23 +00:00
cmp #0
2019-04-26 01:23:50 +00:00
bne do_left_render
2019-04-26 15:40:23 +00:00
lda video_memory_ptr_hb
cmp #video_bottom_hb
2019-04-26 01:23:50 +00:00
beq after_left_render
2019-04-26 15:40:23 +00:00
dec video_memory_ptr_hb
ldx #0
stx video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
do_left_render
2019-04-26 15:40:23 +00:00
dec video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
jsr render_dot
after_left_render
rts
move_up
; don't want to risk moving into non graphics memory so perform boundary checks
2019-04-26 15:40:23 +00:00
ldx video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
; each line contains $40 (64) pixels, if low byte is above this then we're safe to move
cpx #$40
bcs after_up_boundary_check
; couldn't tell if we're safe by looking at low byte, does the high byte allow move?
2019-04-26 15:40:23 +00:00
ldx video_memory_ptr_hb
2019-04-26 01:23:50 +00:00
cpx #$e0
beq after_up_render
after_up_boundary_check
2019-04-26 15:40:23 +00:00
lda video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
sbc #$40
2019-04-26 15:40:23 +00:00
sta video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
; if carry flag is set then we'll also have to decrement the high byte
bcs after_up_subtract
2019-04-26 15:40:23 +00:00
dec video_memory_ptr_hb
2019-04-26 01:23:50 +00:00
after_up_subtract
jsr render_dot
after_up_render
rts
; comments for "move_up" also apply here but direction is obviously reversed
move_down
2019-04-26 15:40:23 +00:00
ldx video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
cpx #$9b
bcc after_down_boundary_check
2019-04-26 15:40:23 +00:00
ldx video_memory_ptr_hb
2019-04-26 01:23:50 +00:00
cpx #$ef
beq after_down_render
after_down_boundary_check
2019-04-26 15:40:23 +00:00
lda video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
adc #$40
2019-04-26 15:40:23 +00:00
sta video_memory_ptr_lb
2019-04-26 01:23:50 +00:00
bcc after_down_add
2019-04-26 15:40:23 +00:00
inc video_memory_ptr_hb
2019-04-26 01:23:50 +00:00
after_down_add
jsr render_dot
after_down_render
rts
2019-04-26 15:40:23 +00:00
; renders a pixel on the screen
2019-04-26 01:23:50 +00:00
render_dot
2019-04-26 15:40:23 +00:00
; if we're clearing the screen then load the rubber colour...
ldx is_clearing_addr
cpx #0
beq set_colour
lda #rubber_colour
jmp end_set_colour
; ... else cycle the drawing colour
set_colour
; change the drawing colour (256 colours and we'll wrap around when $ff is hit)
inc draw_colour_addr
lda draw_colour_addr
end_set_colour
; write the "draw colour" to address pointed to across (video_memory_ptr_hb video_memory_ptr_lb)
ldx #video_memory_ptr_lb
sta (video_memory_ptr_lb, x)
2019-04-26 01:23:50 +00:00
2019-04-26 15:40:23 +00:00
rts
; clears the screen
clear_screen
; go into "clear screen" mode
ldx #1
stx is_clearing_addr
ldx #video_bottom_lb
stx video_memory_ptr_lb
ldx #video_bottom_hb
stx video_memory_ptr_hb
clear_pixel
; use the existing move_right routine to clear the screen from left-to-right/top-to-bottom
jsr move_right
; if we're not at the end of a block then just repeat
lda video_memory_ptr_lb
cmp #$ff
bne clear_pixel
; we're at the of the block...
lda video_memory_ptr_hb
; if we're at the end of the screen then break from loop
cmp #video_top_hb
beq end_clear_pixel
; otherwise move onto the next block
inc video_memory_ptr_hb
ldx #0
stx video_memory_ptr_lb
jmp clear_pixel
end_clear_pixel
; come out of "clear screen" mode
ldx #0
stx is_clearing_addr
; move the draw position back to the top left of screen
ldx #video_bottom_lb
stx video_memory_ptr_lb
ldx #video_bottom_hb
stx video_memory_ptr_hb
2019-04-26 01:23:50 +00:00
rts
2019-04-26 15:40:23 +00:00
; jump to here to end the process
exit