DEV Community

arinak1017
arinak1017

Posted on

6502 Length Converter

Hello, Blog!

If you have just stumbled upon my SPO600 series of blog posts, it has been created to document and share my learnings as I progress through my Software Portability and Optimization college course.

The end of the term is around the corner, and I’m continuing to tackle my backlog of blog posts. Today, I’m sharing my experience completing Lab 3 for the Software Portability and Optimization course.

An inches-and-feet to centimeter converter

In Lab 3, we were tasked to write a 6502 assembly program involving math operations and string manipulation. To be brutally honest, I chose to write a length converter due to time constraints, creating a full game in assembly felt too ambitious given the complexity.

That said, even writing a "simple" inches-and-feet-to-centimeters converter turned out to be incredibly challenging (just like writing anything in assembly).

To write this code I had to deal with:

  • Handling user input and strings: learning to work with ROM routines for basic I/O.
  • Branching and jumps: refreshing the fundamentals of conditional branching and program flow.
  • Challenging arithmetic operations: implementing multi-step calculations using decimal and binary-coded decimal (BCD) math.
  • A LOT of trial and error: iterating through countless debugging cycles to get everything working.

I borrowed the printing logic from our professor, Chris Tyler.
You can find the original implementation here

The Final Solution

This program is a basic unit converter for lengths. Users can choose to convert from inches or feet to centimeters. After selecting a unit (1 for inches or 2 for feet), they enter a one-digit number (0-9). The program then calculates the result using approximated conversion factors (3 cm per inch or 30 cm per foot) and displays it in centimeters. It uses binary-coded decimal (BCD) arithmetic for calculating conversions. Once the result is shown, the program starts over, letting users make another conversion.

The main loop illustrates the overall structure of the program:

MAINLOOP:
    JSR RESET             ; Reset variables
    JSR PRINT_WELCOME     ; Show welcome message
    JSR PROMPT_UNIT_INPUT ; Get unit selection
    JSR GET_NUMBER        ; Get number input
    JSR CONVERT           ; Convert to centimeters
    JSR SHOW_RESULT       ; Display the result
    JMP MAINLOOP          ; Restart
Enter fullscreen mode Exit fullscreen mode

Here is the key code logic:

; Get unit selection
GET_UNIT_INPUT:
    JSR CHRIN          ; Get input    
    CMP #$31           ; Check if 1 pressed
    BEQ UNIT_INCHES
    CMP #$32           ; Check if 2 pressed
    BEQ UNIT_FEET

    JMP GET_UNIT_INPUT ; If neither, keep waiting

; Handle inch selection
UNIT_INCHES:
    JSR PRINT
    DCB "I","n","c","h","e","s",32,"s","e","l","e","c","t","e","d","!",$0d,00
    LDA #$01
    STA UNIT_TYPE
    JMP PROMPT_NUMBER

; Handle feet selection
UNIT_FEET:
    JSR PRINT
    DCB "F","e","e","t",32,"s","e","l","e","c","t","e","d","!",$0d,00
    LDA #$02
    STA UNIT_TYPE
    JMP PROMPT_NUMBER

PROMPT_NUMBER:
    JSR PRINT
    DCB $0d,"E","N","T","E","R",32,"N","U","M","B","E","R",32
    DCB "(","0","-","9",")",":"
    DCB 32,00
    RTS

; Get number from user
GET_NUMBER:
    LDA #$00
    STA INPUT_NUM      ; Clear input storage

READ_DIGIT:
    JSR CHRIN          ; Get character from keyboard
    CMP #$0d           ; Check for ENTER key
    BEQ PROCESS_NUMBER

    CMP #$30           ; Check if less than 0
    BCC READ_DIGIT
    CMP #$3a           ; Check if greater than 9
    BCS READ_DIGIT

    CPX #$01           ; Already have a digit?
    BCS READ_DIGIT     ; If yes, ignore

    PHA                ; Save digit temporarily
    JSR CHROUT         ; Display it
    PLA                ; Retrieve digit

    AND #$0f           ; Convert from ASCII to binary
    STA INPUT_NUM      ; Store directly
    INX
    JMP READ_DIGIT

; Process completed number input
PROCESS_NUMBER:
    LDA #$0d           ; Print newline
    JSR CHROUT
    LDA INPUT_NUM      ; Load final number
    CPX #$00           ; Check if no digits entered
    BEQ READ_DIGIT     ; If none, keep waiting
    RTS

; Convert number based on selected unit
CONVERT:
    SED                ; Set decimal mode for BCD math
    LDA INPUT_NUM
    STA RESULT_L       ; Store initial value
    LDA #$00
    STA RESULT_H

    LDA UNIT_TYPE      ; Check which conversion to do
    CMP #$01
    BEQ CONVERT_INCHES
    JMP CONVERT_FEET

; Convert inches to centimeters (×3)
CONVERT_INCHES:
    LDA INPUT_NUM
    CLC
    ADC INPUT_NUM      ; ×2
    CLC
    ADC INPUT_NUM      ; ×3
    STA RESULT_L
    LDA #$00           ; Clear high byte
    STA RESULT_H
    CLD
    RTS

; Convert feet to centimeters (×30)
CONVERT_FEET:
    SED                ; Set decimal mode (for BCD math)

    ; Multiply by 10
    LDA INPUT_NUM
    STA RESULT_L       ; Store in RESULT_L
    LDA #$00
    STA RESULT_H       ; Clear high byte (start at zero)

    LDX #$09           ; Loop 9 times to add the number to itself (×10)
multiply_by_10:
    CLC
    LDA RESULT_L
    ADC INPUT_NUM
    STA RESULT_L
    LDA RESULT_H
    ADC #$00
    STA RESULT_H
    DEX
    BNE multiply_by_10

    ; Store the result of ×10 in a temporary variable
    LDA RESULT_L
    STA TEMP_L         ; Store low byte
    LDA RESULT_H
    STA TEMP_H         ; Store high byte

    ; Multiply by 3 (add twice more)
    LDY #$02           ; Loop 2 times to add the current result to itself
multiply_by_3:
    CLC
    LDA RESULT_L
    ADC TEMP_L
    STA RESULT_L
    LDA RESULT_H
    ADC TEMP_H
    STA RESULT_H
    DEY
    BNE multiply_by_3

    CLD                ; Clear decimal mode
    RTS
Enter fullscreen mode Exit fullscreen mode

If you’d like to see the complete implementation, feel free to check it out on GitHub.

Execution of my converter

  • Conversion from feet to cm (9 feet -> ~270 cm) Image description
  • Conversion from inch to cm (8 inch -> ~24 cm) Image description

Limitations

  • Single-digit input
  • No floating-point support
  • Approximated conversion factors (1 inch = 3 cm vs. 1 inch = 2.54 cm; 1 foot = 30 cm vs. 1 foot = 30.48 cm)
  • Lack of thorough error handling

Afterthoughts

This is the most complex assembly program I have written as of yet. Completing it required refreshing my understanding of how the 6502 processor handles data, performs arithmetic, and manages program flow. Along the way, I encountered some of the limitations of the 6502, such as its lack of native support for multiplication or floating-point arithmetic. Getting the multiplications right and implementing I/O operations were definitely the most challenging parts of this project. This lab really pushed me making the results more rewarding.

Top comments (0)