/*
 * 解説しよう @ A048 of ArmUZK
 *   by uratan! 2008.10.7
 *     (いや ただのよもやま話になってしまうかもしれんが)
 *     revised 2015.10.24
 */

    「プログラミングに完成はない。ただリリースがあるだけだ」
        ……ということなので、リリースします。
        (予想では後 3つくらい大バグがありそうですが)
    *----------------------------------------------------------------+
    |これは ArmUZK のプログラムコードに関する解説です。詳しくはこちら|
    | http://aid.her.jp/uratan/ArmUZK/ をご覧ください。              |
    *----------------------------------------------------------------+


/*
 * 目次
 *  ファーム構造図
 *  ファイルごとの解説
 *    Makefile, link.cmd, LPC214x.h, Startup.S, common.h,
 *    common.c, rprintf.c, swi_handler.S, irq.h, irq.c,
 *    main.c, timer0.c, uart1.c, pdown.c, usb.h,
 *    dscr_h.S, usbhw.c, usbcore.c, usbjmptb.h, periph.c,
 *    iap_fup.c
 *  A047 --> A048 の変更に関して
 *  LPC2148 に関して
 *  ソースファイルの履歴管理
 *    (山本夏彦語録)
 *  vim を使え
 *  プログラムの記述と統一されたスタイル
 *    (国際邪悪な C コードコンテスト)
 *  vim を本来の形で使うための環境設定
 *  コマンドプロンプトで生活するうえでの便利な tips
 *  cwd (current working directory、現在の作業ディレクトリ)という考え方
 *  UnxUtils の各種コマンドと unix 的なテキストの考え方
 *  diff を使え
 *  HEX コンペア
 *  最近お気に入りの編集テクニック
 *  コーディングと将棋
 *  ソースコードの見栄えの話
 *  
 *  コマンドラインのご褒美
 */


/*
 * ファーム構造図
 */
    まあこんな感じです。
        (まあケースバイケースではありますが)私はトップダウンが好きです。
         こういった図も、解説も、C の記述も。そういう意味ではプログラムの
         記述は本を作る感じですかね。表題があって、目次があって・・・みたいな。

       ArmUZK source file structure
     +------------------------------------------------- Makefile, link.cmd --+
     |                                                                       |
     |        main.c                     +----------+------------------------+
     |                                   | dscr.h.S |                        |
     |                                   +--+-------+--+     periph.c        |
     |                                      |  usb.h   |                     |
     +----------+                           | usbcore.c| usbjmptb.h          |
     |          +-----------------+---------+----------+-+----------+--------+
     | iap_fup.c|    rprintf.c    | pdown.c |  usbhw.c   | timer0.c | uart1.c|
     | Startup.S+--------------+  +---------+------------+----------+--------+
     |          | swi_handler.S|   common.h,  irq.c,  irq.h,  common.c,      |
     +==========+==============+=============================================+
     |        ARM7 core        |        LPC2148.h   (HARDWARE LAYER)         |
     +-------------------------+---------------------------------------------+


/*
 * ファイルごとの解説
 */

●Makefile
    WinARM のサンプルコードの Makefile から始めて、邪魔な記述、私には不要と
    思われるな記述をとっぱらってシンプルにしました。ARM/thumb 混在モードは、
    いろいろ面倒が増えそうなので廃止しました。(thumb の方が 速度はやや落ちる
    みたいですが、コード量が減り、消費電力も小さくなるらしいです)
    私は uart-debug オンリーでデバッガ−とかも使わないので、その関係も 極力
    シンプルにしました。

    「-D ArmUZK」は、いただいたソースをほぼそのまま使っているもので、
    私の加えた変更点を区別するためにつけてあります。
    「-D gDEBUG」は、global-DEBUG の意味で、これを 0 にすると uart-debug
    メッセージを一律に禁止します。

    また「-DLPC_H2148」の有無によって、LPC-H2148 用の処理と専用基板用の処理を
    を切り替えます。本切り分けは、ハードウェアの違いと LPC2148/2141 の違いを
    含みます。

    これらを Makefile にコンパイルオプションとして書くワケは、
        1) C にも asm にもかけたいから
        2) *.h に記述すると、そのヘッダーをちゃんと #include しているか
           気にしなければいけないから
        3) 他のオプションとはちょっと違うんだよ、という意思表示
    です。

    Makefile 中に記載のオプションを変更した場合には、一度 "make clean" して
    すべてのソースを再コンパイルする必要があります。

●link.cmd
    これも WinARM のサンプルコードの LPC2138-ROM.ld から始めて、邪魔な記述、
    私には不要と思われるな記述をとっぱらってシンプルにしました。
    巨大なコメントは、LPC2148 の動作モード毎のメモリ使用場所をまとめたもの
    です。LPC214x には、FLASH 書き換えのための隠しプログラムが仕込んであり、
    ハードリセット時の P0.14 のレベルをみてこれを切り替えます。(FlashMagic は
    これを使って FLASH に書き込むわけです)
    これは ISP (In System Programming) とか Boot Loader とか呼ばれてます。
    普通あまりないですが、特定のメモリの内容を、ハードリセットをまたいで
    利用したい場合などは、ISP が使用するメモリ領域を避ける必要があります。

    また、ユーザープログラム実行中に FLASH を書き換えるために、Boot Loader
    プログラム内のサービス関数を呼び出して使用することが可能です。これは
    IAP (In Application Programming) と呼ばれるらしいです。

    さらにユーザープログラム実行中に、RealMonitor と呼ばれるソフトデバッガ−を
    使うこともできるみたいです。もしこれらを使うつもりならば、これら
    これらプログラムの使用領域を避ける必要があります。

    ちなみに、LPC2148 内部には 512kB の FLASH チップが 1枚だけ載っていて、
    Boot Loader プログラムもユーザープログラムも同チップに同居していると
    最初思っていたのですが、どうやらユーザー用の 512kB のチップとは別に
    Boot Loader 用の 12kB のチップがあるように思われます。
    LPC2148 ではメモリマップ上では重ねられるため、ユーザーが使えるのは
    500kB になりますが、LPC2141 など他のモデルでは、ユーザー FLASH の容量は
    目減りしない、と書いてありました。

    ・ファーム書き換え機能のためにセクションを増やしました。
    ・(A046) LPC2148/2141 の切り替えが難しそうなので、狭い LPC2141 の
             設定を使うようにしました。

●LPC214x.h
    これは WinARM のサンプルコードの LPC214x.h ほぼそのままです。
    私が付け加えた変更は ArmUZK で切り分けてあります。
    A039 での LPC214x.h には USB の DMA 関連のレジスタ定義の括弧の囲い方に
    間違いがあることがわかりましたので使用する際はご注意ください。
        (A041 で直しました)

●Startup.S
    これも WinARM のサンプルコードの Startup.S から始めてます。スタックの
    設定、C 言語変数領域のゼロクリア、C 言語初期値付き変数の初期値の設定と
    C 言語が走るための必要最低限のみとしてあります。

    もともとのポリシーは、
        ・CPU の動作モードの初期化もここでやっちゃって隠蔽してやるぜ
        ・ARM も thumb もケアして、割り込み処理中に割り込める「割り込みネスト・
          多重割り込み」もサポートしてるぜ、おまけに C でかく割り込みハンドラは
          普通の関数でいいぜ。
    だと思うのですが、私のポリシーは、
        ・レジスタをいじる処理は C レイヤーに一元化したほうが読みやすいし
          安全だろ。
        ・thumb は捨てたし、多重割込みは使わないし、割込みは VIC を素直に
          使うからいらね。
    なのでそのように削りました。
    (なので割り込みハンドラ関数には __attribute... をつけなければなりません)

    おまけとして、デバッグ用に、全メモリを固定値で埋めておいたり、スタック
    領域をわかるようにマーキングするコードを追加しました。uart-debug で、
    ターミナルから 'D' を送信するとメモリダンプする機能(main.c 内)とあわせて、
    スタックが足りているか、とかチェックします。

    ファーム書き換えのために、FLASH 上のプログラムを RAM 上に転送して
    実行する機能も付加されました。

●common.h
    どういう区別なのか、と問われるとなかなか一言では言いがたいのですが、
    わたしの中で、「これはこのシステムではあたりまえの定義だ」と考える
    ものをここにまとめてます。この common.h は一番最初に #include され
    なければなりません。もっとも優先順位が高いのです。あたりまえなので
    どのソースからも #include されなくてはなりませんし、あたりまえのように
    使ってよいのです。
    ここに全体にかかるオプションも記述することもあります。(あんまり
    カテゴリー別に *.h を作るのもアレなので、行き場のない定義をここに
    まとめる、という意味もちょっとだけありますが)

    私は関数の extern は個別の *.c 内に列挙する主義(後述)なのですが、
    あたりまえに使える関数に関してはこの common.h に書きます。

    uart-debug 用の入出力関数はここに含まれます。
    CPU の割り込みマスクフラグをいじる関連も、ここに含みます。
    PLL の初期化関数は、システムスタート時とパワーダウンからの復帰時に
    2個所から呼び出す必要があるので、共有するためにここに置きます。

    あと、消費電力をかんがみ、CPU-CLK も PERIPHERAL-CLK も 24MHz を選択
    しています。評価ポイントが難しいですが、それでも EZ-USB 内蔵の 8051
    よりかは CPU 単体としてはうんと早いようです。

    消費電力といえば、調査結果をコメントとして書いてます。ソース中に書く
    ことで、読者(自分)への注意喚起になりますし、ソースのバージョン管理と
    ともに時間軸の情報が累積されます。
    つまり「この調査いつごろやったんだっけ?」「A030->A031 でコメント
    付いてますから そのころですね。」となるわけです。
    調査のやり方を、ソースに痕跡(#if 0)として残せればよりグッドでしょう。

●common.c
    common.h と同じポリシーで関数を置くファイルです。関数の頭に付いている
    cm_ は common.c に属する関数だよ、という意味です。こういうカテゴリーを
    表す prefix (接頭語)は大変重要なのでつけるようにしましょう。

    uart-debug で割り込みを使わないのは、
        1) デバッグ用の仕込みはなるべくシンプルでないと、策士 策に溺れる
           時があるから
        2) バッファリングするとプログラムの進み具合と文字の出力に時間の
           ずれが発生し、デバッグに支障をきたすことがあるから
    です。
    12文字表示すればおおむね 2msec だ、とか、ここからここまで 6文字
    表示してるから 1msec だ、とか時間経過に目安をつけるためにも使えます。

    なお、gDEBUG が 0 の時は関数の存在自体を削除します。これはリンクエラーを
    起こして間違いを知らせるためです。

