風の迷路

移転先:http://fermiumbay13.hatenablog.com/ ここはヤフーブログ終了に伴い12/15閉鎖します

全体表示

[ リスト ]

(2019/8/2追記)
本記事の内容は新ブログに転載済みです:
https://fermiumbay13.hatenablog.com/entry/2019/04/14/180618

論理回路のシミュレーションをプログラミングで行うための支援ライブラリを作りました。
https://github.com/fermiumbay/LogicSimulator

論理計算を行うだけであれば、単に計算式を記述して答えを出させれば済みますが、
このライブラリは素子を登録してそれぞれ接続し、回路を作ることが出来るのが特徴です。
計算式に基づいて出力値が出るのではなく、出力値を得たい素子の値からたどって計算を行います。
素子を接続して実装することから、順序回路のような循環している回路も作成できます。

本ライブラリはC++用です。(C++11以降)

導入

上のリンクからLogicParts.hとLogicParts.cppをダウンロードし、
cppファイルをコンパイルするソースに入れてください。
使用するときはLogicParts.hをインクルードします。

イメージ 1

例えば上のような回路を実装する場合は次のように記述します。

#include <iostream>
using namespace std;

#include "LogicParts.h"
using namespace LogicParts;

int main() {
    auto A = Terminal();    // 端子Aの定義
    auto B = Terminal();    // 端子Bの定義
    auto C = And(Or(A, B), Nand(A, B));    // 端子Cに論理回路を接続

    A->set(0);    // 端子Aに入力値0をセット
    B->set(1);    // 端子Bに入力値1をセット

    cout << C->get() << endl;    // 端子Cの値を出力
}

最初に各端子を定義して論理回路を作ります。
変数の型は面倒なのでautoで宣言していますが、BaseParts*でもOKです。
後は端子にset関数で入力値をセットして、出力値を得たい端子のget関数を呼べばOKです。
上の例はXor回路なので、A=Bのとき0、A≠Bのとき1が返ります。

半加算器

イメージ 2

上図は半加算器HAの例です。出力が2つありますが、同様にして回路を作れます。

#include <iostream>
using namespace std;

#include "LogicParts.h"
using namespace LogicParts;

int main() {
    auto A = Terminal();    // 端子Aの定義
    auto B = Terminal();    // 端子Bの定義
    auto C = And(A, B);    // 端子CにAnd素子を接続
    auto S = Xor(A, B);    // 端子SにXor素子を接続

    A->set(0);    // 端子Aに入力値0をセット
    B->set(1);    // 端子Bに入力値1をセット

    cout << C->get() << endl;    // 端子Cの値を出力
    cout << S->get() << endl;    // 端子Sの値を出力
}

このHAの部分だけを一つの部品として、
次のように関数を作っておくと便利です。

#include <iostream>
using namespace std;

#include "LogicParts.h"
using namespace LogicParts;

// 半加算器(A, B) = (C, S)
vector<BaseParts*> HA(BaseParts* A, BaseParts* B) {
    auto C = And(A, B);    // 端子CにAnd素子を接続
    auto S = Xor(A, B);    // 端子SにXor素子を接続
    return { C, S };	// 出力端子の配列を返す
}

int main() {
    auto A = Terminal();    // 端子Aの定義
    auto B = Terminal();    // 端子Bの定義
    auto D = HA(A, B);    // 端子DにA, Bを接続したHAを接続
    auto C = D[0];    // A, Bを接続したHAの出力C
    auto S = D[1];    // A, Bを接続したHAの出力S

    A->set(0);    // 端子Aに入力値0をセット
    B->set(1);    // 端子Bに入力値1をセット

    cout << C->get() << endl;    // 端子Cの値を出力
    cout << S->get() << endl;    // 端子Sの値を出力
}

全加算器

イメージ 3

HAを接続して全加算器FAを作ります。

#include <iostream>
using namespace std;

#include "LogicParts.h"
using namespace LogicParts;

