[MPASM]list擬似命令の意味と、指定可能なオプション情報一覧

PICのアセンブラであるMPASMでは、list命令でターゲットのPICデバイスを指定します。

LIST P=PIC16F84A



LISTはデバイス指定用の専用命令なのかというとそうではなくて、他にも色々な付加情報(アセンブラ処理や、フォーマット制御)を指定する事が可能です。

今回はlist命令で指定可能なオプションの一覧を確認してみます。

listオプション一覧



bオプション


*.lstファイルのタブストップ位置を指定します。
デフォルト値は8です。

使用例

LIST b=4




cオプション


*.lstファイルのカラム幅を指定します。
デフォルト値は132です。

使用例

LIST c=80




fオプション


アセンブルで生成されるhexファイルのフォーマットを指定します。
デフォルト値はINHX8Mで、INHX32,INHX8M,INHX8Sが指定可能です。
(MPLABのビルドオプションでも指定可能です)

使用例

LIST f=INHX32




freeオプション


フリーフォーマット用のパーサーを使用します。
このオプションは下位互換のために存在します。


freeオプション


フリーフォーマット用のパーサーを使用します。
このオプションは下位互換のために存在します。


fixedオプション


固定フォーマット用のパーサーを使用します。


mmオプション


*.lstファイルにメモリマップを印字します。
デフォルト値はONです

使用例

LIST mm=OFF




nオプション


1ページあたりの行数をセットします。
デフォルト値は60です

使用例

LIST n=50




pオプション


使用するマイコンの種類を指定します。

使用例

LIST p=16F84A





peオプション


使用するマイコンの種類を指定し、拡張命令を有効にします。

使用例

LIST p=PIC16F84A




rオプション


ソースで基数を指定せずに数値を書いた場合のデフォルト基数を指定します。
デフォルト値はhexで,oct,dec,hexが指定できます。

使用例

LIST r=dec




stオプション


*.lstファイルへシンボルテーブルの表示有無を制御します。
デフォルト値はonで,on,offが指定できます。
使用例

LIST st=off




tオプション


1行の長さが長すぎる時、行を折り返すのではなく、途中で切り詰めます。
デフォルト値はoffで,on,offが指定できます。

使用例

LIST t=on




wオプション


アセンブル時の警告メッセージ表示レベルを変更します。
デフォルト値は0で,0,1,2が指定できます。

使用例

LIST w=1





xオプション


マクロ展開のon/offを切り換えます。
デフォルト値はonで,on,offが指定できます。

使用例

LIST x=off






ちなみに、オプションに数値が指定できる場合、数値はデフォルトで10進と見なされます。
また、パラメータは複数同時に指定できます
LIST p=16F84A, r=dec



オプションの説明中に出てくる*.lstファイルは、アセンブルを行うと*.asmファイルと同じフォルダに生成され、このファイルには、asmのソースコートどオブジェクトコードの対応が記載されています。

[パタヘネ:読書メモ]第5章 容量と速度の両立:記憶階層の利用 その5

5.6 仮想マシン


VMという言葉からイメージする仮想化は、CPUバイナリ互換性からJavaVM等まで色々なものがある。
だけど、ここで議論するものは、命令セットアーキテクチャ(ISA:interaction set architecture)の互換性についてのみとする。


このようなものを、システム仮想マシン(system virtual machine)と呼び、どんな物なのかはVMwareなどをイメージすると分かりやすい。VMの下のレイヤーにある仕組みをVMM:仮想マシンモニタ(あるいはハイパーバイザ)と呼び、プラットホーム側をホスト、仮想環境をゲストVMと呼ぶ。
この仮想マシンモニタは、非常にコンパクトになることが多い(1000ステップぐらいらしい!!)

VM環境でソフトウェアを動かす場合、CPU処理が多い場合はオーバーヘッドは少ないが、I/Oが増えると遅くなる。その理由はOSのシステムコール発行が増え、VMとしての仕事が増えるから。

VMMに求められる要件には以下の3つがある

ハードウェアリソース使用時の橋渡し
各ゲストVMの環境を分離する
各ゲストVMから仮想マシンモニタを保護する




VMM自体はソフトウェアとして実装されるけど、VMMを作る上でCPU側にサポートして欲しい機能には、以下のものがある。これがないと、VMMはゲストVMを箱庭の中で飼うことが出来ない。

1.CPUにユーザモードと、システムモードがある事。
2.ユーザモードで特権命令が発行された場合、そのことを例外としてVMMがトラップできる事。





5.7 有限状態機械を用いた単純なキャッシュの制御


有限状態オートマトン(FSM)の考え方で、キャッシュ制御のコントローラを考えてみる話。
特にメモっときたい点が無かったので、省略。


5.8 並列処理と記憶階層:キャッシュ・コヒーレンス


マルチプロセッサ環境では、メモリのキャッシュ(L1,L2キャッシュなど)が各CPUに乗っている事になる。
ライトバックのキャッシュだった場合は、各CPUキャッシュ間で、保持している情報が異なる可能性が出てくる。これは非常に問題で、CPU1が保持しているキャッシュ(メモリに未反映)の情報をCPU2が使用する場合に、データの不整合が発生してしまう。この状態をキャッシュコヒーレンス(cache coherence)と呼ぶ。

コヒーレンスという単語自体の意味は、”干渉のしやすさ”を表していて、音響や光学系の分野で使われている言葉らしい。

不整合が発生する状態を例を挙げて説明すると、以下のようになる

        動作                        メモリの値  CPU1のキャッシュ    CPU2のキャッシュ
step0   初期状態                    0
step1   CPU1がメモリをread          0           0
step2   CPU2がメモリをread          0           0                   0
step3   CPU1がメモリに1をwrite      0           1                   0
 
             -> step4で、CPU1,2間のキャッシュ値に差異が発生!!




ここで、記憶システムに”コヒーレンスが無い”という意味を,もう少し厳密に定義してみる。
“コヒーレンスが無い”記憶システムというのは、以下のことが出来る事を意味する。

読み出し値の保証
    step3の後で、CPU1がメモリをreadしたら1が返ってくる
        -> 当たり前の話
 
キャッシュ値の反映
    step3の後で、CPU2がメモリをreadしたら1が返ってくる
        -> CPU1のキャッシュをCPU2のキャッシュに
           反映させる仕組みが必要
 
メモリアクセスのシリアライズ
    複数のCPUが同一アドレスのメモリに、同時に書き込みを行えないようになっている
        -> 上記例には若干うそが合って、両CPUは同時に動作している。
           step3でCPU1,CPU2が同時に異なる値をメモリに書き込むと問題が出るので、
           そのようなアクセスは同期をとってシリアライズする必要がある。



上記のことを満たせないと、”コヒーレンスがある”記憶システムになる訳で、シングルCPU環境の構成を単純にマルチプロセッサ化すると、前述の例のようにコヒーレンスがある形になってしまう。


上記の問題を解消するためには、各プロセッサ間でやり取りをする仕組みが必要で、この仕組みをキャッシュコヒーレンスプロトコルと呼ぶ。
キャッシュコヒーレンスプロトコルは、バススヌープ方式が一般的で、他にスナーフィングや、ディレクトリベースの一貫性機構などがある。

バススヌープというのは、個々のCPU(というかキャッシュコントローラー)が、常にアドレスバスを監視していて、自分がキャッシュしているデータを他のCPUが書き換えたら自分のキャッシュを無効化するという考え方。
これの実装として、ライトイインバリデートプロトコル(write invalidate protocol)というものがある。

ライトイインバリデートプロトコルの仕組み

前述したように、コヒーレンスが無い状態にする簡単な方法は、ライトキャッシュを1CPUだけが排他的に独占できればよい。

ライトイインバリデートプロトコルについてざっくりとしたコンセプトを説明すると、以下の4つになる。

あるメモリブロックのリードキャッシュは、複数のCPUが保持する事が可能。
あるメモリブロックのライトキャッシュは、単一のCPUしか保持できない。
システムとして、どのCPUがライトキャッシュを保持しているか、オーナーを管理している。
ライトキャッシュされたデータを他のCPUが要求した時は、メモリに変わって保有者が返事する。



これを踏まえて、前述のシーケンスでのデータアクセスを再現してみる。

        動作                                   メモリ値  CPU1  CPU2
                                                         cache cache
step0   初期状態                               0
 
step1   CPU1がメモリをread                     0         0
 
step2   CPU2がメモリをread                     0         0     0
 
step3   CPU1がメモリにwrite                    0         1     
        -> キャッシュを無効化
 
step4  CPU2がメモリをread                      1         1     1
       -> CPU1の値がメモリに書き込まれ、
          同時にCPU2はそれをキャッシュする




5.9 高度な話題:キャッシュ・コントローラの実現(◎CDコンテンツ)


CDがないので省略


5.10 実例:AMD Opteron X4 (Barcelona)とIntel Nehalemの記憶階層


特筆すべき事が無かったので、省略


5.11 誤信と落とし穴


落とし穴:キャッシュをシミュレーションする際に、バイトアドレッシングやキャッシュのブロックサイズを計算に入れるのを忘れる事


サイズやオフセットを計算する時に、単位がバイトだったら8bit単位だけど、ワードだと32bit単位とかになるので、勘違いに注意。


落とし穴:プログラムを組んだりコンパイラでコード生成を行う際に、記憶システムの動作を無視する事


例えば以下の処理は、メモリの離れた位置をアクセスしていくので、キャッシュの恩恵にあずかれないリスクがある。

int a[10][10];
int sum = 0;
for ( int loop1 = 0; loop1 < 10; loop1++ ) {
    for ( int loop2 = 0; loop2 < 10; loop2++ ) {
        sum += a[loop2][loop1];
    }
}



これを、”sum += a[loop1][loop2];”にすれば、連続領域を順にスキャンするので、キャッシュが効きやすい。


落とし穴:共有キャッシュの場合に、そのキャッシュを共有しているコアまたはスレッドの数よりも、セットアソシエイティブ方式の連想度を小さくする事。


例えば4CPU構成の時は、セットアソシエイティブの連想度は4ウェイ以上にする必要があるらしい。
なぜなのかは読んでも、意味が分からなかった…


落とし穴:アウトオブオーダー方式のプロセッサの記憶階層を評価するのに、平均メモリアクセス時間を使用すること


アウトオブオーダーで実行できる場合は、キャッシュミスが発生しても、その間他の命令を実行できる可能性があるので、簡単には計算できない



落とし穴:それまでセグメント化されていなかったアドレス空間の上にセグメントを追加する事によって、アドレス空間を拡張する事。


大きな配列がセグメントをまたぐ時、そのアクセスが煩雑になったりするので結構面倒になる。的な感じ。


落とし穴:仮想化できるように設計されていない命令セットアーキテクチャ上で、仮想マシンモニタを実現する事


CPUのサポートが無いと、ゲストVMからレジスタ内の制御用情報を任意に書き換えられてしまうので、実装が難しくなる。ハードのサポートが得られない場合,ホスト側に一部手を入れる場合もある(例:Xen VMM)。


