Сообщение от
Titus
Код:
2.4 Classic 24-bit / 8-bit Unsigned
Input: HLD = Dividend, E = Divisor, A = 0
Output: HLD = Result, A = Remainder
slia d ; unroll 24 times
add hl,hl ; ...
rla ; ...
sub e ; ...
jr nc,$+3 ; ...
add a,e ; ...
dec d ; ...
Может кто-то обьяснит, куда девалась проверка флага переноса после rla? Или я просто много хочу на ночь глядя? В процедуре деления, где делимое равно или меньше делителя, эта проверка не нужна, т.к. разрядность рабочего регистра остатка больше или равна числу сдвигов. В случае же, когда разрядность делителя меньше делимого, эта проверка требуется, иначе деление на число >= $80 приведет к глюку.
В самом деле, возможен глюк при делении на число >$80 (не всегда). Значит ошибка в алгоритме. Надо же! А ведь я столько времени пользовался похожим алгоритмом, который тоже не проверяет перенос после сдвига рабочего регистра остатка.
Когда делитель >$80, а в рабочем регистре остатка хранится число >=$80, но меньше делителя, то пробное вычитание окажется неуспешным, а на следующем проходе цикла рабочий регистр остатка будет сдвинут влево, т.е. там образуется число >=$100. Однако 8-разрядный аккумулятор не может хранить такое число, и старший разряд попадет во флаг C.
В такой ситуации пробное вычитание должно обязательно быть успешным, т.к. $100>$FF (максимальное значение делителя). Однако поскольку старший разряд, находящийся во флаге C, данным алгоритмом не учитывается, то пробное вычитание снова окажется неуспешным. В результате в частное и в рабочий регистр остатка попадет неверная информация, делающая дальнейшую работу алгоритма ошибочной.
Еще одна ошибка приведенного алгоритма - это то, что нужно применять ADC HL,HL, а не ADD HL,HL.
---
Вот вариация без недокументированных команд и чуть быстрее (на одну команду в цикле):
Код:
2.4 Classic 24-bit / 8-bit Unsigned
Input: HLD = Dividend, A = Divisor
Output: HLD = Result, A = Remainder
neg
ld e,a
xor a
rl d ; unroll 24 times
adс hl,hl ; ...
rla ; ...
add a,e ; ...
jr c,$+3 ; ...
sub e ; ...