●rprintf.c
    これも WinARM のサンプルコードの rprintf.c ほぼそのままです。
    私が付け加えた変更は ArmUZK で切り分けてあります。
    これも、gDEBUG が 0 の時は関数の存在自体を削除します。

●swi_handler.S
    これも WinARM のサンプルコードの swi_handler.S ほぼそのままです。
    オプションを選ぶマクロは、私のシステムでは固定なので Makefile 中に
    コマンドライン与えるのでなく、ここに ArmUZK で書きます。

    ここには CPU の割り込みマスクフラグをいじる機能を、SWI (Software Interrupt)
    を経由して行う関数が記述してあります。中身は良く分かりませんが、とりあえず
    問題ないみたいです。
    WinARM のサンプルコードに含まれる interrupt_util.c では同機能を無理やり
    C で書いてありますが、こちらの方が自然だと思いこちらを採用しました。

    最近のパイプラインで命令を処理する CPU だと、周辺機器側で割り込みを禁止・
    許可しようとすると、実際のレジスタが書き換えが遅れ、効果がでるまで数命令
    先まで実行したりするかもしれないので CPU の内部フラグで全体的に禁止を
    かけた方が確実(な はず)です。

●irq.h
    これも WinARM のサンプルコードの irq.h ほぼそのままです。LPC2148 の
    VIC (Vectored Interrupt Controller) に関連する定義です。「割り込み
    ネスト・多重割り込み」に関する部分は不要なので ArmUZK で切りました。

●irq.c
    これも WinARM のサンプルコードの irq.c ほぼそのままです。
    LPC2148 の VIC (Vectored Interrupt Controller) を使うための関数群です。

    uninstall_irq() は使ってないのでまあいいのですが、最後で、
    /* Enable Interrupt */ しているのが気になります。

●main.c
    一見複雑に見えますが、流れはとてもシンプルです。CPU に近いところから
    順番に足場を固めるようにシステムの初期化を行います。

    あちこちのモジュールで共有するレジスタ PINSELx と FIOxDIR と PCONP に
    関しては、以下のポリシーで運用します。(一部例外あり)
        ・ここで all 0 に初期化しておき、モジュールごとに *初期化ルーチン*で
          PINSELx |= (xx<<nn); して自分のピンの機能を切り替える。
    このリード・モディファイ・ライトに排他制御をかけたくないこと、他のために、
    初期化時は割り込み禁止状態をキープします。

    たたき台にした AN10420 virtual COM port サンプルでは、USB の処理は
    基本的に割り込みタスクで行うイメージの作りですが、本プログラムでは
    通常タスクがメインで処理する、割り込みタスクは影に隠れてハードウェアの
    アシストをする、みたいなイメージになります。

    未使用のピンがオープンのまま入力であると無駄に電力を消費するらしいので、
    関数 set_unwired_io_as_output() にて出力設定にしています。(今ひとつ
    美しくない)
    出力がショートしたりするとまずいので、本処理は LPC-H2148 では行いません。
    「ハードウェア結線」が確定している専用基板でのみ有効にします。

●timer0.c
    あえて解説するまでもない内容ですが・・・。
    自分の回路に PCONP レジスタでクロックを供給して使う、のがこのシステムの
    ポリシーです。
    各種設定を行う場合には、(リセット初期値が停止であっても) 回路を止める
    記述を置く、のは私のくせです。
    タイマー等を使うときに、分周比をそのまま設定すればいい場合と、0 を含めて
    (分周比-1) を設定する場合がありますが、この周辺回路は後者のようです。

●uart1.c
    レジスタアクセスは WinARM のサンプルコードの uart.c から、全体の構造は
    EZ-USB UZK で書いた uart1.c から持ってきて書き上げました。

    Fractional Divider とかいうやつを使うとボーレートの誤差を小さく
    できるのですが、面倒くさくて使っていません。PCLK があんまり小さいと、
    高速ボーレートでの誤差が大きくなるかもしれません。

    User Manual には、ハードウェア FIFO は必ず有りで使え、みたいなことが
    書いてありましたが、無視して使ってません。ソフトウェア FIFO を
    実装していますので。

    USB でもそうですが、受信割込みはデータが来たときに起こります。なので
    割り込みハンドラのジョブとしては、受け取ったものをバッファに保存する、
    という単純なものになります。
    一方送信割込みは、(先のデータの)送信終了を知らせます。割り込みハンドラの
    ジョブの基本は、「割り込みが来たら次のデータ送信する」なのですが、以下の
    点を考慮する必要がありやや複雑です。
        ・一番最初のデータを送信*開始*する動作は割り込みでは処理できない
        ・一番最後のデータを送信終了を知らされても次のデータはない
    なので変数 ti1_will_come を使って、一連のデータ転送を行っている最中なのか、
    いくら待っても割込みは来ないのか、をモード管理します。

    割り込みハンドラと通常ルーチンでたくさんの変数を共有してますので、
    割り込み禁止による排他制御が大活躍ですね。

    割り込みハンドラの最後で、意図しないステータスになったら無限ループして
    フリーズするようにしてあります。これは、開発者としては異常がはっきり
    分かってよいのですが、半面 開発者以外の立場に立つとよろしくない場合が
    あります。それは、ごまかしごまかしでも動きつづけた方がバグとばれない、
    つまりクレームになりにくいからです。

●pdown.c
    LPC2148 をパワーダウンさせるサンプルはあまり一般的ではないため、かなり
    独りよがりに書きました。

    まず wake-up 要因は、RxD1 入力を PINSELx で切り替えて使います。wake-up
    信号に外部からの入力を使うのは至極当然なわけで、これは一見なかなかハード
    ウェアの設計がよい。
    ・(A046) 専用基板では EINT3 を使うように戻しました。深い意味はありません。

    次に少し飛んで PCON に書き込むところ。細かいタイミングの話になりますが、
    以下の場合にハードウェアがどういう動きをするのかをよく押さえることが
    重要です。

        パワーダウンを指定する際に、すでに「起きろ」条件が成立していた
        場合どうなるか?

    たとえば、一旦かならずパワーダウンし、即座に起き上がるハードもあれば、
    パワーダウンそのものを中断するハードもあり、LPC2148 は後者のようです。

    なので wake-up してきたときに、PLL が停止している場合と PLL が停止して
    いない場合があります。PLL 初期化サブルーチンを呼び出すと、必ず PLL を
    再調整してしまい、PLL を停止していないためせっかく安定しているクロックを
    一度スローダウンさせることになります。CPU がスローダウンするのはまだしも、
    外部との通信に使っている USB クロックを必要がないのにスローダウンするのは
    気持ちが悪いですよね。
    で、いろいろ試行錯誤した結果、PLL のロックステータスを見ることで PLL の
    状態が取得できそうなので、そのような記述にしました。

    なので、パワーダウンしようとした時にすでに「起きろ」要件が整っていた場合は、
    何事も無かったように通り抜ける、関数になっています。
    ただし本システムでは、割り込み禁止して 3msec も時間をつぶしているので
    いずれにせよ uart1 受信データはロストしてるんですけどね

    この 3msec 待ちは、USB 割り込みで USB-Suspend を検出してから、実際に
    USB_need_clock が 0 になってパワーダウン可能になるまでの遅延(2msec) を
    待つため(*1)と、uart1 で送信中のデータがあった場合に送信途中でクロックが
    変化しないため、に設けてあります。(9600bps なのでおよそ 1msec 必要)
        (*1) 待たないと寝ないで起きてしまう。

    先に「wake-up 要因を PINSELx で切り替えて使うのがうまい」と書きましたが、
    以上のように「寝ようと思ったら寝なかった」モードが存在するので、システム
    として「パワーダウンに入るときに絶対通信していない」と規定できないと
    すると、RxD1 を切り替えてしまっている間は明らかに受信データを失い、実は
    うまくなかったりするわけです。
        (UZK ではここは規定しません。問題が起きないように使ってください)

    あと、PINSEL0 の扱いは、これでは 20点です。100点な記述は以下のような
    ものです。
        ・PINSEL0 の該当部分の設定を変数にバックアップしておき、wake-up 後は
          もとの設定値をリカバーする。

    割り込みの禁止と再許可も、よくよく見ると IneEnable() ではなくて
    IntRestore() を使ってますよね。「もとに戻す」記述であることで、
    元の状態が禁止でも許可でも通用するわけです。

●usb.h
    USB 規格、USB プロトコルに関連した定義です。FreeBSD(元をたどれば
    NetBSD か?)の記述にならって命名してあります。

●dscr.h.S
    USB の各種ディスクリプタの記述です。
    行を追加さえすれば長さを自動で計算してくれる点がたいへん気持ちよいため、
    アセンブラで書きます。(ConfigLength とか ReportDscr1Len とか)
    これらのディスクリプタを struct 型定義する目的は、C で要素を番号でなく
    名前で参照できることと、要素の追加・サイズの変更などで型を差し替えると
    ソース全体が修正できること、だと思いますが、
    そもそも USB 規格できっちり定められているので定義が変化することはなく、
    言語での記述上で型を変えたら変わるように書く必要もないはずなので。

    このファイルが *.h.S になっているのは、*.S としてアセンブルされて
    ディスクリプタを生成すると同時に、*.h として #include し、各種マクロ定義
    を C と共有するためです。なかなかいい考えでしょ? プリプロセッサ大好き。

    各種定数を C と共有するためには、以下の 3つの手法があります。
        1) マクロ定義を共有する
           (たとえば DSCR_MPSIZE_EP123 in periph.c)
        2) アセンブラのラベルの中身を共有する
           (たとえば bcdDevice in main.c)
             (これは gcc では定数と扱われたり、変数と扱われたりするみたい)
        3) ディスクリプタ−の内容を共有する
           (たとえば if(USB_ConfigDescriptor[7] & UC_SELF_POWERED) in usbcore.c)

    これまた一言では区別を言えないのですが、なるべく 1) は使わない方針です。
    コンパイルオプションと、配列の大きさを宣言するために定数である必要がある
    DSCR_MPSIZE_EPxx と、関数の引数にたくさん使いそうな DSCR_ADDR_EPnn だけに
    とどめてます。