5.12 おわりに

省略


5.13 歴史展望と参考文献(◎CDコンテンツ)

CDがないので省略


5.14 演習問題

省略


[パタヘネ:読書メモ]第5章 容量と速度の両立:記憶階層の利用 その4

5.5 記憶階層間に共通する概念


CPUのL1,L2キャッシュや、仮想記憶など複数の記憶階層間でキャッシュが行われるが、各階層間で似たような技術が使われている。
一方、各記憶階層ではそれぞれ要件(記憶量・速度・キャッシュ場所を求めるのに許容される時間etc)が異なる為、使われる戦略は微妙に異なる。


キャッシュの連想度を上げると、必要なキャッシュが追い出される確率が下がるので、ミス率は低下する傾向にある。但し、キャッシュサイズが大きい時はそもそもキャッシュエントリが競合する確率が低いので、連想度向上の価値が”相対的に”下がる。



キャッシュ方式の戦略


キャッシュ方式には、ダイレクトマップ、セットアソシエイティブ、フルアソシエイティブが有る。

フルアソシエイティブは、検索が大変だけどキャッシュミス率が低いという特徴がある。
この為、CPUのキャッシュにフルアソシエイティブを使用するのは難しい(電子回路的に組むのが難しいので)


一方、ディスクのキャッシュ(仮想記憶)の場面では、フルアソシエイティブのが有効になる。
ディスク-メモリ間は速度差が大きいので面倒な事をするだけの価値があるし、ディスクぐらいアクセス速度が遅くなるとキャッシュ場所の探索を回路ではなく、ソフトウェアで実装する事が出来るから。


キャッシュから追い出すブロックの決定方法


セットアソシエイティブや、フルアソシエイティブでは、キャッシュすべき場所が使用されている場合、どのブロックを追い出すべきかという問題がある。
LRUで決定できれば原理だけど、ハードウェア的にLRUを実装するのは難しいので、LRU風な近似解を使う場合もある。
追い出す対象をランダムで決める方式は、実装が簡単だけどキャッシュのミス率が上がる欠点がある。

と書くと、能力的にはLRUの方がメリットがありそうだけど、前述したようにキャッシュサイズが増えれば相対的にミス率は下がるので、ランダムで対象ブロックを決定してしまった方が速い場合もある。

一方、仮想記憶の場合は、キャッシュミスのコストが高いので、手間を掛けてもLRU的な仕組みを採用するだけの価値がある。


キャッシュ内容の反映方法


キャッシュ内容の反映方法には、ライトスルーとライトバックがある。
今までの話と同様、仮想記憶の場合は、手間が掛かるけどパフォーマンスが良いライトバックが採用される。



キャッシュミス率の分類


これまで、”キャッシュのミス率”と表現しているけど、これは3つに分けることが出来る

初期参照ミス(compulsory miss)
    システム起動時に、キャッシュにデータがロードされていない事に起因するミス
 
    キャッシュのブロックサイズを増やせば、改善できる。
    (だが、ブロックサイズが増えすぎるとミスペナルティが増す為、考慮が必要)
 
 
 
容量性ミス(capacity miss)
    キャッシュ容量が足りない事に起因するミス
 
    これは、キャッシュ容量を増やせばミス率が改善できる
    (容量を増やしすぎると遅くなるので、考慮が必要)
 
 
競合性ミス(conflict miss)
    ダイレクトマップや、セットアソシエイティブ方式で、
    キャッシュ先ブロックの領域が不足する事に起因するミス
 
    連想度を増やせばミス率が改善できる。
    (だが、連想度が増すと遅くなるので考慮が必要)




キャッシュのヒット率を上げるためには、発生した理由別のミス率を求めて、それぞれに対応した対処が必要となる.

各ミス率に対して、改善策はあるがデメリットも同時についてくるため、何かを大量に増やせば性能が際限なく向上していくという意味にはならない。
(バランスを取る事が必要となる)


[電子回路入門]DCモータとは

今回は、直流電源で稼動するDCモータについて説明します。
DCモータと書くと難しそうですが、乾電池直結で動かす事が出来る以下のようなモーターをイメージしてもらえれば良いです(子供向けのラジコンとかに入ってそうなモノです)。

B002KBW1E0
GP.256 ハイパーダッシュ2モーター 15256 (グレードアップパーツシリーズ No.256)


モータの分類


モータを使用することで電気エネルギーを機械的な動作に変換することが出来ます。
モータにはDCモータ、ACモータ、ステッピングモータなど色々なものがあり、それぞれ以下の特徴を持っています。

DCモータ
    直流電源を与える事でモータを回転させることが出来ます。
    コイルの極性をコントロールするために、通常は物理的な接点(ブラシ)を持ちます。
 
ACモータ
    DCモータとは異なり、内部にブラシなどの接点を持たないモータです。
 
ステッピングモータ
    モータに対してパルスを与える事で、一定の角度だけ動作させることが出来るモータです。




DCモータの特徴

DCモータについてさらに掘り下げると、以下の特徴を持っています。

メリット
    回転速度が電圧に比例する
        モータが無負荷(何もつながっていない)状態だと、電圧を上げるとモーターの回転数が増します。
 
    トルクが電流に比例する
        電流を増すと、ほぼ電流に比例した形でトルクが大きくなります。
 
    起動時のトルクが大きい
        モータの回り始めが力強く回転します。
        一方でデメリットとして、始動時に定格の5~10倍程度の大電流が流れる事になります。
 
    安い
        製造が容易なので、比較的低コストで作る事が出来ます。
 
デメリット
    寿命が短い
        機械的な接点として整流子/ブラシがある為、ブラシの磨耗による寿命が有ります。
 
    騒音が大きい
        整流子/ブラシにおいて機械的な摩擦が有る為、他のモータと比べてうるさくなります。
 
    電気ノイズが大きい
        周辺にマイコンを置くと、ノイズによる誤動作の原因となります。
        ノイズ除去のため、モーターの両極間にコンデンサを入れて、ノイズ除去を行うのが通常です。



大きなモータを使用すると、速度が速くなったりトルクが大きくなりますが、一方で価格が高く、重くなってしまうというデメリットがある為、駆動させたい最大負荷にあったモータの選定が必要です。


DCモータの動作原理

DCモータは電磁石の仕組みがベースになっています。
モータ内にはコイルがあり、コイルに対して電流を巻くと磁界が発生します。
コイルの回りには磁石があり、発生させた磁界と磁石の間で発生した反発力をモータの回転エネルギーに変えています。


モータ使用時の周辺回路

モータの特徴としては、モータの始動・停止に大電流が発生するということがあります。
特にモーターの停止時は、慣性でモーターが止まるまでの間、モータが発電機となる為、モータ駆動時と逆方向に電流(逆起電力)が発生します。モーターの回転をPIC等のマイコンで制御する場合、モータの駆動制御にトランジスタを入れることが多いですが、逆起電力が発生してしまうとトランジスタに対して逆方向(エミッタ->コレクタ)に電流が流れる事になってしまい、トランジスタの破損につながります。

これを抑制するために、通常モータを使用する回路には、モータと並列にダイオードを配置します。
このダイオードの事を特に、還流ダイオード(フリーホイールダイオード)と呼びます。

ダイオードには、電子回路用向けの応答が速いが小電流向けのものと、逆に応答が遅いが大電流向けのものがあります。フリーホイールダイオードに求められるスペックは”整流性があって、大電流を流せる”必要があるので、後者のものを使用します。

また、前述しましたが、モータを回転させると、大きなノイズが発生するため、コデンサもモータと並列に配置します。ノイズの発生理由は、DCモータの場合は、筐体と回転部の間が、ブラシと整流子で接続されていますが、回転している間は断続的にブラシが接触したり離れたりするので、この際にノイズが発生します。マイコン制御を行う場合等で、ノイズが少ないモータが欲しい場合は、ブラシレスモータを使用すると良いです。

コンデンサの容量はモータの性能によって異なりますが、おもちゃのラジコンに使われるような小規模なモータの場合だと、積層フィルムコンデンサの0.1μ~10μFあたりを使用します。さらにノイズを除去するためには、電源をマイコン制御系の電源と駆動系で完全に分け、制御系からの信号もフォトカプラを使用して電気的に絶縁させてしまいます。

4274035425
モーターがわかる本 (なるほどナットク!)

4798009598
図解入門 よくわかる最新モータ技術の基本とメカニズム―モータの基礎講座と工作ガイド

Software Design 2012年8月号で紹介されている書籍一覧

B008FQIGFM
Software Design (ソフトウェア デザイン) 2012年 08月号


技術評論社より出版されているSoftware Designの2012年8月号の特集は、”エンジニアのパワーアップ読書”という事で、原則として1人あたり4冊,計16人の方がお勧めの本を紹介されていました。
備忘録として、紹介されていた本の一覧をメモしておきます。

よくある、人月の神話 計算機プログラムの構造と解釈 みたいな、お約束の良書ばかりだけでなく、その人自身が個人的に大きな影響を受けた本が紹介されており、一読の価値ありです(特に最後の、ビックリマンの話がお勧めです)。

選者の経歴や、紹介理由は本書のほうに書かれていますので、知りたい方はこちらを参照してください。


エンジニアリング力


選者:小山哲志

410215972X
暗号解読〈上〉 (新潮文庫)


4757141769
キーボード配列QWERTYの謎


4756142818
フリーソフトウェアと自由な社会 ―Richard M. Stallmanエッセイ集


4873115310
デザイニング・インターフェース 第2版 ―パターンによる実践的インタラクションデザイン


477414164X
プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ)



UNIX系・仮想化/クラウド


選者:台場圭一

4756144152
デーモン君のソース探検―BSDのソースコードを探る冒険者たちのための手引き書 (BSD magazine Books)


4774134325
Googleを支える技術 ~巨大システムの内側の世界 (WEB+DB PRESSプラスシリーズ)


4798121401
KVM徹底入門 Linuxカーネル仮想化基盤構築ガイド


4844323644
まるごとJavaScript & Ajax ! Vol.1


4797324937
Red Hat RPM Guide (redhat PRESS)


選者:中島能和

4798114022
Linuxコマンド ビギナーズブック


4798112836
Inside Linux Software オープンソースソフトウェアのからくりとしくみ


4797328355
ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道


4797338261
Linuxカーネル2.6解読室


4774145017
プロのための Linuxシステム構築・運用技術 (Software Design plus)



ソフトウェア開発・システム構築


選者:伊藤直也

4797327030
増補改訂版Java言語で学ぶデザインパターン入門


4764904063
アルゴリズムイントロダクション 第3版 第1巻: 基礎・ソート・データ構造・数学


4798105538
エンタープライズ アプリケーションアーキテクチャパターン (Object Oriented Selection)


選者:きしだなおき

4797341378
数学ガール (数学ガールシリーズ 1)


