byte - みる会図書館


検索対象: 月刊 C MAGAZINE 2000年7月号
15件見つかりました。

1. 月刊 C MAGAZINE 2000年7月号

その実行結果は Fig. 11 に示すとおりであ る。 ( 1 ) はいずれもクラス F00 のメソッドを 呼び出しているが , ( 2 ) , ( 3 ) では callBaz は Bar のメソッドを呼び出すものの , 翻レ ot は F00 のメソッドを呼び出している。この ようになるのはメソッド zot が private のため である。 private メソッドはオーバロードさ れないと解釈されるので , 常にそのメソッ ドの呼び出しコードが存在するクラス内で 解決される。 List4 では , callZot はクラス F 00 で定義されているため , その内側の zot の 呼び出しはコンパイル時にクラス F00 のメ ソッド zot へと解決されているのである。 それに対して c B の内側にある b の呼 び出しは , そのコード自身はクラス F00 で 定義されているものではあるが , こちらは private メソッドではないので起動モードは ⅵれ ual になり , 実行時のオプジェクトのク ラス型からメソッドの検索を始める。その ため , 上記② , ( 3 ) のケースではクラス Bar の b を起動するのである。 シグネチャはコンバイル時に決まる まず , List 5 をご覧いただきたい。クラ ス Foo と , それを extend したクラス Bar があ り , クラス F00 では zot(int,double) , zot (byte,double) , qux (int,double) という三つ のメソッドを定義している。また , クラス Bar では zot(byte,int) , qux(int,double) , qux(byte,double) という三つのメソッドを 定義している ( 返り型はいずれも void ) 。 そして , メソッド main のなかでは , ( 1 ) クラス F00 型の変数に保持されたクラ ス F00 のインスタンス ( 2 ) クラス Ba 「型の変数に保持されたクラ ス Bar のインスタンス ( 3 ) クラス F00 型の変数に保持されたクラ ( 1 ) クラス F00 型の変数に保持されたク ラス F00 のインスタンス ( 2 ) クラス Bar 型の変数に保持されたク ラス Bar のインスタンス ( 3 ) クラス F00 型の変数に保持されたク ラス Bar 型のインスタンス に対して , ca11B と c レ ot を呼んでいる。 F00. baz F00.20t Bar. baz F00. zot Bar . baz F00.20t Java プロクラミングリファレンス 詳説ル K 解体新ロ ス Bar 型のインスタンス という 3 種類のオプジェクトに対して , 以 下の引数とともにメソッド呼び出しを行っ ている。すなわち , zot(int,int) , zot (byte, int) , qux (int,int) , qux (byte,int) という実 引数の型である。 ここで , 実行例 Fig. 12 をご覧いただきた い。クラス F 。 0 型の変数に保持されたクラ ス F00 のインスタンスを通してのメソッド 呼び出しでは , 当然ながらすべてクラス F00 のメソッドが起動されている (Fig. 12 上部のグループ ) 。 次に , クラス B 型の変数に保持されたク ラス B のインスタンスを通してのメソッド 呼び出しでは , 最初のひとつ zot(int,int) の みクラス Foo のメソッドを呼び出し , 残り はクラス Bar のメソッドを呼び出している (Fig. 12 中央のグループ ) 。これは , 最初の zot の呼び出しにおける実引数が "int,int" で あるため , クラス Bar で定義されている zot ( b e , ⅲ t ) とは適合しないためである。 最後が , クラス F00 型の変数に保持され たクラス Bar 型のインスタンスを通してメ ソッドを呼び出した場合であり , これが注 目に値する。最初の z 。 t の呼び出しが F 。。の メソッドを呼び出すのは先の例と同じ理由 であるが , 第 2 の zot の呼び出しも F00 のメソ ッドを呼び出しているのである。これはな ぜだろうか。 こでの実引数は ( b , int ) であるから , Bar で定義されている zot(byte,int) に適合可 能なので , こちらが呼び出されてもよさそ うに思われる。現に , F 。 o 型の変数に格納 された F00 型のインスタンスを通じて q 皿を 呼んでいた実行例の最初のグループでは , あ くまで Foo の q を呼び出していたのに対し , クラス Foo 型の変数に保持されたクラス Bar 型のインスタンスを通してメソッドを呼び 出しているこの最後のグループの実行例で は , qux の呼び出しはどちらもクラス B の メソッドを呼び出しているではないか。 このような違いが生じるのは , 「もっと も適合するメソッド」はコンパイル時に呼 び出しコードの静的な型に基づいて決まり , 呼び出すべきメソッドのシグネチャはそれ に基づいて指定されるためである。この最 後の例では , 静的な型はあくまで変数の型 であるクラス F00 である。そしてクラス F00 に対して zot(byte,int) という呼び出しを行っ た場合 , もっとも適合するのはクラス Foo の zot(byte,double) になる。したがって , の呼び出しによって起動するメソッドのシ グネチャは ( b e , double ) であるとコンパイ ル時に定められるのだ。その結果 , 実行時 にはクラス B から起動するべきメソッドの 検索を開始するものの , Bar の zot ではシグ ネチャが適合しないため , それは起動され ない。その結果 , シグネチャが適合する F00 の zot(byte,double) が呼び出されるのである。 Fig. 11 List 4 のサンプルラン D:%cmaga*javaref>java も is セ 4 F00 F00 but holds a Bar Fig. 12 List 5 のサンプルラン D:%cmaga%javaref>java List5 F00 F00. zo 日 ( in 日 10 , F00. z 。日 (byte)10, F00. qux((int)10, F00. qux ( ( i 北 ) 10 , Bar F00. zo 日 ( in 日 10 , Bar. zot( (byte)10, Ba て . q ( ( 土 n 日 10 , Bar. qux((bYte)10, ( doub 厄 ) 20 . 0 ) ( doub 厄 ) 20 . 0 ) ( doub 厄 ) 20 . 0 ) ( do 面厄 ) 20 . 0 ) ( doub 厄 ) 20 . 0 ) ( int ) 20 ) ( doub 厄 ) 20 . 0 ) ( do 面厄 ) 20 . 0 ) F00 but hol ds a Bar F00. F00. zot((int)10, 20t ( (byte)10, Bar. qux((int)10, ( d 。厄 ) 20.0 ) r. 叩 x ( ( 土 nt ) 10 , ( do 厄 ) 2 0 . 0 ) ( doub 尾 ) 20 . 0 ) ( do 厄 ) 20.0 ) Java プログラミングリファレンス詳説 JDK 解体新書 119

2. 月刊 C MAGAZINE 2000年7月号

