adds a dual ported RAM

This commit is contained in:
hneemann 2017-11-18 10:55:29 +01:00
parent 43d191b8a0
commit e65635ef0e
10 changed files with 442 additions and 11 deletions

View File

@ -4,9 +4,10 @@ HEAD, planned as v0.16
- RAM components and EEPROM now allow an input invert configuration.
- Measurement values dialog is also able to modify the values.
- Now you can open the measurement value table and graph in a running simulation.
- Added a bit extender to extend signed values.
- Added a bit extender component to extend signed values.
- Added a simple unclocked RS flip-flop
- Added a bit selector
- Added a bit selector component
- Added a dual ported RAM component
- Added tooltips showing the actual value to wires.
- Bug fixes
- Fixed a bug in the RAMSinglePortSel component: Write was not edge-triggered on WE. Now it is.

View File

@ -0,0 +1,140 @@
package de.neemann.digital.core.memory;
import de.neemann.digital.core.*;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
import static de.neemann.digital.core.element.PinInfo.input;
/**
* RAM module with different ports to read and write the data
* and an additional read port. Used to implement graphic card memory.
*
* @author hneemann
*/
public class RAMDualAccess extends Node implements Element, RAMInterface {
/**
* The RAMs {@link ElementTypeDescription}
*/
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(RAMDualAccess.class,
input("str"),
input("C"),
input("ld"),
input("1A"),
input("1D_in"),
input("2A"))
.addAttribute(Keys.ROTATE)
.addAttribute(Keys.BITS)
.addAttribute(Keys.ADDR_BITS)
.addAttribute(Keys.LABEL);
private final DataField memory;
private final ObservableValue out1;
private final ObservableValue out2;
private final int addrBits;
private final int bits;
private final String label;
private final int size;
private ObservableValue addr1In;
private ObservableValue data1In;
private ObservableValue str1In;
private ObservableValue clk1In;
private ObservableValue ld1In;
private ObservableValue addr2In;
private int addr1;
private int addr2;
private boolean lastClk = false;
private boolean ld;
/**
* Creates a new instance
*
* @param attr the elemets attributes
*/
public RAMDualAccess(ElementAttributes attr) {
super(true);
bits = attr.get(Keys.BITS);
out1 = new ObservableValue("1D", bits, true).setPinDescription(DESCRIPTION);
out2 = new ObservableValue("2D", bits).setPinDescription(DESCRIPTION);
addrBits = attr.get(Keys.ADDR_BITS);
size = 1 << addrBits;
memory = new DataField(size);
label = attr.getCleanLabel();
}
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
this.str1In = inputs.get(0).checkBits(1, this);
this.clk1In = inputs.get(1).checkBits(1, this).addObserverToValue(this);
this.ld1In = inputs.get(2).checkBits(1, this).addObserverToValue(this);
this.addr1In = inputs.get(3).checkBits(addrBits, this).addObserverToValue(this);
this.data1In = inputs.get(4).checkBits(bits, this);
this.addr2In = inputs.get(5).checkBits(addrBits, this).addObserverToValue(this);
}
@Override
public ObservableValues getOutputs() {
return new ObservableValues(out1, out2);
}
@Override
public void readInputs() throws NodeException {
long data = 0;
boolean clk = clk1In.getBool();
boolean str;
if (!lastClk && clk) {
str = str1In.getBool();
if (str)
data = data1In.getValue();
} else
str = false;
ld = ld1In.getBool();
if (ld || str)
addr1 = (int) addr1In.getValue();
if (str)
memory.setData(addr1, data);
addr2 = (int) addr2In.getValue();
lastClk = clk;
}
@Override
public void writeOutputs() throws NodeException {
if (ld) {
out1.set(memory.getDataWord(addr1), false);
} else {
out1.set(0, true);
}
out2.setValue(memory.getDataWord(addr2));
}
@Override
public DataField getMemory() {
return memory;
}
@Override
public String getLabel() {
return label;
}
@Override
public int getSize() {
return size;
}
@Override
public int getDataBits() {
return bits;
}
@Override
public int getAddrBits() {
return addrBits;
}
}

