Поднаписал. Но всё равно failed (как мне уже надоело это слово)
Вид для печати
Поднаписал. Но всё равно failed (как мне уже надоело это слово)
Ну не хочет ROBOCOP ходить.
http://dl.dropbox.com/u/12408899/CVB...29ROBOCOP1.zip
При AF=#0012 дает AF=#FAAE вместо #FABE, т.е. ошибочно сбрасывается HF.
#12 значит взведены HF и NF, A=#00. Значит, идем по пункту 2a):
2a) Если флаг H до исполнения был взведен и четыре младших разряда регистра A меньше или равны 5, тогда после исполнения HF должен быть взведен.
Смотреть нужно на значение регистра A как оно было до исполнения инструкции. Может быть, в этом ошибка?
Что-то со стеком или с памятью вообще.
Смотрите со строки 6284:
Здесь вызывается подпрограмма обновления контрольной суммы по адресу #94fd. Это подпрограмма у вас вызывается успешно много раз. Но в очередной раз, начиная вызов со строки 6284, подпрограмма доходит до строкиЦитата:
8928 0092 0000 0000 0092 2000 2000
соответствующей инструкции RET, но возвращает управление не по адресу #8928 + 3 = #892B (адрес инструкции CALL + ее размер), а по адресу #8900.Цитата:
9526 0092 0000 0000 fabe 2000 2000
Если сразу ошибку не найдете, давайте попробуем сделать тот же трейсинг добавив в него значения регистра SP. Может быть, это наведет на нужную мысль.
Исправил. Добавил SPH:SPL в конце строки.
Пока failed. Прошли меньше 0,5% от DAA. Может исключить IX, IY, SP? И ещё: я тут подумал, если ошибка при возникновении накапливается, может найти где она начинается? могу запуститься по содержимому BC сразу с половины, четверти/трёх четвёртых и т д трейсинга.
Начиная с BC=8000:
Здесь проходим все.
К моменту BC=#8000 контрольная сумма уже отличается, то есть ошибка где-то раньше.
Предложение такое: мы уже занем, что оснастка работает как положено. В каждой итерации она исполняется одинаково. Поэтому можно оставить только состояние до и после "DAA". Формально условие будет такое: (PC=#86E7 ИЛИ PC=#86E8). Если объем вывода существенно влияет на время сбора трейсинга, можно оставить только значения для AF.
Отлично, попалась на строке 1570. На входе AF=#0410, на выходе ошибочное AF=#6A2D вместо правильного AF=#0A0C.
Насчет #6A вместо #0A: #60 нужно добавлять только если CF взведен или A >= #9A. В последнем случае CF на выходе следует взвести (тогда в F получим правильное #xD вместо имеющегося #xC).
Насчет взведенного флага 5: это может быть из-за ошибочно добавленного #60 к результату. Если нет, то во флаги 3 и 5 следует скопировать соответствующие разряды результирующего значения регистра A.
В данном случае добавляем #06 из-за взведенного HF.
Если на входе CF взведен или регистр A больше или равен #9A, то следует a) добавить #60 и b) взвести CF.
Далее, если взведен HF или четыре младших разряда A больше или равны 10, тогда добавляем #06 (возможно, к дополнение к ранее добавленным #60).
Далее, если NF взведен, тогда эти #60 и #06 следует не добавлять к A, а вычитать из A.
Как считать HF уже выяснили. Про CF сказано выше. NF не меняем. PF считаем как флаг четности. ZF взводим если результат в A получился нулевым. Про флаги 3 и 5 тоже сказано выше. Вроде бы все, что нужно.
Точно. Н=1. Но тогда я вообще не понимаю. Я пользовался при генерировании DAA вложением. Так вот там эта ситуация (Н=1, С=0, N=0, А=04) - вообще не определена. Значит там где-то ошибка?
P A S S E D !
Вот они, результаты работы с умным человеком !
P A S S E D !
Шлю PC BC AF;
PASSED !
Да ... AVR при выполнении SBC не влияет на Z при нулевом результате, а при ненулевом сбрасывает. А я и не знал.
Всё. Центральный процессор засбоил. Завтра пойду феном выпаивать.
Перепаял вручную. Всё нормально.
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).