• 検索結果がありません。

PowerPoint プレゼンテーション

N/A
N/A
Protected

Academic year: 2021

シェア "PowerPoint プレゼンテーション"

Copied!
49
0
0

読み込み中.... (全文を見る)

全文

(1)

部内向けスキルアップ研修

「組込みOS自作入門」

2013年8月

(2)

目次

• はじめに • ブート・ローダー • シリアル経由でのファイル転送 • XMODEMを実装する(もくもく会) • アセンブラ・プログラミング

(3)

はじめに

前回やったこと

• ROM、RAM、自動変数、静的変数、データ領

域に関する学習

今回やること

• ブート・ローダー

• XMODEMプロトコル

• アセンブラ・プログラミング

(4)

4.1 ブート・ローダー

4.1.1 ブート・ローダーの必要性 • これまでは、作成したプログラムをフラッシュ ROMへ書き込んでROM上で実行してきたが、 実はROMは書き込み回数に上限がある。 →メーカー保証は100回程度 (通常利用の範囲ならば1000回程度) • 電源OFFしても消えないので、電源ONと同時 に起動するOSが作成できるが、短所がある。

(5)

4.1.1 ブートローダの必要性

• そこで、OSの実行形式ファイルを直接フラッ シュROMに書き込む代わりに、OSの実行形式 ファイルをシリアル経由でダウンロードし、そ れをRAM上に展開して起動するプログラムを フラッシュROMに書き込む ↓ ブート・ローダー(boot loader) • ブート・ストラップ(bootstrap) 電源ONでブート・ローダーを起動し、ブー ト・ローダーでOSをダウンロードしてRAM上 でOSを展開し起動するという2段構成

(6)

4.1.1 ブートローダの必要性

• 良いところ – 気軽にOSのダウンロードが繰り返せる – 効率よく開発をすすめることができる • 悪いところ – RAMは電源OFFにすると内容が消えるので、 起動の度にOSをダウンロードしなければなら ない。

(7)

4.1.1 ブートローダの必要性

• ROM化 – 開発中はブートローダーを利用してRAM上に 展開して起動し、製品化の段階でフラッシュ ROMに書き込んでROM上から起動する • 今回はOSのROM化まではやらない • OSをダウンロードしてRAM上で展開し、起動す るブート・ローダーを作成する

(8)

4.2 シリアル経由でのファイル転送

• ブート・ローダーの機能 – シリアル経由でOSの実行形式ファイルをダウ ンロードし、RAM上に一旦保存 – 保存した実行形式ファイルを、RAM上に展開 – RAM上に展開したOSを実行 • シリアル通信には、XMODEMプロトコルを使用 する

(9)

4.2.1 XMODEMプロトコル仕様

• 送信側 1. 受信側から定期的に送信されるNAKを受け たら、送信を開始する 2. ブロック単位でデータ送信 3. ACKが返ってきたら次を送信、NAKが返っ てきたら再送 4. データ終わりはEOTを送信し、ACKが返っ てきたら終了 5. 中断したい場合はCANを送信し、CANを受 信したら中断

(10)

4.2.1 XMODEMプロトコル仕様

• 受信側 1. 準備ができたらNAKを送信し、受信開始。 2. SOHを受けたら、ブロックとして受信。 成功したらACKを返し、失敗したらNAKを 返す。 3. EOTを受けたらACKを返して終了。 4. 中断したい場合はCANを送信し、CANを受 信したら中断。

(11)

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のブロック・フォーマット

(12)

4.2.1 XMODEMプロトコル仕様

• ACK(ACKnowledge)

– 受信成功時の応答として送信されるコード • NAK(NegativeAcKnowledge)

(13)

XMODEMデータフロー概略図

受信側 送信側 → NAK → (送信開始を要求) ← SOH ← (ブロック開始) ← 01 ← (ブロック番号) ← FE ← (ブロック番号を反転させたもの) ← ・・・ ← (実際のデータ 128 バイト) ← sum ← (チェックサム) → ACK → ← SOH ← (ブロック開始) ← 02 ← (ブロック番号) ← FD ← (ブロック番号を反転させたもの) (上記手順を、データがなくなるまで繰り返す) ← EOT ← (転送終了) → ACK →

