1 package net.mograsim.plugin.launch;
3 import java.math.BigInteger;
4 import java.util.HashSet;
6 import java.util.concurrent.atomic.AtomicBoolean;
8 import org.eclipse.core.runtime.IStatus;
9 import org.eclipse.core.runtime.PlatformObject;
10 import org.eclipse.core.runtime.Status;
11 import org.eclipse.debug.core.DebugEvent;
12 import org.eclipse.debug.core.DebugException;
13 import org.eclipse.debug.core.DebugPlugin;
14 import org.eclipse.debug.core.ILaunch;
15 import org.eclipse.debug.core.model.IDebugTarget;
16 import org.eclipse.debug.core.model.IMemoryBlockExtension;
17 import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
18 import org.eclipse.debug.core.model.MemoryByte;
20 import net.mograsim.machine.MainMemory;
21 import net.mograsim.machine.MainMemoryDefinition;
22 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
23 import net.mograsim.plugin.MograsimActivator;
25 public class MainMemoryBlockExtension extends PlatformObject implements IMemoryBlockExtension
27 // TODO do we want to make the memory accessible byte-wise?
29 private final String expression;
30 private final MachineDebugTarget debugTarget;
31 private final MainMemory mem;
33 private final MainMemoryDefinition memDef;
34 private final int cellWidthBits;
35 private final int cellWidthBytes;
36 private final BigInteger cellWidthBytesBI;
37 private final BigInteger minAddrWords;
38 private final BigInteger maxAddrWords;
40 private BigInteger baseAddrWords;
41 private BigInteger lengthWords;
43 private final Set<Object> clients;
44 private final MemoryCellModifiedListener memListener;
45 private final AtomicBoolean memListenerRegistered;
47 public MainMemoryBlockExtension(MachineDebugTarget debugTarget, String expression, @SuppressWarnings("unused") Object expressionContext)
50 this.expression = expression;
51 this.debugTarget = debugTarget;
52 this.mem = debugTarget.getMachine().getMainMemory();
54 this.memDef = mem.getDefinition();
55 this.cellWidthBits = memDef.getCellWidth();
56 this.cellWidthBytes = (cellWidthBits + 7) / 8;
57 this.cellWidthBytesBI = BigInteger.valueOf(cellWidthBytes);
58 this.minAddrWords = BigInteger.valueOf(memDef.getMinimalAddress());
59 this.maxAddrWords = BigInteger.valueOf(memDef.getMaximalAddress());
61 // TODO parse expression better
62 this.baseAddrWords = new BigInteger(expression, 16);
63 this.lengthWords = BigInteger.ONE;
65 if (baseAddrWords.compareTo(minAddrWords) < 0 || baseAddrWords.compareTo(maxAddrWords) > 0)
66 throwDebugException("Base address out of range");
67 if (baseAddrWords.add(lengthWords).compareTo(maxAddrWords) > 0)
68 throwDebugException("End address out of range");
70 this.clients = new HashSet<>();
71 // don't check whether the address is in range, because this memory block could be read outside its "range"
72 this.memListener = a -> fireContentChangeEvent();
73 this.memListenerRegistered = new AtomicBoolean();
77 public long getStartAddress()
79 return baseAddrWords.multiply(cellWidthBytesBI).longValueExact();
83 public long getLength()
85 return lengthWords.multiply(cellWidthBytesBI).longValueExact();
89 public byte[] getBytes() throws DebugException
91 BigInteger endAddrWords = baseAddrWords.add(lengthWords);
92 if (endAddrWords.compareTo(maxAddrWords) > 0)
93 throwDebugException("End address out of range");
94 int lengthBytes = lengthWords.multiply(cellWidthBytesBI).intValueExact();
96 byte[] bytes = new byte[lengthBytes];
99 for (i = 0, j = baseAddrWords.longValue(); i < lengthBytes; i += cellWidthBytes, j++)
101 BigInteger word = mem.getCellAsBigInteger(j);
102 System.arraycopy(word.toByteArray(), 0, bytes, i, cellWidthBytes);
108 public boolean supportsValueModification()
114 public void setValue(long offset, byte[] bytes) throws DebugException
116 if (offset % cellWidthBytes != 0 || bytes.length % cellWidthBytes != 0)
117 throwDebugException("Requested unaligned memory write");
118 BigInteger startAddrWords = baseAddrWords.add(BigInteger.valueOf(offset / cellWidthBytes));
119 if (startAddrWords.compareTo(minAddrWords) < 0 || startAddrWords.compareTo(maxAddrWords) > 0)
120 throwDebugException("Start address out of range");
122 BigInteger endAddrWords = startAddrWords.add(BigInteger.valueOf(bytes.length / cellWidthBytes));
123 if (endAddrWords.compareTo(maxAddrWords) > 0)
124 throwDebugException("End address out of range");
128 for (i = 0, j = startAddrWords.longValue(); i < bytes.length; i += cellWidthBytes, j++)
130 BigInteger word = new BigInteger(bytes, i, cellWidthBytes);
131 mem.setCellAsBigInteger(j, word);
136 public String getModelIdentifier()
138 return MograsimActivator.PLUGIN_ID;
142 public IDebugTarget getDebugTarget()
148 public ILaunch getLaunch()
150 return debugTarget.getLaunch();
154 public String getExpression()
160 public BigInteger getBigBaseAddress() throws DebugException
162 return baseAddrWords;
166 public BigInteger getMemoryBlockStartAddress() throws DebugException
172 public BigInteger getMemoryBlockEndAddress() throws DebugException
178 public BigInteger getBigLength() throws DebugException
180 return maxAddrWords.subtract(minAddrWords);
184 public int getAddressSize() throws DebugException
190 public boolean supportBaseAddressModification() throws DebugException
196 public boolean supportsChangeManagement()
202 public void setBaseAddress(BigInteger address) throws DebugException
204 if (address.compareTo(minAddrWords) < 0 || address.compareTo(maxAddrWords) > 0)
205 throwDebugException("Address out of range");
206 this.baseAddrWords = address;
210 public MemoryByte[] getBytesFromOffset(BigInteger unitOffset, long addressableUnits) throws DebugException
212 return getBytesFromAddress(getBigBaseAddress().add(unitOffset), addressableUnits);
216 public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException
219 throwDebugException("Requested negative amount of unites");
220 int lengthBytes = BigInteger.valueOf(units).multiply(cellWidthBytesBI).intValueExact();
222 MemoryByte[] bytes = new MemoryByte[lengthBytes];
225 for (i = 0, j = address; i < lengthBytes; i += cellWidthBytes, j = j.add(BigInteger.ONE))
227 if (j.compareTo(minAddrWords) >= 0 && j.compareTo(maxAddrWords) <= 0)
229 BigInteger word = mem.getCellAsBigInteger(j.longValue());
230 byte[] wordBytes = word.toByteArray();
231 int l = wordBytes[0] == 0 ? 1 : 0;
233 for (k = 0; k < cellWidthBytes - wordBytes.length + l; k++)
234 bytes[i + k] = new MemoryByte();
235 for (; k < cellWidthBytes; k++, l++)
236 bytes[i + k] = new MemoryByte(wordBytes[l]);
238 for (int k = 0; k < cellWidthBytes; k++)
239 bytes[i + k] = new MemoryByte((byte) 0, (byte) 0);
245 public void setValue(BigInteger offset, byte[] bytes) throws DebugException
247 if (bytes.length % cellWidthBytes != 0)
248 throwDebugException("Requested unaligned memory write");
249 BigInteger startAddrWords = baseAddrWords.add(offset);
250 if (startAddrWords.compareTo(minAddrWords) < 0 || startAddrWords.compareTo(maxAddrWords) > 0)
251 throwDebugException("Start address out of range");
252 BigInteger endAddrWords = startAddrWords.add(BigInteger.valueOf(bytes.length / cellWidthBytes));
253 if (endAddrWords.compareTo(maxAddrWords) > 0)
254 throwDebugException("End address out of range");
256 unregisterMemoryListener();
260 for (i = 0, j = startAddrWords.longValue(); i < bytes.length; i += cellWidthBytes, j++)
262 BigInteger word = new BigInteger(bytes, i, cellWidthBytes);
263 mem.setCellAsBigInteger(j, word);
266 if (!clients.isEmpty())
267 registerMemoryListener();
268 fireContentChangeEvent();
272 public void connect(Object client)
274 registerMemoryListener();
279 public void disconnect(Object client)
281 clients.remove(client);
283 if (clients.isEmpty())
284 unregisterMemoryListener();
288 public Object[] getConnections()
291 Set<Object> clientsLocal = clients;
292 return clientsLocal == null ? new Object[0] : clientsLocal.toArray();
295 private void registerMemoryListener()
297 if (!memListenerRegistered.getAndSet(true))
298 mem.registerCellModifiedListener(memListener);
301 private void unregisterMemoryListener()
303 if (memListenerRegistered.getAndSet(false))
304 mem.deregisterCellModifiedListener(memListener);
308 public void dispose() throws DebugException
311 unregisterMemoryListener();
315 public IMemoryBlockRetrievalExtension getMemoryBlockRetrieval()
321 public int getAddressableSize() throws DebugException
323 return cellWidthBytes;
327 * Fires a terminate event for this debug element.
329 private void fireContentChangeEvent()
331 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
335 * Fires a debug event.
337 * @param event debug event to fire
339 private static void fireEvent(DebugEvent event)
341 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
344 private static void throwDebugException(String message) throws DebugException
346 throw new DebugException(
347 new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, message, null));