Lab 2 COMPLETE

 This is the second part of lab number 2 where I had to develop assembly code to change the bouncing pattern to bounce between the corners of the screen.

Before I start writing the actual code, I'm going to speculate on what needs to be done in order to achieve this effect. We already have a way to change the incrementation of the x and y pos, as previously written about in my previous post. The next step will be to check x and y boundaries so that the program will know when to bounce back and change the x and y increments into a negative value.

This is the code for the x and y position increments:

define XPOS $20

define YPOS $21

define XINC $22

define YINC $23

First we define the X and YINC variables and assign them in memory, then we will simply use LDA and STA to set their values.

; 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

define XINC $22  ; X increment for bouncing

define YINC $23  ; Y increment for bouncing


; 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


; Set initial increment values

LDA #$01      ; Initial X increment is +1

STA XINC

LDA #$01      ; Initial Y increment is +1

STA YINC


; Main loop for diagonal bouncing 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


  

  LDX XPOS

  LDA XINC

  CLC

  ADC XPOS

  CMP #$00       

  BMI REVX       

  CMP #$1C       


SKIPX:

  ; Increment the X position by XINC

  LDA XPOS

  CLC

  ADC XINC

  STA XPOS



  LDY YPOS

  LDA YINC

  CLC

  ADC YPOS

  CMP #$00       

  BMI REVY      

  CMP #$1B      


SKIPY:

  ; Increment the Y position by YINC

  LDA YPOS

  CLC

  ADC YINC

  STA YPOS


  ; Continue the main loop

  JMP MAINLOOP


REVX:

  ; Reverse the X direction by negating XINC

  LDA XINC

  EOR #$FF       

  CLC

  ADC #$01       

  STA XINC

  JMP SKIPX


REVY:

  ; Reverse the Y direction by negating YINC

  LDA YINC

  EOR #$FF     

  ADC #$01       

  STA YINC

  JMP SKIPY


; ==========================================

;

; 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 above code is the full code to implement the bouncing mechanics to the program. This took much longer than I expected and was very difficult to add. The idea behind changing it was rather simple and the logic was easy to come up with but actually implementing it was very difficult. To simply put it I added a X and Y boundary check first. 


LDX XPOS
LDA XINC
CLC
ADC XPOS
CMP #$00       ; Check if less than 0
BMI REVX       ; Reverse direction if out of bounds (negative)
CMP #$1C       ; Check if greater than or equal to 28 (right edge)
BPL REVX.     ; Reverse direction if out of bounds (too far right)

Prior to updating the position, the code checks if XPOS is out of bounds 0-28, and then reverses XINC variable to add the bounce back, the same is done for YPOS.

Next is the REVX and REVY methods. 
REVX:
  LDA XINC
  EOR #$FF       
  CLC
  ADC #$01       
  STA XINC
  JMP SKIPX

When the position of X OR Y hits the boundary I used two's compliment to negate XINC, this causes the the image to bounce and reverse directions.

The SKIPX and SKIPY are very simple and just add the X and YINC variables to adjust the positions.

Overall, this lab was very difficult for me as I had to learn lots of new instructions, and browse through the many instructions in the instruction set to find the correct one. This lab felt like a really big jump between the first.






Comments

Popular posts from this blog

Early stages of project

Building GCC again on aarch64-002

Project Stage 2: Testing