2014年07月28日の日記です



6502 は遅かったのか?  2014-07-28 17:34:00  コンピュータ

昨日書きましたが、MSX もファミコンも、NTSC 信号を元にしたクロックで動作しました。

MSX はそのまま、ファミコンは半分にしていますので、クロックだけで比べるとファミコンは半分の速度です。


このことを調べていたとき、周波数を根拠として「ファミコンは MSX と比較して遅かった」と記述されたページを多数見ました。

もちろん、CPU が違うので周波数で判断できない、と書いてあるページも多数あるのだけど。


僕はファミリーベーシックで 6502 のアセンブラを覚え、MSX でも Z80 のアセンブラを使いました。

でも、MSX はあまりに「遅い」ので驚いた記憶があります。


その時は Z80 の特性を知らず、Z80 で特に遅い命令を多用してしまったからだったのだけど、自分の中では今でもファミコンは MSX に速度で負けてない、という気持ちがあります。




多分、知らない人が勘違いする大きな理由の一つが、機械語命令には、命令ごとに違う「実行に必要なクロック数」がある、ということ。

最近の CPU では、みんな1クロックで実行するのが普通なので、周波数がそのまま速度に直結します。

もっとも、それでも1クロックで「何ができるか」が違うので、CPU の速度を周波数だけで表すことはできないのだけどね。


6502 や Z80 の時代はもっと激しいです。

命令ごとに、2クロックで終わるようなものから、1000クロック以上かかる命令まであるのですから。


これを考慮しなくては速度比較にはなりません。




プログラム中に非常に良く出てくる操作として、「レジスタとメモリ内容の足し算」があります。

例として、この命令の速度を比較してみましょう。


Z80 では、直接アドレスを指定したメモリと足し算する命令はありません。

そのため、2命令を組み合わせます。


LD HL,nn ; 10 (11)

ADD A,(HL) ; 7 (8)


nn は、2バイトの数値を意味しています。


; 以降に、実行に必要なクロック数を書きました。( ) の中は MSX の場合です。

MSX がなぜ遅いのか…という説明は後で書きます。


ここでは、MSX を比較対象として ( ) の中の数値を合計すると、19クロックで完了します。


6502 の足し算命令では、必ずキャリー(桁上がり)を足してしまうため、足し算の前にキャリーを消す必要がありました

また、計算用レジスタは1つしかないため、相手のメモリアドレスだけを指定します。


CLC ; 2

ADC nn ; 4


こちらは合計 6クロック…なのですが、もっと速くできます


6502 の場合、上に書いたように、計算用レジスタが1つしかありません。

そこで、メモリの先頭、8bit でアドレスを表現できる範囲までに限り、高速にアクセスできる方法が用意されていて、256byte をレジスタ代わりに使えるようになっていました。

(6502 では、256 byte ごとに「ページ」と呼んだため、ゼロページアドレッシング、と呼びます)


CLC ; 2

ADC n ; 3


n は1バイトの数値を意味しています。

こちらでは、1クロック減って合計 5クロックです。


ファミコンは半分の周波数で動いている、と考えても、MSX よりもファミコンの方が倍近く速いです。




上の例ではメモリと足し算しましたが、Z80 はメモリアクセスが遅かったため、できるだけメモリアクセスしないテクニックが重要でした。


では、 B レジスタから A レジスタにデータを渡してみましょう。


LD A,B ; 4 (5)



6502 では、レジスタが A X Y の3つしかないため、あまりレジスタ渡しは使いませんでした。

しかし、X から A に渡すのであれば


TXA ; 2


この場合、半分の周波数と考慮しても、ファミコンは MSX より速いです。


現実には 6502 では、ゼロページをレジスタのように使いました。

メモリ相手なので少し遅いのですが、256 本もレジスタがある、と考えるとプログラムの幅が広がります。


LDA n ; 3


メモリを使うにも関わらず、Z80 よりも少ないクロックで動作します。

とはいえ、周波数を考慮すると、この方法ではファミコンよりも MSX の方が速い。


