Lab 02 - Math Lab
Lab 02 - Math Lab
This lab helped me understand boundary checking to control the direction of a moving graphic. Managing pixel placement and position updates is crucial to ensure the graphic behaves as expected, bouncing off the edges of the bitmapped screen in both directions.
Below is the original code that served as the foundation for this task:
; 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
Let's do a deep dive into the changes!
Variables and Initialization Updates
New variables were added to control the movement direction; XINC helps with ensuring graphic bounces horizontally when it hits left/right edges, while YINC controls the up/down movement when graphic hits the edges.
define XPOS $20
define YPOS $21
define XINC $22 - new variable added!
define YINC $23 - new variable added!
Used the instruction LDA #$01 to load and store in both XINC and YINC, ensuring that both start at 1. These could be used for reverse movement.
Previously:
LDA #$00 STA XPOS STA YPOS
Changes:
LDA #$01 - loads #$01 into accumulator from memory
STA XINC - stores 1 into memory (starts +1 due to increment)
STA YINC - stores 1 into memory
Updated INC XPOS and INC YPOS with XINC or YINC since XPOS and YPOS caused the graphic to never bounce.
Previously:
INC XPOS INC YPOS
Changes:
For X Update:
LDA XPOS
CLC - clears flag; initializes flag to 0
ADC XINC - usually used after clearing flag, adds memory to accumulator with carry
STA XPOS
For Y Update:
LDA YPOS
CLC - clears flag; initializes flag to 0
ADC YINC - usually used after clearing flag, adds memory to accumulator with carry
STA YPOS
Boundary Checks to Control Movement
There was no available logic to reverse the movement which is essential to make the graphic bounce in a reverse direction once it hits the edges.
Left/Right Edges - Reverse Movement:
X_MOV logic:
LDA XINC
EOR #$FF - "Exclusive OR" Memory with Accumulator; transfers memory to the adder and stores result to accumulator
CLC - clears flag; initializes flag to 0
ADC #$01 - usually used after clearing flag, adds memory to accumulator with carry
STA XINC
Used X_MOV:
CMP #$00 - compares 0 with XPOS
BEQ X_MOV - if flag is 0, condition follows which is X_MOV
CMP #$1B - checks if XPOS hits the max width
BEQ X_MOV - takes conditional branch when carry flag is on
Y_MOV logic:
LDA YINC
EOR #$FF - "Exclusive OR" Memory with Accumulator; transfers memory to the adder and stores result to accumulator
CLC - clears flag; initializes flag to 0
ADC #$01 - usually used after clearing flag, adds memory to accumulator with carry
STA YINC
JMP MAINLOOP
Used Y_MOV:
CMP #$00 - compares 0 with XPOS
BEQ Y_MOV - if flag is 0, condition follows which is X_MOV
CMP #$1B - checks if XPOS hits the max width
BCS Y_MOV - takes conditional branch when carry flag is on
JMP MAINLOOP
Last step I almost overlooked!
Looking at the movement, I realized it just keeps moving diagonally as it started at 0. To see the reverse movement, I had to start XPOS and YPOS at 5 and 8, respectively instead of having it start at the top leftmost edge.
LDA #$05 STA XPOSLDA #$07 Start Y at 7
Try it out yourself!
Copy and paste this code into a 6502 emulator!
define XPOS $20
define YPOS $21
define XINC $22
define YINC $23
START:
LDA #$05
STA $12
STA $13
LDA #$05
STA XPOS
LDA #$08
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 XPOS
CLC
ADC XINC
STA XPOS
CMP #$00
BEQ X_MOV
CMP #$1B
BCS X_MOV
JMP CHECK_Y
X_MOV:
LDA XINC
EOR #$FF
CLC
ADC #$01
STA XINC
CHECK_Y:
LDA YPOS
CLC
ADC YINC
STA YPOS
CMP #$00
BEQ Y_MOV
CMP #$1B
BCS Y_MOV
JMP MAINLOOP
Y_MOV:
LDA YINC
EOR #$FF
CLC
ADC #$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
Conclusion:
This lab was very challenging to me especially when I have just started learning the concept of talking to a machine, let alone involving instructions that control a graphic's movement. For someone who enjoys high-level coding, I believe this experience encouraged me to open my mind to learning Assembly Language. I am so thrilled to gain better knowledge in low-level programming which absolutely worthwhile!
Comments
Post a Comment