●usbhw.c
    USB 回路のレジスタに実際に触る関数群をまとめてあります。hw は hardware の
    略だと思われます。アプリケーションノートの AN10420 virtual COM port
    サンプル の usbhw.c から始めて、大幅に手を入れました。
        (ちなみに後続の AN10717 には、usb サンプルのより新しいバージョンが
         入ってます)

    大きな変更は以下の通りです。

        1) UDI_CCEMTY_INT など、使う前にクリアするポリシーに変えた
        2) ArmUZK では、割り込みハンドラからも通常タスクからも呼び出すので、
           割り込み禁止による排他制御を加えた。
        3) 割り込みハンドラ内での DEV_INT_STAT の扱いの各種問題を修正した。
        4) 極力シンプルになるよう いろいろ考えた。
        5) ふさわしくない名前を変えた。

    レジスタのビットマップのマクロ定義が頭にずらずら書いてあって見にくい、と
    お思いでしょうが、これら定義は他のソースと共有しないのでこれでいいのです。
    共有するものは、一箇所直せば全部が直るように *.h で共有すべきですが、
    共有しないものはいちいち *.h に置く必要はないのです。私は こういった
    共有が少ない、ソースごとの独立性の高いものがよいプログラムだと考えます。
    extern をいちいち *.c に書くのも、(C 言語的にはやばいといわれますが)
    他ファイルとのこんがらがり具合を常に意識するためにやっています。
      (common.h.common.c は特別です、これは「あたり前」ですから)
    もちろん一旦共有が必要、となったら、すかさず *.h を作ります。ここいら
    へんの手間を惜しんでコピペですませたりすると後々はまります。

    「3) 割り込みハンドラ内での DEV_INT_STAT の扱いの各種問題」について補足
    します。
    このレジスタは各種割り込み要因(終了報告)を保持しますが、ビットごとに
    オーナー(管理人)が異なります。割り込みハンドラが操作してよいのは自らが
    応答する DEV_STAT_INT, FRAME_INT, ERR_INT, EP_SLOW_INT ビットだけで、
    EP_RLZED_INT, CCEMTY_INT, CDFULL_INT ビットの状態は変えてはいけません。
    しかしながら元の記述では、変数 disr で受けた DEV_INT_STAT の内容を
    そのまま DEV_INT_CLR に書き込んで 割り込みハンドラを終了するため、
    disr に読み込んだ段階で 1 が立っているビットはクリアされてしまいます。
    通常タスクから protocol engine にコマンドを送って CCEMTY_INT を待っている
    時に勝手にクリアされたらまずいですよね、これが第一の問題。

    次に DEV_STAT_INT, EP_SLOW_INT ビットはこのビットの向こうにさらに細かい
    割り込み要因があってこれらを合成したものなのですが、この合成方法によって
    クリアの様式が異なり、これの対応がされていないというのが第二の問題です。

    EP_SLOW_INT ビットは EP_INT_STAT をクリアした後でないとクリアされません
    ので、後クリアします。これは正しい。
    DEV_STAT_INT ビットはハードウェアの都合で要因をロストする可能性があると
    いうことなので前クリアが必要らしいです。

    割り込み要因フラグはすべて「レベル」で扱って、なるべく「エッジ」では
    扱わないのが普通かつシンプルなのですが、ハード屋さんはなぜか「エッジ」が
    好きなんですよね。

    後まったく別の話として、要因フラグの前クリア、後クリアには処理時間の
    問題も関係する時があります。
    例えば FRAME_INT ですが、なにかの都合で割り込みハンドラの応答が遅れ、
    2つの要求を処理がまたいでしまった場合を考えてみましょう。下のタイミング
    チャートのように、後クリアであると FRAME_INT の要求 2つ分をクリアして
    しまい、FRAME_INT の要求回数より割り込みハンドラの応答回数が少なくなる
    可能性が高まります。

        FRAME trg  __|________________|________________|____________ (要求:3回)

        FRAME_INT  __|~~~~~~~~|_______|~~~~~~~~~~~~~~~~~~~~|________
                     起動    ↑                応答遅れ    ↑
                     ↓     後クリア              ↓      後クリア
        USB_ISR()  ___|~~~~~~~~|___________________|~~~~~~~~|_______ (起動:2回)

    前クリアであれば応答直後にフラグをクリアしますので、この現象の起こる
    可能性は幾分か低くなります。

        FRAME trg  __|________________|________________|____________ (要求:3回)

        FRAME_INT  __|~|______________|~~~~~~~~~~~~~|__|~~~~~~~|____
                       ↑                  応答遅れ ↑       続けて起動
                       前クリア                   ↓前クリア ↓
        USB_ISR()  ___|~~~~~~~~|___________________|~~~~~~~~|_|~~~~~ (起動:3回)

●usbcore.c
    Control-Endpoint (EP0) の通信を受け持って、各種コマンドの処理、データ
    通信の処理を行います。usbhw.c と同じく、アプリケーションノートの
    virtual COM port サンプル の usbcore.c から始めて、大幅に手を入れました。

    Control-Transfer の制御をステートマシンっぽくしてみたり、
    OUT エンドポイントのフラグ制御方式を変更(後述)してみたり、
    プロトコルサポートを一部縮小したりしてます。
    SETUP リクエストパーサーのあたりは比較的そのままです。

    プロトコルハンドリングに関して、上記のように記述を削っていますので
    以下の制約があります。
        1) Configuration Descriptor が一つであること
        2) Alternate Setting を持たないこと

    uart-debug を行うためには、ちんたらメッセージを出している間なるべく
    ホストが待ってくれる必要があります。ホストへ向けての IN データの転送では、
    こちらがデータを用意するまで当然ホストは待ってくれます。(タイムアウトを
    除いて待たざるを得ません)
    ホストからやってくる OUT データの転送は、(バッファが空いていれば)ハード
    ウェアが勝手に受信してしまいます。なので、OUT データを受けるバッファの、
    「(受け取ったデータを処理したから)次のデータの受け取りが可能やで」フラグを
    必要時以外立てないようにすることで、ホストを待たせてます。このフラグを
    立てるのが CMD_CLR_BUF であり、関数 uhw_ReadEP_finish() です。

    つまり、以下のようにこのフラグを扱います。
        SETUP パケットで受信したデータを取り出してもこのフラグはほっておく。
        コマンドを吟味して、ホストからデータを送って欲しい、となったときに
        始めて「ようやっとバッファ空になったで」とフラグを立てる。

    コマンドを送ってくる SETUP パケットは規格上このフラグにかかわらず
    最優先で受信されますので問題ありません。(STALL 状態でも受信されますし)

    このようにホストを待たせることで、エラー時にうまく STALL を伝えられる
    ようにもなります。バッファを読み終わることで即座にフラグを立てる元の
    実装では、たとえば SET_REPORT クラスリクエストで、コマンドに
    間違いを発見して受け取りを拒否しようと OUT エンドポイントに STALL を
    設定しても、その時にはホスト側からは OUT 転送が終わっていて、Status の
    IN 転送に移っているかもしれません。

    ホストがいつ OUT/IN 要求(パケット)を送ってくるかはホスト任せのようです。
    例えば SET_REPORT コマンドなどで、SETUP/DataOUT/StatusIN のやり取りを
    する際に、Win2000 では、この 3つのパケットは 1msec の間隔をあけて
    発行されてました。しかしながら Mac では、続けざまにやって来てました。
        (http://aid.her.jp/uratan/ArmUZK/h2148.html にオシロ絵あり)

    期待する以外の IN/OUT 割り込みが発生した場合には、ホストのタイム
    アウトを期待し、何もしないことにしました。
    さまざまなエラーケースが考えられるため、むやみにアクションすると返って
    悪さをすることを避けるためです。

    myUDEBUG オプションは、ファイルごとの debug-uart 出力オプションです。
    ローカルオプションなので、あえてどのファイルでも同じ名前にしてます。
    ERR_DEBUG オプションは、先に述べた「調査のやり方を、ソースに痕跡
    (#if 0)として残」したものです。これでいつでも再調査できるといいですね。

●usbjmptb.h
    usbhw.c からユーザーの関数を呼び出す窓口を空けるために、関数への
    ポインターの配列を使用しました。その配列の扱いに関する定義です。
    関数の呼び出しを直接書いてもいいのですが、ちょっと FrameWork っぽく
    汎用性を高めようという試みです。
    動的に関数を登録する方式は一見おしゃれに見えますが、コードを追いかける
    際に非常に読みにくいと思いますし、登録する関数はどうせ固定なので
    これぐらいが妥当ではないでしょうか?

    接頭語はとりあえず USB_ でまとめてあります。最後の USB_N_JT は
    「テーブル個数」Number of Jump Table elements の略で、この位置に置いて
    定義値の 0,1,2,3,4,*5* が連続であることに気づきやすくします。

●periph.c
    HID デバイスとしてのクラスリクエストの解釈や、UZK のそもそもの動作の
    記述です。EZ-USB 用に書いたものを おおむねそのまま使っています。

    Endpoint の初期化は usbcore.c が行いますのでここでは行いません。
    そのために、使用する Endpoint の EndpointDescriptor へのポインタの
    リストを USB_list_of_EpDscrs に設定しておきます。

    基本的な処理は、SET_REPORT でやってきたデータを uart1 から送出すること、
    および、uart1 からやってきたデータを ep1/ep3 からホストへ渡すこと、です。
    両方が同じソースにあったりして(おまけにデバイスが 3つもあったりで)
    やや分かりにくいですが、ここいらが別物だと分かることがまず第一歩ですね。
        (http://aid.her.jp/uratan/UZK/ez-uzk.html に図解あり)

    ここまででお気づきだとは思いますが、このファームウェアは EZ-USB の
    FrameWork に似せました。というより、EZ-USB の fw.c, periph.c の
    構造がなるべくそのまま使えるように LPC2148 の FrameWork を構築したのです。

    TD_xxx() という命名も DR_xxx() という命名も GotSUD という変数名も EZ-USB の
    FrameWork よりいただきました。どなたか TD/DR の意味をお教えくださいまし。
    気になって夜も眠れません。

    uart1 の通信プロトコルにおいて、「HEAD_RESET (0xff) をもって
    通信を初期化する」というのを採用していますが、これがどうも
    パワーダウン + wakeup 時の処理に絶妙に効いてます。我ながら天晴れだ。
        1) wakeup 時、この 0xff の送信時間分だけ wakeup 動作に猶予が与えられる。
        2) uart1 からは、この 0xff はきれいに 1バイトだけ無視され、ビットずれが
           起こらず引き続くデータは化けない
        3) periphe.c 的には、この 0xff が来ないことで続くデータセットを丸ごと
           無視する。
        (http://aid.her.jp/uratan/ArmUZK/h2148.html にオシロ絵あり)
    ・(A047の頃) この 3) の私の認識は間違いで、0xff が来るとステートを
      リセットするが、0xff=>コマンド のペアをモニターしているわけでない、
      ことがわかりました。直したいなぁ。

    SET_REPORT でホストからのデータ転送終了を無限待ちしていた点は、変数
    GotCOD 変数を見てデータ転送終了イベントとして継続するように変更しました。

    従来あった UZK 制御コマンド 'K', 'M', 'C' に、ファームウェア書き換え用の
    コマンド 'E', 'W', 'R' を追加しました。ホントは VENDOR_REQUEST で実装
    したかったのですが、PC 側アプリケーションでの送信方法が分からなかった
    ため あきらめました。
    一度に渡せるデータが 8バイトのため やや時間がかかりますが、PC 側アプリの
    変更が楽ですし、これはこれでいいことにしましょう。

    ・(A047) Mac での Sleep あけに、キーもしくはマウスのどちらか一方が
      通信できなくなるという症状がでました。調べた結果、Mac が Sleep あけに
      CLEAR_FEATURE + ENDPOINT_HALT を発行する時があり(理由は不明、LPC-H2148
      でも再現)、この結果 起動された Endpoint がキャンセルされ、転送終了割り
      込みが来ないため 変数 INxBUF_is_busy[] が busy のままステートが止まる、
      という原因でした。そのため、busy 状態の変数での管理をやめ、ハードウェア
      フラグを直接状態参照するように変えました。
          (これが予想の 3つの大バグのひとつかな  (^_^;)

●iap_fup.c
    ファームウェアの自己書き換えを行う関数群です。FLASH 書き換え処理は、
    Boot Loader 内のサービス関数を呼び出して行います。(IAP)

    以下の制限条件により、メモリの扱いが少々ややこしくなっています。
        1) FLASH の、今実行しているプログラムがある領域を書き換えることは
           できない。
            ==> 「IAP 呼び出しから return してきたらプログラムが変ってた」と
                なりまずいので、自己書き換えの最後は WDT の機能を使って
                自分自身に RESET かけます。またこの処理を行うプログラム
                iap_update_on_ram() はRAM 上に転送され、RAM上から実行します。
        2) 上記 1) の処理の前には、新しいプログラムコードすべてが CPU の
           手の届くメモリ内に揃っていなければならない。
            ==> 書き換え先のコード全部を RAM 上に保持することはできないので、
                FLASH ROM を半分に分けて、後半(FL_WORKING_TOP_ADDR)をバッファ
                代わりに使います。なので、プログラムサイズは ROM サイズの
                半分までに収める必要があります。
        3) IAP での FLASH 書き込みは、最低 256バイト単位である。また書き換え
           データは RAM 上にある必要がある。
            ==> UZK 制御用の SET_REPORT を流用して書き換えコマンドを実装して
                ありますが、データサイズが 8バイトのため、256バイトたまるまでは
                RAM 上のバッファ:iap_buff に蓄積します。
                また上記 1) の処理においても、FLASH 後半に仮置きした新プロ
                グラムは一旦 iap_buff のコピーされてから IAP に渡されます。
    まとめると・・・(かえって分かりにくいですかね)
            **************                +---------------------+
            * SET_REPORT *==> iap_buff ==>| FL_WORKING_TOP_ADDR |
            *  'E', 'W'  *                +---------------------+
            **************

            **************
            * SET_REPORT * ==> copy_n_exec_on_ram(iap_update_on_ram())
            *    'R'     *
            **************

            iap_update_on_ram()
                +---------------------+                +--------------------+
                | FL_WORKING_TOP_ADDR |==> iap_buff ==>| FL_MASTER_TOP_ADDR |
                +---------------------+                +--------------------+
                    .... RESET myself by WDT