4781911609
プログラミングの基礎 (Computer Science Library)


4774149748
2週間でできる! スクリプト言語の作り方 (Software Design plus)


4061492861
哲学の謎 (講談社現代新書)



デザイン/UI・Web



選者:たにぐちまこと

4798010928
Web標準の教科書―XHTMLとCSSでつくる“正しい”Webサイト


4797361190
体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践


4839924023
アジャイルな見積りと計画づくり ~価値あるソフトウェアを育てる概念と技法~


4774144665
JavaScript本格入門 ~モダンスタイルによる基礎からAjax・jQueryまで


4839916063
ディフェンシブ・ウェブデザインの技術―「うまくいかないとき」に備えたデザイン、「上手に」間違えるためのデザイン (Web designing books)


選者:阿部淳也

478850362X
誰のためのデザイン?―認知科学者のデザイン原論 (新曜社認知科学選書)


4274201449
ユーザビリティエンジニアリング―ユーザ調査とユーザビリティ評価実践テクニック


4861005779
IA100 ユーザーエクスペリエンスデザインのための情報アーキテクチャ設計


4153200123
デザイン思考が世界を変える―イノベーションを導く新しい考え方 (ハヤカワ新書juice)


4121012968
美の構成学―バウハウスからフラクタルまで (中公新書)



ネットワーク


選者:生田和正

4894713209
詳解TCP/IP〈Vol.1〉プロトコル


4844332023
挑まなければ、得られない Nothing ventured, nothing gained. (インプレス選書)


1587201372
Network Management Fundamentals


4797336803
新版Perl言語プログラミングレッスン入門編


1587052024
Routing TCP/IP, Volume 1 (CCIE Professional Development)


4756107834
Life with UNIX―UNIXを愛するすべての人に


選者:あきみち

0201634481
Interconnections: Bridges, Routers, Switches, and Internetworking Protocols (Addison-Wesley Professional Computing Series)


4048700731
実践DNS DNSSEC時代のDNSの設定と運用


4140807431
新ネットワーク思考―世界のしくみを読み解く


4434144944
光海底ケーブル (Parade books)


4274068242
インターネットのカタチ―もろさが織り成す粘り強い世界―



データベース


選者:松信嘉範

4534032501
業務別データベース設計のためのデータモデリング入門


479810566X
グラス片手にデータベース設計~販売管理システム編 (DBMagazine SELECTION)


4774150207
Webエンジニアのための データベース技術[実践]入門 (Software Design plus)


4798120723
Linux-DB システム構築/運用入門 (DB Magazine SELECTION)


4774151114
Mobageを支える技術 ~ソーシャルゲームの舞台裏~ (WEB+DB PRESS plus)


選者:ミック

0123820227
Joe Celko’s SQL for Smarties, Fourth Edition: Advanced SQL Programming (The Morgan Kaufmann Series in Data Management Systems)


0071230572
Database Management Systems


1934356557
SQL Antipatterns: Avoiding the Pitfalls of Database Programming (Pragmatic Programmers)


4774143073
[Web開発者のための]大規模サービス技術入門 ―データ構造、メモリ、OS、DB、サーバ/インフラ (WEB+DB PRESS plusシリーズ)


0123877334
Joe Celko’s Trees and Hierarchies in SQL for Smarties, Second Edition (The Morgan Kaufmann Series in Data Management Systems)



マネジメント


選者:小野和俊

4906638015
7つの習慣―成功には原則があった!


4798102245
隠れた人材価値―高業績を続ける組織の秘密 (Harvard Business School Press)


4479791183
すごい会議-短期間で会社が劇的に変わる!


4274066983
アジャイルレトロスペクティブズ 強いチームを育てる「ふりかえり」の手引き


4274066304
Joel on Software


グローバルコミュニケーション


選者:篠原英治

0578012812
Getting Real: The Smarter, Faster, Easier Way to Build a Successful Web Application


4822246795
最強の記憶術 暗記のパワーが世界を変える


4344019741
129円のマンツーマン英会話 スカイプ英語勉強法


1449311520
Hadoop: The Definitive Guide


選者:森山たつを/もりぞお

4478490279
考える技術・書く技術―問題解決力を伸ばすピラミッド原則


4478017034
自分のアタマで考えよう


4101325324
絶対貧困―世界リアル貧困学講義 (新潮文庫)


4091792715
ぼくんち―スピリッツとりあたまコミックス (1)


4798126187
アジア転職読本



洋書の選書


選者:yomoyomo

1936719118
Anything You Want


1257638017
The Architecture of Open Source Applications
※以下のページより、CC3.0ライセンスで本文が公開されています。
The Architecture of Open Source Applications
日本語訳されている方もいます: http://m-takagi.github.com/aosa-ja/aosa.pdf


0596804350
Open Government


0674035070
Understanding Privacy


0140139966
How Buildings Learn: What Happens After They’re Built



スタートアップ


選者:滑川海彦

4534047576
起業のファイナンス ベンチャーにとって一番大切なこと


4822248968
小さく賭けろ!―世界を変えた人と組織の成功の秘密


4822249107
スタートアップ! ― シリコンバレー流成功する自己実現の秘訣


4478016879
「超」入門 失敗の本質 日本軍と現代日本に共通する23の組織的ジレンマ



その他


選者:小飼弾
4873110963
プログラミングPerl〈VOLUME1〉


選者:伊藤直也
447930066X
ひきこもれ―ひとりの時間をもつということ (だいわ文庫)


選者:田中邦裕
TRY PC! 1997年1月号


選者:森山和道
ハイパーテキスト情報整理学―構造的コンテンツ作成のすすめ


選者:小野和俊
B003Q3IKF0
ダンベル 6kg


選者:きたみりゅうじ
B003N0GCAQ
タイタニック [DVD]


選者:川田十夢
B008E95W02
ビックリマン

ダイオードを回路に入れると,電圧が0.6V下がる理由は?

ダイオードはアノードからカソードにのみ電流を流すことが出来るけど、逆方向に流す事は出来ません。
この特性の事を、整流作用と呼びます。

ダイオードを作るためには、シリコン(珪素:けいそ)を使用した半導体を使用することが多いですが、シリコンダイオードはアノードからカソードへ電気を流しても、両端の電位差が0.6V以上ないとほとんど電流を流す事が出来ません。
この電圧のことを順方向電圧と呼びます。

一方、電位差が0.6Vを超えると、ダイオードは非常に大量の電流を流す事が出来ます。

オームの法則はE=IRなので、0.6V以下で電流がほとんど流れないという事はダイオードの抵抗が非常に高く、0.6Vを超えると抵抗が非常に低くなるという事が分かります。

順方向電流について、フェアチャイルド社で製造されている、整流用ダイオードとして有名な1N4001のデータシートをチェックしてみます。


グラフから分かるように、0.6Vだと10mAしか流せませんが、1Vで1A、1.4Vになると20Aも流す事が出来ます。

この値を元に各電圧での抵抗値を計算すると以下のようになります。
以下の抵抗値を見ると1.4Vもかければ、ほぼ無抵抗な状態になることが分かるかと思います。

0.6Vの場合
    R = 0.6 /  0.01 = 600   Ω
 
1.0Vの場合
    R = 1.0 /  1.00 =   1   Ω
 
1.4Vの場合
    R = 1.4 / 20.00 =   0.07Ω



ちなみに、1N4001の場合、順方向に流せる電流の最大値は1.0Aなので、このダイオードに1.0V以上かける場合、電源直結にすると電流が流れすぎてしまう事が分かります。
この為、通常は電流制限用の抵抗を直列に入れる事になります。


順方向電圧は、シリコンダイオードだと必ず0.6Vになるのですが、この値はシリコンの原子構造に起因するものなので変更する事は難しいです(難しく言うと、シリコン半導体にある電子が、自由電子となる閾値が0.6Vになります)。
シリコンの替わりにゲルマニウムを使用したゲルマニウムダイオードだと、順電圧降下は半分の0.3V程度にすることが出来ます。

値だけ見ると、ゲルマニウムダイオードのほうがお得では?と思われるかもしれませんが、ゲルマニウムはレアメタルで採取が難しいのに比べて、近年はシリコンの精製が容易に出来る様になったので、シリコンダイオードがポピュラーです。
(もちろん、現在でもゲルマニウムダイオードを使用する場合もあります)

また、ダイオードによっては、1.2Vの順電圧降下が発生するパーツもありますが、これは内部的にシリコンダイオードが2個直列されていると考えれば良いです。

電子回路を構成するパーツの特徴については、ちょっと古い本ですがブルーバックスから発売されている下記の書籍がお勧めです。
406257084X
図解・わかる電子回路―基礎からDOS/V活用まで (ブルーバックス)
教科書のように理論的過ぎて実用性に乏しいというわけではなく、しかも基本的な仕組みが平易な文章で説明されている良書です。ダイオードやトランジスタの基本的な仕組みは変わらないので、少々古い書籍でも問題ないです。

また、副題に”DOS/V活用まで”とありますが、これは各パーツの特性をシミュレーションするためのプログラムがBASIC等で書かれている為です。もちろん特性の説明は文章でも行われているので、プログラムが分からなくても問題なく読むことが出来ます(というかプログラムの方が補足的です)。

[PIC]TRISA,TRISBレジスタの”TRIS”って何?

PICのレジスタ一覧を見ると、TRISA/TRISBレジスタというものが有ります。
このレジスタは、それぞれPORTA/PORTBの入出力を決定するもので、役割は分かっているのですが、”TRIS”が何の略なのか語源が気になったので調べてみました。



答えは、MPASMのユーザガイドに記載されていました。

Mnemonic
	TRIS r 
 
Description
	Tristate port r






と言うわけで、TRISはTristate(トライステート)の略でした。

TRISA,Bの値を0にすると”High” or “Low”の出力が指定可能で、1にすると入力になる(=ハイインピーダンス状態になる)ので、トライステートラッチというわけです。

PICマイコンの基礎

