Interface増刊「すぐに使える!液晶搭載マイコン・モジュール」の付属基板には、デバッグモニタのファームウェアが搭載されています。
本基板(以下S1C17702基板と呼ぶことにします)のデバッグモニタは、統合開発環境のデバッガ(gdb)が、S1C17702基板と通信するためのものです。
デバッグモニタを通じてS1C17702基板と通信することによって、レジスタやメモリを読み書きしたり、ブレークポイントを設定したりします。
S1C17702基板のデバッグモニタは、P/ECEにたとえると、おおよそ、緊急カーネルに相当する役割です。
(P/ECEの緊急カーネルとは、SELECT+下ボタンを押しながらリセットしたときに使われる、復旧用の最小限カーネルのことです。)
P/ECE開発環境には、緊急カーネルのソースも含まれていて、緊急カーネルの内部動作をソースから理解することができました。
一方、S1C17702基板の開発環境には、デバッグモニタのソースが含まれていないようです。
gdbを使わずにS1C17702基板と直接通信できたら、便利そうなので、デバッグモニタの通信プロトコルを調査してみることにしました。
最初、S1C17702基板のフラッシュメモリをダンプして、逆アセンブルして調査しないといけないかな、と考えていました。
でも、実際には、もっと簡単でした。
S1C17702基板の開発環境には、復旧時のセルフバックアップ用実行ファイルが含まれています。(「C:\EPSON\C17WBIF\selfbackup\SimpleGDBServer.elf」)
実はこれが、デバッグモニタの実行ファイルそのもののようです。
SimpleGDBServer.elfには、ソースコードデバッグ用の情報が含まれていて、objdumpで逆アセンブルすると、元のC言語ソースにかなり近い情報が得られます。
たとえば、関数名や引数型、さらに、ローカル変数の名前までわかります。
そんなわけで、ほとんどC言語ソースを読んでいるのに近い感覚で、調査できました。
デバッグモニタを調査した結果を、「S1C17702基板 デバッグモニタ 擬似コード」として、まとめてみました。
C言語っぽいですが、あくまで擬似コードなので、そのままコンパイルすることはできません。
また、通信設定や、コマンドリファレンスを、以下にまとめました。(でも、説明不足なので、擬似コードの方が判り易いかも知れません。(^^;)
S1C17702基板のファームウェアは、大きく分けると、二つの機能が含まれているようです。
ひとつは、上述のデバッグモニタの機能です。
もうひとつは、セルフバックアップのマスタ側の機能です。
後者について説明すると、万一S1C17702基板のファームウェアが壊れて起動しなくなった場合、正常なS1C17702基板をもう一台使って、修復することが可能です。
これを、セルフバックアップ機能と呼びます。(本誌の、p.29〜34に説明されています)
セルフバックアップの実行中、壊れた側は、S1C17702 CPUの機能だけを使って、動作します。
正常な側は、壊れた側のS1C17702 CPUの機能を外部から制御するプログラムを実行して、壊れた側が修復するのをサポートします。
この、「壊れた側のS1C17702 CPUの機能を外部から制御するプログラム」が、セルフバックアップのマスタの機能です。
ちなみに、P/ECEにも似たような修復手順があって、P/ECEラボラトリさんの、「瀕死のP/ECEを救え」のページで説明されています。
P/ECEの場合、セルフバックアップのマスタの機能に相当するプログラムは、独立したアプリケーションプログラムでした。
修復を行うときに、正常な側のP/ECEにロードして、実行する方法をとっていました。
一方、S1C17702基板の場合、セルフバックアップのマスタの機能に相当するプログラムが、ファームウェアの中に書き込まれています。
ようするに、S1C17702基板は、他の壊れたS1C17702基板を修復サポートするプログラムを、常に内蔵しているわけです。
しかし、実際にセルフバックアップを実行することは、滅多に無さそうです。
そこで今回は、セルフバックアップのマスタ機能に相当する部分は、調査しませんでした。
デバッグモニタの機能と、セルフバックアップのマスタ機能は、ほとんど完全に分離しているため、デバッグモニタの調査には支障ありませんでした。
通信ツールを、このように設定してください。下図は、Tera Term Proの設定例です。
注意 :
通信ツールを使って、S1C17702基板のデバッグモニタと、直接、コマンドの送受信を行うことができます。
各コマンドの内容は、S1C17702基板 デバッグモニタ 擬似コードを参照してください。
以下のリファレンスも、あわせて参照してください。
注意 :
書式 : g
コマンド送受信例 :
方向
文字列
説明
送信 $
g
#67
パケットヘッダ
コマンド種別
チェックサム
受信
+
$
00000000
00000000
01000000
04410000
00000000
00000000
00000000
00000000
c00f0000
aa800000
02000000
#5f
(nul)
ACK
パケットヘッダ
%r0 = 0x000000
%r1 = 0x000000
%r2 = 0x000001
%r3 = 0x004104
%r4 = 0x000000
%r5 = 0x000000
%r6 = 0x000000
%r7 = 0x000000
%sp = 0x000fc0
%pc = 0x0080aa
%psr = 0x02
チェックサム
終端
送信
+
ACK
書式 : G(%r0)(%r1)(%r2)(%r3)(%r4)(%r5)(%r6)(%r7)(%sp)(%pc)(%psr)
コマンド送受信例 :
方向
文字列
説明
送信 $
G
45230100
ab896700
01efcd00
67452300
cdab8900
2301ef00
89674500
efcdab00
c02f0000
00000100
1f000000
#90
パケットヘッダ
コマンド種別
%r0 = 0x012345
%r1 = 0x6789ab
%r2 = 0xcdef01
%r3 = 0x234567
%r4 = 0x89abcd
%r5 = 0xef0123
%r6 = 0x456789
%r7 = 0xabcdef
%sp = 0x002fc0
%pc = 0x010000
%psr = 0x1f
チェックサム
受信
+
$
OK
#9a
(nul)
ACK
パケットヘッダ
成功
チェックサム
終端
送信
+
ACK
書式 : m(アドレス),(データ長)
コマンド送受信例 :
方向
文字列
説明
送信 $
m
009000,80
#2a
パケットヘッダ
コマンド種別
アドレス,データ長
チェックサム
受信
+
$
2025413c7d0f20015c3edc3e5c3c0490
02077f982a101b9002097f9826105c3c
dc3c5c3ddf1b383db83c383c10290181
92290041009c8098ed5fe41b0090020e
7f981310183c088090280fb807b887b0
83a02040009d80990940289e5c3eee5f
251804640090010e7f985c3cc51b383c
0464b83e383e20015c40749c5f409c9c
#ba
(nul)
ACK
パケットヘッダ
データ
チェックサム
終端
送信
+
ACK
書式 : M(アドレス),(データ長):(データ)
コマンド送受信例 :
方向
文字列
説明
送信 $
M
001800,40:
00000000111111112222222233333333
44444444555555556666666677777777
8888888899999999aaaaaaaabbbbbbbb
ccccccccddddddddeeeeeeeeffffffff
#50
パケットヘッダ
コマンド種別
アドレス,データ長:
データ
チェックサム
受信
+
$
OK
#9a
(nul)
ACK
パケットヘッダ
成功
チェックサム
終端
送信
+
ACK
書式 : c
コマンド送受信例 :
方向
文字列
説明
送信 $
c
#63
パケットヘッダ
コマンド種別
チェックサム
受信
+
ACK
デバッグブレークが発生したら…
受信
$
S02
#b5
(nul)
パケットヘッダ
SIGINT
チェックサム
終端
送信
+
ACK
書式 : s
コマンド送受信例 :
方向
文字列
説明
送信 $
s
#73
パケットヘッダ
コマンド種別
チェックサム
受信
+
$
S05
#b8
(nul)
ACK
パケットヘッダ
SIGTRAP
チェックサム
終端
送信
+
ACK
書式 : !
コマンド送受信例 :
方向
文字列
説明
送信 $
!
#21
パケットヘッダ
コマンド種別
チェックサム
受信
+
$
S05
#b8
(nul)
ACK
パケットヘッダ
SIGTRAP
チェックサム
終端
送信
+
ACK
備考 : ? と同じです。
書式 : ?
コマンド送受信例 :
方向
文字列
説明
送信 $
?
#3f
パケットヘッダ
コマンド種別
チェックサム
受信
+
$
S05
#b8
(nul)
ACK
パケットヘッダ
SIGTRAP
チェックサム
終端
送信
+
ACK
備考 : ! と同じです。
書式 : L(セクタ番号)
コマンド送受信例 :
方向
文字列
説明
送信 $
L
10
#ad
パケットヘッダ
コマンド種別
セクタ番号
チェックサム
受信
+
$
OK
#9a
(nul)
ACK
パケットヘッダ
成功
チェックサム
終端
送信
+
ACK
書式 : d(任意の文字列)
コマンド送受信例 :
方向
文字列
説明
送信 $
d
Hello, world!
#ed
パケットヘッダ
コマンド種別
任意の文字列
チェックサム
受信
+
$
d
Hello, world!
#ed
(nul)
ACK
パケットヘッダ
エコーバック
チェックサム
終端
送信
+
ACK
コマンド送受信例 :
方向
文字列
説明
送信 $
g
#00
パケットヘッダ
コマンド種別
チェックサム(誤り)
受信
-
NAK
コマンド送受信例 :
方向
文字列
説明
送信 $
a
#61
パケットヘッダ
コマンド種別(誤り)
チェックサム
受信
+
$
#00
(nul)
ACK
パケットヘッダ
チェックサム
終端
送信
+
ACK