メモリアクセスは遅いのです。




もっと単純に「A に 1 を入れる」を考えてみます。


Z80 では


LD A,#1 ; 7 (8)


6502 では、


LDA #1 ; 2


こちらは、ファミコンの方が圧倒的に速い。


Z80 では、先に挙げた LD A,B は 1バイトの命令でした。そのため、メモリアクセスは1回で済みます。

しかし、LD A,#1 は、 LD A という命令部分と、1 という数値部分の 2バイトに別れていて、2回のメモリアクセスが必要になります。

6502 の LDA #1 でも同様に2バイト命令なのですが、Z80 はメモリアクセスが非常に遅く、6502 と大きく差がつく原因になっています。




さらに、「A に 0 を入れる」。

同じじゃないの? と思われそうですが、Z80 では


SUB A ; 4 (5)


A から A を引いて A に入れる、です。結果は必ず 0 。

一見無意味な命令ですが、メモリアクセスがないので LD A,#0 より速いです。

(同様の意味で XOR A というのも良く使われました。速度は同じ)


6502 では、素直に


LDA #0 ; 2


MSX の方がほんのわずかに遅いのですが、ほぼ同等。




6502 には、インデックスレジスタが X と Y の2つありました。

Z80 にも、IX と IY の二つがあります。


ここで、「インデックスレジスタと数値を足したアドレスの内容を A に読み込む」をしてみましょう。

(インデックスレジスタ相対アドレッシング)


Z80 は、IX と IY は 16 bit で、そこに 8bit の固定値 o (8bitの符号付数値)を足せます。

6502 では、nn は 16bit アドレスで、そこに 8bit の X や Y を足せます。


Z80 では


LD A,(IX + o) ; 19 (21)


6502 では、


LDA nn,X ; 4


ただし、6502 ではページ境界(256byte 単位の区切り)を超えると、 5クロックになります。

(nn + X の結果、上位8bit が nn と違う値になると、追加の1クロックが発生)


こちらは、ファミコンの方が倍以上速い。

インデックスレジスタ相対アドレッシングは、Z80 で特に遅い命令の一つです。

(実は、この命令は 3byte もあり、メモリアクセスが多いのです。)


最初に書いた、僕が「Z80 が遅くて驚いた」理由は、はじめて作った機械語プログラムで、知らずにインデックスレジスタを多用してしまったため。

6502 では特に遅くないので、配列アクセスのための基本テクニックなのですよ。

(というか、インデックスレジスタとはそのためにあるものです)


配列アクセスは多数の敵を動かすゲームで使いたい機能なのだけど、Z80 でゲーム作るときには、絶対使っちゃダメな命令。




さて、機械語が並べられた説明ばかり続いて、そろそろ飽きられそうです。

ちょっと話を変えましょう。


CPU が命令を実行する際は、内部的には次の3つの動作が行われます。


1) メモリにアドレスを送る

2) メモリからデータを読み込む

3) 命令を実行する


これは、順番に行わなくてはなりません。

つまり、一般的に CPU が命令実行に必要な最低クロック数は 3。


ところが、Z80 では、命令を実行するための最低クロック数は 4(MSX の場合は 5)、6502 では 2 です。


<<以下、この節のみ、2014.7.31 に内容変更。

  書き換え前の物は HTML コメントとして残っています>>


元はこの節で、Z80 が遅く、6502 が速い理由について内部構造を解説した…のですが、僕は回路知識が乏しいため、間違っていたようです。


書き換え前は、主に、


・Z80 は 4004 由来で内部バスが4bit である。

・Z80 には命令実行時に1クロック待つことができたが、MSX では回路の都合からこの機能を使っている。


・6502 は、命令実行中に次の命令を読み込んでいた

・6502 は、1クロックで2つの動作ができた


ことを説明し、Z80 はこれが理由で通常より1クロック遅れ、MSX ではさらにもう1クロック遅れるとしました。

