SPO600 Lab2 (Pt.3)-- challenges 3 & 4 and reflection

SPO600 Lab2 (Pt.3)-- challenges 3 & 4 and  reflection

Subsequence to part1 and part2, I am revising a 6502 instruction assembly program which allows a logo to bounce within the screen.


Challenges

Lets work on Challenges 3 and 4.

1. Permit integer value other than -1 and +1 for the X and Y increments (logo velocity).
2. Permit fractional value for the X and Y increments (eg. +1.5 or -0.75)
3. Perturb the ball's position or velocity 
4. Change the graphic image or colour each time it bounces 

Problems analysis and solutions

Assumption: 
1. Only velocity of the bounce direction will be changed.
2. the logo is allowed to stop in case the ball velocity changed to 0 due to the perturbing. (unlikely happening)
3. We do not do perturb to the position since it is just similar to that of velocity.

Solution:
Simple add a Perturb subroutine so that we can add perturbing when it bounds.

code:
; draw-image-subroutine.6502 
; 
; This is a routine that can place an arbitrary 
; rectangular image on to the screen at given
; coordinates.
; 
; Chris Tyler 2024-09-17
; Licensed under GPLv2+
;  

; The subroutine is below starting at the 
; label "DRAW:"

; Zero-page variables
define XPOSL $20
define XPOSH $21
define YPOSL $22
define YPOSH $23

define XNEXTL $24
define XNEXTH $25
define YNEXTL $26
define YNEXTH $27

define X_VL $28
define X_VH $29
define Y_VL $2A
define Y_VH $2B


START:
; Set up the width and height elements of the data structure
  LDA #$05
  STA $12       ; IMAGE WIDTH
  STA $13       ; IMAGE HEIGHT

; initial position
  LDA #$00
  STA XPOSL
  LDA #$01
  STA XPOSH
  LDA #$00
  STA YPOSL
  LDA #$03
  STA YPOSH
; initial velocity x = 1.5, y =-0.75 
  LDA #$01
  STA X_VH
  LDA #$80
  STA X_VL
  LDA #$40
  STA Y_VL
  LDA #$ff
  STA Y_VH

; Main loop for diagonal animation
MAINLOOP:

  ; Set pointer to the image
  ; Use G_O or G_X as desired
  ; The syntax #<LABEL returns the low byte of LABEL
  ; The syntax #>LABEL returns the high byte of LABEL

  LDA #<G_X
  STA $10
  LDA #>G_X
  STA $11

  ; Place the image on the screen
  LDA #$10  ; Address in zeropage of the data structure
  LDX XPOSH  ; X position
  LDY YPOSH  ; Y position
  JSR DRAW  ; Call the subroutine

  ; Delay to show the image
  LDY #$00
  LDX #$50
DELAY:
  DEY
  BNE DELAY
  DEX
  BNE DELAY

  ; Set pointer to the blank graphic
  LDA #<G_BLANK
  STA $10
  LDA #>G_BLANK
  STA $11

  ; Draw the blank graphic to clear the old image
  LDA #$10 ; LOCATION OF DATA STRUCTURE
  LDX XPOSH
  LDY YPOSH
  JSR DRAW
  JMP MOVE
TEMP: JMP MAINLOOP  
  ; Increment the predicted position
MOVE:  LDA X_VL
  CLC
  ADC XPOSL
  STA XNEXTL
  LDA X_VH
  ADC XPOSH
  STA XNEXTH
  LDA Y_VL
  CLC
  ADC YPOSL
  STA YNEXTL
  LDA Y_VH
  ADC YPOSH
  STA YNEXTH

X_LEFTCHECK:  ;check if X reach left edge
  LDA XNEXTH
  BMI X_BOUNCE_L 
 

;check if X excess right edge
  LDA XNEXTH
  CMP #$1b
  BCS X_BOUNCE_R
  JMP Y_TOPCHECK

X_BOUNCE_R: ;bounce on right edge
  LDA #$00
  SEC
  SBC X_VL
  STA X_VL
  LDA #$00
  SBC X_VH
  STA X_VH

  LDA XNEXTH
  SEC
  SBC #$1b
  STA XNEXTH
  LDA $00
  SEC
  SBC XNEXTL
  STA XNEXTL
  LDA #$1b
  SBC XNEXTH
  STA XNEXTH
  JMP X_PERTURB

