論理回路

論理回路の半加算器と全加算器を描きます。

まず,論理記号をパーツとして作りましょう。

名前と位置,サイズを引数とし,入力端子と出力端子の座標を戻り値にします。

AND 回路の元

AND回路の元になるものです。出力端子を描かずにおきます。そうすれば,これを元に,ANDもNANDも描けます。

論理回路の記号は MIL と呼ばれますので,これを関数名の先頭につけましょう。

MILand0(name,pt,sz):=(

regional(p1,p2,p3,p4,p5,p6);

p1=pt+[1.55*sz,0];

p2=p1+[0,-2*sz];

p3=pt+[0,-2*sz];

p4=pt+[-sz/2,-sz/2];

p5=pt+[-sz/2,-3*sz/2];

p6=p1+[0.95*sz,-sz];

Bowdata("and1"+name,[p2,p1],[4.8]);

Listplot("and1"+name,[p1,pt,p3,p2]);

Listplot("and2"+name,[p4,p4+[sz/2,0]]);

Listplot("and3"+name,[p5,p5+[sz/2,0]]);

[p4,p5,p6];

);

pt は点の名前(下図左)または座標(下図右)です。

これを左上の位置として,p1〜p6 が図の位置です。

p1の1.55*sz が横の長さを決定しますので,もう少し横長がよければ 2.05*sz などとするとよいでしょう。

1.55 や 0.95 と半端な値なのは,Bowdata() で描いた弧の位置に関係します。ちょっとずらしておくと,p6の位置がぐあいよくなるのです。

戻り値は,端子の位置を [p4,p5,p6] とリストにして返しています。


OR回路の元

同様に,OR回路の元です。

MILor0(name,pt,sz):=(

regional(p1,p2,p3,p4,p5,p6,p7,p8);

p1=pt+[0.7*sz,0];

p2=pt+[2.5*sz,-sz];

p3=p1+[0,-2*sz];

p4=pt+[0,-2*sz];

p5=pt+[0.3*sz,-sz/2];

p6=pt+[-sz/2,-sz/2];

p7=pt+[0.3*sz,-3*sz/2];

p8=pt+[-sz/2,-3*sz/2];

Bowdata("or1"+name,[p2,p1]);

Bowdata("or2"+name,[p3,p2]);

Bowdata("or3"+name,[p4,pt],[2]);

Listplot("or1"+name,[pt,p1]);

Listplot("or2"+name,[p3,p4]);

Listplot("or3"+name,[p5,p6]);

Listplot("or4"+name,[p7,p8]);

[p6,p8,p2];

);

AND回路

AND回路の元を描いて,出力端子をつけます。

MILand(name,pt,sz):=(

regional(term,p2);

term=MILand0(name,pt,sz);

p2=term_3;

Listplot("and4"+name,[p2,p2+[sz/2,0]]);

[term_1,term_2,p2+[sz/2,0]];

);

Listplot() の名前を "and4" としているのは,"and1" から "and3" までをMILand0() の中で使っているからです。

ここで,サイズ指定はほとんど不要かもしれません。

というのは,Cinderellaの画面のスケールそのものが簡単に変えられるからです。

そこで,サイズ指定を省いたものも定義しておきましょう。

MILand(name,pt):=MILand(name,pt,1);

OR回路

OR回路の元を描いて,出力端子をつけます。AND回路とほとんど同じです。

MILor(name,pt):=MILor(name,pt,1);

MILor(name,pt,sz):=(

regional(term,p2);

term=MILor0(name,pt,sz);

p2=term_3;

Listplot("or5"+name,[p2,p2+[sz/2,0]]);

[term_1,term_2,p2+[sz/2,0]];

);

XOR回路

OR回路の元を描いて,左側にもうひとつ弧を描きます。

MILxor(name,pt):=MILxor(name,pt,1);

MILxor(name,pt,sz):=(

regional(term,p1,p2);

term=MILor0("xor"+name,pt,sz);

p1=pt-[0.3*sz,0];

p2=p1-[0,2*sz];

p3=term_3;

Bowdata(name+"xor",[p2,p1],[2]);

Listplot("xor5"+name,[p3,p3+[sz/2,0]]);

[term_1,term_2,p3+[sz/2,0]];

);

ここまでで,AND,OR,XOR を描いてみましょう。

MILand("1",[0,1],1);

MILor("1",[4,1],1);

MILxor("1",[8,1],1);

NAND回路

このあとは NOT系の回路です。出力側に小円がつきます。まずこれを描く MILcircle() を定義しておきます。

MILcircle(name,pt,sz):=(

regional(center);

center=pt+[sz*0.15,0];

Circledata("1"+name,[center,pt]);

);

