C8051のプログラム上の注意

研究・設計 数理設計研究所 矢澤
yazawa@mail.wind.ne.jp

SINCE 2003/9/16

LAST UP DATE 2003/10/7

概要

 C8051F005において、CPUのバグと思われる現象を発見しました。
 このバグは、レジスタバンク切替とレジスタバンクの操作に関連するものです。

サンプルプログラム

 このプログラムはC8051F005を搭載した評価用キットC8051005DK-J上で動作する試験プログラムです。
 かならずled_on:が実行されるよう記述してあります。led_blink:が実行されることはありません。
 しかし、プログラムを実機で動作させるとled_onではなくled_blinkを実行します。
 Cygnal IDE Ver1.85のJTAGデバッガによるステップ/トレース実行時にはled_onを実行します。
 プログラムの動作を追跡した結果、17行目の実行時に直前のレジスタバンク変更が反映されていないことが判りました。
  ラベル アセンブラコード コメント ステップ実行時 実機動作時
a R0 00h 08h a R0 00h 08h
定義 1   XBR2 DATA 0E3H デジタルクロスバ設定レジスタ    
2    WDTCN DATA 0FFH WDT設定レジスタ
3    PRT1CF DATA 0A5H Port 1入出力方向設定レジスタ
4    P1 DATA 090H Port 1レジスタ
5    PSW DATA 0D0H Program Status Word
初期設定 6   code at 0000h リセットベクタ 0h
7 start: mov XBR2, #40h クロスバ初期設定
8    orl PRT1CF,#01000000b P1.6を出力に設定
9    setb P1.6 LED点燈
10    mov WDTCN, #0DEh WDT禁止の標準手順
11    mov WDTCN, #0ADh
主処理 12 mov psw,#00h レジスタバンク = 0 - - - - - - - -
13    clr, a a = 0h 00 - - - 00 - - -
14    mov r0,#55h R0 = 55h 00 55 55 - 00 55 55 -
15    mov psw,#08h レジスタバンク = 1 00 55 55 - 00 55 55 -
16    mov psw,#00h レジスタバンク = 0 00 55 55 - 00 55 55 -
17    mov r0, a R0 = A 00 00 00 - 00 55 55 00
判定 18    mov a,r0 a = R0 00 00 00 - 55 55 55 00
19   jz led_on if(a == 0)jmp led_on 00 00 00 - 55 55 55 00
終端処理 20 led_blink: djnz R5, led_blink LED点滅   点滅
21   djnz R6, led_blink
22   cpl P1.6
23   jmp led_blink
24 led_on: jmp led_on LED点燈 点燈  
  25   END      
  • 00h はレジスタバンク0のR0
  • 08h はレジスタバンク1のR0
  • 14行目でAレジスタに保存する値は0以外であれば良く、「55」でなくてもよい

レジスタバンク変更のタイミング


 17行と18行の間にmov Rn,a命令を挿入して実験した結果、2回目のmov Rn,a命令ではレジスタバンク変更が反映されていることを確認しました。

  アセンブラコード コメント ステップ実行時 実機動作時
a R0 00h 08h a R0 00h 08h
主処理 12 mov psw,#00h レジスタバンク = 0 - - - - - - - -
13 clr, a a = 0h 00 - - - 00 - - -
14 mov r0,#55h R0 = 55h 00 55 55 - 00 55 55 -
15 mov psw,#08h レジスタバンク = 1 00 55 55 - 00 55 55 -
16 mov psw,#00h レジスタバンク = 0 00 55 55 - 00 55 55 -
17 mov r0, a R0 = A 00 00 00 - 00 55 55 00
mov r0, a R0 = A 00 00 00 - 00 00 00 00
判定 18 mov a,r0 00 00 00 - 00 00 00 00
19 jz led_on if(a == 0)jmp led_on 00 00 00 - 00 00 00 00

 さらに16行と17行の間にnopを挿入して実験した結果、プログラムが記述通りに実行することを確認しました。
  アセンブラコード コメント ステップ実行時 実機動作時
