Lab - 2 In-Class: Mob Programming

Introduction

Here, I learned a code in this lab that draws an O picture on a bitmap that is now moving diagonally. The assignment is to make the O picture bounce off a wall permanently.

Students are given the code below:

;
; 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:"
;

; Test code for our subroutine
; Moves an image diagonally across the screen

; Zero-page variables
define XPOS $20
define YPOS $21

; Set up the data structure
; The syntax #<LABEL returns the low byte of LABEL
; The syntax #>LABEL returns the high byte of LABEL
LDA #<G_X     ; POINTER TO GRAPHIC
STA $10
LDA #>G_X
STA $11
LDA #$05
STA $12       ; IMAGE WIDTH
STA $13       ; IMAGE HEIGHT

; Set initial position X=Y=0
LDA #$00
STA XPOS
STA YPOS

; Main loop for diagonal animation
MAINLOOP:

  ; Set pointer to the image
  ; Use G_O or G_X as desired
  LDA #<G_O
  STA $10
  LDA #>G_O
  STA $11

  ; Place the image on the screen
  LDA #$10  ; Address in zeropage of the data structure
  LDX XPOS  ; X position
  LDY YPOS  ; 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 XPOS
  LDY YPOS
  JSR DRAW

  ; Increment the position
  INC XPOS
  INC YPOS

  ; Continue for 29 frames of animation
  LDA #28
  CMP XPOS
  BNE MAINLOOP

  ; Repeat infinitely
  JMP $0600

; ==========================================
;
; 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
I will only discuss the LOOP code because it is extremely lengthy and the MAINLOOP is the section I need to update.


Modifying the "O" image's initial location.
; Set initial position X=Y=0
LDA #$0d ; X position to Middle
STA XPOS
LDA #$00 ; Y position to First Row
STA YPOS
Using the code above, I first moved the start location to the centre of the first row.


Changing the moving direction.
  ; Increment the position
  DEC XPOS ; Image moving left by decreasing X position
  INC YPOS
I changed the moving direction of the image to the left.


Changing Branching Condition
  ; Continue for 29 frames of animation
  LDA XPOS     ; Load current X Position
  CMP #00.     ; Compare if it becomes 0
  BNE MAINLOOP ; Otherwise, Go back to MAINLOOP    
I changed the branching condition. If the current X position becomes 0, it goes to the next code.


Make a Second Loop for bouncing off from the left wall toward the down and right direction

SECONDLOOP:
  ; Set pointer to the image
  ; Use G_O or G_X as desired
  LDA #<G_O
  STA $10
  LDA #>G_O
  STA $11

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

  ; Delay to show the image
  LDY #$00
  LDX #$50
DELAY2:    ; Becareful for changing the TAG name 
  DEY      ; Otherwise you go back to the MAINLOOP
  BNE DELAY2
  DEX
  BNE DELAY2

  ; 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 XPOS
  LDY YPOS
  JSR DRAW

  ; Increment the position
  INC XPOS ; Move the image toward the right
  INC YPOS ; Move the image toward the bottom

  LDA $fe  ; this is a debugging code to check if this loop is being executed
  STA $0310

  ; Continue for 29 frames of animation
  LDA #28  ; Set the Accumulator with 28
  CMP YPOS ; If Y position becomes 28, Move to the next Code
  BNE SECONDLOOP

The second loop is basically the same as the main loop except for the moving direction and branching condition.


Making a THIRD LOOP for bouncing off from the bottom wall toward the up and right direction

  THIRDLOOP:
  ; Set pointer to the image
  ; Use G_O or G_X as desired
  LDA #<G_O
  STA $10
  LDA #>G_O
  STA $11

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

  ; Delay to show the image
  LDY #$00
  LDX #$50
DELAY3: ; Becareful for changing the TAG name 
  DEY   ; Otherwise you go back to the MAINLOOP
  BNE DELAY3
  DEX
  BNE DELAY3

  ; 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 XPOS
  LDY YPOS
  JSR DRAW

  ; Increment the position
  INC XPOS ; Move the image toward the right
  DEC YPOS ; Move the image toward the Top

  LDA $fe  ; this is a debugging code to check if this loop is being executed
  STA $0410

  ; Check branching condition for Loop
  LDA #28  ; Set the Accumulator with 28
  CMP XPOS ; If X position becomes 28, Move toward left
  BNE THIRDLOOP

THIRDLOOP is also almost the same as the other loops except for moving direction and branching conditions.


Make a Fourth Loop for bouncing off from the right wall toward up and left direction, and then going back to MAINLOOP

FOURTHLOOP:
  ; Set pointer to the image
  ; Use G_O or G_X as desired
  LDA #<G_O
  STA $10
  LDA #>G_O
  STA $11

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

  ; Delay to show the image
  LDY #$00
  LDX #$50
DELAY4:      ; Becareful for changing the TAG name 
  DEY        ; Otherwise you go back to the MAINLOOP
  BNE DELAY4
  DEX
  BNE DELAY4

  ; 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 XPOS
  LDY YPOS
  JSR DRAW

  ; Increment the position
  DEC XPOS ; Moving Left
  DEC YPOS ; Moving Upward

  LDA $fe  ; this is a debugging code to check if this loop is being executed
  STA $0510

  ; Check branching condition for Loop
  LDA YPOS ; Load the accumulator with current Y position
  CMP #00  ; Compare if it becomes Zero, Otherwise Goes back to FOURTHLOOP
  BNE FOURTHLOOP

JMP MAINLOOP ; When the FOURTHLOOP is finished, it goes back to the MAINLOOP
Output:

    




Thoughts about the lab:

This lab was quite difficult. How it creates the visual is still beyond me. I was frustrated by a few of the mistakes I made. I started by changing MAINLOOP to SECONDLOOP by copying it. But I couldn't figure out why the SECONDLOOP wasn't carried out. After just one attempt, it returned to MAINLOOP. This issue arose because I neglected to modify the DELAY tag, which caused it to revert to the DELAY in MAINLOOP. It was not too hard to change the image's direction of movement, but the logic of the painting and the branching and jumping were a little unclear. Setting the criteria and TAG name required extreme caution on my part. This lab taught me how to specify conditions for Branch instructions (BNE, BEQ, etc.) like utilizing CMP or zero flags, as well as how to use Branches and Jump.

That’s a wrap on the first part of this lab! We’ve managed to get the image bouncing across the screen—no small feat! While there were a few bumps along the way, figuring out the movement and branching logic was a rewarding challenge.

But hold on—this is just the beginning! In the next part of the blog, we’ll kick things up a notch by diving into some exciting optional challenges. From adding random movement to changing the image’s colour with every bounce, we’re going to bring this project to life in ways you never imagined! Don’t miss out—let’s make it even more dynamic and fun in the next round!

Comments

Popular posts from this blog

Project Stage 3: Enhancing GCC Pass for Multiple Function Clone Handling: Progress Update

Lab - 1: Exploring 6502 Assembly

Project Stage 1: Troubleshooting a bit - Coming soon