MemoryView is now updated when the memory is modified
[Mograsim.git] / net.mograsim.machine / src / net / mograsim / machine / standard / memory / WordAddressableMemory.java
1 package net.mograsim.machine.standard.memory;
2
3 import java.math.BigInteger;
4 import java.util.Arrays;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.Set;
8
9 import net.mograsim.logic.core.types.Bit;
10 import net.mograsim.logic.core.types.BitVector;
11 import net.mograsim.machine.MainMemory;
12 import net.mograsim.machine.MainMemoryDefinition;
13 import net.mograsim.machine.MemoryObserver;
14
15 public class WordAddressableMemory implements MainMemory
16 {
17         private final int cellWidth;
18         private final long minimalAddress, maximalAddress;
19         private final MainMemoryDefinition definition;
20         private final int pageSize = 64;
21         private Set<MemoryObserver> observers = new HashSet<>();
22
23         private HashMap<Long, Page> pages;
24
25         public WordAddressableMemory(MainMemoryDefinition definition)
26         {
27                 super();
28                 this.cellWidth = definition.getCellWidth();
29                 this.minimalAddress = definition.getMinimalAddress();
30                 this.maximalAddress = definition.getMaximalAddress();
31                 this.definition = definition;
32                 this.pages = new HashMap<>();
33         }
34         
35         private void inBoundsCheck(long address)
36         {
37                 if (address < minimalAddress || address > maximalAddress)
38                         throw new IndexOutOfBoundsException(String.format("Memory address out of bounds! Minimum: %d Maximum: %d Actual: %d",
39                                         minimalAddress, maximalAddress, address));
40         }
41
42         private long page(long address)
43         {
44                 return address / pageSize;
45         }
46         
47         private int offset(long address)
48         {
49                 return (int) (address % pageSize);
50         }
51         
52         @Override
53         public void setCell(long address, BitVector b)
54         {
55                 inBoundsCheck(address);
56                 long page = page(address);
57                 int offset = offset(address);
58                 Page p = pages.get(Long.valueOf(page));
59                 if (p == null)
60                         pages.put(page, p = new Page());
61                 p.setCell(offset, b);
62                 notifyObservers(address);
63         }
64
65         @Override
66         public BitVector getCell(long address)
67         {
68                 inBoundsCheck(address);
69                 long page = page(address);
70                 int offset = offset(address);
71                 Page p = pages.get(Long.valueOf(page));
72                 if (p == null)
73                         return BitVector.of(Bit.ZERO, cellWidth);
74                 return p.getCell(offset);
75         }
76         
77         @Override
78         public BigInteger getCellAsBigInteger(long address)
79         {
80                 inBoundsCheck(address);
81                 long page = page(address);
82                 int offset = offset(address);
83                 Page p = pages.get(Long.valueOf(page));
84                 if (p == null)
85                         return BigInteger.valueOf(0L);
86                 return p.getCellAsBigInteger(offset);
87         }
88
89         @Override
90         public void setCellAsBigInteger(long address, BigInteger word)
91         {
92                 inBoundsCheck(address);
93                 long page = page(address);
94                 int offset = offset(address);
95                 Page p = pages.get(Long.valueOf(page));
96                 if (p == null)
97                         pages.put(page, p = new Page());
98                 p.setCellAsBigInteger(offset, word);
99                 notifyObservers(address);
100         }
101
102         private class Page
103         {
104                 private BitVector[] memory;
105
106                 public Page()
107                 {
108                         memory = new BitVector[pageSize];
109                 }
110
111                 public BitVector getCell(int index)
112                 {
113                         BitVector b = memory[index];
114                         if (b == null)
115                                 return BitVector.of(Bit.ZERO, cellWidth);
116                         return memory[index];
117                 }
118
119                 public void setCell(int index, BitVector bits)
120                 {
121                         if (bits.length() != cellWidth)
122                                 throw new IllegalArgumentException(String.format(
123                                                 "BitVector to be saved in memory cell has unexpected width. Expected: %d Actual: %d", cellWidth, bits.length()));
124                         memory[index] = bits;
125                 }
126
127                 public void setCellAsBigInteger(int index, BigInteger bits)
128                 {
129                         setCell(index, BitVector.from(bits, cellWidth));
130                 }
131                 
132                 public BigInteger getCellAsBigInteger(int index)
133                 {
134                         try {
135                                 return getCell(index).getUnsignedValue();
136                         }
137                         catch(NumberFormatException e)
138                         {
139                                 throw new MemoryException(e);
140                         }
141                 }
142
143                 @Override
144                 public String toString()
145                 {
146                         return Arrays.deepToString(memory);
147                 }
148         }
149
150         @Override
151         public MainMemoryDefinition getDefinition()
152         {
153                 return definition;
154         }
155
156         @Override
157         public void registerObserver(MemoryObserver ob)
158         {
159                 observers.add(ob);
160         }
161
162         @Override
163         public void deregisterObserver(MemoryObserver ob)
164         {
165                 observers.remove(ob);
166         }
167
168         @Override
169         public void notifyObservers(long address)
170         {
171                 observers.forEach(ob -> ob.update(address));
172         }
173 }