CPU

Jeans & Development 電子ブロック工房 三日坊主 フロントページ

NAND型 CPU [CPU]

2015年3月16日

演算がNANDと左シフトのみが可能な、6ビットCPUを考えてみた。

ここのところ、PICやLPCなどの組込みマイコンと、MZ-80Kの話題ばかり続いたが、このブログは本来、副題にもあるとおり「IC・トランジスタで出来たコンピューターを設計・製作する」ためのもので、久々にその初心の話。

NANDの組み合わせだけですべての論理演算が可能であるのはよく知られていることであり、初期のコンピューターの中には、このロジックで作成されていたものもあったらしい。

ということは、CPUで使える演算子としてNANDだけを用意しておけば良いはずで、あと、上位ビットと下位ビットとの間での情報のやりとりとして、シフト演算(左シフト)があれば、すべての演算が行える。加えて、条件分岐できれば、CPUとしての体裁が整うはずである。

この、必要最小限の機能を持ったCPUを如何にシンプルな構造で構築するかというのを、この1-2週間考えていた。

4 bit RISC CPUの回路 [CPU]

2012年12月11日

ほぼ、完成。 JUMP, CALC, SKIPなど、いくつかの命令が予想通り動くことを確認。

2012-12-11-kmrisc4.png

4 bit RISC CPU [CPU]

2012年12月4日

RISCアーキテクチャを用いたCPUに変更する事になりそうだ。

新しいCPUの仕様に従って、回路をこつこつと設計していたのだが、7割ほど出来上がったところで問題が発生した。どうやら、今の設計では、小規模のCPLD(マクロセル64以下)には収まりそうもなく、比較的規模の大きいCPLDか、FPGAの規模になってしまいそうである。

こうなると、まず最初のCPUをCPLDの中に納めるという短期目標が難しくなり、トランジスターで組むという最終目標はほとんど達成できそうもない。今のまま進めても、CPLDレベルや汎用ロジックのレベルでは何とかなるかも知れないが、最初の設計の段階で手を打っておかないと、後で一からやり直しということになりかねないように思う。

CPUをなるだけ簡単にするという事で真っ先に思い浮かぶのはRISCアーキテクチャで、4ビットのCPUもこれで出来ないかと、少し考えてみた。

2012-12-04-registers.png

CPUの仕様を若干修正 [CPU]

2012年11月22日

CPLDで回路を組んでいる途中で気が付いたことに対応するため、命令の順を若干変更した。
2012-11-22-cpu.png

変更したのは、演算命令のssの位置と、それに伴って上位3ビットを011から010に(こうすることで、ソースの指定が 0ss になる )したこと。ソースをbit3-5に固定、デスティネーションをbit0-2に固定するため、ロード命令のsssとdddを入れ替えたこと。インクリメント・デクリメントとリテラル値のSレジスタへの代入を余った領域に割り当て直したこと。

これらの変更で、回路が若干簡略化される。

4 bit CPU ver 0.3 [CPU]

2012年11月12日

新しい4 bit CPUの仕様が、ほぼ固まったと思う。

2012-11-12-registers.png

CPU ver 0.0.7.1 [CPU]

2009年10月7日

CPUの規格を、変更。

data line: 8 bits
address line: 14 bits (8 bits + 6 bits; 256 x 64; 16K bytes)

registors A(8), F(8), PC(12), SP(8)
F: Z, C, S5, S4, S3, S2, S1, S0 (Z, C: zero and carry flags; S: segment registor)
stack segment is always 0x3f
program can be written from 0x0000 to 0x0fff (total 4K bytes)


All 2 byte commands

0x00, 0x01, ... , 0x0f: goto, operand: 12 bits.
0x10, 0x11, ... , 0x1f: call, operand: 12 bits.
0x20, 0x21, ... , 0x27: A=A+XX, A=A-XX, A=(XX), [A]=(XX), A=A&XX, A=A|XX, (XX)=A, (XX)=[A] 
0x2800 - 0x28ff: A=XX
0x2900 - 0x29ff: stack-using processes
    bit 0-1: A, reserved, F, or none
    bit 2: use also c7 for read/write
    bit 3: SP++ or SP-- at c4
    bit 4: SP++ or SP-- at c6
    bit 5: SP++ or SP-- at c8
    bit 6: 0: SP++, 1: SP--
    bit 7: 0: read, 1: write (c5)