一方、6502 では通常より1クロック速くなり、命令によっては追加のメモリアクセスがあるにも関わらず2クロック動作だった、と書いていました。



これに対し、Z80 の内部バス 4bit は ALU (演算回路) 4bit の間違いではないか、と指摘があり、再度調べたところその通りでした。


元の文章を書いた際の参考文献は、R800 (Z80 互換の 16bit CPU) の設計者のインタビュー記事(MSX マガジン永久保存版2収録)。

ここに、「Z80 は / 内部のバスなんかは 4bit だった / だから簡単な命令でも、4クロックで2回に分けて転送したりする」という証言があります。

これを見て、内部バスが 4bit なので余計なクロックが必要となっている、と理解しましたが、これが勘違いでした。


指摘後、詳細情報を調べるために手持ち資料を漁ったところ、Z80 設計者の嶋正利さんの自伝「マイクロコンピュータの誕生 わが青春の 4004」に詳細がありました。

信憑性は、もちろん後者の方がずっと上です。




嶋さんは世界初の CPU 、4004 の設計者でした。これは、日本の会社に在籍しながらインテルと協力して設計したものです。

嶋さんは 4004 完成後に日本に帰国、インテルは 8bit 化した 8008 を作りますが、4004 よりも遅く、周辺回路設計が難しく、ソフトウェアも作りにくい CPU でした。


この後、インテルはリコーに在籍していた嶋さんを「インテルに入社する」ように説得。

最終的にはリコーの人事部にまでインテルから直接交渉が入ります。

リコーの人事部は引き抜きに対して怒りながらも、4年間の休職が認められます。

(これは、4年以内ならいつでも戻ってこい、ということでもあります。神対応!)


ここで、嶋さんは 8080 を設計します。

設計の際には、周辺回路の作りやすさが重視されました。



自伝では、この部分で「遅さ」の理由が明らかにされています。


8080 でも、内部的には1クロックで2つの動作を行っていますが、「外部に対しては」わかりやすく、1クロックで1つの動作しか行わないようにしています。

また、外部にアクセスする際には、CPU の内部状態をデータバスに送出するようにしています。これにより、周辺 LSI はCPU が外部アクセスする「理由」を知ることができ、柔軟な回路設計が可能となるのです。


このため、メモリへのアクセスは「アドレス送信」「CPUステータス送信」「データへのアクセス」という3クロックが必要となります。




Z80 は、嶋さんが仲間と共にインテルをスピンオフし、設立されたザイログ社で作られた CPU です。

別会社なので、回路は完全に新規に作り直していますが、8080 の上位互換になるように設計されています。


この時に、内部回路の高速化によって、ALU は 4bit で十分になっています。

(4bit なのは 4004 由来ではありませんでした)


さらに回路設計をしやすくする工夫が加えられます。Z80 には、DRAM を使用する際に必ず必要な「リフレッシュ回路」が内蔵されているのです。


リフレッシュ回路は、命令実行時に動作します。

これは、命令実行時は CPU 内部で演算が行われていて、メモリは暇なためです。


一方、8080 には存在していなかった「CPU 動作とは関係のないメモリアクセス」が行われるため、命令の読み込みは通常のメモリアクセスよりも早めに切り上げる必要がありました。


また、MSX では、メモリは Z80 には直接接続されていません。

スロット、と呼ばれる仕組みを使い、64Kbyte しかない Z80 のメモリ空間を、1Mbyte に拡張しているのです。


その代償として、スロットへのクロックは、Z80 に供給されるものと比較して、最大で 80ns 遅延しました。


・Z80 では命令実行時のみリフレッシュ回路が働くため、メモリアクセスを通常より速く行わなくてはならない

・MSX ではメモリを直接接続していないため、拡張性と引き換えにアクセスが低速になっている


この2つのことから、MSX では「命令の読み込みが間に合わない」場合が生じます。

その対応として、命令読み込み時のみ、メモリアクセス時に CPU を 1クロックだけ停止させ、メモリのアクセス時間を稼いでいました。