[C#]Pic16f84シミュレータを作成する

これまで1ヶ月ほど掛けて、パタヘネ本でCPUの動作原理を勉強してみたり、PICによるアセンブラプログラムの作成を行ってきました。そこで、今回は勉強した成果として、Microchipから発売されているPic16f84のシミュレーターを作成してみます。


いきなり全部作ると大変になるので、今回は大枠を作るために、ADDLW(Wレジスタの加算)とGOTO命令しか解析できない最低限のCPUシミュレータを、C#で構築します。

このシミュレータは、C#上ではクラス(Pic16f84Simulatorクラス)として実装していきます。

まずはプロパティの定義を行います。

    class Pic16f84Simulator {
        //-------------------------------------------
        /// プロパティの定義
        //-------------------------------------------
        /// <summary> プログラムカウンタ</summary>
        public int Pc { get; private set; }
 
        /// <summary> ワーキングレジスタ</summary>
        public int Wreg{ get; private set; }
 
        /// <summary> プログラムメモリ</summary>
        public int[] ProgMem { get; private set; }
 
        /// <summary> ファイルレジスタ</summary>
        public int[] FileReg { get; private set; }
 
        /// <summary> CPUサイクル</summary>
        public long CpuCycle { get; private set; }
 
        public Pic16f84Simulator() {
            ProgMem = new int[1024];
            FileReg = new int[256];
        }



PICの構成要素である、pc,wreg,プログラムメモリ,ファイルレジスタの定義を行います。
PICのはハーバードアーキテクチャなので、プログラムの保存領域とデータの保存領域は、同一メモリ空間ではなく、別個に存在する事になります。各メモリ領域を意味する配列は,コンストラクタで領域確保しておきます。

また、将来タイマー処理を実装する時のために、CPUサイクルを管理する変数を用意しておきます。



次に、プログラムメモリの読み込みです。

        //*********************************************************************
        /// <summary> プログラムメモリの読み込みを行う
        /// </summary>
        //*********************************************************************
        public void loadProgram( int[] inProgMem ) {
            Array.Copy( inProgMem, this.ProgMem, inProgMem.Length );
        }


これは、単にパラメータで渡された情報をプログラムメモリにコピーしているだけです。
特記すべき事項は有りません。




シミュレータのメインである実行処理です。
今回は、メソッドが一回呼ばれるたびに命令を1つ実行する処理を実装します。
これはMPLABのシミュレータにおけるステップインの機能に相当します。

        //*********************************************************************
        /// <summary> ステップ実行を行う
        /// </summary>
        //*********************************************************************
        public void step() {
            OpeInfo opeInfo;
 
            //-------------------------------
            // 命令のフェッチ
            //-------------------------------
            int opeCode = ProgMem[ Pc ];
            Pc++;
 
            //-------------------------------
            // フェッチされた命令のデコード
            //-------------------------------
            opeInfo = decode( opeCode );
 
            //-------------------------------
            // 命令の実行
            //-------------------------------
            execute( opeInfo );
 
            CpuCycle++;
 
 
            // デバッグ出力
            Console.WriteLine( "命令内容 :" + Pic16f84.toNimonic( opeCode, false ) );
            Console.WriteLine( "   cycle={0}: Pc={1}, Wreg={2}" + Environment.NewLine, CpuCycle, Pc, Wreg );
        }



CPUシミュレータと聞くと大変そうですが、肝となる処理はたったこれだけです。
プログラムカウンタで指定されている命令を読み込み、デコード/実行を行います。

最後のWriteLine()は、動作確認用なので深い意味は有りません。




step()から呼ばれているdecode()メソッドでは、命令のデコード処理を担当します。

        //*********************************************************************
        /// <summary>指定された機械語命令を解析する
        /// </summary>
        /// <param name="mCode">機械語命令</param>
        /// <returns>           解析結果</returns>
        //*********************************************************************
        private OpeInfo decode( int mCode ) {
            OpeInfo opeInfo = new OpeInfo();
 
 
            // GOTO  :  0010 1kkk kkkk kkkk
            if ( ( mCode & 0xF800 ) == 0x2800 ) {
                opeInfo.OpeCode = OPCODE.GOTO;
                opeInfo.Literal = getLiteral11( mCode );
                return opeInfo;
            }
 
            // ADDLW :  0011 111x kkkk kkkk
            if ( ( mCode & 0xFE00 ) == 0x3E00 ) {
                opeInfo.OpeCode = OPCODE.ADDLW;
                opeInfo.Literal = getLiteral8( mCode );
                return opeInfo;
            }
 
            opeInfo.OpeCode = OPCODE.UNKNOWN;
            return opeInfo;
        }


今回は、”最小限のシミュレーターを作る”が目的なので、2命令だけ対応しています。

本メソッドで使用されているOpeInco, OPCODEは、以下の定義になっています。

        //***************************************************************************
        /// <summary>デコード後の命令情報
        /// </summary>
        //***************************************************************************
        class OpeInfo {
            public OPCODE   OpeCode{ get; set; }
            public int      DestReg{ get; set; }
            public int      FileReg{ get; set; }
            public int      BitAddr{ get; set; }
            public int      Literal{ get; set; }
 
            public OpeInfo() {
                OpeCode = OPCODE.UNKNOWN;
            }
        }
 
        //***************************************************************************
        /// <summary>命令コード一覧
        /// </summary>
        //***************************************************************************
        enum OPCODE {
            GOTO,
            ADDLW,
            UNKNOWN,
        };






execute()メソッドは、命令の実行です。

        //***************************************************************************
        /// <summary>   機械語命令の実行を行う
        /// </summary>
        /// <param name="opeInfo"></param>
        //***************************************************************************
        private void execute( OpeInfo opeInfo ) {
            switch ( opeInfo.OpeCode ) {
                case OPCODE.ADDLW:
                    Wreg += opeInfo.Literal;
                    break;
                case OPCODE.GOTO:
                    Pc    = opeInfo.Literal;
                    break;
 
                default:
                    break;
            }
        }


それぞれ命令の内容に従い、Wレジスタの加算やPCの変更処理を行っています。



プログラムのdecode時に使用するメソッド郡です。
命令フォーマットに従い必要な情報を取得する、ユーティリティメソッドになります。

        //***************************************************************************
        /// <summary> BCF,BSF, BTFSC命令などで指定されるbit位置情報を返す
        ///           ビット位置情報はOPCODE<9-7>で指定される。
        /// </summary>
        /// <returns></returns>
        //***************************************************************************
        static private int getOperandBit( int mCode ) {
            int bitOffset = ( mCode & 0x0380 ) >> 7;
            return bitOffset;
        }
 
        //***************************************************************************
        /// <summary> 命令実行結果の格納先(W or F)を返す
        /// </summary>
        /// <returns></returns>
        //***************************************************************************
        static private int getDestination( int mCode ) {
            int dest = ( mCode & 0x0080 ) >> 7;
            return dest;
        }
 
        //***************************************************************************
        /// <summary> ADDWF, MOVF命令などで指定される処理対象レジスタの情報を返す
        ///           レジスタの場所情報はOPCODE<6-0>で指定される。
        /// </summary>
        /// <returns></returns>
        //***************************************************************************
        static private int getOperandRegister( int mCode ) {
            int regAddress = ( mCode & 0x007F );
            return regAddress;
        }
 
 
        //***************************************************************************
        /// <summary> 11桁のリテラル値を返す
        ///           リテラル値の場所はOPCODE<10-0>
        /// </summary>
        /// <param name="mCode"></param>
        /// <returns></returns>
        //***************************************************************************
        static private int getLiteral11( int mCode ) {
            int literal = ( mCode & 0x07FF );
            return literal;
        }
 
        //***************************************************************************
        /// <summary> 8桁のリテラル値を返す
        ///           リテラル値の場所はOPCODE<7-0>
        /// </summary>
        /// <param name="mCode"></param>
        /// <returns></returns>
        //***************************************************************************
        static private int getLiteral8( int mCode ) {
            int literal = ( mCode & 0x00FF );
            return literal;
        }



以上で最低限のシミュレータの作成は完了です。



動作確認するために、以下のPICプログラムを作成しました。

    LIST    P=16F84
    INCLUDE P16F84A.INC
 
    ORG 0
    ADDLW       D'08'
MAIN
    ADDLW       D'01'
    GOTO        MAIN
 
    END



上記のプログラムをアセンブルし、hexファイルにすると以下の内容になります。

:020000040000FA
:06000000083E013E01284C
:04000600003400348E
:00000001FF




これを、今回作成したシミュレータで10ステップほど実行してみました。
とりあえず、問題なく動作できているようです。

 
命令内容 :ADDLW 0x8
   cycle=1: Pc=1, Wreg=8
 
命令内容 :ADDLW 0x1
   cycle=2: Pc=2, Wreg=9
 
命令内容 :GOTO 0x1
   cycle=3: Pc=1, Wreg=9
 
命令内容 :ADDLW 0x1
   cycle=4: Pc=2, Wreg=10
 
命令内容 :GOTO 0x1
   cycle=5: Pc=1, Wreg=10
 
命令内容 :ADDLW 0x1
   cycle=6: Pc=2, Wreg=11
 
命令内容 :GOTO 0x1
   cycle=7: Pc=1, Wreg=11
 
命令内容 :ADDLW 0x1
   cycle=8: Pc=2, Wreg=12
 
命令内容 :GOTO 0x1
   cycle=9: Pc=1, Wreg=12
 
命令内容 :ADDLW 0x1
   cycle=10: Pc=2, Wreg=13


セラロックの波形をオシロスコープで確認する



ムラタから発売されているセラロックは、主に小規模向けマイコンでクロック生成用の安価なパーツとして使用されています。

この、セラロックが作り出しているクロック波形が気になったので、オシロスコープで確認してみました。
今回の確認で使用したパーツは、8MHz出力のCSTLLS8M00G56です。

まずは、手始めにセラロックをPICマイコンの16F84Aに接続し、動作している状態での波形を確認してみました。

画像がぼやけていて見づらいですが、縦横軸のメモリが波形の下に表示されており、横は1メモリが10nsec,縦は1メモリが1Vです。周期も画面右下に出ているのですが、7.96MHzとほぼ仕様値どおりの8MHzの波形が、サインカーブで出力されていました。




次に、セラロックをPICマイコンからはずし、単にセラロックの両端ピンをオシロスコープでみた波形です。

ご覧の通り特に信号は出力されていません。
これは、セラロック自身は共振器に過ぎず、単体で発振できるのですが、インバーター回路等の能動素子がないと直ぐに発振が止まってしまうのが原因です。






というわけで、インバータ回路を組み込んだ最小の発振回路を作成しました。
回路図は以下の通りです。

2つ抵抗をつけていますが、R1に1MΩ、R2には200Ωとします。
インバータは74HCシリーズのロジックICを利用しました。
波形の計測は、インバータの両端にプローブを当てる事で行います。




上記の回路で、セラロックの両端ピンの波形をチェックした結果が以下の通りです。


少々は計のゆがみが出ていますが方形波っぽいものが出力されていました。周波数も7.971MHzと、ほぼ仕様値どおりの値が出ています。

電気に弱い人にもわかるオシロスコープ入門

半加算器をNANDとNORだけで構成する

半加算器(Half adder)というのはは、2つの1桁2進数に対する足し算を行い、和(Sum)と繰り上げ(Carry)を求める回路です。
今回は、半加算器の論理回路をNANDとNORだけで構成する方法について説明します。


まず、半加算器の振る舞いを押さえる為に、”NANDとNORだけ”という話は一旦おいといて、真理値表を確認します。

–半加算器の真理値表–

in   | out
X  Y | C  S
-----+-----
0  0 | 0  0
0  1 | 0  1
1  0 | 0  1
1  1 | 1  0



二入力のいづれか片方が1の場合は和(S)が1で、両方が1の場合は桁上げになるので繰り上げ(C)が1になります。

出力であるSとCのパターンに着目すると、一目瞭然でS(和)はXOR、キャリーはANDになっていることが分かります。
なので、もし任意の論理回路をを使ってもよければ、半加算器は以下の2素子で回路構成できます。






次に、上記の回路ををNANDとNORだけで作ってみます。
※なぜNANDとNORだけの回路に組み替えたいかというと、NAND,NORだと回路製造上で必要なトランジスタ数が少なくなり、コストメリットがある為です。


まず繰り上げ側(C)であるAND処理は簡単で、NANDを2つ用意すればOKです。

まず普通に2入力をNANDに入れて、その出力の否定を取ればANDが作れます。
NANDからNOTを作るには、二つの入力値を同一にすればOKです。




次にCのXOR(0,1,1,0の出力)はちょっと考え方に工夫が必要で、これはゴールから逆算したほうが分かりやすいです。
NAND,NORだけで作るという前提なので、Cの直前の素子がNAND,NORのどちらであったとしても、最後はNOTになります。
なのでNOTが入る直前の真理値は(1,0,0,1)です。


 out
 C  notC
--------
 0   1
 1   0
 1   0
 0   1




仮に、Cの手前の素子がNORだったと仮定した場合、(1,0,0,1)をorで作る事になるので、2つの入力は必ず(1,0,0,0)と(0,0,0,1)となります。

※OR回路だったら、他に(1,0,0,1)の入力も有りうるのでは? と思われえるかもしれませんが、もし(1,0,0,1)を入力できるのであれば、それ自身が既に求めたい答えなので、後続のNOR回路はそもそも必要ありません。故に2つの入力は(1,0,0,0)と(0,0,0,1)の2つになります。



この内、(0,0,0,1)は先ほどCの出力と同じなので、こっちから引っ張ってこれます。

また、もう一方の入力である(1,0,0,0)は、よく見るとXとYのNORで作り出すことが出来ます。
なので、半加算器をNAND,NORだけで構成させようとすると、以下の4素子で組み立てることが出来ます。

[デジタル回路]組合せ回路と順序回路の違い

デジタル回路には、組み合わせ回路と順序回路が有ります。

組み合わせ回路は、入力から出力が決定するものです。
一方、順序回路は、入力値と内部状態から出力が決定します。


順序回路の代表的な例としては、以下の様なものがあります。

ラッチ(latch)
	RSラッチ
	Dラッチ
 
フリップフロップ(flip flop)
	Dフリップフロップ
	JKフリップフロップ
 
加算器(adder)
	全加算器
	半加算器
	並列加算器
 
カウンタ
	5進カウンタ
	10進カウンタ
	24進カウンタ
	60進カウンタ
	...
	グレイコードカウンタ
 
タイマ
	ワンショットタイマ/インターバルタイマ
	ウォッチドッグタイマ




順序回路は、入力だけではなく内部状態に依存するため、順序回路自身が状態を保持するメモリ機能を持っています。
フリップフロップは、非常にシンプルな1ビットのメモリで、この仕組みを利用した記憶装置がSRAMです。

ラッチやフリップフロップについてはこちらの記事にも書きました。



カウンタ回路は、信号が来るたびに値が加算されていき、指定した値でリセット(桁上がり)されます。
24進や60進といったカウンタも用意されており、これらは時計を作る時に便利です。

また、グレイコードカウンタというのは特殊な値の変わり方をするカウンタです。
例えば3ビットのカウンタだと、以下の順に値が遷移します。

10進  グレイコード
0     000
1     001
2     011
3     010
4     110
5     111
6     101
7     100


カウンタで、複数のビットが同時に変わると、一瞬ノイズ(スタティック・ハザード)が発生するため、そのノイズをなくしつつ、指定ビット数のカウンタを作りたい場合に利用します。



タイマは、指定された時間後や、指定された周期でシグナルを発生させるものです。
他の順序回路と異なり、タイマはハードウェア的に作る場合と、ソフトウェア的に発生させる場合が有ります。

ハードウェアタイマについては、カウンタがあれば、リセットのタイミングでシグナルを発生させる事で、実装する事も可能です。

また特殊なタイマとして、ウォッチドッグタイマ(WDT)が有ります。
これは、プログラムが正しく動作しているかの確認タイマで、ソフトウェアからタイマを”一定周期以内に、かつ、定期的に”リセットする必要があります。
一定周期の間リセットが掛からなかった場合は、ハードウェア側でシステムの強制リセットを行わせます。

これにより、通常は定期的なWDTリセットが掛かるため問題ありませんが、ソフトが正しく動作していない場合に自動リセットをハード的にかけることが可能となります。

[MPLAB]エラー”Argument out of range. Least significant bits used.”が出る時にチェックすべき事

MPLABでアセンブル時、Warning[202] Argument out of range. Least significant bits used.エラーが出る場合があります。
このワーニングは、セットした値を代入したとき代入先に値が入りきらないという警告です。


warningなのでhexファイルは作成されますが、値が意図したとおりセットされず、プログラムの動作は期待したものとは異なってしまうため、修正が必要です。


問題が発生する状況を分かりやすい例で言うと、以下のコードはWarning[202]が発生します。

    MOVLW   0x100



Wレジスタは8ビットなので最大で0xff(255)しか入らないにも関わらず、0x100(256)をセットしようとしているためです。


他に、勘違いしやすい例としては以下のコードが有ります。

    MOVLW   255



これは、10進の255をセットしようとしているのですが、MPLABはデフォルトでは基数を指定せずに数値を指定した場合は16進数と見なされるため、このコードは以下のように解釈されます。

    MOVLW   0x255



前述のNG例と同様,0xffより大きな値をセットしようとしているため、ワーニングが表示されます。

[電子回路]コンデンサの基礎知識

コンデンサとは

コンデンサは、電気をためておくことが出来るパーツです。
コンデンサの両端の端子に電圧をかけると、コンデンサの容量分、電気を貯めておく事が可能です。

コンデンサの両端子は電気的につながっていない為、直流成分を通す事が出来ないという特徴が有ります。
この特徴を利用して、特定の周波数成分を取り除くフィルタや、電源近くにコンデンサを置く事でノイズを除去することが出来ます。

他にも、コンデンサがバッファとして使用することで、特定の入力信号に対して、遅延を掛けて出力を行わせる事が出来ます。
これによって、例えばマイコンの初期処理(電源ONするまでの間リセット端子をActiveにする等)の簡易的な遅延タイマー回路を組むことも良く行われます。

また、コンデンサはキャパシタ(capacitor)とも呼ばれます。



コンデンサの寿命

コンデンサは他の素子と同様、当然ながら寿命というものが有りますが、抵抗などと比べると比較的短寿命になります。

寿命が過ぎるとどうなるかが気になるところですが、一般的にコンデンサは寿命内において、以下の特性を保証します。
(厳密な定義は各メーカーによって異なり、データシートやメーカのWebサイトを見ると確認できます)

静電容量
    一般に規格値の±20%以内(メーカーによっては±30%)の静電容量を保持する事。
 
損失角の正接
    変化規定範囲(初期の1.5~3.0倍)を保持する事。
 
漏れ電流
    貯めた電気の漏れが、規格値を保っている事。





コンデンサは、寿命はパーツが稼動している温度によって大きく変わります。
温度が寿命に与える影響は、アレニウスの式というもので以下の数式になります。

L = L0 * 2^( (T2-T1)/10 )
 
L : 推定寿命
L0: 基本寿命
T2: 基本寿命での温度
T1: 使用温度




数式だけだと、分かり辛いので実際の製品を例にとって、確認してみます。


例として、日本セミコンから発売されている、SRAシリーズのコンデンサで確認します。

このコンデンサのデータシートは以下のURLから入手できます。
http://www.chemi-con.co.jp/catalog/pdf/al-j/al-sepa-j/004-lead/al-sra-j-120701.pdf

データシートを見ると、右上に85℃/1,000時間保証と有ります。



上記の保証値が、前述の式のヒントになります。
再度数式を見てみると、この情報は以下のように対応付きます。

L = L0 * 2^( (T2-T1)/10 )
 
L : 推定寿命
L0: 基本寿命           <- 1000時間
T2: 基本寿命での温度   <- 85度
T1: 使用温度



このように、製品が決まると変数の2つが求まるので、後は使用温度を仮定すれば、推定寿命が求まります。例えば、使用温度(T1)が85度だと、2^( (T2-T1)/10 )の部分が2の0乗(=1)となり、当然ながらL=1000時間です。

式から見ても分かりますが、温度のパラメータは指数部にあるので、温度が上がると極端に寿命が短くなってしまいます。ですので、コンデンサは高温にならない状況(常温)で使用することが大事です。

温度と寿命の関係を理解しやすくするために、前述の式に対して、使用温度を5度づつ下げていった場合に推定寿命がどうなるかを一覧表を作成してみました。

T1:使用温度   L:推定寿命
-----------   ----------
85             1,000
80             1,414
75             2,000
70             2,828
65             4,000
60             5,657
55             8,000
50            11,314
45            16,000
40            22,627
35            32,000
30            45,255
25            64,000
20            90,510



基本寿命での温度設定から30度下げるだけで、寿命が10倍以上延びることが分かります。
よくPCで、PC本体の換気が悪くマザーボード周辺の温度が上がってしまうと、故障が非常におきやすくなるのも上記の表を見ると一目瞭然です。

※余談ですが、上記の値をエクセルで計算したい場合は、以下の式で求めることが出来ます。

= 1000 *POWER(2,(85-使用温度)/10)




また、寿命とは関係有りませんが、一般に、コンデンサの容量は高温になるほど大きく、低温になると小さくなる傾向が多いです。

コンプリメンタリ・トランジスタとは何か?




トランジスタのデータシートを見ると、以下のように”コンプリメンタリ・トランジスタ”というものが指定されている場合があります。
ここで言うコンプリメンタリ・トランジスタとは何のことでしょうか?





トランジスタは製造方法によって、PNP型とNPN型というものが有ります。
コンプリメンタリトランジスタというのは、この型(PNP/NPN)だけが逆で、他の特性は同様となるトランジスタの事を指します。




例えばルネサスが発売しているトランジスタである、2SC2334のデータシートを見ると、コンプリメンタリトランジスタとして2SA1010と記載されています。

確認のため、これら2つのトランジスタのデータシートを見比べてみます。
表紙の表記より、2SC2334がNPNで、2SA1010PNP型と、逆の極性である事が分かります。

2SC2334


2SA1010




特性を見ると、正負が異なるだけで基本的に同じ特性を持っています。

2SC2334


2SA1010



このように、コンプリメンタリトランジスタは極性が逆なので、代用品として使用することは出来ません。

また余談ですが、コンプリメンタリはアルファベットで書くとComplementaryで、”補完する”という意味があります。

縦向きのトグルスイッチは,上下どちらをONにすべきか


電子回路を作成する際、回路をON/OFFする為にトグルスイッチを使用する場合があります。

トグルスイッチには対象機器の特性や、スペース、想定する設置場所等によって、上向きや縦向きなど、様々な設置方向がありますが、縦置き式のトグルスイッチを設けた場合、上下どちらをONにすべきでしょうか?



トグルスイッチを縦置きで設置するする場合、モノがぶつかったりした時にスイッチが下に変わってしまう危険があります。
この為、トグルスイッチを上下どちらがONにすべきかを考える時は、”上でON、下でOFF”にするのが一般的です。

これは、地球には重力があるので、下方向に押し下げられる可能性の方が高いところから来ており、フールプルーフを意識した設計です。



同様の話としては、トグルスイッチでは有りませんが、水道のレバー式蛇口で同様の設計が行われています。JIS規格のJIS B2061を確認すると、以下の規定があります。

6.2 水栓の構造・形状・寸法
c)シングル湯水混合水栓の開閉操作方法は"下げ止水方式"とする



水道の蛇口は、昔は”下げ止め方式”と”上げ止め方式”が混在していましたが、欧米で下げ止めが圧倒的に普及しており、2000年度末で下げ止め方式に統一されました。

製品事故に学ぶフールプルーフ設計

[PIC]アセンブラで数値を記述する場合は基数指定が必須です

PICのアセンブラで基数を明示せずに数字を指定すると、通常は16進数として認識されます。
例えばPIC16F84で、以下のコードを実行すると…

    LIST    P=16F84
    INCLUDE P16F84A.INC
    ORG 0
 
MAIN
    MOVLW   0x10
    GOTO    MAIN
 
    END



このように、Wレジスタに0x10(10進数で”16″)がセットされます。




ですがMPLABを使用している場合、この振る舞いはプロジェクトの設定で変更可能なため注意が必要です。
変更が可能なのは、基数指定を明示しない時の解釈方法で、以下の方法で設定が可能です。

MPLABのメニューより、Project -> Build Options- > Projectを選択します。


MPASMのタブをクリックすると、Default Radix(デフォルトの基数)を指定する項目があり、上から順に16進数、10進数,8進数となります。


これを、もしDecimal(10進数)に変更して上記のコードを実行すると、以下のようになります。

コードを全く変更していないにも関わらず、Wレジスタの値が0x0A(10進数で”10″)になっちゃいました。


この為、blog等にMPASMのコードをアップする場合は、基数を明示しないと、プログラムの動作がプロジェクトの設定に依存する事になってしまいます。
プログラマ側も注意が必要で、サンプルのコードを他の人から貰ったりネットからコピーしてきた場合も、このような記法がなされていないかチェックする事が必須です。

なお基数を明示する方法はMPASMの場合、以下の表記をすればOKです。

16進数
        h'0a'
        H'0a'
        0x0a
 
10進数
        d'10'
        D'10'
        .10
 
8進数
        o'12'
        O'12'
 
2進数
        b'00001010'
        B'00001010'
 
アスキー文字
        A'a'
        'a'



例えば、default radixがDecimalで有っても0x10が指定されていた場合は、以下のように16進数で指定されたと見なしてくれています。


mpasm.exeのコマンドラインオプションとしてデフォルト基数を明示する場合は、以下のオプション指定を行います
(/rとその後の文字の間にはスペースを入れません)

/rHEX
/rDEC
/rOCT




プロジェクトの設定ではなく、プログラムでデフォルト基数は以下の2通りの方法があります。

list擬似命令を使用する場合
    list r=hex
    list r=oct
    list r=dec
 
radix擬似命令を使用する場合
    radix hex
    radix oct
    radix dec



radix擬似命令は、プログラムの先頭だけではなく途中でも書く事が出来ます。
その場合、radix命令を書いた行以降でデフォルト基数が変わります。

[C#]PIC16シリーズのバイナリを逆アセンブルする

前回、MPLABで生成されたhexファイルを解析するプログラムをC#で用意しました。


今回はこのバイナリ(機械語)を元に、逆アセンブルするプログラムを作成します。

というわけでプログラムです。
13bitの2進データをみて文字列に変換するだけなので、単純に力技です。
今回は分かりやすいように全命令の処理を列挙しましたが、PICの機械語命令は、命令の各bitに何の情報を持たせるかの構成パターン数が少ないので、最適化させればもう少しシンプルに書けそうです。
PICアセンブラ入門



using System;
 
class Pic16f84 {
    //***************************************************************************
    /// <summary>   指定された機械語の命令をアセンブリのニーモニックに変換する
    ///             PIC16F84は命令長が13bitなので、13bit分のみチェックする
    /// </summary>
    /// <param name="inMachineCode">    機械語命令</param>
    /// <param name="isLittleEndian">   リトルエンディアンか(通常はfalse)</param>
    /// <returns>   ニーモニック文字列</returns>
    //***************************************************************************
    public static string toNimonic( string inMachineCode, bool isLittleEndian = false ) {
        int mCode;
        if ( isLittleEndian ) {
            mCode = Convert.ToInt16( inMachineCode.Substring(2,2) + inMachineCode.Substring(0,2), 16 );
        } else {
            mCode = Convert.ToInt16( inMachineCode, 16 );
        }
 
        if ( mCode == 0x3FFF ) {
            return "";
        }
 
        // RETURN:  0000 0000 0000 1000
        if ( mCode == 0x0008 ) {
            return "RETURN";
        }
 
        // RETFIE:  0000 0000 0000 1001
        if ( mCode == 0x0009 ) {
            return "RETFIE";
        }
 
        // SLEEP :  0000 0000 0110 0011
        if ( mCode == 0x0063 ) {
            return "SLEEP";
        }
 
        // CLRWDT:  0000 0000 0110 0100
        if ( mCode == 0x0064 ) {
            return "CLRWDT";
        }
 
        // TODO:仕様書を要確認
        // NOP   :  0000 0000 0xx0 0000
        if ( mCode == 0x0000 ) {
            return "NOP";
        }
 
        // MOVWF :  0000 0000 1fff ffff
        if ( ( mCode & 0xFF80 ) == 0x0080 ) {
            return "MOVWF " + getOperandRegister( mCode );
        }
 
 
        // CLRW  :  0000 0001 0xxx xxxx
        if ( ( mCode & 0xFF80 ) == 0x0100 ) {
            return "CLRW";
        }
 
        // CLRF  :  0000 0001 1fff ffff
        if ( ( mCode & 0xFF80 ) == 0x0180 ) {
            return "CLRF " + getOperandRegister( mCode );
        }
 
        // SUBWF :  0000 0010 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0200 ) {
            return "SUBWF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // DECF  :  0000 0011 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0300 ) {
            return "DECF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // IORWF :  0000 0100 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0400 ) {
            return "IORWF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // ANDWF :  0000 0101 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0500 ) {
            return "ANDWF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // XORWF :  0000 0110 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0600 ) {
            return "XORWF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // ADDWF :  0000 0111 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0700 ) {
            return "ADDWF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // MOVF  :  0000 1000 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0800 ) {
            return "MOVF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // COMF  :  0000 1001 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0900 ) {
            return "COMF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // INCF  :  0000 1010 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0A00 ) {
            return "INCF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // DECFSZ:  0000 1011 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0B00 ) {
            return "DECFSZ " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // RRF   :  0000 1100 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0C00 ) {
            return "RRF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // RLF   :  0000 1101 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0D00 ) {
            return "RLF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // SWAPF :  0000 1110 dfff ffff
        if ( ( mCode & 0xFF00 ) == 0x0E00 ) {
            return "SWAPF " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // INCFSZ:  0000 1111 dfff ffff
            if ( ( mCode & 0xFF00 ) == 0x0F00 ) {
            return "INCFSZ " + getOperandRegister( mCode ) + ", " + getDestination( mCode );
        }
 
        // BCF   :  0001 00bb bfff ffff
        if ( ( mCode & 0xFC00 ) == 0x1000 ) {
            return "BCF " + getOperandRegister( mCode ) + ", " + getOperandBit( mCode );
        }
 
        // BSF   :  0001 01bb bfff ffff
        if ( ( mCode & 0xFC00 ) == 0x1400 ) {
            return "BSF " + getOperandRegister( mCode ) + ", " + getOperandBit( mCode );
        }
 
        // BTFSC :  0001 10bb bfff ffff
        if ( ( mCode & 0xFC00 ) == 0x1800 ) {
            return "BTFSC " + getOperandRegister( mCode ) + ", " + getOperandBit( mCode );
        }
 
        // BTFSS :  0001 11bb bfff ffff
        if ( ( mCode & 0xFC00 ) == 0x1C00 ) {
            return "BTFSS " + getOperandRegister( mCode ) + ", " + getOperandBit( mCode );
        }
 
        // CALL  :  0010 0kkk kkkk kkkk
        if ( ( mCode & 0xF800 ) == 0x2000 ) {
            return "CALL " + getLiteral11( mCode );
        }
 
        // GOTO  :  0010 1kkk kkkk kkkk
        if ( ( mCode & 0xF800 ) == 0x2800 ) {
            return "GOTO " + getLiteral11( mCode );
        }
 
        // MOVLW :  0011 00xx kkkk kkkk
        if ( ( mCode & 0xFC00 ) == 0x3000 ) {
            return "MOVLW " + getLiteral8( mCode );
        }
 
        // RETLW :  0011 01xx kkkk kkkk
        if ( ( mCode & 0xFC00 ) == 0x3400 ) {
            return "RETLW " + getLiteral8( mCode );
        }
 
        // IORLW :  0011 1000 kkkk kkkk
        if ( ( mCode & 0xFF00 ) == 0x3800 ) {
            return "IORLW " + getLiteral8( mCode );
        }
 
        // ANDLW :  0011 1001 kkkk kkkk
        if ( ( mCode & 0xFF00 ) == 0x3900 ) {
            return "ANDLW " + getLiteral8( mCode );
        }
 
        // XORLW :  0011 1010 kkkk kkkk
        if ( ( mCode & 0xFF00 ) == 0x3A00 ) {
            return "XORLW " + getLiteral8( mCode );
        }
 
        // SUBLW :  0011 110x kkkk kkkk
        if ( ( mCode & 0xFE00 ) == 0x3C00 ) {
            return "SUBLW " + getLiteral8( mCode );
        }
 
        // ADDLW :  0011 111x kkkk kkkk
        if ( ( mCode & 0xFE00 ) == 0x3E00 ) {
            return "ADDLW " + getLiteral8( mCode );
        }
 
        // 不明
        return "???";
    }
 
 
    //***************************************************************************
    /// <summary> BCF,BSF, BTFSC命令などで指定されるbit位置情報を返す
    ///           ビット位置情報はOPCODE<9-7>で指定される。
    /// </summary>
    /// <returns></returns>
    //***************************************************************************
    static private string getOperandBit( int mCode ) {
        int bitOffset = ( mCode & 0x0380 ) >> 7;
        return "0x" + bitOffset.ToString( "x" );
    }
 
    //***************************************************************************
    /// <summary> 命令実行結果の格納先(W or F)を返す
    /// </summary>
    /// <returns></returns>
    //***************************************************************************
    static private string getDestination( int mCode ) {
        int data = ( mCode & 0x0080 ) >> 7;
        if ( data == 0 ) {
            return "W";
        } else {
            return "F";
        }       
    }
 
    //***************************************************************************
    /// <summary> ADDWF, MOVF命令などで指定される処理対象レジスタの情報を返す
    ///           レジスタの場所情報はOPCODE<6-0>で指定される。
    /// </summary>
    /// <returns></returns>
    //***************************************************************************
    static private string getOperandRegister( int mCode ) {
        int regAddress = ( mCode & 0x007F );
        return "0x" + regAddress.ToString( "x" );
    }
 
 
    //***************************************************************************
    /// <summary> 11桁のリテラル値を返す
    ///           リテラル値の場所はOPCODE<10-0>
    /// </summary>
    /// <param name="mCode"></param>
    /// <returns></returns>
    //***************************************************************************
    static private string getLiteral11( int mCode ) {
        int regAddress = ( mCode & 0x07FF );
        return "0x" + regAddress.ToString( "x" );
    }
 
    //***************************************************************************
    /// <summary> 8桁のリテラル値を返す
    ///           リテラル値の場所はOPCODE<7-0>
    /// </summary>
    /// <param name="mCode"></param>
    /// <returns></returns>
    //***************************************************************************
    static private string getLiteral8( int mCode ) {
        int regAddress = ( mCode & 0x00FF );
        return "0x" + regAddress.ToString( "x" );
    }
}




で、こちらが上記クラスの利用者側プログラムのサンプルです。
MPLABでアセンブル可能なコードを出力させています。

//------------------------------------
// hexファイルを元に,逆アセンブルを行う
//------------------------------------
textBox1.Text = "";
textBox1.AppendText( "LIST    P=16F84"     + Environment.NewLine );
textBox1.AppendText( "INCLUDE P16F84A.INC" + Environment.NewLine );
textBox1.AppendText( "ORG " + startAddr + Environment.NewLine );
bool needOrgFlg = false;
 
int dispLine = 1;
for ( int curAddr = startAddr; curAddr < endAddr; curAddr+=2 ) {
    string mWord1 = parser.getValue( curAddr );
    string mWord2 = parser.getValue( curAddr+1 );
    string mWord  = mWord1 + mWord2;
    string mnemonic = Pic16f84.toNimonic( mWord, true );
 
    //------------------------------
    // .asmファイル用のコードを出力
    //------------------------------
    if ( mnemonic.Length <= 0 ) {
        needOrgFlg = true;
    } else {
        if ( needOrgFlg ) {
            textBox1.AppendText( Environment.NewLine );
            textBox1.AppendText( "ORG " + ( curAddr /2 ) + Environment.NewLine );
        }
        needOrgFlg = false;
        textBox1.AppendText( mnemonic + Environment.NewLine );
    }
}



全命令が網羅されたプログラムで試したわけでは有りませんが、アセンブリで100ステップ程のプログラムをアセンブル->逆アセンブル->再度アセンブルしてみたところ、同一hexファイルが生成されたので、正しく逆アセンブル出来てるっぽいです。






また、MPLABの逆アセンブル結果出力互換のコードを生成するプログラムも用意したので公開します。
一部オペランドの指定の基数が10進と16進で異なる部分がありますが、それ以外はdiffをとっても同じ出力になりました。

//------------------------------------
// hexファイルを元に,逆アセンブルを行う
//------------------------------------
txtDisAsmWithAddr.Text = "";
txtDisAsmWithAddr.AppendText( " Line  Address  Opcode               Disassembly              " + Environment.NewLine );
 
 
int dispLine = 1;
for ( int curAddr = startAddr; curAddr < endAddr; curAddr+=2 ) {
    string mWord1 = parser.getValue( curAddr );
    string mWord2 = parser.getValue( curAddr+1 );
    string mWord  = mWord1 + mWord2;
    string mnemonic = Pic16f84.toNimonic( mWord, true );
 
    //---------------------------
    // MPLAB互換のダンプを出力
    //---------------------------
    txtDisAsmWithAddr.AppendText( String.Format( "{0,6}", dispLine.ToString() ) +
                          "   " +
                          ( curAddr / 2  ).ToString( "X3" ) +           /* addrはbyteでは無くword(16bit)なので2で割る */
                          "     " +
                          mWord2 + mWord1 +
                          "  " +
                          mnemonic + Environment.NewLine );
    dispLine++;
}



MPLAB側の逆アセンブル出力は、以下の操作でファイルに落とすことが出来ます。

MPLABのメニューバーに有るViewよりProgram Memoryを選択します。


表示されたウィンドウの適当なところを右クリックして、Output To Fileをクリックします。


ファイル保存ダイアログが表示されます。



4501532300
PICアセンブラ入門

Androidのスマホに、ノートPCのキーボードから文字入力する[あやつ郎]



ケータイ(スマホ)のアドレスへメールを直接送ってこられると、ちょっとイラッとします。
報告メールで返信が不要な場合は問題ないのですが、返信が必要な場合、入力が不便なスマホから文章をしなければならないので、非常にストレスがたまってしまいます。

スマホだとフリック入力できるので慣れれば速いとか言われたりもしますが、プログラマなら当然キーボードからの入力をしたいところです。


出先でも大抵ノートPCは持っているので,このキーボードを使えれば便利なのになぁ…
と思ってたのですが、この悩みを解消してくれるモノが発売されました。

B008MTUX6C
いつものPCキーボードでスマホ・タブレットを操作!「あやつ郎」 USBVTKB2

発売元は、ちょっと変わった商品を売ってることで有名なサンコーです。



このデバイス、一見するとUSBメモリのような形ですが、Bluetoothのデバイスとして動作します。
プロファイル的にはBluetooth HIDで動作します。

ノートPCに刺した上で…


ペアリングしてあげれば入力できます。




今まで長文の返信が必要な場合は、以下のような手間を掛けてメール打ってたのですが…

スマホで返信が必要なメールを発見!!
↓
ノートPCレジューム
↓
スマホのテザリングをON
↓
ブラウザを開く
↓
gmailにアクセス
↓
メール送信
↓
ブラウザ閉じる
↓
スマホのテザリングをOFF
↓
ノートPCサスペンド



これが、「あやつ郎」を持っていれば、ここまで簡略化できるようになります。

スマホで返信が必要なメールを発見!!
↓
ノートPCレジューム
↓
ノートPCのキーボードからスマホに文字入力
↓
スマホで返信操作
↓
ノートPCサスペンド



これは、かなりの手間削減です!!


他にも、「あやつ郎」の裏技的な使い方として、Bluetooth付きの他のPCへ文字入力を行うということも可能なので、簡易的な”キーボード切り替え器”替わりにもなりそうです。


注意点としては、一部の記号キーの入力が、キートップの表示と異なるものになる点です。
(販売元にキーマッピングの情報があったので転記しておきます)
出来れば改善して欲しいところですが、スマホでプログラムを書くわけではないので、メール返信目的なら許容範囲かと思えるレベルです。



スマホユーザでノートPCを持ち歩く事が多い人には、お勧めのアイテムです。
重さはわずか8gで、対応OSはWin XP/Vista/7、ターゲットデバイスはiOSやAndroid2.x対応です。


いつものPCキーボードでスマホ・タブレットを操作!「あやつ郎」 USBVTKB2


[Win2003Svr]SSD購入時に設定すべきレジストリ項目5つ

Windows 2003 Serverの起動ディスクをHDDからSSD構成に変更しました。
SSD化に伴い、設定しておくべきレジストリ項目をメモしておきます。


SSDはHDDと比較すると、最大書き換え回数が低いというのと、ランダムアクセス性能が良いという特徴がありますが、Windows 2003 Serverはデフォルトでインストールすると、HDD動作時での振舞いに最適化されているので、設定の変更が必要となります。

というわけで設定内容は、SSDの場合は意味がないものと、ディスクへの書き込みを極力抑えるという変更がメインです。今回はWindows 2003 Server用で設定&運用確認を行った項目を記載していますが、WindowsXPでも基本的は同じです。


デフラグを無効.reg

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\OptimalLayout]
"EnableAutoLayout"=dword:00000000



プリフェッチ無効化

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters]
"EnablePrefetcher"=dword:00000000



最終アクセス日時を更新しない

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"NtfsDisableLastAccessUpdate"=dword:00000001



8.3文字ファイル名の自動生成をしない

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"NtfsDisable8dot3NameCreation"=dword:00000001




一気に設定しておきたい人のために、上記の内容を纏めたものです。
下の定義をコピーして*.regファイルとして保存し、ダブルクリックすれば設定完了です。

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\OptimalLayout]
"EnableAutoLayout"=dword:00000000
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters]
"EnablePrefetcher"=dword:00000000
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"NtfsDisableLastAccessUpdate"=dword:00000001
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"NtfsDisable8dot3NameCreation"=dword:00000001





