現在進行形で作成中の自作三進 CPU 、愛称を Libra the Processor としました。(以下省略して Libra と書きます)
名前の由来は天秤座の英名 Libra です。平衡三進数は英語では Balanced Ternary といいますが、 balance という単語は天秤という意味も持ちます。
このページでは実装の回路的な話はあまりせずに、プログラムを描いたりするうえで把握したい情報をまとめたいと思います。
アーキテクチャ
まずは Libra のアーキテクチャを簡単に説明します。 Libra は大きく分けて以下の 4 つのユニットから構成されます。
- ステートユニット
- レジスタユニット
- ALUユニット
- メモリユニット
そしてすべてのユニットが一つの大きなバスに接続される形となっています。なお、すべてをバスに接続する形を採用したのは、それぞれのユニットを基板を分けて作ったときに接続しやすいようにという実装上の理由です。

次にそれぞれのユニットに含まれるものについて説明します。
ステートユニット
ステートユニットは CPU の状態を管理するためのユニットです。 Libra はマルチサイクルプロセッサなので、各クロックにおいて命令のどの段階を実行しているかを state が表します。具体的な状態遷移についてはここでは省略します。
PC (プログラムカウンタ)は実行する命令のアドレスを表し、 SP (スタックポインタ)はスタックトップのアドレスを表します。どちらも幅は 5trit 、初期値は -121 (0t#####) です。
sign は演算命令を行った際にその結果の符号が記憶されるレジスタです。条件付きジャンプに使用します。幅は 1trit です。
レジスタユニット
Libra は 3 つの汎用レジスタを持ちます。 Imm は即値命令を実行する際にメモリから読みだした即値を格納するレジスタで、自由にアクセスすることはできません。
A, B, C の 3 つのレジスタのうち、 A レジスタは特殊なレジスタで基本的にどの演算もオペランドの片方は A レジスタとなります。アキュムレータに近いですが、書き込み先は B, C も選べるので微妙なところです。後述する ISA も併せて確認してください。
レジスタはすべて 5trit です。
ALUユニット
ALU ユニットは計算を行うユニットです。(ALUのUはUnitなのでALUユニットって表記は気持ち悪いですね。)記憶素子は持ちません。
ALU が実行できる演算は以下のとおりです。(すべて 5trit 幅)
- ADD
- SUB (NOT + ADD)
- NOT
- AND
- OR
- Shift Left (1trit)
- Shift Right (1trit)
Shift Left の LST, Shift Right の MST には 0 が補充されます。
メモリユニット
Libra は命令メモリ、データメモリ、スタックと 3 つのメモリを持っています。アドレス空間はそれぞれ独立しています。
アドレス幅、データ幅ともに 5trit です。
データメモリの 121(0t11111) 番地は MMIO として使用する予定です。(変更の可能性あり)
ISA
Libra 用の命令セットを紹介します。 ISA についてはあまり練れていないので、 Libra the Processor 1 号機が動いた後には改良することも考えています。
4~0 の欄は機械語のコードです。どの命令も 1 ワードで表現しています。即値を使う命令は命令本体と即値で 2 ワードとなっています。
r, d は A, B, C のレジスタを表し、機械語では A: 1, B: 0, C: # に対応します。
形式はアセンブリの引数を表しています。
| 命令 | 説明 | sign変更 | 命令長 | サイクル数 | 4 | 3 | 2 | 1 | 0 | 形式 |
|---|---|---|---|---|---|---|---|---|---|---|
| AND | d = A AND r | 〇 | 1 | 3 | 1 | r | 1 | 1 | d | DR |
| OR | d = A OR r | 〇 | 1 | 3 | 1 | r | 1 | # | d | DR |
| ADD | d = A + r | 〇 | 1 | 3 | 1 | r | 0 | 1 | d | DR |
| MOV | d = r | 〇 | 1 | 3 | 1 | r | 0 | 0 | d | DR |
| SUB | d = A – r | 〇 | 1 | 3 | 1 | r | 0 | # | d | DR |
| LD | d = MEM[r] | 1 | 3 | 1 | r | # | 1 | d | DR | |
| CMP | A – r | 〇 | 1 | 3 | 1 | r | # | 0 | – | R |
| ST | MEM[r] = A | 1 | 3 | 1 | r | # | # | – | R | |
| SL | d = A << 1 | 〇 | 1 | 3 | 0 | 1 | 1 | – | d | D |
| NOT | d = NOT A | 〇 | 1 | 3 | 0 | 1 | 0 | – | d | D |
| SR | d = A >> 1 | 〇 | 1 | 3 | 0 | 1 | # | – | d | D |
| ANDI | d = A AND imm | 〇 | 2 | 5 | 0 | 0 | 1 | 1 | d | DI |
| ORI | d = A OR imm | 〇 | 2 | 5 | 0 | 0 | 1 | # | d | DI |
| ADDI | d = A + imm | 〇 | 2 | 5 | 0 | 0 | 0 | 1 | d | DI |
| MOVI | d = imm | 〇 | 2 | 5 | 0 | 0 | 0 | 0 | d | DI |
| LDI | d = MEM[imm] | 2 | 5 | 0 | 0 | # | 1 | d | DI | |
| CMPI | A – imm | 〇 | 2 | 5 | 0 | 0 | # | 0 | – | I |
| STI | MEM[imm] = A | 2 | 5 | 0 | 0 | # | # | – | I | |
| PUSH | STACK[SP] = A; SP++ | 1 | 5 | 0 | # | 1 | – | – | N | |
| POP | SP–; d = STACK[SP] | 1 | 4 | 0 | # | # | – | d | D | |
| J | PC = imm | 2 | 5 | # | – | 1 | 1 | – | L | |
| JP | if (sign == 1) PC = imm | 2 | 5 | # | 1 | # | 1 | – | L | |
| JZ | if (sign == 0) PC = imm | 2 | 5 | # | 0 | # | 1 | – | L | |
| JN | if (sign == #) PC = imm | 2 | 5 | # | # | # | 1 | – | L | |
| CALL | PUSH(PC+1); PC = imm | 2 | 7 | # | – | 1 | 0 | – | L | |
| RET | PC = POP(); | 1 | 4 | # | – | # | 0 | – | N | |
| HALT | プロセッサ停止 | 1 | 3 | # | # | # | # | # | N |
特徴、注意点としては以下のような点が挙げられるでしょうか。
- Aレジスタをオペランドの片方として使う
- 書き込み先は自由に選べる
- ST, PUSHはAレジスタからしか保存できない
- 分岐はCMP + JZ (JP/JN) で行う
- スタックへのアクセスはPUSH/POP, CALL/RET で行う。特にSPは直接触れない
- MOVでもsignが変わってしまう(設計ミス)
- CMPは引き算の結果の符号だけ使うが、オーバーフロー、アンダーフローしたときも下位5tritの値で符号を判断するので注意(設計ミス)
まだ私自身もこの命令セットでプログラムをほとんど書いたことがないので使い勝手が分かりません…
アセンブリ
アセンブリのサンプルとして適当に書いたプログラムを載せておきます。 R 形式だけ例がありませんが、まあ分かるでしょってことで。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 100から3ずつ増加させて出力を10回繰り返すプログラム MOVI A, 10 // DI MOVI B, 3 MOVI C, 100 L1: PUSH // N MOV A, C // DR ADD A, B STI 0t11111 // I MOV C, A POP A // D ADDI A, -1 JZ L2 // L J L1 L2: HALT |
記述の特徴としては以下の点があります。
- コメントは //
- 即値は10進法または0tのプレフィックスをつけた平衡三進法で記述
- 即値の範囲は-121~121 (0t##### ~ 0t11111)
- N形式は引数なし
- L形式はラベル名を引数にとる
ツール
Libra the Processor を他の人にも触ってほしいという気持ちから、ツールをウェブで動かせるように作ったのでぜひ遊んでみてください。






数学の授業中に先生が「3進法で動いているコンピューターとかないかな」って呟いたのを聞いて、確かにと思い調べ始めました。電子工作やプログラミングなどはやっていないにわかですが、三進CPUとありとても興味を惹かれました。setunでは調べても大した情報が出てこなかったので、実在しないわけはないだろうと思い調べていた所きっちーさんのサイトに辿り着けました。平衡三進法の記事も読みましたが、nmosとpmosってなんだろうで躓いてしまったので勉強してから出直します(?)面白い取り組みだと思いました!