【问题标题】:PIC Assembly function callingPIC 汇编函数调用
【发布时间】:2010-06-18 23:06:38
【问题描述】:

我正在用 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 等问题。有没有办法让这个函数调用更好?

【问题讨论】:

    标签: assembly microcontroller pic18


    【解决方案1】:

    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
    

    【讨论】:

      【解决方案2】:

      是的,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
      

      【讨论】:

      • 嗯,如果你想保持芯片便宜,其中许多都是必要的。
      【解决方案3】:

      你能否安排一些事情,使它们在 FSR0-FSR2 指向你的操作数和结果寄存器时表现得更合理?例如

      movf POSTINC0,w,c mulwf POSTINC1,c ; Op0L*Op1L(现在都指向 MSB) movff PRODL,POSTINC2 ;结果0 movff PRODH,INDF2 ;结果1 mulwf POSTDEC1,c ; Op0L*Op1H(现在 MSB 为 0 点,LSB 为 1) movf PRODL,w,c addwf POSTINC2,f,c ; Result1(现在指向 Result2) 移动 0 addwfc PRODH,w,c movwf POSTDEC2,c ; Result2(现在指向 Result1) movf INDF0,w,c ;操作0H mulwf POSTINC1,c ; OP1L movf PRODL,w,c addwf POSTINC2,f,c ;结果1 movf PRODH,w,c addwfc POSTINC2,f,c ; Result2(进位可能未完成) clrf INDF2,f,c ;结果3 rlcf POSTDEC2,f,c ;商店携带 movf INDF0,w,c ;操作0H mulwf POSTINC1,c ; OP1H movf PRODL,w,c addwf POSTINC2,f,c movf PRODH,w,c addwfc INDF2,f,c

      LFSR 比手动移动大量数据更便宜。

      【讨论】:

        猜你喜欢
        • 2012-11-06
        • 1970-01-01
        • 1970-01-01
        • 2012-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-13
        相关资源
        最近更新 更多