diff options
Diffstat (limited to 'src/electronics/components/ram.cpp')
-rw-r--r-- | src/electronics/components/ram.cpp | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/electronics/components/ram.cpp b/src/electronics/components/ram.cpp new file mode 100644 index 0000000..add745a --- /dev/null +++ b/src/electronics/components/ram.cpp @@ -0,0 +1,232 @@ +/*************************************************************************** + * 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 "libraryitem.h" +#include "logic.h" +#include "ram.h" +#include "variant.h" + +#include <cmath> +#include <klocale.h> + +Item* RAM::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new RAM( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* RAM::libraryItem() +{ + return new LibraryItem( + QString("ec/ram"), + i18n("RAM"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + RAM::construct + ); +} + +RAM::RAM( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "ram" ) +{ + m_name = i18n("RAM"); + m_desc = i18n("This RAM stores data as a collection of words; each of which contains <i>word size</i> bits of data.<br><br>To read data, set the CS (<i>chip select</i>) and the OE (<i>output enable</i>) pins high, and select the word using the address pins <i>A*</i>. The word is outputted on the data-out pins: <i>DO*</i>.<br><br>To write data, set the CS (<i>chip select</i>) and the WE (<i>write enable</i>) pins high, and select the address to write to with the <i>A*</i> pins. Write to the selected word using the data-in pins: <i>DI*</i>.<br><br>The <i>Address Size</i> is the number of bits that determine an address; so the total number of words stored will be 2^<sup><i>Address Size</i></sup>."); + + m_data = 0l; + m_pCS = 0l; + m_pOE = 0l; + m_pWE = 0l; + m_wordSize = 0; + m_addressSize = 0; + + createProperty( "wordSize", Variant::Type::Int ); + property("wordSize")->setCaption( i18n("Word Size") ); + property("wordSize")->setMinValue(1); + property("wordSize")->setMaxValue(256); + property("wordSize")->setValue(2); + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(32); + property("addressSize")->setValue(4); + + m_data = createProperty( "data", Variant::Type::Raw )->value().asBitArray(); +} + +RAM::~RAM() +{ +} + + +void RAM::dataChanged() +{ + m_wordSize = dataInt("wordSize"); + m_addressSize = dataInt("addressSize"); + + int newSize = int( m_wordSize * std::pow( 2., m_addressSize ) ); + m_data.resize(newSize); + + initPins(); +} + + +void RAM::inStateChanged( bool newState ) +{ + Q_UNUSED(newState); + + bool cs = m_pCS->isHigh(); + bool oe = m_pOE->isHigh(); + bool we = m_pWE->isHigh(); + + if ( !cs || !oe ) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh(false); + } + + if ( !cs || (!oe && !we) ) + return; + + unsigned address = 0; + for ( int i = 0; i < m_addressSize; ++i ) + address += (m_address[i]->isHigh() ? 1 : 0) << i; + + if (we) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_data[ m_wordSize * address + i ] = m_dataIn[i]->isHigh(); + } + + if (oe) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh( m_data[ m_wordSize * address + i ] ); + } +} + + +void RAM::initPins() +{ + int oldWordSize = m_dataIn.size(); + int oldAddressSize = m_address.size(); + + int newWordSize = dataInt("wordSize"); + int newAddressSize = dataInt("addressSize"); + + if ( newAddressSize == oldAddressSize && + newWordSize == oldWordSize ) + return; + + QStringList leftPins; // Pins on left of IC + leftPins << "CS" << "OE" << "WE"; + for ( int i = 0; i < newAddressSize; ++i ) + leftPins << QString("A%1").arg( QString::number(i) ); + + QStringList rightPins; // Pins on right of IC + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DI%1").arg( QString::number(i-1) ); + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DO%1").arg( QString::number(i-1) ); + + // Make pin lists of consistent sizes + for ( unsigned i = leftPins.size(); i < rightPins.size(); ++i ) + leftPins.append(""); + for ( unsigned i = rightPins.size(); i < leftPins.size(); ++i ) + rightPins.prepend(""); + + QStringList pins = leftPins + rightPins; + + initDIPSymbol( pins, 72 ); + initDIP(pins); + + ECNode *node; + + if (!m_pCS) + { + node = ecNodeWithID("CS"); + m_pCS = createLogicIn(node); + m_pCS->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pOE) + { + node = ecNodeWithID("OE"); + m_pOE = createLogicIn(node); + m_pOE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pWE) + { + node = ecNodeWithID("WE"); + m_pWE = createLogicIn(node); + m_pWE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if ( newWordSize > oldWordSize ) + { + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + + for ( int i = oldWordSize; i < newWordSize; ++i ) + { + node = ecNodeWithID( QString("DI%1").arg( QString::number(i) ) ); + m_dataIn.insert( i, createLogicIn(node) ); + m_dataIn[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + + node = ecNodeWithID( QString("DO%1").arg( QString::number(i) ) ); + m_dataOut.insert( i, createLogicOut(node, false) ); + } + } + else if ( newWordSize < oldWordSize ) + { + for ( int i = newWordSize; i < oldWordSize; ++i ) + { + QString id = QString("DO%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataIn[i], false ); + removeNode(id); + + id = QString("DI%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataOut[i], false ); + removeNode(id); + } + + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + } + + if ( newAddressSize > oldAddressSize ) + { + m_address.resize(newAddressSize); + + for ( int i = oldAddressSize; i < newAddressSize; ++i ) + { + node = ecNodeWithID( QString("A%1").arg( QString::number(i) ) ); + m_address.insert( i, createLogicIn(node) ); + m_address[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + } + else if ( newAddressSize < oldAddressSize ) + { + for ( int i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = QString("A%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_address[i], false ); + removeNode(id); + } + + m_address.resize(newAddressSize); + } +} + + |