BATCH 3 | LAB 3 - Working Code for Addition and Subtraction Calculator

 Lab 3 - Addition and Subtraction


Hi everyone! If you've been following along, you will notice in my list of blog posts that I previously wrote an assembly code for a simple addition and subtraction calculator designed for the 6502 Emulator. Unfortunately, my first attempt did not work as intended. So now, here's an improved and fully testable version that performs much better.

Before we jump into testing the code, let's break down each part of the code to understand exactly what's happening.

1. Predefined ROM Routines and Constants

To use the ROM routines, we were provided with define directives to paste into our code. These directives were taken from Chris Tyler's Wiki

 

define SCINIT   $ff81 

define CHRIN    $ffcf

define CHROUT   $ffd2

define SCREEN   $ffed

define PLOT     $fff0  

 

2. Zero Page Memory Locations

These define directives reserve addresses in the zero page for storing data including INPUT1 and INPUT2 that store the numeric values of the first and second digits, RESULT that holds the result of the operation. OPERATOR that stores the operator character for + and - operations and RESULT_TEMP that is used during the process of converting the number into a readable form.

 

define INPUT1       $0010   

define INPUT2       $0011   

define RESULT       $0012    

define OPERATOR     $0013    

define RESULT_TEMP  $0014    

 

3. ASCII Character Define Directives

These define directives provide readable names for ASCII codes and are used in input routines or screen output to compare or print characters.

 

define BACKSPACE    $08  

define ENTER        $0D  

define SPACE        $20

define BLACK        $A0

define LEFT         $83

 

4. Jump for Execution

The first executable instruction is a jump so that the CPU starts executing at START. Prevents the CPU from mistakenly interpreting data as code..

     JMP START

5. Prompt Messages

Using DCB to prompt messages to be displayed. Each string is defined character by character in hexadecimal. For instance, PROMPTFIRST spells out "ENTER FIRST DIGIT (0-9): " and ends with a 0. Code handles all newlines for formatting and easy readability. 

PROMPTFIRST:

  dcb $45,$4E,$54,$45,$52,$20,$46,$49,$52,$53,$54,$20,$44,$49,$47,$49,$54,$20,$28,$30,$2D,$39,$29,$3A,$20,$00

... 

PROMPTOPERATOR:

  dcb $45,$4E,$54,$45,$52,$20,$4F,$50,$45,$52,$41,$54,$4F,$52,$20,$28,$2B,$20,$2D,$29,$3A,$20,$00

...

PROMPTSECOND:

  dcb $45,$4E,$54,$45,$52,$20,$53,$45,$43,$4F,$4E,$44,$20,$44,$49,$47,$49,$54,$20,$28,$30,$2D,$39,$29,$3A,$20,$00

...

PROMPTRESULT:

  dcb $52,$45,$53,$55,$4C,$54,$3A,$20,$00

6. Storage for Echoing Input

These DCB declarations temporarily hold the character input for the first digit, second digit, and operator. They are used by the input routines so that the entered digits can be stored and later converted from ASCII to numeric form and then echoes input on screen.

INPUTFIRST_STORAGE:

  dcb $00

INPUTSECOND_STORAGE:

  dcb $00

OPERATOR_STORAGE:

  dcb $00


7. Main Code

This is where the main execution of the calculator begins. The logic will be explained down below after the code:

START:

  JSR SCINIT                    

  LDY #$00

LOOP_PROMPT_FIRST:

  LDA PROMPTFIRST, Y            

  BEQ GET_FIRST_DIGIT            

  JSR CHROUT                    

  INY

  BNE LOOP_PROMPT_FIRST


GET_FIRST_DIGIT:

  JSR INPUT_FIRST                

  JSR PRINT_NEWLINE              

  LDY #$00

LOOP_PROMPT_OPERATOR:

  LDA PROMPTOPERATOR, Y

  BEQ GET_OPERATOR

  JSR CHROUT

  INY

  BNE LOOP_PROMPT_OPERATOR


GET_OPERATOR:

  JSR CHRIN                     

  CMP #$3D

  BEQ TREAT_AS_PLUS

  CMP #$2B

  BEQ STORE_OPERATOR

  CMP #$2D

  BEQ STORE_OPERATOR

  JMP GET_OPERATOR              

TREAT_AS_PLUS:

  LDA #$2B                     

STORE_OPERATOR:

  STA OPERATOR                  

  JSR CHROUT                    

  JSR PRINT_NEWLINE

  LDY #$00

LOOP_PROMPT_SECOND:

  LDA PROMPTSECOND, Y

  BEQ GET_SECOND_DIGIT

  JSR CHROUT

  INY

  BNE LOOP_PROMPT_SECOND


GET_SECOND_DIGIT:

  JSR INPUT_SECOND               

  JSR PRINT_NEWLINE

  LDA INPUTFIRST_STORAGE

  SEC

  SBC #$30                     

  STA INPUT1

  LDA INPUTSECOND_STORAGE

  SEC

  SBC #$30                    

  STA INPUT2

  LDA OPERATOR

  CMP #$2B                     

  BEQ DO_ADDITION

  CMP #$2D                    

  BEQ DO_SUBTRACTION

  JMP ERROR                    

