Lab 2 - 6502 Math Lab

The Mob Programming session emphasizes collaborative learning. Participants work in teams, designating a Driver (who types) and a Presenter (who explains the group's solution). The goal is to collectively understand and implement the 6502 Math Lab tasks.

Steps for Collaboration:

  1. Join a Zoom breakout group and assign roles.

  2. Decide on a code-sharing method (Git, Pastebin, email, or Zoom chat).

  3. Use the 6502 Emulator (http://6502.cdot.systems) to run and test code.

  4. Follow structured coding suggestions where non-Drivers provide coding instructions.

  5. Switch roles periodically to ensure collective learning.



The Setup 

The code below moves a 5×5 graphic diagonally across the screen like the series of images above. 

The speed can be adjusted with the speed slider.

;
; 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

Bouncing Graphic 


  • Select a starting location for the graphic where X and Y have different values.
; Set initial position for the graphic (different X and Y values)
LDA #$01        ; Set X position to 1
STA XPOS         ; Store in XPOS (X position)
LDA #$09        ; Set Y position to 9
STA YPOS         ; Store in YPOS (Y position)


  • Select an X increment that is -1 or +1, and a Y increment that is -1 or +1. You can choose to use either a signed byte or some other representation to hold these values.
; Set X and Y increments (+1 or -1) LDA #$01 ; Set X increment to +1 (move right) STA XINC ; Store in XINC LDA #$01 ; Set Y increment to +1 (move down) STA YINC ; Store in YINC
  •  Successively move the graphic by adding the X and Y increments to the graphic's X and Y position.
; Main loop for moving the graphic MAINLOOP: ; Move the graphic by adding the X and Y increments LDA XPOS CLC ADC XINC STA XPOS ; Update X position LDA YPOS CLC ADC YINC STA YPOS ; Update Y position
  • Make the graphic bounce when it hits the edge of the bitmapped screen, both vertically (when it hits the top/bottom) and horizontally (when it hits the left/right edge).

; Check for horizontal bounce (left-right)
LDA XPOS
CMP #$00            ; Check if X position reached 0 (left edge)
BEQ REVERSE_X_LEFT  ; If true, reverse direction (move right)
CMP #$1B            ; Check if X position reached 27 (right edge)
BEQ REVERSE_X       ; If true, reverse direction (move left)

; Check for vertical bounce (top-bottom)
LDA YPOS
CMP #$00            ; Check if Y position reached 0 (top edge)
BEQ REVERSE_Y_DOWN  ; If true, reverse direction (move down)
CMP #$1B            ; Check if Y position reached 27 (bottom edge)
BEQ REVERSE_Y       ; If true, reverse direction (move up)

JMP MAINLOOP         ; Continue moving the graphic

; Reverse direction horizontally (left)
REVERSE_X:
DEC XINC             ; Reverse X increment (move left)
JMP MAINLOOP

; Reverse direction horizontally (right)
REVERSE_X_LEFT:
INC XINC             ; Reverse X increment (move right)
JMP MAINLOOP

; Reverse direction vertically (up)
REVERSE_Y:
DEC YINC             ; Reverse Y increment (move up)
JMP MAINLOOP

; Reverse direction vertically (down)
REVERSE_Y_DOWN:
INC YINC             ; Reverse Y increment (move down)
JMP MAINLOOP
Entire 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 POS_X $20 define POS_Y $21 define INC_X $22 ; X increment (+1 or -1) define INC_Y $23 ; Y increment (+1 or -1) INIT: ; 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 #$01 STA POS_X LDA #$09 STA POS_Y LDA #$01 STA INC_X STA INC_Y ; Main loop for diagonal animation LOOP: ; 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 POS_X ; X position LDY POS_Y ; 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 POS_X LDY POS_Y JSR DRAW LDA INC_X ; Load the value of INC_X BEQ MOVE_LEFT ; If RIGHT is false (INC_X = 0), jump to MOVE_LEFT ; Move right, increment POS_X INC POS_X LDA #27 CMP POS_X ; Check if POS_X reached 27 BEQ REVERSE_X ; If POS_X is 27, reverse direction JMP MOVE_Y ; Otherwise, move to Y-axis logic REVERSE_X: DEC INC_X ; Reverse direction (set INC_X to 0, moving left) JMP MOVE_Y ; Proceed to Y-axis movement MOVE_LEFT: ; Move left, decrement POS_X DEC POS_X LDA #0 CMP POS_X ; Check if POS_X reached 0 BEQ REVERSE_X_LEFT ; If POS_X is 0, reverse direction JMP MOVE_Y ; Otherwise, move to Y-axis logic REVERSE_X_LEFT: INC INC_X ; Reverse direction (set INC_X to 1, moving right) JMP MOVE_Y ; Proceed to Y-axis movement MOVE_Y: LDA INC_Y ; Load INC_Y value (DOWN flag) BEQ MOVE_UP ; If DOWN is false (INC_Y = 0), jump to MOVE_UP ; Move down, increment POS_Y INC POS_Y LDA #27 CMP POS_Y ; Check if POS_Y reached 27 BEQ REVERSE_Y ; If POS_Y is 27, reverse direction JMP LOOP ; Otherwise, return to main loop REVERSE_Y: DEC INC_Y ; Reverse direction (set INC_Y to 0, moving up) JMP LOOP ; Proceed back to main loop MOVE_UP: ; Move up, decrement POS_Y DEC POS_Y LDA #0 CMP POS_Y ; Check if POS_Y reached 0 BEQ REVERSE_Y_DOWN ; If POS_Y is 0, reverse direction JMP LOOP ; Otherwise, return to main loop REVERSE_Y_DOWN: INC INC_Y ; Reverse direction (set INC_Y to 1, moving down) JMP LOOP ; Proceed back to main loop ; Repeat infinitely JMP LOOP ; ========================================== ; ; 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 IMG_PTR $A0 define IMG_PTR_H $A1 define IMG_WIDTH $A2 define IMG_HEIGHT $A3 define SCR_PTR $A4 define SCR_PTR_H $A5 define SCR_X $A6 define SCR_Y $A7 DRAW: ; SAVE THE X AND Y REG VALUES STY SCR_Y STX SCR_X ; GET THE DATA STRUCTURE TAY LDA $0000,Y STA IMG_PTR LDA $0001,Y STA IMG_PTR_H LDA $0002,Y STA IMG_WIDTH LDA $0003,Y STA IMG_HEIGHT ; CALCULATE THE START OF THE IMAGE ON ; SCREEN AND PLACE IN SCR_PTR_H ; ; THIS IS $0200 (START OF SCREEN) + ; SCR_X + SCR_Y * 32 ; ; WE'LL DO THE MULTIPLICATION FIRST ; START BY PLACING SCR_Y INTO SCR_PTR LDA #$00 STA SCR_PTR_H LDA SCR_Y STA SCR_PTR ; NOW DO 5 LEFT SHIFTS TO MULTIPLY BY 32 LDY #$05 ; NUMBER OF SHIFTS MULT: ASL SCR_PTR ; PERFORM 16-BIT LEFT SHIFT ROL SCR_PTR_H DEY BNE MULT ; NOW ADD THE X VALUE LDA SCR_X CLC ADC SCR_PTR STA SCR_PTR LDA #$00 ADC SCR_PTR_H STA SCR_PTR_H ; NOW ADD THE SCREEN BASE ADDRESS OF $0200 ; SINCE THE LOW BYTE IS $00 WE CAN IGNORE IT LDA #$02 CLC ADC SCR_PTR_H STA SCR_PTR_H ; NOTE WE COULD HAVE DONE TWO: INC SCR_PTR_H ; NOW WE HAVE A POINTER TO THE IMAGE IN MEM ; COPY A ROW OF IMAGE DATA COPY_ROW: LDY #$00 ROW_LOOP: LDA (IMG_PTR),Y STA (SCR_PTR),Y INY CPY IMG_WIDTH BNE ROW_LOOP ; NOW WE NEED TO ADVANCE TO THE NEXT ROW ; ADD IMG_WIDTH TO THE IMG_PTR LDA IMG_WIDTH CLC ADC IMG_PTR STA IMG_PTR LDA #$00 ADC IMG_PTR_H STA IMG_PTR_H ; ADD 32 TO THE SCR_PTR LDA #32 CLC ADC SCR_PTR STA SCR_PTR LDA #$00 ADC SCR_PTR_H STA SCR_PTR_H ; DECREMENT THE LINE COUNT AND SEE IF WE'RE ; DONE DEC IMG_HEIGHT BNE COPY_ROW 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


  • Permit integer values other than -1 and +1 for the X and Y increments (deltas)

We need to allow X_STEP and Y_STEP to be any signed integer.

The values in X_STEP and Y_STEP are used to update X_COORD

and Y_COORD, which determine the image's position on the screen.

We then check if the image's current position (X_COORD and Y_COORD)

has gone out of bounds.


ADC X_STEP ADC Y_STEP


  • Permit fractional values for the X and Y increments (e.g., +1.5 or -0.75). One way of doing this would be to use 16-bit (2-byte) X and Y increment values (deltas), where the lowest byte is fractional and the highest byte is integer (i.e., the radix point is between the two bytes).

define XSTEP_FRAC $30 ; Fractional part of X increment (0-255) define XSTEP_INT $31 ; Integer part of X increment (-128 to 127)

define YSTEP_INT $33 ; Integer part of Y increment (-128 to 127)
define YSTEP_FRAC $32 ; Fractional part of Y increment (0-255)


  • Perturb (subtly disrupt or randomize) the ball's position or bounce so that it is not overly predictable. (Remember that there's a pseudo-random number generator available in memory location $00FE).

  • Change the graphic image or colour each time it bounces.

Reflection

Working with Assembly Language was both challenging and eye-opening. Unlike high-level languages, it required precise control over hardware operations. I learned how to manipulate data at the byte level, handle signed and unsigned integers, and use conditional jumps for program flow. Debugging was difficult, but it helped me develop a deeper understanding of low-level computing. This lab reinforced my appreciation for modern programming abstractions while highlighting the power of working close to the hardware.

Comments

Popular posts from this blog

Project Stage 1

Lab05 - x86_64

Lab 03 - 6502 Program Lab (Revised)