In order to be more than a toy the 8 bit Juno CPU needs to be capable of performing multi-byte mathematical operations.
It is capable of adding, subtracting and shifting of multi-byte numbers as described below. The shifting operations are used to support multiplication and division.
In order to make the examples below simpler and shorter 4 bit numbers are used but the Juno CPU is 8 bit.
Multi-byte addition
In order to add two multi-byte numbers the bytes are added starting with the least significant bytes first. Adding the least significant bytes calculates the least significant byte of the result and the carry. The next two bytes are then added plus the carry and so on.
Example
28 + 28 = 56
In binary this is
This is calculated 4 bits at a time as follows
Set carry = 0
1100 + 1100 + carry = 1000 (carry =1)
0001 + 0001 + carry = 11 (carry = 0)
Two CPU instructions are required to perform the above calculation in assembler code. The first instruction is to clear the carry flag e.g. CLC. The second instruction is to add two number with carry e.g. ADC.
The inclusion of a third instruction to the Instruction set add without carry, ADD, which over-rides the carry flag with 0 allows the addition to be implemented more optimally in fewer lines of code as it removes the need to explicitly clear the carry flag first.
Multi-byte subtraction
In order to subtract two multi-byte numbers the fact that mathematically a- b is the same as a + (-b) is exploited as it is easy to calculate -b and doing so allows the logic of the adder to be reused rather than building an entirely seperate piece of logic dedicated to subtraction.
-b is calculated by inverting b and adding 1 to produce the two's complement representation of -b. The invertion can be achieved through the application of not logic and the adding of 1 can be done by forcing the carry to 1 for the addition of the first two bytes. The addition of subsequent bytes adds the resultant carry of the previous calculation.
Example
28 - 27 = 1
In binary this is
0001 1100 - 0001 1011
This is calculated 4 bits at a time as follows
Set carry = 1 (force carry to 1 to calculate the two's complement)
1100 + (invert 1011) + carry =
1100 + 0100 + carry =
0001 (carry = 1)
0001 + (invert 0001) + carry =
0001 + 1110 + carry =
0000 (carry = 1)
The final carry of 1 is ignored.
Two CPU instructions are required to perform the above calculation in assembler code. The first instruction is to set the carry flag e.g. SEC. The second instruction is to subtract two numbers with carry e.g. SBC.
The addition of a third instruction to subtract without carry, SUB, which over-rides the carry flag with 1 allows the subtraction to be implemented more optimally in fewer lines of code as it removes the need to explicitly set the carry flag first.
Shifting multi-byte numbers left and right
The ability to shift numbers is key to implementing multiplication and division efficiently in assembler as the Juno CPU does not have dedicated multiplication and division instructions.
Mathematically shifting a number 1 place to the left is the equivalent of multiplying by 2. Likewise, mathematically shifting a number 1 place to the right is the equivalent of dividing by 2.
In order to shift multi-byte numbers two types of shift operation are required, mathematical shift and rotation.
Mathematical shift fills the gap created by the shift with a zero and moves the bit that drops off into the carry flag.
Examples
1101 mathematically shifted to the left becomes 1010 (carry = 1)
0101 mathematically shifted to the left becomes 1010 (carry = 0)
1101 mathematically shifted to the right becomes 0110 (carry = 1)
The value of carry before the shift is irrelevant.
Rotational shift is similar to mathematical shift but fills the gap with the input value of carry. Like mathematical shift the output value of the carry flag is set to the bit that drops off.
Example
carry = 1
1101 rotated to the left becomes 1011 (carry = 1)
In order to multiply a multi-byte number by two the least significant byte is first mathematically shifted to the left by one place. The subsequent bytes are then rotated to the left by one place starting with the second least significant byte. This approach preserves the bit that 'drops off' and moves it into the next byte.
In order to divide a multi-byte number by two a similar approach is taken but starting with mathematically shifting the most significant byte to the right by 1 place. Subsequent bytes are then rotated to the right by one place starting with the second most significant byte.
The rotate and shift operations can be implemented by two CPU instructions.
ROR - ROtate Right through carry. Fill with carry.
ROL - ROtate Left through carry. Fill with carry.
In order to optimise assemble code additional instructions could be provided that over-ride the value of carry removing the need to clear, or set, carry before performing a Mathematical Shift instruction.
SL0 - Shift Left filling with 0
SL1 - Shift Left filling with 1
SR0 - Shift Right filling with 0
SR1 - Shift Left filling with 1
No comments:
Post a Comment