/*
 * A047 --> A048 の変更に関して
 */
    Host 側が PC でなく簡易型のもの(具体的にはこれ)の場合、受けバッファが
    8バイトしかないので こちら側が MaxPacketSize=64 だと一切コミュニ
    ケーションできませんでした。なので MaxPacketSize=8 に縮めるオプションを
    付けると同時に、各種データバッファの扱いをよかれと思う方向に少々
    修正しました。この MPS8 オプションは A048 ではデフォルトでは off なので
    A048 の動作仕様は A047 とまったく同じ(はず)です。
    ちなみに BSKM201BK では ArmUZK は keyboard だけ認識しました。


/*
 * LPC2148 に関して
 */
    OLIMEX の web ページにも書いてありますが、ARM core のマイコン、初心者には
    お勧めできません。
    おまけに NXP のこれ、内蔵周辺機器がいままで使ってきたマイコンと違って
    かなりクセが強いと思います。
    おまけに www.nxp.comwww.standardics.nxp.com で置いてある資料の
    バージョンの新旧が違ったり、あったり無かったりしますので両方を捜索
    しなければならなりません。で同じ内容なのにファイル名やバイナリの中身が
    違います。
    おまけに、英語が格調高く文学的(?)で、今ひとつはっきりしない表現が
    多いように思います。
    User Manual の USB の項目なんて知りたいことがちっとも書いてありません。


/*
 * ソースファイルの履歴管理
 */
    開発は独りでやっているのですが、ソースの履歴管理もやってます。
    やり方は、バージョン番号を打って手作業で差分をログにつけ zip に
    まとめる、というものです。

    ロッククライミングで、定期的に岩になんか打ち込んで安全確保をするじゃ
    ないですか。あんな感じで、何かあってもある特定の場所にいつでも戻れる
    ことが保証されていると、いろいろ冒険しやすくなります。
    また、基準位置があることで、「A018 からこれとこれを変えた」と自分の
    立ち位置の把握がしっかりします。道に迷ったとき地図で確認しますが
    一番難しいのは自分が地図の中でどこにいるか(、と方角)、なんですよ。
    さらに その特定の場所に呼び名(バージョン番号)が付くことで、「A029 から
    この動作がおかしい」などプログラムのハンドリングも楽になります。
        (いちいち名前を付けるほどわずらわしいことはないですよね。
         これにせよ、関数・変数名にせよ)

    履歴管理のログは「あれとこれを変えた(はず)」などと記憶に頼らず、
    diff でソースの差分をとってそれをすべて吟味します。これで変更の
    記録もれがなくなると同時に、自分の立ち位置の再確認ができます。

    逆に言えば、ファイルの変更・バージョンアップにはテーマがあるんです。
    「A024 からこれを変えて A025 にしよう」の「これ」です。機能を追加
    するとか、問題を直すとか。
    「あれとこれとそれと、あ、これも変わってたわ」というように、バージョン
    アップ毎のテーマが多くなると失敗のもとです。小刻みにバージョン登録
    します。
        (もちろん「こだわらず修正するのがテーマ」の時もあります。とくに黎明期)


 - * - * - * - * - * - * -


    山本夏彦の言葉に、
        「言葉は電光石火のごとく伝わるもので、それは
          聞き手がその言葉を持っているからである」
    というのがあります。

    つたない C 言語で書くプログラム、なるべく言葉を持っていない人にも
    分かるように書きたいと思ってはいるのですが、未来の自分に宛ててが
    精一杯なのですが、いかがだったでしょうか?
      (といいながら、解説を別ファイルに書いているのは矛盾?)


とりあえず、こんなところで。



 - * - * - * - * - * - * -

    *------------------------------------------+
    |このへんからよもやま話っぽくなっていきます|
    *------------------------------------------+


/*
 * vim を使え
 */
    まあ四の五の言わんとこれ
        http://www.amazon.co.jp/dp/4873110831/
    「入門 vi」を読んで vi をマスターしてください。
    テキストをいじる世界が変わりますよ。いままで自分自身がテキスト編集の
    最下層で ちまちま文字を打っていたのが、vi という秘書/下請けができて
    vi に「これ変更しといて」と任せられるようになる感じかな。
        (しかもホームポジションから手を動かさなくてもいい)

    たとえば C でプロトタイプ宣言用の関数のリストを作る場合、私はこの
        vim-anim1.gif (108kB)
    ようにやっています。
    プロトタイプ宣言は私にとっては必要なときにいつでもさくっと作成できる
    もの(しかも完璧)なのである意味どうでも良いものなのです。

    また vi で最も強力なコマンドが '*'(そのワード検索、VIM の機能) と
    '.'(繰り返し) だと思うのですが、reg-naming.txt を作成する過程として
    レジスタ名とアドレスのみのリストを作成する過程でその強力さを
    お見せしましょう。
        vim-anim2.gif (445kB)
    もちろん ":%s/..." の全置換を駆使してやってもいいのですが、こういうふうに
    対話的に、目視確認しながらやるのが気持ちいいのです。間違えたら 'u' undo で
    戻れますし。

    またここでは外部コマンドをテキストフィルターとして使うこともあたり前の
    ように使っています。sort.exe と awk.exe ですね。
    とりあえず sort で並べなおすことによって全貌把握が容易になることが
    多いです。awk はなんでもできるスクリプト言語ですが、ここでは 2列目と
    6列目を抽出するのに使っています。

    フィルターを使う作業は unix 的にはコマンドラインでパイプで繋いで…、な
    所なんですが、vi から 使うと、入力データの範囲をその場で指定できたり、
    気に入らなければ undo できたりと、いちいち出力ファイル名を考えなくて
    よかったりと大変楽です。

    あ、vim-anim2.gif では LPC214x.h (A039) のバグが見つかってしまいましたね。
    ロングポインタであるところの USB_BASE_ADDR に 0x50 を加えると、
    (USB_BASE_ADDR+0x50*4)番地にアクセスしてしまいますね。テキストを
    加工しているだけで不具合が見つかってしまいました。

    箸を使えるようになったあなたは 今では手づかみで食事しようとは
    思わないでしょ? 別に vim でなくてもいいですが、いい道具を自由自在に
    とことん使えると良いことが多いです。