X_BOUNCE_L:  ;bounce on left edge

  LDA #$00
  SEC
  SBC X_VL
  STA X_VL
  LDA #$00
  SBC X_VH
  STA X_VH

  LDA #$00
  SEC
  SBC XNEXTL
  STA XNEXTL
  LDA #$00
  SBC XNEXTH
  STA XNEXTH

X_PERTURB:; add random velocity in x direction
  lda $fe
  CLC
  ADC X_VL
  STA X_VL
  LDA #$00
  ADC X_VH
  STA X_VH

;check if Y reach TOP edge
Y_TOPCHECK:  LDA YNEXTH
  BMI Y_BOUNCE_T

  ;check if Y reach Bottom edge
Y_BOTCHECK:  LDA YNEXTH
  CMP #$1b
  BCS Y_BOUNCE_B
  JMP END_CHECK

Y_BOUNCE_T:
  LDA #$00 ;reverse velocity
  SEC
  SBC Y_VL
  STA Y_VL
  LDA #$00
  SBC Y_VH
  STA Y_VH

;reverse position
  LDA #$00
  SEC
  SBC YNEXTL
  STA YNEXTL
  LDA #$00
  SBC YNEXTH
  STA YNEXTH
  
  JMP Y_PERTURB
Y_BOUNCE_B:
  LDA #$00
  SEC
  SBC Y_VL
  STA Y_VL
  LDA #$00
  SBC Y_VH
  STA Y_VH

 LDA YNEXTH
  SEC
  SBC #$1b
  STA YNEXTH
  LDA $00
  SEC
  SBC YNEXTL
  STA YNEXTL
  LDA #$1b
  SBC YNEXTH
  STA YNEXTH

Y_PERTURB:; add random velocity in y direction
  lda $fe
  CLC
  ADC Y_VL
  STA Y_VL
  LDA #$00
  ADC Y_VH
  STA Y_VH

  
END_CHECK:

  LDA XNEXTH
  STA XPOSH
  LDA XNEXTL
  STA XPOSL
  LDA YNEXTH
  STA YPOSH
  LDA YNEXTL
  STA YPOSL

  JMP TEMP ; Repeat infinitely

; ==========================================
;
; DRAW :: Subroutine to draw an image on 
;         the bitmapped display
;
; Entry conditions:
;    A - location in zero page of: 
;        a pointer to the image (2 bytes)
;        followed by the image width (1 byte)
;        followed by the image height (1 byte)
;    X - horizontal location to put the image
;    Y - vertical location to put the image
;
; Exit conditions:
;    All registers are undefined
;
; Zero-page memory locations
define IMGPTR    $A0
define IMGPTRH   $A1
define IMGWIDTH  $A2
define IMGHEIGHT $A3
define SCRPTR    $A4
define SCRPTRH   $A5
define SCRX      $A6
define SCRY      $A7

DRAW:
  ; SAVE THE X AND Y REG VALUES
  STY SCRY
  STX SCRX

  ; GET THE DATA STRUCTURE
  TAY
  LDA $0000,Y
  STA IMGPTR
  LDA $0001,Y
  STA IMGPTRH
  LDA $0002,Y
  STA IMGWIDTH
  LDA $0003,Y
  STA IMGHEIGHT

  ; CALCULATE THE START OF THE IMAGE ON
  ; SCREEN AND PLACE IN SCRPTRH
  ;
  ; THIS IS $0200 (START OF SCREEN) +
  ; SCRX + SCRY * 32
  ; 
  ; WE'LL DO THE MULTIPLICATION FIRST
  ; START BY PLACING SCRY INTO SCRPTR
  LDA #$00
  STA SCRPTRH
  LDA SCRY
  STA SCRPTR
  ; NOW DO 5 LEFT SHIFTS TO MULTIPLY BY 32
  LDY #$05     ; NUMBER OF SHIFTS
MULT:
  ASL SCRPTR   ; PERFORM 16-BIT LEFT SHIFT
  ROL SCRPTRH
  DEY
  BNE MULT

  ; NOW ADD THE X VALUE
  LDA SCRX
  CLC
  ADC SCRPTR
  STA SCRPTR
  LDA #$00
  ADC SCRPTRH
  STA SCRPTRH

  ; NOW ADD THE SCREEN BASE ADDRESS OF $0200
  ; SINCE THE LOW BYTE IS $00 WE CAN IGNORE IT
  LDA #$02
  CLC
  ADC SCRPTRH
  STA SCRPTRH
  ; NOTE WE COULD HAVE DONE TWO: INC SCRPTRH

  ; NOW WE HAVE A POINTER TO THE IMAGE IN MEM
  ; COPY A ROW OF IMAGE DATA
