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)