J a フ恤クラミングリファレンス 詳説 JDK 解体新 呼び出し対象オプジェクトが特定されて パイルせずに古いバイナリを使うと実行時 static メソッドはコンバイル時に解決されている いれば , それにロックをかける。さもなけ にエラー (NoSuchMethodError) になる。 れば (static メソッドの場合 ) , ロック対象は Fig. 9 の ( 1 ) からもわかるように , 呼び出 P 「 ivate メソッドは仮想起動しない し対象メソッドが s ねⅱ c の場合 , それがどの 該当のクラスオプジェクトである。また該 F1g. 9 の ( 3 ) では , 起動モード "nonvirtual 当メソッドの実行が正常終了であれ中断終 クラスに属しているメソッドであるかはコ 了であれ , 完了したあとにはロックは自動 ンパイル時に決定されている。より正確に の場合の説明をしている。その影響を示す いえば , static メソッドの呼び出しコードが 的に解除される。 のが List 4 である。クラス F00 のなかで , メ 含まれているコンパイル単位をコンパイル ソッド b と zot を定義している。 baz は prote 注 . すべき動 した時点で , どのクラスに従属するメソッ cted であり , zot は private である。またこれ ドを呼び出すかが決定され , クラスファイ らを間接的に呼び出すメソッド callBaz と 以上の仕様からの帰結として , 呼び出す caIIZot を定義している。それから , F00 を ルのなかに指定される。したがって , 呼び 出される側のコンパイル単位で s ねⅱ c メソッ べきメソッドの解決については注意を要す extend したクラス Bar においても , 同様に ドを定義する位置をクラス階層の上に移 protected baz と private bar を定義している。 る動作が生じる。それらのいくつかについ て最後に簡単に触れておこう。 すような変更を行い , 呼び出し側を再コン そして , メソッド main のなかでは , シグネチャはコンバイル時に定まっている s 起動モード non ⅵ ua に起動モードⅵ「 tu 引 / * List5. javä * / * シグネチャはコンパイル時に定まっている class F00 ( public 0 土 d 20 日 in セ n, double x) { SY em. ou し prin れ ( ” F00. zo こ ( (int)* public void zot(byte b, do 曲地 x) ( system. out. printIn("F00.20日 (byte)" 十 b 十な public void qux(int れ , double x) { / * st4. java * / * 起動モードれ onv 辷 tu 引と起動モード v 近 t ー class F00 { protected void ) ( system. out.println( ” F00. baz っ private void 名 0t ( ) ( system. ou し . p て土 n 目 n ( ″ F00.20 セつ public void caIIBaz( ) { / / v 土て tu モード baz(); public void ca 日 20 セけ ( 〃れ 0 れ辻 u 引モード 20t ( リ 十れ十 % (double)" 十 x 十つ” ) ・ ( do 曲厄ド + x + 物尸わ ( do 面厄尸十十つつ・ system. 0uしPてin凵n(”F00. qux((int)" 十 n 十” class Bar extends を 00 { public void zot(byte b, int m) ( system ・ out.println("Bar. 20t( (byte)" 十 b 十 public void x ( 土北 n, dO x) { system. out. printIn("Bar. qux( (int)" 十 n 十 public void qux(byte b, do 面 le 幻 ( class Bar extends を 00 { protected void baz( ) ( system. out. println("Bar. baz 0 て土 va セ e void 20t ( ) ( system ・ 0uしPて土n日nに Bar. 20 し (int)" 十 m 十つ″ ( do 面厄尸十 x 十”ド system. out.println("Bar. qux( (byte)" 十 b 十第 , (double)t 十 x 十物尸リ 0 lass List4 extends Bar { public static void main(String[J args) F00 myFOO = new F00 ( ) ー て myBar new Bar( system. out. println( ” F00 つ myF00. caIIBaz( リ myFoo. callZot( system. out. println(" system. out. printIn("Bar"); myBa て . caIIBaz( myBar ・ callZ0t( system. out. println(* system. out. Pて土n凵nにF00 but holds a Bar" リ myFoo ま myBar; myF00. caIIBaz( myFOO. ca Ⅱ 20 日 c lass も土虻 5 { public static void main(string[ ] args) F00 myFOO ま new F00 ( ) ・ Bar myBar = new Bar( byte b ま 1 の system. out. Pて土n凵nにF00”リ myF00. zo 日 10 , 20 myF00. zot(), 20 リ myFOO. qux(10, 20 myF00. qux(), 20 リ System ・ 0uしPてin日れに system. out.println("Bar") 引 myBar. Z0t(10, 20 ) : myBar. zot(), 20 myBar.qux(10, 20 myBar. qux(), 20 潺 system. ou し printl n に system. out. println( ” F00 but holds a Bar"); myFoo = myBar; myFOO. zot ( 10 , 20 myF00. zot(), 20 myFOO. qux(10, 20 リ 叫 F00. q 皿 ( b , 20 ) を 1 18 C MAGAZINE 2 0 7

3. 月刊 C MAGAZINE 2000年7月号

いる値が代入先の型で表現可能であるなら ば , 特別に縮小変換を許容しようというの がこのルールの趣旨である。たとえば代入 先が b e 型の変数の場合 , -128 から 127 まで の int の値であれば , 暗黙のうちに b e 型へ 変換され , 代入が行われる。 しかし , 日 g. 2 に示すようにメソッド呼び 出し変換においてはそのような特別扱いは 行われない。 int の実引数はあくまでⅲ t 以上 の引数にしか変換されない。これをしつか り認識しておかないと , 適用可能なメソッ ドがどれであるかの認識を誤ることになる。 listl をご覧いただきたい。このサンプル プログラムでは三つのクラス F00 , Bar , Baz を定義していて , それらは F 。。を頂点 とするサプクラス階層を形成している。そ してすべてのクラスで zot というメソッド を定義しているのだが , その引数の型が少 しずつ違っていて , F00. zot (double,doub (e) , Bar. zot ( ⅲ short) , Baz. zot(byte, char) となっている。 さてここで , クラス ListI の main メソッド の内側で , B のインスタンス myB に対し Java プロクラミングリファレンス 詳説 JDK 解体新 て , 加 t ( 10 , という呼び出しを行った場合 , どのメソッドが起動されるのだろうか。 まず実引数の型を調べると , (int,char) と なる。それに対してクラス Baz の zot は , 第 一引数が b e であり , int → b e の型変換は できないため , このメソッドは適用できな い。次にクラス Bar の zot は , 第一引数はⅲ t であって型変換可能 ( 恒等変換 ) であるが , 第二引数が short であり , char → short の型 変換はできないため , このメソッドもまた 適用できない。結局 , 適用可能なのはクラ ス Foo の zot であり , この場合ふたつの実引 数はいずれも double に型変換されて受け取 られる。もちろん , 実引数を明示的にキャ ストしたり , 変数を用いて型を指定したり することで , 特定のメソッドを適用可能に することもできる (Fig. 5 ) 。 もしも , 以上の条件を満たすメソッドが ひとつもなければ適用可能なメソッドは存 在しないということであり , コンパイルエ ラーである。逆に適用可能かつアクセス可 能なメソッドが複数存在する場合には , も っともよく適合するものを選択する。その 方法は Fig. 6 に示すルールに基づいて行う。 このルールは , スーパークラスよりもサプク ラスの側で定義されているメソッドのほう が , より引数の型を特定していれば , そち らがより適合するという内容である。いい 換えれば , サプクラスでのメソッドは , 引 数の型もサプクラスになっていればよい。 引数の型が数値型の場合には , サプクラス のメソッドの引数の型は , より表現範囲が 狭い型になっていればよい。つまりこれは , F1g. 3 に示した基本拡幅変換の図の矢印を逆 にした関係 ( たとえば , double → float , float →ⅲ t など ) であればよいということである。 このルールによって , もっとも適合するメ ソッドがひとつだけ特定できればそれを呼 び出す。しかし , その手順によってメソッ ドをひとつだけに絞ることができなけれ ば , 「呼び出しが曖味である」として , コン パイルエラーにする。この実例については 前回示したので , こでは省略する。 メソッド呼び出しの妥当性の検査 上記ふたつのステップを経て , 呼び出し Fig. 2 メソッド呼び出し変換として行われる 3 種類の変換 ( 1 ) 恒等変換 (identity conversion) (2) 基本拡幅変換 (widening p 「 imitive conve 「 sion) (3) 参照拡幅変換 (widening 「 efe 「 ence conversion) Fig. 3 基本拡幅変換 矢印の方向には基本拡幅変換が可能であり , 複数の矢印を経由してもよい。 たとえば , byte を dou e へ変換することもできる。 byte → short → int → long → float → double ↑ Cha 「 Fig. 4 代入変換の第 4 ルール ( 4 ) 基本縮小変換 ( na 「「 owing p 「 imitive conve 「 sion) ただしこれは ・式が int の定数式 ・変数の型が byte , sho 「 t あるいは cha 「 ・式の値が変数の型で表現可能な値のときにかきる 1 14 C MAGAZINE 20g 7 Fig. 5 List 1 のサンプルラン D:%cmaga%Javaref>java ListI F00. zot ( ( doub 厄 ) 10.0 , ( do 厄 ) 97.0 ) Bar. zot((int)10, ( sho て t ) 97 ) Baz. Z0セ((bYセe)10, (char)a) Fig. 6 もっとも適合するメソッドの決定ルール [ 前提 ] n 個の引数を持つメソッド m の呼び出しがあり , それに適用可能で , かっ アクセス可能なメソッドがクラス T とクラス U で定義されているものとする。 [ 条用 このとき , 以下の条件をともに満たせば T で定義されたメソッド m は U で定 義されたメソッド m よりもより適合するメソッドである。 ( 1 ) T はメソッド呼び出し変換によって U に型変換できる ( 2 ) 1 .. n のすべての j に対して , 仮引数工は対応する仮引数 U にメソッド呼び出 し変換によって変換できる ただし T で定義されたメソッドの仮引数を TI.. Tn とし U で定義されたメ ソッドの仮引数を UI ・・・ Un とする ー注意 ] この条件判断において , メソッドの返り型は考慮されない

4. 月刊 C MAGAZINE 2000年7月号

耳むずかしな力ドジりました 第朝回 CVS 入門の入門 宏 石合 な市場競争のある製品に共通しているのは , 備投資を要しますが , ソフトウェア産業の 素っ裸のプログラミングから 製品の規格の共通化および公共化です。各 市場競争への参入は南アジアやアフリカな 卒業 社とも , 同じ製品規格の上で競争をする。 どなどの超貧乏国の人々にも十分に可能で Micros 社の分割が仮に実現したとして 規格が共通しているからこそ , 競争もあり す。しかしそれが実際に可能であるために も , 独占という状態は解消されませんよね。 える。パソコンのソフトウェア業界に活況 は , OS をはじめとする主要ソフトウェアの 規格の公共化 = 独占の打破が必要です。 この最も肝心と思われる問題を法廷やマス をもたらすためには OS としての Windows , コミ等が無視しているのは , アメリカでは および主要実務ソフトとしての Word , Exc パソコンのハードウェアの面では , 日米の 有名大企業の製品の中身はほとんど台湾製 独占そのものは違法ではないからだそうで el , Access , lnternet Explorer あたりの仕様 規格が公共化される必要があります。 ですが , ソフトウェア的にもいろんな国の す。反トラスト法は , 独占そのものではな 異なる規格の乱立は , 消費者の不利であ ・・・ Microso れ独占時代に比べると随分安い く独占という立場を利用して行う競争妨害 行為を禁止しています。ずば抜けて最大の り労働者の不利であり産業界一般の不利で ・・・製品がバンドルされるようになるとお す。ですから , OS である Windows だけでは もしろいし , 超貧乏国の経済の底上げに寄 競争妨害行為が独占ではないか , と私なんか なく , OS の独占という立場をベースに築か 与していきます。 常識人の常識の一環として思うんですけど。 れてきた主要実務ソフトにおける実質的な そうやってソフトウェア産業の全世界的 今はアメリカでも日本でも , パソコン雑 な多様化競争化活況化が進めば , 本誌に代 独占 = たまたま確立してしまったデファクト 誌に中 ~ 上級誌というものがすっかり姿を 表されるようなプログラミング技術誌なん スタンダードに関しても , それらのソフト 消しました。先年の BYTE 誌の廃刊は , 中 かの部数は飛躍的に伸びますね。英語版や ウェアの規格が公共化されることによって , 級誌としてのメジャーな雑誌だっただけに スワヒリ語版やベルシャ語版の C MAGAZI 彳的でした。今書店で建在なのは Windows, 独占の打破 = 競争状態の導入が図られる必 NE を作って , どんどん輸出する必要があり 要があるのです。 Microsoft 社も , 「独占者」 iMac , Microsoft Word , 同 ExceI , 同 Acc ますね。アメリカのプログラミング誌はい から他と互角な「競争者」へと一変しなけれ ess などの初歩的な使い方を教える初級誌の ばなりません。それでやっとわれわれも , 初 くつかの "Microsoftå, 支術誌 " を除いてはほと みです。これがたとえば「ワープロソフト : んど廃刊になっていますから , 本誌などに めて , すっきりした気分になれるでしよう ! M ⅳ 09 Word と BorI d Word と Lotus Word 各社の製品がすべて公共化された共通規 チャンス ? いやいや , そうなると BYI 、 E 誌 の三強を比較する」というテーマなら中級誌 格を完全に実装している ( その実装技術に優 の記事になりえるし , またこれら競争状態 なども墓場から元気に蘇ったりしますから , 劣の差が生じる ) と共に , 各社独自の " 付加的 楽観は禁物です。 にある企業からの広告が雑誌の経営を支え 機能 " を売り物にしてもよいと思います。忙 BYTE 誌のような中級誌は , 個人がコン ます。 BYTE 誌等の廃刊は , 中級誌として しい労働者ューザはたぶん共通規格の部分 ビュータを使うこと ( " パーソナルコンピュ の話題も広告源もなくなったことによる " 枯 ーティング " ) の中にはある程度のプログラ の機能しか使わないと思いますが・・・ 死 " です。 ミングも含まれるという考えを前提として 自動車や半導体製品のようなハードウェ テレビなどの家電製品 , 自動車 , パソコ いました。これはパソコンの前のミニコン アは , そういう産業を興すために巨額な設 ンのハードウェア (Mac 系を除く ) など , 健全 C 言語フォーラム 149

5. 月刊 C MAGAZINE 2000年7月号

同期単位に変更することで対処可能です グラフィック , スプライトの多重画面を実 ッフアへのアクセスがはるかに多いことか 機の 3 倍程度の速度で毎フレーム合成する ら画像合成に最適化して割り当てます。 が , この方法はオーバヘッドが少なくない 必要があります。この部分に処理時間がか ため , 現在は MPU のエミュレーション内の また合成した画像を DIB として保持する 描画時に水平同期信号から走査線 [ 注 2 ] の位 かるようであれば MPU のエミュレーション ためのバッフアは表示するために必要なサ 時間を削るか , 画像生成と画像転送自体を 置を算出して描画タイミングとともに記録 イズのほかに左右に 32 ビットぶんの余白を 間引く必要が出てきます。 をとっています。この記録を画像生成の段 割り当てます。もちろん , この領域が画面 階で利用することでスプライトダブラやラ に表示されることはありませんが , 画像合 さらに X68000 のハードウェアの機能では インスクロールを擬似的に再現しています。 成の際にスクロールにより画面外へはみ出 ありませんが , ゲームソフトのなかにはス [ 注 2 ] ここで再現している走査線のタイミング プライトダブラといわれる走査線と同期を た描画をクリッピングするための判定ルー は仮想マシン内でのタイミングで , Windows 画面 チンの代わりに利用できます。この領域を とりながらパレットデータやスクロール位 の走査線との同期はまったくとっていない。 での同期合わせは一般的に使われる Windows の 置 , スプライトの位置の再定義 , プライオ 設けることにより左右 16 ピクセル内のクリ 画面の垂直同期信号に合わせた画面切り替えと は別の目的で使われる。 リティの再設定を行い , それをダイナミッ ッピング処理を行う必要がなくなります。 クに画像生成するテクニックを使ったもの 資源の実装 バレット変換 があります。たとえば表示途中で背景のパ レットを書き換えるとその時点から下の画 画像の生成はすべての機能を実装してい X68000 と Windows ではビデオバッフアの 面の背景は新しいパレット色で表示されま ない現在の EX68 でも負荷の重いものになっ RGB の定義が違うため , ピクセル単位での す。スプライトやバックグラウンドも走査 ています。実機の X68000 と互換性を高める データの変換が必要になります。 Windows, 線ごとにスクロール値を書き換えることに ためには画像生成を高速に行う必要があり X68000 ともに 16 ビットを使用したカラーモ より , 1 ライン単位で表示位置を入れ替え ます。 ードが存在しますが , これらは Fig. 7 に示 ることができます。 EX68 では画像合成をフ まず , EX68 の行う画像生成ルーチンのた すように RGB の並びが違うだけでなく , 輝 レーム単位で行っているため , このままで めの資源を定義します。実際の画像生成で 度ビットの有無という違いもあります。 はこれらの機能を再現できません。 は MC68000 のエミュレート部からのアクセ X68000 では RGB 各 5 ビットのほかに残り 根本的には画像合成のタイミングを水平 ス頻度より画像生成のための仮想ビデオバ の 1 ビットを RGB 共通の最下位ビットとし パフォーマンスカウンタでエミュレーション結果を計測する ビットマップテキストの変換処理 / / TEXT の 4 プレーン 8 ピクセルを 4b / p 土 xel x 8 に変換するテーブル #define h(b) ( ( 0X80 ) ” 7 ) 十当 ( ( 0X40 ) ” 2 ) 十当 ( ( 0X20 ) くく 3 ) 十 ( ( 0X10 ) くく 8 ) 十 ( ( 20X8k く 13 ) = 十当 ( ( b & 0X4 ) くく 18 ) + ( ( b & 0X2 ) くく 23 ) 十 ( ( b & 0x1)< く 28 ) const ÜLONG bcnv—tt ] = h(8),h(9),h(0xa),h(6xb) ,h(Oxc5,h(Oxd),h(0xe)'h(Oxf), . 省略 . Oxf0 ) ( 0xfI ) h(0xf2) れ ( 0xf3 ) h(0xf4) h(0xf5) h(0xf6) h(0xf7) h(0xf85,h(0xf95,h(0xfa5,h(Oxfb5,h(0xfc5,h(0xfd5,h(0xfe5,h(0xft5 *defåne TEXTCDNV —asm ( 当 XO て eax'eax 第 —asm XO て ecx ecx —asm mov 引 ,byte ptr X6. tmem 十 0X60000 [ es 幻 —asm mov cl ,byte ptr X6. tmem 十 0X60001 [ es —asm mov ebx,dwo て d p セて [bcnv—t 十 eax*41 —asm mov edx,dword ptr [bcnv—t 十 ecx*4J —asm —asm 加 OV al,byte p とで X6. と mem 十 0X40000 [ esi ] mov cl,b e ptr X6. tmem 十 0X4000 es 土 ] lea ebx,rebx 十 ebx] —asm —asm —asm lea edx, [edx 十 edxl 0 て ebx,dword ptr bcnv—t 十 eax*41 or edx,dword ptr bcnv—t 十 ecx*4) 当 —asm mo al,byte p セて X6. tmem 十 0X20000 [ es 土 1 —asm mov cl ,b e ptr X6 北 mem 十 0X20001 [ es 幻当 lea ebx ltebx 十 ebx] 当 —asm —asm lea edx 靆 edx 十 edxl asm or ebx ′ dword ptr [ bcnv-t 十 eax*4 ] 蕚 asm 0 て edx,dword p して tbcnv—t 十 ecx*4] 蕚 mov 引 ,byte ptr X6. tmem 十 0X00000 [ es 幻 asm e tr X6 . tmem 十 0X0 圓 01 [ es 幻 厄 0 0 最 b 、呈 eb 幻 asm —asm lea edx , [ edx 十 edx ] —asm or ebx,dword ptr [bcnv—t 十 eax*4) —asm 0 て edx,dword ptr [bcnv—t 十 ecx*4] 当 asm *if PERFORM void perfdif: :readl() ~ (X6. perf. use) QueryPerformanceCounter( (—LARGE—INTEGER*)&lpIiPerformanceCount1); void perfdif: :read2( ト (X6. perf. use) QueryperformanceCounter( ( —LARGE—工 NTEGER* ) & ゆ liperformanceCount2); void perfdif: :culc() 土 (x6. perf,use) msec=( IpIiPerformanceCount2-lpliPerformanceCount1)*10000/X6. perf. pe て fNVi / / 。 if (rmax«sec) mmax=msec• s し [ (hpt4+)&15]=msecv 、 void perfdif: : p て t ( 0 r *msg) sprintf ( s zbuff, .1fmS #endif #if PERFORM void perf: ;chk—device( ) union { LARGE—INTEGER 、 lpIiperformanceFreq; 土 nt64 perf64; LARGE—INTEGER ゆ liPerformanceCount ー can=QueryPerformanceFrequency(&lpliPerformanceFreq)i if (can) can=QueryPerformanceCounter ( & ゆ liPerformanceCount); if (can) / / ー perf1V=perf64/60; perfNV=perf64;- use=can char セ emp [ 256 sprintf(temp perf Freq: 制 x 08 ⅸ rlpIiPerfo て mancepreq. 日土 hParti ゆは 20r 0 て manc ・ F = ・ q. LO ・ pa てし卩 p は p ・て formanceF = eq. も owpar セ / 1000 ヲ 1000 add—information( (CString)temp); (fIoat)msec/10, msg); / / co 聞レ sec #endif 50 C MAGAZINE 2000 7

6. 月刊 C MAGAZINE 2000年7月号

特集 3 ペク村レ量子化のレゴリスム す。たとえば 16 次元のべクトルを 256 個に 量子化する場合 , 再帰回数は 8 回なので , すべての軸で分割が行われる以前の段階で べクトル表が飽和してしまいます。これは べクトル成分当たりのビットレートを 1 ビ ット未満にできないことを意味します。ま た , 分割数が 2 のべき乗でないと具合がよ くないことも明白です。 階層型クラスタリング 再帰分割はトップダウン手順ですが , 階 層型クラスタリングはポトムアップ手順と なります (Fig. 5 , 6 ) 。 量子化誤差は , 住と / の距離に住の個数 を乗じた値と , 滝と / の距離に滝の個数を 乗じた値との和で与えます。 この方法は , ハフマン符号の考え方と似 ています。この手順が最良の色集合を与え ることは数学的帰納法で説明できます。し かし計算量が色数 N の 3 乗に達するのでは , 安心して使うことができません。もちろん , 計算量は N の 2 乗オーダにまで落とせます。 そもそも量子化誤差が最小となるべアを見 つけるのには 2 乗オーダの計算量が必要で すが , これを毎回行う必要はありません。 色と色胃を併合して重心色 / に置換する とき , 量子化誤差の統計を維持するには更 新された夜卩 / に関係する箇所だけ計算し 直せばよいのです。 たとえば , 色の構造体に最良近似候補 ( もっとも併合損失が少ない色 ) へのインデ ックスと最良近似候補との量子化誤差を保 持しておきます。併合された住滝はきわめ て近い位置に存在するか , または所属画素 の個数が少ないかのどちらかです。距離が 近ければほかの色が最良近似候補として。 または滝を選択する確率は低いことになり ます。画像の性質・・・・・・グラデーションなど の滑らかな濃淡変化を構成するには , 多く の似た色が必要なので , 住か滝の度数が低 いこと自体 , この周辺に色の分布する確率 が小さいことを意味します。いずれのケー スでもかが最良近似候補に選択される 確率は低いといえます。 ほかの色が最良近似候補として住か滝を 選択している場合は , 量子化誤差を求め直 します。また新たに加わった / に対しては まだ情報が存在しないので , / とほかの色 との距離を求めます。このとき , / との量 子化誤差がすでに保持している最小の誤差 よりも小さくなる場合は , 相手の最良近似 候補を / に更新します。階層型クラスタリ ングを適用する場合には , 常にこうした高 速化の手法を使うべきです ( List2 ) 。 階層型クラスタリングの分割統治法 アルゴリズムに詳しい方なら , 整列アル ゴリズムを連想して分割統治法へたどりつ くことと思います。学習データが大きすぎ い ヨ ド 朝 1 再帰分割のサンプルコード / / 再帰分割 ( メディアンカット ) で色集合を求める #include <windows . h> #include く s に d 土 0 . h > # incl ude <string. h> #include <stdlib. h> typedef struct tagBGRE{ unsigned char b,g,r,e; typedef struct tagRANGE{ unsigned char bmin,gmin,rmin,bmax'gmax,rmax; unsigned char bits[3] [ 32 unsigned ー ong bsum , gsum , rsum , count ー RANGE; / * 118 byte * / int i ー int minmax(BYTE* hist, BYTE* imin, BYTE* imax) / * ヒストグラムから領域境界の未使用部を詰める * / BGRE; 土十十 ) ヨ 1 3 1 / * 最適な色集合をて e [ ] に生成する * / void sampling(BGRE bg て e [ 256 ] , FILE* bmpfile) fo て (bits=0; b 土セ s く = bits 十十 ) { range->bmax = range—>gmax = range->rmax = 255 ー memset(range' 0 , sizeof range); RANGE range[256]; long curloc = ftell(bmpfile); int b , g , て , 1 , , bits , stop , current—range for ( i=0; i く current—range; i 十十 ) { = EOF) break; if ()r = getc(bmpfile)) = EOF) break; if ()g = getc(bmpfile)) = EOF) break; if ()b = getc(bmpfile)) for (; memset(range[i] . bits,O,sizeof(RANGE)-6); for ( i= 0 ー i く current—range ー土十十 ) printf( "*rQuantized 宅 d / 8 level", bits); fo て (i=O; i く 256 & & (hist[i/8] & ( 1 くく (i & 7 ) ) ) if ( 土く = *imax) *imin = i; fo て ( 土 = 25 i>0 & & (hist[i/8] & ( 1 くく (i & 7 ) ) ) if ( 土 > = *imin) *imax = i; return * imax ー *imin 十 1 ー / * 区間幅 * / RANGE* rc = &range[oldpos]; VOid devide(RANGE* range, int newpos, int oldpos) / * range[newpos] と range [ 引 dpos ] に分割結果を書き戻す * / / * クラスタを分割する。元クラスタはて ange [ 引 dpos ] で与え * / range[newpos] . bmin = rc->bsum 十 range[oldpos] . bmax = rc->bsum; . rmin = rc->rsum 十 1ー return; range[oldpos] . rmax = rc->rsum; if ()w >= gw & & rw > = (w){ / * select て vector * / range [ newpos ] . gmin = rc->gsum 十 1 ー return ・ range[oldpos] . gmax = rc-ygsum; if ()w >= bw & & gw >= てⅵ { / * select green vector * / memcpy(range 十 newpos, sizeof(RANGE) int rw = minmax(rc->bits[2] , &(rc->rmin) , &(rc->rmax) int gw = minmax(rc->bits[l] , &(rc->gmin) , &(rc->gmax) int bw = minmax()c → bits[0] , &(rc->bmin) , &(rc->bmax) if (b くて ge [ 幻 . in Ⅱ if (g く range[i] ・ gmin Ⅱ if (r くて衄ge[幻 . rmin Ⅱ break; range[i] . bsum 十 = range[i] . gsum 十 = g; range[i] . rsum 十 = て一 range[i] . count 十 = range[i] . bits[0][ (b ” 3 ) ] range[i] . bits[l][ (g >> 3 ) ] range[i] . bits[2][ ( て” 3 ) ] fseek(bmpfile, curloc, SEEK—SET); fO て ( 土 = i<current—range; 土十十 ) { b 〉 range[i] . bmax) continue; g > range[i] . gmax) continue; て〉 range[i] . rmax) continue; ( 1 くく仕 & 7 ) ( 1 くく (g & 7 ) ( 1 くく (b & 7 ) / * 色の重心 ( 平均値 ) を出す * / if (range[i] . count = = 0 ) range[i] . count = bgre[i] . b = (range[il . bsum / = range[i] ・ C0聞し嶹 bgre[i] . g = ( て ge [ 幻 . gs / = r 聞 ge は ] ・ co 聞し 地 re [ 幻 . て = (range[i] . rsum / = r ge は ] ・ co 聞し bgre[i] . e = if (bits = 8 ) break; / * if 256 color done * / stop = current—range ー for ( 土 = i<stop; i 十十 ) devide ( range , current—range 十十 , i 特集 3 べクトル量子化のアルゴリズム 63

7. 月刊 C MAGAZINE 2000年7月号

indows 用 68000 工ミュレータの 仕組み 説明 ため , これらを利用して演算と演算結果のフ ラグを得る処理を高速化することが目的で す。 MPU 工ミュレーションの基本 MPU 工ミュレーションの 1 サイクルは MC 68000 プロセッサの実行サイクルの動作を分 解したものになります。 MPU 工ミュレーショ ンの処理の流れは , 1. MPU に対する割り込みの処理 2. オペレーションコードの読み出し 3. オペレーションコードのデコード 4. インストラクション実行ルーチンの呼び 出し 5. データリードルーチンの呼び出し 6. 演算 , 代入などの処理の実行 7. データライトルーチンを呼び出し , 演算 結果を出力 8. 処理にかかった MC68000 のクロック数を 算出し , 同期信号を作る 9. 同期信号により , WindowsiJf イスとの 入出力を呼び出す 10. 以上の処理を繰り返す となります。 まず , MPU に対する割り込み要求がある かどうかを調べます。 MPU の外部からの割り 込み要求がある場合 , プログラムによってマ スク設定されている割り込みレベルと比較し て , それが有効であれば割り込みシーケンス を実行します。この外部からの割り込み要求 工ンティアンの変換を行う / / 工ンディアンの変換 //long word 4bytes inline int bswap(int data) —asm { mov eax,data bswap eax ーこれがエンディアン変換命令 # 引 se inco ーー ax て 0 て mov ax,incol -asm { #if USE—ASM 土 n は e USHORT bsw(USHORT 土豆 COI) //word 2byte / / 工ンディアンの変換 mov data, eax 滝ードの変換は巡回シフト命令を使う #endif return ( (in>>8)&0xff) 十 ( ( in くく 8 ) & Oxff00 TabIe 1 EX68 がエミュレート対象とする X68000 のハードウェアの概要 カテゴリ MPU メモリ 周辺 LSI 名称 HDC CRTC PPI ADPCM FM 音源 FDC RTC SCC MFP DMAC SRAM スプライト VRAM グラフィック VRAM テキスト VRAM メインメモリ CGROM IPLROM サ 5CPU メイン MPU チップ名 / 容量 MC68000 MSM80C51 256K バイト 768K バイト 1 ~ 12M バイト 10MHz 8 x 8 ドット ~ 24 x 24 ドットのフォント IPL, BIOS キーボード用サブ CPU 512K バイト 512K バイト 32K バイト 16K バイト H D63450 NC68901 Z8530 日 P5C15 uPD72065 YM2151 MSM6258 uPD8255 カスタム L カスタム L 、ユレー はエミュレーション内デバイスのエミ ンが呼び出されます。さらに , MPU 外へのア ードに応じて用意されたデータリードルーチ 実行ルーチンのなかから , アドレッシングモ このインストラクションごとに用意された ンプリメントします。 す。これからは実行ルーチンごとに動作をイ タといっしょに実行ルーチンに制御を渡しま 理内容は違いますが , 2 次テープルのポイン インストラクションの実行ルーチンごとに処 ストラクション実行ルーチンを呼び出します。 す。そして , デコードの結果 , 対応するイン ーにしてテープル参照を行い , デコードしま ペレーションコードは 2 バイトのコードをキ る最初のステップになります。読み出したオ チを行います。これはすべての命令を解釈す ンタ PC の値を元にインストラクションフェッ 割り込み判定処理の次は , プログラムカウ みレベルも更新します。 します。同時にステータスレジスタの割り込 レスを読み出し , プログラムカウンタに設定 クタテープルから割り込みに応じた処理アド スタック上に退避したうえで , メモリ上のべ プログラムカウンタとステータスレジスタを 割り込みシーケンスでは MC68000 の現在の ション結果として要求されているものです。 バッテリバックアップされたメモリ 4chDMA コントローラ 割り込みやキーボードとのインタフェイス 日 S232C とマウス用 時計 フロッピードライブのコントローラ 8chFM 音源 LSI ADPCM 音源 LSI ジョイスティック用 画像関係 ハードディスクインタフェイス SA 用 クセスが起きた場合は , 周辺デノヾイスを特定 するためのアドレスデコードを行い , デバイ スごとに用意されたデータリードルーチンへ と処理が引き継がれます。 アドレスデコード後のデータリードルーチ ンはデータのサイズ別に計 3 タイプを , それ ぞれのデバイスごとに個別に用意します。 こでワードとロングワードの読み込みには工 ンディアンの変換が必要なので注意してくだ メモリの読み込み以外ではデバイスごとに 違いますが , ステータスやパラメータを返す ことがおもな動作です。デバイスによっては 内部シーケンスに応じて返すパラメータが変 化するので , コマンドシーケンスを解釈する 必要があります。インストラクションによっ てはさらに連続するアドレスから複数のデー タリードルーチンを呼び出したり , 別のアド レッシングモードでデータリードルーチンを 呼び出します。 次に読み出されたデータ , あるいはレジス タの値を使い , インストラクションごとに必 要な機能 , 演算 , 代入を行います。演算はオ ーバヘッドを減らすため , 可能なかぎり Pen ⅱ um のインストラクションで置き換えていま す。このとき , MC68000 のフラグを更新する 特集 2 Windows 用 X68000 工ミュレータの仕組み 43

8. 月刊 C MAGAZINE 2000年7月号

Java プロクラミングリファレンス 詳説 JDK 解は新ロ か , fo 「文における「初期化部分」およ び「更新部分」のいずれかがそれに該 当する これらの検査のどれかに適合しない場合 , コンパイルエラーとなる。 以上の検査をすべて通過してコンパイル 時の作業は完了であり , コンパイラは , 各 メソッド呼び出しについて Fig. 7 に示す内容 の情報をクラスファイルに書き記す。以下 で説明するように , 実行時にこの情報を参 照して , 実際に呼び出すメソッドを最終的 に決定するのである。 メソッド呼びし ~ 実行時の作業 コンパイル時にかなりのチェック作業を 終了しているとはいえ , Java におけるメソ ッド呼び出しでは , 実行時にもかなりの作 業工数が必要になる。 Fig. 1- ( b ) にも示した ように , その作業は五つのステップから 構成される。 呼び出し対象オブジェクトの特定 条件から妥当なものであるかどうかを検査 Fig. 7 各メソッド呼び出しに関連して記される情報 実行時にまず行うのは , どのオプジェク することである。 1 . メソッドの名前 トを通してメソッド呼び出しを行うのか ( あ この検査は以下の三つに分けられる。 2. メソッドのコンバイル時の宣言が行われた 型 ( クラス 0 「インタフェイス ) (l)static メソッドの呼び出しのみが可能 るいは , そのようなオプジェクトはないの 3. 仮引数の個数とそれぞれの型 か ) を定める作業 , すなわち対象オプジェク なコード部分から呼び出しているメソ 4. コンバイル時に宣言された返り型 トの決定である。簡単にいえば , static メソ ッドが , 実際に s ね tic メソッドである 5. 以下で決定される起動モード ッドを呼び出す場合 , 対象オプジェクトは かの検査。ここで , static メソッドの 5-1 . コンバイル時の宣言に static 修飾子が指 定されていれば , 起動モードは static ない。そうでない場合には , 何らかの形で 呼び出しのみが可能なコードは , sta 5-2. さもなくて , コンパイル時の宣言に 対象オプジェクトを特定する。以下 , 該当 tic メソッドの本体 , static 初期化子の p 「ⅳ ate 修飾子が指定されていれば , 起 メソッドは s ねⅱ c でないことを前提にする。 内側 , static 変数の初期化子部分など 動モードは nonvirtual メソッド呼び出しのソース上の記述が単 である 5-3. さもなくて , メソッド起動の名前指定部 分「 supe 「 . 識別子」の形であれば , 起動モ なる識別子からなる場合 , たとえば o ( x , ( 2 ) メソッド名に「型名 . 識別子」という形 ードは supe 「 y ) 」のような形式であれば , これは実は「 this. 式を用いて呼び出しているメソッド 5-4. さもなくて , コンバイル時の宣言がイン ( x , y ) 」の省略形であると解釈されるから , が static メソッドであるかの検査 タフェイス型で行われていれば , 起動モ 対象オプジェクトは this の値である。 ( 3 ) 呼び出しているメソッドの返り型が ードは interface 5-5. さもなければ , 起動モードは virtual 呼び出し対象オプジェクトの指定部分に void である場合には , それを呼び出 式が用いられている場合 , その式を評価し , すことが許される文脈からの呼び出 その結果得られるオプジェクトを対象オプ しであるかの検査。ここで , 返り型 をする対象のメソッド名 , そのメソッドを ジェクトとする。なお , もしも式の評価結 が void のメソッドを呼び出すことが 呼び出す型 , およびメソッドシグネチャま 果が nu Ⅱであったとしても , この時点では 許されるのは , トップレベルの式 , でが決定された。コンパイル時に行う最後 まだ工ラーにはしない。ただし , 途中でこ すなわち , 「式」の値を利用しないよ の作業は , このようにしてシグネチャまで の評価が中断終了した場合には , その時点 うな文脈である。具体的には , 式文 が特定されたメソッドの呼び出しが , 文脈 メソッド呼び出し変換の例 / * List1.java * / キメゾッド呼び出し変換の例 * 定数 10 はあぐまで土北であって , に e には変換されない 0 lass F00 ( public void zot(double も double y). { System.out.println("Foo. zot((double)" 十茎十” ( d0 面尸十 y 十つ” ) 0 lass Bar extends 00 { p 面は 0 void ZO 日土 n sh0 て 0 Y) ( 号 ystem ・ ou し・店土 nt ⅲ ( " B .20t ( ( 土 n し尸十区十ツ , ( s れ or し戸十 Y 十、尸嵭 class Baz extends お a て ( public void zot(byte a でⅵ ( system. 0uこ . println("Baz. Z0t((取しe广十十。 % 往 h 矼尸十十 ? 尸リ class s セ 1 ー ( public static main(string[ 1 args) イ Baz myBaz れ e 曾 Baz( 嶹 マ / どのメソッドが呼び出されるか ? myBaz.zot(10,- ' 記 / / char → sho てしへ、強制的に型変換することは可能 叫 Baz 、 40t ( 10 , ( 曲 0 てむ ) ' / / この初期化でば、加が代入変換で by に e に変換されることに注意 byte わ = 1 の / / こんどはどのメソッドが呼び出されるか ? nyBaz. zot(), ' 記 ) ー Java プログラミングリファレンス詳説 JDK 解体新書 115

9. 月刊 C MAGAZINE 2000年7月号

・ IOCS のフック ・ハードウェア MFP(Multi Function peri pheral) と SCC のエミュレーション の両方を実装します。これは , こまで解 説してきた IOCS のフックとは別の理由によ ります。 X68000 のキーポードは JIS キーポードで す。 Wmdows でも JIS キーポードを使う場合 はキー割り当てがほとんど同じなのでハー ドウェア MFP のエミュレーションを使いキ ーデータを変換します。一方 , W1ndows で US キーポードを使っている場合は困ったこ とにキートップのレイアウト ( とくにシフト 状態での記号の配置 ) がずれてしまいます。 この場合 , 単にキーデータを変換しただけ ではキーがずれたままになります。そこで , IOCS をフックしてキーコードを解釈するこ とで , キーレイアウトのずれに対処します。 また , マウスの場合はそのデバイス特性 からハードウェア SCC の通信で扱えるデー タがマウスの移動の相対値でしかありませ ん。そもそも , マウスという入力装置は自 分の絶対位置を持っていません。そのため , X68000 内のマウスカーソルの位置と Win dows のマウスカーソルの位置を一致させる ためにはそれぞれのマウスカーソルの絶対 位置を扱う必要があり , IOCS のフックによ ってこれを可能にしているのです。 IOCS をフックする方法は , 先ほどディス クアクセスの IOCS をフックしたときに利用 した方法をそのまま使います。 X68000 上のプログラムからは IOCS を利 用するほかにワークエリアの直接読み出し も行われるので , EX68 でも IOCS をフック するほかにワークエリアのパラメータ更新 も行っています。ただし , ハードウェア工 ミュレーション以外でのソフトウェアへの 介入は実機との互換性において不利になる ので利用時に選択できるようにしています。 X68000 外部の ハードウェアへのアクセス EX68 では X68000 外部のハードウェアとし てゲーム用のジョイスティックをサポート しています。ジョイスティックはハードウ 56 C MAGAZINE 2000 7 ェアポートをエミュレーションすることで 実装しています。ジョイスティックのよう な単純なハードウェアは , その場で変換処 理を行うことも可能ですが , ポートをエミ ュレーションすることで , ジョイスティッ ク以外のハードウェアやポートに接続され るジョイスティックの拡張機能をエミュレ ータに組み込むことができます。 この場合は , Winodws のジョイスティッ クをサンプリングするルーチンとエミュレ ーションされているポートのハンドリング ルーチンの間に連射機能やボタンの拡張機 能のルーチンを接続しています。 Windows のドライブをリモートド イブとして実装する ( wind Ⅳ . sys ) 前述したディスクイメージへのアクセス は X68000 にもともとあるハードディスクや フロッピーディスクとのインタフェイスを 使用したものですが , X68000 工ミュレータ としてではなく , W1ndows のアプリケーシ ョンとして動作する EX68 からも Windows の ファイルを読み書きできると便利です。 このように , X68000 にはもともと存在し ない Windows のドライプを仮想の X68000 に 認識させるためにはどのようにすればよい でしようか ? 前述したような IOCS や演算 ドライバのフックで利用した拡張方法はこ こでは利用できません。なぜなら X68000 と しては置き換えるインタフェイスを持って いないことと , いままで扱ったドライプと は別のドライプを追加するということは , OS に対して機能を追加することを意味する からです。 このような場合は , 工ミュレータ本体の EX68 とエミュレータ内部で動作している仮 想の X68000 , そして OS である Human68k の 複数のレベルでのインタフェイスを作る必 要があります。 まず , Human68k が追加ドライプを扱え るようにする正規の手順が必要です。 では Human68k 用のデバイスドライノヾ W1n d Ⅳ . sys を作成してエミュレーション内の Hu man68k 起動時に組み込みます。このデノヾ イスドライノヾは Human68k にドライプを追 加しますが , このデバイスドライバを組み 込んだだけでは仮想空間内のプログラムが 動作しているだけで , まだドライプの中身 はありません。 次に EX68 が Wind Ⅳ . sys の機能呼び出し を解釈するための仮想のデバイスとして , メモリ空間にハードウェアのポートを作成 します。これはアドレスデコーダのテープ ルにエントリを追加して E9F000 ~ E9FFFF にリード / ライトルーチンを作成し , 割り 当てます。このポートはトリガとして利用 するだけで , パラメータはレジスタを使っ て渡します。パラメータは機能番号のほか にメモリへのポインタを渡し , このポイン タの指すメモリ経由でファイルの読み書き を行います。ポートをトリガとして使うだ けならば 1 バイトあれば十分ですが , デコ ード上のイメージとして 4K バイトのサイズ のまま残しています ( List14 ) 。 このイメージは個別にリード / ライトル ーチン内でアドレスデコード ( この場合は テープルを使わずアドレスを直接判定でき る ) を行えばバスエラーに割り当てること も別の用途に割り当てることもできます。 このリード / ライトルーチンが W ⅲ d Ⅳ . sys の 機能呼び出しを解釈して対応する Pen ⅱ um コードのルーチンを呼び出します。 Human68k から Windows のドライプを扱 う場合に問題となるのがファイルシステム の違いです。 DOS のファイルシステムに近 い Hum 68k の形式に対して , Windows で は FAT16 のほかに FA 2 , NTFS などさまざ Wind Ⅳ用に追加したボートのインタフェイス / / W 土 nd て v 用に追加したインターフェース 〃 e9f000.. e9ffff //Windrv の ID を読む 乢 0 G crb-win(ULONG addr) åf (addr 0xe9 印 00 ) read—busg—error-byte(); return ℃ //Windrv 確認用 ID 〃 e9f000.. e9ffff //windrv. s s からの呼び出し void cwb—wIn(ULONG addr,ULONG data) if (addr く 0Xe9f000 ) write-buss—error—byte( return ー / ここが w 土 nd て v の本体となる。 X6. wdrv. win—sub( return

10. 月刊 C MAGAZINE 2000年7月号

Windows 用 68000 工ミュレータの 仕組み I/O ポートのデコーダ ノ / ー 0 ポトのデコーダ / / e9e000 / / ー 0 アクセステーブル cons こ io—read-tbl 一土 0 て eadby し e [ 16 ト { rb—crtc,rb—pal,rb—dma,rb—area,rb—mfp,rb—rtc,rb セ rb—sys, rb—fm,rb—ad,rb-fd,rb—hd,rb—scc,rb—joy,rb—intl,#w{n 、 00n3 し iO ー土 te ユユ 0 址 eby e [ 16 ト { wb-crtc,wb—pal,wb—dma,wb—area,wb—mfp,wb—rtc,wb—prt,wb—sys, wb—fm,wb*d,wb—fd,wb—hd,wb—scctwb-,$oyt wb—intlt wb„win 〃ー 0 アクセス 〃 e80000 ー e9ffff nake 阯 0 G read-åo-byte() mov edx,ecx and e 亟′ 001e000h shr e 亟 , 13 push eCX dword 「 p セて t—ioreadbyte 十 4*edx ] ca Ⅱ #if IOHIST POP ecx mov edx,eax READIOBYTE # 引 se add sp,4 mo edX, eax *endif nake VOid 址 0 ー土 0 ー byte ( ) —asm イ ÄOV eax,ecx and eax , 001e000 れ shr eax, 13 push edx push 第 eCX call を第 = dwo て 0 ptr t—iowritebyte 十 4*eax] # 迂工 0 日 I OP ecx POP edx WRITEIOBYTE #el se add sp,8 $endif て MPU のインストラクションの一部として けられたものですが , 工ミュレータにとっ る同時アクセスを行う機能 実行されます。この MPU からの問い合わせ ては再現するための負担が大きなものとな ・ 4 ラスタ単位でのテキストメモリのデ に対してはその時点でのデバイスの状態を っています。 ータを転送する機能 決定しなければなりませんが , これもマス EX68 ではよく使われる機能を組み込んで ・テキスト画面を高速にクリアする機能 タカウンタから逆算することになります。 ・ビット単位に描画をマスクする機能 います。 書き出し動作ではデバイスへのコマンドを があります。 ビデオコントローラの機能を実装 設定する必要があるので , この時点で実行 グラフィックメモリに対しても高速クリ 可能なコマンドはその場で実行します。 実際 EX68 の処理する時間は 1 フレーム 55 アの機能があり , これらは MPU 工ミュレー 即時実行する例としては DMA コントロー Hz の場合で約 18ms です。 Pentium に内蔵の ションを通して読み込み / 書き出しの機能 パフォーマンスカウンタを使って (List 9 ) , が呼び出された時点で起動され , その結果 ラの転送開始 , ADPCM の再生開始 , ビデ 初期の X68000 に付属しているゲームソフト は仮想のビデオメモリに保持されます。 オコントローラへの描画開始などがありま 「グラデイウス」のエミュレーションを計測 一方 , 同じ画像生成処理でも X68000 にと す。 した結果では , MPU のエミュレーションに って表示の時点で機能する部分は仮想のビ ビデオコントローラ デオメモリから Windows のビデオメモリ形 5.4ms , ビデオの画像生成に 5.9ms , そして Windows への画像の転送が 5.2ms となって 式 DIB へ変換する部分で実装します。おも います (Celeron 466MHz : W1ndows 2000 ) 。 なものは , ビデオコントローラは描画を高速化する このうち , 転送時間は使っているビデオカ ための仕組みとさまざまな表示効果を得る ・スクロール ・ピクセルごとのパレット変換 ために多彩な機能を搭載しています。 X68 ードによりかなり違いますが , 5.2ms は遅 ・表示プライオリティの入れ換え 000 と PC / AT 機では画面の構成などの仕様 いほうだと思います。 ・反転を含めたスプライト , テキスト , があまりにも違いすぎるので , これらすべ 画像生成処理のうち , 描画機能は仮想の ビデオメモリへアクセスした時点でエミュ グラフィック画面の描画 てを正しく実装することは困難です ( TabIe レーションを行います。描画機能は , です。この部分は先ほどの「グラデイウス」 2 , 3 ) 。ビデオコントローラの数々の機能 ・テキストメモリの複数プレーンに対す の計測結果からもわかるとおりテキスト , は , 本来 X68000 の処理速度を稼ぐために設 TabIe 3 X68000 の表示画面サイズ TabIe 2 X68000 の画面とバッフアサイズ バッフアサイス 画面 水平同期 テキスト画面 1024X1024X4 面 31 .5Khz 1024X1024X4bPP グラフィック画面 512X512X16bPP 512X512X8bPPX2 面 スプライト BG 1024X1024X2 面 垂直同期表示画面サイズ 768X512 , 512X512 , 512X256 , 256X256 512X512. 512X256 , 61 .5Hz 15.9KHz 標準解像度 256X256 注 . 768 x 512 の表示が可能なのは , 実画面が 1024X 1024 のサイズの場合のみ 特集 2 Windows 用 X68000 工ミュレータの仕組み 49 垂直同期 55.5Hz 度 像 解 高