Таки грамотно сделано - не надо запоминать состояние после предыдущего SUB...
Вид для печати
Всё. Центральный процессор засбоил. Завтра пойду феном выпаивать.
Перепаял вручную. Всё нормально.
ADC16 чуть по-больше:
Здесь сразу и ADC и SBC: (пришлось частями, всё не лезет)
Попались на строке 66048. Вместо
имеемЦитата:
87ac 80ff 8000 fe91
то есть ошибочно взведен PF.Цитата:
87ac 80ff 8000 fe91
PF в ADC16/SBC16 считается так. Считается значение PF как для всех прочих арифметических операций, но только для старших половин результата, прежнего значения HL и операнда.
Далее делается следующее. Если сумма второго операнда (то, что добавляется) и CF вызывает переполнение (то есть, CF взведен и операнд был равен #FFFF или стал равен #0000 после сложения с CF), тогда результирующее значение PF меняется на обратное, то есть взводится если сброшен и наоборот.
Мы уже знаем, что ADC8 считается верно, значит правильно работающее вычисление PF для арифметических инструкций есть, и нужно только правильно применить его к ADC16/SBC16.
То есть правильно я понимаю?
OPH:OPL - операнд. Сначала делаю ADD L,OPL, ADC H,OPH. Затем запоминаю PF. Затем если в начале C=0 - то выхожу, а если C=1 - инкрементирую HL и проверяю C, и если этот самый С=1 - значит инвертирую PF?
А флаг С я считаю как С1 or С2, где С1 - флаг переполнеия при первом сложении (старших байт), а С2 - при возможном втором (если в начале С=1).
Премного благодарен за консультацию !!!
Не совсем. PF нужно инвертировать не тот, который получился при сложении HL и OP, а тот, который получился при сложении HL, OP и CF. Получив его, мы смотрим на то, дает ли переполнение сложение OP и CF. Переполнение будет только если CF был взведен и OP=#FFFF. Так вот если это переполнение случилось, следует проинвертировать PF.
Не забудьте также, про случаи "ADC HL, HL" и "SBC HL, HL" -- эти инструкции модифицируют свои вторые операнды, но во время их исполнения OP (то есть, эти самые вторые операнды) должны рассматриваться равными значению HL до исполнения инструкций, как бы HL ни изменялся во время их исполнения.
Есть идея сделать так:
1. Прибавить к операнду изначалое значение С.
2. Запомнить флаги P1, C1, S1, V1 - после первой операции.
2. Прибавить к HL текущее значение операнда используя компнда ADD, ADC.
3. Запомнить флаги P2, C2, S2, V2 после второго действия.
4. Вычислить флаги P, C, S результата как P=(P1ORP2)XORC1, C=C1ORC2, S=S1ORS2, V=V1ORV2, Z вычислить проверкой HL на ноль.
Почти. :)
В терминах Z80, и если перекладывать на восьмиразрядные инструкции, инструкция "ADC HL, OP" эквивалентно следующему.
1) Прибавляем CF к OP:
Здесь запоминаем флаги CF1 и PF1.Код:LD A, OPL
ADC A, 0
LD OPL, A
LD A, OPH
ADC A, 0
LD OPH, A
Имеем в виду, что OP -- это временная копия операнда, а не сам этот регистр в правой части инструкции. То есть, сам регистр не модифицируем.
2) Прибавляем OP к HL:
3) Считаем PF. Он равен текущему PF (после "ADD A, OPH") в ксорке с PF1, то естьКод:LD A, L
ADD A, OPL
LD L, A
LD A, H
ADD A, OPH
LD H, A
4) Считаем CF. Он равен текущему CF (после той же инструкции) в дизъюнкции с CF1 -- как вы и написали, то естьКод:PF = PF XOR PF1
5) Считаем ZF. Это, действительно, просто проверка HL на 0.Код:CF = CF OR CF1
6) SF считать не нужно. Последняя инструкция его выставит сама.
7) А вот HF посчитать придется. То, что дает последняя инструкция будет правильным значением для инкрементированного операнда (если CF на входе взведен), а нам нужен HF для исходных операндов, то есть до инкремента.
8) MEMPTR = значение HL до исполнения.
9) Во флаги 3 и 5 копируем соответствующие разряды старшей половины резлуьтата (то есть H).