0x2900 - 0x2907: A=[SP], reserved, F=[SP], reserved
0x2908 - 0x290f: [SP]=A, reserved, [SP]=F, reserved
0x2910 - 0x2917: pop A, reserved, pop F, SP++
0x2918 - 0x291f: [++SP]=A, reserved, [++SP]=F,
0x2920 - 0x2927: A=[SP++], reserved, F=[SP++],
0x2928 - 0x292f: [SP++]=A, reserved, [SP++]=F,
0x2930 - 0x2937: A=[++SP++], reserved, F=[++SP++], SP+=2, , , , return
0x2938 - 0x293f: [++SP++]=A, reserved, [++SP++]=F,
0x2960 - 0x2967: A=[SP++++], reserved, F=[SP++++], 
0x2968 - 0x296f: [SP++++]=A, reserved, [SP++++]=F,
0x2970 - 0x2977: A=[++SP++++], reserved, F=[++SP++++], SP+=3
0x2978 - 0x2978: [++SP++++]=A, reserved, [++SP++++]=F,
0x2990 - 0x2997: A=[--SP], reserved, F=[--SP], SP--
0x2998 - 0x299f: [--SP]=A, reserved, [--SP]=F,
0x29a0 - 0x29a7: A=[SP--], reserved, F=[SP--],
0x29a8 - 0x29af: push A, reserved, push F,
0x29b0 - 0x29b7: A=[--SP--], reserved, F=[--SP--], SP-=2
0x29b8 - 0x29bf: [--SP--]=A, reserved, [--SP--]=F,
0x29e0 - 0x29e7: A=[SP----], reserved, F=[SP----],
0x29e8 - 0x29ef: [SP----]=A, reserved, [SP----]=F,
0x29f0 - 0x29f7: A=[--SP----], reserved, F=[--SP----], SP-=3
0x29f8 - 0x29ff: [--SP----]=A, reserved, [--SP----]=F,
0x2a00 - 0x2a03: A=A (NOP), reserved, A=F, A=SP
0x2a04 - 0x2a07: reserved
0x2a08 - 0x2a0b: F=A, reserved, resreved, F=SP
0x2a0c - 0x2a0f: SP=A, reserved, SP=F, reserved
0x2a10 - 0x2aff: reserved
0x2b00 - 0x2dff: reserved
0x2e00 - 0x2eff: (XX)++
0x2f00 - 0x2fff: (XX)--

0x30, 0x31, ... , 0x38: A=A+(XX), A=A-(XX), A=A+(XX)+C, A=A-(XX)-C, A=A&(XX), A=A|(XX), A=A^(XX), A=~(XX)
0x39, 0x3a, ... , 0x3f: (XX)=(XX)+A, (XX)=(XX)-A, (XX)=(XX)+A+C, (XX)=(XX)-A-C, 
                        (XX)=(XX)&A, (XX)=(XX)|A, (XX)=(XX)^A, (XX)=~A
0x40, 0x41, ... , 0x4f: jz, operand: 12 bits.
0x50, 0x51, ... , 0x5f: jc, operand: 12 bits.
0x60, 0x61, ... , 0x6f: jnz, operand: 12 bits.
0x70, 0x71, ... , 0x7f: jnc, operand: 12 bits.
0x80, 0x81, ... , 0x8f: reserved
0x90, 0x91, ... , 0x9f: reserved
0xa0, 0xa1, ... , 0xaf: reserved
0xb0, 0xb1, ... , 0xbf: reserved
0xc0, 0xc1, ... , 0xcf: reserved
0xd0, 0xd1, ... , 0xdf: reserved
0xe0, 0xe1, ... , 0xef: reserved
0xf0, 0xf1, ... , 0xff: reserved

(XX) = [3Fh:XX]; used as registors; genelary, F8-FF (8 registors) are used.

設計進捗 [CPU]

2009年9月18日

ジャンプ・コール・リターンの3つの命令が実行できるようになった。とりあえず、バックアップの意味もかねて、記事を上げる。

現在設計中のコンピューターの特徴は、次のとおり。

・データラインは8ビット、アドレスラインは14ビット(16384 bytes)。
・2つの8ビット汎用レジスター、X, Y。
・フラグは、ゼロとキャリーの2つ。これらを含むFレジスターは、データ読み書きのセグメントアドレスを含む。
・ プログラムカウンタは、12ビット。従って、全アドレスのうち4分の1の、4096バイトのみがプログラミングに利用できる。
・スタックポインタは、8ビット。全アドレスの最後の256バイトのみが、スタック領域として利用できる部分。
・すべての命令が2バイトで記述される。

8 bit CPU [CPU]

2009年7月21日

紆余曲折の結果、結局 8 bit のオーソドックスなCPUに落ち着きそう。

仕様は、次のとおり。

version 0.0.6.1
data line: 8 bits
address line: 14 bits (8 bits + 6 bits; 256 x 64)

registors X(8), Y(8), F(8), PC(12), SP(8)
F: Z, C, S5, S4, S3, S2, S1, S0 (Z, C: zero and carry flags; S: segment registor)
stack segment is always 0x3f
program can be written from 0x0000 to 0x0fff