/*
 * プログラムの記述と統一されたスタイル
 */
    上の vim-anim2.gif では、LPC214x.h をテキストとして修正しているだけで
    不具合が見つかってしまいました。

    この例でわかるように、同じことをする記述を同じスタイルで書くことは
    非常に重要です。同じことをする記述は揃ってないといけないのです。

    vim-anim2.gif で、繰り返しの "." を有効に使えて省力化できたのは、この
    レジスタ定義の記述
        +--------------------------------
        |(VIC_BASE_ADDR + 0x000))
        |(VIC_BASE_ADDR + 0x004))
        |...
        +--------------------------------
    がスペースの数や数値の桁数まで含めて揃っていたからですね。
    機械のためだけでなく、実はそのほうが人間にもやさしいのです。

    スタイルが揃っていることで、「あ、いつものこれね」とコードの認識を
    助けます。逆にいえば、いつものやり方と違うことをするところだけは*逆*に
    記述スタイルを変えて、「なんかいつもと違うな」と読者の注意力を高める
    ように書くべきなのです。(簡単には「コメントを付けろ」ですね)

    例えば「マクロ定義には(主に)大文字を使う」は比較的広く共有されている
    スタイルですよね。別に従わなくてもいいんですけどね。従った方が理解が
    容易でしょ? それがフツーだし。

    そういった大きなスタイルから、細かいところでは 例えば #define の後が
    TAB が SPACE か、とか、行末に余分な TAB や SPACE が付いていないかなど
    瑣末なことも、スタイルです。これらは、いつかこうやって(人間や機械に)
    フィルタリングされることを考えると統一されているに越したことはないです。
        (ただしあんまり揃っていることに注意を奪われてしまうと)
        (なかなかコーディングが進みません。時おりチェックして)
        (揺らいでいたら直せばいいのです、vi の機能を使って)

    先の vim-anim1.gif では「VIM で C のプロトタイプ宣言用の関数の
    リストを作るやりかた」を説明しましたが、逆に言えば、これでリストが
    作製できるようなスタイルを私が固持して関数を記述しているわけです。

    vi などの高機能なエディターを自由自在に使えるようになって、スタイルの
    揃ったソースコードの作成が苦もなくできるようになることが大変重要です。

    - * - * -


    世の中にはアマノジャクな人がいて、逆にスタイル(に限らないが)を崩して、
    「どれだけ分かりにくいプログラムを書くか」を競っている人がいます。

    たとえばこれ。 1992/westley.c
        +--------------------------------
        |           main(l
        |      ,a,n,d)char**a;{
        |  for(d=atoi(a[1])/10*80-
        | atoi(a[2])/5-596;n="@NKA\
        |CLCCGZAAQBEAADAFaISADJABBA^\
        |SNLGAQABDAXIMBAACTBATAHDBAN\
        |ZcEMMCCCCAAhEIJFAEAAABAfHJE\
        |TBdFLDAANEfDNBPHdBcBBBEA_AL\
        | H E L L O,    W O R L D! "
        |   [l++-3];)for(;n-->64;)
        |      putchar(!d+++33^
        |           l&1);}
        +--------------------------------
    これコンパイルできて動くんですよ。なんと緯度と経度を引数として与えると
    画面に世界地図を表示してその場所を示してくれます!

    これらはここで見られます。
        国際邪悪な C コードコンテスト
        (ただし最近の作品は単なる ASCII ART が多い(ように思う)ですので、)
        (初期のころのサンプルを一度よーく吟味されてみることをお勧めします)


/*
 * vim を本来の形で使うための環境設定
 */
    vi を使う上では vi から呼び出す外部フィルタも大変重要です。
    unix 系のテキストフィルターを一式用意しましょう。とりあえず これです。
        http://sourceforge.net/projects/unxutils/
    VIM 本体はこちらからどうぞ。
        http://www.vim.org/

    今は Windows2000/XP 上で VIM 6.4 を使っていますが、私の環境を構築する
    方法を記しておきましょう。私は c:\ura を私の環境置き場、c:\uratan を
    作業ディレクトリとしています。そして c:\ura\etc に環境設定ファイルを、
    c:\ura\bin にバイナリを置きます。

    \ura\etc\uratan.bat の中身はこんな感じです。
        (C:\tmp フォルダも作っておいてね)
        +-------------------------------------------
        |@echo off
        |SET PATH=c:\ura\bin;%path%
        |set HOME=c:\ura\etc
        |set VIMRUNTIME=c:\Program Files\Vim\vim64
        |set TMP=c:\tmp
        |set TMPDIR=c:\tmp                              <--- sort.exe 用に追加
        +-------------------------------------------

    c:\ura\etc\_vimrc には以下の初期設定が書いてあります。
        +-------------------------------------------
        |set backup
        |set backupext=.bak
        |set ai
        |set sm
        |set ts=4
        |set sw=4
        |set vb
        |set dir=$TMP
        |set exrc
        |:lan mess en
        |set iminsert=0
        |set imsearch=0
        |set nomore
        +-------------------------------------------

    c:\ura\etc\_gvimrc はこれだけです。
        +-------------------------------------------
        |color blue
        +-------------------------------------------

    先に示した UnxUtils に含まれる usr\local\wbin\*.exe は c:\ura\bin に
    移しておきます。gawk.exe と make.exe はそれぞれ awk.exe と gmake.exe と
    いう名前でコピーを作っておくとよいでしょう。 (どっちでも使えるように)
    また、bin\sh.exe は c:\ura\bin\zsh.exe と名前を変えて使ってます。
      (なぜなら make.exe が「あっ sh あるじゃん」って内部起動して)
      (使っちゃうので いろいろややこしくなるから)
        (win7 の cmd.exe と zsh.exe 相性悪いですね。codepage 1252 が設定され)
        (て極小フォントに切り替わるみたい。あらかじめ 'chcp 437' で us mode)
        (にしておくか、1252 でフォントを選ぶか。日本語に戻すのは 'chcp 932')
        (XP まではあった C:\WINDOWS\system32\us.bat / jp.bat がもう無いし)
        (設定を変えると大元に codepage まで記憶されちゃうし・・・)
          ([2014.01.08]  win7 だと patch.exe が UAC に引っかかりますね…。)
          (この patch.exe.manifest を同 dir に置いて、キャッシュを更新する)
          (ために 'touch patch.exe' でタイムスタンプを更新すればいいみたい)

    この作業をアシストするバッチファイルを用意しましたので使ってください。
        make_env.bat
    使い方はバッチファイル内に書いてありますのでいきなりダブルクリックなぞ
    せずにまずは覗いてみてくださいな。

    最後に、コマンドプロンプトのショートカットをコピーして、「リンク先」を
    以下のように変更し、各種初期設定を uratan.bat で行うように修正します。
    こんな感じです。

    なおこの環境設定は当然ながらこのコマンドプロンプト内のみで有効です。
    なので vim.exe も gvim.exe もこのコマンドプロンプトから起動してください。
    myComputer のプロパティからユーザー全体の環境変数を書き換えてもいいの
    ですが、ここはアプリケーションのインストーラーが勝手に書き換えるところ
    ですし、c:\ura\bin がいつも最優先(PATH の先頭)であって欲しいのでこの
    ようにしています。逆に考えれば、目的によってさまざまな環境設定を選択・
    切り替えられますし。


/*
 * コマンドプロンプトで生活するうえでの便利な tips
 */
    といわけであなたもコマンドプロンプトの住人にならざるを得なくなりましたね。
    でも大丈夫です。Windows2000 以降のコマンドプロンプトは win95/98/Me の
    Dos Prompt に比べてかなり快適になってます。コマンドプロンプトで生活する
    上でなくてはならない技を少々伝授しましょう。

    ・start コマンド
        start filename とコマンドを打つことにより、そのファイルに関連付けられた
        アプリケーションが自動的に起動します。
        start 00README.txt とやれば「メモ帳」が起動して 00README.txt が表示
        されます。

    ・コマンドヒストリの呼び出しとエディット
        過去に入力したコマンドはカーソルの上下で呼び出せます。カーソル左右で
        任意に修正できます。
            (通常デフォルトで有効)

    ・文字列のコピー・ペースト
        マウスの左ボタンで画面上の文字列を選択し、右クリックでクリップボードに
        コピーできます。
        クリップボードの中身は右クリックでペーストできます。
            (コマンドプロンプトのプロパティで「簡易編集モード」が必要)

    ・アイコンのドラッグドロップ
        コマンドプロンプトにデスクトップや Explorer のファイルアイコンを
        ドラッグ・ドロップすることでそのファイルのフルパス名がペーストされます。

        私は とりあえずデスクトップに置いたファイルを以下のようにカレント
        ワーキングディレクトリに移動したり、入力が面倒くさいディレクトリに
        移動する際に使ってます。
        +--------------------------------
        |C:\uratan\arm>move "C:\Documents and Settings\uratan\デスクトップ\arm-uzk-039.zip" .
        |
        |C:\uratan\arm>cd C:\uratan\arm\新しいフォルダ
        |
        |C:\uratan\arm\新しいフォルダ>
        +--------------------------------

    ・TAB によるファイル名補完
        ファイル名が必要なところで TAB を押すとファイル名を補完してくれます。
        ファイルの先頭の(数)文字をあたえてから TAB を押すとその文字で始まる
        ファイルが対象になります。
        カレントワーキングディレクトリ以外のファイルでも、パス名を入力している
        途中で使えます。SHIFT+TAB ではファイル名検索を逆順に行います。
            (無効の場合は cmd.exe のオプションあるいはレジストリで有効に)
            (HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\CompletionChar = 0x09)

        基本的に日本語のファイル名は使わないのですが、他人が作成したファイル
        などで日本語ファイル名をどうしてもコマンドラインで指定したい場合など、
        該当のファイル名が出てくるまで我慢強く TAB を押す、なんてこともします。