COPYROW:
  LDY #$00
ROWLOOP:
  LDA (IMGPTR),Y
  STA (SCRPTR),Y
  INY
  CPY IMGWIDTH
  BNE ROWLOOP

  ; NOW WE NEED TO ADVANCE TO THE NEXT ROW
  ; ADD IMGWIDTH TO THE IMGPTR
  LDA IMGWIDTH
  CLC
  ADC IMGPTR
  STA IMGPTR
  LDA #$00
  ADC IMGPTRH
  STA IMGPTRH
 
  ; ADD 32 TO THE SCRPTR
  LDA #32
  CLC
  ADC SCRPTR
  STA SCRPTR
  LDA #$00
  ADC SCRPTRH
  STA SCRPTRH

  ; DECREMENT THE LINE COUNT AND SEE IF WE'RE
  ; DONE
  DEC IMGHEIGHT
  BNE COPYROW

  RTS

; ==========================================

; 5x5 pixel images

; Image of a blue "O" on black background
G_O:
DCB $00,$0e,$0e,$0e,$00
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $00,$0e,$0e,$0e,$00

; Image of a yellow "X" on a black background
G_X:
DCB $07,$00,$00,$00,$07
DCB $00,$07,$00,$07,$00
DCB $00,$00,$07,$00,$00
DCB $00,$07,$00,$07,$00
DCB $07,$00,$00,$00,$07

; Image of a black square
G_BLANK:
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
The highlighted part is the perturb part for the velocity change.

Output:




Challenges 4


Change the graphic image each time it bounces 


Solution:
Use two 2-bytes pointer to store the location of the logos. Use a Subroutine to swap pointer when ever it bounces.


; draw-image-subroutine.6502 
; 
; This is a routine that can place an arbitrary 
; rectangular image on to the screen at given
; coordinates.
; 
; Chris Tyler 2024-09-17
; Licensed under GPLv2+
;  

; The subroutine is below starting at the 
; label "DRAW:"

; Zero-page variables
define XPOSL $20
define XPOSH $21
define YPOSL $22
define YPOSH $23

define XNEXTL $24
define XNEXTH $25
define YNEXTL $26
define YNEXTH $27

define X_VL $28
define X_VH $29
define Y_VL $2A
define Y_VH $2B

define LOGO_AL $30
define LOGO_AH $31
define LOGO_BL $32
define LOGO_BH $33

START:
; Set up the width and height elements of the data structure
  LDA #$05
  STA $12       ; IMAGE WIDTH
  STA $13       ; IMAGE HEIGHT

; initi logo attribute
  LDA #<G_O
  STA LOGO_AL
  LDA #>G_O
  STA LOGO_AH
  LDA #<G_X
  STA LOGO_BL
  LDA #>G_X
  STA LOGO_BH

; initial position
  LDA #$00
  STA XPOSL
  LDA #$01
  STA XPOSH
  LDA #$00
  STA YPOSL
  LDA #$03
  STA YPOSH
; initial velocity x = 1.5, y =-0.75 
  LDA #$01
  STA X_VH
  LDA #$80
  STA X_VL
  LDA #$40
  STA Y_VL
  LDA #$ff
  STA Y_VH

  ; Set pointer to the image
  ; Use G_O or G_X as desired
  ; The syntax #<LABEL returns the low byte of LABEL
  ; The syntax #>LABEL returns the high byte of LABEL



; Main loop for diagonal animation
MAINLOOP:
  LDA LOGO_AL
  STA $10
  LDA LOGO_AH
  STA $11


  ; Place the image on the screen
  LDA #$10  ; Address in zeropage of the data structure
  LDX XPOSH  ; X position
  LDY YPOSH  ; Y position
  JSR DRAW  ; Call the subroutine

  ; Delay to show the image
  LDY #$00
  LDX #$50
