adds dual-port multi-byte memory that allows single bytes to be overwritten; closes #231

This commit is contained in:
hneemann 2019-01-15 09:51:08 +01:00
parent 2af7b15180
commit 9816cae471
9 changed files with 311 additions and 4 deletions

View File

@ -4,6 +4,8 @@ Release Notes
HEAD, planned as v0.22
- Improved the RAM/ROM data loader. Now binary files and Intel HEX files are
supported.
- A dual-port multi-byte memory has been added that allows single bytes to
be overwritten.
v0.21, released on 10. Dec 2018
- Added a simple SVG importer to define custom shapes.

View File

@ -52,7 +52,7 @@ public class RAMDualPort extends Node implements Element, RAMInterface {
/**
* Creates a new instance
*
* @param attr the elemets attributes
* @param attr the elements attributes
*/
public RAMDualPort(ElementAttributes attr) {
super(true);
@ -167,11 +167,15 @@ public class RAMDualPort extends Node implements Element, RAMInterface {
addr = (int) addrIn.getValue();
if (str)
memory.setData(addr, data);
writeDataToMemory(addr, data);
lastClk = clk;
}
void writeDataToMemory(int addr, long data) {
memory.setData(addr, data);
}
@Override
public void writeOutputs() throws NodeException {
if (ld) {

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2019 Helmut Neemann.
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.core.memory;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.ObservableValues;
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;
/**
* A memory which allows to overwrite single bytes.
*/
public class RAMDualPortMasked extends RAMDualPort {
private static final long[] MASK_TABLE = new long[256];
static {
for (int i = 0; i < 256; i++) {
long m = 0;
long bits = 0xff;
for (int b = 0; b < 8; b++) {
if ((i & (1 << b)) != 0)
m = m | bits;
bits = bits << 8;
}
MASK_TABLE[i] = m;
}
}
/**
* The RAMs {@link ElementTypeDescription}
*/
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(RAMDualPortMasked.class,
input("A"),
input("Din"),
input("str"),
input("C").setClock(),
input("ld"),
input("mask"))
.addAttribute(Keys.ROTATE)
.addAttribute(Keys.BITS)
.addAttribute(Keys.ADDR_BITS)
.addAttribute(Keys.IS_PROGRAM_MEMORY)
.addAttribute(Keys.LABEL);
private final int maskBits;
private ObservableValue maskVal;
/**
* Creates a new instance
*
* @param attr the elements attributes
*/
public RAMDualPortMasked(ElementAttributes attr) {
super(attr);
maskBits = Math.min(8, (getDataBits() - 1) / 8 + 1);
}
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
super.setInputs(inputs);
maskVal = inputs.get(5).checkBits(maskBits, this).addObserverToValue(this);
}
@Override
void writeDataToMemory(int addr, long data) {
DataField memory = getMemory();
long old = memory.getDataWord(addr);
long mask = MASK_TABLE[(int) maskVal.getValue()];
data = data & mask;
old = old & ~mask;
memory.setData(addr, data | old);
}
}

View File

@ -170,6 +170,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(new LibraryNode(Lang.get("lib_memory"))
.add(new LibraryNode(Lang.get("lib_ram"))
.add(RAMDualPort.DESCRIPTION)
.add(RAMDualPortMasked.DESCRIPTION)
.add(RAMSinglePort.DESCRIPTION)
.add(RAMSinglePortSel.DESCRIPTION)
.add(RegisterFile.DESCRIPTION)

View File

@ -478,6 +478,24 @@
<string name="elem_RAMDualPort_pin_ld">Ist diese Leitung high, wird der Ausgang aktiviert, und die Daten liegen dort an.</string>
<string name="elem_RAMDualPort_pin_str">Ist diese Leitung high, wird das Datenwort gespeichert, wenn der Takt ansteigt.</string>
<string name="elem_RAMDualPortMasked">RAM, getrennte Ports, Byte-Zugriff</string>
<string name="elem_RAMDualPortMasked_short">RAM</string>
<string name="elem_RAMDualPortMasked_tt">Ein RAM Modul mit getrennten Daten-Anschlüssen für Lesen und Schreiben.
Es gibt einen Eingang für das Beschreiben und einen Ausgang für das Auslesen der gespeicherten Daten.
Zusätzlich wird das Überschreigen einzelner Bytes ermöglicht. Auf diese Weise kann z.B. in einem 32
Bit Speicher ein einzelnes Byte überschrieben werden.
</string>
<string name="elem_RAMDualPortMasked_pin_A">Die Adresse, an der gelesen bzw. geschrieben wird.</string>
<string name="elem_RAMDualPortMasked_pin_C">Der Takt. Eine steigende Flanke aktiviert das Speichern.</string>
<string name="elem_RAMDualPortMasked_pin_Din">Die Daten, die gespeichert werden sollen.</string>
<string name="elem_RAMDualPortMasked_pin_D">Ausgabe der gespeicherten Daten.</string>
<string name="elem_RAMDualPortMasked_pin_ld">Ist diese Leitung high, wird der Ausgang aktiviert, und die Daten liegen dort an.</string>
<string name="elem_RAMDualPortMasked_pin_str">Ist diese Leitung high, wird das Datenwort gespeichert, wenn der Takt ansteigt.</string>
<string name="elem_RAMDualPortMasked_pin_mask">Setzt die Schreibmaske. In dieser Maske steht jewels ein Bit für ein
Byte im Speicher, welches überschrieben werden kann. Soll also das zweite Byte im Speicherwort überschrieben werden,
muss auch das zweite Bit in der Maske gesetzt sein.
</string>
<string name="elem_EEPROMDualPort">EEPROM, getrennte Ports</string>
<string name="elem_EEPROMDualPort_short">EEPROM</string>
<string name="elem_EEPROMDualPort_tt">Ein EEPROM Modul mit getrennten Daten-Anschlüssen für Lesen und Schreiben.

View File

@ -484,6 +484,21 @@
<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>
<string name="elem_RAMDualPortMasked">RAM, separated ports, byte access</string>
<string name="elem_RAMDualPortMasked_short">RAM</string>
<string name="elem_RAMDualPortMasked_tt">A RAM module with separate inputs for storing and output for reading the stored data.
In addition, individual bytes can be overwritten. In this way, for example, a single byte can be overwritten in a 32-bit memory.
</string>
<string name="elem_RAMDualPortMasked_pin_A">The address to read from or write to.</string>
<string name="elem_RAMDualPortMasked_pin_C">Clock input</string>
<string name="elem_RAMDualPortMasked_pin_Din">The data to be stored in the RAM.</string>
<string name="elem_RAMDualPortMasked_pin_D">The data output pin</string>
<string name="elem_RAMDualPortMasked_pin_ld">If this input is high the output is activated and the data is visible at the output.</string>
<string name="elem_RAMDualPortMasked_pin_str">If this input is high and when the clock becomes high, the the data is stored.</string>
<string name="elem_RAMDualPortMasked_pin_mask">Sets the write mask. In this mask there is one bit for each byte in the memory,
which can be overwritten. If the second byte in the memory word is to be overwritten, the second bit in
the mask must also be set.</string>
<string name="elem_EEPROMDualPort">EEPROM, separated Ports</string>
<string name="elem_EEPROMDualPort_short">EEPROM</string>
<string name="elem_EEPROMDualPort_tt">A EEPROM module with separate inputs for storing and output for reading the stored data.</string>

View File

@ -43,8 +43,8 @@ public class TestExamples extends TestCase {
*/
public void testTestExamples() throws Exception {
File examples = new File(Resources.getRoot(), "/dig/test");
assertEquals(146, new FileScanner(this::check).scan(examples));
assertEquals(138, testCasesInFiles);
assertEquals(147, new FileScanner(this::check).scan(examples));
assertEquals(139, testCasesInFiles);
}
/**

View File

@ -0,0 +1,184 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes/>
<visualElements>
<visualElement>
<elementName>RAMDualPortMasked</elementName>
<elementAttributes>
<entry>
<string>AddrBits</string>
<int>8</int>
</entry>
<entry>
<string>Bits</string>
<int>32</int>
</entry>
</elementAttributes>
<pos x="400" y="180"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>D</string>
</entry>
<entry>
<string>Bits</string>
<int>32</int>
</entry>
</elementAttributes>
<pos x="500" y="240"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>A</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="260" y="180"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Din</string>
</entry>
<entry>
<string>Bits</string>
<int>32</int>
</entry>
</elementAttributes>
<pos x="380" y="200"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>str</string>
</entry>
</elementAttributes>
<pos x="260" y="220"/>
</visualElement>
<visualElement>
<elementName>Clock</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C</string>
</entry>
</elementAttributes>
<pos x="380" y="260"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>ld</string>
</entry>
</elementAttributes>
<pos x="260" y="280"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>mask</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="380" y="300"/>
</visualElement>
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes>
<entry>
<string>Testdata</string>
<testData>
<dataString>C A Din str ld mask D
# no write at all, mask is zero
C 0 0xffffffff 1 0 0b0000 x
0 0 0 0 1 0b0000 0
# write bytes
C 0 0xffffffff 1 0 0b0001 x
0 0 0 0 1 0b0000 0xff
C 0 0xffffff00 1 0 0b0010 x
0 0 0 0 1 0b0000 0xffff
C 0 0xffff0000 1 0 0b0100 x
0 0 0 0 1 0b0000 0xffffff
C 0 0xff000000 1 0 0b1000 x
0 0 0 0 1 0b0000 0xffffffff
# write 16 bit words
C 1 0xffff 1 0 0b0011 x
0 1 0 0 1 0b0000 0xffff
C 1 0xffff0000 1 0 0b1100 x
0 1 0 0 1 0b0000 0xffffffff
C 1 0xaaaa00 1 0 0b0110 x
0 1 0 0 1 0b0000 0xffaaaaff
# write 32 bit words
C 2 0xffffffff 1 0 0b1111 x
0 2 0 0 1 0b0000 0xffffffff
</dataString>
</testData>
</entry>
</elementAttributes>
<pos x="320" y="340"/>
</visualElement>
</visualElements>
<wires>
<wire>
<p1 x="460" y="240"/>
<p2 x="500" y="240"/>
</wire>
<wire>
<p1 x="260" y="180"/>
<p2 x="400" y="180"/>
</wire>
<wire>
<p1 x="380" y="260"/>
<p2 x="400" y="260"/>
</wire>
<wire>
<p1 x="380" y="200"/>
<p2 x="400" y="200"/>
</wire>
<wire>
<p1 x="260" y="280"/>
<p2 x="400" y="280"/>
</wire>
<wire>
<p1 x="260" y="220"/>
<p2 x="400" y="220"/>
</wire>
<wire>
<p1 x="380" y="300"/>
<p2 x="400" y="300"/>
</wire>
</wires>
</circuit>