【问题标题】:Z80 DAA instructionZ80 DAA指令
【发布时间】:2011-11-14 09:34:34
【问题描述】:

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

我的问题是:

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

【问题讨论】:

    标签: math bcd z80


    【解决方案1】:

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

    是的。该文档仅告诉您 DAA 的用途。也许你指的是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   |
    |------------------------------------------------------------------------------|
    

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

    【讨论】:

    • 非常感谢 - 我希望不要找到太多像这样的模棱两可的说明:-)
    • Z80 的 DAA 应该等同于 x86 的 DAA 和 DAS,因为它们具有相同的用途。查看两者的 x86 描述。许多 CPU 上都有某种类型的 DAA。
    • @Alex:x86 芯片有两条小数调整指令:DAA(加法后的小数调整)和 DAS(减法后的小数调整)。 Z80 DAA 指令通过假设最近的加/减操作数是有效的 BCD 数字,将它们合二为一。
    • 请注意,8080 DAA 与 Z80 在细微但重要的方面(我对此知之甚少)有所不同。
    • 如果 ADD,ADC,INC 用 N=0 代替,SUB,SBC,DEC,NEG 用 N=1 代替,表格可以大大改善。 DAA 不知道最后执行的是哪条指令。
    【解决方案2】:

    只是想补充一点,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'。换句话说,二进制到十六进制的转换器。

    【讨论】:

      【解决方案3】:

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

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

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

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

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

      【讨论】:

      • 这似乎缺少最后四个操作(SUB、SBC、NEG 和 DEC)。
      • @Salgat N=1 也适用相同的规则。唯一的问题是N=1时必须减去修正。
      【解决方案4】:

      这是生产中的代码,正确实现 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-05
        • 1970-01-01
        • 1970-01-01
        • 2017-05-12
        相关资源
        最近更新 更多