DEV Community

Krinskumar Vaghasia
Krinskumar Vaghasia

Posted on • Edited on

SPO Week 3.1 - full lab

Lab Report: 6502 Emulator Calculator
This lab was one of my favorites; we had the freedom to create whatever we wanted. I decided to make a calculator that runs on a 6502 emulator. This calculator prompts the user for two two-digit numbers and displays the result on both the screen and the text window. I utilized some code from the example provided by our professor to help me get started.

Concept and Design
The primary goal of this project was to develop a simple yet effective calculator capable of handling basic arithmetic operations using the 6502 assembly language. I aimed for a user-friendly interface that would allow users to easily input their numbers and clearly see the results. In designing the calculator, I focused on usability and clarity, ensuring that each step of the process was intuitive for the user.

Implementation
The implementation involved several key steps, each contributing to the overall functionality of the calculator:

Input Handling: I created a robust function to read user input, ensuring that the calculator only accepted valid two-digit numbers. This step was crucial for maintaining the intended functionality and preventing errors during calculations. I implemented strict checks to reject any input that did not meet the criteria, including letters or out-of-range numbers.

Arithmetic Operations: I wrote specific functions to handle addition. The addition function takes two numbers as input, performs the arithmetic operation, and returns the result. Writing this function in assembly language required me to work closely with the processor and memory, deepening my understanding of how low-level programming interacts with hardware.

Output Display: The results are displayed both on the screen and in a dedicated text window, providing immediate feedback to the user. I paid special attention to formatting the output for clarity and ease of reading. I aimed to ensure that users could easily interpret the results without confusion.

Using Provided Code: To enhance the efficiency of my project, I incorporated some snippets from the example code our professor shared. This not only saved development time but also allowed me to learn and understand best practices in assembly programming, such as effective memory management and input/output routines.

Challenges Faced
Throughout the development process, I encountered several challenges, the most significant of which was ensuring that user input was valid. Implementing input validation checks required careful attention, as I had to identify potential failure points in the code where incorrect inputs could cause errors. Debugging this part of the code proved to be quite a task, demanding a methodical approach to tracing the flow of data and identifying issues.

Additionally, I faced difficulties in getting the numbers to print correctly on the screen. This involved creating ASCII art representations for each digit and meticulously mapping their locations on the display. I had to ensure that each number was rendered accurately, which required significant trial and error. However, overcoming these challenges ultimately enhanced my problem-solving skills and increased my familiarity with the assembly language.

Conclusion
Overall, this project was a great learning experience. It not only reinforced my understanding of assembly language and the 6502 architecture but also allowed me to express my creativity in designing a functional tool. Seeing my calculator come to life was incredibly rewarding, and I enjoyed every moment of the process. The hands-on experience I gained through this lab has significantly enriched my programming skills and knowledge.

Reflecting on this lab, I appreciate the opportunity to explore my interests and learn through practical experience. The freedom to design and implement a project that resonated with my interests inspired me to continue experimenting with programming concepts. I am eager to apply the skills I developed in this lab to future projects and further enhance my proficiency in assembly language programming.

Screenshots
Handling a two digit addition and displaying

Image description

Handling a two digit addition with a three digit result

Image description

; ROM routine entry points
define      SCINIT      $ff81 ; initialize/clear screen
define      CHRIN       $ffcf ; input character from keyboard
define      CHROUT      $ffd2 ; output character to screen
define      SCREEN      $ffed ; get screen size
define      PLOT        $fff0 ; get/set cursor coordinates

; zeropage variables
define      PRINT_PTR   $10
define      PRINT_PTR_H $11
; 12 for number height
; 13 for number width
define      value       $14
define      value_h     $15
define    operation $1
define    XPOS $20
define    YPOS $21

; absolute variables
define      GETNUM_1    $0080
define      GETNUM_2    $0081


; set width and height of numbers on the screen
LDA #$05
STA $12       ; IMAGE WIDTH
STA $13       ; IMAGE HEIGHT

; Set initial position X=Y=0
LDA #$01
STA XPOS
STA YPOS

jsr SCINIT
jsr CHRIN
jsr PRINT
dcb "C","a","l","c","u","l","a","t","o","r",00