(14)

4.3 XMODEMを実装する

• もくもく会 – 今回追加するファイル xmodem.h, xmodem.c – 今回修正するファイル main.c コマンド動作を実装 ld.scr バッファ領域を追加 serial.h,serial.c 文字の受信を実装 lib.h, lib.c ライブラリ関数を追加 Makefile

(15)

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」を入力

(16)

4.3 XMODEMを実装する

手順

6.リセットボタンを押すとプロンプト「kzload > 」が出るので、「load」を入力 7.直ちに、メニューから、ファイル-転送-XMODEM-送信を選択する。ファイル選択 ウィンドウが開くので、とりあえず、 「defines.h」を転送してみる。 8.間に合わなかった場合は、再度、リセットボタ ンを押してやり直す。 9.完了したら、dumpコマンドを使って、転送し たファイルを確認

(17)

4.3 XMODEMを実装する

手順

10. cygwinで転送元ファイルを表示し、転送し たファイルを比較 $ hexdump –c defines.h 11.転送データはブロック単位で送信されるた め、受信したファイルは余った部分が0x1aで 埋められている事を確認して下さい。 (XMODEMの仕様。気にしない!)

(18)

アセンブラ・プログラミング

• OSを自作する場合、アセンブラ(assembler)

の知識は必須

→「スタート・アップ」「割り込みの入口と

と出口」「スレッドのディスパッチ」の3箇

所はアセンブラでないと書けない!

• とりあえず、処理の「目的」を意識して、内

容にアタリをつけて読むと理解しやすい

(全部命令を覚える必要はない)

(19)

4.5.1 スタック

• C言語でプログラムを書くとき、すべての変

数を静的変数にするのはムダ

→ 常時メモリを占有し続けるのはムダ

• 関数に入った時のみ獲得され、returnによっ

て関数から抜けるときには捨てられ、メモリ

領域が使いまわせる「自動変数」が必要

(20)

4.5.1 スタック

効率よくメモリを利用する手順

1. ある程度の容量の領域を予め確保 2. 現在、領域のどこまでを利用しているかを示す ポインタを用意 3. 関数呼び出しにより自動変数のための領域が必 要になった場合には、必要分だけポインタをず らす 4. さらに関数呼び出しされた場合には、更にポイ ンタを必要分だけずらす 5. 関数から戻るときには、ポインタを戻す

(21)

4.5.1 スタック

スタックを管理するために利用されるポイ

ンタをスタック・ポインタ

関数単位でスタック上に確保される領域を

(22)

4.5.2 アセンブラ

• CPUはメモリ上にある機械語命令を逐次実行して いく • しかしメモリ上には数値しか保存できない • したがって、機械語命令とは数値のことで、数値 が命令としての意味を持っている

(23)

4.5.3 CPUのレジスタ

レジスタとは、CPU内部にある記憶領域のこと • CPUは加算や減算などの数値計算を行うための回 路を持っているが、これらの回路の入力や出力は レジスタに接続 • CPU(RISC)は、メモリ上の値を直接操作できず、 CPU上のレジスタに読み込んでから処理

(24)

4.5.3 CPUのレジスタ

「c = a + b」の演算の場合 1. 変数aが配置されている位置のメモリの値を、レジスタ 1に読み込む 2. 変数bが配置されている位置のメモリの値を、レジスタ 2に読み込む 3. レジスタ1とレジスタ2を加算し、結果をレジスタ3に格 納する 4. レジスタ3の値を、変数cが配置されている位置のメモ リに書き込む

(25)

4.5.3 CPUのレジスタ

• メモリ上の値をレジスタに読み込むことをロード • レジスタの値をメモリ上に書き込むことをストア • メモリ上のデータのロードやストア、演算など汎

(26)

4.5.4

プログラム・カウンタ(PC)

