乗算による除算 16bit/10=16bit アセンブラプログラム

icon 項目のみ表示/展開表示の切り替え

概要

PIC18には割り算命令はありません。引き戻し法で除算すると非常に時間が掛かります。
定数であれば乗算により高速に計算できます。
ここでは16bitを10で割ってみます。除算は逆数を乗ずることで求められます。例えば65536/10=6554倍にして16bit右へずらせば近い商が計算できます。
若干の誤差が生じますので仮の商に除数を乗じて非除数との差が10以上であれば商に1加算し、先ほどの差に10を加算します。
35命令サイクル+30命令サイクル(16bit*16bit)+14命令サイクル(16bit*8bit)=79命令サイクル(64MHz 4.94μs)となります。
汎用の16bit/8bitで計算する場合、最悪336命令サイクルですので、4.2倍ほど高速となります。1秒間に約202000回の除算ができることになります。
被除数はDIV_A16、除数は10固定です。商はMUL_A16,余りはDIV_A16に格納されます。
データの並び順はリトルエンディアンです。
答えを表示するプログラムは記載していないのでエミュレーター上で実行してください。
12345÷10の実行例を示します。商の1234と余りの5が得られています。

使用メモリは以下のとおりです。
プログラムサイズ 175byte
アクセスバンク 17byte

プログラムの説明

ソースファイル

以下のファイルで構成されている
div16_10da.asm ・・・ メインプログラム

ソースファイルのダウンロード div16_10da.zip

; 乗算による除算 16bit/10=16bit  Version 1.00
; 2017/01/09
; PIC18
; MPLAB X IDE v3.45 Microchip MPASM(v5.70)

#INCLUDE <p18f46k22.inc>  
        ; 水晶発振(16MHz) クロック分周無 PLL有効(*4) プライマリクロック有効  ウォッチドッグタイマ無効 低電圧プログラム書き込みモード無効
        CONFIG FOSC = HSHP,PLLCFG=ON,PRICLKEN=ON,WDTEN=OFF,LVP=OFF

bank0       UDATA_ACS

DIV_A16     RES     2 ; 除算の被除数を指定 サブルーチンコール後答えが返る
DIV_M16     RES     2 ; サブルーチンコール後余りが返る
DIV_B       RES     1 ; 除算の除数を指定
DIV_A16T    RES     2 ;
DIV_A16T2   RES     2 ;

MUL16A   RES    2   ;   乗算引数1
MUL8B               ;   乗算引数2       
MUL16B   RES    2   ;   乗算引数2       
MUL16DTC            ;   乗算結果
MUL32DTC RES    4   ;   乗算結果 

        CODE
        ORG 0
        goto   start    ;   リセット時

DIV1    EQU d'12345' ; 被除数
DIV2    EQU d'10'    ; 除数
        
start
        movlw   LOW DIV1
        movwf   DIV_A16
        movlw   HIGH DIV1
        movwf   DIV_A16+1
        call    div16_d10
        bra    $

;       除算    DIV_A16 / 10  MUL16A:商 DIV_A16:余
;       2017/01/09
        
div16_d10   ;   16bit/10
        movff   DIV_A16,MUL16A
        movff   DIV_A16+1,MUL16A+1
        movlw   LOW ((d'65536')/(DIV2))
        movwf   MUL16B
        movlw   HIGH ((d'65536')/(DIV2))
        movwf   MUL16B+1
        call    mul16_16
        movff   MUL32DTC+2,MUL16A
        movff   MUL32DTC+3,MUL16A+1
        movlw   DIV2
        movwf   MUL8B
        call    mul16_8
        movf    MUL16DTC,w
        subwf   DIV_A16
        movf    MUL16DTC+1
        subwfb  DIV_A16+1
        movf    DIV_A16,w
        cpfsgt  MUL8B   ; 10>wregのとき次の命令をスキップ
        bra     div16_d10_mod
        bra     div16_d10_exit
div16_d10_mod
        incf    MUL16A
        clrf    WREG
        addwfc  MUL16A+1
        movlw   DIV2
        subwf   DIV_A16
        clrf    WREG
        subwfb  DIV_A16+1
div16_d10_exit
        return
        
; 乗算サブルーチン(16bit * 8bit -> 24bit)
; MUL16DTC=MUL16A*MUL8B 
; 2017/01/08

mul16_8
        ; 下位8bit*8bit
        movf    MUL16A,W
        mulwf   MUL8B
        movff   PRODL,MUL16DTC
        movff   PRODH,MUL16DTC+1
        ; 上位8bit*8bit
        movf    MUL16A+1,W
        mulwf   MUL8B
        movf    PRODL,W
        addwf   MUL16DTC+1
        btfsc   STATUS,C
        incf    PRODH
        movf    PRODH,w
        movwf   MUL16DTC+2
        return
        
; 乗算サブルーチン(16bit * 16bit -> 32bit)
; MUL32DTC=MUL16A*MUL16B        
; 2017/01/09
        
mul16_16
        ; 下位8bit*8bit
        movf    MUL16A,W
        mulwf   MUL16B
        movff   PRODL,MUL32DTC
        movff   PRODH,MUL32DTC+1
        ; 上位8bit*8bit
        movf    MUL16A+1,W
        mulwf   MUL16B
        movf    PRODL,W
        addwf   MUL32DTC+1
        btfsc   STATUS,C
        incf    PRODH
        movf    PRODH,w
        movwf   MUL32DTC+2
        ; 下位8bit*8bitH
        movf    MUL16A,w
        mulwf   MUL16B+1
        movf    PRODL,w
        addwf   MUL32DTC+1
        movf    PRODH,w
        addwfc  MUL32DTC+2
        ; 上位8bit*8bitH
        movf    MUL16A+1,w
        mulwf   MUL16B+1
        movf    PRODL,w
        addwf   MUL32DTC+2
        btfsc   STATUS,C
        incf    PRODH
        movf    PRODH,w
        movwf   MUL32DTC+3
        return


        END