/*
 * cwd (current working directory、現在の作業ディレクトリ)という考え方
 */
    GUI って便利ですか?
    確かに、ちまちました作業をするときに対話的・場当たり的に操作できるのは
    便利です。でもこんな経験は無いですか?
        ファイルに関係する作業で、まずファイルを開くときに 目的のファイルの
        入っているフォルダーをいつもいつも延々と追いかけて開く。
        あーめんどくさい。
        で、作業が終わって、ファイルをセーブすると、意図していたフォルダーに
        入ってない! あれ? どこにセーブされたんだ?
    なんてことが。

    unix 的には、「(現在の)作業ディレクトリ(current working directory)」と
    いう概念がしっかり根付いており、単にファイル名だけを指定した場合や、
    相対パスでファイルを指定した場合には この cwd を基準にファイルが
    選択されます。
    この概念は windows でも当然あるのですが、大変しばりが弱い。
    なので上のダイアローグ毎に基準ディレクトリが異なったりするわけです。
        (ある意味デスクトップがホームディレクトリ・基準作業ディレクトリ)
        (なのですが、ここにファイルを置くとデスクトップが汚くなるという)
        (致命的な欠点がありますよね)

    コマンドプロンプト的には、"cd (change directory)" でフォルダーを移動
    しますよね。これで移動した先が cwd にあたります。
    なので cd c:\uratan\arm\arm-uzk しといて vim LPC214x.h すれば
    c:\uratan\arm\arm-uzk\LPC214x.h が編集対象になりますし、":w yy"とすれば
    そのまま同じディレクトリにファイル yy としてセーブされます。
    違うファイルを編集したければ、vim ..\arm-uzk-039\LPC214x.h と相対パスで
    指定するもよし、vim c:\uratan\arm\arm-uzk-039\LPC214x.h と絶対バスで
    指定するもよしです。

    make でもなんでもそうです。cd arm-uzk-039 で make すれば Ver.039 が、
    cd arm-uzk-040 で make すれば Ver.040 が おなじ Makefile で作成されます。
    これはすべてのファイルアクセスは cwd に対する相対パスで指定してあるから
    です。
    arm-uzk-039 フォルダーが c:\uratan\arm にあろうが、d:\xxxx\yyy\w\w\w に
    あろうがそこに cd さえすれば同じに扱えるのです。

    作業フォルダーを自由に移動するために、環境変数 PATH (command search path)
    ほかで *.exe など各種ファイルのありかを指定するようになっており、これらの
    設定が快適なコマンドライン生活には必須なのです。

       (コマンドプロンプトで 'start .' すると cwd 対象の Explorer が開き)
       (ます。Explorer でツリーをたどるより便利に思うのは私だけ?)


/*
 * UnxUtils の各種コマンドと unix 的なテキストの考え方
 */
    unix の主たる世界では、すべてがテキストで閉じています。
        ・キーボードを打って手でコマンドを入力
        ・コマンドが書かれたファイルを読んで実行
        ・画面に出力される結果を見て考える。
        ・画面に出力される結果をファイルに落として vi でゆっくり吟味
        ・データが書かれたファイルを読んで処理
        ・あるフィルターが出力したデータを再度別処理の入力として使う
    ことが基本的に区別無く、シームレスにできるわけです。
    しかもテキストなので vi でどんなふうにも編集できる!

    例えば GUI ではなんでも画面に表示されますが、表示された結果を
    再利用するためにはその結果をコピーペーストとか、画面をキャプチャーする
    とか、ファイルに出力して移動しなければなりません。そして問題は、手間が
    かかることだけではなく、アプリケーションによってはこれらの処理が許されて
    いない場合があることです。

    コマンドラインではすべて非常にスムーズにできます。
    コマンドラインでは「リダイレクト」、「パイプ」、VIM からなら "%! xxx"
    とかです。調べてみてください。

    そういうわけで私は unix 系のテキストコマンドが大好きです。
    Windows 上では UnxUtils がないと生きていけません。

    - * - * -

    GNU ツールはコマンドラインで --help オプションを付加することで
    簡単な説明が表示されますので試してみてください。

        +--------------------------------
        |C:\uratan\arm>expand --help
        |Usage: expand [OPTION]... [FILE]...
        |Convert tabs in each FILE to spaces, writing to standard output.
        |With no FILE, or when FILE is -, read standard input.
        |
        |  -i, --initial       do not convert TABs after non whitespace
        |  -t, --tabs=NUMBER   have tabs NUMBER characters apart, not 8
        |  -t, --tabs=LIST     use comma separated list of explicit tab positions
        |      --help          display this help and exit
        |      --version       output version information and exit
        |
        |Instead of -t NUMBER or -t LIST, -NUMBER or -LIST may be used.
        |
        |Report bugs to .
        |
        |C:\uratan\arm>
        +--------------------------------

    本格的なマニュアルは本家
        http://www.gnu.org/manual/
    や web 上を探してみてください。日本語のものもあるはずです。
    ちなみに DOS ネイティブのコマンドは /? オプションを付加することで
    同様に help が出ます。

    UnxUtils にはたくさんの *.exe が含まれますが、私が良く使うのはこれらの
    コマンド(とオプション)です。
        pwd
        ls, ls -l, ls -lrt
        find . -name *.bak
        rm, rm -fr
        make
        diff, diff -r, diff -wb
        fgrep, grep
        expand -4
        cat -n
        awk
        sort, uniq, uniq -c


/*
 * diff を使え
 */
    そういうわけで、diff です。ファイルの差分を抽出するツールです。
    あらゆる場面で使います。しかも強力です。ディレクトリ階層を追いかけての
    比較もできますし、バイナリファイルでも、同じか違うかぐらいは教えてくれます。

    diff の吐く差分は一見 見にくいですが、慣れると平気です。慣れましょう

    私は以下の zz-vim-diff という vim 用のスクリプトを用意して、バージョン
    アップ時には diff の出力を毎回 ":source zz-vim-diff" と整形してから
    眺めてます。
        +--------------------------------
        |:g/^diff/s/^/^M^M/
        |:g/^[0-9]/s/^/^M/
        |:g/^Only/mo$
        |:g/^Bina/mo$
        +--------------------------------
            (^M とは改行のことです。vim.exe でコマンドプロンプトから)
            (CTRL-V, CTRL-M と入力します)

    たとえば 00change.log はこんなふうに作成されているわけです。
        vim-anim3.gif (102kB)

    あ、頭が zz- から始まるのは私のファイル名命名のスタイルです。ls で
    一覧をとるときに、ソースファイルではないカテゴリーとして固めるためです。


/*
 * HEX コンペア
 */
    最近仕事が国際化してきて、外国人とコミュニケーションが…、なんて場面も
    多いですが、そもそも日本人同士だからといって日本語が通じているわけでは
    ないのですよ。
    山本夏彦氏の言葉の通り、各個人ごとに「単語-->イメージ」の個別辞書があって、
    この辞書がシンクロしないと伝わらないのです。

    日本人同士でも、開発者が顔を付きあわせて現象を見ていれば、複雑な事象でも
    「アレ」とか「ソレ」とかの名称で共有できるようになります。むしろ一言で
    表現できず、これ以外に表現しようが無い場合もありますし、逆に言えばその
    現場で「アレ」という新しい日本語がその場で共有定義されると言い換えても
    いいでしょう。
    ソースコードで flag, flag2 とか使っていても、開発中は記憶と動作イメージが
    フレッシュで十分なんですが、時間とともにこれらが失われるとなんのことだか
    分からなくなります。なので名前(マクロ名、関数名、変数名)は大変重要だと
    考えます。

    で私は気に入らない名前の付け替えをよくやります。ソースコードは極力変化
    させない主義もありますが、こちらには vim もあるし、気に入らない名前は
    バシバシ変えます。ただし、保険をかけます。

    それは、名前を変える前のコンパイル結果と、変えた後のコンパイル結果を
    比較して、実行コードに変化がないことを確認するのです。ArmUZK の場合では
    新旧の arm-uzk.hex 同士を diff で比較します。

    コンパイラや環境、コンパイルオプションによって、名前を変えても結果が
    変わらない範囲が変わります。C のマクロ定義は単なる文字置換なので通常
    いつでも自由に変えられますが、変数名を変えるとメモリへの割り付けが
    変わって結果が変わるコンパイラもありますし、Windows の *.exe などでは
    タイムスタンプを内包しておるようで同じソースをコンパイルしても違う結果に
    なるものもあります。

    さらに #if で条件コンパイルを指定している裏側は 元々 *.hex に含まれません
    ので、この部分はそのままでは比較できません。
    これらコンパイラのクセや比較の必要条件・十分条件は、事前に良く調べて
    おくことが大切です。

    あと、名前を変えるとソース比較では相違点が膨大になります。名前を変える
    テーマのバージョンアップでは名前を変えるだけにとどめ、「*.hex が変わって
    いないこと」をバージョンアップ条件にすることが多いです。

    じゃどんな名前がいいのか、というのはまた別問題です。ソースコードは
    英語もどきな書き方をしますが、私はなるべく辞書を引いてイメージに近い
    英単語、できれば英語文章になるように努力してます。
    int I_have_to_send_this_for とか、int data_has_sent とか。

    日本人の限界を感じるときもあります。残りバイト数を表す residue とか、
    USB2.0 の chirp とか、オーディオ・ビデオファイル系で出てくる chunk とか
    いう単語はそうそうイメージできません。(ですよね?)

    もう一つは名前にカテゴリーを表す prefix をつけることです。名前を一連の
    シリーズとして扱い、適用範囲を限定することで、比較的すくない文字数で
    付帯情報を増やせ、人間の理解を助けます。
    またこの prefix は英語文章的には主語になり、主体を表す意味もあります。
    主語はそのタスクにするとしっくりくることが多いですね。

    名前の変更で活躍するのが VIM の ワードサーチ "*" と 繰り返し "." です。
    非常にリズミカルに、対話的に修正できます。あとから *.hex を比較すれば
    変更の善し悪しがはっきり分かるので、ビール飲みながらでも楽しくできます。


/*
 * 最近お気に入りの編集テクニック
 */
    最近お気に入りの編集テクニックを少々。

    ・ターゲットを集めて確認・修正
        vim-anim4.gif (110kB)

      まず cat -n で各行に文字として番号を振ります。その後、ファイル内に
      分散している対象行を一箇所に集め 気持ちよく修正します。sort -n すると
      あら元通り。行番号を削除しておしまい。
      ソースファイル中をあちこち飛び回るより見通しもいいし落ち着いて
      編集できます。

    ・ソースを一本化し一気に編集した後、再度個別ファイルに分解する
        vim-anim5.gif (257kB)

      ファイルをまたがった編集は対象ファイル群を一本化して行うと
      たいへん楽になります。ファイル群の結合・分解には awk を使います。
      いじるマクロ名がコンパイルオプションの場合には Makefile のケアも
      お忘れなく。
        (z-dec_src.awk, z-inc_src.awk)


    ・おまけ - 残像デバッグ
        vim-anim6.gif (70kB)

    ・おまけ - vim で計算  (UnxUtils の bc.exe を使ってます)
        vim-anim7.gif (27kB)