View File

@ -150,6 +150,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(RAMSinglePortSel.DESCRIPTION)
.add(EEPROM.DESCRIPTION)
.add(GraphicCard.DESCRIPTION)
.add(RAMDualAccess.DESCRIPTION)
.add(Counter.DESCRIPTION))
.add(new LibraryNode(Lang.get("lib_arithmetic"))
.add(Add.DESCRIPTION)

View File

@ -7,10 +7,7 @@ import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.core.element.PinDescriptions;
import de.neemann.digital.core.io.*;
import de.neemann.digital.core.memory.EEPROM;
import de.neemann.digital.core.memory.RAMDualPort;
import de.neemann.digital.core.memory.RAMSinglePort;
import de.neemann.digital.core.memory.RAMSinglePortSel;
import de.neemann.digital.core.memory.*;
import de.neemann.digital.core.pld.*;
import de.neemann.digital.core.switching.*;
import de.neemann.digital.core.wiring.*;
@ -79,6 +76,7 @@ public final class ShapeFactory {
map.put(RAMSinglePort.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, RAMSinglePort.DESCRIPTION));
map.put(RAMSinglePortSel.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, RAMSinglePortSel.DESCRIPTION));
map.put(EEPROM.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, EEPROM.DESCRIPTION));
map.put(RAMDualAccess.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, RAMDualAccess.DESCRIPTION));
map.put(In.DESCRIPTION.getName(), InputShape::new);
map.put(Reset.DESCRIPTION.getName(), ResetShape::new);

View File

@ -434,8 +434,25 @@
<string name="elem_GraphicCard_pin_str">Ist dieser Eingang 1 wird mit steigendem Takt das Datenwort gespeichert.</string>
<string name="elem_GraphicCard_pin_C">Der Takt. Eine steigende Flanke aktiviert das Speichern.</string>
<string name="elem_GraphicCard_pin_ld">Ist dieser Eingang 1 wird das Datenwort ausgegeben.</string>
<string name="elem_GraphicCard_pin_B">Auswahl der anzuzeigenden Seite. Mit diesem Eingang kann zwischen zwei Speicherseiten umgeschaltet werden.</string>
<string name="elem_GraphicCard_pin_B">Auswahl der anzuzeigenden Seite.
Mit diesem Eingang kann zwischen zwei Speicherseiten umgeschaltet werden.</string>
<string name="elem_GraphicCard_pin_D">Der bidirektionale Datenanschluss.</string>
<string name="elem_RAMDualAccess">RAM, Dual Port</string>
<string name="elem_RAMDualAccess_short">RAM</string>
<string name="elem_RAMDualAccess_tt">RAM mit einem Port der das Beschreiben und Lesen des RAMs ermöglicht, und einem
zweiten Leseport. Dieser zweite Port kann verwendet werden, um einer Grafik-Logik Zugriff auf den Speicherinhalt
zu geben. Auf diese Weise kann ein Prozessor in das RAM schreiben, und eine Grafik-Logik kann das RAM
gleichzeitig auslesen.</string>
<string name="elem_RAMDualAccess_pin_1D">Ausgabeport 1</string>
<string name="elem_RAMDualAccess_pin_2D">Ausgabeport 2</string>
<string name="elem_RAMDualAccess_pin_1A">Die Adresse, an der über Port 1 gelesen bzw. geschrieben wird.</string>
<string name="elem_RAMDualAccess_pin_2A">Die Adresse, an der über Port 2 gelesen wird.</string>
<string name="elem_RAMDualAccess_pin_C">Der Takt. Eine steigende Flanke aktiviert das Speichern.</string>
<string name="elem_RAMDualAccess_pin_1D_in">Die Daten die gespeichert werden sollen.</string>
<string name="elem_RAMDualAccess_pin_ld">Ist diese Leitung high, wird der Ausgang D1 aktiviert, und die Daten liegen dort an.</string>
<string name="elem_RAMDualAccess_pin_str">Ist diese Leitung high wird das Datenwort an D1 gespeichert, wenn der Takt ansteigt.</string>
<string name="elem_Counter">Zähler</string>
<string name="elem_Counter_tt">Ein einfacher Zähler-Baustein.
Zählt jede steigende Flanke am C Eingang und kann über den clr Eingang zurückgesetzt werden.