// 半加算器(A, B) = (C, S)
vector<BaseParts*> HA(BaseParts* A, BaseParts* B) {
    auto C = And(A, B);    // 端子CにAnd素子を接続
    auto S = Xor(A, B);    // 端子SにXor素子を接続
    return{ C, S };	// 出力端子の配列を返す
}

// 全加算器(A, B, prevC) = (C, S)
vector<BaseParts*> FA(BaseParts* A, BaseParts* B, BaseParts* prevC) {
    auto D = HA(A, B);    // HAの出力を端子群Dとして定義
    auto E = HA(D[1], prevC);    // HAの出力を端子群Eとして定義
    auto C = Or(D[0], E[0]);    // HAの出力とOr素子を接続して端子Cに接続
    auto S = E[1];    // HAの出力を端子Sに接続
    return{ C, S };	// 出力端子の配列を返す
}

int main() {
    auto A = Terminal();    // 端子Aの定義
    auto B = Terminal();    // 端子Bの定義
    auto prevC = Terminal();    // 端子prevCの定義
    auto C = FA(A, B, prevC)[0];    // A, Bを接続したFAの出力C
    auto S = FA(A, B, prevC)[1];    // A, Bを接続したFAの出力S

    A->set(1);    // 端子Aに入力値1をセット
    B->set(1);    // 端子Bに入力値1をセット
    prevC->set(1);    // 端子prevCに入力値1をセット

    cout << C->get() << endl;    // 端子Cの値を出力
    cout << S->get() << endl;    // 端子Sの値を出力
}

一旦部品を作ってしまえば取り扱いが楽になります。

RSフリップフロップ

イメージ 4

入力端子を循環させれば順序回路も作れます。

#include <iostream>
using namespace std;

#include "LogicParts.h"
using namespace LogicParts;

// RSフリップフロップ
vector<BaseParts*> RS_FF(BaseParts* S, BaseParts* R) {
	auto Q = Nand(Not(S), 0);    // 端子Q
	auto notQ = Nand(Not(R), Q);    // 端子notQ
	Q->input[1] = notQ;    // 端子Qの入力端子の一つにnotQをセット

	return{ Q, notQ };	// 出力端子の配列を返す
}

int main() {
	auto S = Terminal();    // 端子Sの定義
	auto R = Terminal();    // 端子Rの定義
	auto Q = RS_FF(S, R)[0];    // 出力QをA, Bを接続したHAの出力C

	S->set(0); R->set(0); cout << Q->get() << endl;    // 保持
	S->set(1); R->set(0); cout << Q->get() << endl;    // Q=1にセット
	S->set(0); R->set(0); cout << Q->get() << endl;    // 保持
	S->set(0); R->set(1); cout << Q->get() << endl;    // Q=0にセット
	S->set(0); R->set(0); cout << Q->get() << endl;    // 保持
}

notQが未定義の状態でQ = Nand(Not(S), notQ)とは出来ませんから、
上記のように、一旦notQの部分は0(未接続)としておいて、
notQを作ってからQの入力端子にnotQをセットする、という方法で接続しています。


うまいように設計してやれば、大規模な論理回路も作れそうですね!

.
検索 検索
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
フェルミウム湾
フェルミウム湾
男性 / O型
人気度
Yahoo!ブログヘルプ - ブログ人気度について

過去の記事一覧

よしもとブログランキング

もっと見る

[PR]お得情報

ふるさと納税サイト『さとふる』
実質2000円で特産品がお手元に
11/30までキャンペーン実施中!
数量限定!イオンおまとめ企画
「無料お試しクーポン」か
「値引きクーポン」が必ず当たる!
ふるさと納税サイト『さとふる』
お米、お肉などの好きなお礼品を選べる
毎日人気ランキング更新中!

その他のキャンペーン


プライバシー -  利用規約 -  メディアステートメント -  ガイドライン -  順守事項 -  ご意見・ご要望 -  ヘルプ・お問い合わせ

Copyright (C) 2019 Yahoo Japan Corporation. All Rights Reserved.

みんなの更新記事