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