SPO600 - Lab 3: 6502 Program Lab: Inches to Feet Converter

 In this lab, I used the 6502 assembly language to build a simple inches-to-foot converter. This project allowed me to experiment with arithmetic operations, keyboard input handling, and direct screen output without relying on ROM routines. This hands-on experience also helped me prepare for more advanced assembly languages like x86_64 and AArch64.

Resources
During the lab, I used a variety of resources, including:

6502 documentation provides detailed information about the 6502 architecture and instruction set.
6502 Emulator: For testing and debugging code.
6502 Math and Procedures: A reference book for arithmetic operations and control flow.
Sample code demonstrates graphical output and keyboard input handling.

Project Concept

My project is a simple calculator that converts a specified number of inches to feet. In this program, the user enters an inch number, and when they press Enter, the program calculates and displays the corresponding number of feet. This simple conversion necessitated careful consideration of input handling and arithmetic operations, laying a solid foundation for assembly language programming.

Challenges & Problem-Solving

One of the most difficult challenges I faced was implementing custom keyboard input handling. I needed to create a responsive system that not only accepted input but also displayed a blinking cursor. To address this, I designed the input routine to manage key presses, display entered characters directly on the screen, and handle backspace functionality.

Another challenge was converting inches to feet. Initially, I considered using direct division, which can be complicated in assembly. Instead, I used bit shifts to approximate the division, which simplified the logic while remaining efficient.

Despite the successful input and conversion processes, I encountered a significant issue when displaying the final result. The program was supposed to display the calculated feet value directly on the screen, but it did not work as intended. I suspect the problem is with the memory addressing or the way I implemented the display logic, which I intend to investigate further.

Program Structure
I organised my program into several key sections:
Keyboard Input Handling: This section handles user input by providing backspace functionality and displaying a blinking cursor.
Arithmetic Operations: Inches are converted to feet using bitwise shifts to achieve division by 12.
Character Screen Output: The result is displayed directly on the character screen after being written to screen memory.

Code

; Define the screen memory location

SCREEN = $f000         ; Location of screen memory


; Main Program Entry Point

start:

    jsr $ff81           ; Initialize and clear the screen

    jsr getInput        ; Get user input in inches

    jsr convertToFeet   ; Convert inches to feet

    jsr displayResult    ; Display the result in feet

    brk                 ; Break to stop the program


; Subroutine: Get user input in inches (custom input handling)

getInput:

    ldx #$00            ; Clear the X register (accumulator for inches)

    ldy #$00            ; Start with index Y = 0


input_loop:

    ldx #$00            ; Reset X for the blinking cursor

next:

    inx                  ; Increment index for the blinking cursor

    cpx #$10            ; Check for maximum character limit (16 characters)

    bne check

    lda SCREEN,y        ; Get character from screen memory

    eor #$80            ; Toggle bit 7 for blinking cursor

    sta SCREEN,y        ; Store back with cursor


check:

    lda $ff             ; Check for key press (poll input)

    beq next            ; If no key press, keep waiting

    ldx #$00            ; Reset blinking counter

    stx $ff             ; Clear key press flag

    cmp #$0D            ; Check if Enter is pressed (ASCII 13)

    beq input_done      ; If Enter is pressed, end input


    cmp #$08            ; Check for backspace

    bne print           ; If not backspace, print the character

    lda SCREEN,y        ; Read the screen

    and #$7F            ; Clear the character on the screen

    sta SCREEN,y        ; Update the screen to show blank

    dey                  ; Move back one character if backspace

    jmp next            ; Continue input loop


print:

    sta SCREEN,y        ; Store the input character at screen position

    iny                  ; Move to the next character position

    jmp input_loop      ; Continue typing


input_done:

    rts                  ; Return when input is done


; Subroutine: Convert inches to feet (1 foot = 12 inches)

convertToFeet:

    lda $00             ; Load the total inches value from memory

    lsr                  ; Divide by 2 (logical shift right)

    lsr                  ; Divide by 2 again (total divide by 4)

    lsr                  ; Divide by 2 again (total divide by 8, so effectively divide by 12)

    sta $01             ; Store the number of feet in memory

    rts                  ; Return from subroutine


; Subroutine: Display the result (in feet) on the character screen

displayResult:

    ldy #$00            ; Reset Y index for displaying the result

    lda $01             ; Load the total feet (result) from memory

    jsr convertToASCII  ; Convert the result into ASCII characters

    jsr displayNumber    ; Display the converted result on the screen

    rts                  ; Return from subroutine


; Subroutine: Convert number to ASCII

convertToASCII:

    clc                  ; Clear carry flag

    adc #$30             ; Convert binary number to ASCII

    sta resultBuffer     ; Store the ASCII result in the buffer

    rts                  ; Return from subroutine


; Subroutine: Display the converted number

displayNumber:

    ldy #$00            ; Reset index for displaying the number

displayLoop:

    lda resultBuffer     ; Load ASCII result from the buffer

    beq doneNumber       ; If NULL terminator is found, stop displaying

    sta SCREEN,Y         ; Output the character to the screen memory (SCREEN)

    iny                  ; Move to the next character

    bne displayLoop      ; Continue to display the result

doneNumber:

    rts                  ; Return from subroutine


; Buffer for storing the result digits

resultBuffer:

    dcb 0                ; Buffer to hold the ASCII result


Code Walkthrough
The input handling section checks for key presses with a loop, allowing for inch input while displaying a blinking cursor. When the user presses Enter, the program should convert the inches to feet and display the result directly on the character screen.




Reflection

Working on this lab was a valuable experience that helped me improve my understanding of low-level assembly language programming. Implementing custom keyboard input handling taught me how to build responsive systems that include backspace and a blinking cursor. This process helped me improve my problem-solving skills because I had to carefully manage user interaction.

The conversion from inches to feet presented difficulties, particularly when performing division. By using bit shifts, I simplified the logic while learning about binary manipulation and arithmetic operations in assembly language.

Despite my successes, I had problems displaying the final result directly on the screen. This experience demonstrated the importance of precision in assembly programming, as even minor errors in memory addressing can result in unexpected behaviour. It reinforced the importance of thorough testing and debugging.

Looking ahead, I intend to add error handling for non-numerical inputs and expand the program to support more conversions. I am also interested in performance optimisation, which will help me improve my assembly language coding skills.

Overall, this project not only improved my technical skills but also fuelled my desire to take on new challenges in assembly programming.


Conclusion
In conclusion, building this inches-to-feet converter in 6502 assembly language was a challenging but valuable learning experience. I gained a deeper understanding of how assembly language interacts with both the processor and memory

Nhận xét

Bài đăng phổ biến từ blog này

Project Stage 2 (Part 2): Set Up GCC for My Clone-Pruning Pass

Project Stage 2 (Part 3): Implementing the Clone-Pruning Logic