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.
ktechlab/src/electronics/components/ram.cpp

233 lines
6.5 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 "libraryitem.h"
#include "logic.h"
#include "ram.h"
#include "variant.h"
#include <cmath>
#include <tdelocale.h>
Item* RAM::construct( ItemDocument *itemDocument, bool newItem, const char *id )
{
return new RAM( (ICNDocument*)itemDocument, newItem, id );
}
LibraryItem* RAM::libraryItem()
{
return new LibraryItem(
TQString("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;
TQStringList leftPins; // Pins on left of IC
leftPins << "CS" << "OE" << "WE";
for ( int i = 0; i < newAddressSize; ++i )
leftPins << TQString("A%1").arg( TQString::number(i) );
TQStringList rightPins; // Pins on right of IC
for ( unsigned i = newWordSize; i > 0; --i )
rightPins << TQString("DI%1").arg( TQString::number(i-1) );
for ( unsigned i = newWordSize; i > 0; --i )
rightPins << TQString("DO%1").arg( TQString::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("");
TQStringList 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( TQString("DI%1").arg( TQString::number(i) ) );
m_dataIn.insert( i, createLogicIn(node) );
m_dataIn[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) );
node = ecNodeWithID( TQString("DO%1").arg( TQString::number(i) ) );
m_dataOut.insert( i, createLogicOut(node, false) );
}
}
else if ( newWordSize < oldWordSize )
{
for ( int i = newWordSize; i < oldWordSize; ++i )
{
TQString id = TQString("DO%1").arg( TQString::number(i) );
removeDisplayText(id);
removeElement( m_dataIn[i], false );
removeNode(id);
id = TQString("DI%1").arg( TQString::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( TQString("A%1").arg( TQString::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 )
{
TQString id = TQString("A%1").arg( TQString::number(i) );
removeDisplayText(id);
removeElement( m_address[i], false );
removeNode(id);
}
m_address.resize(newAddressSize);
}
}