In the above code fragments, I introduced the ADDQ instruction to add a value to a register. There are a few arithmetic instructions covering addition, subtraction, division and multiplication.
ADD.size source,Dn or ADD.size Dn,destination
This adds the source to the destination. The destination is overwritten but source is not affected. The size can be byte, word or long. All the flags are affected as follows :
N is set if the result is negative, cleared if not.
Z is set if the result is zero, cleared if not.
V is set if an overflow was generated, cleared if not.
C is set if a carry was generated, cleared if not.
X is set to the same value as the C flag.
Note that byte sized ADDs cannot be done if source is An. If destination is An then ADDA should be used, however, some assemblers will convert ADD Dn,An into ADDA Dn,An for you.
ADDA.size source,An
This adds the source to the address register specified. The size can only be word or long but note that regardless of the size of source, the whole of the address register is affected. Words are sign extended to 32 bits. This instruction has no effect on the condition codes.
ADDI.size #data,destination
This instruction ads immediate data to the destination. The flags are all affected as per the ADD instruction above. The size can be byte, word or long. It is not permitted to use this to add to an address register.
ADDQ.size #data,destination
This is a very quick version of the above ADDI but it can only be used to add values between 1 and 8 to the destination. The size is byte, word or long as required. This instruction is always 2 bytes long where the ADDI can be 4 or 6 bytes. Use ADDQ wherever a value between 1 and 8 is to be added.
The flags are affected as per the ADDI instruction. The difference between this and ADDI is that you can use ADDQ to add 1,2,3,4,5,6,7 or 8 to an address register. Useful in loops.
ADDX.size Dx,Dy ADDX.size -(Ax),-(Ay)
This one adds with the X flag added as well. It is useful when adding numbers together that are more than a register long - 32 bits. If you were to write a program that used 8 bytes in memory to store a number, then you could add two of them together using ADDX.
The destination becomes set to the value source + destination + X flag.
The flags are affected as follows :
N is set if the result is negative, cleared if not.
Z is UNCHANGED if the result is zero, cleared if not.
V is set if an overflow was generated, cleared if not.
C is set if a carry was generated, cleared if not.
X is set to the same value as the C flag.
Note the Z flag. If the result is zero it will be left as it is and not changed. If the result is non zero it is cleared. For this reason the Z flag should be set before any ADDXing takes place so that at the end, the result of zero shows up by having the Z flag still set.
This instruction and the SUBX one are mostly used in multiple precision addition and subtraction routines.
ABCD Dx,Dy ABCD -(Ax),-(Ay)
This is Add Binary Coded Decimal and is almost identical to ADDX above except that the values in the source and destination are treated as BCD instead of binary. Only 8 bits of the source and destination are affected.
Assuming that the X flag is clear, this will result in D1 being set to $22 which is the result of adding 19 and 3 in DECIMAL. The hexadecimal numbers in the register $19 and $03 are interpreted as decimal digits, one digit for each 4 bits. The above example Is actually adding 25 and 3 to make 34 !
The flags are affected as follows :
N is undefined.
Z is UNCHANGED if the result is zero, cleared if not.
V is UNDEFINED
C is set if a DECIMAL carry was generated, cleared if not.
X is set to the same value as the C flag.
The Subtraction instructions are exactly the same as the Addition flags, but subtract instead. I have listed them below, but not explained them - read the corresponding ADD instruction for details.
SUB, SUBA, SUBI, SUBQ, SUBX and SBCD.
DIVS source,Dn
This instruction divides destination by source and puts the result into destination. Source is a word size and destination is long. The operation is carried out using signed values. The size is always word.
The destination WORD is divided by the source WORD and the result put into the destination LOW WORD. The remainder is placed in the destination HIGH WORD.
Any attempt to divide by zero will cause a divide by zero exception to occur and on a standard QL this will lock up. If overflow is detected during the operation the overflow flag is set but the operation is aborted and the source and destination are unaffected.
The flags are affected as follows :
N is set if the quotient is negative, cleared otherwise. Undefined on overflow.
Z is set if the quotient is zero, cleared if not. Undefined on overflow.
V is set if division overflow is detected. Cleared otherwise.
C is always cleared.
X is never affected. (Unchanged)
For those of us with short memories or a long period since our schooldays, the quotient is the result of the division. The remainder is what is left over.
Results in D0 being set to $00010009 which is 9 remainder 1. The 9 is in the lowest word while the 1 is in the highest word.
The instruction should be read as 'divide source into destination'.
DIVU source,Dn
This is identical to the above except that both operands are treated as unsigned numbers. The flags are affected as per the DIVS instruction. Although the quotient is always positive, the N flag is set to the value in the highest bit of the lower word of destination. (ie the sign bit of a 16 bit word.)
MULS source,Dn
Multiply the destination word by the source word and place the LONG result into the destination register. Both operands are treated as signed numbers.
The flags affected are :
N - set if the result is negative, cleared otherwise.
Z - set if the result is zero, cleared otherwise.
V - Always cleared.
C - Always cleared.
X - Unchanged.
MULU source,Dn
Multiply the destination word by the source word and place the LONG result into the destination register. Both operands are treated as unsigned numbers. The flags are set or cleared as per the MULS instruction. The N flag is set to bit 31 of the result.
NEG.size destination
This instruction converts the binary value in the destination to its two's compliment value. This is done by subtracting the current value from zero, putting the result back into the destination and seting the flags. All the flags are affected by this instrcuction. The instruction can act upon byte, word or long sized values.
The flags affected are :
N - set if the result is negative, cleared otherwise.
Z - set if the result is zero, cleared otherwise.
V - set if an overflow occurred, cleared otherwise.
C - Cleared if the result was zero, set otherwise
X - Set the same as the C flag.-->
NEGX.size destination
Same as NEG above except the value in the X flag is also subtracted to get the final result. The flags are not affected in the same way as NEG, but as follows :
N - set if the result is negative, cleared otherwise.
Z - set if the result is zero, UNCHANGED otherwise.
V - set if an overflow occurred, cleared otherwise.
C - Set if a 'borrow' was generated, cleared otherwise.
X - Set the same as the C flag.
NBCD destination
This instruction works on byte sized values only. It is similar to NEGX above, but the values are treated as decimal and not binary. The contents of the byte at 'destination' is subtracted from zero then the current value of the X flag is subtracted as well. The result is put back into 'destination' and the flags set as follows :
N - undefined
Z - set if the result is zero, cleared otherwise.
V - undefined
C - set if a borrow was required, cleared otherwise
X - Set the same as the C flag.