• 汎用レジスタとは別の重要なレジスタで、「プロ グラム・カウンタ(program counter)」がある – CPUが現在実行中の命令アドレスを指す (正確には、次の命令のアドレス) • CPUはPCを加算しつつPCの指すメモリ先の命令を 逐次実行しながら処理を進めていく – PCは次の命令を指す位置まで自動で加算される • PCの役割は、いわゆるジャンプ命令 (C言語でいうところのgoto)

(27)

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)にストア

(28)

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)にストア

(29)

4.5.5

ニーモニックとアセンブラ

• インストラクション – 機械語の命令はインストラクションとも呼ばれる – どの数値がどの命令として動作するかという決まりを、 「命令セット」「インストラクション・セット」と呼ぶ – 命令セットはCPUごとに違う (H8の命令セットとPentium系の命令セットは異なる)

(30)

4.5.5

ニーモニックとアセンブラ

• アセンブリ言語、アセンブル – ニーモニックで表した機械語プログラム表記をアセンブ リ言語という – アセンブリ言語で書いたコードを機械語コードに変換す る作業をアセンブルという – アセンブル変換するプログラムをアセンブラと呼ぶ – 機械語コードをアセンブラに逆変換することを逆アセン ブルと呼ぶ

(31)

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

(32)

逆アセンブルの結果

• 0000010c <_main>: – main関数の先頭 • 000004f8 <_func>: – func()関数の先頭 • 00000162 jsr @0x4f8:24 – func()の呼び出し箇所だろうと想像できる ニーモニックの細かい文法は気にせず、想像で読 んでいくことがコツ

(33)

逆アセンブルの結果

• 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型整数やポインタ)

(34)

main()関数部

• 79 01 00 02 mov.w #0x2, r1 – 「79」はオペコード、後ろ3バイトがオペランドで、 1バイト目は値の格納先レジスタ、後は代入値 – R1に0x0002という値を代入 • ビッグ・エンディアンとリトル・エンディアン – 「0x0002」を格納するとき、ビッグ・エンディアン は「0x00」「0x02」、リトル・エンディアンは「0x02」、 「0x00」とひっくり返して格納する – CPUによって異なり、H8はビッグ・エンディアン。 Pentium系CPUはリトル・エンディアン。近年の多く はビッグ・エンディアン。

(35)

main()関数部

• イミディエイト値(即値)

– オペランドにレジスタに代入する「0x0002」という値 が、そのまま記述

(36)

func()関数部

• mov.l er6, @-er7

– H8ではER7がスタック・ポインタとして利用される – スタック・ポインタを減算してスタック4バイト領域 を確保してスタック・ポインタの指す先にER6の値を 格納(ストア)する – ER6が上書きされてしまうので、ER6の値(内容)を スタックに退避している – スタックを獲得するのにER7の値を減算している。ア ドレス値が少なくなる方向に伸びること(下方伸長) – 「@er7」レジスタの値をアドレス値として、アドレ スが指す先のメモリの意味(レジスタ間接) →メモリ参照の方法をアドレッシング・モード

(37)

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

(38)

func()関数部

• アドレッシング・モード – 「@-er7」レジスタの加減算とメモリ・アクセスを1 命令で同時に行う – スタック操作に2命令が利用されると、その命令の間 で割り込みが入りスタック操作された時に、スタック の整合性が取れなく可能性がある – スタック操作は1命令で行える必要がある

(39)

func()関数部

• mov.l er7,er6 – スタック・ポインタであるER7の値をER6にコピーし ている – ER6はフレーム・ポインタと呼ばれる使われ方をして おり、スタック・フレームの先頭を指している – ER6もER7も、ポインタとして利用されるため、アド レスを保持する必要があるので、32ビットレジスタ が利用される。

(40)

func()関数部

• subs #4, er7 – スタック・ポインタであるER7をさらに4バイトだけ 減算して、4バイトの領域を確保 – func()の内部で利用している自然変数「c」の領域 – 「#4」の4は定数値を表すイミディエイト値(即値)

(41)

func()関数部

• add.w r1,r0

– R0とR1の値を加算して、R0に代入 – 「a +b 」の処理(1 + 2)をしている

• mov.w r0, @(0xfffe:16, er6)

– 加算結果はR0に格納されているが、自動変数「c」 はスタック上に存在