SSDへの入れ替え前後のベンチマークも取ってみました。

こちらは入れ替え前のHDDです。Maxtor 7B300R0のかなり古いHDDを使用していたので、最大でも60MB/sec程度しか出ていません。


入れ替え後のSSDはこちら。
IntelSSD320ですが、バスの速度がボトルネックになっているらしく200MB/secで頭打ちです。
HDDのように内周と内周で速度が違うということもないので、全エリアで速度は同じです。



こちらはディスクの空き容量です。
80GBのSSDを購入しましたが、Cドライブは基本的にOSしか入ってないのでスカスカです。




今回のSSD入れ替えの目的は、速度向上ではなく消費電力の削減なので、ベンチマーク的には十分すぎるぐらいの形での向上になりました。
一方、プログラムはCドライブ以外に入っているので、体感速度は特に変わってません。
起動速度は速くなった気もしますが、そもそも24時間付けっぱなしでほとんど再起動しないので、ブートが速くなっても特に嬉しくはないです…。


消費電力の削減については、以前ざっくりと計算したので、その時のメモをリンクしておきます。
手元にエコワットなどの機器が無く結果を計測できてないので、机上の計算だけですが、興味があれば参考にしてください。
 HDDをSSDに交換した際に,電気代の節約効果


今回の購入時点でIntel 320シリーズのSSDは、現行モデルではなく型落ちだったのですが、消費電力削減が目的の場合はあえて1世代前を狙ったほうが、コストパフォーマンス的にお徳かと思います。