これが、MSX の命令が Z80 標準よりさらに1クロック遅い理由です。

(なお、一部命令では命令部分がプリフィックス付の 2byte です。この場合、「命令」の読み込みを2回繰り返すため、2クロック遅くなります)


以上、Z80 が遅い理由は、

・周辺回路の設計しやすさを考慮し、高速性よりもわかりやすさを優先している。このため、メモリアクセスだけで3クロック。

・MSX では、メモリ空間が増大した代償としてメモリアクセスが遅れるため、命令読み込み時のみ1クロックの待ち時間が追加される。

でした。




6502 は、Z80 とは違い、メモリアクセスを最短時間で行います。

1クロックの間に、アドレスの送信とメモリアクセスを行うため、データの取得自体は1クロックです。


命令実行時は、Z80 はリフレッシュ回路を動かしていました。

しかし、6502 は「命令の次のアドレス内容」をすぐに読み込んでしまいます。


次の内容は、命令に使われるデータかもしれませんし、次の命令かもしれません。

これにより、 LDA #1 のような命令でも、たったの2クロックで終わらせることができます。

(実際には、命令読み込み、命令解釈&データ取得、命令実行の3クロックかかっているが、命令実行中には次の命令を読み込んでいるため、見た目上1クロック短くなる)


命令解釈と命令実行はわかれているようで、データが不要な CLC (クリアキャリー)のような命令でも、2クロックになります。

この際、命令解釈時点で得た「次のメモリ内容」は、そのまま捨てられ、再度同じアドレスを命令実行時に取得するようです。


このため、最低実行時間は2クロックです。


参考:hpcl6502

FPGAで実装された 6502 と、アクセスタイミングなどの説明。

互換品に過ぎないわけですが、6502 は回路構成が単純で作りやすいようで、同等の試みが世界中で行われています。

製作者も良く検討して作っているようなので、互換品とはいえ信頼できると思って参考にしています。






さて、先ほどは単純な機能でクロックを比較しましたが、これだと 6502 に有利な命令ばかり選んでいるのではないか、という気もします。

もう少し、Z80に有利な条件で見てみましょう。


Z80 はレジスタが多いですし、一部のレジスタでは 16bit 計算もできます。

また、ループ専用の命令もあります。

これらは 6502 にはないものです。


また、Z80 はメモリアクセスが遅いので、レジスタの多さを活かしてメモリアクセスがない題材を考えましょう。


そこで、1~100 の数字を全て足すプログラムを作ってみましょう。

答えは 5050 です。8bit には収まらないので、16bit 計算が必要です。


Z80だと次のようになります。


LD HL,#0 ; 10 (11)

LD DE,#1 ; 10 (11)

LD B,#100 ; 7 (8)

LOOP:

ADD HL,DE ; 11 (12)

INC DE ; 6 (7)

DJNZ LOOP ; 13 / 8 (14 / 9)


結果は HL に入ります。


ループごとに1つづつ値が変わる変数、として DE と B の2つがあり、無駄っぽく見えます。

でも、16bit 演算は 16bit のレジスタ同士でないとできないため、DE は必要で、16bit レジスタの INC / DEC ではフラグ変化がないため、B も必要です。


そして、DJNZ は B を暗黙に使用し、減算結果が 0 でない場合はジャンプします。

クロック数を2つ書いてあるのは、ジャンプするときは 14クロック、しない時は 9 クロックになるため。

LOOP: はラベル。アドレスを示す目印で命令ではありません。


LOOP 以前の部分の合計は MSX で 30 クロック。LOOP 以下は 33 クロックですが、100 回繰り返されるので、3300クロック。

ただし、最後の1回は 5 クロック短いので、3295クロック。

総計は 3325 クロックです。


6502 だと次のようになります。


LDA #0 ; 2

STA >0 ; 3

STA >1 ; 3

LDA #100 ; 2

STA >2 ; 3

LOOP:

CLC ; 2

LDA >0 ; 3

ADC >2 ; 3

STA >0 ; 3

LDA >1 ; 2

