--- /dev/null
+package net.mograsim.logic.core.components.gates;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import net.mograsim.logic.core.components.BasicComponent;
+import net.mograsim.logic.core.timeline.Timeline;
+import net.mograsim.logic.core.types.Bit;
+import net.mograsim.logic.core.types.BitVector;
+import net.mograsim.logic.core.wires.Wire.ReadEnd;
+import net.mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class WordAddressableMemoryComponent extends BasicComponent
+{
+ private final WordAddressableMemory memory;
+ private final static Bit read = Bit.ONE;
+
+ private ReadWriteEnd data;
+ private ReadEnd rWBit, address;
+
+ /**
+ *
+ * @param timeline
+ * @param processTime
+ * @param minimalAddress
+ * @param maximalAddress
+ * @param data
+ * @param rWBit 0: Write 1: Read
+ * @param address
+ */
+ public WordAddressableMemoryComponent(Timeline timeline, int processTime, long minimalAddress, long maximalAddress, ReadWriteEnd data,
+ ReadEnd rWBit, ReadEnd address)
+ {
+ super(timeline, processTime);
+ this.data = data;
+ this.rWBit = rWBit;
+ this.address = address;
+ data.registerObserver(this);
+ rWBit.registerObserver(this);
+ address.registerObserver(this);
+
+ memory = new WordAddressableMemory(data.length(), minimalAddress, maximalAddress);
+ }
+
+ @Override
+ protected void compute()
+ {
+ if (!address.hasNumericValue())
+ {
+ if (read.equals(rWBit.getValue()))
+ data.feedSignals(BitVector.of(Bit.U, data.length()));
+ else
+ data.clearSignals();
+ return;
+ }
+ long addressed = address.getUnsignedValue();
+ if (read.equals(rWBit.getValue()))
+ data.feedSignals(memory.getCell(addressed));
+ else
+ {
+ data.clearSignals();
+ System.out.println(memory);
+ memory.setCell(addressed, data.getValues());
+ }
+ }
+
+ @Override
+ public List<ReadEnd> getAllInputs()
+ {
+ return List.of(data, rWBit, address);
+ }
+
+ @Override
+ public List<ReadWriteEnd> getAllOutputs()
+ {
+ return List.of(data);
+ }
+
+ private class WordAddressableMemory
+ {
+ private final int cellWidth;
+ private final long minimalAddress, maximalAddress;
+ private final int pageSize;
+
+ private HashMap<Long, Page> pages;
+
+ public WordAddressableMemory(int cellWidth, long minimalAddress, long maximalAddress)
+ {
+ super();
+ this.cellWidth = cellWidth;
+ this.minimalAddress = minimalAddress;
+ this.maximalAddress = maximalAddress;
+ this.pages = new HashMap<>();
+ this.pageSize = 64;
+ }
+
+ public void setCell(long address, BitVector b)
+ {
+ if (address < minimalAddress || address > maximalAddress)
+ throw new IndexOutOfBoundsException(String.format("Memory address out of bounds! Minimum: %d Maimum: %d Actual: %d",
+ minimalAddress, maximalAddress, address));
+ long page = address / pageSize;
+ int offset = (int) (address % pageSize);
+ Page p = pages.get(Long.valueOf(page));
+ if (p == null)
+ pages.put(page, p = new Page());
+ p.setCell(offset, b);
+ }
+
+ public BitVector getCell(long address)
+ {
+ long page = address / pageSize;
+ int offset = (int) (address % pageSize);
+ Page p = pages.get(Long.valueOf(page));
+ if (p == null)
+ return BitVector.of(Bit.U, cellWidth);
+ return p.getCell(offset);
+ }
+
+ private class Page
+ {
+ private BitVector[] memory;
+
+ public Page()
+ {
+ memory = new BitVector[pageSize];
+ }
+
+ public BitVector getCell(int index)
+ {
+ BitVector b = memory[index];
+ if (b == null)
+ return BitVector.of(Bit.U, cellWidth);
+ return memory[index];
+ }
+
+ public void setCell(int index, BitVector bits)
+ {
+ if (bits.length() != cellWidth)
+ throw new IllegalArgumentException(
+ String.format("BitVector to be saved in memory cell has unexpected length. Expected: %d Actual: %d", cellWidth,
+ bits.length()));
+ memory[index] = bits;
+ }
+
+ @Override
+ public String toString()
+ {
+ return Arrays.deepToString(memory);
+ }
+ }
+ }
+}
+//import java.math.BigInteger;
+//
+//import net.mograsim.logic.core.types.Bit;
+//import net.mograsim.logic.core.types.BitVector;
+//
+//private byte[] encode(BitVector v)
+//{
+// BigInteger d = BigInteger.ZERO;
+// Bit[] bits = v.getBits();
+// for (int i = v.length() - 1; i >= 0; i--)
+// {
+// d = d.add(BigInteger.valueOf(bits[i].ordinal()));
+// d = d.multiply(BigInteger.valueOf(Bit.values().length));
+// }
+// return d.toByteArray();
+//}
+//
+///**
+// *
+// * @param bytes
+// * @param numBits length of the resulting BitVector
+// * @return
+// */
+//private BitVector decode(byte[] bytes, int numBits)
+//{
+// BigInteger d = new BigInteger(bytes);
+// Bit[] bits = new Bit[numBits];
+// return BitVector.of(bits);
+//}
+//
+//private static class CellArray
+//{
+// private byte[] bytes;
+// private final static byte mask = -1;
+// public CellArray(int numCells, int cellSize)
+// {
+// bytes = new byte[numCells * cellSize / 8];
+// }
+//
+// public byte[] getCell(int i)
+// {
+//
+// }
+//}
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
+import java.math.BigInteger;
+import java.util.Random;
import java.util.function.LongConsumer;
+import org.junit.Before;
import org.junit.jupiter.api.Test;
import net.mograsim.logic.core.components.Connector;
import net.mograsim.logic.core.components.gates.NorGate;
import net.mograsim.logic.core.components.gates.NotGate;
import net.mograsim.logic.core.components.gates.OrGate;
+import net.mograsim.logic.core.components.gates.WordAddressableMemoryComponent;
import net.mograsim.logic.core.components.gates.XorGate;
import net.mograsim.logic.core.timeline.Timeline;
import net.mograsim.logic.core.types.Bit;
{
private Timeline t = new Timeline(11);
+ @Before
+ void resetTimeline()
+ {
+ t.reset();
+ }
+
@Test
void circuitExampleTest()
{
@Test
void splitterTest()
{
- t.reset();
Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), in = new Wire(t, 8, 1);
in.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
new Splitter(t, in.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(), c.createReadWriteEnd());
@Test
void mergerTest()
{
- t.reset();
Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), out = new Wire(t, 8, 1);
a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO);
b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO);
@Test
void fusionTest1()
{
- t.reset();
Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), out = new Wire(t, 8, 1);
Wire.fuse(a, out, 0, 0, a.length);
Wire.fuse(b, out, 0, a.length, b.length);
@Test
void fusionTest2()
{
- t.reset();
Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 1);
Wire.fuse(a, b);
ReadWriteEnd rw = a.createReadWriteEnd();
@Test
void fusionTest3()
{
- t.reset();
Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 1);
a.createReadWriteEnd().feedSignals(Bit.Z, Bit.U, Bit.X);
t.executeAll();
@Test
void muxTest()
{
- t.reset();
Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), out = new Wire(t, 4, 1);
ReadWriteEnd selectIn = select.createReadWriteEnd();
@Test
void demuxTest()
{
- t.reset();
Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), in = new Wire(t, 4, 1);
ReadWriteEnd selectIn = select.createReadWriteEnd();
@Test
void andTest()
{
- t.reset();
Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);
new AndGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
@Test
void orTest()
{
- t.reset();
Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);
new OrGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
@Test
void nandTest()
{
- t.reset();
Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1), d = new Wire(t, 4, 1);
new NandGate(t, 1, d.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
@Test
void norTest()
{
- t.reset();
Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1), d = new Wire(t, 4, 1);
new NorGate(t, 1, d.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
@Test
void xorTest()
{
- t.reset();
Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2), c = new Wire(t, 3, 1), d = new Wire(t, 3, 1);
new XorGate(t, 1, d.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
@Test
void notTest()
{
- t.reset();
Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2);
new NotGate(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd());
a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
@Test
void rsLatchCircuitTest()
{
- t.reset();
Wire r = new Wire(t, 1, 1), s = new Wire(t, 1, 1), t1 = new Wire(t, 1, 15), t2 = new Wire(t, 1, 1), q = new Wire(t, 1, 1),
nq = new Wire(t, 1, 1);
@Test
void numericValueTest()
{
- t.reset();
-
Wire a = new Wire(t, 4, 1);
a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE);
@Test
void multipleInputs()
{
- t.reset();
Wire w = new Wire(t, 2, 1);
ReadWriteEnd wI1 = w.createReadWriteEnd(), wI2 = w.createReadWriteEnd();
wI1.feedSignals(Bit.ONE, Bit.Z);
{
// Nur ein Experiment, was über mehrere 'passive' Bausteine hinweg passieren würde
- t.reset();
-
Wire a = new Wire(t, 1, 2);
Wire b = new Wire(t, 1, 2);
Wire c = new Wire(t, 1, 2);
test2.assertAfterSimulationIs(Bit.ONE);
}
+ @Test
+ public void wordAddressableMemoryLargeTest()
+ {
+ Wire rW = new Wire(t, 1, 2);
+ Wire data = new Wire(t, 16, 2);
+ Wire address = new Wire(t, 64, 2);
+ ReadWriteEnd rWI = rW.createReadWriteEnd();
+ ReadWriteEnd dataI = data.createReadWriteEnd();
+ ReadWriteEnd addressI = address.createReadWriteEnd();
+
+ WordAddressableMemoryComponent memory = new WordAddressableMemoryComponent(t, 4, 4096L, Long.MAX_VALUE, data.createReadWriteEnd(),
+ rW.createReadOnlyEnd(), address.createReadOnlyEnd());
+
+ Random r = new Random();
+ for (long j = 1; j > 0; j *= 2)
+ {
+ for (int i = 0; i < 50; i++)
+ {
+ String sAddress = String.format("%64s", BigInteger.valueOf(4096 + i + j).toString(2)).replace(' ', '0');
+ sAddress = new StringBuilder(sAddress).reverse().toString();
+ BitVector bAddress = BitVector.parse(sAddress);
+ addressI.feedSignals(bAddress);
+ t.executeAll();
+ String random = BigInteger.valueOf(Math.abs(r.nextInt())).toString(5);
+ random = random.substring(Integer.max(0, random.length() - 16));
+ random = String.format("%16s", random).replace(' ', '0');
+ random = random.replace('2', 'X').replace('3', 'Z').replace('4', 'U');
+ BitVector vector = BitVector.parse(random);
+ dataI.feedSignals(vector);
+ rWI.feedSignals(Bit.ZERO);
+ t.executeAll();
+ rWI.feedSignals(Bit.ONE);
+ t.executeAll();
+ dataI.clearSignals();
+ t.executeAll();
+
+ assertBitArrayEquals(dataI.getValues(), vector.getBits());
+ }
+ }
+ }
+
private static void assertBitArrayEquals(BitVector actual, Bit... expected)
{
assertArrayEquals(expected, actual.getBits());