a R0 00h 08h a R0 00h 08h
主処理 12 mov psw,#00h レジスタバンク = 0 - - - - - - - -
13 clr, a a = 0h 00 - - - 00 - - -
14 mov r0,#55h R0 = 55h 00 55 55 - 00 55 55 -
15 mov psw,#08h レジスタバンク = 1 00 55 55 - 00 55 55 -
16 mov psw,#00h レジスタバンク = 0 00 55 55 - 00 55 55 -
nop   00 00 00 - 00 00 00 -
17 mov r0, a R0 = A 00 00 00 - 00 00 00 -
判定 18 mov a,r0 00 00 00 - 00 00 00 -
19 jz led_on if(a == 0)jmp led_on 00 00 00 - 00 00 00 -

 この2点から、レジスタバンクの変更がmov Rn,a命令の実行に反映されるまでに、レジスタバンク変更後1命令以上経過した後であることを確認しました。。

バンク切替の試験


 特定のレジスタバンク特有の問題であるかどうかを確認するために、初期レジスタバンクと一時変更先レジスタバンクのすべての組み合わせ(4バンク×4バンク=16通り)を試験した結果、以下のことを確認しました。
  • どのバンクからどのバンクへの変更でも構わない。
  • 同一バンクへの変更ではいけない(それは変更ではない)

Rnレジスタの試験


 特定のRnレジスタの問題であるかどうかを確認するために、14行と17行のRnをR0〜R7に設定して試験した結果、特定のRnレジスタ特有の問題ではないことを確認しました。
 なお、初期レジスタバンク0で試験を実施しました。他のレジスタバンクでは未試験です。

レジスタバンク参照命令の試験


 すくなくともレジスタバンク変更直後のmov Rn,a命令実行時にはレジスタバンク変更の効果が得られないことがわかっているが、その他のレジスタバンクを参照する命令が正常に動作するかどうかを確認した。
 C8051ではレジスタバンクを参照する命令は以下に示す31命令であり、

17行の実行時に直前のレジスタバンク変更が反映されない条件として、以下を確認ました。
  • mov Rn,a命令であること。
    • mov R0,a で無くてもよい。
  • 17行でレジスタバンクを変更すること
    • どのバンクからどのバンクへの変更でも構わない。
    • 同一バンクへの変更ではいけない
    • 16行と17行の間にnopがあってはいけない
分類 ニーモニック オペランド 機能 結果
算術演算 1 ADD A,Rn A ← A + Rn
2 ADD @Ri A ← A + (Ri)
3 ADDC A,Rn A ← A + Rn + Carry
4 ADDC @Ri A ← A + (Ri) + Carry
5 SUBB A,Rn A ← A - Rn - Borrw
6 SUBB @Ri A ← A - (Ri) - Borrow
7 INC Rn Rn ← Rn + 1
8 INC @Ri (Ri) ← (Ri) + 1
9 DEC Rn Rn ← Rn - 1
10 DEC @Ri (Ri) ← (Ri) - 1
論理演算 11 ANL A,Rn A ← A .OR. Rn
12 ANL @Ri A ← A .OR. @Ri
13 ORL @Ri A ← A OR @Ri
14 XRL A,Rn A ← A .XOR. Rn
15 XRL @Ri A ← A .XOR. @Ri
データ転送 16 MOV A,Rn A ← Rn OK
17 MOV A,@Ri A ← @Ri
18 MOV Rn,A Rn ← A NG
19 MOV Rn,direct Rn ← (direct)
20 MOV Rn,#data Rn ← data
21 MOV direct,Rn (direct) ← Rn
22 MOV direct,@Ri (direct) ← @Ri
23 MOV @Ri,A Ri ← A
24 MOV @Ri,direct Ri ← (direct)
25 MOV @ri,#data Ri ← data
26 MOVX A,@Ri A ← Ri
27 MOVX @Ri,A Ri ← A
28 XCH A,Rn A xch Rn
29 XCH A,direct A xch (direct)
30 XCH A,@Ri A xch Ri
プログラム分岐 31 DJNZ Rn,rel DEC Rn, Jump if (Rn <> 0)

考察