円周率の計算 (7)

STmicroelectronics 社の開発環境 ST Visual Develop (STVD) 用の spigot アルゴリズムアセンブラ・ソースプログラムを下に示します。
STM8S Discovery 上で実行すると、PD5/UART2_TX 端子 (コネクタ CN4 の 10 番ピン) から 38.4 kbps シリアルでπの値を小数点以下 40 桁出力します。 値が正しいのは 37 桁までです。

3.1415926535 8979323846 2643383279 5028841666

STM8S Discovery の基板上には RS232C インターフェース回路は搭載されていないので、PC 等と接続するには外部に回路を設ける必要があります。
シリアル出力と同時に、内部の RAM の 0x0100 番地以降にも ASCII 文字列として値を格納しますから、デバッガでメモリ・ダンプすれば結果を見ることができます。
クロックの設定は変更していないので、デフォルトの 16 MHz 内部高速クロック (HSI) を 8 分周した、HSI / 8 = 2 [MHz] の CPU クロックでの実行になります。
また、STVD のデバッグ・ターゲットをシミュレータに設定すれば、STM8S Discovery がなくても、ソフトウェアだけで実行させることができます。
アセンブル方法としては、まず、STVD で新規ワークスペース/新規プロジェクトを作成します。
そして、下のプログラム・リストをコピー・アンド・ベーストした「spigot.asm」ファイルをプロジェクトのフォルダの中に作成します。
spigot.asm

stm8/
;***************************************************
;* spigot.asm : pi calculation by spigot algorithm *
;*              using 128 byte array x 1           *
;*              37 decimal digit accuracy          *
;*                                                 *
;* 2011-08-20 : Created by pcm1723                 *
;***************************************************
;
; UART2 registers
;
UART2_BASE      equ     $5240
UART2_SR        equ     {UART2_BASE+$0}
UART2_DR        equ     {UART2_BASE+$1}
UART2_BRR1      equ     {UART2_BASE+$2}
UART2_BRR2      equ     {UART2_BASE+$3}
UART2_CR1       equ     {UART2_BASE+$4}
UART2_CR2       equ     {UART2_BASE+$5}
;
; constant equates
;
f_cpu.l         equ     2000000 ; cpu clock = 2 MHz (HSI/8)
bps.l           equ     38400   ; 38.4 kbps
uart_div.w      equ     {{f_cpu+{bps/2}}/bps}
brr1_val.b      equ     {{$0ff0 and uart_div}shr 4}
brr2_val.b      equ     {{$0f and uart_div}or {{$f000 and uart_div}shr 12}}
outdigits.b     equ     40      ; output decimal digits
nterms.b        equ     128     ; number of terms
nsteps.b        equ     4       ; 
base.b          equ     100     ; base 100 number
n_lim.b         equ     {nterms-{2 mult outdigits}}
;
; global variables in page 0
;
                segment 'ram0'
num.b           ds.b    nterms  ; array for pi calc
temp.b          ds.w    1       ; (word) temporay
obufidx.b       ds.w    1       ; (word) output buffer index
n.b             ds.b    1       ; (byte) loop counter n
out.b           ds.b    1       ; (byte) output value
;
; global variables
;
        segment 'ram1'
obuf    ds.b    256     ; output buffer

        segment 'rom'
;
; Spigot main
;
.spigot                         ; implicit public label
        callr   setup_uart      ; setup uart
        callr   out_crlf        ; output CR/LF
        ld      a,#nterms
        ld      n,a             ; n  <-- nterms
; array initialize
        dec     a               ; A  <-- (nterms-1)
        exg     a,xl            ; XL <-- (nterms-1)
        ld      a,#2
for_i_loop_0
        ld      (x),a           ; num[i] <-- 2
        decw    x               ; --i
        jrne    for_i_loop_0    ; branch if not
        ld      out,a           ; out <-- 2
;                               ; now, X == 0   
for_n_loop
;                               ; X as (temp), Y as (i)
; 'for(i' setup
        ld      a,n             ; A  <--  n
        dec     a               ; A  <-- (n-1)
        exg     a,yl            ; YL <-- (n-1)
for_i_loop
        ld      a,yl            ; A <-- i
        mul     x,a             ; X = temp * i
        ldw     temp,x          ; save current temp
        ld      a,(y)           ; A <-- num[i]
        ldw     x,#base         ; X <-- base
        mul     x,a             ; X = num[i] * base
        addw    x,temp          ; X = temp * i
                                ;   + num[i] * base
; calc denom in A = 2 * i - 1   
        ld      a,yl            ; A <-- i
        sll     a               ; A <<= 1
        dec     a               ; A -= 1
        div     x,a             ; X = temp / denom,
                                ; A = temp % denom
        ld      (y),a           ; num[i] <-- temp % denom
; 'for (i' iteration    
        decw    y               ; i -= 1
        cpw     y,#1
        jrne    for_i_loop      ; branch if (1 != i)
