Группа из нас (студенты-электронщики – Великобритания) недавно в свое время освоили программирование микроконтроллера PIC16F84A. Возникла необходимость перемножить два 8-битных числа, не зная минимального/максимального значения для каждого из них. Однокурсник предложил следующую идею.
multiply_numbers:
; Takes numbers in Num1 and Num2, and returns product in OutH:OutL
clrf OutH ; clear all non-input variables
clrf OutL
mult_loop
bcf STATUS,c ; clear carry bit
movfw Num2
addwf OutL ; add Num2 to OutL
btfsc STATUS,c ; check carry bit
incf OutH ; if set, increment OutH
decfsz Num1 ; decrement Num1
goto mult_loop ; if Num1 is not zero, repeat loop
return ; else return
Я чувствовал, что это, хотя и довольно короткое с точки зрения строк кода, может занять относительно много времени для выполнения для больших чисел. Я немного подумал и начал двигаться по маршруту, сдвигая одно число вправо, другое влево и добавляя сдвинутое влево число определенное количество раз по пути к выходу, чтобы получить окончательный ответ. Я делал это не совсем правильно, но затем наткнулся на этот вопрос на SO, который дал мне идею выразить одно из входных чисел как:
N = a_0 + a_1*2 + a_2* 2^2 + a_3*2^3 + ... + a_7*2^7
Исходя из этого, я придумал метод умножения двух 8-битных чисел для получения 16-битного результата (хранящегося в два 8-битных регистра).
multiply_numbers:
; Takes numbers in Num1 and Num2L, and returns product in OutH:OutL
clrf Num2H ; clear all non-input variables
clrf OutL
clrf OutH
mult_loop
btfsc Num1,0 ; test LSB of Num1
call add_num16 ; if set, add Num2H:Num2L to OutH:OutL
call shift_left ; shift Num2H:Num2L left (multiply by 2)
rrf Num1,f ; shift Num1 right
clrw ; clear working register (0x00)
bcf STATUS,z ; clear zero bit (3) of the STATUS register
addwf Num1,w ; add 0x00 to Num1
btfss STATUS,z ; if Num1 is zero, then exit loop
goto mult_loop ; else, continue with another iteration
return
add_num16
movfw Num2H
addwf OutH,f ; add Num2H to OutH
bcf STATUS,c ; clear carry bit (0) of the STATUS register
movfw Num2L
addwf OutL,f ; add Num2L to OutL
btfsc STATUS,c ; check carry bit
incf OutH,f ; increment OutH if set (OutL overflowed)
return
shift_left
bcf STATUS,c ; clear carry bit
rlf Num2L,f ; rotate Num2L left (carry -> LSB, MSB -> carry)
rlf Num2H,f ; rotate Num2H left, using carry bit from Num2L
return
Я думаю, что этот второй пример в большинстве случаев быстрее, просто потому, что цикл будет повторяться только до 8 раз, а не до 256 раз.
Правильно ли я предполагаю их относительную скорость/эффективность? И действительно ли второй блок кода работает так, как я задумал (есть ли какие-либо потенциальные проблемы с ним, которые я пропустил)? Наконец, можно ли дополнительно оптимизировать это умножение с помощью еще не использовавшихся методов?
Заранее благодарю.
П.С. Все переменные/регистры были правильно определены со своими собственными адресами. Обширное комментирование кода связано с тем, что мы пытаемся скомпилировать набор подпрограмм, к которым мы можем обращаться в будущем и по-прежнему с первого взгляда знать, что происходит и почему.
П.П.С. Этот вопрос связан с личным / хобби интересом к программированию этой картинки и не имеет ничего общего с какой-либо текущей курсовой работой и т. Д.Просто чтобы рассеять любые подозрения, которые у вас могли быть!
Микроконтроллер: PIC16F84A
Среда разработки: MPLABX IDE v1.10
Компилятор: mpasm (v5.43)
Метод 2 улучшен:
multiply_numbers:
; Takes numbers in Num1 and Num2, and returns product in OutH:OutL
clrf OutL ; clear all non-input variables
clrf OutH
; 1st iteration
btfsc Num1,7 ; test MSB of Num1
call add_num8 ; if set, add Num2 to OutH:OutL
bcf STATUS,c ; clear carry bit
rlf OutL,f ; rotate OutL left (carry -> LSB, MSB -> carry)
rlf OutH,f ; rotate OutH left, using carry bit from OutL
rlf Num1,f ; shift Num1 left
; 2nd iteration
btfsc Num1,7
call add_num8
bcf STATUS,c
rlf OutL,f
rlf OutH,f
rlf Num1,f
; 3rd iteration
btfsc Num1,7
call add_num8
bcf STATUS,c
rlf OutL,f
rlf OutH,f
rlf Num1,f
; 4th iteration
btfsc Num1,7
call add_num8
bcf STATUS,c
rlf OutL,f
rlf OutH,f
rlf Num1,f
; 5th iteration
btfsc Num1,7
call add_num8
bcf STATUS,c
rlf OutL,f
rlf OutH,f
rlf Num1,f
; 6th iteration
btfsc Num1,7
call add_num8
bcf STATUS,c
rlf OutL,f
rlf OutH,f
rlf Num1,f
; 7th iteration
btfsc Num1,7
call add_num8
bcf STATUS,c
rlf OutL,f
rlf OutH,f
rlf Num1,f
; 8th iteration
btfss Num1,7 ; test MSB of Num1
return ; if not set, then return. else...
add_num8
bcf STATUS,c ; clear carry bit (0) of the STATUS register
movfw Num2
addwf OutL,f ; add Num2L to OutL
btfsc STATUS,c ; check carry bit
incf OutH,f ; increment OutH if set (OutL overflowed)
return