You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
348 lines
8.9 KiB
348 lines
8.9 KiB
/***************************************************************************
|
|
* Copyright (C) 2005 by David Saxton *
|
|
* david@bluehaze.org *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
***************************************************************************/
|
|
|
|
#include "flipflop.h"
|
|
#include "icndocument.h"
|
|
#include "logic.h"
|
|
#include "libraryitem.h"
|
|
#include "node.h"
|
|
#include "simulator.h"
|
|
|
|
#include <kiconloader.h>
|
|
#include <tdelocale.h>
|
|
#include <tqpainter.h>
|
|
|
|
|
|
//BEGIN class ECDFlipFlop
|
|
Item* ECDFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id )
|
|
{
|
|
return new ECDFlipFlop( (ICNDocument*)itemDocument, newItem, id );
|
|
}
|
|
|
|
LibraryItem* ECDFlipFlop::libraryItem()
|
|
{
|
|
return new LibraryItem(
|
|
"ec/d_flipflop",
|
|
i18n("D Flip-Flop"),
|
|
i18n("Integrated Circuits"),
|
|
"ic3.png",
|
|
LibraryItem::lit_component,
|
|
ECDFlipFlop::construct );
|
|
}
|
|
|
|
ECDFlipFlop::ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Component( icnDocument, newItem, (id) ? id : "d_flipflop" )
|
|
{
|
|
m_name = i18n("D-Type Flip-Flop");
|
|
m_desc = i18n("The output state is set from the input state when the clock is pulsed.");
|
|
|
|
setSize( -32, -24, 64, 48 );
|
|
|
|
init2PinLeft( -8, 8 );
|
|
init2PinRight( -8, 8 );
|
|
|
|
m_prevD[0] = m_prevD[1] = false;
|
|
m_whichPrevD = 0;
|
|
m_prevDSimTime = 0;
|
|
m_pSimulator = Simulator::self();
|
|
|
|
m_bPrevClock = false;
|
|
m_pD = createLogicIn( m_pNNode[0] );
|
|
m_pClock = createLogicIn( m_pNNode[1] );
|
|
m_pQ = createLogicOut( m_pPNode[0], false );
|
|
m_pTQBar = createLogicOut( m_pPNode[1], false );
|
|
|
|
setp = createLogicIn( createPin( 0, -32, 90, "set" ) );
|
|
rstp = createLogicIn( createPin( 0, 32, 270, "rst" ) );
|
|
|
|
addDisplayText( "D", TQRect( -32, -16, 20, 16 ), "D" );
|
|
addDisplayText( ">", TQRect( -32, 0, 20, 16 ), ">" );
|
|
addDisplayText( "Q", TQRect( 12, -16, 20, 16 ), "Q" );
|
|
addDisplayText( "Q'", TQRect( 12, 0, 20, 16 ), "Q'" );
|
|
addDisplayText( "Set", TQRect( -16, -20, 32, 16 ), "Set" );
|
|
addDisplayText( "Rst", TQRect( -16, 4, 32, 16 ), "Rst" );
|
|
|
|
m_pD->setCallback( this, (CallbackPtr)(&ECDFlipFlop::inputChanged) );
|
|
m_pClock->setCallback( this, (CallbackPtr)(&ECDFlipFlop::clockChanged) );
|
|
setp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) );
|
|
rstp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) );
|
|
|
|
inStateChanged(false);
|
|
}
|
|
|
|
ECDFlipFlop::~ECDFlipFlop()
|
|
{
|
|
}
|
|
|
|
void ECDFlipFlop::asyncChanged(bool)
|
|
{
|
|
bool set = setp->isHigh();
|
|
bool rst = rstp->isHigh();
|
|
if(set || rst)
|
|
{
|
|
m_pQ->setHigh(set);
|
|
m_pTQBar->setHigh(rst);
|
|
}
|
|
}
|
|
|
|
void ECDFlipFlop::inputChanged( bool newState )
|
|
{
|
|
unsigned long long simTime = m_pSimulator->time();
|
|
if ( (simTime == m_prevDSimTime) && (newState == m_prevD[m_whichPrevD]) )
|
|
return;
|
|
|
|
m_prevDSimTime = simTime;
|
|
m_whichPrevD = 1-m_whichPrevD;
|
|
m_prevD[m_whichPrevD] = newState;
|
|
}
|
|
|
|
void ECDFlipFlop::clockChanged( bool newState )
|
|
{
|
|
bool set = setp->isHigh();
|
|
bool rst = rstp->isHigh();
|
|
|
|
bool fallingEdge = m_bPrevClock && !newState;
|
|
m_bPrevClock = newState;
|
|
|
|
if( set || rst ) return;
|
|
|
|
if (fallingEdge)
|
|
{
|
|
unsigned long long simTime = m_pSimulator->time();
|
|
bool d = ( simTime == m_prevDSimTime ) ? m_prevD[1-m_whichPrevD] : m_prevD[m_whichPrevD];
|
|
|
|
m_pQ->setHigh(d);
|
|
m_pTQBar->setHigh(!d);
|
|
}
|
|
}
|
|
|
|
void ECDFlipFlop::inStateChanged(bool)
|
|
{
|
|
// Only called when the flipflop is created.
|
|
m_pQ->setHigh(false);
|
|
m_pTQBar->setHigh(true);
|
|
}
|
|
//END class ECDFlipFlop
|
|
|
|
|
|
//BEGIN class ECJKFlipFlop
|
|
Item* ECJKFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id )
|
|
{
|
|
return new ECJKFlipFlop( (ICNDocument*)itemDocument, newItem, id );
|
|
}
|
|
|
|
LibraryItem* ECJKFlipFlop::libraryItem()
|
|
{
|
|
return new LibraryItem(
|
|
TQString("ec/jk_flipflop"),
|
|
i18n("JK Flip-Flop"),
|
|
i18n("Integrated Circuits"),
|
|
"ic3.png",
|
|
LibraryItem::lit_component,
|
|
ECJKFlipFlop::construct );
|
|
}
|
|
|
|
ECJKFlipFlop::ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Component( icnDocument, newItem, (id) ? id : "jk_flipflop" )
|
|
{
|
|
m_name = i18n("JK-Type Flip-Flop");
|
|
m_desc = i18n("The output state is set according to J and K when the clock is pulsed.");
|
|
|
|
setSize( -32, -32, 64, 64 );
|
|
|
|
init3PinLeft( -16, 0, 16 );
|
|
init2PinRight( -16, 16 );
|
|
|
|
m_pJ = createLogicIn( m_pNNode[0] );
|
|
m_pClock = createLogicIn( m_pNNode[1] );
|
|
m_pK = createLogicIn( m_pNNode[2] );
|
|
|
|
m_pQ = createLogicOut( m_pPNode[0], false );
|
|
m_pTQBar = createLogicOut( m_pPNode[1], false );
|
|
|
|
setp = createLogicIn( createPin( 0, -40, 90, "set" ) );
|
|
rstp = createLogicIn( createPin( 0, 40, 270, "rst" ) );
|
|
|
|
addDisplayText( "J", TQRect( -32, -24, 20, 16 ), "J" );
|
|
addDisplayText( ">", TQRect( -32, -8, 20, 16 ), ">" );
|
|
addDisplayText( "K", TQRect( -32, 8, 20, 16 ), "K" );
|
|
addDisplayText( "Q", TQRect( 12, -24, 20, 16 ), "Q" );
|
|
addDisplayText( "Q'", TQRect( 12, 8, 20, 16 ), "Q'" );
|
|
addDisplayText( "Set", TQRect( -16, -28, 32, 16 ), "Set" );
|
|
addDisplayText( "Rst", TQRect( -16, 12, 32, 16 ), "Rst" );
|
|
|
|
m_pClock->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::clockChanged) );
|
|
setp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) );
|
|
rstp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) );
|
|
|
|
inStateChanged(false);
|
|
}
|
|
|
|
ECJKFlipFlop::~ECJKFlipFlop()
|
|
{
|
|
}
|
|
|
|
void ECJKFlipFlop::clockChanged(bool newvalue)
|
|
{
|
|
bool j = m_pJ->isHigh();
|
|
bool k = m_pK->isHigh();
|
|
bool set = setp->isHigh();
|
|
bool rst = rstp->isHigh();
|
|
|
|
if( set || rst ) return;
|
|
|
|
// a JK flip-flop change state when clock do 1->0
|
|
if (!newvalue && (j || k)) {
|
|
if ( j && k ) {
|
|
m_pQ->setHigh(!prev_state);
|
|
m_pTQBar->setHigh(prev_state);
|
|
prev_state = !prev_state;
|
|
} else {
|
|
// (J=1 && K=0) || (J=0 && K=1)
|
|
m_pQ->setHigh(j);
|
|
m_pTQBar->setHigh(k);
|
|
prev_state = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ECJKFlipFlop::asyncChanged(bool)
|
|
{
|
|
bool set = setp->isHigh();
|
|
bool rst = rstp->isHigh();
|
|
|
|
if (set || rst) {
|
|
m_pQ->setHigh(set);
|
|
m_pTQBar->setHigh(rst);
|
|
prev_state = set;
|
|
}
|
|
}
|
|
|
|
void ECJKFlipFlop::inStateChanged(bool)
|
|
{
|
|
m_pTQBar->setHigh(true);
|
|
m_pQ->setHigh(false);
|
|
prev_state = false;
|
|
}
|
|
//END class ECJKFlipFlop
|
|
|
|
|
|
//BEGIN class ECSRFlipFlop
|
|
Item* ECSRFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id )
|
|
{
|
|
return new ECSRFlipFlop( (ICNDocument*)itemDocument, newItem, id );
|
|
}
|
|
|
|
LibraryItem* ECSRFlipFlop::libraryItem()
|
|
{
|
|
return new LibraryItem(
|
|
TQString("ec/sr_flipflop"),
|
|
i18n("SR Flip-Flop"),
|
|
i18n("Integrated Circuits"),
|
|
"ic3.png",
|
|
LibraryItem::lit_component,
|
|
ECSRFlipFlop::construct );
|
|
}
|
|
|
|
ECSRFlipFlop::ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Component( icnDocument, newItem, (id) ? id : "sr_flipflop" )
|
|
{
|
|
m_name = i18n("SR Flip-Flop");
|
|
m_desc = i18n("The output is made high by holding <i>set</i> high, and low by holding <i>reset</i> high.");
|
|
|
|
setSize( -24, -24, 48, 48 );
|
|
|
|
init2PinLeft( -8, 8 );
|
|
init2PinRight( -8, 8 );
|
|
|
|
m_pS = createLogicIn( m_pNNode[0] );
|
|
m_pR = createLogicIn( m_pNNode[1] );
|
|
m_pQ = createLogicOut( m_pPNode[0], true );
|
|
m_pTQBar = createLogicOut( m_pPNode[1], false );
|
|
|
|
old_q1 = true;
|
|
old_q2 = false;
|
|
m_pQ->setHigh(old_q1);
|
|
m_pTQBar->setHigh(old_q2);
|
|
|
|
addDisplayText( "S", TQRect( -24, -16, 20, 16 ), "S" );
|
|
addDisplayText( "R", TQRect( -24, 0, 20, 16 ), "R" );
|
|
addDisplayText( "Q", TQRect( 4, -16, 20, 16 ), "Q" );
|
|
addDisplayText( "Q'", TQRect( 4, 0, 20, 16 ), "Q'" );
|
|
|
|
m_pS->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
|
|
m_pR->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
|
|
m_pQ->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
|
|
m_pTQBar->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
|
|
}
|
|
|
|
ECSRFlipFlop::~ECSRFlipFlop()
|
|
{
|
|
}
|
|
|
|
void ECSRFlipFlop::inStateChanged(bool)
|
|
{
|
|
// Q = v_q1, Q-bar = v_q2
|
|
bool new_q1 = false;
|
|
bool new_q2 = false;
|
|
|
|
bool s = m_pS->isHigh();
|
|
bool r = m_pR->isHigh();
|
|
bool q1 = m_pQ->isHigh();
|
|
bool q2 = m_pTQBar->isHigh();
|
|
|
|
// Easy ones to do :-)
|
|
if (!q1) new_q2 = true;
|
|
if (!q2) new_q1 = true;
|
|
|
|
if ( q1 && q2 )
|
|
{
|
|
if ( s && !r )
|
|
{
|
|
new_q1 = true;
|
|
new_q2 = false;
|
|
}
|
|
else if ( !s && r )
|
|
{
|
|
new_q1 = false;
|
|
new_q2 = true;
|
|
}
|
|
else if ( s && r )
|
|
{
|
|
new_q1 = old_q1;
|
|
new_q2 = old_q2;
|
|
}
|
|
else if ( !s && !r )
|
|
{
|
|
new_q1 = false;
|
|
new_q2 = false;
|
|
}
|
|
}
|
|
else if ( q1 && !q2 )
|
|
{
|
|
// Note: We only need to set the value of v_q2
|
|
if ( r && !s ) new_q2 = true;
|
|
else new_q2 = false;
|
|
}
|
|
else if ( !q1 && q2 )
|
|
{
|
|
// Note: We only need to set the value of v_q1
|
|
if ( s && !r ) new_q1 = true;
|
|
else new_q1 = false;
|
|
}
|
|
|
|
old_q1 = new_q1;
|
|
old_q2 = new_q2;
|
|
|
|
m_pQ->setHigh(new_q1);
|
|
m_pTQBar->setHigh(new_q2);
|
|
}
|
|
//END class ECSRFlipFlop
|