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