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.
Check out my 1-st post about 6502 Assembly: 6502 Assembly Intro
Find the 6502 emulator I used here: 6502 Emulator
Nice and colourful 6502 reference: Ultimate 6502 Reference
Sample code provided by our professor, Chris Tyler: 6502js-code
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
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
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)
- Conversion from inch to cm (8 inch -> ~24 cm)
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)