; output result digits  
        ld      a,#base         ; A <-- base
        div     x,a             ; X = temp / base
                                ; A = temp % base
        exg     a,xl            ; A <-- quo., XL <-- rem
        add     a,out           ; A <-- out + temp/base
        callr   out2dig         ; output 2 digits
        ld      a,xl            ; A <-- rem.
        ld      out,a           ; out <-- temp % base
; 'for (n' iteration    
        ld      a,n             ; A <-- n
        sub     a,#nsteps       ; A -= nsteps
        ld      n,a             ; update n
        cp      a,#n_lim        ; compare to limit
        jrnc    for_n_loop      ; branch if not end
        ret
;
; UART setup and init output buffer index 
;
setup_uart
        mov     UART2_BRR2,#brr2_val    ; b15..b12,b3..b0
        mov     UART2_BRR1,#brr1_val    ; b11..b4
        mov     UART2_CR1,#0            ; enable UART, 8N
        mov     UART2_CR2,#%00001100    ; Rx, Tx enable
        clrw    y
        clrw    x
        ldw     obufidx,x               ; clear buffer index
        ret     
;
; output CR/LF
;
out_crlf
        push    a       ; save A
        ld      a,#$0d  ; CR
        callr   outc
        ld      a,#$0a  ; LF
        callr   outc
        pop     a       ; restore A
        ret     
;
;  output 2 digits
;
out2dig
        push    a               ; save A
        pushw   y               ; save Y
        pushw   x               ; save X
        clrw    y
        ld      yl,a            ; YL <-- out
        ld      a,#10           ;
        div     y,a             ; Y = out / 10
                                ; A = out % 10
        exg     a,yl            ; A  <-- (out/10)
                                ; YL <-- (out%10)
        ldw     x,obufidx       ; output buffer index
        jreq    out2d1          ; skip the very first '0'
        callr   outnum          ; output 1st digit
out2d1  
        exg     a,yl            ; A <-- YL (out%10)
        callr   outnum          ; output 2nd digit
;       
        ld      a,#11           ; 10 digit + 1 delim
        pushw   x               ; save buffer index
        div     x,a             ; A = idx % 11
        popw    x               ; restore buffer index
        cp      a,#1            ; 1 == (idx mod 11) ?
        jrne    out2d3          ; no delimiter needed
        ld      a,#'.'          ; decimal point
        cpw     x,#1            ; test for integer digit
        jreq    out2d2          ; branch if so
        ld      a,#' '          ; blank
out2d2  
        callr   outchar         ; output delimiter
out2d3
        ldw     obufidx,x       ; update buffer index
        popw    x               ; restore X
        popw    y               ; restore Y
        pop     a               ; restore A
        ret
;
; output a char to UART
;
outnum  add     a,#'0'          ; cnvert to ASCII
outchar
        ld      (obuf,x),a      ; store char in buffer
        incw    x
outc    
        btjf    UART2_SR,#7,*   ; wait until Tx empty
        ld      UART2_DR,a      ; output char via UART
outc_ret        
        ret
        
        end

そして、STVD 上で「spigot.asm」を「プロジェクトに追加」し、新規プロジェクト作成時に自動生成された「main.asm」に下のように 2 行追加します。
main.asm

stm8/

        #include "mapping.inc"

        extern  spigot.w ; ******* この行を追加 *******    

        segment 'rom'
main.l

....... < 中略 >  .......

clear_stack.l
        clr (X)
        incw X
        cpw X,#stack_end        
        jrule clear_stack
        
        call spigot      ; ******* この行を追加 *******    

infinite_loop.l
        jra infinite_loop

....... < 後略 >  .......

以上の準備でアセンブルができます。
アセンブル結果の S フォーマット・ファイルを下に示します。

S00600004844521B
S1138080AE07FF94AE00007F5CA300FF23F9AE01AE
S1138090007F5CA305FF23F9AE06007F5CA307FF06
S10B80A023F9CD80A820FE8025
S11380A8AD48AD5CA680B7844A41A602F75A26FCBF
S11380B8B785B6844A61909F42BF8090F6AE00644B
S11380C84272BB0080909F484A6290F7905A90A3EE
S11380D8000126E2A6646241BB85AD2F9FB785B631
S11380E884A004B784A13024C981350452433503DC
S11380F8524235005244350C5245905F5FBF82812D
S113810888A60DAD3DA60AAD3984818890898990E9
S11381185F9097A60A906261BE822702AD1E61AD88
S11381281BA60B896285A101260BA62EA300012795
S113813802A620AD09BF828590858481AB30D70122
S10E8148005C720F5240FBC7524181E3
S113800082008080820080A7820080A7820080A7EF
S1138010820080A7820080A7820080A7820080A7B8
S1138020820080A7820080A7820080A7820080A7A8
S1138030820080A7820080A7820080A7820080A798
S1138040820080A7820080A7820080A7820080A788
S1138050820080A7820080A7820080A7820080A778
S1138060820080A7820080A7820080A7820080A768
S1138070820080A7820080A7820080A7820080A758
S9030000FC

ソースからアセンブルしなくても、このファイルを ST Visual Programmer (STVP) で STM8S Discovery に書き込んでも実行できます。