What It Does:

  • SCINIT is used to set up a clear display.
  • PROMPT and GET input print the prompt messages for the first digit, the operator and the second digit by looping through each DCB-defined string and using CHROUT. It then calls the input subroutines such as INPUT_FIRST and INPUT_SECOND to get valid digits.
  •  Operator reads the operator, treating "=" as "+" since it requires a shift + = to get "+".
  •  After the input is echoed, it converts the ASCII digits to numeric values by subtracting $30.
  • Depending on the chose operator, whether it is '+' or '-', it will perform addition or subtraction and stores the result.
  • It prints the "RESULT: " prompt and then calls the PRINT_NUMBER routine to display the result.
  • If an error occurs such as an invalid operator, it prints an error character and restarts. Otherwise, after printing the result, the program ends with BRK. 

8. DO_ADDITION and DO_SUBTRACTION

This part of the code performs the basic arithmetic operations depending on the chosen operator. If user inputs "+", it will perform DO_ADDITION which clears the carry, adds the two numeric values, and stores the result. Otherwise, DO_SUBTRACTION will be called which sets the carry then subtracts the second value from the first, and stores the result which will eventually display on screen.

DO_ADDITION:

  CLC

  LDA INPUT1

  ADC INPUT2                  

  STA RESULT

  JMP PRINT_RESULT


DO_SUBTRACTION:

  SEC

  LDA INPUT1

  SBC INPUT2               

  STA RESULT

  JMP PRINT_RESULT

 

9. Result Printing 

This part prints the "RESULT: " prompt and then prints the calculated result. It checks if the result is negative. If it is negative, it then prints a '-' sign, computes the absolute value and then prints the positive number. For numbers less than 10, it prints one digit but for numbers 10 or greater, it calculates tens and ones using a loop that prints two digits.

PRINT_RESULT:

  LDY #$00

  // (print PROMPTRESULT) 

PRINT_NUMBER:

  LDA RESULT

  CMP #$80                   

  BCC PRINT_POSITIVE          

 

10. PRINT_NEWLINE Subroutine

This part of the code is used to have that results appear on a new line for easy readability. It outputs a carry return and line using CHROUT.

PRINT_NEWLINE:

  LDA #$0D               

  JSR CHROUT

  LDA #$0A                 

  JSR CHROUT

  RTS

11. INPUT_FIRST and INPUT_SECOND

These subroutines wait for the user to enter a key, validate that it’s a digit between 0 and 9, store the ASCII character in a temporary storage, and echoes the digit on the screen. They loop until a valid digit is being inputted.

INPUT_FIRST:

  LDY #$00

GETKEY1:

  JSR CHRIN               

  CMP #$00

  BEQ GETKEY1

  CMP #$30             

  BMI GETKEY1

  CMP #$3A            

  BPL GETKEY1

  STA INPUTFIRST_STORAGE   

  JSR CHROUT            

  RTS

LET'S TEST IT OUT!

1. Positive Results on both Addition and Subtraction Operations:




2. Negative Result:




3. Double Digit Result:


Try it out on 6502 Emulator!

Testable code to copy paste into the emulator provided for us: 6502 Emulator

define SCINIT   $ff81 
define CHRIN    $ffcf
define CHROUT   $ffd2
define SCREEN   $ffed
define PLOT     $fff0

define INPUT1       $0010   
define INPUT2       $0011    
define RESULT       $0012    
define OPERATOR     $0013   
define RESULT_TEMP  $0014    

define BACKSPACE    $08  
define ENTER        $0D  
define SPACE        $20
define BLACK        $A0
define LEFT         $83

         JMP START

PROMPTFIRST:
  dcb $45,$4E,$54,$45,$52,$20,$46,$49,$52,$53,$54,$20,$44,$49,$47,$49,$54,$20,$28,$30,$2D,$39,$29,$3A,$20,$00
; "ENTER FIRST DIGIT (0-9): "

PROMPTOPERATOR:
  dcb $45,$4E,$54,$45,$52,$20,$4F,$50,$45,$52,$41,$54,$4F,$52,$20,$28,$2B,$20,$2D,$29,$3A,$20,$00
; "ENTER OPERATOR (+ -): "

PROMPTSECOND:
  dcb $45,$4E,$54,$45,$52,$20,$53,$45,$43,$4F,$4E,$44,$20,$44,$49,$47,$49,$54,$20,$28,$30,$2D,$39,$29,$3A,$20,$00
; "ENTER SECOND DIGIT (0-9): "

PROMPTRESULT:
  dcb $52,$45,$53,$55,$4C,$54,$3A,$20,$00
; "RESULT: "

INPUTFIRST_STORAGE:
  dcb $00
INPUTSECOND_STORAGE:
  dcb $00
OPERATOR_STORAGE:
  dcb $00


START:
  JSR SCINIT                    
  LDY #$00
LOOP_PROMPT_FIRST:
  LDA PROMPTFIRST, Y             
  BEQ GET_FIRST_DIGIT            
  JSR CHROUT                     
  INY
  BNE LOOP_PROMPT_FIRST

