From 7fff4149337201514f3af6698daeafd6b7109e52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Moritz=20'Morty'=20Str=C3=BCbe?= <morty@gmx.net>
Date: Mon, 5 Dec 2011 11:12:16 +0100
Subject: [PATCH] Add Proxy to CPUMonitor

---
 se/sics/mspsim/cli/DebugCommands.java |   10 ++-
 se/sics/mspsim/core/MSP430Core.java   |  177 ++++++++++++++++++++++++++-------
 2 files changed, 149 insertions(+), 38 deletions(-)

diff --git a/se/sics/mspsim/cli/DebugCommands.java b/se/sics/mspsim/cli/DebugCommands.java
index 95264d0..46e5feb 100644
--- a/se/sics/mspsim/cli/DebugCommands.java
+++ b/se/sics/mspsim/cli/DebugCommands.java
@@ -39,6 +39,8 @@
  *           $Revision$
  */
 package se.sics.mspsim.cli;
+import java.util.Hashtable;
+
 import se.sics.mspsim.core.CPUMonitor;
 import se.sics.mspsim.core.DbgInstruction;
 import se.sics.mspsim.core.DisAsm;
@@ -59,6 +61,8 @@ public class DebugCommands implements CommandBundle {
   private long lastCall = 0;
   private long lastWall = 0;
   private ComponentRegistry registry;
+  private Hashtable<Integer,CPUMonitor> breakpoints= new Hashtable<Integer,CPUMonitor>();
+  
 
   private ELF getELF() {
     return (ELF) registry.getComponent(ELF.class);
@@ -89,7 +93,7 @@ public class DebugCommands implements CommandBundle {
           return 0;
         }
         public void stopCommand(CommandContext context) {
-          cpu.clearBreakPoint(address);
+          cpu.removeBreakPoint(address, breakpoints.get(address));
         }
       });
 
@@ -159,7 +163,7 @@ public class DebugCommands implements CommandBundle {
         }
 
         public void stopCommand(CommandContext context) {
-          cpu.clearBreakPoint(address);
+          cpu.removeBreakPoint(address, breakpoints.get(address));
           context.exit(0);
         }
       });
@@ -200,7 +204,7 @@ public class DebugCommands implements CommandBundle {
         }
 
         public void stopCommand(CommandContext context) {
-          cpu.clearBreakPoint(register);
+        	cpu.removeBreakPoint(register, breakpoints.get(register));;
         }
       });
 
diff --git a/se/sics/mspsim/core/MSP430Core.java b/se/sics/mspsim/core/MSP430Core.java
index 224fc7f..3c41152 100644
--- a/se/sics/mspsim/core/MSP430Core.java
+++ b/se/sics/mspsim/core/MSP430Core.java
@@ -40,8 +40,13 @@
  */
 
 package se.sics.mspsim.core;
+
 import java.io.PrintStream;
+import java.security.InvalidParameterException;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.WeakHashMap;
+
 import se.sics.mspsim.util.ComponentRegistry;
 import se.sics.mspsim.util.MapEntry;
 import se.sics.mspsim.util.MapTable;