/*
 * コーディングと将棋
 */
    どうも棋士の人たちは、対局をベクターデータで管理しているらしい。
    つまり我々が盤面の状態をそのまま bitmap データで 盤面dump として
    記憶・管理しようとするのに対して、彼らは vector データ、すなわち
    ある基点からの駒の動きの積算結果として認識しているようだ。

    だから たった今行った対局で、「24手目で、こっちを打っていたら
    どうしました?」などと自由自在に途中を切り取り感想戦ができるし、
    そもそもプロなどは先達の過去の勝負の“棋譜”をほとんど覚えているらしい。
    そこには単なる動きだけではなく、背後にある戦略も理解しているからこそ
    できる技なのであろう。

    コーディングも似ていて、ソースコードはある意味ビットマップであり、
    ソースコードだけでは なかなかそれに含まれる戦略が見えず、
    「おつり(影響)がわからないから直せません」とか、「レイヤー分けして
    書こうとしているのはわかるが、矛盾があってそのポリシーが類推できん」
    とかいう状態が普通に存在する。

    システムを構成するこれら基本戦略をなるべく残すべきであり、また
    これら基本戦略が なんの文章でも残っていないとしても、せめて
    文脈的・typo 的・単純ミス的・ポカ的間違いをしない・矛盾を埋め込まない
    ためにも、vim をはじめとするテキストツールを活用するように
    したいものである。

      (2年半ぶりに drive_uzk.c に手を入れたが記憶ちゅうのは薄れるもんだねぇ)

        (補足: これちょっと結論が ぼけてました。言いたかったことは、
        (
        (        ベクターデータ的に扱えること = 履歴を活用できる/すること
        (
        (      なので、(最終版だけではなくて)各バージョンも保存して、
        (      時間軸情報も活用できる/するようにしましょう、だったです。
        (                        (もちろん diff を大活躍させます)
        (      00README.txt, 11change.log をつけるのはあたりまえで、
        (      これは(ドキュメントではなく)ソース(の一部)なので、
        (      当然 履歴管理の対象ですよ。


/*
 * ソースコードの見栄えの話
 */
    ソースコードの『見栄え』には非常にこだわってます。絵を使わずに私の
    こだわりを伝えることは大変難しいと思いつつ、伝えてどうするとも思い
    つつ、うまい絵も描けないので とりあえず綴ってみます。

     - * - * -

    海外旅行で初めての場所に行くと非常に疲れますよね。それは目に入るす
    べての視覚情報が不慣れなものばかりなので、かなり真剣に全入力情報を
    解析をするからだと考えてます。普段馴染んだ場所では、深く解析するべ
    き部分とそうでない部分をほぼ無意識に取捨選択しており、必要部分だけ
    に集中できるので楽なのだと思います。なので、文章・ソースコードもぼ
    んやり見てもまず区別がわかる、ことが重要ではないかと考えてます。ま
    あこの"慣れ"がスタイルであり、どんなに強制されても苦手なスタイルに
    はなかなか馴染まないものですが。

    と、スタイルを変えて普通の出版物のように書いてみましたがどうでしょう。
    通常だと、こんなふうなレイアウトにしますが。

     | 海外旅行で初めての場所に行くと非常に疲れますよね。それは
     | 目に入るすべての視覚情報が不慣れなものばかりなので、
     | かなり真剣に全入力情報を解析をするからだと考えてます。
     |
     | 普段 馴染んだ場所では、深く解析するべき部分と そうでない部分を
     | ほぼ無意識に取捨選択しており、必要部分だけに集中できるので
     | 楽なのだと思います。
     |
     | なので、文章・ソースコードも ぼんやり見てもまず区別がわかる、
     | ことが重要ではないかと考えてます。
     |   (まあこの"慣れ"がスタイルであり、どんなに強制されても苦手な
     |   (スタイルにはなかなか馴染まないものですが。

     - * - * -

    というわけで 私のこだわりのツボは、以下のあたりです。 (脈絡ないですね)
    引き続く [例nn] は、一番下が私のスタイルです。
      (ちなみに私に目指すスタイルを与えてくれた きっかけ はここにあります)

      (1) ぼんやり見ても間違えにくいこと
      (2) 着目点にクセをつけること。
      (3) フォントの面圧に配慮   (面圧は 今 適当に作った言葉です)
      (4) エッジ検出・包絡線・ブロック強調、そのための空白


    [例01]
        '*' が縦に並ぶことで、赤ペンで縦線引いたように「ここコメントブロック」と
        目に訴えてくるように思います。"//" だとちょっと弱い。また各行頭に '*' を
        含むことで、grep で行抽出したときに一行だけでも「これはコメント行だ」と
        わかる副次効果も狙ってます。
        さらに開始と終了で(ほぼ)空行が前後に入り、コメント本体が浮かび上がります。
        +--------------------------------
        |/* LPC1830.h - peripheral register addresses for me
        |   by uratan! 2012.10.17
        |*/
        |
        |#endif
        +--------------------------------
        |// LPC1830.h - peripheral register addresses for me
        |//   by uratan! 2012.10.17
        |
        |#endif // __LPC1830_H__
        +--------------------------------
        |/*
        | * LPC1830.h - peripheral register addresses for me
        | *   by uratan! 2012.10.17
        | */
        |
        |#endif /* __LPC1830_H__ */
        +--------------------------------
        ちなみに #else #endif には必ずコメントで識別条件を付けます。
        vim で "ma*:'a,.dndd" とかやると さっくり片側を削除できます。

    [例02]
        面圧の小さい '_' があることで、目線が 'S'→'F'→'数字' とひっかかって、
        数字の間違いが減る気がします。キャメルケース("CamelCase")は スネーク
        ケース("snake_case")よりアクセントが弱いと思います。
        +--------------------------------
        |#define SFS_FUNC0          (0 <<0)
        |#define SFS_FUNC1          (1 <<0)
        +--------------------------------
        |#define SFS_FUNC_0         (2 <<0)
        |#define SFS_FUNC_1         (3 <<0)
        +--------------------------------

    [例03]
        '#' は面圧が高いので これは縦線として揃えたまま define を 2つ字
        下げして、レジスタ定義とそのビットアサイン定義、が まとまった上で
        メリハリつけてるつもりです。
        +--------------------------------
        |#define SCU_SFS_P2_4            *(_v_u_l *)(LPC_SCU_BASE + 0x110)
        |#define SFS_FUNC_0           (0 <<0)
        |#define SFS_FUNC_1           (1 <<0)
        +--------------------------------
        |#define SCU_SFS_P2_4            *(_v_u_l *)(LPC_SCU_BASE + 0x110)
        |  #define SFS_FUNC_0         (0 <<0)
        |  #define SFS_FUNC_1         (1 <<0)
        +--------------------------------
        |#define SCU_SFS_P2_4            *(_v_u_l *)(LPC_SCU_BASE + 0x110)
        |#  define SFS_FUNC_0         (0 <<0)
        |#  define SFS_FUNC_1         (1 <<0)
        +--------------------------------
          (ちなみに '#' は、C 言語にとってはコメント行よ、という意味で
          ("#define" という予約語なわけではない、と思うのです。

    [例04]
        まあ慣れの問題ではありますが、verilog のマクロの '`' なんて、
        見落としてくれ、と言っているようなものだと思いませんか?
        C 言語の構造体あたりの '.' とか "->" とかって面圧が絶妙だと思います。
        +--------------------------------
        |`define VERSION     8'ha8       /* <== manege this ! */
        |...
        |        .BITS   ( `VERSION ),   /*  */  .DOUT   ( do02 ),
        +--------------------------------

    [例05]
        そうそう、MS-DOS の致命的な欠点は、path 区切りの backslash が
        日本語環境だと '\' になってしまいこれがまた元のグリフや '/' とは
        面圧が違いすぎることなんですよね。
        +--------------------------------
        |C:\uratan\lpc1830\minimon\test-peri>
        +--------------------------------
        |C:/uratan/lpc1830/minimon/test-peri>
        +--------------------------------

    [例06]
        ',' だけだと微妙につながってしまうので、スペースを加えて区切りを
        はっきりさせます。" | " でも切れてしまっているのはご愛嬌、でも '|' が
        飛び出して見えるでしょ。横がきつい時はケースバイケースでつなぐことも
        ありますが。
        +--------------------------------
        | stat = pSpifi->spifi_init(&obj,CS_HIGH,S_RCVCLK|S_FULLCLK,CLOCK);
        +--------------------------------
        | stat = pSpifi->spifi_init(&obj, CS_HIGH, S_RCVCLK | S_FULLCLK, CLOCK);
        +--------------------------------

    [例07]
        HEX ファイルだって、スペース少々でこんなに見やすくなります。
        +--------------------------------
        |:10000000004B0810410000001900081031000810D2
        |:100010004900081061000810790008107856341261
        |:1000200001000810010008100100081091000810DC
        +--------------------------------
        |:10 0000 00 004B081041000000 1900081031000810 D2
        |:10 0010 00 4900081061000810 7900081078563412 61
        |:10 0020 00 0100081001000810 0100081091000810 DC
        +--------------------------------

    [例08]
        個人的に最強の横線は @@@@ です。濃淡がわかりますか?
        +--------------------------------
        |/*- - - - - - - - - - - - - - - - - - - - - - - - -*/
        |/*-------------------------------------------------*/
        |/*=================================================*/
        |/***************************************************/
        |/*#################################################*/
        |/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
        +--------------------------------

    [例09]
        思い切って空行(もしくはラベルのみの行)をはさむ事で、ブロックの
        切れ目を印象付けます。縦線コメントでコメントを浮き上がらせます。
        アセンブラソースだからこそ、ですが C だって同じでしょ。
        ちなみにコメントの ';' は面圧弱すぎですね。昔はわざわざ ";*" と
        運用してたこともあります。
        +--------------------------------
        |        ; Relocate .data section (Copy from ROM to RAM)
        |        LDR     R1, =_lma_data_start    ; src
        |        LDR     R2, =_data_start        ; dest start
        |        LDR     R3, =_data_end          ; dest end
        |lp21:   CMP     R2, R3
        |        BHS     lp22
        |        LDR     R4, [R1]
        |        STR     R4, [R2]
        |        ADD     R1, #4
        |        ADD     R2, #4
        |        B       lp21
        |        ; Clear .bss section (Zero init)
        |lp22:   LDR     R2, =_bss_start
        |        LDR     R3, =_bss_end
        |        MOV     R4, #0
        |lp31:   CMP     R2, R3
        |        BHS     lp32
        |        STR     R4, [R2]
        |        ADD     R2, #4
        |        B       lp31
        |        ; copy C related for RAM
        |lp32:   LDR     R1, =_lma_exec_start
        |        LDR     R2, =_exec_start
        |        LDR     R3, =_exec_end
        |lp51:   CMP     R2, R3
        |        BHS     lp52
        |        LDR     R4, [R1]
        |        STR     R4, [R2]
        |        ADD     R1, #4
        |        ADD     R2, #4
        |        B       lp51
        |        ; Enter the C code
        |lp52:   LDR     R0,=main
        |        MOV     PC,R0
        +--------------------------------
        |    /*
        |     * Relocate .data section (Copy from ROM to RAM)
        |     */
        |    LDR     R1, =_lma_data_start    /* src */
        |    LDR     R2, =_data_start        /* dest start */
        |    LDR     R3, =_data_end          /* dest end */
        |lp21:
        |    CMP     R2, R3
        |    BHS     lp22
        |    LDR     R4, [R1]
        |    STR     R4, [R2]
        |    ADD     R1, #4
        |    ADD     R2, #4
        |    B       lp21
        |lp22:
        |
        |    /*
        |     * Clear .bss section (Zero init)
        |     */
        |    LDR     R2, =_bss_start
        |    LDR     R3, =_bss_end
        |    MOV     R4, #0
        |lp31:
        |    CMP     R2, R3
        |    BHS     lp32
        |    STR     R4, [R2]
        |    ADD     R2, #4
        |    B       lp31
        |lp32:
        |
        |    /*
        |     * copy C related for RAM
        |     */
        |    LDR     R1, =_lma_exec_start
        |    LDR     R2, =_exec_start
        |    LDR     R3, =_exec_end
        |lp51:
        |    CMP     R2, R3
        |    BHS     lp52
        |    LDR     R4, [R1]
        |    STR     R4, [R2]
        |    ADD     R1, #4
        |    ADD     R2, #4
        |    B       lp51
        |lp52:
        |
        |    /*
        |     * Enter the C code
        |     */
        |    LDR     R0,=main
        |    MOV     PC,R0
        +--------------------------------

    [例10]
        一番目は詰まりすぎ、二番目は空行(もどき)が入りすぎです。目線の縦の
        動きが 3行も飛ぶのは…。
        基本のスタイルは三番目だったんですが、(長いブロックの場合は)一番下の
        ように空行を挟むっぽく 縦目線は if の真下が else でいい感じかなぁ、と
        最近ゆれてます。
        +--------------------------------
        |    if(boot_from_spifi && spifi_boot_requested) {
        |        /* reboot from 0x8010_0000 of SPIFI-flash */
        |        M3_MEMMAP = USER_ROM_TOP_at_WIN2;
        |        RESET_CTRL0 = RES0_M3_RST;      /* 1clk -> auto-clear */
        |    } else {
        |        if(RUN_MINIMON_FIRST) {
        +--------------------------------
        |    if(boot_from_spifi && spifi_boot_requested)
        |    {
        |        /* reboot from 0x8010_0000 of SPIFI-flash */
        |        M3_MEMMAP = USER_ROM_TOP_at_WIN2;
        |        RESET_CTRL0 = RES0_M3_RST;      /* 1clk -> auto-clear */
        |    }
        |    else
        |    {
        |        if(RUN_MINIMON_FIRST) {
        +--------------------------------
        |    if(boot_from_spifi && spifi_boot_requested) {
        |        /*
        |         * reboot from 0x8010_0000 of SPIFI-flash
        |         */
        |        M3_MEMMAP = USER_ROM_TOP_at_WIN2;
        |        RESET_CTRL0 = RES0_M3_RST;      /* 1clk -> auto-clear */
        |    } else {
        |        if(RUN_MINIMON_FIRST) {
        +--------------------------------
        |    if(boot_from_spifi && spifi_boot_requested) {
        |        /*
        |         * reboot from 0x8010_0000 of SPIFI-flash
        |         */
        |        M3_MEMMAP = USER_ROM_TOP_at_WIN2;
        |        RESET_CTRL0 = RES0_M3_RST;      /* 1clk -> auto-clear */
        |    }
        |    else {
        |        if(RUN_MINIMON_FIRST) {
        +--------------------------------

    [例11]
        定数テーブルは使うのも気合を入れて修飾するのも好きですね。
        #define 定義をコピーしてきてコメントに変換するなんざ vim で
        すいすいです。
        '5' がずれてるのも意味を込めてます。
        +--------------------------------
        |/* index for USB_Jump_Table[] */
        |#define USB_JT_RESET    0
        |#define USB_JT_SUSPEND  1
        |#define USB_JT_RESUME   2
        |#define USB_JT_POWER    3
        |#define USB_JT_SOF      4
        |#define USB_N_JT        5
        |
        |/* list of USB device events callbacks */
        |const INTR_subFUNCs USB_Jump_Table[USB_N_JT] = {
        |    isr_Reset_Event,
        |    isr_Suspend_Event,
        |    isr_Resume_Event,
        |    NULL  /*isr_Power_Event*/,
        |    NULL  /*isr_SOF_Event*/,
        |};
        +--------------------------------
        |/*
        | * index for USB_Jump_Table[]
        | */
        |#define USB_JT_RESET    0
        |#define USB_JT_SUSPEND  1
        |#define USB_JT_RESUME   2
        |#define USB_JT_POWER    3
        |#define USB_JT_SOF      4
        |#define USB_N_JT       5
        |
        |/*
        | * list of USB device events callbacks
        | */
        |const INTR_subFUNCs USB_Jump_Table[USB_N_JT] = {
        |/*0:USB_JT_RESET  */    isr_Reset_Event,
        |/*1:USB_JT_SUSPEND*/    isr_Suspend_Event,
        |/*2:USB_JT_RESUME */    isr_Resume_Event,
        |/*3:USB_JT_POWER  */    NULL  /*isr_Power_Event*/,
        |/*4:USB_JT_SOF    */    NULL  /*isr_SOF_Event*/,
        |};
        +--------------------------------
          (keyconv.c @ wuzk.exe のヤツの方が例としては良かったかな…

     - * - * -

    下の vim script でソースを変換してみると、もう少し私の気持ちが伝わるかな…。
    ファイルに落としておいて ":source xxx.vim" で仕掛ければ楽です。
        +--------------------------------
        |:%s/[ABCDEFGHIJKLMNOPQRSTUVWXYZ]/M/g
        |:%s/[abcdefghijklmnopqrstuvwxyz]/m/g
        |:%s/[#$%&\\]/#/g
        |:%s/[0123456789]/B/g
        +--------------------------------

    ちなみに以下のような変換です。
        ========================================================
          ASCII CODE
             | x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf
          -----------------------------------------------------
          2x | SP !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /
          3x | 0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?
          4x | @  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O
          5x | P  Q  R  S  T  U  V  W  X  Y  Z  [  \  ]  ^  _
          6x | `  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o
          7x | p  q  r  s  t  u  v  w  x  y  z  {  |  }  ~  DEL
        ========================================================
                       |      |      |      |
                       V      V      V      V
        ========================================================
          MMMMM MMMM
             | mB mB mB mB mB mB mB mB mB mB mm mm mm mm mm mm
          -----------------------------------------------------
          Bm | MM !  "  #  #  #  #  '  (  )  *  +  ,  -  .  /
          Bm | B  B  B  B  B  B  B  B  B  B  :  ;  <  =  >  ?
          Bm | @  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M
          Bm | M  M  M  M  M  M  M  M  M  M  M  [  #  ]  ^  _
          Bm | `  m  m  m  m  m  m  m  m  m  m  m  m  m  m  m
          Bm | m  m  m  m  m  m  m  m  m  m  m  {  |  }  ~  MMM
        ========================================================

    横軸の 16進数部分 xa, xb, ... は やっぱり xA, xB, ... の方が良さそうですね。


 - * - * - * - * - * - * -


    というところで、あなたもコマンドラインから vim を使い、diff, awk 他を
    駆使して楽しいコンピューター生活を送りましょう。

     (少なくともこのファイルはこれでおしまいにしなきゃね…)


では こんなところで。



 - * - * -



    かつて UNIX MAGAZINE 誌に「プログラマーの理想と現実」という 遠藤知宏さんの
    連載がありまして、"一発完動プログラミング"など たいへん共感するところが
    多かったのですが 雑誌の休刊と共に埋もれてしまっております。                   あえて 幻も!

     | すべてを一発完動にするわけではないのです。まず知る。
     | 知るために動かす習作プログラムは一発完動の必要はない。
     | "自分はすべてを知らない" を認識することがまず第一。(ソクラテスですね)
     | そして すべて知った、段階で、書き始める。
     | ゆえにそれは一発で完全動作する。
     |
     | 巨大な橋やビルは「落ちてもいい」と施工しないですよね?
     | そんな感じだと 私も思うのです。
     |    (もちろん想定外はいつもあなたのそばにいます、でもね…)

 - * - * -


/*
 * コマンドライン作業のご褒美
 */

    また夏が来ましたねぇ、どうですか、ガリガリ キーボード叩いてますか?
    汗がベタベタするのが気持ち悪いので 机の上にタオルを敷いたりしてますが、
    ちょっと違和感がありますね。

    そんなコマンドラインで作業しているあなた、あなたにご褒美があります。

    「コマンドラインのいいところも十分わかったけど、日々の繰り返しを
    毎度毎度 打つのもアレだなぁ…」と思い始めたあなた、make.exe を
    活用しませんか?

    いいんですよ、世の中には TOEIC 892点ぐらいの(理解不能の) Makefile も
    ありますが、これでいいんです。
    日々の作業をもう一人の秘書(make.exe)にやらせる、これでいいんです。

        +--------------------------------
        |#
        |# Makefile for daily operation
        |#
        |all:
        |
        |claen:
        |
        |here:
        |    xcopy.exe /Y .\debug\obj\xyz.hex  current.hex
        |
        |there:  here
        |    xcopy.exe /Y current.hex d:\eval-tmp\test.hex
        |
        |relclean:
        |    -rm -f .\debug\obj\*.obj
        |    -rm -f .\debug\obj\*.d
        |
        |release:
        |    xcopy.exe /Y .\debug\obj\xyz.hex ..\..\PRJ-XYZ\release\xyz.hex
        |
        +--------------------------------

        # なんでフォルダを掘って分けるかねぇ… ここ(cwd)でいいのに

----
  uratan@miomio.jp

upward