DELAY:
  DEY
  BNE DELAY
  DEX
  BNE DELAY

  ; Set pointer to the blank graphic
  LDA #<G_BLANK
  STA $10
  LDA #>G_BLANK
  STA $11

  ; Draw the blank graphic to clear the old image
  LDA #$10 ; LOCATION OF DATA STRUCTURE
  LDX XPOSH
  LDY YPOSH
  JSR DRAW
  JMP MOVE
TEMP: JMP MAINLOOP  
  ; Increment the predicted position
MOVE:  LDA X_VL
  CLC
  ADC XPOSL
  STA XNEXTL
  LDA X_VH
  ADC XPOSH
  STA XNEXTH
  LDA Y_VL
  CLC
  ADC YPOSL
  STA YNEXTL
  LDA Y_VH
  ADC YPOSH
  STA YNEXTH

X_LEFTCHECK:  ;check if X reach left edge
  LDA XNEXTH
  BMI X_BOUNCE_L 
 

;check if X excess right edge
  LDA XNEXTH
  CMP #$1b
  BCS X_BOUNCE_R
  JMP Y_TOPCHECK

X_BOUNCE_R: ;bounce on right edge
  LDA #$00
  SEC
  SBC X_VL
  STA X_VL
  LDA #$00
  SBC X_VH
  STA X_VH

  LDA XNEXTH
  SEC
  SBC #$1b
  STA XNEXTH
  LDA $00
  SEC
  SBC XNEXTL
  STA XNEXTL
  LDA #$1b
  SBC XNEXTH
  STA XNEXTH
  JSR CH_LOGO
  JMP Y_TOPCHECK

X_BOUNCE_L:  ;bounce on left edge
  LDA #$00
  SEC
  SBC X_VL
  STA X_VL
  LDA #$00
  SBC X_VH
  STA X_VH

  LDA #$00
  SEC
  SBC XNEXTL
  STA XNEXTL
  LDA #$00
  SBC XNEXTH
  STA XNEXTH
  JSR CH_LOGO

;check if Y reach TOP edge
Y_TOPCHECK:  LDA YNEXTH
  BMI Y_BOUNCE_T

  ;check if Y reach Bottom edge
Y_BOTCHECK:  LDA YNEXTH
  CMP #$1b
  BCS Y_BOUNCE_B
  JMP END_CHECK

Y_BOUNCE_T:
  LDA #$00 ;reverse velocity
  SEC
  SBC Y_VL
  STA Y_VL
  LDA #$00
  SBC Y_VH
  STA Y_VH

;reverse position
  LDA #$00
  SEC
  SBC YNEXTL
  STA YNEXTL
  LDA #$00
  SBC YNEXTH
  STA YNEXTH
  
  JSR CH_LOGO
  JMP END_CHECK
Y_BOUNCE_B:
  LDA #$00
  SEC
  SBC Y_VL
  STA Y_VL
  LDA #$00
  SBC Y_VH
  STA Y_VH

  LDA YNEXTH
  SEC
  SBC #$1b
  STA YNEXTH
  LDA $00
  SEC
  SBC YNEXTL
  STA YNEXTL
  LDA #$1b
  SBC YNEXTH
  STA YNEXTH
  JSR CH_LOGO
  JMP END_CHECK
CH_LOGO:; add random velocity in y direction
  LDA LOGO_AL
  LDY LOGO_BL
  STA LOGO_BL
  STY LOGO_AL
  LDA LOGO_AH
  LDY LOGO_BH
  STA LOGO_BH
  STY LOGO_AH
  RTS

  
END_CHECK:

  LDA XNEXTH
  STA XPOSH
  LDA XNEXTL
  STA XPOSL
  LDA YNEXTH
  STA YPOSH
  LDA YNEXTL
  STA YPOSL

  JMP TEMP ; Repeat infinitely

; ==========================================
;
; DRAW :: Subroutine to draw an image on 
;         the bitmapped display
;
; Entry conditions:
;    A - location in zero page of: 
;        a pointer to the image (2 bytes)
;        followed by the image width (1 byte)
;        followed by the image height (1 byte)
;    X - horizontal location to put the image
;    Y - vertical location to put the image
;
; Exit conditions:
;    All registers are undefined
;
; Zero-page memory locations
define IMGPTR    $A0
define IMGPTRH   $A1
define IMGWIDTH  $A2
define IMGHEIGHT $A3
define SCRPTR    $A4
define SCRPTRH   $A5
define SCRX      $A6
define SCRY      $A7