C#でintelのhexファイルフォーマットを解析する

C#でintelのhexファイルフォーマットの解析プログラムを作成したので,公開しておきます。

hexファイルフォーマットはアスキー形式の可変長テキストですが、シンプルな作りになっているので読み込みは簡単です。

ファイルフォーマットの詳細が知りたい場合は、以下のエントリで説明しています。興味があれば参考にしてください。
MPLABで作成されたhexファイルのフォーマットを解析する


ここで読み込んだ情報を元にPIC16F84A用のバイナリを逆アセンブルしてみる予定ですが、本クラス自体はターゲットデバイス非依存な作りです。
(pic以外用のROMデータでも解析できるはずです)


というわけで、解析処理のクラスです。

using System;
using System.Collections.Generic;
 
public class HexFileParser {
    /// <summary> hexファイル情報</summary>
    class HexFileData {
        public int    Offset  { get; set; } // オフセット   0~65536
        public int    Length  { get; set; } // データ長     0~255
        public string RecType { get; set; } // レコード種別 2byte
                                            // 00   データレコード
                                            // 01   ファイル終了レコード
                                            // 02   拡張セグメントアドレスレコード
                                            // 03   スタートセグメントアドレスレコード
                                            // 04   拡張リニアアドレスレコード
                                            // 05   スタートリニアアドレスレコード
        public string Data    { get; set; }
    }
 
