Skip to content

Arithmetic instructions

Rodion Gorkovenko edited this page Jan 23, 2015 · 10 revisions

You will see this CPU supports only few kinds of operations - additions, shifts and inversion of bits. Let us start with simplest of them.

###Inversion

  • CMC - complements (inverts) Carry;
  • CMA - complements (inverts) Accumulator;

These two are quite straightforward. We can rewrite them in Python in several ways:

#CMC:
cy = 1 - cy
#or
cy ^= 1

#CMA:
acc = 15 - acc
#or
acc ^= 0xF

###Addition

  • ADD - adds some register (and Carry flag) to Accumulator (i.e. add r2)

This is more complicated than you may expect. It sums 3 operands:

result = acc + reg + cy

And then result is stored in Accumulator (lower 4 bits) and Carry (highest bit):

cy = result >> 4
acc = result & 0xF

So before addition Carry should be cleared if it is not wanted. After operation it could be used for summation of higher digits. Let us see an example of adding 0x59 to 0x38:

fim r0 $59   ; r0 = 5  and  r1 = 9
fim r2 $38   ; r2 = 3  and  r3 = 8

; summing lower digits (9 and 8)
clc          ; carry = 0
ld r1        ; acc = r1
add r3       ; acc += r3
xch r1       ; store result back to r1
             ; we do not clear carry after that!
; summing higher digits (5 and 3)
ld r0        ; acc = r0
add r2       ; acc += r2
xch r0       ; store result to r0

see demo

After these operations r0:r1 shows results of $91. You see that when we summed higher nibbles (5+3) the Carry was also added from previous summation. You can check correctness with your calculator (if it supports hexadecimal values).

###Subtraction

As a matter of fact CPU performs this operation via addition and inversion:

  • SUB - subtracts some register (and Carry) from Accumulator (i.e. sub r3)

it is logically the same as:

result = acc + inversion(reg) + inversion(cy) = acc + (reg^0xF) + (cy^1)

Further the result is processed in the same way as with normal addition, so the SUB instruction is really a shorthand for sequence of CMC, CMA and ADD.

What is the meaning of Carry after this operation? If you will study it with pencil and paper you will find that:

  • Carry is set to 1 if Acc was greater than or equal to (reg+cy) - i.e. if there was no "borrow";
  • Carry is set to 0 otherwise (e.g. if we calculate 3 - 5) - meaning that borrow was generated.

This means that Carry also could be used for subtracting long values digit-by-digit (though it should be inverted after each operation, you'll see).

###Increment and Decrement

As there are no instructions to add or subtract constant (without loading it to register), few shorthand instructions for changing value by 1 exist:

  • IAC - increments accumulator by 1
  • DAC - decrements accumulator by 1
  • INC - increments some register (i.e. inc r12)

Carry is changed by IAC and DAC in the same manner as by ADD and SUB. (however it itself does not affect result so you need not clear it first)

Meanwhile INC does not change Carry at all.

###Shifts or Rotations

  • RAL - shifts (rotates) Accumulator left, moving its highest bit to Carry and Carry itself to lowest bit;
  • RAR - shifts (rotates) Accumulator right, also through Carry;
  • TCC - "transfer carry and clear" - moves Carry to Accumulator (highest bits of Acc and Carry itself are cleared).

Addition raises Carry flag if the result is greater than 15. Increment on accumulator affects Carry in the same way (though INC does not change Carry at all).

Subtraction is, really just the form of Addition, but with second operand inverted. This lead to somewhat bewildering behavior - Carry flag is set to 1 after subtraction if the first operand (Accumulator) was greater or equal to second (register) - i.e. no "borrow" occurred. This could be used both for subtraction of long values and for comparing numbers between them.

Clone this wiki locally