DRAW:
  ; SAVE THE X AND Y REG VALUES
  STY SCRY
  STX SCRX

  ; GET THE DATA STRUCTURE
  TAY
  LDA $0000,Y
  STA IMGPTR
  LDA $0001,Y
  STA IMGPTRH
  LDA $0002,Y
  STA IMGWIDTH
  LDA $0003,Y
  STA IMGHEIGHT

  ; CALCULATE THE START OF THE IMAGE ON
  ; SCREEN AND PLACE IN SCRPTRH
  ;
  ; THIS IS $0200 (START OF SCREEN) +
  ; SCRX + SCRY * 32
  ; 
  ; WE'LL DO THE MULTIPLICATION FIRST
  ; START BY PLACING SCRY INTO SCRPTR
  LDA #$00
  STA SCRPTRH
  LDA SCRY
  STA SCRPTR
  ; NOW DO 5 LEFT SHIFTS TO MULTIPLY BY 32
  LDY #$05     ; NUMBER OF SHIFTS
MULT:
  ASL SCRPTR   ; PERFORM 16-BIT LEFT SHIFT
  ROL SCRPTRH
  DEY
  BNE MULT

  ; NOW ADD THE X VALUE
  LDA SCRX
  CLC
  ADC SCRPTR
  STA SCRPTR
  LDA #$00
  ADC SCRPTRH
  STA SCRPTRH

  ; NOW ADD THE SCREEN BASE ADDRESS OF $0200
  ; SINCE THE LOW BYTE IS $00 WE CAN IGNORE IT
  LDA #$02
  CLC
  ADC SCRPTRH
  STA SCRPTRH
  ; NOTE WE COULD HAVE DONE TWO: INC SCRPTRH

  ; NOW WE HAVE A POINTER TO THE IMAGE IN MEM
  ; COPY A ROW OF IMAGE DATA
COPYROW:
  LDY #$00
ROWLOOP:
  LDA (IMGPTR),Y
  STA (SCRPTR),Y
  INY
  CPY IMGWIDTH
  BNE ROWLOOP

  ; NOW WE NEED TO ADVANCE TO THE NEXT ROW
  ; ADD IMGWIDTH TO THE IMGPTR
  LDA IMGWIDTH
  CLC
  ADC IMGPTR
  STA IMGPTR
  LDA #$00
  ADC IMGPTRH
  STA IMGPTRH
 
  ; ADD 32 TO THE SCRPTR
  LDA #32
  CLC
  ADC SCRPTR
  STA SCRPTR
  LDA #$00
  ADC SCRPTRH
  STA SCRPTRH

  ; DECREMENT THE LINE COUNT AND SEE IF WE'RE
  ; DONE
  DEC IMGHEIGHT
  BNE COPYROW

  RTS

; ==========================================

; 5x5 pixel images

; Image of a blue "O" on black background
G_O:
DCB $00,$0e,$0e,$0e,$00
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $00,$0e,$0e,$0e,$00

; Image of a yellow "X" on a black background
G_X:
DCB $07,$00,$00,$00,$07
DCB $00,$07,$00,$07,$00
DCB $00,$00,$07,$00,$00
DCB $00,$07,$00,$07,$00
DCB $07,$00,$00,$00,$07

; Image of a black square
G_BLANK:
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
yellow highlighted part is the declaration and initialization of the two logo pointer
Cyan highlighted part is the subroutine of the swapping of two logo pointer 

Output:





Reflection

In this workshop, I practiced subtraction and addition of multi-bytes values. I noted the role of the carry flag in these operation. Meanwhile, I learn that CMP is actually perform subtraction without recording the result. However, negative flag, carry flag and zero flag will indicate the result of the subtraction. In this connection, we are able to use CMP instruction to perform some conditional branching, eg BNE, BCC, BMI, etc. Also, I practiced to use JSR, JMP and RTS to do subroutine. 

Regarding assembly language, I am happy that I know what exactly would happen when a instruction run. However, I feel like even a simple task in assembly language is extremely time consuming. Also, assembly code, with multiple JMP, RTS,JSR is hard to read. 

Comments

Popular posts from this blog

SPO600 Project Stage 1 (Pt.1) - Create a GCC Pass

SPO600 Project Stage 2 (Pt.1) - GCC pass locating clone function

SPO600 Project Stage 2 (Pt.2) - GCC pass locating clone function -modified version