Skip to content

Commit 7276e05

Browse files
author
Bowen Fu
committed
Finish circuit.
1 parent 84089bf commit 7276e05

File tree

1 file changed

+228
-0
lines changed

1 file changed

+228
-0
lines changed

circuit.cpp

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#include <memory>
2+
#include <cstdlib>
3+
#include <functional>
4+
#include <vector>
5+
#include <string>
6+
#include <iostream>
7+
#include <queue>
8+
#include <map>
9+
10+
class Wire
11+
{
12+
public:
13+
auto getSignal() const
14+
{
15+
return mValue;
16+
}
17+
void setSignal(bool newValue)
18+
{
19+
if (mValue == newValue)
20+
{
21+
return;
22+
}
23+
mValue = newValue;
24+
for (auto const& action : mActions)
25+
{
26+
action();
27+
}
28+
}
29+
void addAction(std::function<void()> func)
30+
{
31+
func();
32+
mActions.push_back(func);
33+
}
34+
private:
35+
bool mValue{};
36+
std::vector<std::function<void()>> mActions;
37+
};
38+
39+
using WirePtr = std::shared_ptr<Wire>;
40+
41+
auto makeWire()
42+
{
43+
return std::make_shared<Wire>();
44+
}
45+
46+
auto afterDelay(int32_t delay, std::function<void()> action) -> std::function<void()>;
47+
48+
void orGate(WirePtr in1, WirePtr in2, WirePtr out)
49+
{
50+
auto const action = [out = std::move(out), in1, in2]{
51+
auto const newValue = in1->getSignal() || in2->getSignal();
52+
out->setSignal(newValue);
53+
};
54+
auto const orGateDelay = 5;
55+
auto const delayedAction = afterDelay(orGateDelay, action);
56+
in1->addAction(delayedAction);
57+
in2->addAction(delayedAction);
58+
}
59+
60+
void andGate(WirePtr in1, WirePtr in2, WirePtr out)
61+
{
62+
auto const action = [out = std::move(out), in1, in2]{
63+
auto const newValue = in1->getSignal() && in2->getSignal();
64+
out->setSignal(newValue);
65+
};
66+
auto const andGateDelay = 3;
67+
auto const delayedAction = afterDelay(andGateDelay, action);
68+
in1->addAction(delayedAction);
69+
in2->addAction(delayedAction);
70+
}
71+
72+
void inverter(WirePtr in, WirePtr out)
73+
{
74+
auto action = [in, out = std::move(out)]
75+
{
76+
auto newValue = !(in->getSignal());
77+
out->setSignal(newValue);
78+
};
79+
auto const inverterDelay = 2;
80+
in->addAction(afterDelay(inverterDelay, action));
81+
}
82+
83+
auto halfAdder(WirePtr a, WirePtr b, WirePtr s, WirePtr c)
84+
{
85+
auto d = makeWire();
86+
auto e = makeWire();
87+
orGate(a, b, d);
88+
andGate(a, b, c);
89+
inverter(c, e);
90+
andGate(d, e, s);
91+
}
92+
93+
auto fullAdder(WirePtr a, WirePtr b, WirePtr cIn, WirePtr sum, WirePtr cOut)
94+
{
95+
auto s = makeWire();
96+
auto c1 = makeWire();
97+
auto c2 = makeWire();
98+
halfAdder(b, cIn, s, c1);
99+
halfAdder(a, s, sum, c2);
100+
orGate(c1, c2, cOut);
101+
}
102+
103+
auto adder(std::vector<WirePtr> A, std::vector<WirePtr> B, std::vector<WirePtr> S, WirePtr C)
104+
{
105+
assert(A.size() == B.size());
106+
assert(A.size() == S.size());
107+
auto Cin = makeWire();
108+
for (size_t i = 0; i < A.size() - 1; ++i)
109+
{
110+
auto Cout = makeWire();
111+
fullAdder(A[i], B[i], Cin, S[i], Cout);
112+
Cin = Cout;
113+
}
114+
fullAdder(A.back(), B.back(), Cin, S.back(), C);
115+
}
116+
117+
class Agenda
118+
{
119+
private:
120+
std::map<int32_t, std::queue<std::function<void()>>> mItems{};
121+
int32_t mTime{};
122+
Agenda() = default;
123+
public:
124+
static Agenda& instance()
125+
{
126+
static Agenda theAgenda;
127+
return theAgenda;
128+
}
129+
bool empty() const
130+
{
131+
return mItems.empty();
132+
}
133+
auto pop()
134+
{
135+
auto& first = mItems.begin()->second;
136+
auto result = first.front();
137+
mTime = mItems.begin()->first;
138+
first.pop();
139+
if (first.empty())
140+
{
141+
mItems.erase(mItems.begin());
142+
}
143+
return result;
144+
}
145+
auto push(int32_t time, std::function<void()> action)
146+
{
147+
mItems[time].push(action);
148+
return action;
149+
}
150+
auto currentTime() const
151+
{
152+
return mTime;
153+
}
154+
};
155+
156+
auto afterDelay(int32_t delay, std::function<void()> action) -> std::function<void()>
157+
{
158+
return [=]
159+
{
160+
auto &theAgenda = Agenda::instance();
161+
theAgenda.push(theAgenda.currentTime() + delay, action);
162+
};
163+
}
164+
165+
auto propagate()
166+
{
167+
auto& theAgenda = Agenda::instance();
168+
if (theAgenda.empty())
169+
{
170+
return;
171+
}
172+
auto firstItem = theAgenda.pop();
173+
firstItem();
174+
propagate();
175+
}
176+
177+
void probe(std::string const& name, WirePtr wire)
178+
{
179+
auto const action = [=]
180+
{
181+
std::cout << name << " "
182+
<< Agenda::instance().currentTime()
183+
<< " New-value = "
184+
<< wire->getSignal() << std::endl;
185+
};
186+
wire->addAction(action);
187+
}
188+
189+
int32_t main()
190+
{
191+
auto input1 = makeWire();
192+
auto input2 = makeWire();
193+
auto sum = makeWire();
194+
auto carry = makeWire();
195+
// probe("input1", input1);
196+
// probe("input2", input2);
197+
probe("sum", sum);
198+
probe("carry", carry);
199+
//sum 0 New-value = 0
200+
// carry 0 New-value = 0
201+
202+
halfAdder(input1, input2, sum, carry);
203+
input1->setSignal(1);
204+
propagate();
205+
// sum 5 New-value = 1
206+
input2->setSignal(1);
207+
propagate();
208+
// carry 11 New-value = 1
209+
// sum 16 New-value = 0
210+
211+
//=== 2 bit adder
212+
auto a0 = makeWire();
213+
auto a1 = makeWire();
214+
auto b0 = makeWire();
215+
auto b1 = makeWire();
216+
auto s0 = makeWire();
217+
auto s1 = makeWire();
218+
auto c = makeWire();
219+
adder({a0, a1}, {b0, b1}, {s0, s1}, c);
220+
a0->setSignal(1);
221+
a1->setSignal(1);
222+
b1->setSignal(1);
223+
propagate();
224+
assert(s0->getSignal() == 1);
225+
assert(s1->getSignal() == 0);
226+
assert(c->getSignal() == 1);
227+
return 0;
228+
}

0 commit comments

Comments
 (0)