File indexing completed on 2024-05-05 05:46:06
0001 /*************************************************************************** 0002 * Copyright (C) 2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "flipflop.h" 0012 #include "ecnode.h" 0013 #include "icndocument.h" 0014 #include "libraryitem.h" 0015 #include "logic.h" 0016 #include "node.h" 0017 #include "simulator.h" 0018 0019 #include <KLocalizedString> 0020 #include <QPainter> 0021 0022 // BEGIN class ClockedFlipFlop 0023 ClockedFlipFlop::ClockedFlipFlop(ICNDocument *icnDocument, bool newItem, const char *id) 0024 : Component(icnDocument, newItem, id) 0025 { 0026 createProperty("trig", Variant::Type::Select); 0027 property("trig")->setCaption(i18n("Trigger Edge")); 0028 QStringMap allowed; 0029 allowed["Rising"] = i18n("Rising"); 0030 allowed["Falling"] = i18n("Falling"); 0031 property("trig")->setAllowed(allowed); 0032 property("trig")->setValue("Rising"); 0033 m_edgeTrigger = Rising; 0034 } 0035 0036 void ClockedFlipFlop::dataChanged() 0037 { 0038 EdgeTrigger t = (dataString("trig") == "Rising") ? Rising : Falling; 0039 if (t == m_edgeTrigger) 0040 return; 0041 0042 m_edgeTrigger = t; 0043 initSymbolFromTrigger(); 0044 } 0045 // END class ClockedFlipFlop 0046 0047 // BEGIN class ECDFlipFlop 0048 0049 0050 void ECDFlipFlop_inputChanged(void *objV, bool state) { // Enable 0051 ECDFlipFlop *objT = static_cast<ECDFlipFlop*>(objV); 0052 objT->inputChanged(state); 0053 } 0054 void ECDFlipFlop_clockChanged(void *objV, bool state) { 0055 ECDFlipFlop *objT = static_cast<ECDFlipFlop*>(objV); 0056 objT->clockChanged(state); 0057 } 0058 void ECDFlipFlop_asyncChanged(void *objV, bool state) { 0059 ECDFlipFlop *objT = static_cast<ECDFlipFlop*>(objV); 0060 objT->asyncChanged(state); 0061 } 0062 0063 Item *ECDFlipFlop::construct(ItemDocument *itemDocument, bool newItem, const char *id) 0064 { 0065 return new ECDFlipFlop(dynamic_cast<ICNDocument *>(itemDocument), newItem, id); 0066 } 0067 0068 LibraryItem *ECDFlipFlop::libraryItem() 0069 { 0070 return new LibraryItem(QStringList(QString("ec/d_flipflop")), i18n("D Flip-Flop"), i18n("Integrated Circuits"), "ic3.png", LibraryItem::lit_component, ECDFlipFlop::construct); 0071 } 0072 0073 ECDFlipFlop::ECDFlipFlop(ICNDocument *icnDocument, bool newItem, const char *id) 0074 : ClockedFlipFlop(icnDocument, newItem, id ? id : "d_flipflop") 0075 { 0076 m_name = i18n("D-Type Flip-Flop"); 0077 0078 setSize(-32, -24, 64, 48); 0079 init2PinLeft(-8, 8); 0080 init2PinRight(-8, 8); 0081 initSymbolFromTrigger(); 0082 0083 m_prevD = false; 0084 m_pSimulator = Simulator::self(); 0085 0086 m_bPrevClock = false; 0087 m_pD = createLogicIn(m_pNNode[0]); 0088 m_pClock = createLogicIn(m_pNNode[1]); 0089 m_pQ = createLogicOut(m_pPNode[0], false); 0090 m_pQBar = createLogicOut(m_pPNode[1], false); 0091 0092 setp = createLogicIn(createPin(0, -32, 90, "set")); 0093 rstp = createLogicIn(createPin(0, 32, 270, "rst")); 0094 0095 // (The display text for D, >, Set, Rst is set in initSymbolFromTrigger 0096 addDisplayText("Q", QRect(12, -16, 20, 16), "Q"); 0097 addDisplayText("Q'", QRect(12, 0, 20, 16), "Q'"); 0098 //m_pD->setCallback(this, static_cast<CallbackPtr>(&ECDFlipFlop::inputChanged)); 0099 m_pD->setCallback2(ECDFlipFlop_inputChanged, this); 0100 //m_pClock->setCallback(this, static_cast<CallbackPtr>(&ECDFlipFlop::clockChanged)); 0101 m_pClock->setCallback2(ECDFlipFlop_clockChanged, this); 0102 //setp->setCallback(this, static_cast<CallbackPtr>(&ECDFlipFlop::asyncChanged)); 0103 setp->setCallback2(ECDFlipFlop_asyncChanged, this); 0104 //rstp->setCallback(this, static_cast<CallbackPtr>(&ECDFlipFlop::asyncChanged)); 0105 rstp->setCallback2(ECDFlipFlop_asyncChanged, this); 0106 0107 inStateChanged(false); 0108 } 0109 0110 ECDFlipFlop::~ECDFlipFlop() 0111 { 0112 //m_pD->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0113 m_pD->setCallback2(nullptr, nullptr); 0114 //m_pClock->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0115 m_pClock->setCallback2(nullptr, nullptr); 0116 //setp->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0117 setp->setCallback2(nullptr, nullptr); 0118 //rstp->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0119 rstp->setCallback2(nullptr, nullptr); 0120 } 0121 0122 void ECDFlipFlop::initSymbolFromTrigger() 0123 { 0124 int offset = (m_edgeTrigger == Rising) ? 0 : 6; 0125 0126 int w = 64 - offset; 0127 setSize(offset - 32, -24, w, 48, true); 0128 m_pNNode[0]->setLength(8 + offset); 0129 addDisplayText("D", QRect(offset - 28, -16, 20, 16), "D", true, Qt::AlignLeft); 0130 addDisplayText(">", QRect(offset - 28, 0, 20, 16), ">", true, Qt::AlignLeft); 0131 addDisplayText("Set", QRect(offset - 28, -20, w - 8, 16), "Set", true, Qt::AlignHCenter); 0132 addDisplayText("Rst", QRect(offset - 28, 4, w - 8, 16), "Rst", true, Qt::AlignHCenter); 0133 0134 updateAttachedPositioning(); 0135 } 0136 0137 void ECDFlipFlop::drawShape(QPainter &p) 0138 { 0139 Component::drawShape(p); 0140 0141 if (m_edgeTrigger == Falling) { 0142 initPainter(p); 0143 p.drawEllipse(int(x() - 32), int(y() + 5), 6, 6); 0144 deinitPainter(p); 0145 } 0146 } 0147 0148 void ECDFlipFlop::asyncChanged(bool) 0149 { 0150 bool set = setp->isHigh(); 0151 bool rst = rstp->isHigh(); 0152 if (set || rst) { 0153 m_pQ->setHigh(set); 0154 m_pQBar->setHigh(rst); 0155 } 0156 } 0157 0158 void ECDFlipFlop::inputChanged(bool newState) 0159 { 0160 if (newState == m_prevD) { 0161 // Only record the time that the input state changes 0162 return; 0163 } 0164 0165 m_prevD = newState; 0166 m_prevDChangeSimTime = m_pSimulator->time(); 0167 } 0168 0169 void ECDFlipFlop::clockChanged(bool newState) 0170 { 0171 bool set = setp->isHigh(); 0172 bool rst = rstp->isHigh(); 0173 0174 bool fallingEdge = m_bPrevClock && !newState; 0175 bool edge = (m_edgeTrigger == Falling) ? fallingEdge : !fallingEdge; 0176 0177 m_bPrevClock = newState; 0178 0179 if (set || rst) 0180 return; 0181 0182 if (edge) { 0183 // The D Flip-Flop takes the input before the edge fall/rise - not after 0184 // the edge. So see if the input state last changed before now or at 0185 // now to work out if we should take the current value of m_prevD, or 0186 // its inverse. 0187 0188 unsigned long long simTime = m_pSimulator->time(); 0189 bool d = (simTime == m_prevDChangeSimTime) ? !m_prevD : m_prevD; 0190 0191 m_pQ->setHigh(d); 0192 m_pQBar->setHigh(!d); 0193 } 0194 } 0195 0196 void ECDFlipFlop::inStateChanged(bool) 0197 { 0198 // Only called when the flipflop is created. 0199 m_pQ->setHigh(false); 0200 m_pQBar->setHigh(true); 0201 } 0202 // END class ECDFlipFlop 0203 0204 // BEGIN class ECJKFlipFlop 0205 void ECJKFlipFlop_clockChanged(void *objV, bool state) { 0206 ECJKFlipFlop *objT = static_cast<ECJKFlipFlop*>(objV); 0207 objT->clockChanged(state); 0208 } 0209 void ECJKFlipFlop_asyncChanged(void *objV, bool state) { 0210 ECJKFlipFlop *objT = static_cast<ECJKFlipFlop*>(objV); 0211 objT->asyncChanged(state); 0212 } 0213 0214 Item *ECJKFlipFlop::construct(ItemDocument *itemDocument, bool newItem, const char *id) 0215 { 0216 return new ECJKFlipFlop(dynamic_cast<ICNDocument *>(itemDocument), newItem, id); 0217 } 0218 0219 LibraryItem *ECJKFlipFlop::libraryItem() 0220 { 0221 return new LibraryItem(QStringList(QString("ec/jk_flipflop")), i18n("JK Flip-Flop"), i18n("Integrated Circuits"), "ic3.png", LibraryItem::lit_component, ECJKFlipFlop::construct); 0222 } 0223 0224 ECJKFlipFlop::ECJKFlipFlop(ICNDocument *icnDocument, bool newItem, const char *id) 0225 : ClockedFlipFlop(icnDocument, newItem, id ? id : "jk_flipflop") 0226 { 0227 m_name = i18n("JK-Type Flip-Flop"); 0228 0229 setSize(-32, -32, 64, 64); 0230 init3PinLeft(-16, 0, 16); 0231 init2PinRight(-16, 16); 0232 initSymbolFromTrigger(); 0233 0234 m_bPrevClock = false; 0235 0236 createProperty("trig", Variant::Type::Select); 0237 property("trig")->setCaption(i18n("Trigger Edge")); 0238 QStringMap allowed; 0239 allowed["Rising"] = i18n("Rising"); 0240 allowed["Falling"] = i18n("Falling"); 0241 property("trig")->setAllowed(allowed); 0242 property("trig")->setValue("Rising"); 0243 m_edgeTrigger = Rising; 0244 initSymbolFromTrigger(); 0245 0246 m_pJ = createLogicIn(m_pNNode[0]); 0247 m_pClock = createLogicIn(m_pNNode[1]); 0248 m_pK = createLogicIn(m_pNNode[2]); 0249 0250 m_pQ = createLogicOut(m_pPNode[0], false); 0251 m_pQBar = createLogicOut(m_pPNode[1], false); 0252 0253 setp = createLogicIn(createPin(0, -40, 90, "set")); 0254 rstp = createLogicIn(createPin(0, 40, 270, "rst")); 0255 0256 addDisplayText("Q", QRect(12, -24, 20, 16), "Q"); 0257 addDisplayText("Q'", QRect(12, 8, 20, 16), "Q'"); 0258 0259 //m_pClock->setCallback(this, static_cast<CallbackPtr>(&ECJKFlipFlop::clockChanged)); 0260 m_pClock->setCallback2(ECJKFlipFlop_clockChanged, this); 0261 //setp->setCallback(this, static_cast<CallbackPtr>(&ECJKFlipFlop::asyncChanged)); 0262 setp->setCallback2(ECJKFlipFlop_asyncChanged, this); 0263 //rstp->setCallback(this, static_cast<CallbackPtr>(&ECJKFlipFlop::asyncChanged)); 0264 rstp->setCallback2(ECJKFlipFlop_asyncChanged, this); 0265 0266 inStateChanged(false); 0267 } 0268 0269 ECJKFlipFlop::~ECJKFlipFlop() 0270 { 0271 //m_pClock->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0272 m_pClock->setCallback2(nullptr, nullptr); 0273 //setp->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0274 setp->setCallback2(nullptr, nullptr); 0275 //rstp->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0276 rstp->setCallback2(nullptr, nullptr); 0277 } 0278 0279 void ECJKFlipFlop::initSymbolFromTrigger() 0280 { 0281 int offset = (m_edgeTrigger == Rising) ? 0 : 6; 0282 0283 int w = 64 - offset; 0284 setSize(offset - 32, -32, w, 64, true); 0285 m_pNNode[0]->setLength(8 + offset); 0286 m_pNNode[2]->setLength(8 + offset); 0287 addDisplayText("J", QRect(offset - 28, -24, 20, 16), "J", true, Qt::AlignLeft); 0288 addDisplayText(">", QRect(offset - 28, -8, 20, 16), ">", true, Qt::AlignLeft); 0289 addDisplayText("K", QRect(offset - 28, 8, 20, 16), "K", true, Qt::AlignLeft); 0290 addDisplayText("Set", QRect(offset - 28, -28, w - 8, 16), "Set", true, Qt::AlignHCenter); 0291 addDisplayText("Rst", QRect(offset - 28, 12, w - 8, 16), "Rst", true, Qt::AlignHCenter); 0292 0293 updateAttachedPositioning(); 0294 } 0295 0296 void ECJKFlipFlop::drawShape(QPainter &p) 0297 { 0298 Component::drawShape(p); 0299 0300 if (m_edgeTrigger == Falling) { 0301 initPainter(p); 0302 p.drawEllipse(int(x() - 32), int(y() - 3), 6, 6); 0303 deinitPainter(p); 0304 } 0305 } 0306 0307 void ECJKFlipFlop::clockChanged(bool newvalue) 0308 { 0309 bool fallingEdge = (m_bPrevClock && !newvalue); 0310 bool edge = (m_edgeTrigger == Falling) ? fallingEdge : !fallingEdge; 0311 m_bPrevClock = newvalue; 0312 0313 bool j = m_pJ->isHigh(); 0314 bool k = m_pK->isHigh(); 0315 bool set = setp->isHigh(); 0316 bool rst = rstp->isHigh(); 0317 0318 if (set || rst) 0319 return; 0320 0321 // a JK flip-flop change state when clock do 1->0 0322 if (edge && (j || k)) { 0323 if (j && k) { 0324 m_pQ->setHigh(!prev_state); 0325 m_pQBar->setHigh(prev_state); 0326 prev_state = !prev_state; 0327 } else { 0328 // (J=1 && K=0) || (J=0 && K=1) 0329 m_pQ->setHigh(j); 0330 m_pQBar->setHigh(k); 0331 prev_state = j; 0332 } 0333 } 0334 } 0335 0336 void ECJKFlipFlop::asyncChanged(bool) 0337 { 0338 bool set = setp->isHigh(); 0339 bool rst = rstp->isHigh(); 0340 0341 if (set || rst) { 0342 m_pQ->setHigh(set); 0343 m_pQBar->setHigh(rst); 0344 prev_state = set; 0345 } 0346 } 0347 0348 void ECJKFlipFlop::inStateChanged(bool) 0349 { 0350 m_pQBar->setHigh(true); 0351 m_pQ->setHigh(false); 0352 prev_state = false; 0353 } 0354 // END class ECJKFlipFlop 0355 0356 // BEGIN class ECSRFlipFlop 0357 void ECSRFlipFlop_inStateChanged(void *objV, bool state) { 0358 ECSRFlipFlop *objT = static_cast<ECSRFlipFlop*>(objV); 0359 objT->inStateChanged(state); 0360 } 0361 0362 Item *ECSRFlipFlop::construct(ItemDocument *itemDocument, bool newItem, const char *id) 0363 { 0364 return new ECSRFlipFlop(dynamic_cast<ICNDocument *>(itemDocument), newItem, id); 0365 } 0366 0367 LibraryItem *ECSRFlipFlop::libraryItem() 0368 { 0369 return new LibraryItem(QStringList(QString("ec/sr_flipflop")), i18n("SR Flip-Flop"), i18n("Integrated Circuits"), "ic3.png", LibraryItem::lit_component, ECSRFlipFlop::construct); 0370 } 0371 0372 ECSRFlipFlop::ECSRFlipFlop(ICNDocument *icnDocument, bool newItem, const char *id) 0373 : Component(icnDocument, newItem, id ? id : "sr_flipflop") 0374 { 0375 m_name = i18n("SR Flip-Flop"); 0376 0377 setSize(-24, -24, 48, 48); 0378 0379 init2PinLeft(-8, 8); 0380 init2PinRight(-8, 8); 0381 0382 m_pS = createLogicIn(m_pNNode[0]); 0383 m_pR = createLogicIn(m_pNNode[1]); 0384 m_pQ = createLogicOut(m_pPNode[0], true); 0385 m_pQBar = createLogicOut(m_pPNode[1], false); 0386 0387 old_q1 = true; 0388 old_q2 = false; 0389 m_pQ->setHigh(old_q1); 0390 m_pQBar->setHigh(old_q2); 0391 0392 addDisplayText("S", QRect(-24, -16, 20, 16), "S"); 0393 addDisplayText("R", QRect(-24, 0, 20, 16), "R"); 0394 addDisplayText("Q", QRect(4, -16, 20, 16), "Q"); 0395 addDisplayText("Q'", QRect(4, 0, 20, 16), "Q'"); 0396 0397 //m_pS->setCallback(this, static_cast<CallbackPtr>(&ECSRFlipFlop::inStateChanged)); 0398 m_pS->setCallback2(ECSRFlipFlop_inStateChanged, this); 0399 //m_pR->setCallback(this, static_cast<CallbackPtr>(&ECSRFlipFlop::inStateChanged)); 0400 m_pR->setCallback2(ECSRFlipFlop_inStateChanged, this); 0401 //m_pQ->setCallback(this, static_cast<CallbackPtr>(&ECSRFlipFlop::inStateChanged)); 0402 m_pQ->setCallback2(ECSRFlipFlop_inStateChanged, this); 0403 //m_pQBar->setCallback(this, static_cast<CallbackPtr>(&ECSRFlipFlop::inStateChanged)); 0404 m_pQBar->setCallback2(ECSRFlipFlop_inStateChanged, this); 0405 } 0406 0407 ECSRFlipFlop::~ECSRFlipFlop() 0408 { 0409 //m_pS->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0410 m_pS->setCallback2(nullptr, nullptr); 0411 //m_pR->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0412 m_pR->setCallback2(nullptr, nullptr); 0413 //m_pQ->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0414 m_pQ->setCallback2(nullptr, nullptr); 0415 //m_pQBar->setCallback(nullptr, static_cast<CallbackPtr>(nullptr)); 0416 m_pQBar->setCallback2(nullptr, nullptr); 0417 } 0418 0419 void ECSRFlipFlop::inStateChanged(bool) 0420 { 0421 // Q = v_q1, Q-bar = v_q2 0422 bool new_q1 = false; 0423 bool new_q2 = false; 0424 0425 bool s = m_pS->isHigh(); 0426 bool r = m_pR->isHigh(); 0427 bool q1 = m_pQ->isHigh(); 0428 bool q2 = m_pQBar->isHigh(); 0429 0430 // Easy ones to do :-) 0431 if (!q1) 0432 new_q2 = true; 0433 if (!q2) 0434 new_q1 = true; 0435 0436 if (q1 && q2) { 0437 if (s && !r) { 0438 new_q1 = true; 0439 new_q2 = false; 0440 } else if (!s && r) { 0441 new_q1 = false; 0442 new_q2 = true; 0443 } else if (s && r) { 0444 new_q1 = old_q1; 0445 new_q2 = old_q2; 0446 } else if (!s && !r) { 0447 new_q1 = false; 0448 new_q2 = false; 0449 } 0450 } else if (q1 && !q2) { 0451 // Note: We only need to set the value of v_q2 0452 if (r && !s) 0453 new_q2 = true; 0454 else 0455 new_q2 = false; 0456 } else if (!q1 && q2) { 0457 // Note: We only need to set the value of v_q1 0458 if (s && !r) 0459 new_q1 = true; 0460 else 0461 new_q1 = false; 0462 } 0463 0464 old_q1 = new_q1; 0465 old_q2 = new_q2; 0466 0467 m_pQ->setHigh(new_q1); 0468 m_pQBar->setHigh(new_q2); 0469 } 0470 // END class ECSRFlipFlop