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.
233 lines
6.5 KiB
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 <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(
|
|
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);
|
|
}
|
|
}
|
|
|
|
|