Finished MPROM support. Fixes #10
[Mograsim.git] / plugins / net.mograsim.machine / src / net / mograsim / machine / standard / memory / CoreBitVectorMemory.java
1 package net.mograsim.machine.standard.memory;
2
3 import java.util.List;
4
5 import net.mograsim.logic.core.components.BasicCoreComponent;
6 import net.mograsim.logic.core.timeline.Timeline;
7 import net.mograsim.logic.core.timeline.TimelineEventHandler;
8 import net.mograsim.logic.core.types.Bit;
9 import net.mograsim.logic.core.types.BitVector;
10 import net.mograsim.logic.core.wires.CoreWire.ReadEnd;
11 import net.mograsim.logic.core.wires.CoreWire.ReadWriteEnd;
12 import net.mograsim.machine.BitVectorMemory;
13 import net.mograsim.machine.BitVectorMemoryDefinition;
14 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
15
16 /**
17  * A memory component that only allows access to words of a specific width
18  */
19 public class CoreBitVectorMemory<M extends BitVectorMemory> extends BasicCoreComponent
20 {
21         private final static Bit read = Bit.ONE;
22
23         private final ReadWriteEnd data;
24         private final ReadEnd rWBit, address;
25         private final boolean readonly;
26         private final MemoryCellModifiedListener memObs;
27         private final BitVectorMemoryDefinition definition;
28         private M memory;
29
30         /**
31          * @param data    The bits of this ReadEnd are the value that is written to/read from memory; The bit width of this wire is the width of
32          *                a memory word
33          * @param rWBit   The value of the 0th bit dictates the mode: 0: Write, 1: Read
34          * @param address The bits of this ReadEnd address the memory cell to read/write
35          */
36         public CoreBitVectorMemory(Timeline timeline, int processTime, BitVectorMemoryDefinition definition, ReadWriteEnd data, ReadEnd rWBit,
37                         ReadEnd address, boolean readonly)
38         {
39                 super(timeline, processTime);
40                 if (data.width() != definition.getCellWidth())
41                         throw new IllegalArgumentException(
42                                         String.format("Bit width of data wire does not match main memory definition. Expected: %d Actual: %d",
43                                                         definition.getCellWidth(), data.width()));
44                 if (!readonly && rWBit.width() != 1)
45                         throw new IllegalArgumentException(
46                                         String.format("Bit width of read/write mode select wire is unexpected. Expected: 1 Actual: %d", rWBit.width()));
47                 if (address.width() != definition.getMemoryAddressBits())
48                         throw new IllegalArgumentException(
49                                         String.format("Bit width of address wire does not match main memory definition. Expected: %d Actual: %d",
50                                                         definition.getMemoryAddressBits(), address.width()));
51                 this.data = data;
52                 this.rWBit = rWBit;
53                 this.address = address;
54                 this.readonly = readonly;
55                 this.definition = definition;
56                 this.memObs = a -> update();
57                 data.registerObserver(this);
58                 if (!readonly)
59                         rWBit.registerObserver(this);
60                 address.registerObserver(this);
61         }
62
63         public void setMemory(M memory)
64         {
65                 if (memory != null && !memory.getDefinition().equals(definition))
66                         throw new IllegalArgumentException("Memory of incorrect memory definition given");
67                 if (this.memory != null)
68                         this.memory.registerCellModifiedListener(memObs);
69                 this.memory = memory;
70                 if (memory != null)
71                         memory.registerCellModifiedListener(memObs);
72                 update();
73         }
74
75         public M getMemory()
76         {
77                 return memory;
78         }
79
80         @Override
81         protected TimelineEventHandler compute()
82         {
83                 if (memory == null)
84                         return e -> data.feedSignals(Bit.U.toVector(data.width()));
85                 boolean isReading = readonly || read.equals(rWBit.getValue());
86                 if (!address.getValues().isBinary())
87                 {
88                         if (isReading)
89                                 return e -> data.feedSignals(Bit.U.toVector(data.width()));// TODO don't always feed U, but decide to feed X or U.
90                         return e -> data.clearSignals();
91                 }
92                 long addressed = address.getValues().getUnsignedValueLong();
93                 if (isReading)
94                 {
95                         BitVector storedData = memory.getCell(addressed);
96                         return e -> data.feedSignals(storedData);
97                 }
98                 BitVector transData = data.getValues();
99                 boolean isNewData = !transData.equals(memory.getCell(addressed));
100                 return e ->
101                 {
102                         data.clearSignals();
103                         if (isNewData)
104                                 memory.setCell(addressed, transData);
105                 };
106         }
107
108         @Override
109         public List<ReadEnd> getAllInputs()
110         {
111                 return readonly ? List.of(data, address) : List.of(data, rWBit, address);
112         }
113
114         @Override
115         public List<ReadWriteEnd> getAllOutputs()
116         {
117                 return List.of(data);
118         }
119 }