LAB 2
Introduction:
In this lab, I will work with 6502 assembly language to perform how graphics are displayed and manipulated on a bitmapped screen. We provided a program that included a subroutine, which takes a rectangular image and places it at specified X and Y coordinates on the screen. The code calculates the correct screen memory address for the image using the position and dimensions provided, then copies the image data row by row to the screen memory. I began by testing this program by assembling and running it, ensuring it functioned correctly while observing how the DRAW subroutine works. After that I modified it to create a "bouncing graphic" animation. I started by setting an initial position for the graphic and defined increments for X and Y movement. The program then updated the graphic's position by adding these increments to its X and Y coordinates. When the graphic reached the screen's edges, the code reversed the direction by flipping the movement increment, creating a bouncing effect.
Initial 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:"
;
; 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
The image diagonally across the screen:
Bouncing Graphic:
LDA #$01STA XPOSLDA #$09STA YPOS
define XINC $22 ; X incrementdefine YINC $23 ; Y increment; Set increments to +1LDA #$01STA XINCSTA YINC
LDA XINC ; Load the value of XINCBEQ MOV_LEFT ; If RIGHT is false (XINC = 0), jump to MOV_LEFT; Move right, increment XPOSINC XPOSLDA #27CMP XPOS ; Check if XPOS reached 27BEQ REVERSE_X ; If XPOS is 27, reverse directionJMP MOV_Y ; Otherwise, move to Y-axis logicREVERSE_X:DEC XINC ; Reverse direction (set XINC to 0, moving left)JMP MOV_Y ; Proceed to Y-axis movementMOV_LEFT:; Move left, decrement XPOSDEC XPOSLDA #0CMP XPOS ; Check if XPOS reached 0BEQ REVERSE_X_LEFT ; If XPOS is 0, reverse directionJMP MOV_Y ; Otherwise, move to Y-axis logicREVERSE_X_LEFT:INC XINC ; Reverse direction (set XINC to 1, moving right)JMP MOV_Y ; Proceed to Y-axis movementMOV_Y:LDA YINC ; Load YINC value (DOWN flag)BEQ MOV_UP ; If DOWN is false (YINC = 0), jump to MOV_UP; Move down, increment YPOSINC YPOSLDA #27CMP YPOS ; Check if YPOS reached 27BEQ REVERSE_Y ; If YPOS is 27, reverse directionJMP MAINLOOP ; Otherwise, return to main loopREVERSE_Y:DEC YINC ; Reverse direction (set YINC to 0, moving up)JMP MAINLOOP ; Proceed back to main loopMOV_UP:; Move up, decrement YPOSDEC YPOSLDA #0CMP YPOS ; Check if YPOS reached 0BEQ REVERSE_Y_DOWN ; If YPOS is 0, reverse directionJMP MAINLOOP ; Otherwise, return to main loopREVERSE_Y_DOWN:INC YINC ; Reverse direction (set YINC to 1, moving down)JMP MAINLOOP ; Proceed back to main loop; Repeat infinitelyJMP MAINLOOP
;; 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 variablesdefine XPOS $20define YPOS $21define XINC $22 ; X increment (+1 or -1)define YINC $23 ; Y increment (+1 or -1)START:; Set up the width and height elements of the data structureLDA #$05STA $12 ; IMAGE WIDTHSTA $13 ; IMAGE HEIGHT; Set initial position X=Y=0LDA #$01STA XPOSLDA #$09STA YPOSLDA #$01STA XINCSTA YINC; Main loop for diagonal animationMAINLOOP:; 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 LABELLDA #<G_OSTA $10LDA #>G_OSTA $11; Place the image on the screenLDA #$10 ; Address in zeropage of the data structureLDX XPOS ; X positionLDY YPOS ; Y positionJSR DRAW ; Call the subroutine; Delay to show the imageLDY #$00LDX #$50DELAY:DEYBNE DELAYDEXBNE DELAY; Set pointer to the blank graphicLDA #<G_BLANKSTA $10LDA #>G_BLANKSTA $11; Draw the blank graphic to clear the old imageLDA #$10 ; LOCATION OF DATA STRUCTURELDX XPOSLDY YPOSJSR DRAWLDA XINC ; Load the value of XINCBEQ MOV_LEFT ; If RIGHT is false (XINC = 0), jump to MOV_LEFT; Move right, increment XPOSINC XPOSLDA #27CMP XPOS ; Check if XPOS reached 27BEQ REVERSE_X ; If XPOS is 27, reverse directionJMP MOV_Y ; Otherwise, move to Y-axis logicREVERSE_X:DEC XINC ; Reverse direction (set XINC to 0, moving left)JMP MOV_Y ; Proceed to Y-axis movementMOV_LEFT:; Move left, decrement XPOSDEC XPOSLDA #0CMP XPOS ; Check if XPOS reached 0BEQ REVERSE_X_LEFT ; If XPOS is 0, reverse directionJMP MOV_Y ; Otherwise, move to Y-axis logicREVERSE_X_LEFT:INC XINC ; Reverse direction (set XINC to 1, moving right)JMP MOV_Y ; Proceed to Y-axis movementMOV_Y:LDA YINC ; Load YINC value (DOWN flag)BEQ MOV_UP ; If DOWN is false (YINC = 0), jump to MOV_UP; Move down, increment YPOSINC YPOSLDA #27CMP YPOS ; Check if YPOS reached 27BEQ REVERSE_Y ; If YPOS is 27, reverse directionJMP MAINLOOP ; Otherwise, return to main loopREVERSE_Y:DEC YINC ; Reverse direction (set YINC to 0, moving up)JMP MAINLOOP ; Proceed back to main loopMOV_UP:; Move up, decrement YPOSDEC YPOSLDA #0CMP YPOS ; Check if YPOS reached 0BEQ REVERSE_Y_DOWN ; If YPOS is 0, reverse directionJMP MAINLOOP ; Otherwise, return to main loopREVERSE_Y_DOWN:INC YINC ; Reverse direction (set YINC to 1, moving down)JMP MAINLOOP ; Proceed back to main loop; Repeat infinitelyJMP MAINLOOP; ==========================================;; 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 locationsdefine IMGPTR $A0define IMGPTRH $A1define IMGWIDTH $A2define IMGHEIGHT $A3define SCRPTR $A4define SCRPTRH $A5define SCRX $A6define SCRY $A7DRAW:; SAVE THE X AND Y REG VALUESSTY SCRYSTX SCRX; GET THE DATA STRUCTURETAYLDA $0000,YSTA IMGPTRLDA $0001,YSTA IMGPTRHLDA $0002,YSTA IMGWIDTHLDA $0003,YSTA 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 SCRPTRLDA #$00STA SCRPTRHLDA SCRYSTA SCRPTR; NOW DO 5 LEFT SHIFTS TO MULTIPLY BY 32LDY #$05 ; NUMBER OF SHIFTSMULT:ASL SCRPTR ; PERFORM 16-BIT LEFT SHIFTROL SCRPTRHDEYBNE MULT; NOW ADD THE X VALUELDA SCRXCLCADC SCRPTRSTA SCRPTRLDA #$00ADC SCRPTRHSTA SCRPTRH; NOW ADD THE SCREEN BASE ADDRESS OF $0200; SINCE THE LOW BYTE IS $00 WE CAN IGNORE ITLDA #$02CLCADC SCRPTRHSTA SCRPTRH; NOTE WE COULD HAVE DONE TWO: INC SCRPTRH; NOW WE HAVE A POINTER TO THE IMAGE IN MEM; COPY A ROW OF IMAGE DATACOPYROW:LDY #$00ROWLOOP:LDA (IMGPTR),YSTA (SCRPTR),YINYCPY IMGWIDTHBNE ROWLOOP; NOW WE NEED TO ADVANCE TO THE NEXT ROW; ADD IMGWIDTH TO THE IMGPTRLDA IMGWIDTHCLCADC IMGPTRSTA IMGPTRLDA #$00ADC IMGPTRHSTA IMGPTRH; ADD 32 TO THE SCRPTRLDA #32CLCADC SCRPTRSTA SCRPTRLDA #$00ADC SCRPTRHSTA SCRPTRH; DECREMENT THE LINE COUNT AND SEE IF WE'RE; DONEDEC IMGHEIGHTBNE COPYROWRTS; ==========================================; 5x5 pixel images; Image of a blue "O" on black backgroundG_O:DCB $00,$0e,$0e,$0e,$00DCB $0e,$00,$00,$00,$0eDCB $0e,$00,$00,$00,$0eDCB $0e,$00,$00,$00,$0eDCB $00,$0e,$0e,$0e,$00; Image of a yellow "X" on a black backgroundG_X:DCB $07,$00,$00,$00,$07DCB $00,$07,$00,$07,$00DCB $00,$00,$07,$00,$00DCB $00,$07,$00,$07,$00DCB $07,$00,$00,$00,$07; Image of a black squareG_BLANK:DCB $00,$00,$00,$00,$00DCB $00,$00,$00,$00,$00DCB $00,$00,$00,$00,$00DCB $00,$00,$00,$00,$00DCB $00,$00,$00,$00,$00
Challege:
Permit integer values other than -1 and +1 for the X and Y increments (deltas):
XPOS
and YPOS
) has gone out of bounds.
Comments
Post a Comment