stet
← logs
open

AIで何でもできるようになってしまった今、Nand2TetrisでCSの基礎固めを大事にする

Eiichiro Iriguchi  ·  started 2026.06.20  ·  4 posts
2026.06.20 15:41

今日はHDLシミュレータでNandゲートを使ったNotゲートの実装からMux、DMuxと16bitのNot,And,Orゲートの実装までやった
Muxの実装は最初わけわかんなかったけど、Claudeにヒントをもらって、Excelに真理値表を書いたら理解できた。DMuxも最初は戸惑ったけど、真理値表を読み解いて実装したら案外行けた

2026.06.20 15:58

if文やfor文が生まれた当初は、CSの大革命期だったのかもしれない
「これ、if文があれば一瞬で解けるのに!」とか「for文があれば3行で実装できるじゃん……!」があった

2026.06.21 14:20

なんとか1章を完走。
Mux4Way16でつまづいたが、Claudeにヒントを聞いたところ「トーナメント形式と考えてみればいける」と言われてやってみたら行けた

DMux4Wayは最初以下のように実装していたんだけど、冒頭の三行がDMuxでやっていることと全く同じだということに気づいて書き換えた
【書き換え前】

Not(in=sel[1] , out=nsel1 );
And(a=in , b=nsel1 , out=neq1 );
And(a=in , b=sel[1] , out=neq2 );
DMux(in=neq1 , sel=sel[0] , a=a , b=b );
DMux(in=neq2 , sel=sel[0] , a=c , b=d );

【書き換え後】

DMux(in=in , sel=sel[1] , a=neq1 , b=neq2 );
DMux(in=neq1 , sel=sel[0] , a=a , b=b );
DMux(in=neq2 , sel=sel[0] , a=c , b=d );

DMux8Wayは「最初にDMux4Wayが使えそうだぞ?ということに気づいて一発で解けた
そのあと、「Mux8Way16ももしかして同じ要領で解けるのでは?」と思い至って、以下のように書き直した
【書き換え前】

Mux16(a=a , b=b , sel=sel[0] , out=ab );
Mux16(a=c , b=d , sel=sel[0] , out=cd );
Mux16(a=e , b=f , sel=sel[0] , out=ef );
Mux16(a=g , b=h , sel=sel[0] , out=gh );
Mux16(a=ab , b=cd , sel=sel[1] , out=abcd );
Mux16(a=ef , b=gh , sel=sel[1] , out=efgh );
Mux16(a=abcd , b=efgh , sel=sel[2] , out=out );

【書き換え後】

Mux4Way16(a=a , b=b , c=c , d=d , sel=sel[0..1] , out=abcd );
Mux4Way16(a=e , b=f , c=g , d=h , sel=sel[0..1] , out=efgh );
Mux16(a=abcd , b=efgh , sel=sel[2] , out=out );
2026.07.02 15:45

ALUの実装までやった。
outが0かの判定のところで、out=の仕様が分かってなくてめちゃくちゃ時間を食ってしまった。
out[0..7]=out[15]=で出力をスライスさせるのは覚えておこう。
あと、最上位ビットが負数であることを表現しているということをすっかり忘れていた。ここはALUの仕様周りを再読する必要がありそう。

Claudeにヒントをもらいながら実装したのが以下

    // xyが0になるかを判定
    Mux16(a=x , b=false , sel=zx , out=zeroorx );
    Mux16(a=y , b=false , sel=zy , out=zeroory );

    // xyが反転するかを判定
    Not16(in=zeroorx , out=notx );
    Mux16(a=zeroorx , b=notx , sel=nx , out=notorx );
    Not16(in=zeroory , out=noty );
    Mux16(a=zeroory , b=noty , sel=ny , out=notory );

    // AddなのかAndなのかを判定
    Add16(a=notorx , b=notory , out=addxy );
    And16(a=notorx , b= notory, out=andxy );
    Mux16(a=andxy , b=addxy , sel=f , out=result );

    // 結果を反転させるかを判定
    Not16(in=result , out=notresult );
    Mux16(a=result , b=notresult , sel=no , out=out );

    // outが0かを判定
    Mux16(a=result , b=notresult , sel=no , out[0..7]=neqout1, out[8..15]=neqout2 );
    Or8Way(in=neqout1 , out=nzr1 );
    Or8Way(in=neqout2 , out=nzr2 );
    Or(a=nzr1 , b=nzr2 , out=nzr );
    Not(in=nzr , out=zr );

    // outが0未満かを判定
    Mux16(a=result , b=notresult , sel=no , out[15]=ng );

で、「outはスライスできる」というClaudeの助言をもらってリファクタした。

    // xyが0になるかを判定
    Mux16(a=x , b=false , sel=zx , out=zeroorx );
    Mux16(a=y , b=false , sel=zy , out=zeroory );

    // xyが反転するかを判定
    Not16(in=zeroorx , out=notx );
    Mux16(a=zeroorx , b=notx , sel=nx , out=notorx );
    Not16(in=zeroory , out=noty );
    Mux16(a=zeroory , b=noty , sel=ny , out=notory );

    // AddなのかAndなのかを判定
    Add16(a=notorx , b=notory , out=addxy );
    And16(a=notorx , b= notory, out=andxy );
    Mux16(a=andxy , b=addxy , sel=f , out=result );

    // 結果を反転させるかを判定
    Not16(in=result , out=notresult );
    Mux16(a=result , b=notresult , sel=no , out=out, out[0..7]=neqout1, out[8..15]=neqout2, out[15]=ng );

    // outが0かを判定
    Or8Way(in=neqout1 , out=nzr1 );
    Or8Way(in=neqout2 , out=nzr2 );
    Or(a=nzr1 , b=nzr2 , out=nzr );
    Not(in=nzr , out=zr );