Lab - 2 In-Class: Mob Programming
Introduction
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
; 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.
; Increment the position
DEC XPOS ; Image moving left by decreasing X position
INC YPOS
; 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
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
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
Post a Comment