Decimal Adjust Accumulator on the 4004
Brent Hilpert
hilpert at cs.ubc.ca
Thu Jan 28 20:33:44 CST 2016
On 2016-Jan-28, at 5:30 PM, Kyle Owen wrote:
> I'm currently writing a bit of code for the 4004 at the moment, and playing
> with it in the online Javascript emulator found here:
> http://e4004.szyc.org/emu/
>
> According to http://e4004.szyc.org/iset.html (which I believe is copied
> straight from the MCS-4 Users Manual), the DAA instruction should increment
> the accumulator by 6 if carry is set or if the accumulator is greater than
> 9. Carry should be set following the instruction if the resulting addition
> generated a carry; otherwise it's unaffected.
>
> Let's say the accumulator is currently 9, carry is not set. I add another
> 9. Accumulator is now 2 with a carry. Running DAA should turn this into 8
> with carry set, indicating that 9+9=(1)8. Am I thinking through this
> correctly?
>
> I ask, because according to the simulator's source code, DAA won't do that,
> if I'm following it correctly:
>
> function opDAA() { //DAA Decimal Adjust Accumulator
> if(A_reg > 9) A_reg += 6;
> C_flag=0; if (A_reg & 0xf0) {A_reg&=0xf; C_flag=1;}
> incPC();
> }
>
> It says that it'll only add 6 if the accumulator is greater than 9, not if
> a carry is already set. It will then reset carry and set it if and only if
> there was a carry.
>
> Have I found a bug in the simulator? Am I misreading the MCS-4 Users
> Manual?
>
> In any event, this is my proposed fix to better match what the instruction
> description says:
>
> function opDAA() { //DAA Decimal Adjust Accumulator
> if((A_reg > 9) | (C_flag)) A_reg += 6;
> if (A_reg & 0xf0) {A_reg&=0xf; C_flag=1;}
> incPC();
> }
>
> Seems to work as I would expect it to.
The original looks correct to me.
I think you or the documentation are confusing the hardware carry flag with the carry out of the 4th bit (nibble carry).
A binary addition of two BCD digits will require correction either if the result is in the range 0xA to 0xF or if there was a carry out of the 4th bit.
The hardware carry flag is the carry out of the 8th bit and is irrelevant immediately after the addition.
Note whether or not correction is needed is synonymous with the state of *decimal* carry from the addition.
To rephrase the original code:
- If the 8-bit result of a preceding binary addition of two BCD digits located in the lower nibble of the source operands is > 0x9 then add 0x6 to the result.
This corrects results which were both in the range 0xA to 0xF and 0x10 to 0x12 (the max result of adding two BCD digits is 9+9=0x12).
The lower nibble of the acc now correctly reflects the desired decimal digit value.
- We now need to adjust the hardware carry flag to reflect whether there was a decimal carry (so it is valid for input to a subsequent BCD digit addition).
Because of the conditional addition of the 'correcting 6', all results which required correction are now > 0xF in the acc (have overflowed into the higher nibble) (0xA+6=0x10),
so we set the hardware carry flag accordingly, as well as clear out the extraneous bits in the higher nibble of the acc so it contains only our desired decimal digit.
I've been through this binary-BCD addition correction stuff numerous times in reverse engineering discrete and SSI calculators -
it's far more fun when it's being done with serial bit-streams in hardware.
More information about the cctech
mailing list