除算(引き戻し法) 16bit/8bit=16bit アセンブラプログラム

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

概要

PIC18には割り算命令はありません。引き戻し法で除算プログラム(16bit/8bit=16bit)を作成しました。
筆算と同じ方法で被除数の上位から除数を引き結果がマイナスになれば除数を足してもとに戻します。引き算結果がプラスの場合はビットに1を立てます。
以上の処理をビットをずらしながら16回実行すると商と余りを求めることができます。
計算時間は非常に時間がかかり、大雑把な計算では最悪21命令サイクル*16回=336命令サイクル(クロック64MHzで21μs)かかります。1秒間に約47000回程度しか計算できないことになります。
8086のDIV命令でAX/reg8 -> AH:ALの場合、80~90クロック要します。10MHzの場合最悪9μsとなります。
H8 3048のDIVXU命令の場合14クロックです。(16MHz 0.875μs) 例えば12345/67を2進数での筆算による計算例を以下に示します。
                        0000 0000 1011 1000   -->商 184
                      ---------------------
除数 67 --> 0100 0011 ) 0011 0000 0011 1001   <--被除数 12345
                         010 0001 1
                       ---------------
                           0 1110 1011
                           0 1000 0110
                          ------------
                             0110 0101 
                             0100 0011
                            ------------
                             0010 0010 1
                             0010 0001 1
                            ---------------
                             0000 0001 0001    -->余 17
             
被除数はDIV_A16、除数はDIVL_Bに格納してからdiv16_8をコールします。商はDIV_A16,余りはDIV_M16に格納されます。
データの並び順はリトルエンディアンです。
答えを表示するプログラムは記載していないのでエミュレーター上で実行してください。以下に実行例を示します。

使用メモリは以下のとおりです。
プログラムサイズ 77byte
アクセスバンク 9byte(スタック4byte)

プログラムの説明

ソースファイル

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

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

; 除算(引き戻し法) 16bit/8bit=16bit  Version 1.00
; 2017/01/08
; 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

STACK_MAX   EQU d'4'
   
bank0       UDATA_ACS

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

stack1      RES     STACK_MAX ; スタックエリア

        CODE
        ORG 0
        goto   start    ;   リセット時

DIV1    EQU d'12345' ; 被除数
DIV2    EQU    d'67' ; 除数
        
start
        BANKSEL ANSELC
        lfsr    2,stack1+(STACK_MAX-1)  ;   スタックの設定
        movlw   LOW DIV1
        movwf   DIV_A16
        movlw   HIGH DIV1
        movwf   DIV_A16+1

        movlw   DIV2
        movwf   DIV_B
        call    div16_8
        bra    $

        
;       除算    DIV_A16 / DIV_B  商はDIV_A16  余りはDIV_M16に返される
;       2017/01/08 FSR2で示されるスタックを1byte使用
div16_8      ;   16bit/8bit=16bit
        clrf    DIV_M16
        clrf    DIV_M16+1
        movlw   d'16'
div16_8_loop
        movwf   POSTDEC2
        bcf     STATUS,C
        rlcf    DIV_A16
        rlcf    DIV_A16+1
        rlcf    DIV_M16
        rlcf    DIV_M16+1
        movf    DIV_B,W
        subwf   DIV_M16
        clrf    WREG
        subwfb  DIV_M16+1
        bnc     div16_8_non_sub
        bsf     DIV_A16,0
        bra     div16_8_shift
div16_8_non_sub
        movf    DIV_B,W
        addwf   DIV_M16
        btfsc   STATUS,C
        incf    DIV_M16+1
div16_8_shift
        movf    PREINC2,W
        decfsz  WREG
        bra     div16_8_loop
        return

        END