PIC汇编函数调用

5

我正在用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

要将0x450x47相乘并将结果存储在0x50中。问题在于当我需要在不同的数据上调用此函数时,因为汇编器不允许我两次“设置”任何指针。我尝试过使用间接访问(即使用LFSR1、LFSR2和LFSR0来存储被乘数和结果),但是这样我只会陷入POSTINC0等混乱的状态。有没有办法使这个函数调用更加友好?
3个回答

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

是的,PIC汇编语言让许多事情变得不必要地复杂。

我假设你正在这个学习过程中尝试实践,否则你可以使用基本数学函数库,例如Roger Froud或Fr. Thomas McGahee编写的库,或者切换到高级语言,其中所有上述内容都可以用“*”(BASIC,C,Pyastra,JAL,Forth等)替换。

GJ所展示的调用约定非常普遍,特别是在从仅具有一个FSR寄存器和没有“PLUSW”寄存器的PIC16移植的代码中。

由于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

许多这些是必要的,如果你想保持芯片的廉价。 - BlueRaja - Danny Pflughoeft

0

你能否安排好事情,使得FSR0-FSR2指向你的操作数和结果寄存器并且表现得合理吗?例如:

movf POSTINC0,w,c
mulwf POSTINC1,c; Op0L * Op1L(现在两者都指向MSB)
movff PRODL,POSTINC2; Result0
movff PRODH,INDF2; Result1
mulwf POSTDEC1,c; Op0L * Op1H(现在0指向MSB 1指向LSB)
movf PRODL,w,c
addwf POSTINC2,f,c; Result1(现在指向Result2)
movlw 0
addwfc PRODH,w,c
movwf POSTDEC2,c; Result2(现在指向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(进位可能未处理)
clrf INDF2,f,c; Result3
rlcf POSTDEC2,f,c; 存储进位
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比手动移动大量数据更便宜。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接