PPPのうち、HDLCによるフレーム伝送、LCPによる接続、PAPによる認証までを書き終えた。PPPだけでも、認証用のCHAPとIP割り当ての為のIPCPを実装しなければならないので、まだまだ先は長いのだが、とりあえずPPPのメドはたった。
これ(PPP)を書いていて思ったのが、もう少しMulti thread modelの勉強をしてから始めれば良かったという事。Threadを実装する際の知識が貧弱なので、えらく汚いコードになってしまった。MSX-DOSならThreadもProcessも同じだと思っていたのが、そもそもの間違いか。
現時点で残っているのはProtocol stackの下から順に、CHAP/IPCP/IP/ICMP/UDP/DNS/TCPといったところ。楽そうなのはIPCPとICMPくらいなので、大変なところ丸残りといった感がある。
RELAが遂にインダイレクトファイルに対応したので、ML.COMのRELA対応版を作った。
が、動かない。コマンドラインを標準出力に返してNo error(s)
を表示するダミープログラムを、RAS.COM/RLK.COMの代わりに入れてやると動くのだが、本物のRASを使うと1つ目のファイルをアセンブルした後、暴走する。RAS.COMやCOMMAND2.COMのキャッシュにVRAMを使っているので、その部分をRASが破壊してるんじゃないかと思うのだが、確証なし。
0〜MAX-1までの数字をループさせたい。
MAXが2^nであれば、and命令を使えば1byteでできる。これに当てはまらない数値の場合は、分岐処理が必要になる(剰余を求める方法は遅いから却下)。
inc b ld a,b cp MAX jr c,BRUNCH xor a ;MAXに達したら0に戻す BRUNCH: ld b,a
しかし、jr/jp命令嫌い(管理せにゃならんラベルが増えるから)なプログラマとしては、他の手を使いたくなるわけだ。で、考えたのがこんな手。ちょっと作為的だけど気にしない。
inc b ld a,b cp MAX sbc a,a and b ld b,a
書いてみれば、かつてMSX・FANに載ったゲームアーツZ80 Quiz
と同じネタである(たぶん)。今頃こんな事を言うのもなんだけど、こ〜やって使うもんだったのね。
2月4日に書いたPPPフレームの0挿入の話だが、やはり非同期伝送等のbyte streamな方式ではフラグエスケープを使えばいいらしい。そんなわけで、現行のコードをそのまま使うことにした。
論理的帰結と現実が一致するのは、なんだか気持ちがいい。
梅田で「RFC事典」を購入。
PPPの解説があるRFC1548を原文で読む根性がなかったからだが、それだけの理由で9500円もする本をポンと買えちゃうのは我ながらいい身分だと思う。学生の時分なら、3ヶ月は悩んだに違いない。
しかし、厚い、重たい、おまけに高価と、まるでInternet版Datapack。版元もASCIIだし、これで続巻が半分スポンジだったりしたら大笑いである。
VC++6.0続きの続き。
Visual Studio6.0のMSDN disk2にWin32 APIの日本語マニュアルが入っているという話(出典:Amateur Now!
)を思い出し、インストールしていなかった部分を入れてみたら、確かに日本語の説明が出てくるようになった。ただし、主要APIだけ。
本を引っ繰り返せば載ってるような有名どころのAPIなぞ、日本語マニュアルがあってもしょうがない。本当に欲しいのは、SwitchDesktop()とかCreateWindowStation()等のマイナーAPIに関する日本語マニュアルなのだが、見事に全部英語。EnumPrinters()なんて、VC++2.0付属のヘルプに日本語の説明があったのに、今度のでは英語のまま。COM関係がいくらか日本語化されてるのは嬉しいけど、これじゃ使い物にならないなぁ。やたらと遅いし。
ふじさんに修理を依頼していたたんせいRAM
が返ってきた。
Segment 3だけが化けるという謎の症状で困り果てていたのだが、結局直らなかった。ただ、色々対処して貰ったお蔭で全体的な安定性は向上した上、容量が2MB増えて4MBとなったのは本当にありがたい。電流容量が少し心配だけど、EXPANSION SLOT
だから大丈夫かな。
Segment 3が化けるのはどうしょうもないので、ソフトで対処することにした。単にSegment 3を確保して開放しないだけ。RRAMDISKとの兼ね合いで少し困ったが、なんとかなった。本体RAM、うっかりくん
を合わせ、約8.5MB環境。RAMDISKのやりくりを考えなくてもよくなったのは大きい。
ダイヤルアップ接続で使われるHDLCフレームなPPPでは、パケットの開始と終了を示す符号としてフラグ7EH(01111110B)が使われる。
で、このフラグの唯一性を守る為、bit stream1が5個続いたら送信側では無条件に0を挿入し、受信側では挿入された0を除去する。と、教科書には書いてあるのだが、RS-232Cのインターフェイスはbyte stream指向だからこれをやる方法が思い付かない。とゆ〜か、やる意味があるのだろうか?
と思って資料を引っ繰り返していたら、HDLCは完全なbit streamで使われるもので、1byte送信する毎にstart bit/stop bitを挿入する調符式(非同期)伝送とは馴染まないような気がしてきた。だいたい、0挿入をやるなら7EHをエスケープする為のフラグ(7DH)なんて必要ないわけで.....って、HDLCの資料には7EH以外のフラグなんて書いてない。
そんなわけで、7DHによるフラグエスケープを行う場合は0挿入は要らないという結論になったんだけど、どうなんかなぁ。あんまり自信がない。
VC++4.1で、static_castの振舞にバグ発見。
static_castで、class(or struct)への参照を返すユーザー定義の変換を呼び出そうとすると、reinterpret_castと同じ動作をする。
#include <iostream.h> #include <stdio.h> class CMember { }; class CTest { public: CTest(void) {}; virtual ‾CTest() {} operator const CMember&(void) const {return m_sMember;} operator const CMember*(void) const {return &m_sMember;} const CMember& GetMember(void) const {return m_sMember;} private: CMember m_sMember; }; int main(void) { CTest test; cout << static_cast<const CMember*>(test) << endl; // - (1) ポインタへのユーザー定義変換 cout << &(test.GetMember()) << endl; // - (2) 参照への変換関数 cout << &((const CMember&) test) << endl; // -(3) Cスタイルのキャストで参照へのユーザー定義変換 cout << &static_cast<const CMember&>(test) << endl; // - (4) static_castで参照へのユーザー定義変換 return EXIT_SUCCESS; }
(1)〜(4)は同じ値が出力される事を期待して書かれている。実際、VC++5.0/6.0では同じ値になるのだが、VC++4.1では(1)〜(3)がtest.m_sMemberのアドレスを出力し、(4)はtestのアドレスになる。CTest::operator const CMember&()に適当な出力関数を置いて調べると、(4)では変換関数が呼ばれていない。これは、static_castがreinterpret_cast相当の動作しかしていない事を意味している。
intやchar等の組み込み型の参照への変換演算子では、static_castでも問題は発生しなかったのだが、参照を返すのは大抵classかstructであり、あまり慰めになっていない。
まぁ、今時VC++4.1で仕事しているのはウチ位かも知れないけど(4.1の後、4.2/5.0/6.0が出てるから3代も前の製品)。切り替えるときは部署全体でやる必要がある(バイナリの互換性の問題)ので、中々新しくならないんだよね。個人的に最新版を入れる分にはいいんだけど。
RELA/M80用のライブラリを更新。
1998/12/04の7bytesで0〜Fを'0'〜'F'に変換する
ネタを利用して、16進文字列への変換が速くなっている。そんなわけで、手っ取り早く答えを知りたい方はどうぞ。STRING.MACのHEX$Bだったかな。
他に、FILE.MACにルーチンが追加されてたような記憶があるけど、気のせいかも知れない。