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();
232 for (k = 0; k < cellWidthBytes - wordBytes.length; k++)
233 bytes[i + k] = new MemoryByte();
234 for (int l = 0; k < cellWidthBytes; k++)
235 bytes[i + k] = new MemoryByte(wordBytes[l]);
237 for (int k = 0; k < cellWidthBytes; k++)
238 bytes[i + k] = new MemoryByte((byte) 0, (byte) 0);
244 public void setValue(BigInteger offset, byte[] bytes) throws DebugException
246 if (bytes.length % cellWidthBytes != 0)
247 throwDebugException("Requested unaligned memory write");
248 BigInteger startAddrWords = baseAddrWords.add(offset);
249 if (startAddrWords.compareTo(minAddrWords) < 0 || startAddrWords.compareTo(maxAddrWords) > 0)
250 throwDebugException("Start address out of range");
251 BigInteger endAddrWords = startAddrWords.add(BigInteger.valueOf(bytes.length / cellWidthBytes));
252 if (endAddrWords.compareTo(maxAddrWords) > 0)
253 throwDebugException("End address out of range");
255 unregisterMemoryListener();
259 for (i = 0, j = startAddrWords.longValue(); i < bytes.length; i += cellWidthBytes, j++)
261 BigInteger word = new BigInteger(bytes, i, cellWidthBytes);
262 mem.setCellAsBigInteger(j, word);
265 if (!clients.isEmpty())
266 registerMemoryListener();
267 fireContentChangeEvent();
271 public void connect(Object client)
273 registerMemoryListener();
278 public void disconnect(Object client)
280 clients.remove(client);
282 if (clients.isEmpty())
283 unregisterMemoryListener();
287 public Object[] getConnections()
290 Set<Object> clientsLocal = clients;
291 return clientsLocal == null ? new Object[0] : clientsLocal.toArray();
294 private void registerMemoryListener()
296 if (!memListenerRegistered.getAndSet(true))
297 mem.registerCellModifiedListener(memListener);
300 private void unregisterMemoryListener()
302 if (memListenerRegistered.getAndSet(false))
303 mem.deregisterCellModifiedListener(memListener);
307 public void dispose() throws DebugException
310 unregisterMemoryListener();
314 public IMemoryBlockRetrievalExtension getMemoryBlockRetrieval()
320 public int getAddressableSize() throws DebugException
322 return cellWidthBytes;
326 * Fires a terminate event for this debug element.
328 private void fireContentChangeEvent()
330 fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
334 * Fires a debug event.
336 * @param event debug event to fire
338 private static void fireEvent(DebugEvent event)
340 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
343 private static void throwDebugException(String message) throws DebugException
345 throw new DebugException(
346 new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, message, null));