Lab 3 addition/subtraction calculator
In this blog post I will write and actually implement the subtracting portion of my previous blog post about lab 3. Below is the code for the subtraction and addition calculator in the 6502 emulator.
; Adding calculator with addition and subtraction capabilities
; ROM routine entry points
define SCINIT $ff81 ; initialize/clear screen
define CHRIN $ffcf ; input character from keyboard
define CHROUT $ffd2 ; output character to screen
define SCREEN $ffed ; get screen size
define PLOT $fff0 ; get/set cursor coordinates
; zeropage variables
define PRINT_PTR $10
define PRINT_PTR_H $11
define value $14
define value_h $15
define second_value $16
define second_value_h $17
define OPERATOR $18
; absolute variables
define GETNUM_1 $0080
define GETNUM_2 $0081
; constants
; --------------------------------------------------------
jsr SCINIT
jsr CHRIN
jsr PRINT
dcb "A","d","d","i","n","g",32,"o","r",32,"s","u","b","t","r","a","c","t","i","n","g",32
dcb "c","a","l","c","u","l","a","t","o","r",00
start: jsr PRINT
dcb $0d,$0d,"E","n","t","e","r",32,"a",32,"n","u","m","b","e","r"
dcb "(","0","-","9","9",")",":",32,00
lda #$00
sta value_h
jsr GETNUM
sta value
jsr CHOOSE_OP ; Choose addition or subtraction
jsr PRINT
dcb "E","n","t","e","r",32,"a","n","o","t","h","e","r"
dcb 32,"n","u","m","b","e","r",32,"(","0","-","9","9",")",":",32,00
lda #$00
sta second_value_h
jsr GETNUM
sta second_value
lda OPERATOR
beq do_add
do_sub: sed
sec
lda value
sbc second_value
sta value
lda value_h
sbc second_value_h
sta value_h
cld
jmp result
do_add: sed
clc
lda value
adc second_value
sta value
lda value_h
adc second_value_h
sta value_h
cld
result: pha
jsr PRINT
dcb "R","e","s","u","l","t",":",32,00
pla
tax
ldy #$00
print_result: ldx value_h
cpx #$00
beq low_digits_result
lda value_h
and #$0f
ora #$30
jsr CHROUT
low_digits_result:
lda value
and #$f0
beq ones_digit_result
lda value
lsr
lsr
lsr
lsr
and #$0f
ora #$30
jsr CHROUT
ones_digit_result:
lda value
and #$0f
ora #$30
jsr CHROUT
jsr start
; --------------------------------------------------------
; Print a message
;
; Prints the message in memory immediately after the
; JSR PRINT. The message must be null-terminated and
; 255 characters maximum in length.
PRINT: pla
clc
adc #$01
sta PRINT_PTR
pla
sta PRINT_PTR_H
tya
pha
ldy #$00
print_next: lda (PRINT_PTR),y
beq print_done
jsr CHROUT
iny
jmp print_next
print_done: tya
clc
adc PRINT_PTR
sta PRINT_PTR
lda PRINT_PTR_H
adc #$00
sta PRINT_PTR_H
pla
tay
lda PRINT_PTR_H
pha
lda PRINT_PTR
pha
rts
; ---------------------------------------------------
; GETNUM - get a 2-digit decimal number
;
; Returns A containing 2-digit BCD value
GETNUM: txa
pha
tya
pha
ldx #$00 ; count of digits received
stx GETNUM_1
stx GETNUM_2
getnum_cursor: lda #$a0 ; black square
jsr CHROUT
lda #$83 ; left cursor
jsr CHROUT
getnum_key: jsr CHRIN
cmp #$00
beq getnum_key
cmp #$08 ; BACKSPACE
beq getnum_bs
cmp #$0d ; ENTER
beq getnum_enter
cmp #$30 ; "0"
bmi getnum_key
cmp #$3a ; "9" + 1
bmi getnum_digit
jmp getnum_key
getnum_enter: cpx #$00
beq getnum_key
lda #$20
jsr CHROUT
lda #$0d
jsr CHROUT
lda GETNUM_1
cpx #$01
beq getnum_done
asl
asl
asl
asl
ora GETNUM_2
getnum_done: sta GETNUM_1
pla
tay
pla
tax
lda GETNUM_1
rts
getnum_digit: cpx #$02
bpl getnum_key
pha
jsr CHROUT
pla
and #$0f
sta GETNUM_1,x
inx
jmp getnum_cursor
getnum_bs: cpx #$00
beq getnum_key
lda #$20
jsr CHROUT
lda #$83
jsr CHROUT
jsr CHROUT
lda #$20
jsr CHROUT
lda #$83
jsr CHROUT
dex
lda #$00
sta GETNUM_1,x
jmp getnum_cursor
; ---------------------------------------------------
; Operator Selection Subroutine
;
CHOOSE_OP: jsr PRINT
dcb $0d,$0d,"C","h","o","o","s","e",32,"o","p","e","r","a","t","o","r",32,"(","+","-",")",":",32,00
get_op: jsr CHRIN
cmp #$2b ; "+"
beq op_add
cmp #$2d ; "-"
beq op_sub
jmp get_op
op_add: lda #$00 ; Addition
sta OPERATOR
rts
op_sub: lda #$01 ; Subtraction
sta OPERATOR
rts
In my previous post I already discussed how the addition portion of this program works so I will talk more about the new subroutines that I added, more specifically the subtraction and operation choice routines.
First, a prompt is given to the user to choose whether they want to add or subtract, this user input is read using CHRIN. If the input matches +/- (#2b, or #2d in ASCII) then the program will jump to its respective operation.
I added a do_add or sub routines to handle each arithmetic operation. I will explain the do_sub. The value of the operator is determined first to see which arithmetic operation it should do, then sed sets the decimal mode for BCD arithmetic. sec instruction (set carry flag) is then used to start subtracting. I learned that sec must be set before using the sbc instruction to indicate that no borrow has occurred at the start, and so the processor will know that the full value is available for subtracting. lda is then used to load the low byte of the first number in the accumulator, then sbc second_value is used to subtract second_value from the value in the accumulator. Then the result is stored using sta. The same thing is done for the decimal high byte , if a borrow occurs during the low byte subtraction, then it is carried over and considered in this section to ensure the result is correct. Finally, we cld to clear the decimal mode and revert the processor to the regular binary mode.
To summarize the result displaying section, it first pushes and then pulls the accumulator value to save the result temporarily when printing the result message. It also determines if result is a multi-byte value, and if the high byte is not zero then it prints to 3 digits.
The calculator works fine for all 2 digit numbers and can handle 3 digit addition results but when it comes to subtracting and getting a negative number it will not work due to how the numbers are represented. We use binary here to represent decimals in our code, and there is no way to show a negative like that. Furthermore, our result printing logic always assumes a non negative value as a result. So many alterations would be needed to implement negative numbers. I know that we can use two's complement rule to allow the accumulator to hold negative and positive values but we would need to switch up our whole arithmetic logic. Not only that but we would have to change our display logic too.
Comments
Post a Comment