View File

@ -398,7 +398,7 @@
<string name="elem_RAMDualPort_tt">A RAM module with separate inputs for storing and output for reading the stored data.</string>
<string name="elem_RAMDualPort_pin_A">The address to read from or write to.</string>
<string name="elem_RAMDualPort_pin_C">Clock input</string>
<string name="elem_RAMDualPort_pin_D_in">The data to be stored in the RAM</string>
<string name="elem_RAMDualPort_pin_D_in">The data to be stored in the RAM.</string>
<string name="elem_RAMDualPort_pin_D">The data output pin</string>
<string name="elem_RAMDualPort_pin_ld">If this input is high the output is activated and the data is visible at the output.</string>
<string name="elem_RAMDualPort_pin_str">If this input is high and when the clock becomes high, the the data is stored.</string>
@ -441,6 +441,22 @@
<string name="elem_GraphicCard_pin_ld">If this input is high the output is activated and the data is visible at the output.</string>
<string name="elem_GraphicCard_pin_B">Selects the screen buffer to show.</string>
<string name="elem_GraphicCard_pin_D">The bidirectional data connection.</string>
<string name="elem_RAMDualAccess">RAM, Dual Port</string>
<string name="elem_RAMDualAccess_short">RAM</string>
<string name="elem_RAMDualAccess_tt">RAM with one port that allows to write to and read from the RAM, and a second
read only port.
This second port can be used to give some graphic logic access to the memory contents. In this way, a processor
can write to the RAM, and a graphics logic can simultaneously read from the RAM.</string>
<string name="elem_RAMDualAccess_pin_1D">Output Port 1</string>
<string name="elem_RAMDualAccess_pin_2D">Output Port 2</string>
<string name="elem_RAMDualAccess_pin_1A">The address at which port 1 is read or written.</string>
<string name="elem_RAMDualAccess_pin_2A">The address used to read via port 2.</string>
<string name="elem_RAMDualAccess_pin_C">Clock</string>
<string name="elem_RAMDualAccess_pin_1D_in">The data to be stored in the RAM.</string>
<string name="elem_RAMDualAccess_pin_ld">If this input is high the output is activated and the data is visible at the output 1D.</string>
<string name="elem_RAMDualAccess_pin_str">If this input is high and when the clock becomes high, the the data is stored.</string>
<string name="elem_Counter">Counter</string>
<string name="elem_Counter_tt">A simple counter component. The clock input increases the counter.
Can be reset back to 0 with the clr input.

View File

@ -0,0 +1,33 @@
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
entity DIG_RAMDualAccess is
generic (
Bits : integer;
AddrBits : integer );
port (
PORT_1D: out std_logic_vector ((Bits-1) downto 0);
PORT_2D: out std_logic_vector ((Bits-1) downto 0);
PORT_str: in std_logic;
PORT_C: in std_logic;
PORT_ld: in std_logic;
PORT_1A: in std_logic_vector ((AddrBits-1) downto 0);
PORT_1D_in: in std_logic_vector ((Bits-1) downto 0);
PORT_2A: in std_logic_vector ((AddrBits-1) downto 0) );
end DIG_RAMDualAccess;
architecture DIG_RAMDualAccess_arch of DIG_RAMDualAccess is
-- CAUTION: uses distributed RAM
type memoryType is array(0 to (2**AddrBits)-1) of STD_LOGIC_VECTOR((Bits-1) downto 0);
signal memory : memoryType;
begin
process ( PORT_C )
begin
if rising_edge(PORT_C) AND (PORT_str='1') then
memory(to_integer(unsigned(PORT_1A))) <= PORT_1D_in;
end if;
end process;
PORT_1D <= memory(to_integer(unsigned(PORT_1A))) when PORT_ld='1' else (others => 'Z');
PORT_2D <= memory(to_integer(unsigned(PORT_2A)));
end DIG_RAMDualAccess_arch;

