Затребовалось мне посчитать сумму квадратов трёхбайтных величин. Я, в принципе, знаю один способ умножения столбиком. В нём произведение строится в цикле по битам одно сомножителя прямо на месте другого сомножителя (с добавлением дополнительных байт для хранения результата, разумеется). Соответствующая процедура очень компактна по коду и использует минимально возможное число регистров процессора (1 на счётчик, n на один множитель и n*m на результат и другой множитель, размер которого m байт). Но она жутко медленная, а мне нужно считать квадраты в прерывании быстро.
Я знаю другой способ, с использованием таблиц квадратов. Кто не знаком с ним, вот эту статью можно взять за отправную точку. Единственный минус подхода в статье заключается в том, что там используют сумму сомножителей, которая на один бит выходит за пределы размера сомножителей. Использование схемы ab = (a^2 + b^2 - (a - b)^2) / 2 более рационально в плане памяти, на мой взгляд. Особенно, если учесть, что таблица квадратов байта занимает в памяти 512 байт, что уже составляет 25% от всего ПЗУ моего МК.
Для построения программы составил себе шпаргалку:
Теперь вот думаю, как бы это по-лучше всё складывать. Квадраты будут суммироваться в кумулятивную сумму, которую логично хранить в оперативке. Так как обращение к ней медленнее, чем к регистрам, то логично формировать каждый байт-разряд суммы залпом, один раз читая его в начале и один раз записывая его в конце. Чтение таблицы квадратов из ПЗУ тоже не быстрая операция, поэтому логично читать каждый квадрат один раз и хранить результат в регистре, пока в нём есть потребность. Чтобы не таскать перенос от сложения по всей сумме от текущего разряда до самого старшего, логично собирать все переносы в отдельный регистр и добавлять к следующему разряду суммы, только когда приступим к его формированию. В итоге требуется очень много регистров МК, чтобы процедура работала шустро. Возможно, где-то быстродействием стоит пожертвовать, чтобы сократить расход регистров, они и в других частях программы используются.
Кто-нибудь делал что-нибудь подобное? Какие могут быть советы/рекомендации?
Добавлено after 2 hours 5 minutes 53 seconds:
Как-то так выглядит умножение двух байт:
Спойлер
Код: Выделить всё
;==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
; Процедура перемножает два байта табличным методом по формуле
; A * B = (A^2 + B^2 - (A - B)^2) / 2
; Используемые регистры:
; - r16 и r17 - исходные сомножители
; - r14 и r15 - возвращаемое произведение
; - r18 и r19 - вспомогательные регистры для промежуточных данных
; - Z - указатель для чтения таблицы квадратов в ПЗУ
; Размер процедуры 54 байта (27 инструкций)
; Время выполнения 45 тактов (включая rcall и ret)
;--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--
mul_8x8: mov ZL, r16 ; Чтение из ПЗУ квадрата первого сомножителя
ldi ZH, HIGH(2*SquareTable1)
lpm r15, Z ; Старший байт квадрата
ldi ZH, HIGH(2*SquareTable0)
lpm r14, Z ; Младший байт квадрата
sub ZL, r17 ; Расчёт модуля разности сомножителей
brcc mul_8x8_
neg ZL ; Если разность отрицательна, то сменить знак
mul_8x8_: lpm r19, Z ; Чтение младшего байта квадрата разности
sub r14, r19 ; Вычитание его из результата
ldi ZH, HIGH(2*SquareTable1)
lpm r19, Z ; Чтение старшего байта квадрата разности
sbc r15, r19 ; Вычитание его из результата
sbc r18, r18 ; Сохранение заёма в старшем разряде
mov ZL, r17 ; Чтение квадрата второго сомножителя
ldi ZH, HIGH(2*SquareTable0)
lpm r19, Z ; Младший байт
add r14, r19 ; Сложение его с результатом
ldi ZH, HIGH(2*SquareTable1)
lpm r19, Z ; Старший байт
adc r15, r19 ; Сложение его с результатом
clr r19
adc r18, r19 ; Перенос в старший разряд
lsr r18 ; Деление результата на 2
ror r15
ror r14
ret
;==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
Спойлер
Код: Выделить всё
;==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
.org 0x0300
;--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--
SquareTable0: .dw 0x0100, 0x0904, 0x1910, 0x3124, 0x5140, 0x7964, 0xA990, 0xE1C4
.dw 0x2100, 0x6944, 0xB990, 0x11E4, 0x7140, 0xD9A4, 0x4910, 0xC184
.dw 0x4100, 0xC984, 0x5910, 0xF1A4, 0x9140, 0x39E4, 0xE990, 0xA144
.dw 0x6100, 0x29C4, 0xF990, 0xD164, 0xB140, 0x9924, 0x8910, 0x8104
.dw 0x8100, 0x8904, 0x9910, 0xB124, 0xD140, 0xF964, 0x2990, 0x61C4
.dw 0xA100, 0xE944, 0x3990, 0x91E4, 0xF140, 0x59A4, 0xC910, 0x4184
.dw 0xC100, 0x4984, 0xD910, 0x71A4, 0x1140, 0xB9E4, 0x6990, 0x2144
.dw 0xE100, 0xA9C4, 0x7990, 0x5164, 0x3140, 0x1924, 0x0910, 0x0104
.dw 0x0100, 0x0904, 0x1910, 0x3124, 0x5140, 0x7964, 0xA990, 0xE1C4
.dw 0x2100, 0x6944, 0xB990, 0x11E4, 0x7140, 0xD9A4, 0x4910, 0xC184
.dw 0x4100, 0xC984, 0x5910, 0xF1A4, 0x9140, 0x39E4, 0xE990, 0xA144
.dw 0x6100, 0x29C4, 0xF990, 0xD164, 0xB140, 0x9924, 0x8910, 0x8104
.dw 0x8100, 0x8904, 0x9910, 0xB124, 0xD140, 0xF964, 0x2990, 0x61C4
.dw 0xA100, 0xE944, 0x3990, 0x91E4, 0xF140, 0x59A4, 0xC910, 0x4184
.dw 0xC100, 0x4984, 0xD910, 0x71A4, 0x1140, 0xB9E4, 0x6990, 0x2144
.dw 0xE100, 0xA9C4, 0x7990, 0x5164, 0x3140, 0x1924, 0x0910, 0x0104
;--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--
SquareTable1: .dw 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
.dw 0x0101, 0x0101, 0x0101, 0x0201, 0x0202, 0x0202, 0x0303, 0x0303
.dw 0x0404, 0x0404, 0x0505, 0x0505, 0x0606, 0x0706, 0x0707, 0x0808
.dw 0x0909, 0x0A09, 0x0A0A, 0x0B0B, 0x0C0C, 0x0D0D, 0x0E0E, 0x0F0F
.dw 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1716, 0x1817
.dw 0x1919, 0x1A1A, 0x1C1B, 0x1D1C, 0x1E1E, 0x201F, 0x2121, 0x2322
.dw 0x2424, 0x2625, 0x2727, 0x2928, 0x2B2A, 0x2C2B, 0x2E2D, 0x302F
.dw 0x3131, 0x3332, 0x3534, 0x3736, 0x3938, 0x3B3A, 0x3D3C, 0x3F3E
.dw 0x4140, 0x4342, 0x4544, 0x4746, 0x4948, 0x4B4A, 0x4D4C, 0x4F4E
.dw 0x5251, 0x5453, 0x5655, 0x5957, 0x5B5A, 0x5D5C, 0x605F, 0x6261
.dw 0x6564, 0x6766, 0x6A69, 0x6C6B, 0x6F6E, 0x7270, 0x7473, 0x7776
.dw 0x7A79, 0x7D7B, 0x7F7E, 0x8281, 0x8584, 0x8887, 0x8B8A, 0x8E8D
.dw 0x9190, 0x9493, 0x9796, 0x9A99, 0x9D9C, 0xA09F, 0xA4A2, 0xA7A5
.dw 0xAAA9, 0xADAC, 0xB1AF, 0xB4B2, 0xB7B6, 0xBBB9, 0xBEBD, 0xC2C0
.dw 0xC5C4, 0xC9C7, 0xCCCB, 0xD0CE, 0xD4D2, 0xD7D5, 0xDBD9, 0xDFDD
.dw 0xE2E1, 0xE6E4, 0xEAE8, 0xEEEC, 0xF2F0, 0xF6F4, 0xFAF8, 0xFEFC
;==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==


А в чём разница?