All 2 byte commands

0x00, 0x01, ... , 0x0f: goto, operand: 12 bits.
0x10, 0x11, ... , 0x1f: call, operand: 12 bits.
0x20, 0x21, ... , 0x27: X=XX, [X]=XX, X=(XX), (XX)=X, Y=XX, [Y]=XX, X=(XX), (XX)=X
0x28, 0x29, ... , 0x2f: (see below)
0x2800 - 0x280f: X=X (NOP), X=Y, X=F, X=SP, reserved, X=[Y],
0x2810 - 0x281f: Y=X, Y=Y, Y=F, Y=SP, Y=[X], reserved,
0x2820 - 0x282f: F=X, F=Y, F=F, SP=SP, F=[X], F=[Y],
0x2830 - 0x283f: SP=X, SP=Y, SP=F, SP=SP, SP=[X], SP=[Y],
0x2880 - 0x288f: [X]=X, [X]=Y, [X]=F, [X]=SP, reserved, reserved,
0x2890 - 0x289f: [Y]=X, [Y]=Y, [Y]=F, [Y]=SP, reserved, reserved,
0x2900 - 0x290f: [SP]=X, [SP]=Y, [SP]=F,
0x2920 - 0x292f: push X, push Y, push F, SP--
0x2940 - 0x294f: [++SP]=X, [++SP]=Y, [++SP]=F,
0x2960 - 0x296f: [SP+1]=X, [SP+1]=Y, [SP+1]=F,
0x2980 - 0x298f: X=[SP], Y=[SP], F=[SP],
0x29a0 - 0x29af: X=[SP--], Y=[SP--], F=[SP--],
0x29c0 - 0x29cf: pop X, pop Y, pop F, SP++
0x29e0 - 0x29ef: X=[SP+1], Y=[SP+1], F=[SP+1],
0x30, 0x31, ... , 0x38: (XX)=X+Y, (XX)=X-Y, (XX)=X&Y, (XX)=X|Y, (XX)=X+Y+C, (XX)=X-Y-C, (XX)=X^Y, (XX)=~X
0x38, 0x31, ... , 0x3f: X=++(XX), X=--(XX), reserved x2, Y=++(XX), Y=--(XX), reservedx2
0x40, 0x41, ... , 0x4f: jz, operand: 12 bits.
0x50, 0x51, ... , 0x5f: jc, operand: 12 bits.
0x60, 0x61, ... , 0x6f: jnz, operand: 12 bits.
0x70, 0x71, ... , 0x7f: jnc, operand: 12 bits.
0x80, 0x81, ... , 0x8f: reserved
0x90, 0x91, ... , 0x9f: reserved
0xa0, 0xa1, ... , 0xaf: reserved
0xb0, 0xb1, ... , 0xbf: reserved
0xc0, 0xc1, ... , 0xcf: reserved
0xd0, 0xd1, ... , 0xdf: reserved
0xe0, 0xe1, ... , 0xef: reserved
0xf0, 0xf1, ... , 0xff: reserved

(XX) = [3Fh:XX]; used as registors; genelary, F0-FF (16 registors) are used.

6bit CPU [CPU]

2007年8月6日

ニーモニック表を更新。2 byte, 3 byte 命令を認識しやすくするため、少し順序を入れ替えた。

6 bit CPU [CPU]

2007年7月27日

ばかげた 1 bit CPU を考えていて気が付いたのは、6ビットCPUが結構シンプルに設計できそうなこと。先日のクロック周りの回路の設計から来る考察をくわえて、さらにシンプルなCPUが出来そうな気配。

今考えているのは、6ビットのレジスタとして、

a: アキュムレータ
b: メモリ指定用レジスタ
ds: データセグメント
ip: インデックスポインタ(プログラムカウンタ)
cs: コードセグメント
sp: スタックポインタ

の6つを用意。アドレス空間は、12ビットのアドレスラインで4096ワード(3072ビット)。簡単なプログラムなら、これくらいの要領があればおそらく十分。このあたり、4ビットではなくて6ビットにしたのが味噌で、2ワードのアドレスラインで必要最小限と思われるメモリ領域にアクセスできる。4ビットなら、3ワード必要だろう。74174という6ビットのフリップフロップがあるのも、良い。1つのセグメントが64ワードだから、そこそこの大きさのプログラムがここに収まる。4ビットの考え方だと16ワードで、小さなプログラムしかかけない。ジャンプ命令の仕様で難が出る。

スタックセグメントは、6502に習って省略した。従って、スタック領域は64ワードのみ。フラグは、例によってキャリーとゼロの2つだけである。
<<前の記事