@@ -66,14 +71,14 @@ public class MSP430Core extends Chip implements MSP430Constants {
   // 16 registers of which some are "special" - PC, SP, etc.
   public int[] reg = new int[16];
 
-  public CPUMonitor globalMonitor;
+  private CPUMonitorProxy globalMonitor;
   
-  public CPUMonitor[] regWriteMonitors = new CPUMonitor[16];
-  public CPUMonitor[] regReadMonitors = new CPUMonitor[16];
+  private final CPUMonitorProxy[] regWriteMonitors = new CPUMonitorProxy[16];
+  private final CPUMonitorProxy[] regReadMonitors = new CPUMonitorProxy[16];
   
   // For breakpoints, etc... how should memory monitors be implemented?
   // Maybe monitors should have a "next" pointer...? or just have a [][]?
-  public CPUMonitor[] breakPoints;
+  private final CPUMonitorProxy[] breakPoints;
   // true => breakpoints can occur!
   boolean breakpointActive = true;
 
@@ -166,7 +171,7 @@ public class MSP430Core extends Chip implements MSP430Constants {
     MSP430XArch = config.MSP430XArch;
 
     memory = new int[MAX_MEM];
-    breakPoints = new CPUMonitor[MAX_MEM];
+    breakPoints = new CPUMonitorProxy[MAX_MEM];
 
     System.out.println("Set up MSP430 Core with " + MAX_MEM + " bytes memory");
     
@@ -289,7 +294,11 @@ public class MSP430Core extends Chip implements MSP430Constants {
   }
 
   public void setGlobalMonitor(CPUMonitor mon) {
-      globalMonitor = mon;
+      globalMonitor =  CPUMonitorProxy.getProxy(globalMonitor, mon, true);
+  }
+  
+  public void removeGlobalMonitor(CPUMonitor mon) {
+      globalMonitor =  CPUMonitorProxy.getProxy(globalMonitor, mon, false);
   }
 
   public ComponentRegistry getRegistry() {
@@ -355,23 +364,37 @@ public class MSP430Core extends Chip implements MSP430Constants {
   }
   
   public void setBreakPoint(int address, CPUMonitor mon) {
-    breakPoints[address] = mon;
+    breakPoints[address] = CPUMonitorProxy.getProxy(breakPoints[address], mon, true);
+  }
+  
+  public void removeBreakPoint(int address, CPUMonitor mon){
+	  breakPoints[address] = CPUMonitorProxy.getProxy(breakPoints[address], mon, false);
   }
 
   public boolean hasBreakPoint(int address) {
     return breakPoints[address] != null;
   }
   
+  
+  @Deprecated
   public void clearBreakPoint(int address) {
     breakPoints[address] = null;
   }
 
   public void setRegisterWriteMonitor(int r, CPUMonitor mon) {
-    regWriteMonitors[r] = mon;
+    regWriteMonitors[r] = CPUMonitorProxy.getProxy(regWriteMonitors[r], mon, true);
+  }
+  
+  public void removeRegisterWriteMonitor(int r, CPUMonitor mon) {
+    regWriteMonitors[r] = CPUMonitorProxy.getProxy(regWriteMonitors[r], mon, false);
   }
 
   public void setRegisterReadMonitor(int r, CPUMonitor mon) {
-    regReadMonitors[r] = mon;
+    regReadMonitors[r] = CPUMonitorProxy.getProxy(regReadMonitors[r], mon, true);
+  }
+  
+  public void removeRegisterReadMonitor(int r, CPUMonitor mon) {
+    regReadMonitors[r] = CPUMonitorProxy.getProxy(regReadMonitors[r], mon, false);
   }
 
   public int[] getMemory() {
@@ -380,9 +403,12 @@ public class MSP430Core extends Chip implements MSP430Constants {
   
   public void writeRegister(int r, int value) {
     // Before the write!
-    if (regWriteMonitors[r] != null) {
-      regWriteMonitors[r].cpuAction(CPUMonitor.REGISTER_WRITE, r, value);
-    }
+	{
+		CPUMonitor mon =regWriteMonitors[r];
+		if (mon != null) {
+			mon.cpuAction(CPUMonitor.REGISTER_WRITE, r, value);
+	    }
+	}
     reg[r] = value;
     if (r == SR) {
       boolean oldCpuOff = cpuOff;
@@ -425,8 +451,9 @@ public class MSP430Core extends Chip implements MSP430Constants {
   }
 
   public int readRegister(int r) {
-    if (regReadMonitors[r] != null) {
-      regReadMonitors[r].cpuAction(CPUMonitor.REGISTER_READ, r, reg[r]);
+	CPUMonitor mon = regReadMonitors[r];
+    if (mon != null) {
+      mon.cpuAction(CPUMonitor.REGISTER_READ, r, reg[r]);
     }
     return reg[r];
   }
@@ -437,19 +464,22 @@ public class MSP430Core extends Chip implements MSP430Constants {
       // No monitoring here... just return the CG values
       return CREG_VALUES[r - 2][m];
     }
-    if (regReadMonitors[r] != null) {
-      regReadMonitors[r].cpuAction(CPUMonitor.REGISTER_READ, r, reg[r]);
+    CPUMonitor mon = regReadMonitors[r];
+    if (mon != null) {
+      mon.cpuAction(CPUMonitor.REGISTER_READ, r, reg[r]);
     }
     return reg[r];
   }
 
   public int incRegister(int r, int value) {
-    if (regReadMonitors[r] != null) {
-      regReadMonitors[r].cpuAction(CPUMonitor.REGISTER_READ, r, reg[r]);
+	CPUMonitor mon;   
+	mon = regReadMonitors[r];  
+    if (mon != null) {
+      mon.cpuAction(CPUMonitor.REGISTER_READ, r, reg[r]);
     }
-    if (regWriteMonitors[r] != null) {
-      regWriteMonitors[r].cpuAction(CPUMonitor.REGISTER_WRITE, r,
-				    reg[r] + value);
+    mon = regWriteMonitors[r];
+	if (mon != null) {
+	  mon.cpuAction(CPUMonitor.REGISTER_WRITE, r, reg[r] + value);
     }
     reg[r] += value;
     return reg[r];
@@ -742,8 +772,11 @@ public class MSP430Core extends Chip implements MSP430Constants {
               }
           }
       }
-      if (breakPoints[address] != null) {
-          breakPoints[address].cpuAction(CPUMonitor.MEMORY_READ, address, val);
+      {
+    	  CPUMonitor bp = breakPoints[address];
+	      if ( bp != null) {
+	          bp.cpuAction(CPUMonitor.MEMORY_READ, address, val);
+	      }
       }
       /* is a null check as fast as a boolean check ?*/
       if (globalMonitor != null) {
@@ -759,10 +792,11 @@ public class MSP430Core extends Chip implements MSP430Constants {
           printWarning(ADDRESS_OUT_OF_BOUNDS_WRITE, dstAddress);
           dstAddress %= MAX_MEM;
       }
-      
-      if (breakPoints[dstAddress] != null) {
-      breakPoints[dstAddress].cpuAction(CPUMonitor.MEMORY_WRITE, dstAddress, dst);
-    }
+      CPUMonitor bp = breakPoints[dstAddress];
+      if (bp != null) {
+              bp.cpuAction(CPUMonitor.MEMORY_WRITE, dstAddress, dst);
+      }
+
     boolean word = mode != MODE_BYTE;
 
     // Only word writes at 0x1fe which is highest address...
@@ -943,14 +977,17 @@ public class MSP430Core extends Chip implements MSP430Constants {
 
     // This is quite costly... should probably be made more
     // efficiently
-    if (breakPoints[pc] != null) {
-      if (breakpointActive) {
-	breakPoints[pc].cpuAction(CPUMonitor.EXECUTE, pc, 0);
-	breakpointActive = false;
-	return -1;
-      }
-      // Execute this instruction - this is second call...
-      breakpointActive = true;
+    {
+    	CPUMonitor bp = breakPoints[pc]; //Temporary variable saves one lookop
+	    if (bp != null) {
+	      if (breakpointActive) {
+	    	  bp.cpuAction(CPUMonitor.EXECUTE, pc, 0);
+	    	  breakpointActive = false;
+	    	  return -1;
+	      }
+	      // Execute this instruction - this is second call...
+	      breakpointActive = true;
+	    }
     }
     if (globalMonitor != null) {
         globalMonitor.cpuAction(CPUMonitor.EXECUTE, pc, 0);
@@ -1614,3 +1651,73 @@ public class MSP430Core extends Chip implements MSP430Constants {
       return buf.toString();
   }
 }
+
+class CPUMonitorProxy implements CPUMonitor{
+
+	  //There is no WeakList, so let's use the WeakHashMap
+	  private static WeakHashMap<CPUMonitorProxy, Object> cache = new WeakHashMap<CPUMonitorProxy, Object>();
+	  
+	  synchronized static CPUMonitorProxy getProxy(CPUMonitorProxy oldproxy, CPUMonitor mon, boolean add){
+		  //Use ArrayList as it makes stuff simpler
+		  ArrayList<CPUMonitor> monlist;
+		  
+		  if(mon == null){
+			  throw new InvalidParameterException("Can't set null-monitor");
+		  }
+		  
+		  if(oldproxy != null){
+			  monlist = new ArrayList<CPUMonitor>(Arrays.asList(oldproxy.getMonitors()));
+		  } else {
+			  monlist = new ArrayList<CPUMonitor>(1);
+		  }
+		  boolean contains = monlist.contains(mon);
+		  
+		  if(add){
+			  if(!contains) monlist.add(mon);
+		  } else {
+			  if(contains) monlist.remove(mon);
+		  }
+
+		  //No need for empty stuff
+		  if(monlist.size() == 0){
+			  return null;
+		  }
+		  
+		  //Convert back to array
+		  CPUMonitor[] monarray = monlist.toArray(new CPUMonitor[0]);
+		  
+		  //Sort to allow comparing arrays
+		  Arrays.sort(monarray); 
+		  
+		  // Ok, lets check the cache, whether this proxy already exists
+		  // keySet() *should* strengthen all references during the loop 
+		  for(CPUMonitorProxy ref : cache.keySet()){
+			  if(Arrays.equals(ref.getMonitors(), monarray)){
+				  return ref;
+			  }
+		  }
+		  
+		  CPUMonitorProxy new_mon = new CPUMonitorProxy(monarray);
+		  cache.put(new_mon, null);
+		  return new_mon;
+	  }
+	  
+	  final private CPUMonitor[] mons;
+	  
+	  public CPUMonitorProxy(CPUMonitor[] mon) {
+		  mons= mon;
+	  }
+	  
+	  public CPUMonitor[] getMonitors() {
+		return mons;
+	  }
+		  
+	  public void cpuAction(int type, int adr, int data) {
+		  for(CPUMonitor mon : mons){
+			  mon.cpuAction(type, adr, data);
+		  }		
+	  }
+
+	  
+}
+
-- 
1.7.2.5

