Lab 2 - Lab Results
Introduction
In this blog post, I will share my experience working on a lab where we animated a small 5x5 graphic to move diagonally across the screen and bounce off the edges. The lab required an understanding of low-level memory manipulation, conditional logic, and efficient screen rendering. I'll walk you through the code, the changes made to implement bouncing logic, and my reflections on the learning process.
**Since we collaborated as a group on optimizing the code, my work may resemble that of my teammates
===================================================================
Initial Code
The following code moves a 5×5 graphic diagonally across the screen:
; ; 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 START: ; Set up the width and height elements of the data structure 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 ; The syntax #<LABEL returns the low byte of LABEL ; The syntax #>LABEL returns the high byte of LABEL 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 START ; ========================================== ; ; 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
Code example:
Code example:
Code example:
Code example:
;
; draw-image-subroutine.bouncing.6502
;
; This routine places an arbitrary
; rectangular image on the screen at given
; coordinates and makes it bounce within
; the screen boundaries.
;
; 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 and bounces it off the edges
; Zero-page variables
define XPOS $20 ; Current X position
define YPOS $21 ; Current Y position
define XINC $22
define YINC $23
START:
LDA #$05
STA $12
STA $13
LDA #$0A
STA XPOS
LDA #$05
STA YPOS
LDA #$01
STA XINC
STA YINC
MAINLOOP:
LDA #<G_O
STA $10
LDA #>G_O
STA $11
LDA #$10
LDX XPOS
LDY YPOS
JSR DRAW
LDY #$00
LDX #$50
DELAY:
DEY
BNE DELAY
DEX
BNE DELAY
LDA #<G_BLANK
STA $10
LDA #>G_BLANK
STA $11
LDA #$10
LDX XPOS
LDY YPOS
JSR DRAW
LDA XINC
CMP #$01
BEQ INC_XPOS
LDA XPOS
SEC
SBC #$01
STA XPOS
JMP CHECK_X_BOUNDARY
INC_XPOS:
INC XPOS
CHECK_X_BOUNDARY:
LDA XPOS
CMP #$1B
BCC NO_CHANGE_X
LDA #$FF
STA XINC
JMP UPDATE_Y
NO_CHANGE_X:
LDA XPOS
CMP #$00
BNE UPDATE_Y
LDA #$01
STA XINC
UPDATE_Y:
LDA YINC
CMP #$01
BEQ INC_YPOS
LDA YPOS
SEC
SBC #$01
STA YPOS
JMP CHECK_Y_BOUNDARY
INC_YPOS:
INC YPOS
CHECK_Y_BOUNDARY:
LDA YPOS
CMP #$1B
BCC NO_CHANGE_Y
LDA #$FF
STA YINC
JMP MAINLOOP
NO_CHANGE_Y:
LDA YPOS
CMP #$00
BNE MAINLOOP
LDA #$01
STA YINC
JMP MAINLOOP
; ==========================================
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:
STY SCRY
STX SCRX
TAY
LDA $0000,Y
STA IMGPTR
LDA $0001,Y
STA IMGPTRH
LDA $0002,Y
STA IMGWIDTH
LDA $0003,Y
STA IMGHEIGHT
LDA #$00
STA SCRPTRH
LDA SCRY
STA SCRPTR
LDY #$05
MULT:
ASL SCRPTR
ROL SCRPTRH
DEY
BNE MULT
LDA SCRX
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
LDA #$02
CLC
ADC SCRPTRH
STA SCRPTRH
COPYROW:
LDY #$00
ROWLOOP:
LDA (IMGPTR),Y
STA (SCRPTR),Y
INY
CPY IMGWIDTH
BNE ROWLOOP
LDA IMGWIDTH
CLC
ADC IMGPTR
STA IMGPTR
LDA #$00
ADC IMGPTRH
STA IMGPTRH
LDA #32
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
DEC IMGHEIGHT
BNE COPYROW
RTS
; ==========================================
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
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
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==================================================================================Challenge Section Results
One of the challenges involved tweaking the delay loop to adjust the animation speed. A longer delay made movement smoother, while a shorter delay made it appear too fast or flickery. The balance was achieved with:
LDY #$00 LDX #$50 DELAY: DEY BNE DELAY DEX BNE DELAYAdditionally, another challenge was modifying the image to have different starting values for
XPOSandYPOSinstead of (0,0), making it more visually dynamic. ConclusionThrough working on this lab, I gained a deeper understanding of advanced concepts like subroutines, loops, and jumps. I faced some difficulty grasping decimal values, as they are represented in hex in the 6502 system. While adding and subtracting values are straightforward in decimals, it took me some time to figure out how to implement them using memory addresses and hex notation.
Overall, the 6502 Math Lab has helped me think more in the 6502 language. While concepts like if/else, loops, and functions are easy to implement in languages I’m familiar with, such as JavaScript, it was fascinating to see how these logic structures are handled in a low-level language!
Comments
Post a Comment