ADDNUMBERS:

  ; get the first number
  jsr PRINT
  dcb $0d,$0d,"E","n","t","e","r",32,"a",32,"n","u","m","b","e","r"
  dcb "(","0","-","9","9",")",":"
  dcb 32,32,32,32,32,32,32,32,00
  lda #$00
    sta value_h
    jsr GETNUM
    sta value

  ; get the second number
    jsr PRINT
  dcb "E","n","t","e","r",32,"a","n","o","t","h","e","r"
  dcb 32,"n","u","m","b","e","r",32,"(","0","-","9","9",")",":",32,00

  jsr GETNUM

  sed
    clc
    adc value
    cld

    sta value
    bcc result
    inc value_h

result:     
    pha
        jsr PRINT

  dcb "R","e","s","u","l","t",":",32
  dcb 32,32,32,32,32,32,32
  dcb 32,32,32,32,32,32,32
  dcb 32,32,32,32,32,32,32
  dcb 00

        lda value_h
        beq low_digits
        and #$0f
        ora #$30
        jsr CHROUT

    jsr update_value
    ; draw this digit 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
    LDA XPOS       ; Load the current value of XPOS into the accumulator
    CLC             ; Clear the carry flag to ensure proper addition
    ADC #$06       ; Add the immediate value 6 to the accumulator
    STA XPOS       ; Store the new value back into XPOS

        jmp draw_100s

low_digits: lda value
        and #$f0
        beq ones_digit

draw_100s:  lda value
        lsr
        lsr
        lsr
        lsr
        ora #$30
        jsr CHROUT

    jsr update_value
    ; draw this digit 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
    LDA XPOS       ; Load the current value of XPOS into the accumulator
    CLC             ; Clear the carry flag to ensure proper addition
    ADC #$06       ; Add the immediate value 6 to the accumulator
    STA XPOS       


ones_digit: lda value
        and #$0f
        ora #$30
        jsr CHROUT
    jsr update_value
    ; draw this digit 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
    LDA XPOS       ; Load the current value of XPOS into the accumulator
    CLC             ; Clear the carry flag to ensure proper addition
    ADC #$06       ; Add the immediate value 6 to the accumulator
    STA XPOS   

  ; end the programe
  RTS  


; ==========================================
;
; 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 $0006,Y
  STA IMGPTR
  LDA $0007,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


PRINT:      pla
        clc
        adc #$01
        sta PRINT_PTR
        pla
        sta PRINT_PTR_H

        tya
        pha

        ldy #$00
print_next: lda (PRINT_PTR),y
        beq print_done

        jsr CHROUT
        iny
        jmp print_next

print_done: tya
        clc
        adc PRINT_PTR
        sta PRINT_PTR

        lda PRINT_PTR_H
        adc #$00
        sta PRINT_PTR_H

        pla
        tay

        lda PRINT_PTR_H
        pha
        lda PRINT_PTR
        pha

        rts

; ---------------------------------------------------
; GETNUM - get a 2-digit decimal number
;
; Returns A containing 2-digit BCD value

GETNUM:     txa
        pha
        tya
        pha

        ldx #$00    ; count of digits received
        stx GETNUM_1
        stx GETNUM_2


getnum_cursor:  lda #$a0    ; black square
        jsr CHROUT
        lda #$83    ; left cursor
        jsr CHROUT

getnum_key: jsr CHRIN
        cmp #$00
        beq getnum_key

        cmp #$08    ; BACKSPACE
        beq getnum_bs

        cmp #$0d    ; ENTER
        beq getnum_enter

        cmp #$30    ; "0"
        bmi getnum_key

        cmp #$3a    ; "9" + 1
        bmi getnum_digit

        jmp getnum_key

getnum_enter:   cpx #$00
        beq getnum_key

        lda #$20
        jsr CHROUT
        lda #$0d
        jsr CHROUT

        lda GETNUM_1

        cpx #$01
        beq getnum_done

        asl
        asl
        asl
        asl
        ora GETNUM_2

getnum_done:    sta GETNUM_1
        pla
        tay
        pla
        tax
        lda GETNUM_1

        rts

getnum_digit:   cpx #$02
        bpl getnum_key
        pha
        jsr CHROUT
        pla
        and #$0f
        sta GETNUM_1,x
        inx
        jmp getnum_cursor

getnum_bs:  cpx #$00
        beq getnum_key
        lda #$20
        jsr CHROUT
        lda #$83
        jsr CHROUT
        jsr CHROUT
        lda #$20
        jsr CHROUT
        lda #$83
        jsr CHROUT
        dex
        lda #$00
        sta GETNUM_1,x
        jmp getnum_cursor