– フレーム・ポインタを減算してアドレスを計算して、 そこに加算結果を代入

(42)

func()関数部

• mov.w @(0xfffe:16, er6), r0

– スタック上に格納されている変数「c」の値をr0に代 入することでモリチの準備をし、R0を関数の戻り値 とする – 元々、R0に「c」の値が入っていたからムダな処理 – 「c」をvolatile定義したため、最適化処理が行われ ていない – 「加算して、結果をスタックに保存して、戻り値を準 備する」という一連の処理が最適化されていない

(43)

func()関数部

• adds #4, er7

– スタック・ポインタを4バイト加算することで、自動 変数「c」の為に確保していたスタックを開放

• mov.l @er7+, er6

– スタック上に対比されていたER6の値をER6に読み込 んで(ロード)、ER6を元に戻す – ロード後にスタック・ポインタであるER7は4バイト 加算 • rts – スタック上から戻り先アドレスを取得し、ジャンプし て関数の呼び出し元に戻る

(44)

4.5.7

役割の決まっているレジスタ

• 関数の呼び出しは「jsr」、関数からの復帰は「rts」 • jsrを実行すると、スタック・ポインタである ER7の指す先にプログラム・カウンタの値を保 存してから、プログラム・カウンタを書き換え てジャンプ • rtsを実行すると、ER7の指す先の値をプログラ ム・カウンタに代入して呼び出し元に戻る • ER7は、jsrやrtsを実行すると自動的に利用され、 値も変更される。 • ER7は、CPUがスタック・ポインタとして明示 的に操作しているレジスタ

(45)

4.5.8

スタート・アップ

• startup.sのソースコード _start: mov.l #_stack,sp jsr @_main • 「_start」はラベル(label)と呼ばれ、アセン ブラ内でラベルが利用されると、定義されてい る位置のアドレスに置き換わる

(46)

4.5.8

スタート・アップ

• スタート・アップで行うべきことは、スタッ ク・ポインタの初期値設定 • スタック・ポインタを適切に設定してから出な いと、C言語の関数呼び出しを正常に行う事がで きない • jsrでメイン関数を呼び出しているので、その前 に「mov.l」でスタック・ポインタを設定 • 「_stack」のアドレス値をspに代入しているが、 spはER7ど同義で、stack pointer のこと

(47)

4.5.8

スタート・アップ

• 「bra」は戻り先アドレスをスタックに保存しな い単純なジャンプ 1: bra 1b • 「1b」というラベルはない。1bが書かれた箇所 より前で「1:」という記述がある最も近い物を 指す • main()の呼び出しから戻ってきた時に暴走しな いようにとりあえず無限ループをおいて、実行 がそれ以上進まないようにしている

(48)

今日やったこと

• XMODEMによるファイル転送ができるように なった • ブート・ローダーから起動できるまで、あと少 し! • アセンブラに関する学習 • アセンブラはアタリをつけて読む – スタックの確保、レジスタの退避、自動変数の作成 – レジスタの復旧とスタックの開放、戻り先へのジャン プ

(49)

次回の開催予定

• 日時

– 9月10日(火) 13:00~

• 場所

– 技術支援室

• 担当

– 山田さん

参照

関連したドキュメント

Lane and Bands Table と同様に、Volume Table と Lane Statistics Table も Excel 形式や CSV

全国の宿泊旅行実施者を抽出することに加え、性・年代別の宿泊旅行実施率を知るために実施した。

このように雪形の名称には特徴がありますが、その形や大きさは同じ名前で

出来形の測定が,必要な測 定項目について所定の測 定基準に基づき行われて おり,測定値が規格値を満 足し,そのばらつきが規格 値の概ね

その職員の賃金改善に必要な費用を含む当該職員を配置するために必要な額(1か所

①正式の執行権限を消費者に付与することの適切性

・分速 13km で飛ぶ飛行機について、飛んだ時間を x 分、飛んだ道のりを ykm として、道のりを求め

QRされた .ino ファイルを Arduino に‚き1む ことで、 GUI |}した ƒ+どおりに Arduino を/‡((スタンドアローン})させるこ とができます。. 1)