Расчет флагов

Материал из Emuverse
Этот документ создан для Emuverse и распространяется на условиях лицензии CC-BY-SA-3.0.

В данной статье описываютя алгоритмы расчета значений регистра состояния процессора (регистра флагов).

В следующих алгоритмах используются следующие обозначения (предполагается, что вычисления 8-битовые):

  • A: Аккумулятор, первый операнд;
  • d: второй операнд;
  • r8: результат вычислений при использовании 8-разрядной переменной;
  • r16: результат вычислений при использовании 16-разрядной переменной;

Перенос

Установка флага переноса обозначает, что результат предущей операции не уместился в регистре результата.

  • для r8: CY=1 если A>r при сложении, CY=1 если A<r при вычитании;
  • для r16: просто
    • r16>>8&1 (Си)
    • (r16 shr 8) and 1 (Паскаль);

В формулах подразумеватся, что бит переноса самый младший в регистре флагов.

Ноль и знак

Установка флага «Ноль» в единицу означает, что результат равен нулю. Флаг знака равен старшему биту результата.

Оба флага удобно устанавливать одновременно по массиву:

Flags := Flags or ZERO_SIGN[r8];

ZERO_SIGN:array [0..255] of byte =(
	F_ZERO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,				// 00-0F */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          			// 10-1F */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,          			// 20-2F */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 				// 30-3F */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 				// 40-4F */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 	 			// 50-5F */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 				// 60-6F */
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 				// 70-7F */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,  	// 80-8F */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,  	// 90-9F */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,  	// A0-AF */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,  	// B0-BF */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,  	// C0-CF */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,  	// D0-DF */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,  	// E0-EF */
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,
	F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN,F_SIGN); 	// F0-FF */

Четность

Установка флага четности означает, что количество разрядов результата, равных 1, четное. Далее приведен пример с использованием массива.

Flags := Flags or PARITY[r8];

PARITY:array [0..255] of Byte = (
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,     // 00-0F
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // 10-1F
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // 20-2F
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,     // 30-3F
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // 40-4F
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,     // 50-5F
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,     // 60-6F
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // 70-7F
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // 80-8F
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,     // 90-9F
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,     // A0-AF
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // B0-BF
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,     // C0-CF
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // D0-DF
	0,F_PARITY,F_PARITY,0,F_PARITY,0,0,F_PARITY,F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,     // E0-EF
	F_PARITY,0,0,F_PARITY,0,F_PARITY,F_PARITY,0,0,F_PARITY,F_PARITY,0,F_PARITY,0,0,4);    // F0-FF

Частичный перенос

Частичный перенос аналогичен обычному переносу, но означает, что результат операции над младшими 4-мя битами не уместился в 4 четыре младших бита результата. Этот флаг используется в операциях с двоично-десятичными числами (ВСD);

  • (r^A^d)&0x10; (Си);
  • (r xor A xor d) and $10; (Паскаль).

В формулах подразумеватся, что бит частичного переноса пятый в регистре флагов.

Переполнение

Установка флага переполнения означает, что результат предыдущей операции не уместился в отведенный регистр, если рассматривать операнды как числа со знаком. То есть флаг аналогичен флагу переноса, но только для значений в дополнительном коде.

  • Си:
    • ((A^r)&(d^r))>>5&4 после сложения
    • ((A^d)&(A^r))>>5&4 после вычитания
  • Паскаль:
    • (((A xor r) and (d xor r)) shr 5) and 4 после сложения
    • (((A xor d) and (A xor r)) shr 5) and 4 после вычитания

В указанных формулах предполагается, что флаг переполнения является третьим битом в регистре состояния (справедливо для Z80).