5

私はPIC18アセンブリでかなり基本的なプログラムを書いています。2 つの 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つのレジスタに格納するというものです。これは、この乗算を 1 回か 2 回実行するだけでよい場合にうまく機能します。つまり、次のように言えます。

mul_16ptr1   set    0x45
mul_16ptr2   set    0x47
mul_16res    set    0x50
call         mul_16bit

乗算0x450x47て に格納し0x50ます。問題は、異なるデータに対してこれを複数回呼び出す必要がある場合です。これは、アセンブラーがポインターを 2 回「設定」できないためです。間接アクセス (つまり、被乗数と結果を格納するために LFSR1、LFSR2、および LFSR0 を使用) を使用しようとしましたが、POSTINC0 などの巨大な混乱が発生します。この関数呼び出しをより適切にする方法はありますか?

4

3 に答える 3

2

PIC18 の機能は通常、RegA、RegB、RegR などの専用の入力変数を使用します。したがって、次のように宣言されています。

RegA res 2    ;16bit var
ResB res 2    ;16bit var
ResR res 4    ;32bit var

suchlike 関数の呼び出しは次のようになります。

;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
于 2010-06-19T15:41:21.217 に答える
1

はい、PIC アセンブリ言語は多くのことを不必要に複雑にします。

学習経験の一環としてこれを行っていると仮定しています。それ以外の場合は、Roger Froud や Fr. のような基本的な数学関数ライブラリを使用することになります。Thomas McGahee、または上記のすべてを「*」に置き換えることができる高水準言語 (BASIC、C、Pyastra、JAL、Forth など) に切り替えることもできます。

GJ が示す呼び出し規則は、特に FSR レジスタが 1 つしかなく、「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
于 2010-06-24T03:44:04.520 に答える
0

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 ; Op0H
  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 ; Op0H
  mulwf POSTINC1,c ; Op1H
  movf PRODL,w,c
  addwf POSTINC2,f,c
  movf PRODH,w,c
  addwfc INDF2、f、c

LFSR は、大量のデータを手動で移動するよりも安価です。

于 2010-08-19T18:32:17.347 に答える