6502tinymachines

このチップの作り

tools/export-idioms.py が生成する。どの計数も web/*.json から導かれる。なぜの行は書き下ろしで、そう印が付いている。人の読みと測定は、互いに洗濯して混ぜてはならないからだ。

1975 年のチップ設計者に、呼べるライブラリは無かった。ここにある構造はどれも、一つの部品 (ゲートが高のときに導通するトランジスタ) と一つの手品 (何かが引き下げられる、電源への抵抗) から組まれている。以下は、その二つから落ちてきた語彙を、数えたものだ。

1. ゲートはただ一種類しかない

NMOS の論理の作り方は一つだ: プルアップが出力を高に保ち、接地へのトランジスタの網がそれに勝てる。だから網が導通しているとき出力は低になる。並列のトランジスタが OR で、直列が AND で、プルアップが全体を反転する。したがって、このダイにある静的ゲートはどれも、積の和を反転したものだ。

このチップのどこにも AND ゲートは無く、OR ゲートも無い。 AND が欲しければ、NOR を作って入力を反転するか、出力を反転する。その一つの事実が、ダイの見た目のほとんどを説明する。

形数
インバータ534
nor354
nand39
aoi91
ダイナミック (プルアップがまったく無い。イディオム 3 を参照)142

なぜ (書き下ろし)。 プルアップはシリコンを食い、ゲートが低の間はずっと電流を焼く。直列のトランジスタは遅い。一つごとに抵抗が増えるからだ。だから安いゲートは幅の広い NOR で、高いゲートは深い NAND になる。それがまさにダイの見せる比だ: NOR 354 個に対して NAND 39 個。技術の費用の構造が、ゲートの配合に見えている。

2. 記憶は、切ることのできる輪だ

このチップには、どのゲートも駆動しないノードが 386 個ある。それらは値を抱えていて、抱え方の形は少数だ:

形数何か
latch236クロック付きのスイッチとゲート、帰還は無い: クロックが高の間は透過、そのあとは電荷で保持
ring53インバータ二つの輪にスイッチが一つ入ったもの: 本物の記憶セル
chain27記憶が記憶だけにつながっていて、間にゲートが無い
mux25三つ以上の出どころが一本の線を取り合う
gated24片側にゲート、クロックは無い
precharge21クロックで高に駆動され、そのあと引き下げられるか保持のまま残される

輪はどれもインバータ二段ぶんだ。 53 個のうち 53 個、例外は無い。このチップのレジスタ 1 ビットとは、反転して、もう一度反転して、パストランジスタを通して輪を閉じたものだ。トランジスタを開けば値は永久に巡る。閉じればそのビットはバスから書かれてよくなる。例: x2、#ABL7、y0、x4、#ABH3、x1、#ABL1、y6。

なぜ (書き下ろし)。 静的 RAM のセルにはトランジスタが六つ要る。これは四つで済み、そのうち二つはどうせ必要なプルアップだ。代価は、輪を開けたままにしすぎると値が漏れて消えることで、だからこのプロセッサには最高クロック速度だけでなく最低クロック速度がある。6502 は、止めると忘れる。

3. ダイナミック論理: 仕事はクロックにやらせる

142 個のゲートには、プルアップがまったく無い。クロック付きのトランジスタが一方の位相でノードを高に引き上げ、論理が次の位相でそれを引き下げるか、電荷を抱えたまま残す。輪と同じ手品を、記憶セルではなくゲートに当てたものだ。

なぜ (書き下ろし)。 トランジスタは半分、定常電流はゼロ。その代わり、動き続けなければならない。このチップの制御線はほとんどすべてこのやり方で働く。

4. 一本の線に多くの駆動側: バス

ここでのバスは部品ではない。何も駆動しない線で、クロックで高にプリチャージされ、あり得る出どころのすべてへパストランジスタが付いている。デコーダはちょうど一つを開く。

一本の線の出どころの数線は何本
1238
296
39
48
51
613
77
116
122

チップで最も広い線は sb0 で、出どころは 12 個。そしてこれは要約ではなく一覧そのものだ: どれも、自前の解読線を持つパストランジスタだ。

制御線届く先
dpc0_YSB#564
dpc11_SBADDalua0
dpc1_SBYy0
dpc20_ADDSB06alu0
dpc23_SBACa0
dpc24_ACSB#146
dpc25_SBDBidb0
dpc27_SBADHadh0
dpc2_XSB#1169
dpc3_SBXx0
dpc4_SSB#332
dpc6_SBSs0

名前を読めば約束事が落ちてくる: 線は対で来る。一方が値を線に載せ、もう一方が線から取る。YSB/SBY、SBAC/ACSB、XSB/SBX、SSB/SBS。この名前は私たちのものではない。MOS の設計図にある Hanson の SOURCE/DEST であり、どこから来たかは docs/atlas.md が辿っている。

なぜ (書き下ろし)。 十二個のトランジスタを通した十二の出どころは、ゲートで組んだ 12 入力のマルチプレクサよりずっと安い。そして、解読 PLA の出力がこれほど多い理由でもある: あのパストランジスタの一つ一つに、いつ開くかを言う誰かが要る。バスは安く、その制御が高い部分だ。

5. オペコードの規則が実際に住んでいる場所

普通の意味での参照表もマイクロコード ROM も無い。あるのは PLA だ: 命令レジスタの 8 ビットとその補数が一方向に走り、122 本の積項の線がもう一方向に走る格子。項は、気にするビットのところにプルダウンのトランジスタを持つので、オペコードが自分の模様に一致したときに項が発火する。あるビットを試さない項は、そこにトランジスタが無いだけで、どちらでも一致する。

積項122
ダイが名前を与えている項121
IR のビット 0 か 1 で直接ゲートされる項48
出ていく制御線46
うち項まで辿れたもの32

文書に無いオペコードが、その教訓だ。 このチップには、オペコードが正当かどうかを検査するものが何も無い。LDA と LDX は格子の二つの行で、8 個のオペコードでは両方の行が同時に一致する ($A3 $A7 $AB $AF $B3 $B7 $BB $BF) ので、両方が発火し、チップは同じ取り込みから A と X を読み込む。それが LAX だ: 機能でもバグでもなく、二つの模様が重なったときに格子がやることに過ぎない。それらのオペコードはどれも下位 2 ビットが 11 で、そこはどちらの行も縛っていないビットだ。

なぜ (書き下ろし)。 PLA はマスクの変更で編集できるデコーダであり、命令ごとにゲート一つではなく条件ごとにトランジスタ一つで済む。代価は、命令が何であるかを知らないことだ。PLA は模様に一致するだけで、一致できる模様には必ず一致する。

6. サイクルを数えるものは何も無い

このチップにサイクルカウンタは無い。あるのは 6 段のシフトレジスタで、命令は積項がそれをリセットしたときに終わる。だから命令の長さはどこにも保存されていない: 何かが鎖を止めるまでに何サイクル過ぎたかがそれだ。

256 個のオペコードすべてを実測した: 2 サイクルが 56 個、3 サイクルが 27 個、4 サイクルが 64 個、5 サイクルが 27 個、6 サイクルが 39 個、7 サイクルが 19 個、8 サイクルが 12 個、そして 12 個のオペコードはまったく終わらない。鎖をリセットするものが何も無いからだ。それが JAM のオペコードであり、シリコンの中の特別扱いではない。特別扱いの不在だ。

なぜ (書き下ろし)。 カウンタには比較器と長さの表が要る。シフトレジスタには 1 段あたりトランジスタ一つと、すでに組んであるデコーダで済む。答えが「特別なことは何もしない」であるとき、シリコンはたいていそうする。

7. 何でも八つ、ただし大事なところを除いて

データパスは、一つのビットスライスを八つ写したものだ。例外があるところに設計があるので、その全部をここに挙げる。実測した各バスの 8 ビットを比べ、兄弟と違うものを報告して見つけたものだ。この一覧の中身は、どれも調べ物ではない。

バスビット兄弟とどう違うか
ab0ゲートのプルダウンの脚が 3 本、他は 4 本
adl0他はバスなのに、ダイナミックに駆動されている
adl1他はバスなのに、ダイナミックに駆動されている
adl2他はバスなのに、ダイナミックに駆動されている
alu7dpc19_ADDSB7 が届き、他には届かない。dpc20_ADDSB06 は届かない
db1ゲートのプルダウンの脚が 8 本、他は 9 本
db3ゲートのプルダウンの脚が 8 本、他は 9 本
db5ゲートのプルダウンの脚が 8 本、他は 9 本
db7ゲートのプルダウンの脚が 5 本、他は 9 本
idb5H1x1 が届かない
p5存在しない
p4他はバスなのに、インバータに駆動されている。H1x1 が届き、他には届かない。cp1 は届かない
sb0dpc23_SBAC が届き、他には届かない
sb4dpc23_SBAC が届き、他には届かない
sb7dpc19_ADDSB7 が届き、他には届かない。dpc20_ADDSB06 は届かない

24 本のバスにわたって例外は 15 個。 そのうち四つは、よく読む価値がある。どれも、命令セットの丸ごと一つの機能が、隣と似ていない一本の線として現れたものだからだ。

シフタ。 sb と alu のビット 7 は dpc19_ADDSB7 が開け、ビット 0 から 6 は dpc20_ADDSB06 を共有する。制御線が一本ではなく二本あるのは、値を回転させるときに別扱いしなければならない、あのひとつのビットのためだ。

十進の補正。 sb0 と sb4 は dpc23_SBAC でアキュムレータへ直接届き、他の六ビットは届かない。ダイにはちょうどその六本のための dasb という名前の第二の線の組がある。BCD の補正は 6 を足すもので、2 進では 0110 だから、ビット 0 と 4 は決して変わり得ない。設計者はそれらを補正の回路に通さなかった。命令セットの十進モードが、近道をする二本の線として見えている。

割り込みベクタ。 adl0、adl1、adl2 は 0/ADL0..2 という名前のゲートに駆動されている。このバスの他のビットはどれも、何も駆動しない純粋な線だ。三ビットなのは、6502 が取り込める六つのベクタアドレス (NMI の $FFFA と $FFFB、リセットの $FFFC と $FFFD、IRQ と BRK の $FFFE と $FFFF) が下位三ビットでしか違わないからだ。アドレスの残りはすべて 1 でどこから来てもよく、どの割り込みを取っているかを選ぶ部分は、ちょうど三本の線だ。

保存されないフラグ。 p にビット 5 は無く、idb5 は H1x1 が届かない唯一のデータバスのビットだ。H1x1 はステータスレジスタをバスに載せる線で、存在しないビットをそこに載せることはできない。p のビット 4 も変わっている: 記憶ではなくインバータだ。B は保存されたフラグではまったくなく、チップがなぜ P を押しているかの読みだからだ。

なぜ (書き下ろし)。 規則正しさは、配置するのも検証するのも無料だ。だから同じスライスを八つ組んで、同じでは間違いになる二、三の場所に知恵を使う。例外を探すこと。設計者が考えていたのはそこだ。

実際に見に行く

上のイディオムはどれも、稼働中のチップの上にある。以下のリンクは、それを描くページを、その当のものの位置で開く。下の各パラメータは、このファイルが書かれる前に、行き先のページ自身のソースに照らして確認されている。このプロジェクトはすでに、どのページも読んだことのないパラメータを抱えたリンクを出荷したことがあり、死んだディープリンクは壊れた機能とまったく同じに見えるからだ。

何を見るかどこで
二段インバータの輪、レジスタ一つずつ/tracer?reg=x
最も広いバスと、そこに届く線/tracer?bus=sb
十進の補正: 遠回りをする六ビット/tracer?sb=dasb
保存されないフラグ/tracer?flag=B
シフタ自身のビットスライス/chipmap?sel=alu:bit7
タイミングの鎖を、カウンタではなくセルとして/tracer?chain=T3
LDA と LAX が共有する PLA の行/decode?term=28
一つのゲートと、それを作っているもの/schematic?signal=sb0

docs/atlas.md が住所の規則を与えるので、上のどれも名前で引ける。レジスタのセルは regs:x:#1 (x2) だ。チップマップはあらゆる容れ物を描き、トレーサはそれらを半サイクルずつ光らせる。

そしてもう一方の向き、こちらが身に付くほうだ: チップのためにプログラムを書く。Die Runner は、画面が自分のメモリの 1 ページである 6502 の ROM で、そのエミュレータではなくこのシミュレーションの上で走る。だから毎フレームが、本物の解読 PLA が本物の模様に一致し、本物のバスが上に挙げた出どころの間を調停するところだ。games/README.md。