Z80 DAA instruction
Asked Answered
R

4

21

Apologies for this seemingly minor question, but I can't seem to find the answer anywhere - I'm just coming up to implementing the DAA instruction in my Z80 emulator, and I noticed in the Zilog manual that it is for the purposes of adjusting the accumulator for binary coded decimal arithmetic. It says the instruction is intended to be run right after an addition or subtraction instruction.

My questions are:

  • what happens if it is run after another instruction?
  • how does it know what instruction preceeded it?
  • I realise there is the N flag - but this surely wouldnt definitively indicate that the previous instruction was an addition or subtraction instruction?
  • Does it just modify the accumulator anyway, based on the conditions set out in the DAA table, regardless of the previous instruction?
Rattan answered 14/11, 2011 at 9:34 Comment(0)
E
17

Does it just modify the accumulator anyway, based on the conditions set out in the DAA table, regardless of the previous instruction?

Yes. The documentation is only telling you what DAA is intended to be used for. Perhaps you are referring to the table at this link:

--------------------------------------------------------------------------------
|           | C Flag  | HEX value in | H Flag | HEX value in | Number  | C flag|
| Operation | Before  | upper digit  | Before | lower digit  | added   | After |
|           | DAA     | (bit 7-4)    | DAA    | (bit 3-0)    | to byte | DAA   |
|------------------------------------------------------------------------------|
|           |    0    |     0-9      |   0    |     0-9      |   00    |   0   |
|   ADD     |    0    |     0-8      |   0    |     A-F      |   06    |   0   |
|           |    0    |     0-9      |   1    |     0-3      |   06    |   0   |
|   ADC     |    0    |     A-F      |   0    |     0-9      |   60    |   1   |
|           |    0    |     9-F      |   0    |     A-F      |   66    |   1   |
|   INC     |    0    |     A-F      |   1    |     0-3      |   66    |   1   |
|           |    1    |     0-2      |   0    |     0-9      |   60    |   1   |
|           |    1    |     0-2      |   0    |     A-F      |   66    |   1   |
|           |    1    |     0-3      |   1    |     0-3      |   66    |   1   |
|------------------------------------------------------------------------------|
|   SUB     |    0    |     0-9      |   0    |     0-9      |   00    |   0   |
|   SBC     |    0    |     0-8      |   1    |     6-F      |   FA    |   0   |
|   DEC     |    1    |     7-F      |   0    |     0-9      |   A0    |   1   |
|   NEG     |    1    |     6-F      |   1    |     6-F      |   9A    |   1   |
|------------------------------------------------------------------------------|

I must say, I've never seen a dafter instruction spec. If you examine the table carefully, you will see that the effect of the instruction depends only on the C and H flags and the value in the accumulator -- it doesn't depend on the previous instruction at all. Also, it doesn't divulge what happens if, for example, C=0, H=1, and the lower digit in the accumulator is 4 or 5. So you will have to execute a NOP in such cases, or generate an error message, or something.

Eleen answered 14/11, 2011 at 9:55 Comment(5)
Thanks very much - I hope to find not too many more ambiguous instructions such as this :-)Rattan
Z80's DAA should be equivalent to x86's DAA and DAS as they have the same purpose. Check out the x86 descriptions of both. Some kind of DAA is available on many CPUs.Halutz
@Alex: the x86 chips have two Decimal Adjust instructions: DAA (Decimal Adjust after Addition) and DAS (Decimal Adjust after Subtraction). The Z80 DAA instruction combines them into one, by assuming that the operands of the most recent add/subtract were valid BCD numbers.Eleen
Beware that the 8080 DAA differs in subtle but important ways (of which I know little) from the Z80's.Pain
The table can be largely improved if ADD,ADC,INC is replaced by N=0 and SUB,SBC,DEC,NEG by N=1. DAA does not have an idea which instruction was last executed.Aubin
G
13

Just wanted to add that the N flag is what they mean when they talk about the previous operation. Additions set N = 0, subtractions set N = 1. Thus the contents of the A register and the C, H and N flags determine the result.

The instruction is intended to support BCD arithmetic but has other uses. Consider this code:

    and  15
    add  a,90h
    daa
    adc  a,40h
    daa

It ends converting the lower 4 bits of A register into the ASCII values '0', '1', ... '9', 'A', 'B', ..., 'F'. In other words, a binary to hexadecimal converter.

Glick answered 13/1, 2012 at 9:3 Comment(0)
A
11

This is code in production, implementing DAA correctly and passes the zexall/zexdoc/z80test Z80 opcode test suits.

Based on The Undocumented Z80 Documented, pag 17-18.

void daa()
{
   int t;
    
   t=0;
    
   // 4 T states
   T(4);
    
   if(flags.H || ((A & 0xF) > 9) )
         t++;
    
   if(flags.C || (A > 0x99) )
   {
         t += 2;
         flags.C = 1;
   }
    
   // builds final H flag
   if (flags.N && !flags.H)
      flags.H=0;
   else
   {
       if (flags.N && flags.H)
          flags.H = (((A & 0x0F)) < 6);
       else
          flags.H = ((A & 0x0F) >= 0x0A);
   }
    
   switch(t)
   {
        case 1:
            A += (flags.N)?0xFA:0x06; // -6:6
            break;
        case 2:
            A += (flags.N)?0xA0:0x60; // -0x60:0x60
            break;
        case 3:
            A += (flags.N)?0x9A:0x66; // -0x66:0x66
            break;
   }
    
   flags.S = (A & BIT_7);
   flags.Z = !A;
   flags.P = parity(A);
   flags.X = A & BIT_5;
   flags.Y = A & BIT_3;
}

For visualising the DAA interactions, for debugging purposes, I have written a small Z80 assembly program, that can be run in an actual ZX Spectrum or in an emulation that emulates accurately DAA: https://github.com/ruyrybeyro/daatable

As how it behaves, got a table of flags N,C,H and register A before and after DAA produced with the aforementioned assembly program: https://github.com/ruyrybeyro/daatable/blob/master/daaoutput.txt

Aubin answered 7/9, 2019 at 19:57 Comment(1)
Thank you so much for the code, I was going insane here trying to properly code DAA on my pet emulator.Nagle
R
9

I found this instruction rather confusing as well, but I found this description of its behavior from z80-heaven to be most helpful.

When this instruction is executed, the A register is BCD corrected using the contents of the flags. The exact process is the following: if the least significant four bits of A contain a non-BCD digit (i. e. it is greater than 9) or the H flag is set, then $06 is added to the register. Then the four most significant bits are checked. If this more significant digit also happens to be greater than 9 or the C flag is set, then $60 is added.

This provides a simple pattern for the instruction:

  • if the lower 4 bits form a number greater than 9 or H is set, add $06 to the accumulator
  • if the upper 4 bits form a number greater than 9 or C is set, add $60 to the accumulator

Also, while DAA is intended to be run after an addition or subtraction, it can be run at any time.

Richardson answered 1/5, 2015 at 15:39 Comment(2)
It looks like this is missing the last four operations (SUB, SBC, NEG, and DEC).Revisory
@Salgat The same rule applies when N=1. The only thing is that you have to subtract the correction when N=1.Unreadable

© 2022 - 2024 — McMap. All rights reserved.