Skip to content

Commit ac40518

Browse files
committed
Implemented JK master-slave flip-flops + preparations for v0.9.8 release
1 parent dfe8635 commit ac40518

File tree

12 files changed

+302
-8
lines changed

12 files changed

+302
-8
lines changed

Common.pri

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ HEADERS += \
88
$$PWD/Components/ComplexLogic/FullAdder.h \
99
$$PWD/Components/ComplexLogic/HalfAdder.h \
1010
$$PWD/Components/ComplexLogic/JKFlipFlop.h \
11+
$$PWD/Components/ComplexLogic/JkMsFlipFlop.h \
1112
$$PWD/Components/ComplexLogic/LogicCells/LogicCounterCell.h \
1213
$$PWD/Components/ComplexLogic/LogicCells/LogicDMsFlipFlopCell.h \
1314
$$PWD/Components/ComplexLogic/LogicCells/LogicDecoderCell.h \
@@ -16,6 +17,7 @@ HEADERS += \
1617
$$PWD/Components/ComplexLogic/LogicCells/LogicFullAdderCell.h \
1718
$$PWD/Components/ComplexLogic/LogicCells/LogicHalfAdderCell.h \
1819
$$PWD/Components/ComplexLogic/LogicCells/LogicJKFlipFlopCell.h \
20+
$$PWD/Components/ComplexLogic/LogicCells/LogicJkMsFlipFlopCell.h \
1921
$$PWD/Components/ComplexLogic/LogicCells/LogicMultiplexerCell.h \
2022
$$PWD/Components/ComplexLogic/LogicCells/LogicRsClockedFlipFlopCell.h \
2123
$$PWD/Components/ComplexLogic/LogicCells/LogicRsMsFlipFlopCell.h \
@@ -87,6 +89,7 @@ SOURCES += \
8789
$$PWD/Components/ComplexLogic/FullAdder.cpp \
8890
$$PWD/Components/ComplexLogic/HalfAdder.cpp \
8991
$$PWD/Components/ComplexLogic/JKFlipFlop.cpp \
92+
$$PWD/Components/ComplexLogic/JkMsFlipFlop.cpp \
9093
$$PWD/Components/ComplexLogic/LogicCells/LogicCounterCell.cpp \
9194
$$PWD/Components/ComplexLogic/LogicCells/LogicDMsFlipFlopCell.cpp \
9295
$$PWD/Components/ComplexLogic/LogicCells/LogicDecoderCell.cpp \
@@ -95,6 +98,7 @@ SOURCES += \
9598
$$PWD/Components/ComplexLogic/LogicCells/LogicFullAdderCell.cpp \
9699
$$PWD/Components/ComplexLogic/LogicCells/LogicHalfAdderCell.cpp \
97100
$$PWD/Components/ComplexLogic/LogicCells/LogicJKFlipFlopCell.cpp \
101+
$$PWD/Components/ComplexLogic/LogicCells/LogicJkMsFlipFlopCell.cpp \
98102
$$PWD/Components/ComplexLogic/LogicCells/LogicMultiplexerCell.cpp \
99103
$$PWD/Components/ComplexLogic/LogicCells/LogicRsClockedFlipFlopCell.cpp \
100104
$$PWD/Components/ComplexLogic/LogicCells/LogicRsMsFlipFlopCell.cpp \

Components/ComplexLogic/DMsFlipFlop.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,5 @@ QJsonObject DMasterSlaveFlipFlop::GetJson() const
7575

