このあたりからはご存じの方が多いかと思います。マイクロプロセッサが急速に普及したのは、この8080Aが契機だといっても過言ではないでしょう。これ以前の、たとえば8008ではコンピュータとして動作させるのに60個以上のICから構成される回路を作成しなくてはなりませんでした。ところが8080Aでは20個程度のICから構成される回路でコンピュータの形態になります。4040と違い、8 bitの文字データを簡単に操作できますし、プログラムとデータの区別なく同じメモリに格納するようになっています。また、それまでのマイクロプロセッサ製品と異なり、プロセッサを普及させ応用できる技術者を増やすために、各社が評価用のキットを発売したというのも、事件でした。本来の対象であったすぐに応用製品を開発しなくてはならない技術者以外の、コンピュータに興味があったアマチュアが一斉に飛び付いたからです。日本でもNECからuPD8080Aを搭載したTK-80が発売され、これで8080Aを知った方も多いと思います。またMITS社のALTAIRキットのように、ミニコンピュータ風のコンピュータシステムを構築しやすい初のLSIでもありました。8008では8080の数倍規模の外付け回路が必要で、そのわりに性能が低く、汎用コンピュータ風のシステムが発売された例はごく少数です。同時にメモリの価格も低下してきていて、8080Aが使われだした時代には1 KByte数万円以下で購入できる程度になっていたのも、そういう用途への後押しになったと思われます。
IntelのWeb資料によれば、8080は1974年4月1日発表、6 umのn-MOSプロセスで約6000個のトランジスタを集積してあり、2 MHzクロックで動作するとのことです。ただし、4800個のトランジスタとしている文献もあり、おそらくこちらが正しそうです。内部レジスタに対する8 bit加算命令には最短4クロック必要ですから、2 usの実行時間で、8008の20 usと比べれば10倍の性能ということができるでしょう。
さて、では写真。これは1976年製。
ピン配置はこのようになっています。
A10 1 40 A11 VSS 2 39 A14 D4 3 38 A13 D5 4 37 A12 D6 5 36 A15 D7 6 35 A9 D3 7 34 A8 D2 8 33 A7 D1 9 32 A6 D0 10 31 A5 VBB 11 30 A4 RESET 12 29 A3 HOLD 13 28 VDD (+12 V) INT 14 27 A2 CK2 15 26 A1 INTE 16 25 A0 DBIN 17 24 WAIT WR* 18 23 READY SYNC 19 22 CK1 VCC 20 21 HLDA VBBは-5 V、VCCは+5 V
8008と比べると、ピン数が多いのはもちろんですが、なんかデータ線やアドレス線の順番が入れ代わっていたりして、マスクレイアウトの都合がそのまま反映されている感じがします。ソフトウェアや信号の意味が互換のNECのuPD753のピン配置と比べるとおもしろいかもしれません。
電源とアドレス・データ信号の意味は自明でしょう。RESETはリセット信号で正論理です。というより、負論理の信号はWR*のみで正論理信号ばかりが使われているのが特徴ともいえます。HOLDとHLDAがDMA用の信号、INTとINTEが割り込み用、CK1とCK2がクロック、WAITとREADYがメモリやI/Oへのアクセスタイム調整用信号、DBINとWR*が読み書きのタイミング指示、SYNCが内部ステータス情報のデータバス出力タイミング信号です。
以上の信号には、メモリとI/Oのアクセスを区別する信号などが含まれていません。それらはステータス情報を解読して決定してやらなくてはなりません。つまり8080Aの全機能を利用するためには、バスの制御タイミングを決定する少し面倒な回路を外付けする必要があるのです。ここがMC6800との大きな違いとなります。そのためにIntel社は8228システムコントローラといったICを別に提供していました。
ステータス情報の詳細について説明しましょう。ステータス情報は8080がバスを介してデータ転送を行うサイクルの途中、実際にデータ転送を行う前のタイミングで、SYNCがHの間にデータバスに出力されます。SYNCとステータス情報とは完全にタイミングが一致していないため、SYNCがHかつCK1がHのタイミングでラッチして情報を保持するのが普通です。ステータス情報は出力されるデータバスの個々のビットごとに異なった意味が割り当てられています。
D0 INTA 割り込み応答バスサイクルであることを示す。 D1 WO* 書き込みを行うバスサイクルであることを示す。 D2 STACK スタックポインタの指すメモリへのバスサイクルであることを示す。 D3 HLTA HALT命令を実行していることを示す。 D4 OUT I/Oポートへの出力サイクルであることを示す。 D5 M1 CPUが命令の第1バイトを読み込むバスサイクルであることを示す。 D6 INP I/Oポートからの入力サイクルであることを示す。 D7 MEMR メモリからの読み込みを行うバスサイクルであることを示す。
これらによって、完全に分類すれば10種類のステータスが表現されます。それぞれのステータスがどのようなステータス情報の組み合わせで表現されるか、お暇なら考えてみてください。とにかく256通りの組み合わせのある8 bitデータで、実際に出力されるのは下の10種類の組み合わせだけなのです。
その中には、スタックへの書き込みやスタックからの読み込みなんかも含まれていて、そうする必要があるなら、スタック専用にしか使われない特別なメモリを8080Aコンピュータシステムに付け加えることすらできます。また、実際のデータ転送に先立って、これから実行されるのが書き込みか読み込みかWO*で識別することができるため、データバスのバッファの方向制御を行いやすいとか、情報がCPUからたくさん出力される分、便利なこともあります。しかし普通に必要となる解読情報はメモリリード、メモリライト、I/Oリード、I/Oライト、割り込みアクノレッジの5種類だけで、しかもメモリリードやメモリライトはスタックかそれ以外かの区別がない形式のものだけです。当時普通に入手できたLS TTLでこのステータス情報の保持解読回路を作成すると、4個のICが必要になるなど、小規模な応用にはよけいなお世話というべきものでした。そのため、通常は保持解読回路の4個のICとデータバスバッファの2個のICをひとつのパッケージに入れたような8228が使われ、ステータス情報を直接利用するような応用はほとんどみられませんでした。
さて、私はIntelオリジナルの8080は持っていません。上の写真は8080Aであって、8080の出力ピンの駆動力を強化した改良品です(だからAが付いている)。オリジナルの8080では、アドレスバス、WAIT, INTE, WR, DBIN, HLDAの出力ピンの駆動能力はL-TTLファミリ1個分しかありませんでした。8080Aでは通常のTTLファミリ1回路分の駆動能力(IOL: -1.9 mA)が保証されています。ところで、次の写真のTexas Instruments社のTMS8080にはAが付いていませんが、8080相当品なのでしょうか、8080A相当品なのでしょうか。たぶん8080A相当品だと考えていますが、正確にはわからないので、どなたか教えてください。
と、思っていたのだけど、今、TK-80のコメントを書こうとTK-80に電源を入れて使える状態になっていることをいいことに、uPD8080AFと差し替えてみたら、数10秒で暴走する。タイミングか電圧レベルのマージンが足りないような症状で、ファンアウトが足りないと仮定するとしっくりくるから、やっぱり8080相当品の可能性が高いかもしれない。あ、TK-80は上記の信号の中でTTL 1回路分の負荷をかけてしまっているところや、LS TTL 2回路分近い負荷がある信号が存在するために、8080では正常動作しない可能性があるので。なお、これ以外のここに掲載した8080A相当品はみんなTK-80で安定して動作しました。
Texas Instruments社のTMS8080(上)、NEC社のuPD8080A(中央)とuPD8080AF(下)。
と、読者の方から指摘がありました。特性の抜粋を知らせてくださいましたが、TMS8080は8080と8080Aの中間的な特性を持っていたようです。バスの電気的特性は8080Aに近いものでしたが、クロック信号に関するタイミングや電気的特性は8080に近いものでした。どうもクロック信号の条件が満たされていないための誤動作のようです。
写真中央のICは、文字が読み取れませんが、uPD8080Aです。一部命令の実行クロック数が異なるのと、減算のときにも10進補正命令が動作するという改良が(勝手に)行われていた石です。TK-80のオリジナルにも使われていましたね。下の方はuPD8080AF。FはFull CompatibleのFと言われていました。オリジナルの8080Aとまったく同一の動作をするように修正されたものです。当時は、命令の実行時間を利用して外部機器の制御タイミングをとることが結構行われていましたから、下手に少し早くなるような改良を行うと不評だったのですね。実行クロック数の比較は後にある命令表を参照のこと。
レジスタセットはこのようになっています。
B, C, D, E, H, Lがスクラッチパッドレジスタで、Aがアキュムレータです。ほとんどすべての演算は、このAレジスタと別のスクラッチパッドレジスタとの間で行われます。また、Fレジスタは演算結果によって自動的にセットされるフラグ類がまとめられているもので、演算の対象となりません。フラグの意味は、SがSignで演算結果の符号、ZがZeroで演算結果が0かどうか、HがHalf Carryで10進補正命令用の下位4 bitからの桁あげ、PがParityで演算結果の1のビットが偶数個あればセット、CがCarryで演算結果で桁あげが発生したことを示します。AF, BC, DE, HLはそれぞれ対になって、16 bit幅のレジスタとして操作されることがあります。
PCと表記されているプログラムカウンタは64 KByteに拡張されたアドレス空間を指すべく16 bit幅で、サブルーチンからの戻りアドレスを記録するスタックは外部メモリにとられるようになり、SPと表記されているスタックポインタがそのアドレスを指しています。また、このスタックはAF, BC, DE, HLのレジスタ対を個別にプッシュしたりポップしたりできるようになっていて、Intelのマイクロプロセッサでは初めて現代的なスタックになっています。ただし、スタックポインタにオフセットを加えるようなアドレッシングモードも、インデックス修飾の可能なアドレッシングモードも、共に命令体系の中には存在しませんから、スタックフレームを用いたローカル変数管理なんかを行おうとすると、手間です。が、BCレジスタ対とDEレジスタ対がスタックトップの2語、あるいはDEレジスタ対がスタックトップの1語というように解釈すれば、小さなサブルーチンならそれほどローカル変数が必要ありませんから、再帰的定義なども意外にうまく行きます。XTHL命令でスタックトップとHLレジスタを入れ替えることができますから、アキュムレータを作業用に残しておいてもBC, DE, HLとスタックトップ2 Byte分、計8 Byte分のローカル変数を持つことができます。サブルーチンを呼び出すときには破壊してはいけないレジスタをスタックにプッシュすれば、一種のローカル変数用のスタックフレームが自然とスタック上に形成されるというわけ。今から見れば整理されていない非力な命令体系のように思えるでしょうが、当時としてはそれ以前の4004とか8008などの本当に初期のマイクロプロセッサと比べていたのですから、そりゃもう至れり尽せりの強力なアーキテクチャでした。
では具体的な命令について見ていきましょう。命令表を以下に示します。読み方については表の後にある注釈を参照。一応、これだけわかればアセンブラを作成したり、アセンブリ言語でプログラムを書ける程度には整備したつもりですが。なお、アセンブラ表記のオペランドの項にimmとある命令とIN/OUT命令は2 Byte命令で、addrかimm16が含まれる命令は3 Byte命令になります。それ以外の命令はすべて1 Byte命令です。
命令コード アセンブラ表記 clock uPDck 意味 01 ddd sss MOV rm, r 5/7 4/7 move 01 ddd 110 MOV r, M 7 7 move memory to register 01 110 110 HLT 7 7 halt 00 ddd 110 MVI rm, imm 7/10 7/10 move immediate 00 ddd 100 INR rm 5/10 5/10 increment 00 ddd 101 DCR rm 5/10 5/10 decrement 10 000 sss ADD rm 4/7 4/7 add 10 001 sss ADC rm 4/7 4/7 add with carry 10 010 sss SUB rm 4/7 4/7 subtract 10 011 sss SBB rm 4/7 4/7 subtract with borrow 10 100 sss ANA rm 4/7 4/7 and with A 10 101 sss XRA rm 4/7 4/7 exclusive or with A 10 110 sss ORA rm 4/7 4/7 or with A 10 111 sss CMP rm 4/7 4/7 compare with A 11 000 110 ADI imm 7 7 add immediate to A 11 001 110 ACI imm 7 7 add immediate to A with carry 11 010 110 SUI imm 7 7 subtract immediate from A 11 011 110 SBI imm 7 7 subtract immediate from A with borrow 11 100 110 ANI imm 7 7 and immediate with A 11 101 110 XRI imm 7 7 exclusive or immediate with A 11 110 110 ORI imm 7 7 or immedeate with A 11 111 110 CPI imm 7 7 compare immediate with A 00 000 111 RLC 4 4 rotate A left 00 001 111 RRC 4 4 rotate A right 00 010 111 RAL 4 4 rotate A left through carry 00 011 111 RAR 4 4 rotate A right through carry 11 000 011 JMP addr 10 10 jump unconditional 11 011 010 JC addr 10 10 jump on carry 11 010 010 JNC addr 10 10 jump on no carry 11 001 010 JZ addr 10 10 jump on zero 11 000 010 JNZ addr 10 10 jump on no zero 11 110 010 JP addr 10 10 jump on positive 11 111 010 JM addr 10 10 jump on minus 11 101 010 JPE addr 10 10 jump on parity even 11 100 010 JPO addr 10 10 jump on parity odd 11 001 101 CALL addr 17 17 call unconditional 11 011 100 CC addr 11/17 11/17 call on carry 11 010 100 CNC addr 11/17 11/17 call on no carry 11 001 100 CZ addr 11/17 11/17 call on zero 11 000 100 CNZ addr 11/17 11/17 call on no zero 11 110 100 CP addr 11/17 11/17 call on positive 11 111 100 CM addr 11/17 11/17 call on minus 11 101 100 CPE addr 11/17 11/17 call on parity even 11 100 100 CPO addr 11/17 11/17 call on parity odd 11 001 001 RET 10 11 return 11 011 000 RC 5/11 5/11 return on carry 11 010 000 RNC 5/11 5/11 return on no carry 11 001 000 RZ 5/11 5/11 return on zero 11 000 000 RNZ 5/11 5/11 return on no zero 11 110 000 RP 5/11 5/11 return on positive 11 111 000 RM 5/11 5/11 return on minus 11 101 000 RPE 5/11 5/11 return on parity even 11 100 000 RPO 5/11 5/11 return on parity odd 11 vvv 111 RST vec 11 11 restart 11 011 011 IN port 10 10 input 11 010 011 OUT port 10 10 output 00 pp0 001 LXI rp, imm16 10 10 load imediate register pair 11 pp0 101 PUSH rr 11 11 push register pair on stack 11 pp0 001 POP rr 10 10 pop register pair off stack 00 110 010 STA addr 13 13 store A direct 00 111 010 LDA addr 13 13 load A direct 11 101 011 XCHG 4 4 exchange D & E, H & L registers 11 100 011 XTHL 18 17 exchange top of stack, H & L 11 111 001 SPHL 5 4 H & L to stack pointer 11 101 001 PCHL 5 5 H & L to program counter 00 pp1 001 DAD rp 10 11 add register pair to H & L 00 pp0 010 STAX rx 7 7 store A indirect 00 pp1 010 LDAX rx 7 7 load A indirect 00 pp0 011 INX rp 5 5 increment register pair 00 pp1 011 DCX rp 5 5 decrement register pair 00 101 111 CMA 4 4 complement A 00 110 111 STC 4 4 set carry 00 111 111 CMC 4 4 complement carry 00 100 111 DAA 4 4 decimal adjust A 00 100 010 SHLD addr 16 16 store H & L direct 00 101 010 LHLD addr 16 16 store H & L direct 11 111 011 EI 4 4 enable interrupts 11 110 011 DI 4 4 disable interrupt 00 000 000 NOP 4 4 no operation
注:2進数表記の命令コードの中に書かれた記号の意味については、dddはディスティネーションレジスタを示す数値、sssはソースレジスタを示す数値。ppはレジスタペアを表す数値。これらの具体的な数値については後で表にして示す。vvvはリスタートベクトルを表す数値(0から7)。
clockは命令実行に必要なクロック数。ただし、オペランドにrmと指定のあるものはc1/c2と表記されていて、実際にrが指定されたときにc1クロック、Mが指定されたときにはc2クロックが消費される。同じく条件命令の場合、条件が成立しなかったときにc1クロック、成立したときにc2クロックが消費される。uPDckはuPD8080Aの場合の命令実行クロック数。uPD8080AFの場合にはclockの項が適用される。
アセンブリ言語表記のオペランド部で、rはA, B, C, D, E, H, Lのいずれか、rmはA, B, C, D, E, H, L, Mのいずれかを指定する。レジスタペアを表すrpはB, D, H, SPのいずれか、rxはBかDを指定し、それぞれBC, DE, HL, SPの16 bitポインタレジスタを意味する。ただしPUSH/POP命令に関してはB, D, H, PSWをrrとして指定でき、それぞれBC, DE, HL, AFのレジスタペアを意味する。immは8 bit定数で、imm16は16 bit定数。addrは16 bitの絶対アドレスを表す数値。vecは0から7までの数値。portは8 bitのI/Oアドレスを表す。
レジスタ名と命令コード上でレジスタを表す数値との対応は次の表の通り。
レジスタ名 ddd/sss r rm A 111 * * B 000 * * C 001 * * D 010 * * E 011 * * H 100 * * L 101 * * M 110 *
レジスタペアについては、このような値で指定する。「表記」という列はアセンブリ言語上での表記法について書き込んである。BCレジスタペアのアセンブリ言語上での表記はBとなることに注意。
ペア 表記 pp rp rr rx BC B 00 * * * DE D 01 * * * HL H 10 * * SP SP 11 * AF PSW 11 *
また、そのレジスタがr, rm, rp, rxの指定に含まれる場合に各欄に*を書き込んでおいた。無印のレジスタ(例:rの場合のMレジスタ)は、そのアセンブリ言語表記でオペランドに使用するとエラーになる。
上の命令表で、LXI命令からDI命令までが8008にはなくて8080で新設された命令です。それ以外の命令は8008に備わっていますがアセンブリ言語レベルで同一表記になるだけで、バイナリコードには互換性がありません。
総じて、レジスタペアを用いる命令が強化されています。レジスタペアをポインタとして使える他、16 bitデータのインクリメントやデクリメントに加えて加算まで可能になっています。8008で書きにくかった256 Byteアラインメントを越えるデータ操作が楽になっています。PUSH/POP命令はレジスタペア単位で保存と復帰が可能な1 Byte命令で、効率良くワーキングレジスタを実質的に増やすことができます。また、PCHLはHLレジスタペアの指す場所へのジャンプ命令で、計算値や表駆動による分岐が可能になりました。XTHLもポインタを実質的に増やすための命令ですし、サブルーチン内でうまく使用するとCALL命令に続けて格納された定数に対して処理を行なうプログラムを効率良く書けます。
また、新設された命令ではありませんが、条件付きRET命令のクロック数は特徴的で、条件判定にうまく利用すると、条件不成立のときにわずか5クロックで実行されますから高速化に役立ちますし、1 Byte命令であることもあってコード密度を高めることができます。なにしろ8080の他の条件分岐命令はすべて3 Byte命令ですから。
uPD8080Aとそれ以外の8080および互換プロセッサの命令実行クロック数を比較してみると、レジスタ間のMOV命令やXTHL命令なんかがuPD8080Aの方が1クロックほど短くなっています。しかしDAD命令やRET命令のように遅くなっている命令もあります。NECでIntelのまねをして設計しているときに、設計の都合でわずかに変化してしまったという感じですね。
ADD命令と内部レジスタに対するINC命令を比較するとADD命令の方が1クロック早くなっていますが、これはディスティネーションレジスタがADD命令ではAレジスタに固定されているのに、INC命令ではAからHまでのどれかのレジスタが対象になるための違いでしょう。INC命令では対象レジスタからデータを読み出してインクリメンタに入力して、その出力を一時的にテンポラリレジスタに書き込んでから、よけいに必要な1クロックで対象レジスタにテンポラリレジスタの内容を書き込んでいたのでしょう。普通の8080ではMOV命令が4クロックでなくて5クロックなのも、テンポラリレジスタを介した転送のためではないかと思われます。するとXCHG命令の4クロックというのは異様な速度ですが、やはり入れ替えが簡単になるような特別な回路が用意されていたのでしょうね。HLレジスタとBCレジスタを入れ替えることはできませんし。
採用したコンピュータ製品
Intel SDK-80
NEC TK-80, TK-80E, TK-80BS, COMPO BS/80
東芝 EX-80, EX-80BS
AER MK-80A
MITS Altair 8800シリーズ
IMSAI 8080
POLY 88