    /// <summary> 開始アドレス</summary>
    public int StartAddr { get{ return startAddr; } }
 
    /// <summary> 終了アドレス</summary>
    public int EndAddr   { get{ return endAddr;   } }
 
    // 解析エラー情報を取得する
 
    public List<string>ParseErrorInfo { get{ return parseErrorInfo;} }
 
    public string DefaultValue { get; set; }
 
    /// <summary>開始アドレス</summary>
    private int startAddr;
    /// <summary>終了アドレス</summary>
    private int endAddr;
 
    /// <summary> Hexファイル情報リスト(元ファイル1行で1データ)</summary>
    private List<HexFileData> hexFileList = new List<HexFileData>();
 
 
    /// <summary>解析エラー情報</summary>
    private List<string> parseErrorInfo = new List<string>();
 
 
    //*********************************************************************
    /// <summary> コンストラクタ
    /// </summary>
    //*********************************************************************
    public HexFileParser() {
        DefaultValue = "00";
 
        clearParseInfo();
    }
 
 
    //*********************************************************************
    /// <summary>   解析情報をクリアする
    /// </summary>
    //*********************************************************************
    public void clearParseInfo() {
        startAddr    = 0xFFFF;
        endAddr      = 0x0000;
        parseErrorInfo.Clear();
        hexFileList.Clear();
    }
 
