Lab3 Bouncing Graphic/Ball (Part III)
Tags: assembly, spo600, 6502emulator, math
Published: 2021-10-31 05:37:32

## Lab3 Overview 
This lab is to prepare for learning more complex x86_64 and AArch64 assembly language, by writing code with arithmetic/math in **6502 assembly language**.

The option I chose is bouncing graphic. It requires several techniques, including placing a graphic on the screen, bouncing an object around the screen and detecting when the object has collided with the edge of the screen or other objects. 

At this stage, the most important part is to improve the `draw` function, make this function works well when the ball is moving, get cleared then redrawed. Especially the taking `keystroke input` functionality, it took a lot of time to write and after all, keystrokes other than up, down, left, right arrow keys can pause the ball from moving. Thus, this function is not fully working as designed.

The code was shown below, including functions to calculate pointer location, draw graphic, taking and check keystrokes, check if the ball touching the edge of the screen, clear the screen for redraw the ball: 

```
define WIDTH   5 
define HEIGHT  5

define  POINTER         $12      
define  POINTER_H       $13
define  ROW_COUNT       $14 
define  ROW             $15 
define  COLUMN          $16
define  CHECK_LINE      $17  ; this is to check the edge
define  ROW_FLAG    $18  ; edge on row or col flag
define  COL_FLAG   $19  
define  PTR_CAL   $20
define  DATA_INDEX      $21
define  SCREENCOL_INDEX $22
define  KEY             $23

 lda #$00
 sta ROW_FLAG
 sta COL_FLAG

 lda  #$05          
 sta  ROW
 lda  #$05 
 sta  COLUMN

; prepare to move by row and col
cal_init:
  lda  #$00    
  sta  POINTER
  lda  #$02
  sta  POINTER_H
 
  lda #$00  
  sta ROW_COUNT

  lda #$00   
  sta PTR_CAL 

  cmp ROW
  beq column_count
  bne row_count

row_count:
 lda PTR_CAL
 clc
 adc #$20
 sta PTR_CAL
 
 lda POINTER_H
 adc #$00
 sta  POINTER_H

 inc ROW_COUNT 
 
 lda ROW
 cmp ROW_COUNT
 bne row_count    ; run utill get the row set 
 beq column_count

column_count:
 lda PTR_CAL
 clc
 adc  COLUMN
 sta PTR_CAL
 sta  POINTER     ; once row and col done, set pointer

; draw graphic initializing 
 lda #$00
 sta ROW_COUNT

 ldx #$00  
 ldy #$00  

; draw graph, while checking the keystroke
draw: lda ball,x

 sta (POINTER),y 

 inx
 iny
 cpy #WIDTH
 bne draw

 inc ROW_COUNT

 lda #HEIGHT 
 cmp ROW_COUNT
 beq readkey_init
  
 lda POINTER
 clc
 adc #$20 
 sta POINTER 
 lda POINTER_H 
 adc #$00
 sta POINTER_H  

 ldy #$00 
 beq draw

; 
readkey_init:
 txa     
 sta DATA_INDEX
 tya 
 sta SCREENCOL_INDEX   

readkey: lda  $ff  ; get a keystroke 

 ldx #$00 ; clear out the key buffer
 stx $ff  ; store index x in memory


  cmp  #$80 ; if not a cursor key, ignore
  bmi  readkey_check   ; branch on minus
  cmp  #$84
  bpl  readkey_check   ; branch on plus

  cmp  #$80  ; check key, up key
  bne  rightKey_check

  dec  ROW  ; if yes, decrement row
  jmp  readkey_check

 rightKey_check: 
 cmp  #$81  ; check key, right key
  bne  downKey_check

  inc  COLUMN   ; if yes, increment col
  jmp  readkey_check

 downKey_check: 
 cmp  #$82  ; check if key, down key
  bne  leftKey_check

  inc  ROW  ;  if yes, increment row
  jmp  readkey_check
  
 leftKey_check: 
 cmp  #$83  ; check if key, left key
  bne  readkey_check

  dec  COLUMN   ; if yes, decrement col
  clc
  bcc  readkey_check 

readkey_check:
 ldx DATA_INDEX
 ldy SCREENCOL_INDEX
 jmp check_location
 
check_location: 
 jsr check_top
 jsr check_bottom
 jsr check_right 
 jsr check_left
 jsr move_pointer

check_initialize: 
 lda #$00
 sta CHECK_LINE
 rts                 ; return

check_top: 
 jsr check_initialize 
 lda ROW  
 cmp #$01            ; 01
 lda CHECK_LINE
 adc #$00
 cmp #$00  
 beq flip_rowFlag
 rts

check_bottom: 
 jsr check_initialize
 lda ROW
 cmp #$1b           ; 1b
 lda CHECK_LINE
 adc #$00
 cmp #$01
 beq flip_rowFlag 
 rts

check_left:
 jsr check_initialize
 lda COLUMN
 cmp #$01          ; 01
 lda CHECK_LINE
 adc #$00
 cmp #$00
 beq flip_colFlag
 rts

check_right:
 jsr check_initialize
 lda COLUMN
 cmp #$1b
 lda CHECK_LINE
 adc #$00
 cmp #$01
 beq flip_colFlag
 rts

;Set Row Flag 
flip_rowFlag:
 lda ROW_FLAG
 cmp #$00 
 beq inc_rowFlag
 bne dec_rowFlag
 rts

inc_rowFlag:
 inc ROW_FLAG
 rts

dec_rowFlag:
 dec ROW_FLAG
 rts


; Set Col Flag 
flip_colFlag:
 lda COLFLIP_FLAG
 cmp #$00
 beq inc_colFlag
 bne dec_colFlag
 rts

inc_colFlag:
 inc COLFLIP_FLAG
 rts

dec_colFlag:
 dec COLFLIP_FLAG
 rts

; move the graph 
; first move the pointer
move_pointer:
 jsr row_check
 jsr col_check
 jmp clear      ; jump to clear

row_check:
 lda ROW_FLAG
 cmp #$01
 beq dec_row
 bne inc_row

col_check:
 lda COLFLIP_FLAG
 cmp #$01
 beq dec_col
 bne inc_col

inc_row:
 inc ROW
 rts

dec_row:
 dec ROW
 rts

inc_col:
 inc COLUMN
 rts

dec_col:
 dec COLUMN 
 rts

; move the graph 
;move: inc ROW
; inc COLUMN

; clear the screen before redraw the graph
clear: lda ball
 sta POINTER 
 lda #$02
 sta POINTER_H
 
 ldy #$00
 tya

clear_loop:
 sta (POINTER),y
 iny
 bne clear_loop

 inc POINTER_H
 ldx POINTER_H 
 cpx #$06
 bne clear_loop

 jsr  cal_init

; data constant byte (dcb)
ball:
 dcb 00,07,07,07,00
 dcb 07,07,07,07,07
 dcb 07,07,07,07,07
 dcb 07,07,07,07,07
 dcb 00,07,07,07,00
```

![The bouncing ball](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c83g67dsuho9g751l5rf.png)
 

## what I have learnt

The main take away is to use branches, functions and subroutines to properly put all functionalities work together. The second most important stuff is the math (addition) in 6502 assembly language, especially with carry.
All work on this lab can be found by, [part I](https://dev.to/qiwenyu/lab3-bouncing-graphic-part-i-27lg), [part II](https://dev.to/qiwenyu/lab3-bouncing-graphicball-part-ii-2mem), and this part. It took me a lot of time trying to think in the way properly to program using assembly language. I think I still need more time to be more proficient in branching and subroutines in assembly language.