Z80 DAA инструкция

Извиняюсь за этот, казалось бы, незначительный вопрос, но я нигде не могу найти ответ - я только подхожу к реализации инструкции DAA в своем эмуляторе Z80, и я заметил в руководстве Zilog, что это для целей настройки аккумулятор для двоично-десятичной арифметики. В нем говорится, что инструкция предназначена для запуска сразу после инструкции сложения или вычитания.

Мои вопросы:

  • что произойдет, если он запустится после другой инструкции?
  • откуда он знает, какая инструкция ему предшествовала?
  • Я понимаю, что есть флаг N, но это, конечно, не будет окончательно указывать на то, что предыдущая инструкция была инструкцией сложения или вычитания?
  • В любом случае он просто модифицирует аккумулятор на основе условий, изложенных в таблице DAA, независимо от предыдущей инструкции?

person PhilPotter1987    schedule 14.11.2011    source источник


Ответы (4)


В любом случае он просто модифицирует аккумулятор на основе условий, изложенных в таблице 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. Если вы внимательно изучите таблицу, то увидите, что действие инструкции зависит только от флагов C и H и значения в аккумуляторе — оно вообще не зависит от предыдущей инструкции. Также не разглашается, что произойдет, если, например, C=0, H=1, а младшая цифра в аккумуляторе будет 4 или 5. Так что вам придется выполнять NOP в таких случаях, или генерировать сообщение об ошибке, или что-то в этом роде. .

person TonyK    schedule 14.11.2011
comment
Большое спасибо - надеюсь найти не слишком много двусмысленных инструкций, подобных этой :-) - person PhilPotter1987; 14.11.2011
comment
DAA Z80 должен быть эквивалентен DAA и DAS x86, поскольку они имеют ту же цель. Ознакомьтесь с описаниями x86 обоих. Некоторые виды DAA доступны на многих процессорах. - person Alexey Frunze; 14.11.2011
comment
@Alex: чипы x86 имеют две инструкции десятичной настройки: DAA (десятичная настройка после сложения) и DAS (десятичная настройка после вычитания). Инструкция Z80 DAA объединяет их в одну, предполагая, что операнды самой последней операции сложения/вычитания были допустимыми числами BCD. - person TonyK; 23.11.2011
comment
Имейте в виду, что 8080 DAA отличается тонкими, но важными особенностями (о которых я мало знаю) от Z80. - person Dan Sheppard; 25.08.2015
comment
Таблица может быть значительно улучшена, если ADD,ADC,INC заменить на N=0, а SUB,SBC,DEC,NEG на N=1. DAA не знает, какая инструкция выполнялась последней. - person Rui F Ribeiro; 03.09.2019

Просто хотел добавить, что флаг N — это то, что они имеют в виду, когда говорят о предыдущей операции. Сложения устанавливают N = 0, вычитания устанавливают N = 1. Таким образом, содержимое регистра A и флаги C, H и N определяют результат.

Эта инструкция предназначена для поддержки двоично-десятичных арифметических операций, но имеет и другие применения. Рассмотрим этот код:

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

Он завершает преобразование младших 4 битов регистра A в значения ASCII '0', '1',... '9', 'A', 'B',..., 'F'. Другими словами, преобразователь двоичного кода в шестнадцатеричный.

person George Phillips    schedule 13.01.2012

Я также нашел эту инструкцию довольно запутанной, но я нашел это описание ее поведения на z80-heaven. чтобы быть наиболее полезным.

При выполнении этой инструкции регистр А корректируется в двоично-десятичном коде с использованием содержимого флагов. Точный процесс следующий: если младшие значащие четыре бита A содержат цифру, отличную от BCD (т. е. больше 9), или установлен флаг H, то в регистр добавляется $06. Затем проверяются четыре старших бита. Если эта более значащая цифра также больше 9 или установлен флаг C, то добавляется 60 долларов.

Это обеспечивает простой шаблон для инструкции:

  • если младшие 4 бита образуют число больше 9 или установлено H, добавьте $06 к аккумулятору
  • если старшие 4 бита образуют число больше 9 или установлено C, добавьте 60 долларов к аккумулятору

Кроме того, хотя DAA предназначен для запуска после сложения или вычитания, его можно запустить в любое время.

person theotherjim    schedule 01.05.2015
comment
Похоже, что отсутствуют последние четыре операции (SUB, SBC, NEG и DEC). - person Austin Salgat; 23.06.2015
comment
@Salgat То же правило применяется, когда N=1. Единственное, приходится вычитать поправку, когда N=1. - person GabrielOshiro; 30.07.2015

Это рабочий код, который правильно реализует DAA и проходит тесты Zexall/zexdoc/z80test Z80.

Основано на недокументированном документе Z80, стр. 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

Как это себя ведет, получил таблицу флагов N,C,H и регистра A до и после DAA, созданного с помощью вышеупомянутой программы сборки: https://github.com/ruyrybeyro/daatable/blob/master/daaoutput.txt

person Rui F Ribeiro    schedule 07.09.2019