部 内 向 けスキルアップ 研 修 組 込 みOS 自 作 入 門 2013 年 8 月 4thステップ 担 当 : 中 村
目 次 はじめに ブート ローダー シリアル 経 由 でのファイル 転 送 XMODEMを 実 装 する(もくもく 会 ) アセンブラ プログラミング
はじめに 前 回 やったこと ROM RAM 自 動 変 数 静 的 変 数 データ 領 域 に 関 する 学 習 今 回 やること ブート ローダー XMODEMプロトコル アセンブラ プログラミング
4.1 ブート ローダー 4.1.1 ブート ローダーの 必 要 性 これまでは 作 成 したプログラムをフラッシュ ROMへ 書 き 込 んでROM 上 で 実 行 してきたが 実 はROMは 書 き 込 み 回 数 に 上 限 がある メーカー 保 証 は100 回 程 度 ( 通 常 利 用 の 範 囲 ならば1000 回 程 度 ) 電 源 OFFしても 消 えないので 電 源 ONと 同 時 に 起 動 するOSが 作 成 できるが 短 所 がある
4.1.1 ブートローダの 必 要 性 そこで OSの 実 行 形 式 ファイルを 直 接 フラッ シュROMに 書 き 込 む 代 わりに OSの 実 行 形 式 ファイルをシリアル 経 由 でダウンロードし そ れをRAM 上 に 展 開 して 起 動 するプログラムを フラッシュROMに 書 き 込 む ブート ローダー(boot loader) ブート ストラップ(bootstrap) 電 源 ONでブート ローダーを 起 動 し ブー ト ローダーでOSをダウンロードしてRAM 上 でOSを 展 開 し 起 動 するという2 段 構 成
4.1.1 ブートローダの 必 要 性 良 いところ 気 軽 にOSのダウンロードが 繰 り 返 せる 効 率 よく 開 発 をすすめることができる 悪 いところ RAMは 電 源 OFFにすると 内 容 が 消 えるので 起 動 の 度 にOSをダウンロードしなければなら ない
4.1.1 ブートローダの 必 要 性 ROM 化 開 発 中 はブートローダーを 利 用 してRAM 上 に 展 開 して 起 動 し 製 品 化 の 段 階 でフラッシュ ROMに 書 き 込 んでROM 上 から 起 動 する 今 回 はOSのROM 化 まではやらない OSをダウンロードしてRAM 上 で 展 開 し 起 動 す るブート ローダーを 作 成 する
4.2 シリアル 経 由 でのファイル 転 送 ブート ローダーの 機 能 シリアル 経 由 でOSの 実 行 形 式 ファイルをダウ ンロードし RAM 上 に 一 旦 保 存 保 存 した 実 行 形 式 ファイルを RAM 上 に 展 開 RAM 上 に 展 開 したOSを 実 行 シリアル 通 信 には XMODEMプロトコルを 使 用 する
4.2.1 XMODEMプロトコル 仕 様 送 信 側 1. 受 信 側 から 定 期 的 に 送 信 されるNAKを 受 け たら 送 信 を 開 始 する 2. ブロック 単 位 でデータ 送 信 3. ACKが 返 ってきたら 次 を 送 信 NAKが 返 っ てきたら 再 送 4. データ 終 わりはEOTを 送 信 し ACKが 返 っ てきたら 終 了 5. 中 断 したい 場 合 はCANを 送 信 し CANを 受 信 したら 中 断
4.2.1 XMODEMプロトコル 仕 様 受 信 側 1. 準 備 ができたらNAKを 送 信 し 受 信 開 始 2. SOHを 受 けたら ブロックとして 受 信 成 功 したらACKを 返 し 失 敗 したらNAKを 返 す 3. EOTを 受 けたらACKを 返 して 終 了 4. 中 断 したい 場 合 はCANを 送 信 し CANを 受 信 したら 中 断
4.2.1 XMODEMプロトコル 仕 様 フィールド サイズ 意 味 a 1バイト SOH (Start Of Header) b 1バイト ブロック 番 号 c 1バイト チェック ブロック 番 号 を 反 転 d 128バイト データ 部 空 きはEOFで 埋 める e 1バイト データ 部 のチェックサム データ 部 を256で 割 った 余 り a b c d e XMODEMのブロック フォーマット
4.2.1 XMODEMプロトコル 仕 様 ACK(ACKnowledge) 受 信 成 功 時 の 応 答 として 送 信 されるコード NAK(NegativeAcKnowledge) エラー 時 の 応 答 として 送 信 されるコード
XMODEMデータフロー 概 略 図 受 信 側 送 信 側 NAK ( 送 信 開 始 を 要 求 ) SOH (ブロック 開 始 ) 01 (ブロック 番 号 ) FE (ブロック 番 号 を 反 転 させたもの) ( 実 際 のデータ 128 バイト) sum (チェックサム) ACK SOH (ブロック 開 始 ) 02 (ブロック 番 号 ) FD (ブロック 番 号 を 反 転 させたもの) ( 上 記 手 順 を データがなくなるまで 繰 り 返 す) EOT ( 転 送 終 了 ) ACK
4.3 XMODEMを 実 装 する もくもく 会 今 回 追 加 するファイル xmodem.h, xmodem.c 今 回 修 正 するファイル main.c コマンド 動 作 を 実 装 ld.scr バッファ 領 域 を 追 加 serial.h,serial.c 文 字 の 受 信 を 実 装 lib.h, lib.c ライブラリ 関 数 を 追 加 Makefile
4.3 XMODEMを 実 装 する 手 順 1. 前 回 のフォルダ 3.2 をコピーして 4.1 を 作 成 2. ファイルの 追 加 修 正 3. make make image 4. ディップスイッチを 書 き 込 みモード (1,1,0,1)に 設 定 後 make write 5. Tera termを 起 動 して ディップスイッチを 実 行 モード(1,0,1,0)に 設 定 後 電 源 ON 6. リセットボタンを 押 すとプロンプト kzload > が 出 るので load を 入 力
4.3 XMODEMを 実 装 する 手 順 6.リセットボタンを 押 すとプロンプト kzload > が 出 るので load を 入 力 7. 直 ちに メニューから ファイル- 転 送 - XMODEM- 送 信 を 選 択 する ファイル 選 択 ウィンドウが 開 くので とりあえず defines.h を 転 送 してみる 8. 間 に 合 わなかった 場 合 は 再 度 リセットボタ ンを 押 してやり 直 す 9. 完 了 したら dumpコマンドを 使 って 転 送 し たファイルを 確 認
4.3 XMODEMを 実 装 する 手 順 10. cygwinで 転 送 元 ファイルを 表 示 し 転 送 し たファイルを 比 較 $ hexdump c defines.h 11. 転 送 データはブロック 単 位 で 送 信 されるた め 受 信 したファイルは 余 った 部 分 が0x1aで 埋 められている 事 を 確 認 して 下 さい (XMODEMの 仕 様 気 にしない!)
アセンブラ プログラミング OSを 自 作 する 場 合 アセンブラ(assembler) の 知 識 は 必 須 スタート アップ 割 り 込 みの 入 口 と と 出 口 スレッドのディスパッチ の3 箇 所 はアセンブラでないと 書 けない! とりあえず 処 理 の 目 的 を 意 識 して 内 容 にアタリをつけて 読 むと 理 解 しやすい ( 全 部 命 令 を 覚 える 必 要 はない)
4.5.1 スタック C 言 語 でプログラムを 書 くとき すべての 変 数 を 静 的 変 数 にするのはムダ 常 時 メモリを 占 有 し 続 けるのはムダ 関 数 に 入 った 時 のみ 獲 得 され returnによっ て 関 数 から 抜 けるときには 捨 てられ メモリ 領 域 が 使 いまわせる 自 動 変 数 が 必 要
4.5.1 スタック 効 率 よくメモリを 利 用 する 手 順 1. ある 程 度 の 容 量 の 領 域 を 予 め 確 保 2. 現 在 領 域 のどこまでを 利 用 しているかを 示 す ポインタを 用 意 3. 関 数 呼 び 出 しにより 自 動 変 数 のための 領 域 が 必 要 になった 場 合 には 必 要 分 だけポインタをず らす 4. さらに 関 数 呼 び 出 しされた 場 合 には 更 にポイ ンタを 必 要 分 だけずらす 5. 関 数 から 戻 るときには ポインタを 戻 す
4.5.1 スタック スタックを 管 理 するために 利 用 されるポイ ンタをスタック ポインタ 関 数 単 位 でスタック 上 に 確 保 される 領 域 を スタック フレーム
4.5.2 アセンブラ CPUはメモリ 上 にある 機 械 語 命 令 を 逐 次 実 行 して いく しかしメモリ 上 には 数 値 しか 保 存 できない したがって 機 械 語 命 令 とは 数 値 のことで 数 値 が 命 令 としての 意 味 を 持 っている
4.5.3 CPUのレジスタ レジスタとは CPU 内 部 にある 記 憶 領 域 のこと CPUは 加 算 や 減 算 などの 数 値 計 算 を 行 うための 回 路 を 持 っているが これらの 回 路 の 入 力 や 出 力 は レジスタに 接 続 CPU(RISC)は メモリ 上 の 値 を 直 接 操 作 できず CPU 上 のレジスタに 読 み 込 んでから 処 理
4.5.3 CPUのレジスタ c = a + b の 演 算 の 場 合 1. 変 数 aが 配 置 されている 位 置 のメモリの 値 を レジスタ 1に 読 み 込 む 2. 変 数 bが 配 置 されている 位 置 のメモリの 値 を レジスタ 2に 読 み 込 む 3. レジスタ1とレジスタ2を 加 算 し 結 果 をレジスタ3に 格 納 する 4. レジスタ3の 値 を 変 数 cが 配 置 されている 位 置 のメモ リに 書 き 込 む
4.5.3 CPUのレジスタ メモリ 上 の 値 をレジスタに 読 み 込 むことをロード レジスタの 値 をメモリ 上 に 書 き 込 むことをストア メモリ 上 のデータのロードやストア 演 算 など 汎 用 的 に 利 用 されるレジスタを 汎 用 レジスタと 呼 ぶ
4.5.4 プログラム カウンタ(PC) 汎 用 レジスタとは 別 の 重 要 なレジスタで プロ グラム カウンタ(program counter) がある CPUが 現 在 実 行 中 の 命 令 アドレスを 指 す ( 正 確 には 次 の 命 令 のアドレス) CPUはPCを 加 算 しつつPCの 指 すメモリ 先 の 命 令 を 逐 次 実 行 しながら 処 理 を 進 めていく PCは 次 の 命 令 を 指 す 位 置 まで 自 動 で 加 算 される PCの 役 割 は いわゆるジャンプ 命 令 (C 言 語 でいうところのgoto)
4.5.5 ニーモニックとアセンブラ オペコードとオペランド アセンブリの 命 令 を 表 す 部 分 をオペコードと 呼 ぶ 命 令 に 対 する 引 数 に 相 当 する 部 分 をオペランドと 呼 ぶ 機 械 語 を 数 値 で 表 すのは 人 間 には 読 みづらいので 適 当 な 単 語 を 使 って 人 間 がわかりやすいようにしたのがニー モニック c = a + b の 機 械 語 プログラム 例 01 01 80 00 1 番 レジスタに 変 数 a(アドレス:0x8000)の 値 をロード 01 02 80 04 2 番 レジスタに 変 数 a(アドレス:0x8004)の 値 をロード 03 03 01 02 1 番 レジスタと2 番 レジスタを 加 算 し3 番 レジスタに 格 納 02 03 80 10 3 番 レジスタの 値 を 変 数 c(アドレス:0x8010)にストア
4.5.5 ニーモニックとアセンブラ ニーモニック 0x01は ロード を 行 う 機 械 語 命 令 なので ld 0x02は ストア を 行 う 機 械 語 命 令 なので st 0x03は 加 算 を 行 う 機 械 語 命 令 なので add 以 上 のように 定 義 した 場 合 の c = a + b の 機 械 語 プ ログラムのニーモニック 表 記 ld r1, 0x8000 1 番 レジスタに 変 数 a(アドレス:0x8000)の 値 をロード ld r2, 0x8004 2 番 レジスタに 変 数 a(アドレス:0x8004)の 値 をロード add r3, r1, r2 1 番 レジスタと2 番 レジスタを 加 算 し3 番 レジスタに 格 納 st r3,0x8010 3 番 レジスタの 値 を 変 数 c(アドレス:0x8010)にストア
4.5.5 ニーモニックとアセンブラ インストラクション 機 械 語 の 命 令 はインストラクションとも 呼 ばれる どの 数 値 がどの 命 令 として 動 作 するかという 決 まりを 命 令 セット インストラクション セット と 呼 ぶ 命 令 セットはCPUごとに 違 う (H8の 命 令 セットとPentium 系 の 命 令 セットは 異 なる)
4.5.5 ニーモニックとアセンブラ アセンブリ 言 語 アセンブル ニーモニックで 表 した 機 械 語 プログラム 表 記 をアセンブ リ 言 語 という アセンブリ 言 語 で 書 いたコードを 機 械 語 コードに 変 換 す る 作 業 をアセンブルという アセンブル 変 換 するプログラムをアセンブラと 呼 ぶ 機 械 語 コードをアセンブラに 逆 変 換 することを 逆 アセン ブルと 呼 ぶ
4.5.6 H8のアセンブラ 実 際 にアセンブラを 読 んでみよう 方 法 はいくつかあるが 今 回 は 最 後 に 生 成 された 実 行 形 式 ファイルを 逆 アセンブルしたものを 確 認 する 手 順 先 程 作 成 したフォルダ 4.1 をコピーして 4.2 フォルダを 作 成 lib.cファイルに 関 数 を 追 記 (P.155 リスト4.13) main.cに 関 数 呼 び 出 しを 追 記 (P.155 リスト4.14) make を 実 行 Cygwinで 以 下 のコマンドを 実 行 $ /usr/local/h8300-elf/bin/objdump d kzload.elf
逆 アセンブルの 結 果 0000010c <_main>: main 関 数 の 先 頭 000004f8 <_func>: func() 関 数 の 先 頭 00000162 jsr @0x4f8:24 func()の 呼 び 出 し 箇 所 だろうと 想 像 できる ニーモニックの 細 かい 文 法 は 気 にせず 想 像 で 読 んでいくことがコツ
逆 アセンブルの 結 果 0000015a: mov.w #0x2, r1 r1レジスタに2を 代 入 0000015e: mov.w #0x1, r0 r0レジスタに1を 代 入 H8はR0~R7という16ビットレジスタを8 個 持 っ ている 拡 張 レジスタとしてE0~E7という16 ビットレジスタがあり これらを 組 み 合 わせて ER0~ER7という32ビットレジスタとして 利 用 することができる(long 型 整 数 やポインタ)
main() 関 数 部 79 01 00 02 mov.w #0x2, r1 79 はオペコード 後 ろ3バイトがオペランドで 1バイト 目 は 値 の 格 納 先 レジスタ 後 は 代 入 値 R1に0x0002という 値 を 代 入 ビッグ エンディアンとリトル エンディアン 0x0002 を 格 納 するとき ビッグ エンディアン は 0x00 0x02 リトル エンディアンは 0x02 0x00 とひっくり 返 して 格 納 する CPUによって 異 なり H8はビッグ エンディアン Pentium 系 CPUはリトル エンディアン 近 年 の 多 く はビッグ エンディアン
main() 関 数 部 イミディエイト 値 ( 即 値 ) オペランドにレジスタに 代 入 する 0x0002 という 値 が そのまま 記 述 命 令 内 に 直 接 記 述 される 数 値
mov.l er6, @-er7 func() 関 数 部 H8ではER7がスタック ポインタとして 利 用 される スタック ポインタを 減 算 してスタック4バイト 領 域 を 確 保 してスタック ポインタの 指 す 先 にER6の 値 を 格 納 (ストア)する ER6が 上 書 きされてしまうので ER6の 値 ( 内 容 )を スタックに 退 避 している スタックを 獲 得 するのにER7の 値 を 減 算 している ア ドレス 値 が 少 なくなる 方 向 に 伸 びること( 下 方 伸 長 ) @er7 レジスタの 値 をアドレス 値 として アドレ スが 指 す 先 のメモリの 意 味 (レジスタ 間 接 ) メモリ 参 照 の 方 法 をアドレッシング モード
func() 関 数 部 アドレッシング モード H8は8 種 類 のアドレッシング モードを 持 つ No アドレッシングモード 記 号 (1) レジスタ 直 接 Rn (2) レジスタ 間 接 @ERn (3) ディスプレースメント 付 きレジスタ 間 接 @(d:16, ERn)/@ (d:24, ERn) (4) ポストインクリメントレジスタ 間 接 @ERn+ プリデクリメントレジスタ 間 接 @-ERn (5) 絶 対 アドレス @aa:8/@aa:16/@aa:24 (6) イミディエイト #xx:8/#xx:16/#xx:32 (7) プログラムカウンタ 相 対 @(d:8,pc) /@(d:16, PC) (8) メモリ 間 接 @@aa:8
func() 関 数 部 アドレッシング モード @-er7 レジスタの 加 減 算 とメモリ アクセスを1 命 令 で 同 時 に 行 う スタック 操 作 に2 命 令 が 利 用 されると その 命 令 の 間 で 割 り 込 みが 入 りスタック 操 作 された 時 に スタック の 整 合 性 が 取 れなく 可 能 性 がある スタック 操 作 は1 命 令 で 行 える 必 要 がある
mov.l er7,er6 func() 関 数 部 スタック ポインタであるER7の 値 をER6にコピーし ている ER6はフレーム ポインタと 呼 ばれる 使 われ 方 をして おり スタック フレームの 先 頭 を 指 している ER6もER7も ポインタとして 利 用 されるため アド レスを 保 持 する 必 要 があるので 32ビットレジスタ が 利 用 される
subs #4, er7 func() 関 数 部 スタック ポインタであるER7をさらに4バイトだけ 減 算 して 4バイトの 領 域 を 確 保 func()の 内 部 で 利 用 している 自 然 変 数 c の 領 域 #4 の4は 定 数 値 を 表 すイミディエイト 値 ( 即 値 )
add.w r1,r0 func() 関 数 部 R0とR1の 値 を 加 算 して R0に 代 入 a +b の 処 理 (1 + 2)をしている mov.w r0, @(0xfffe:16, er6) 加 算 結 果 はR0に 格 納 されているが 自 動 変 数 c はスタック 上 に 存 在 フレーム ポインタを 減 算 してアドレスを 計 算 して そこに 加 算 結 果 を 代 入
func() 関 数 部 mov.w @(0xfffe:16, er6), r0 スタック 上 に 格 納 されている 変 数 c の 値 をr0に 代 入 することでモリチの 準 備 をし R0を 関 数 の 戻 り 値 とする 元 々 R0に c の 値 が 入 っていたからムダな 処 理 c をvolatile 定 義 したため 最 適 化 処 理 が 行 われ ていない 加 算 して 結 果 をスタックに 保 存 して 戻 り 値 を 準 備 する という 一 連 の 処 理 が 最 適 化 されていない
adds #4, er7 func() 関 数 部 スタック ポインタを4バイト 加 算 することで 自 動 変 数 c の 為 に 確 保 していたスタックを 開 放 mov.l @er7+, er6 スタック 上 に 対 比 されていたER6の 値 をER6に 読 み 込 んで(ロード) ER6を 元 に 戻 す ロード 後 にスタック ポインタであるER7は4バイト 加 算 rts スタック 上 から 戻 り 先 アドレスを 取 得 し ジャンプし て 関 数 の 呼 び 出 し 元 に 戻 る
4.5.7 役 割 の 決 まっているレジスタ 関 数 の 呼 び 出 しは jsr 関 数 からの 復 帰 は rts jsrを 実 行 すると スタック ポインタである ER7の 指 す 先 にプログラム カウンタの 値 を 保 存 してから プログラム カウンタを 書 き 換 え てジャンプ rtsを 実 行 すると ER7の 指 す 先 の 値 をプログラ ム カウンタに 代 入 して 呼 び 出 し 元 に 戻 る ER7は jsrやrtsを 実 行 すると 自 動 的 に 利 用 され 値 も 変 更 される ER7は CPUがスタック ポインタとして 明 示 的 に 操 作 しているレジスタ
4.5.8 スタート アップ startup.sのソースコード _start: mov.l #_stack,sp jsr @_main _start はラベル(label)と 呼 ばれ アセン ブラ 内 でラベルが 利 用 されると 定 義 されてい る 位 置 のアドレスに 置 き 換 わる
4.5.8 スタート アップ スタート アップで 行 うべきことは スタッ ク ポインタの 初 期 値 設 定 スタック ポインタを 適 切 に 設 定 してから 出 な いと C 言 語 の 関 数 呼 び 出 しを 正 常 に 行 う 事 がで きない jsrでメイン 関 数 を 呼 び 出 しているので その 前 に mov.l でスタック ポインタを 設 定 _stack のアドレス 値 をspに 代 入 しているが spはer7ど 同 義 で stack pointer のこと
4.5.8 スタート アップ bra は 戻 り 先 アドレスをスタックに 保 存 しな い 単 純 なジャンプ 1: bra 1b 1b というラベルはない 1bが 書 かれた 箇 所 より 前 で 1: という 記 述 がある 最 も 近 い 物 を 指 す main()の 呼 び 出 しから 戻 ってきた 時 に 暴 走 しな いようにとりあえず 無 限 ループをおいて 実 行 がそれ 以 上 進 まないようにしている
今 日 やったこと XMODEMによるファイル 転 送 ができるように なった ブート ローダーから 起 動 できるまで あと 少 し! アセンブラに 関 する 学 習 アセンブラはアタリをつけて 読 む スタックの 確 保 レジスタの 退 避 自 動 変 数 の 作 成 レジスタの 復 旧 とスタックの 開 放 戻 り 先 へのジャン プ
次 回 の 開 催 予 定 日 時 9 月 10 日 ( 火 ) 13:00~ 場 所 技 術 支 援 室 担 当 山 田 さん