40873f0020e36c428f0202d77ac96e91d19803cf
[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> implements Memory<T>
9 {
10         private final long minimalAddress, maximalAddress;
11         private final MemoryDefinition 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(MemoryDefinition 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 Object[] memory;
71
72                 public Page()
73                 {
74                         memory = new Object[pageSize];
75                 }
76
77                 public T getCell(int index)
78                 {
79                         @SuppressWarnings("unchecked")
80                         T data = (T) memory[index];
81                         return data;
82                 }
83
84                 public void setCell(int index, T data)
85                 {
86                         memory[index] = data;
87                 }
88
89                 @Override
90                 public String toString()
91                 {
92                         return Arrays.deepToString(memory);
93                 }
94         }
95
96         @Override
97         public void registerCellModifiedListener(MemoryCellModifiedListener ob)
98         {
99                 observers.add(ob);
100         }
101
102         @Override
103         public void deregisterCellModifiedListener(MemoryCellModifiedListener ob)
104         {
105                 observers.remove(ob);
106         }
107
108         protected void notifyObservers(long address)
109         {
110                 observers.forEach(ob -> ob.update(address));
111         }
112
113         @Override
114         public MemoryDefinition getDefinition()
115         {
116                 return definition;
117         }
118 }