出力側の座標を pt として引数に渡せば,半径 0.15 の円を描きます。円の大きさは sz*0.15 のところで変えられますが,このあとの関数で出力端子を描くときに,円の大きさが関係します。現在は直径 0.3 です。

NAND回路を AND回路の元と小円を使って描きます。

MILnand(name,pt):=MILnand(name,pt,1);

MILnand(name,pt,sz):=(

regional(term,p2);

term=MILand0(name+"n",pt,sz);

p2=term_3;

p3=p2+[0.3*sz,0];

MILcircle("nandc"+name,p2,sz);

Listplot("nand5"+name,[p3,p3+[0.2*sz,0]]);

[term_1,term_2,p3+[0.2*sz,0]];

);

p3を決める式の 0.3 が小円の直径です。

NOR回路

NAND と同様に描きます。

MILnor(name,pt):=MILnor(name,pt,1);

MILnor(name,pt,sz):=(

regional(term,p2);

term=MILor0("nor"+name,pt,sz);

p2=term_3;

p3=p2+[0.3*sz,0];

MILcircle("norc"+name,p2,sz);

Listplot("nor5"+name,[p3,p3+[0.2*sz,0]]);

[term_1,term_2,p3+[0.2*sz,0]];

);

NOT回路

三角形を描き,MILcircle() で小円を描きます。出力端子も描きます。

MILnot(name,pt):=MILnot(name,pt,1);

MILnot(name,pt,sz):=(

regional(p1,p2,p3);

p1=pt+[2*sz,-sz];

p2=pt+[0,-2*sz];

p3=pt+[-sz/2,-sz];

Listplot("not"+name,[pt,p1,p2,pt]);

MILcircle("not"+name,p1,sz);

Listplot("not2"+name,[p3,p3+[sz/2,0]]);

Listplot("not3"+name,[p1+[0.3*sz,0],p1+[sz,0]]);

[p3,p3,p1+[0.3*sz,0]];

);

6つの図を並べてみましょう。方眼を描いて,入力端子,出力端子の位置がどうなっているか確認します。

MILand("1",[0,4]);

MILor("1",[4,4]);

MILxor("1",[8,4]);

MILnand("1",[0,1]);

MILnor("1",[4,1]);

MILnot("1",[8,1]);

半加算器を描く

Cinderellaの作図機能を利用して半加算器を描きます。

まず,おおよその位置に,記号を描くための点A,B,C,D を作図します。

スクリプトは

MILand("1",A);

MILor("1",B);

MILnot("1",C);

MILand("2",D);

配置がよければ,「線分を加える」ツールで線を引いていきます。青の線が描いた線です。

これでよければ,Listplot() で出力用の線を引きます。

Listplot([E,F]);

Listplot([G,H]);

Listplot([K,L,M]);

Listplot([S,R,Q,P,O,N]);

Listplot([T,U]);

Listplot([X,Y]);

Listplot([Z,P0]);

Listplot([V,W]);

出力側に,Carry と Sum を描きます。Sum の端子のところには点がありません。

このために,戻り値を用意しているのですが,今はUの位置から簡単に求められますので,それを使います。

Letter([U,"e2","Carry",U-[0,2.5],"e2","Sum"]);

最後に,全体のサイズを調整しておきます。

Setunitlen("8mm");

Texに書き出して確認しましょう。

結局,それぞれの関数の戻り値(入力端子,出力端子の座標)は使いませんでした。

引数も座標でなく点の名前でできました。

全加算器を描く

全加算器を描きます。パーツは5つになります。半加算器の図を書き換えたので,アルファベット順がちょっと変ですが,問題にはなりません。

スクリプトは

MILand("1",A);

MILxor("1",B);

MILand("2",C);

MILxor("2",D);

MILor("2",N);

Setpt(6);

Pointdata("1",[K,O,P7,P6]);

Listplot([E,F]);

Listplot([R,S]);

Listplot([K,L,M]);

Listplot([O,Q,U]);

Listplot([T,X,Y,Z]);

Listplot([P10,P11]);

Listplot([V,W]);

Listplot([P7,P8,P9]);

Listplot([G,H]);

Listplot([P4,P5,P6]);

Listplot([P0,P1,P2,P3]);

Listplot([P10,P11]);

Listplot([P12,P13]);

Fontsize("Large");

Letter([E,"w2","$a_n$",R,"w2","$b_n$",G,"w3","$c_{n-1}$",P11,"e","$c_n$",P13,"e","$s_n$"]);

Setunitlen("6mm");

なお,Tikzで描く方法が,「Latexで論理回路(1)」(MadChemiker) にありますので参考にしてください。

以上をまとめたものを MILparts.txt として下からダウンロードできます。

テキストファイルですので,Initializaitonスロットにコピーして使うことができます。