お世話になります。
RAMパリティ・エラーの発生について教えていただけるでしょうか。
コンパイラはCC-RLでCS+のコードジェネレータで生成したコードを基本としています。
自前のセクションなどは使用しない場合で,RAMパリティ・エラーが発生することはあり得るでしょうか。
また,cstart.asm 内の _start 直後のコードで,_stkinitがコメントアウトされていますが,スタック領域は初期化しなくても
大丈夫なのでしょうか。
;-------------------------------------------------- ; initializing stack area ;--------------------------------------------------;$IF (__RENESAS_VERSION__ >= 0x01010000); MOVW AX,#LOWW(__STACK_ADDR_END);$ELSE ; for CC-RL V1.00; MOVW AX,#LOWW(_stackend);$ENDIF; CALL !!_stkinit <--- ここです。 ;-------------------------------------------------- ; hardware initialization ;-------------------------------------------------- CALL !!_hdwinit
度々の質問で恐縮ですが,ご教授頂けますようお願いいたします。
スタック領域は通常初期化しなくても問題ありませんが、スタックに割付られた未初期化のローカル変数を参照するとパリティエラーが発生する可能性はありますね。
fujita nozomu様
ご回答ありがとうございます。
パリティエラーが発生する可能性があるんですね。本来なら未初期化のローカル変数を参照する事態は
ないはずなので,stkinit 関数はコメントされていても問題ないと言うことなんでしょうか。
実は現在ROM化状態で,この状況に直面しているんですが,未初期化のローカル変数を参照してしまって
いるところがあるという前提でコードを見直してみます。
いつもいつも,的確なご回答ありがとうございます。本当に助かります。
あと以前に CC-RL ではなくて GCC でのことですが、構造体の各メンバは初期化されていたものの構造体中のギャップ部分が未初期化だったために、構造体全体を memcpy() するとパリティエラーが生じるという報告がありました。
GR-KURUMIでメモリの読み込みで再起動
http://japan.renesasrulz.com/gr_user_forum_japanese/f/110/p/2331/9991.aspx
コンパイラが異なるので同じ現象が生ずるがわかりませんがご確認されることをお勧めします。
貴重な情報をありがとうございます。
構造体を多用していますので今一度確認してみたいと思います。ギャップ部分が生じる場合,
意図的にダミーの変数を入れて埋めてしまうのが良いのかもしれないですね。
CC-RLでは,構造体の複数バイト変数が偶数アドレスに配置されないとの情報を見た気もするのですが
そのあたりも含めつつ調査してみます。ありがとうございました。
RAMパリティ・エラーの発生について
CPUの動作ですから、コンパイラの問題ではないと思います。
RL78/G13
ユーザーズマニュアル ハードウェア編
R01UH0146JJ0320 Rev.3.20 2014.07.14 857ページ RAMパリティ・エラー検出機能 の
注意 データ書き込み時にパリティが書き込まれ,データ読み出し時にパリティをチェックします。 そのため,RAMパリティ・エラー・リセット発生を許可する(RPERDIS = 0)場合,データ・ア クセス時は「使用するRAM領域」をデータ読み出し前に必ず初期化してください。 また,RL78はパイプライン動作のためCPUが先読みを行い,使用しているRAM領域の先にある初 期化されていないRAM領域を読み込むことで,RAMパリティ・エラーが発生する場合があります。 したがって,RAMパリティ・エラー・リセット発生を許可する(RPERDIS = 0)場合,RAM領域 からの命令実行時は「使用するRAM領域+10バイト」の領域を必ず初期化してください
スタックエリアはcallされてまず戻りアドレス等が書き込まれてから、retで読みだされる順番だから良しとされているようです。callされずにretが行われるならば、errorが運悪く発生するでしょう。(実行アドレスメモリ外)
C言語で未初期化変数は、0が読める仕様で使用するならハードイニシャライズでまずRAMをすべて0クリアしておいてパリティをすべてつけておいてから、ROM化のソフトイニシャライズで再度初期化してもよいのではないでしょうか?
どちらにしてもCPUの安全機能を使用するならば、マニュアルに記述されていることは、確実に行っておくべきだと思います。
kcd様
ご指摘ありがとうございます。その通りだと思います。現在,CS+のコードジェネレータで作成したプログラムで
RAM初期化もやっているのですが,I2C通信の関連でRAMパリティ・エラーが発生してしまい,スタック関連を気に
している次第です。意図的なケースは別として,ローカル変数が書かれる前に参照されるならコンパイラが警告して
くれますし,なんだろうなと調査中です。もう少しがんばってみます。ありがとうございました。
>ハードイニシャライズでまずRAMをすべて0クリアしておいてパリティをすべてつけておいてから
デフォルトのCS+のコードジェネレータで作成したプログラムだとたぶんsp=fe20hで CALL !!_hdwinitを呼び出しているはずですから、hdwinitプログラムで、使用しているCPUのRAMの先頭からspが示している番地までのRAMクリアを行っていますか?(far callとauto変数分スタックが消費され呼ばれた中では、spはfe18ぐらいになっていると思います)これにあとRB0を除くsadderエリアfe20h~fef7hのクリアこれで全RAMクリアとなります。
RL78はK0と違い命令での(アセンブラレベルで)ポインタアクセス機能が強化されているため、関数が使用するauto変数(C言語のワークエリア)を、saddrではなくスタックで賄っているようです。
情報ありがとうございます。見てみたところ,sp=fe20hでhdwinitを呼び出し,その後,bssとsbssセクションを0でクリアや
初期値付変数の初期化が続きmainをコールしていました。使用しているRAMはすべてクリアないし初期化されているようですが,
スタック領域はクリアされていないようです。
今RAM・パリティエラーが発生しているのは,コードジェネレータが作成したIIC関連の関数なんです。
ROM化した場合にのみ発生しています。以下の関数です。オシロでチェックするためにP16を変化させるコード①②を
追加しています。正常時はP16がH→Lとなりますが,パリティエラーが発生する時は,Hになってすぐにリセットがかかり
ポートが入力状態になります。
引数の変数 wait を念のため逆アセンブルで見てみましたが,一旦スタックに書き込んでからデクリメントしていました。
エラーが発生する時はかならずこの関数なんですが何が原因なのか,奮闘中です。
------------------------------------------------------------------------------------------------------------------------------------
MD_STATUS R_IICA0_Master_Receive(uint8_t adr, uint8_t * const rx_buf, uint16_t rx_num, uint8_t wait)
{
MD_STATUS status = MD_OK;
P1_bit.no6 = 1; // ・・・①
IICAMK0 = 1U; /* disable INTIIA0 interrupt */
STT0 = 1U; /* set IICA0 start condition */
IICAMK0 = 0U; /* enable INTIIA0 interrupt */
/* Wait */
while (wait--)
;
}
if (0U == STD0)
status = MD_ERROR3;
else
/* Set parameter */
g_iica0_rx_len = rx_num;
g_iica0_rx_cnt = 0U;
gp_iica0_rx_address = rx_buf;
g_iica0_master_status_flag = _00_IICA_MASTER_FLAG_CLEAR;
adr |= 0x01U; /* set receive mode */
IICA0 = adr; /* receive address */
P1_bit.no6 = 0; // ・・・②
return (status);
ackさん、横レス失礼します。
全く論理的ではありませんが、②の位置を一行ずつ上に(逆に①の直下から一行ずつ下に)移動し、オシロでH→Lになる/ならない、の変曲点をサーチすれば、トリガコードに辿り着くと思います。ROM化が面倒ですが...
チョコです。
このプログラムで読み出しているのは、スタックで渡された引数だけのようです。
もしかすると、呼び出し元では8ビットで設定しているだけなのに、参照時に16ビットで
読み出している可能性(実際には8ビットしか使っていない)があります。
そうなると、最初のPOSTに有ったスタック領域の初期化を有効にすれば解決する可能性が
あります。
ビシ様,チョコ様
アドバイスありがとうございます。
ビシ様の仰る通り②を上にずらしていったところ,while (wait--)の直前の場合は,きれいにH→Lとなっており,
その後リセットしていましたので,wait変数が鍵となりそうです。
逆アセンブルで,この関数の引数を見てみましたが,8bitデータは8bitでアクセスしているように見えましたが,
チョコ様からご指摘頂いた通りスタック領域の初期化を有効にしたところ症状がでなくなりました。
場所は特定できないのですが,チョコ様の言われた「参照時に16ビットで読み出している可能性(実際には8ビット
しか使っていない)」が,論理的な気がいたします。
スタックを初期化するのも気持ちがいいので,これで行きたいと思います。
皆様の的確なアドバイス,本当にありがとうございました。