GET_FIRST_DIGIT:
  JSR INPUT_FIRST                
  JSR PRINT_NEWLINE             

  LDY #$00
LOOP_PROMPT_OPERATOR:
  LDA PROMPTOPERATOR, Y
  BEQ GET_OPERATOR
  JSR CHROUT
  INY
  BNE LOOP_PROMPT_OPERATOR

GET_OPERATOR:
  JSR CHRIN                    
  
  CMP #$3D
  BEQ TREAT_AS_PLUS
  CMP #$2B
  BEQ STORE_OPERATOR
  CMP #$2D
  BEQ STORE_OPERATOR
  JMP GET_OPERATOR             
TREAT_AS_PLUS:
  LDA #$2B                    
STORE_OPERATOR:
  STA OPERATOR                   
  JSR CHROUT                   
  JSR PRINT_NEWLINE

  LDY #$00
LOOP_PROMPT_SECOND:
  LDA PROMPTSECOND, Y
  BEQ GET_SECOND_DIGIT
  JSR CHROUT
  INY
  BNE LOOP_PROMPT_SECOND

GET_SECOND_DIGIT:
  JSR INPUT_SECOND               
  JSR PRINT_NEWLINE

  LDA INPUTFIRST_STORAGE
  SEC
  SBC #$30                     
  STA INPUT1
  LDA INPUTSECOND_STORAGE
  SEC
  SBC #$30                    
  STA INPUT2

  LDA OPERATOR
  CMP #$2B                    
  BEQ DO_ADDITION
  CMP #$2D                     
  BEQ DO_SUBTRACTION
  JMP ERROR                   
DO_ADDITION:
  CLC
  LDA INPUT1
  ADC INPUT2                  
  STA RESULT
  JMP PRINT_RESULT

DO_SUBTRACTION:
  SEC
  LDA INPUT1
  SBC INPUT2                 
  STA RESULT
  JMP PRINT_RESULT

ERROR:
  LDA #$45                    
  JSR CHROUT
  JMP START                   
PRINT_RESULT:
  LDY #$00
LOOP_PROMPT_RESULT:
  LDA PROMPTRESULT, Y
  BEQ PRINT_NUMBER
  JSR CHROUT
  INY
  BNE LOOP_PROMPT_RESULT
PRINT_NUMBER:
  LDA RESULT
  CMP #$80                   
  BCC PRINT_POSITIVE          
  LDA #$2D                   
  JSR CHROUT
  LDA RESULT
  EOR #$FF
  CLC
  ADC #$01
  STA RESULT_TEMP
  JMP CONVERT_NUMBER
PRINT_POSITIVE:
  STA RESULT_TEMP            
CONVERT_NUMBER:
  LDA RESULT_TEMP
  CMP #$0A                 
  BCC PRINT_ONE_DIGIT

  LDX #$00                  
  LDA RESULT_TEMP
DIV_LOOP:
  CMP #$0A
  BCC DIV_DONE
  SEC
  SBC #$0A
  INX                      
  STA RESULT_TEMP          
  JMP DIV_LOOP
DIV_DONE:
  TXA                     
  CLC
  ADC #$30                
  JSR CHROUT
  LDA RESULT_TEMP         
  CLC
  ADC #$30
  JSR CHROUT
  RTS
PRINT_ONE_DIGIT:
  CLC
  ADC #$30
  JSR CHROUT
  RTS

PRINT_NEWLINE:
  LDA #$0D                
  JSR CHROUT
  LDA #$0A                 
  JSR CHROUT
  RTS

INPUT_FIRST:
  LDY #$00
GETKEY1:
  JSR CHRIN                
  BEQ GETKEY1
  CMP #$30                
  BMI GETKEY1
  CMP #$3A                
  BPL GETKEY1
  STA INPUTFIRST_STORAGE   
  JSR CHROUT               
  RTS

INPUT_SECOND:
  LDY #$00
GETKEY2:
  JSR CHRIN
  CMP #$00
  BEQ GETKEY2
  CMP #$30
  BMI GETKEY2
  CMP #$3A
  BPL GETKEY2
  STA INPUTSECOND_STORAGE
  JSR CHROUT
  RTS

Reflection:

While working on getting this code to run on the 6502 Emulator, I realized just how much I still have to learn. Using the provided define directives helped me get started. The learning curve has been steep, but after several attempts, I finally saw the prompts and inputs appear on the screen which was something I was not able to achieve in my first Lab 3 attempt. If you want to see my first process, check out my blog post under the title Lab 3 - Addition and Subtraction Calculator. Although there is still a lot for me to learn, this lab definitely helped me understand assembly language more clearly and was helpful in preparing me to write more complex code.


Comments

Popular posts from this blog

BATCH 3 | Project Stage 2, Part 3 - Cloned Functions Comparison and Reflection

BATCH 4 | Clone-Prune Analysis Code Pass On Both Architectures

BATCH 3 | Project Stage 2, Part 1 - Clone-Pruning Analysis Pass