ADC #0 ; 2

STA >1 ; 3

DEC >2 ; 5

BNE LOOP ; 3 / 2



6502長げーよ。


レジスタが1個しかないため、ゼロページアドレッシングを使っています。 >0 は、ゼロページの 0 番地の意味。

最終結果は 16bit なので >0 と >1 に置き、ループ変数は「足す数」と同じで >2 に置きます。


6502 の加算命令は、常にキャリーを一緒に足すため、CLC でキャリークリアしてから開始。

足す数は 8bit しかないので、上位 8bit には #0 で 0 を指定しています。


LOOP 以前の部分が 13クロック。LOOP 後は 26クロックで、100回繰り返されるので 2600クロック。

ただし、最後の1回は1クロック短いので、2599クロック。


総計で、2625 クロックです。



ファミコンと MSX でいえば、ファミコンが5割ほど遅いです。

しかし、Z80 に一方的に有利な条件で考えた題材にしては、ファミコンは健闘しています。



実際にはファミコンと MSX は CPU としては同程度の速度だったように思います。

Dhrystone とか、BASIC で同じプログラムを走らせてみるとか、ベンチマーク比較はいろいろ見たのですが、CPU の性能と言うより「言語処理系の性能」が色濃く反映されてしまい、均一な速度指標が得られません。


ただ、リストによって 6502 の方が速かったり、Z80 の方が速かったりするのも事実。

(6502 を Z80 の半分の周波数にする形で比較した場合)


つまり、言語による差はあれど、CPU としてはだいたい同じだったのではないかと。



ウォズが 6502 を Apple I に使ったのは、欲しかった 6800 とよく似ているのにずっと安かったから。

ファミコンが 6502 を採用したのは、あまり使われてなくて解析されにくかったから…という理由もあるけど、「Z80 よりも小さな回路サイズなので、Z80 と同じサイズなら、別の機能も入れられる」ためだったらしい。


いずれにせよ、性能が他の CPU とほぼ同等なのに、6502 はコスト面で有利な CPU だったのでしょう。



ファミコンと MSX でいえば、CPU 性能よりも画面周り回路の違いが大きかったように思います。

どっちが良い、ではなくて、違いがはっきりしていて、一長一短あった。


当時は僕は両方持っていたので、同じゲームが両機種にあれば、より上手に作られている方を楽しんでいました。

グラディウスとか、ファミコンより MSX の方が、遥かに良移植だった。


もちろん、スクロールはファミコンの方が滑らかでしたけどね。


2014.8.3 追記

僕の書いたプログラムは、「同程度の性能であることの比較」ができれば十分、という意図だったのですが、もっと速く出来るというご意見を多数いただきました。

非常に面白かったため、解説も含めて別記事にしました。更なる改良もお待ちしております。





同じテーマの日記(最近の一覧)

コンピュータ

関連ページ

ランダムアクセス

Z80 vs 6502

「ああ播磨灘」ゲームボーイ版【日記 15/02/16】

ファミコン・SG-1000の発売日(1983)【日記 15/07/15】

続・6502は遅かったのか?【日記 14/09/06】

別年同日の日記

06年 誕生日

07年 誕生日

08年 海の日

08年 誕生日

09年 水族館

15年 マイコプラズマ肺炎:治癒報告

16年 セガサターンモデム


名前 内容

【オールドプログラマ】 Z80と比べて遅いって…当時現役で仕事で使っていた人間なら全員鼻で笑いますね… (2016-06-04 12:47:36)

あきよし】 情報ありがとうございます。ファミコンで実際使われていた、という証言は重いです。この方法をありにして、別ページの方を書き変えました。ただ、ループ展開は制限させてもらっています(展開競争は虚しいので)。 (2014-08-04 10:16:58)

【名無し】 巨大テーブルはレジスタ間演算を高速にやりたい他のルーチンからも共用できるので、ある程度以上の大きさのプログラムでは非現実的なものではない筈です。ファミコンのプログラムで見掛けたこともありますし、http://wiki.nesdev.com/w/index.php/6502_assembly_optimisations なんかでもテクニックのひとつとして紹介されてますね。 (2014-08-03 17:01:28)

