nand2tetris-rs

I try doing [Nand to Tetris](https://www.nand2tetris.org/) in Rust.


Project maintained by KBone12 Hosted on GitHub Pages — Theme by mattgraham

トップページ

Boolean Logic

And, Or 等の基本的なチップを実装します。また本家ではHDLを使っており、 Nand はプリミティブなものとして扱っていますが、ここでは Nand のみ Rust 言語の演算子を組み合わせて使い、以降は Nand を使って実装します。

Nand

Nand を演算子で実装しようとすると、結局 And と Not の組み合わせになってしまいます。

pub fn nand(a: bool, b: bool) -> bool {
    !(a && b)
}

Not

Not は単項演算なので、 Nand に渡す際に入力を複製することになります。すると、自動的に Not の完成です。

pub fn not(input: bool) -> bool {
    nand(input, input)
}

And

今回は Nand に Rust 言語の And を使っているのでわざわざ And を実装するのは手間に感じますが、既に Nand も Not もできているので単純に組み合わせるだけです。

pub fn and(a: bool, b: bool) -> bool {
    not(nand(a, b))
}

Or

Or は少し考える必要があります。ド・モルガンの法則より、 $\lnot{(a \land b)}=\lnot{a}\lor\lnot{b}$ が成り立つので、これを用いて以下のように実装します。

pub fn or(a: bool, b: bool) -> bool {
    nand(not(a), not(b))
}

Xor

Xor の実装は個人的に Or より少し難しかったです。真理値表を考えると、

$a$ $b$ $a \oplus b$
F F F
F T T
T F T
T T F

であり、入力それぞれの否定を考えると、

$a$ $b$ $\lnot{a}$ $\lnot{b}$ $a \oplus b$
F F T T F
F T T F T
T F F T T
T T F F F

すなわち、 $a \oplus b=(a \land \lnot{b})\lor(\lnot{a} \land b)$ で表されることが分かります。また、これらを Nand に分解していくと、

\[\begin{aligned} a \oplus b &= (a \land \lnot{b})\lor(\lnot{a} \land b)\\ &\iff \lnot{(\lnot{(a \land \lnot{b})}\land\lnot{(\lnot{a} \land b)})}\\ &\iff \text{Nand}(\text{Nand}(a,\lnot{b}),\text{Nand}(\lnot{a},b)) \end{aligned}\]

となり、さらに $\text{Nand}(a, \lnot{b})=\text{Nand}(a, \text{Nand}(a, b))$ が成り立つことに注意すると、最小 Nand 数の実装は次のようになります。

pub fn xor(a: bool, b: bool) -> bool {
    let tmp = nand(a, b);
    nand(nand(a, tmp), nand(tmp, b))
}

Mux

Mux は multiplexor すなわち、 selector のことです。 selector 信号が On か Off かでそれぞれの入力と And を取れば良く、また Or が入力それぞれの論理否定を取った後 Nand していることと、 And が Nand の論理否定として実装されていることを考えると、次のように実装すれば最小 Nand 数で実装できます。

pub fn mux(a: bool, b: bool, selector: bool) -> bool {
    nand(nand(not(selector), a), nand(selector, b))
}

DMux

DMux は demultiplexor すなわち、 Mux の逆です。 Mux が簡単に実装できたように、これも簡単に実装できます。

pub fn dmux(input: bool, selector: bool) -> (bool, bool) {
    (and(input, not(selector)), and(input, selector))
}

multi-ways や multi-bits なものはほとんどこの繰り返しでテストコードが長くなるだけなので、この記事では省略します。よってこれで Project 1 は無事完了です。