21

为这个看似次要的问题道歉,但我似乎无法在任何地方找到答案 - 我只是想在我的 Z80 模拟器中实现 DAA 指令,我在 Zilog 手册中注意到它是为了调整二进制编码十进制算术的累加器。它说该指令旨在在加法或减法指令之后立即运行。

我的问题是:

  • 如果它在另一条指令之后运行会发生什么?
  • 它怎么知道它之前的指令?
  • 我意识到有 N 标志 - 但这肯定不会明确表明前一条指令是加法或减法指令?
  • 不管前面的指令如何,它是否只是根据 DAA 表中规定的条件修改累加器?
4

4 回答 4

17

不管前面的指令如何,它是否只是根据 DAA 表中规定的条件修改累加器?

是的。该文档仅告诉您 DAA 的用途。也许您指的是此链接中的表格:

--------------------------------------------------------------------------------
|           | 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   |
|------------------------------------------------------------------------------|

我必须说,我从来没有见过 dafter 指令规范。如果您仔细检查表格,您会发现指令的效果仅取决于CandH标志和累加器中的值——它根本不取决于前面的指令。此外,它不会透露如果,例如,,C=0并且H=1累加器中的低位数字是 4 或 5,会发生什么。因此,在这种情况下,您将不得不执行 a NOP,或者生成错误消息或其他内容。

于 2011-11-14T09:55:14.597 回答
10

只是想补充一点,N 标志是他们在谈论之前的操作时的意思。加法设置 N = 0,减法设置 N = 1。因此,A 寄存器的内容和 C、H 和 N 标志确定结果。

该指令旨在支持 BCD 算术,但还有其他用途。考虑这段代码:

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

它结束了将 A 寄存器的低 4 位转换为 ASCII 值 '0'、'1'、...'9'、'A'、'B'、...、'F'。换句话说,二进制到十六进制的转换器。

于 2012-01-13T09:03:42.633 回答
9

我发现这条指令也相当混乱,但我发现z80-heaven对其行为的描述最有帮助。

执行该指令时,使用标志的内容对 A 寄存器进行 BCD 校正。确切的过程如下:如果 A 的最低有效四位包含非 BCD 数字(即大于 9)或设置了 H 标志,则将 $06 添加到寄存器中。然后检查四个最高有效位。如果这个更重要的数字也恰好大于 9 或设置了 C 标志,则添加 $60。

这为指令提供了一个简单的模式:

  • 如果低 4 位形成大于 9 的数字或设置了 H,则将 $06 添加到累加器
  • 如果高 4 位形成大于 9 的数字或设置了 C,则将 $60 加到累加器中

此外,虽然 DAA旨在在加法或减法之后运行,但它可以随时运行。

于 2015-05-01T15:39:50.747 回答
5

这是生产中的代码,正确实现 DAA 并通过了 zexall/zexdoc/z80test Z80 操作码测试套件。

基于The Undocumented Z80 Documented,第 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;
}

为了可视化 DAA 交互,出于调试目的,我编写了一个小型 Z80 汇编程序,可以在实际 ZX Spectrum 或准确模拟 DAA 的仿真中运行:https ://github.com/ruyrybeyro/daatable

至于它的行为方式,在使用上述汇编程序生成 DAA 之前和之后得到一个标志 N、C、H 和寄存器 A 的表:https ://github.com/ruyrybeyro/daatable/blob/master/daaoutput.txt

于 2019-09-07T19:57:42.157 回答