マシンオブジェクト 状態:この文書の翻訳作業は完了しています 原文:NV133.pdf 翻訳者:caskaz 対象読者:オブジェクトについての初歩知識 By Jon Williams 先月にPropellerチップを紹介してから頭の中でぐるんぐるんPropellerが回ってたかい? 先月、オブジェクト指向のspin言語について話したけれど、実際有利な点はそこじゃない。ちょっと試してみたら考えたこともないような素晴らしい事を始めることになって満面の笑顔になるのは間違いないさ。 僕は自分でもかなりのプログラマーだと思ってる。もちろんアセンブリも使ってるけど、あんまり好きじゃない。誰かが書いたアセンブラコードを使う時は好きじゃないという意味だけどね。それを読むのはちょっとした仕事だからだ。 でもまずはちょっとしたおさらいをしよう。Propellerチップは8個の32ビットプロセッサ(Cog)が同時に動作するのは覚えているよね? CogはSPIN言語インタプリタやアセンブラ言語プログラムを実行している。 もちろん、SPINとアセンブラにはパフォーマンスで差がある。アセンブラはSPINの250倍の実行速度がある。システムクロック80MHzで設定されたPropellerチップは1秒間で8万行のSPINコードを実行できる。これはかなり速い。 さて、Propellerオブジェクトをロードしてアセンブラを使ったSPINプログラムの能力を確かめてみよう。 PC_Debugの目的はPCターミナルに情報を送信する事だ。その為にシリアル送信を処理するコードが必要なのでChipが書いたFullDuplex?という高機能なUARTオブジェクトを利用させてもらおう。 今月ダウンロード用に準備したZIPファイルは特殊な名前だ。これはPropellerのアーカイブファイル名だ。 OBJ uart : “fullduplex” プロジェクト内でuartの名前でFullDuplex?オブジェクトを使える。 大抵startメソッドはコードの処理に基いてTrur(-1)かFalse(0)の値をリターンする。 PUB start(baud) : okay okay := uart.start(31,30, baud) これは簡単なメソッドだがまだなにも起こっていない。PUB宣言でスタートし、このメソッドをもっと高いレベルのオブジェクトによってもアクセスできるようにPUBLICにする必要がある。このメソッドはbaudと呼ばれるパラメータを必要だ。パラメータのサイズについては考慮しなくてよく、いつもLong変数だ。 今はコードはたったの1行だ:okayがuart.startメソッドのリターン値にセットされている。Spinのオブジェクトはオブジェクト指向言語で見られるドットを使っている。 PUB startx(rx_pin, tx_pin, baud) : okay okay := uart.start(rx_pin, tx_pin, baud) staretx(x付き)メソッドはボーレートと使用するピン番号を単に通過させてるだけだ。 OBJ terminal[2] : “ “pc_debug” ' Now we just need to asign the terminal to ddifferent Propeller I/O pins PUB main terminal[0] : start(9600) terminal[1] : startx(1, 0, 57600) 上記でterminal[0]は9600baudでdefaultのピン(31,30)を使用している。 PC_Debugオブジェクトに戻ろう。これは送信データをターミナルに便利な形式で表示できるようにFullDuplex?をラッパーしている。FullDuplex?オブジェクトは新しいCogで起動しているので自身のCogを停止、又他のプロセスの為に自身を有効にするメソッドを持っている。このメソッドはstopメソッドをコールし、簡単にそれへのアクセスを提供する。 PUB stop uart.stop 上記は冗長なようにみえる、でも実際は違う。PC_Debugを使うどんなプログラム(top object)もFullDuplex?のメソッドに直接アクセスすることはできない。それはラッパーで提供されているからだ。この良い点は必要なものだけラッパーで提供でき、多少保護されたメソッドはそのままにしておける。 PC_Debugオブジェクトを見ることでFullDuplex?のオブジェクト用に他のラッパーがあるということがわかるだろう。 PUB dec(value) | div, zpad if (value < 0) -value out(“-”) div := 1_000_000_000 zpad~ repeat 10 if (value => div) out(value / div + “0”) value //= div zpad~~ elseif zpad or (div == 1) out(“0”) div /= 10 オーケー、これは初見だと少し秘密っぽく見えるけどSpinではよく使われているということを言語の効率が好きな君に信じてほしい。 いくつか新しい事があるのでそのそこから始めよう。 コードの最初は単純だ:引数が負なら引数を正数にして”-”キャラクタと数値を出力しているだけだ。次に除数(div)を初期化してzpad flagをクリアする。 zpad~ これは下記と同じだ zpad := 0 さて、今度はdecメソッドの意味を考えよう。 値が除数より大きいか等しいか検査して、もしそうなら除数で値を割ることによって現在の商を得てASCIIキャラクタ”0”を加算し変換する。 値が除数より小さければzpad flagまたは除数がゼロでないかをチェックする。 オーケー、今度はbinary-hex変換メソッドを見てみよう。このルーチンはキチンとして綺麗だ(僕には作れない)、その上Spin言語の技巧を感じさせてくれる。 PUB bin(value, digits) digits := 1 #> digits <# 32 value <<= 32 – digits repeat digits out((value <-= 1) & %1 + “0”) このメソッドは digitsの桁数を必要としている点がdecとは少し違っている。しかし、コード自体は少ない。 実際の処理はここだ:表示するdigitsの数だけループしている。まず1ビット左にローテートしている。ローテートはビットがなくなるシフトと違ってビットを回転している。 オーケー、16進変換の準備はできたかい?2進とおんなじだよ。 PUB hex(value, digits) digits := 1 #> digits <# 8 value <<= (8 – digits) << 2 repeat digits out(lookupz((value <-= 4) & %1111 : “0”..”9”, “A”..”F””)) 16進の1桁は4ビットで構成されるので必要桁数digitsに応じた桁数分だけ4ビットシフトの実行をする。digitsを評価した8から減算したあと、2ビットシフトする。 PC_Debugオブジェクトが表示出力する時間のことを考えよう。アーカイブの中にPC_Debug_Test.spinがある。それはとても短く、そして PUB main | idx debug.start(460_800) debug.str(string(FF, “Debug Test”, CR, LF, LF)) repeat debug.hex(idx, 2) debug.out(Space) if (( ++idx // 16) == 0) debug.crlf until (idx == $100) debug.crlf debug.dec(-1) debug.crlf debug.ibun(-1, 32) debug.crlf debug.ihex(-1, 8) ebug.stop プログラムには一つだけpublicメソッドがあり、それはmainと呼ばれる。 最初の行はフォームフィードキャラクタ(HyperTerminal?では画面をクリアする)、テキスト、キャリッジリターン、2行のラインフィードから出来た文字列だ。 DAT titl byte “Nuts & Volts rocks!”, 0 ゼロターミネータに注意! debug.str(@title) プログラム本体は$00から$FFまでの16進数を縦16横16で表示するループだ。 repeat idx from $00 TO $FF 終了処理も下記のように置き換えられる。 If (idx == $100) quit 僕はrepeatは自由度が大変大きくてオプションも多様性があることを見せたかったんだ。 オーケー、これでPCの通信プログラムにデータ送信できるツールを手にいれたわけだ。 Propeller アーカイブ †今月のZIPファイルは特殊な名前だと気付いていると思う。このZIPファイルはPropeller Tool > File menuのArchiveで作られたものだ。これはIDEの非常に便利な特徴で、使用しているファイルがどこにあるかに関係なくプロジェクトの全てのファイルを集めて保存してくれる。 Propellerで楽しんでください、次回まで・・楽しくブン回そう! |