mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-15 07:48:29 -04:00
adds dual-port multi-byte memory that allows single bytes to be overwritten; closes #231
This commit is contained in:
parent
2af7b15180
commit
9816cae471
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
184
src/test/resources/dig/test/RAM/maskedRAM.dig
Normal file
184
src/test/resources/dig/test/RAM/maskedRAM.dig
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user