我正在PIC18汇编中编写一个非常基本的程序。它要求我写一个子程序来乘以两个16位数。这就是我现在所拥有的:
;***********************************************************************
; mul_16bit: subroutine that multiplies two 16 bit numbers stored in
; addresses mul_16ptr1, mul_16ptr1+1 and mul_16ptr2,mul_16ptr2+1 and
; returns the 32-bit result in addresses mul_16res1 to mul_16res1+3
;***********************************************************************
mul_16bit:
movf mul_16ptr2, W ;multiply the lower bytes
mulwf mul_16ptr1, W
movff PRODH, mul_16res+1
movff PRODL, mul_16res
movf mul_16ptr2+1, W ;multiply upper bytes
mulwf mul_16ptr1+1, W
movff PRODH, mul_16res+3
movff PRODL, mul_16res+2
movf mul_16ptr2, W ;multiply lower byte of num2
mulwf mul_16ptr1+1, W ; and upper byte of num1
movf PRODL, W
addwf mul_16res+1, F
movf PRODH, W
addwfc mul_16res+2, F
movlw 0 ; add carry
addwfc mul_16res+3, F
movf mul_16ptr2+1, W ;multiply upper byte
;of num1 and lower
mulwf mul_16ptr1, W ; byte of num2
movf PRODL, W ;add the result to mul_16res
addwf mul_16res+1, F ;...
movf PRODH, W ;...
addwfc mul_16res+2, F ;...
movlw 0 ; add carry
addwfc mul_16res+3, F
return
我现在写的方式是它将第一个注释中提到的注册中存储的数字相乘,并将它们存储在注释中的4个寄存器中。如果我只需要做一次或两次这样的乘法,那就行得很好,即我可以这样说:
mul_16ptr1 set 0x45
mul_16ptr2 set 0x47
mul_16res set 0x50
call mul_16bit
将0x45
和0x47
相乘并将其存储在0x50
中。问题是当我需要在不同的数据上多次调用它时,因为汇编器不会让我“设置”任何指针两次。我尝试过使用间接访问(即使用LFSR1,LFSR2和LFSR0来存储被乘数和结果),但后来我只是陷入了大量的POSTINC0等等。无论如何要让这个函数调用更好的东西吗?
答案 0 :(得分:2)
PIC18下的功能通常使用RegA,RegB和RegR等专用输入变量。 所以有声明:
RegA res 2 ;16bit var
ResB res 2 ;16bit var
ResR res 4 ;32bit var
调用类似的函数看起来像:
;Constants declaration
OperandA set 1234
OperandB set 7777
;
;
;Prepare calling operand A
movlw low OperandA
movwf RegA
movlw high OperandA
movwf RegA + 1
;Prepare calling operand B
movlw low OperandB
movwf RegB + 0
movlw high OperandB
movwf RegB + 1
;Function call
call MullAB_16bit
;Result is in RegR
答案 1 :(得分:1)
是的,PIC汇编语言使许多事情变得不必要地复杂化。
我假设你这样做是学习经历的一部分 - 否则你要么使用basic math function library,如Roger Froud或Fr. Thomas McGahee,或者转换到更高级别的语言,其中所有上述语言都可以用“*”(BASIC,C,Pyastra,JAL,Forth等)代替。
GJ演示的调用约定非常常见,特别是在从PIC16移植的代码中,它只有一个FSR寄存器而没有“PLUSW”寄存器。
由于PIC18具有“PLUSWx”寄存器,因此可以使用各种更好的调用约定。 有没有办法调整这一点以获得R. Reese推荐的“重入”代码?
#include<18f4550>
OperandA res 2
OperandB res 2
Product res 4
clock_ticks res 2
useconds_per_clock_tick res 2
total_time res 4
; example of the "call" part of a possible 3-pointer calling convention.
; Public domain.
; To multiply by some number in Flash or EEPROM,
; first copy them (perhaps using TBLPTR/TABLAT)
; into some convenient temporary Operand buffer in RAM.
; Then:
; WARNING: untested code.
; put pointer to first (least-significant) byte of 16-bit operand A into FSR2
BANKSEL FSR0
lfsr2 OperandA
; put pointer to first (least-significant) byte of 16-bit operand B into FSR1
lfsr1 OperandB
; put pointer to first (least-significant) byte of 32-bit product into FSR0
lfsr0 Product
;Function call
call mul16x16bit
;Result is in Product
; example of calling the same subroutine with different arguments.
BANKSEL FSR0
lfsr2 clock_ticks
lfsr1 useconds_per_clock_tick
lfsr0 total_time
call mul16x16bit
; result is in total_time.
return
;***********************************************************************
; mull16x16bit: subroutine that multiplies two 16 bit numbers
; pointed to by the pointer FSR2, FSR2+1, FSR3, FSR3+1, and
; returns the 32-bit result in addresses pointed to by
; FSR0 to FSR0+3.
;***********************************************************************
; example of a function using a possible 3-pointer calling convention
; WARNING: untested code
; The pointers to operands are: FSR2, FSR1
; The pointer to the result is: FSR0.
; Mostly identical to code in the Microchip PIC18F2550 datasheet, page 98
; Public domain.
RESULT res 4 // temporary 4 byte register
TEMP EQU RESULT // temporary 1 byte register
mul_16bit:
movlw 1 ; multiply upper bytes
movff PLUSW2, TEMP
movf PLUSW1, W
mulwf TEMP
movff PRODH, RESULT+3
movff PRODL, RESULT+2
movf INDF2, W ;multiply the lower bytes
mulwf INDF1, W
movff PRODH, RESULT+1
movff PRODL, RESULT+0
movlw 1 ; multiply the high byte of num2
movf PLUSW2
mulwf INDF1 ; and the low byte of num1
movf PRODL, W
addwf RESULT+1, F
movf PRODH, W
addwfc RESULT+2, F
movlw 0 ; add carry
addwfc RESULT+3, F
movlw 1 ; multiply the high byte of num1
movf PLUSW1
mulwf INDF2 ; and the low byte of num2
movf PRODL, W
addwf RESULT+1, F
movf PRODH, W
addwfc RESULT+2, F
movlw 0 ; add carry
addwfc RESULT+3, F
movff RESULT+0, POSTINC0 ; copy result to destination where FSR points.
movff RESULT+1, POSTINC0
movff RESULT+2, POSTINC0
movff RESULT+3, POSTINC0
movlw 4
subwf FSR0 ; restore original value of FSR0.
return
答案 2 :(得分:0)
你可以安排一些事情,以便他们在FSR0-FSR2指向你的操作数和结果寄存器时表现得很明智吗? E.G。
movf POSTINC0,w,c mulwf POSTINC1,c ; Op0L*Op1L (now both point at MSB) movff PRODL,POSTINC2 ; Result0 movff PRODH,INDF2 ; Result1 mulwf POSTDEC1,c ; Op0L*Op1H (now 0 points at MSB 1 at LSB) movf PRODL,w,c addwf POSTINC2,f,c ; Result1 (now points at Result2) movlw 0 addwfc PRODH,w,c movwf POSTDEC2,c ; Result2 (now points at Result1) movf INDF0,w,c ; Op0H mulwf POSTINC1,c ; Op1L movf PRODL,w,c addwf POSTINC2,f,c ; Result1 movf PRODH,w,c addwfc POSTINC2,f,c ; Result2 (carry may be outstanding) clrf INDF2,f,c ; Result3 rlcf POSTDEC2,f,c ; Store carry movf INDF0,w,c ; Op0H mulwf POSTINC1,c ; Op1H movf PRODL,w,c addwf POSTINC2,f,c movf PRODH,w,c addwfc INDF2,f,c
LFSR比手动移动大量数据便宜。