View File

@ -37,7 +37,7 @@ public class TestInSimulator extends TestCase {
File examples = new File(Resources.getRoot(), "/dig/test/vhdl");
try {
int tested = new FileScanner(this::check).scan(examples);
assertEquals(23, tested);
assertEquals(24, tested);
assertEquals(tested, testBenches);
} catch (FileScanner.SkipAllException e) {
// if ghdl is not installed its also ok

View File

@ -40,8 +40,8 @@ public class TestExamples extends TestCase {
*/
public void testTestExamples() throws Exception {
File examples = new File(Resources.getRoot(), "/dig/test");
assertEquals(112, new FileScanner(this::check).scan(examples));
assertEquals(102, testCasesInFiles);
assertEquals(113, new FileScanner(this::check).scan(examples));
assertEquals(103, testCasesInFiles);
}

View File

@ -0,0 +1,225 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes/>
<visualElements>
<visualElement>
<elementName>RAMDualAccess</elementName>
<elementAttributes>
<entry>
<string>AddrBits</string>
<int>8</int>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="480" y="200"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>1D</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="580" y="200"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>2D</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="580" y="240"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>str</string>
</entry>
</elementAttributes>
<pos x="360" y="200"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C</string>
</entry>
</elementAttributes>
<pos x="360" y="240"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>ld</string>
</entry>
</elementAttributes>
<pos x="360" y="280"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>1A</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="360" y="320"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>1Di</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="360" y="360"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>2A</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="360" y="400"/>
</visualElement>
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes>
<entry>
<string>Testdata</string>
<testData>
<dataString>str C ld 1A 1Di 1D 2A 2D
loop (a, 256)
1 c 0 (a) (a+10) z 0 x
end loop
loop (a, 256)
0 0 1 (a) 0 (a+10) (a+10) (a+20)
end loop
</dataString>
</testData>
</entry>
</elementAttributes>
<pos x="540" y="360"/>
</visualElement>
</visualElements>
<wires>
<wire>
<p1 x="560" y="240"/>
<p2 x="580" y="240"/>
</wire>
<wire>
<p1 x="360" y="240"/>
<p2 x="380" y="240"/>
</wire>
<wire>
<p1 x="400" y="240"/>
<p2 x="480" y="240"/>
</wire>
<wire>
<p1 x="360" y="320"/>
<p2 x="420" y="320"/>
</wire>
<wire>
<p1 x="360" y="400"/>
<p2 x="460" y="400"/>
</wire>
<wire>
<p1 x="420" y="260"/>
<p2 x="480" y="260"/>
</wire>
<wire>
<p1 x="540" y="200"/>
<p2 x="580" y="200"/>
</wire>
<wire>
<p1 x="360" y="200"/>
<p2 x="480" y="200"/>
</wire>
<wire>
<p1 x="360" y="280"/>
<p2 x="400" y="280"/>
</wire>
<wire>
<p1 x="440" y="280"/>
<p2 x="480" y="280"/>
</wire>
<wire>
<p1 x="360" y="360"/>
<p2 x="440" y="360"/>
</wire>
<wire>
<p1 x="540" y="220"/>
<p2 x="560" y="220"/>
</wire>
<wire>
<p1 x="380" y="220"/>
<p2 x="480" y="220"/>
</wire>
<wire>
<p1 x="460" y="300"/>
<p2 x="480" y="300"/>
</wire>
<wire>
<p1 x="560" y="220"/>
<p2 x="560" y="240"/>
</wire>
<wire>
<p1 x="400" y="240"/>
<p2 x="400" y="280"/>
</wire>
<wire>
<p1 x="420" y="260"/>
<p2 x="420" y="320"/>
</wire>
<wire>
<p1 x="440" y="280"/>
<p2 x="440" y="360"/>
</wire>
<wire>
<p1 x="380" y="220"/>
<p2 x="380" y="240"/>
</wire>
<wire>
<p1 x="460" y="300"/>
<p2 x="460" y="400"/>
</wire>
</wires>
</circuit>