あきよし】 巨大テーブル化。速度は速いですが、コスト・効率比が悪すぎて現実的に使われることは無いテクニックだと思います。そのため、比較としては NG。ただ、この発想は僕はすごく好きです。 (2014-08-03 16:45:27)

あきよし】 みなさん、改良案ありがとうございます。別記事を書きましたので、今後はそちらに投稿していただけるとありがたいです。 (2014-08-03 16:42:43)

【名無し】 以上のコードでおよそ1120クロック程度です。 (2014-08-02 12:41:20)

【名無し】 記事のタイトルが「6502 は遅かったのか?」であり、コードサイズはかんけいないので ORG $C000;LDY #100;LDA #0;TAX;JMP SKIP;INCH:;INX;DEY;BEQ EXIT;SKIP:;CLC;LOOP:;ADC TABLE,Y;BCS INCH;DEY;BEQ EXIT;ADC TABLE,Y;BCS INCH;DEY;BEQ EXIT;ADC TABLE,Y;BCS INCH;DEY;BEQ EXIT;ADC TABLE,Y;BCS INCH;DEY;BEQ EXIT;ADC TABLE,Y;BCS INCH;DEY;BNE LOOP;EXIT:;STA >0;STX >1;;ORG $C100;TABLE:;DB $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F;DB $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F;DB $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2A,$2B,$2C,$2D,$2E,$2F;DB $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F;DB $40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E,$4F;DB $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5A,$5B,$5C,$5D,$5E,$5F;DB $60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6A,$6B,$6C,$6D,$6E,$6F;DB $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7A,$7B,$7C,$7D,$7E,$7F;DB $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F;DB $90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F;DB $A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7,$A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF;DB $B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB,$BC,$BD,$BE,$BF;DB $C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7,$C8,$C9,$CA,$CB,$CC,$CD,$CE,$CF;DB $D0,$D1,$D2,$D3,$D4,$D5,$D6,$D7,$D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF;DB $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7,$E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF;DB $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF (2014-08-02 12:40:15)

【名無し】 6502の高速版のコードサイズが28バイトなので、Z80で同程度のコードサイズが許されるならば若干のループ展開が可能になります。LD HL,0;LD BC,100;LOOP:;ADD HL,BC;DEC C;JR Z,EXIT;ADD HL,BC;DEC C;JR Z,EXIT;ADD HL,BC;DEC C;JR Z,EXIT;ADD HL,BC;DEC C;JR Z,EXIT;ADD HL,BC;DEC C;JP NZ,LOOP;EXIT: で27バイト、2582クロックなので、ファミコンには勝ったことになると思います。 (2014-08-01 18:25:49)

【名無し】 訂正: ジャンプに1wait足すのを忘れてました。11+11+100*(12+5+11)=2822クロックで、ファミコンには僅かに負けます。 (2014-07-31 21:44:23)

【名無し】 jr nz,loop を jp nz,loop にすると更に速くなります。11+11+100*(12+5+10)=2722クロックで、半分のクロック速度のファミコンの1395クロックよりは速いことになりますね。 (2014-07-31 21:39:19)

【m】 ループ内が短すぎてほとんどどうにもなりませんが、ld hl,0; ld bc,100; loop: add hl,bc; dec c; jr nz,loop のほうが少し速い(100から1まで足す,になりますが)。単純に総和を取るんじゃなくて公式 n*(n+1)/2 のほうで比べるとかすれば z80 のほうが速いかも (2014-07-31 21:19:15)

【名無し】 6502の高速版プログラムですが2+3+2+2+3+2+19*(3+3+2+5+2+2)+81*(3+2+5+3)-1+3+3=1395クロックが正しいようです。先の「1357クロック」は、おそらくはキャリーが発生した際のCLCを計算に入れなかったミスっぽい。 (2014-07-31 21:00:06)