    //*********************************************************************
    /// <summary> 指定された行のデータを解析する
    /// </summary>
    /// <param name="lineNo">行番号(エラー出力用)</param>
    /// <param name="inData">hexファイル行データ</param>
    //*********************************************************************
    public void parseLine( int lineNo, string inData ) {
        string startMark;       // 1byte    スタートマーク(":"固定)
        string byteCount;       // 2byte    データ長
        string offsetAddress;   // 4byte    データオフセット(開始位置)
        string recType;         // 2byte    レコード種別 00:データ
        string data;            // variable データ
        string checkSum;        // 2byte    チェックサム
 
        //--------------------
        // レコード長チェック
        //--------------------
        if ( inData.Length < 11 ) {
            parseErrorInfo.Add( "行:" + lineNo + " レコード長が不正です" );
            return;
        }
 
        //------------------------------------
        // 入力レコードを、フィールド分割する
        //------------------------------------
        startMark     = inData.Substring( 0, 1 );
        byteCount     = inData.Substring( 1, 2 );
        offsetAddress = inData.Substring( 3, 4 );
        recType       = inData.Substring( 7, 2 );
        data          = inData.Substring( 9, inData.Length - 11 );
        checkSum      = inData.Substring( inData.Length - 2 );
 
        //--------------------
        // データチェック
        //--------------------
 
        // スタートマーク
        if ( !startMark.Equals( ":" ) ) {
            parseErrorInfo.Add( "行:" + lineNo + " スタートマークが':'では有りません[data=" + startMark + "]" );
            return;
        }
 
        // バイト数
        if ( !isHexaDecimal( byteCount ) ) {
            parseErrorInfo.Add( "行:" + lineNo + " バイトカウントが16進文字列では有りません[data=" + byteCount + "]" );
            return;
        }
 
        // オフセット
        if ( !isHexaDecimal( offsetAddress ) ) {
            parseErrorInfo.Add( "行:" + lineNo + " オフセットアドレスが16進文字列では有りません[data=" + offsetAddress + "]" );
            return;
        }
 
        // レコード種別
        if ( !isHexaDecimal( recType ) ) {
            parseErrorInfo.Add( "行:" + lineNo + " レコード種別が16進文字列では有りません[data=" + recType + "]" );
            return;
        }
        if ( !recType.Equals( "00" ) && !recType.Equals( "01" ) && !recType.Equals( "02" ) &&
             !recType.Equals( "03" ) && !recType.Equals( "04" ) && !recType.Equals( "05" ) ) {
            parseErrorInfo.Add( "行:" + lineNo + " レコード種別が00~05以外の値です[data=" + recType + "]" );
            return;
        }
 
        // データ
        if ( !isHexaDecimal( data ) ) {
            parseErrorInfo.Add( "行:" + lineNo + " データが16進文字列では有りません[data=" + data + "]" );
            return;
        }
 
        // チェックサム
        if ( !isHexaDecimal( checkSum ) ) {
            parseErrorInfo.Add( "行:" + lineNo + " チェックサムが16進文字列では有りません[data=" + checkSum + "]" );
            return;
        }
 
        //------------------------------
        // チェックサムの整合性チェック
        //------------------------------
 
        // スタートマークの次の位置(2byte目)~チェックサムの手前までを合算する
        uint calcValue = 0;
        for ( int loop = 1; loop < inData.Length - 2; loop +=2 ) {
            string curValue = inData.Substring( loop, 2 );
            calcValue += (uint)Convert.ToInt32( curValue, 16 );
        }
        calcValue = (~calcValue) + 1; // 2の補数を取る
        calcValue &= 0x000000FF;      // 下位16ビット分だけを抽出
        if ( Convert.ToInt32( checkSum, 16 ) != calcValue ) {
            parseErrorInfo.Add( "行:" + lineNo + " チェックサムが一致しません[calc=" + calcValue.ToString() + ", data=" + checkSum + "]" );
            return;
        }
 
        // 解析した値を覚える
        int start = Convert.ToInt32( offsetAddress, 16 );
        int len   = Convert.ToInt32( byteCount, 16 );
        storeValue( start, len, recType, data );
 
    }
 
 
    //*********************************************************************
    /// <summary> 指定されたアドレスの値を取得する
    /// </summary>
    /// <param name="address">  取得対象アドレス</param>
    /// <returns>               メモリ値</returns>
    //*********************************************************************
    public string getValue( int address ) {
        // 指定されたアドレスに対する定義を探す
        HexFileData targetData = null;
        foreach ( HexFileData curData in hexFileList ) {
            if ( curData.Offset <= address && curData.Offset + curData.Length > address ) {
                targetData = curData;
                break;
            }
        }
 
        // 指定されたアドレスの定義がない場合は、デフォルト値を返す
        if ( targetData == null ) {
            int wordLen = DefaultValue.Length / 2;  // 1ワードの長さを求める
            int wordPos = address % wordLen;        // 要求されたアドレスが、ワード中のどこにあたるかかのoffsetを求める
 
            return DefaultValue.Substring( wordPos * 2, 2 );
        }
 
        // 定義がある場合は、ファイルの内容を返す
        int pos = address - targetData.Offset;
        return targetData.Data.Substring( pos*2, 2 );
    }
 
 
    //*********************************************************************
    /// <summary>解析した文字列を保存する
    /// </summary>
    /// 
    /// <param name="recType">      レコード種別</param>
    /// <param name="data">         データ(空文字列の可能性もあり</param>
    //*********************************************************************
    private void storeValue( int start, int len, string recType, string data ) {
        // データレコード以外は保存しない
        if ( !recType.Equals( "00") ) {
             return;
        }
 
        //-------------------------------------------------------
        // このデータによって開始・終了アドレスが変わるかチェック
        //-------------------------------------------------------
        if ( start < startAddr ) {
            startAddr = start;
        }
        if ( start + len > endAddr ) {
            endAddr = start + len;
        }
 
        //-------------------------------------------------------
        // 追加すべきデータをセット
        //-------------------------------------------------------
        HexFileData hexFileData = new HexFileData();
        hexFileData.Offset  = start;
        hexFileData.Length  = len;
        hexFileData.RecType = recType;
        hexFileData.Data    = data;
 
        //-------------------------------------------------------
        // 一覧に追加
        //-------------------------------------------------------
        hexFileList.Add( hexFileData );
    }
 
    //*********************************************************************
    /// <summary>指定された値が16進文字列であるかをチェックする
    ///          (= '0'~'F'のみで構成されているか)
    /// </summary>
    /// 
    /// <param name="inData">   チェック対象データ</param>
    /// <returns>true:16進文字列である, false:16進文字列ではない</returns>
    //*********************************************************************
    private bool isHexaDecimal( string inData ) {
        foreach ( Char data in inData ) {
            if ( ( data >= '0' && data <= '9' ) ||
                 ( data >= 'A' && data <= 'F' ) ) {
                continue;
            }
 
            // "0-9A-F"以外->値がおかしい
            return false;
        }
 
        // チェックOK
        return true;
    }
}



このクラスの利用側は以下のような感じになります。

    string fileName ="c:\\test.hex";
    public HexFileParser parser = new HexFileParser();
 
    // デフォルト値の指定(pic16F84Aの場合"0x3FFF"だがlittle endianなのでFF3Fになる)
    parser.DefaultValue = "FF3F"; 
 
    using ( StreamReader reader = new StreamReader( fileName ) ) {
        int lineNo = 0;
        //-------------------------------
        // 全ての行を読み込むまで繰り返し
        //-------------------------------
        while ( true ) { 
            string line = reader.ReadLine();
            if ( line == null ) {
                break;
            }
 
            //-------------------------------------
            // Hexファイルのフォーマット解析を行う
            //-------------------------------------
            parser.parseLine( lineNo, line );
 
            // 解析したデータを画面に表示
            textBox1.AppendText( line + Environment.NewLine );
 
            lineNo++;
        }
    }
 
    //------------------------------------
    // hexファイルを元に,16進ダンプを行う
    //------------------------------------
    txtHexDump.Text = "";
 
    int loopCol = 0;
    int startAddr = parser.StartAddr;
    int endAddr   = parser.EndAddr;
    for ( int curAddr = startAddr; curAddr < endAddr; curAddr++ ) {
        string mCode = parser.getValue( curAddr );
        // 16進ダンプ値を表示
        textBox1.AppendText( mCode + " " );
 
 
        // 16byte単位で改行を入れる
        if ( loopCol++ >= 16 ) {
            loopCol = 0;
            textBox1.AppendText( Environment.NewLine );
        }
    }



次回は、このプログラムを元にPIC16F84のバイナリを逆アセンブルしてみます。
PIC16シリーズのバイナリを逆アセンブルする