7676
SwVersion DMasterSlaveFlipFlop::GetMinVersion(void) const
7777
{
78-
return SwVersion(0, 9, 7);
78+
return SwVersion(0, 9, 8);
7979
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include "JkMsFlipFlop.h"
2+
#include "LogicCells/LogicJkMsFlipFlopCell.h"
3+
4+
JkMasterSlaveFlipFlop::JkMasterSlaveFlipFlop(const CoreLogic* pCoreLogic, Direction pDirection):
5+
AbstractComplexLogic(pCoreLogic, std::make_shared<LogicJkMsFlipFlopCell>(), 3, 2, pDirection)
6+
{
7+
mComponentText = components::complex_logic::JK_MS_FLIPFLOP_TEXT;
8+
mInputLabels = {"J", ">", "K"};
9+
mOutputLabels = {"Q", ""};
10+
11+
mDescriptionFontSize = 10;
12+
}
13+
14+
JkMasterSlaveFlipFlop::JkMasterSlaveFlipFlop(const JkMasterSlaveFlipFlop& pObj, const CoreLogic* pCoreLogic):
15+
JkMasterSlaveFlipFlop(pCoreLogic, pObj.mDirection)
16+
{
17+
mLogicCell->SetInputInversions(pObj.mLogicCell->GetInputInversions());
18+
mLogicCell->SetOutputInversions(pObj.mLogicCell->GetOutputInversions());
19+
};
20+
21+
JkMasterSlaveFlipFlop::JkMasterSlaveFlipFlop(const CoreLogic* pCoreLogic, const QJsonObject& pJson):
22+
JkMasterSlaveFlipFlop(pCoreLogic, static_cast<Direction>(pJson["dir"].toInt()))
23+
{
24+
setPos(SnapToGrid(QPointF(pJson["x"].toInt(), pJson["y"].toInt())));
25+
26+
std::vector<bool> ininv, outinv;
27+
auto ininvArray = pJson["ininv"].toArray();
28+
for (const auto& inv : ininvArray)
29+
{
30+
ininv.push_back(inv.toBool());
31+
}
32+
GetLogicCell()->SetInputInversions(ininv);
33+
34+
auto outinvArray = pJson["outinv"].toArray();
35+
for (const auto& inv : outinvArray)
36+
{
37+
outinv.push_back(inv.toBool());
38+
}
39+
GetLogicCell()->SetOutputInversions(outinv);
40+
}
41+
42+
IBaseComponent* JkMasterSlaveFlipFlop::CloneBaseComponent(const CoreLogic* pCoreLogic) const
43+
{
44+
return new JkMasterSlaveFlipFlop(*this, pCoreLogic);
45+
}
46+
47+
QJsonObject JkMasterSlaveFlipFlop::GetJson() const
48+
{
49+
QJsonObject json;
50+
51+
json["type"] = file::ComponentId::JK_MS_FLIPFLOP;
52+
json["x"] = x();
53+
json["y"] = y();
54+
json["dir"] = static_cast<int32_t>(mDirection);
55+
{
56+
QJsonArray ininv, outinv;
57+
58+
for(const bool& inv : mLogicCell->GetInputInversions())
59+
{
60+
ininv.append(inv);
61+
}
62+
63+
json["ininv"] = ininv;
64+
65+
for(const bool& inv : mLogicCell->GetOutputInversions())
66+
{
67+
outinv.append(inv);
68+
}
69+
70+
json["outinv"] = outinv;
71+
}
72+
73+
return json;
74+
}
75+
76+
SwVersion JkMasterSlaveFlipFlop::GetMinVersion(void) const
77+
{
78+
return SwVersion(0, 9, 8);
79+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#ifndef JKMSFLIPFLOP_H
2+
#define JKMSFLIPFLOP_H
3+
4+
#include "AbstractComplexLogic.h"
5+
6+
///
7+
/// \brief The JkMasterSlaveFlipFlop class represents an JK master-slave flip-flop
8+
///
9+
class JkMasterSlaveFlipFlop : public AbstractComplexLogic
10+
{
11+
Q_OBJECT
12+
public:
13+
/// \brief Constructor for JkMasterSlaveFlipFlop
14+
/// \param pCoreLogic: Pointer to the core logic, used to connect the component's signals and slots
15+
/// \param pDirection: The direction of the component
16+
JkMasterSlaveFlipFlop(const CoreLogic* pCoreLogic, Direction pDirection);
17+
18+
/// \brief Copy constructor for JkMasterSlaveFlipFlop
19+
/// \param pObj: The object to be copied
20+
/// \param pCoreLogic: Pointer to the core logic
21+
JkMasterSlaveFlipFlop(const JkMasterSlaveFlipFlop& pObj, const CoreLogic* pCoreLogic);
22+
23+
/// \brief Constructor for loading from JSON
24+
/// \param pCoreLogic: Pointer to the core logic, used to connect the component's signals and slots
25+
/// \param pJson: The JSON object to load the component's data from
26+
JkMasterSlaveFlipFlop(const CoreLogic* pCoreLogic, const QJsonObject& pJson);
27+
28+
/// \brief Clone function for the component
29+
/// \param pCoreLogic: Pointer to the core logic, used to connect the component's signals and slots
30+
/// \return A pointer to the new component
31+
IBaseComponent* CloneBaseComponent(const CoreLogic* pCoreLogic) const override;
32+
33+
/// \brief Saves the dats of this component to the given JSON object
34+
/// \return The JSON object with the component data
35+
QJsonObject GetJson(void) const override;
36+
37+
/// \brief Gets the minimum version compatible with this component
38+
/// \return the minimum version
39+
SwVersion GetMinVersion(void) const override;
40+
};
41+
42+
#endif // JKMSFLIPFLOP_H
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#include "LogicJkMsFlipFlopCell.h"
2+
3+
LogicJkMsFlipFlopCell::LogicJkMsFlipFlopCell():
4+
LogicBaseCell(3, 2),
5+
mOutputStates(2, LogicState::LOW),
6+
mPrevInputStates(3, LogicState::LOW),
7+
mInternalState(LogicState::LOW),
8+
mStateChanged(true)
9+
{}
10+
11+
void LogicJkMsFlipFlopCell::LogicFunction()
12+
{
13+
if (mPrevInputStates[1] == LogicState::LOW && mInputStates[1] == LogicState::HIGH) // rising edge
14+
{
15+
// read in state
16+
if (mPrevInputStates[0] == LogicState::HIGH && mPrevInputStates[2] == LogicState::HIGH) // both => toggle
17+
{
18+
if (mInternalState == LogicState::LOW)
19+
{
20+
mInternalState = LogicState::HIGH;
21+
}
22+
else
23+
{
24+
mInternalState = LogicState::LOW;
25+
}
26+
}
27+
else if (mPrevInputStates[0] == LogicState::HIGH && mPrevInputStates[2] == LogicState::LOW) // J => pull up
28+
{
29+
mInternalState = LogicState::HIGH;
30+
}
31+
else if (mPrevInputStates[0] == LogicState::LOW && mPrevInputStates[2] == LogicState::HIGH) // K => pull down
32+
{
33+
mInternalState = LogicState::LOW;
34+
}
35+
36+
}
37+
else if (mPrevInputStates[1] == LogicState::HIGH && mInputStates[1] == LogicState::LOW) // falling edge
38+
{
39+
mOutputStates[0] = mInternalState;
40+
mOutputStates[1] = ((mOutputStates[0] == LogicState::HIGH) ? LogicState::LOW : LogicState::HIGH);
41+
}
42+
43+
if (mPrevInputStates[1] != mInputStates[1]) // Trigger repaint on every clock change
44+
{
45+
mStateChanged = true;
46+
}
47+
48+
mPrevInputStates = mInputStates;
49+
}
50+
51+
LogicState LogicJkMsFlipFlopCell::GetOutputState(uint32_t pOutput) const
52+
{
53+
Q_ASSERT(pOutput <= 1);
54+
if (mOutputInverted[pOutput] && mIsActive)
55+
{
56+
return InvertState(mOutputStates[pOutput]);
57+
}
58+
else
59+
{
60+
return mOutputStates[pOutput];
61+
}
62+
}
63+
64+
void LogicJkMsFlipFlopCell::OnSimulationAdvance()
65+
{
66+
AdvanceUpdateTime();
67+
68+
if (mStateChanged)
69+
{
70+
mStateChanged = false;
71+
NotifySuccessor(0, mOutputStates[0]);
72+
NotifySuccessor(1, mOutputStates[1]);
73+
74+
emit StateChangedSignal();
75+
}
76+
}
77+
78+
void LogicJkMsFlipFlopCell::InputReady(uint32_t pInput, LogicState pState)
79+
{
80+
if (mInputStates[pInput] != pState)
81+
{
82+
emit StateChangedSignal(); // to trigger immediate update of the component
83+
}
84+
LogicBaseCell::InputReady(pInput, pState);
85+
}
86+
87+
void LogicJkMsFlipFlopCell::OnWakeUp()
88+
{
89+
mInputStates = std::vector<LogicState>(mInputStates.size(), LogicState::LOW);
90+
91+
for (size_t i = 0; i < mInputStates.size(); i++)
92+
{
93+
mInputStates[i] = mInputInverted[i] ? LogicState::HIGH : LogicState::LOW;
94+
}
95+
96+
mPrevInputStates = std::vector<LogicState>(mInputStates.size(), LogicState::LOW);
97+
98+
mOutputStates[0] = LogicState::LOW;
99+
mOutputStates[1] = LogicState::HIGH;
100+
mNextUpdateTime = UpdateTime::NOW;
101+
102+
mStateChanged = true; // Successors should be notified about wake up
103+
mIsActive = true;
104+
emit StateChangedSignal();
105+
}
106+
107+
void LogicJkMsFlipFlopCell::OnShutdown()
108+
{
109+
mOutputCells = std::vector<std::pair<std::shared_ptr<LogicBaseCell>, uint32_t>>(mOutputCells.size(), std::make_pair(nullptr, 0));
110+
mInputStates = std::vector<LogicState>(mInputStates.size(), LogicState::LOW);
111+
mOutputStates = std::vector<LogicState>(mInputStates.size(), LogicState::LOW);
112+
mIsActive = false;
113+
emit StateChangedSignal();
114+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef LOGICJKMSFLIPFLOPCELL_H
2+
#define LOGICJKMSFLIPFLOPCELL_H
3+
4+
#include "Components/LogicBaseCell.h"
5+
6+
///
7+
/// \brief Logic Cell class for the JK master-slave Flip-Flop
8+
///
9+
class LogicJkMsFlipFlopCell : public LogicBaseCell
10+
{
11+
Q_OBJECT
12+
public:
13+
/// \brief Constructor for the JK master-slave flip-flop logic cell
14+
LogicJkMsFlipFlopCell(void);
15+
16+
/// \brief The logic function that determines the output states based on the inputs
17+
void LogicFunction(void) override;
18+
19+
/// \brief Getter for the current output state number pOutput of this cell
20+
/// \param pOutput: The number of the output to retreive
21+
/// \return The logic state of this cell's output number pOutput
22+
LogicState GetOutputState(uint32_t pOutput = 0) const override;
23+
24+
/// \brief Sets input number pInput to the new state pState
25+
/// \param pInput: The number of the changed input
26+
/// \param pState: The new state of the input
27+
void InputReady(uint32_t pInput, LogicState pState) override;
28+
29+
public slots:
30+
/// \brief Advances the simulation of this cell by one logic tick
31+
void OnSimulationAdvance(void) override;
32+
33+
/// \brief Sets the in- and outputs low for edit mode and triggers a component repaint
34+
void OnShutdown(void) override;
35+
36+
/// \brief Initializes the logic cell's states and triggers a component repaint
37+
void OnWakeUp(void) override;
38+
39+
protected:
40+
std::vector<LogicState> mOutputStates;
41+
std::vector<LogicState> mPrevInputStates;
42+
LogicState mInternalState;
43+
44+
bool mStateChanged;
45+
};
46+
47+
#endif // LOGICJKMSFLIPFLOPCELL_H

Configuration.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ static constexpr auto T_FLIPFLOP_TEXT = "TF";
216216
static constexpr auto JK_FLIPFLOP_TEXT = "JK";
217217
static constexpr auto RS_MS_FLIPFLOP_TEXT = "RS-MS";
218218
static constexpr auto D_MS_FLIPFLOP_TEXT = "FF-MS";
219+
static constexpr auto JK_MS_FLIPFLOP_TEXT = "JK-MS";
219220
static constexpr auto MULTIPLEXER_TEXT = "MUX";
220221
static constexpr auto DEMULTIPLEXER_TEXT = "DEMUX";
221222
static constexpr auto DECODER_TEXT = "";

CoreLogic.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Components/ComplexLogic/DMsFlipFlop.h"
2121
#include "Components/ComplexLogic/TFlipFlop.h"
2222
#include "Components/ComplexLogic/JKFlipFlop.h"
23+
#include "Components/ComplexLogic/JkMsFlipFlop.h"
2324
#include "Components/ComplexLogic/Multiplexer.h"
2425
#include "Components/ComplexLogic/Demultiplexer.h"
2526
#include "Components/ComplexLogic/Decoder.h"
@@ -409,8 +410,7 @@ std::optional<IBaseComponent*> CoreLogic::GetItem() const
409410
{
410411
if (mIsJkFlipFlopMasterSlave)
411412
{
412-
qDebug() << "This JK flip-flop would be master-slave";
413-
item = new JKFlipFlop(this, mComponentDirection);
413+
item = new JkMasterSlaveFlipFlop(this, mComponentDirection);
414414
}
415415
else
416416
{
@@ -1974,6 +1974,11 @@ bool CoreLogic::CreateComponent(const QJsonObject &pJson)
19741974
item = new JKFlipFlop(this, pJson);
19751975
break;
19761976
}
1977+
case file::ComponentId::JK_MS_FLIPFLOP:
1978+
{
1979+
item = new JkMasterSlaveFlipFlop(this, pJson);
1980+
break;
1981+
}
19771982
case file::ComponentId::RS_MS_FLIPFLOP:
19781983
{
19791984
item = new RsMasterSlaveFlipFlop(this, pJson);

Gui/MainWindow.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,8 @@ void MainWindow::OnCircuitFileHasNewerIncompatibleVersion(const QString& pVersio
525525
mNewerVersionIncompatibleBox.setWindowTitle("Linkuit Studio");
526526
mNewerVersionIncompatibleBox.setWindowIcon(QIcon(":/images/icons/icon_default.png"));
527527
mNewerVersionIncompatibleBox.setText(tr("This file has been created with a newer version of Linkuit Studio."));
528-
mNewerVersionIncompatibleBox.setInformativeText(QString("It seems like this file was last saved using version %0. "
529-
"It is marked incompatible with the current version %1. Please update Linkuit Studio to open the file.").arg(pVersion).arg(QString(FULL_VERSION)));
528+
mNewerVersionIncompatibleBox.setInformativeText(QString("This file is compatible with version %0 or newer. "
529+
"It is therefore incompatible with the current version %1. Please update Linkuit Studio to open the file.").arg(pVersion).arg(QString(FULL_VERSION)));
530530
mNewerVersionIncompatibleBox.setStandardButtons(QMessageBox::Ok);
531531
mNewerVersionIncompatibleBox.setDefaultButton(QMessageBox::Ok);
532532
mNewerVersionIncompatibleBox.exec();

HelperFunctions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ static const std::map<ComponentType, ConfiguratorMode> CONFIGURATOR_MODE_MAP{{Co
2323
{ComponentType::RS_FLIPFLOP, ConfiguratorMode::RS_FLIPFLOP_TYPE},
2424
{ComponentType::D_FLIPFLOP, ConfiguratorMode::MASTER_SLAVE},
2525
{ComponentType::T_FLIPFLOP, ConfiguratorMode::DIRECTION_ONLY},
26-
{ComponentType::JK_FLIPFLOP, ConfiguratorMode::DIRECTION_ONLY},
26+
{ComponentType::JK_FLIPFLOP, ConfiguratorMode::MASTER_SLAVE},
2727
{ComponentType::MULTIPLEXER, ConfiguratorMode::MULTIPLEXER_BITS},
2828
{ComponentType::DEMULTIPLEXER, ConfiguratorMode::MULTIPLEXER_BITS},
2929
{ComponentType::DECODER, ConfiguratorMode::ENCODER_DECODER},

0 commit comments

Comments
 (0)