【名無し】 Z80に花を持たせるにはメモリのブロック転送などが有効だと思います。Z80ではLDIRで済む程度の処理が6502では案外面倒なことになります。 (2014-07-31 16:59:55)

【名無し】 ご対応ありがとうございます。「Z80 版は、計算したところ残念ながら却って遅くなっていました」とのことですが、XOR A;LD H,A;LD B,100;LOOP:ADD A,B;JP NC,SKIP;INC H;SKIP:DJNZ LOOP;LD L,Aで3113クロックとなり、遅くなってはいないと思います。ちなみに6502版にロジックを合わせてXOR A;LD H,A;LD B,100;JP LOOP;INCH:INC H;DEC B;JR Z,EXIT;LOOP:ADD A,B;JR C,INCH;DJNZ LOOP;EXIT:LD L,Aとすると2900クロックで更に高速化できます。 (2014-07-31 16:51:25)

あきよし】 ご意見ありがとうございます。参考に修正しました。 (2014-07-31 12:59:53)

【名無し】 LDA #100;STA >2;LDA #0;TAX;JMP SKIP;INCH:INX;DEC >2;BEQ EXIT;SKIP:CLC;LOOP:ADC >2;BCS INCH;DEC >2;BNE LOOP;EXIT:STA >0;STX >1 で1357クロックなので、クロック速度倍のZ80と比べてもいくらか速いと思います。 (2014-07-29 20:00:49)

【名無し】 6502、LDA #100;STA >2;LDA #0;TAX;CLC;LOOP:ADC >2;BCC SKIP;INX;CLC;SKIP:DEC >2;BNE LOOP;STA >0;STX >1 で1800くらいかな。 (2014-07-29 04:53:58)

あきよし】 早期に書き変えたいと思いますが、次の週末かな…申し訳ない。 (2014-07-29 04:52:34)

あきよし】 ご意見多数ありがとうございます。感謝いたします。特に、より高速なプログラムを示してくれたのは非常にありがたいです。(もう何十年も使ってなかったので勘が鈍ってます) (2014-07-29 04:51:32)

【名無し】 「1~100 の数字を全て足すプログラム」 Z80でも16bitレジスタを使わずに XOR A;LD H,A;LD B,100;LOOP:ADD A,B;JP NC,SKIP;INC H;SKIP:DJNZ LOOP;LD L,A 等としたほうが高速です。6502版は更に無駄が多すぎ。 (2014-07-29 01:38:48)

【名無し】 「0.5 クロック単位で作業ができるため、0.5クロック目で「アドレス送信」を行い、1クロック目で「データ読み込み」を行うことで、1クロックで読み込みが完了するのです。」タイミングチャート見てもそういうことにはなってないですね。http://www.mdawson.net/vic20chrome/cpu/mos_6500_mpu_preliminary_may_1976.pdf (2014-07-29 01:25:18)

【名無し】 「命令実行前に1クロック待つ」のは外部回路によるもので、Z80の機能ではないし同等のことは他のプロセッサでも可能です。 (2014-07-29 01:20:26)

【名無し】 Z80について「内部バスが 4bit しかない」というのはALUの間違いでは? Z80が「命令を実行するための最低クロック数は 4」である主な原因はM1サイクルの前半と後半でそれぞれ2クロック掛けて外部バスをアクセスしているためだと思います(それだけではないだろうが)。 (2014-07-29 01:17:49)

【名無し】 6502でLDA (nn,X)のアドレッシングはIndexed Indirectになるので「インデックスレジスタと数値を足したアドレスの内容を A に読み込む」とは動作が異なります。 (2014-07-29 01:13:01)

【名無し】 「A に 1 を入れる」のは、6502ではA9 01、Z80では3E 01で大して変わりありません。「ファミコンの方が圧倒的に速い。 1という数字が、命令の一部とはいえ、メモリに入っているためです」という説明は意味不明。 (2014-07-29 01:11:09)


戻る
トップページへ

-- share --

37001

-- follow --




- Reverse Link -