論理回路
論理回路の半加算器と全加算器を描きます。
まず,論理記号をパーツとして作りましょう。
名前と位置,サイズを引数とし,入力端子と出力端子の座標を戻り値にします。
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スロットにコピーして使うことができます。