update_value:
    cmp #$31       ; Compare with '0'
    bmi update_0   ; If less than '0', jump to update_0

    cmp #$32       ; Compare with '1'
    bmi update_1   ; If less than '1', jump to update_1

    cmp #$33       ; Compare with '2'
    bmi update_2   ; If less than '2', jump to update_2

    cmp #$34       ; Compare with '3'
    bmi update_3   ; If less than '3', jump to update_3

    cmp #$35       ; Compare with '4'
    bmi update_4   ; If less than '4', jump to update_4

    cmp #$36       ; Compare with '5'
    bmi update_5   ; If less than '5', jump to update_5

    cmp #$37       ; Compare with '6'
    bmi update_6   ; If less than '6', jump to update_6

    cmp #$38       ; Compare with '7'
    bmi update_7   ; If less than '7', jump to update_7

    cmp #$39       ; Compare with '8'
    bmi update_8   ; If less than '8', jump to update_8

    cmp #$40       ; Compare with '9'
    bmi update_9   ; If less than '9', jump to update_9

    rts             ; Return if no updates are made

update_0:
    LDA #<N_0
    STA $16
    LDA #>N_0
    STA $17
    rts

update_1:
    LDA #<N_1
    STA $16
    LDA #>N_1
    STA $17
    rts

update_2:
    LDA #<N_2
    STA $16
    LDA #>N_2
    STA $17
    rts

update_3:
    LDA #<N_3
    STA $16
    LDA #>N_3
    STA $17
    rts

update_4:
    LDA #<N_4
    STA $16
    LDA #>N_4
    STA $17
    rts

update_5:
    LDA #<N_5
    STA $16
    LDA #>N_5
    STA $17
    rts

update_6:
    LDA #<N_6
    STA $16
    LDA #>N_6
    STA $17
    rts

update_7:
    LDA #<N_7
    STA $16
    LDA #>N_7
    STA $17
    rts

update_8:
    LDA #<N_8
    STA $16
    LDA #>N_8
    STA $17
    rts

update_9:
    LDA #<N_9
    STA $16
    LDA #>N_9
    STA $17
    rts





; ==========================================
; 5x5 pixel numbers
; Image of a blue "O" on black background
G_O:
DCB $11,$11,$11,$11,$11
DCB $11,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11
DCB $00,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11

N_0:
DCB $00,$11,$11,$11,$00
DCB $11,$00,$00,$00,$11
DCB $11,$00,$00,$00,$11
DCB $11,$00,$00,$00,$11
DCB $00,$11,$11,$11,$00

N_1:
DCB $00,$11,$11,$00,$00
DCB $11,$00,$11,$00,$00
DCB $11,$00,$11,$00,$00
DCB $00,$00,$11,$00,$00
DCB $11,$11,$11,$11,$11

N_2:
DCB $00,$11,$11,$11,$11
DCB $11,$00,$00,$11,$00
DCB $00,$00,$11,$00,$00
DCB $00,$11,$00,$00,$11
DCB $11,$11,$11,$11,$00

N_3:
DCB $11,$11,$11,$11,$11
DCB $00,$00,$00,$00,$11
DCB $00,$00,$11,$11,$11
DCB $00,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11

N_4:
DCB $00,$00,$00,$11,$00
DCB $00,$00,$11,$11,$00
DCB $00,$11,$00,$11,$00
DCB $11,$11,$11,$11,$11
DCB $00,$00,$00,$11,$00

N_5:
DCB $11,$11,$11,$11,$11
DCB $11,$00,$00,$00,$00
DCB $11,$11,$11,$11,$11
DCB $00,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11

N_6:
DCB $11,$11,$11,$11,$11
DCB $11,$00,$00,$00,$00
DCB $11,$11,$11,$11,$11
DCB $11,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11

N_7:
DCB $11,$11,$11,$11,$00
DCB $00,$00,$00,$11,$00
DCB $00,$00,$11,$11,$11
DCB $00,$00,$00,$11,$00
DCB $00,$00,$00,$11,$00

N_8:
DCB $11,$11,$11,$11,$11
DCB $11,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11
DCB $11,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11

N_9:
DCB $11,$11,$11,$11,$11
DCB $11,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11
DCB $00,$00,$00,$00,$11
DCB $11,$11,$11,$11,$11

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)