Finished MPROM support. Fixes #10
[Mograsim.git] / plugins / net.mograsim.machine / src / net / mograsim / machine / GenericMemory.java
1 package net.mograsim.machine;
2
3 import java.util.Arrays;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Set;
7
8 public abstract class GenericMemory<T, D extends MemoryDefinition> implements Memory<T>
9 {
10         private final long minimalAddress, maximalAddress;
11         private final D definition;
12         private final int pageSize = 64;
13         private Set<MemoryCellModifiedListener> observers = new HashSet<>();
14
15         private HashMap<Long, Page> pages;
16
17         public GenericMemory(D definition)
18         {
19                 super();
20                 this.definition = definition;
21                 this.minimalAddress = definition.getMinimalAddress();
22                 this.maximalAddress = definition.getMaximalAddress();
23                 this.pages = new HashMap<>();
24         }
25
26         private void inBoundsCheck(long address)
27         {
28                 if (address < minimalAddress || address > maximalAddress)
29                         throw new IndexOutOfBoundsException(String.format("Memory address out of bounds! Minimum: %d Maximum: %d Actual: %d",
30                                         minimalAddress, maximalAddress, address));
31         }
32
33         private long page(long address)
34         {
35                 return address / pageSize;
36         }
37
38         private int offset(long address)
39         {
40                 return (int) (address % pageSize);
41         }
42
43         @Override
44         public void setCell(long address, T data)
45         {
46                 inBoundsCheck(address);
47                 long page = page(address);
48                 int offset = offset(address);
49                 Page p = pages.get(Long.valueOf(page));
50                 if (p == null)
51                         pages.put(page, p = new Page());
52                 p.setCell(offset, data);
53                 notifyObservers(address);
54         }
55
56         @Override
57         public T getCell(long address)
58         {
59                 inBoundsCheck(address);
60                 long page = page(address);
61                 int offset = offset(address);
62                 Page p = pages.get(Long.valueOf(page));
63                 if (p == null)
64                         return null;
65                 return p.getCell(offset);
66         }
67
68         private class Page
69         {
70                 private T[] memory;
71
72                 @SuppressWarnings("unchecked")
73                 public Page()
74                 {
75                         memory = (T[]) new Object[pageSize];
76                 }
77
78                 public T getCell(int index)
79                 {
80                         return memory[index];
81                 }
82
83                 public void setCell(int index, T data)
84                 {
85                         memory[index] = data;
86                 }
87
88                 @Override
89                 public String toString()
90                 {
91                         return Arrays.deepToString(memory);
92                 }
93         }
94
95         @Override
96         public void registerCellModifiedListener(MemoryCellModifiedListener ob)
97         {
98                 observers.add(ob);
99         }
100
101         @Override
102         public void deregisterCellModifiedListener(MemoryCellModifiedListener ob)
103         {
104                 observers.remove(ob);
105         }
106
107         protected void notifyObservers(long address)
108         {
109                 observers.forEach(ob -> ob.update(address));
110         }
111
112         @Override
113         public D getDefinition()
114         {
115                 return definition;
116         }
117 }