miSim DE Back Index Next

Chapter 6 - Technical Details Continued

ProcessorListener Interface

The Processor listener interface allows a class to respond to the starting and stopping of simulation. There is only one method to implement:

 
  /**
   * Called when the simulation starts or stops.
   * @param state The new state of the processor, see the Processor STATE_ variables
   * @param message A text message describing the event that has occured
   * @see Processor#getState
   */
   public void processorStateChange( int state, String message );

The parameter 'state' is defined in the Processor class and may be one of:

StateMeaning
STATE_CLEAR - The processor has no program loaded
STATE_LOADED - A program and associated data is loaded
STATE_RUNNING - The processor is running the loaded program
STATE_STOPPED - The running program has been stopped
STATE_HALTED - The running program terminated unexpectedly

Normally, a Plugin would respond to the STATE_STOPPED event to update any display at the end of a 'Step' or 'Over' button click, or when 'Stop' is clicked to stop a running simulation. The STATE_HALTED event may occur if a Plugin causes an exception, or a breakpoint is reached.

The message parameter to the processorStateChange method is a text description of the event that has ocurred, and is the same as the messages displayed in the log file when 'Step', 'Over' etc. are clicked. Note however, that this text cannot be relied upon, as internationalisation may change the exact values of message.


ClockListener Interface

In fact, a Plugin should not implement the ClockListener interface, but its sub class ChainedClockListener. A ClockListener that has been added to the MachineState will be notified after each instruction is simulated, so long as the miSim DE preferences are set to 'Accurate' simulation. Typically, the clock listener will therefore be called after one or two clock cycles (depending on the instruction being simulated). However, if 'Fast Loop Simulation' is enabled in the miSim DE preferences dialog, the clock listener will be called at the end of empty delay loops, which may take a few hundred clock cycles.

Clock Listeners can therefore perform tasks that are exactly synchronised with the processor clock - for instance, a listener could use the information to generate a serial input to the microcontroller. If a Plugin only needs to respond to output from the microcontroller, and can be coded to only change its state when the microcontroller changes its output, then a much more efficient PortListener should be used in the place of a Clock Listener. If however, the Clock Listener preforms functions completely independantly of the output from the microcontroller, a ClockListener should be used with the associated speed penalties.

ChainedClockListener Methods

The following methods must be written for Plugins that implement ChainedClockListener.

 
  /**
   * Prepare for simulation, beginning at the given clock count
   * @param clocks The clock count that simulation will start at
   */
   public void prepare( long clocks ) {

   }

The Prepare method is called when simulation is about to start. Note that the clock count may change between simulation runs, so the prepare method may need to restart any internal timers with the new value.

 
  /**
   * This method is called after each instruction is executed. Note that
   * the number of clocks since the last call may be more than 1. This 
   * will occur for some branch instructions, and when loops have been
   * optimised - resulting in a sequence of loop instructions being 
   * simulated in a single atomic event.
   * @param clocks The current clock count for the processor
   */
   public void clockEvent( long clocks ) {
      nextListener.clockEvent( clocks );

      ... Plugin code...
   }

The clock event method is called after each instruction is simulated. Note that the chained clock listener interface requires that at the start of this method, the next listener in the chain is called. As the ChainedClockListener is defined as an interface, the implementation is up to the author of the plugin, but code much like that shown here should be used. This assumes that a variable 'nextListener' of type 'ClockListener' is declared in the Plugin class, and set by the following method:

 
  /** 
   * Set the next event handler in the chain. The implementation of
   * this class MUST call nextListener.clockEvent at the start of the
   * clockEvent method - ie. it must honour the chain.
   * @param nextListener The next clock event listener in the chain
   */
   public void setNext( ClockListener nextListener ) {

   }

When a ChainedClock listener is added to the MachineState so that it can respond to clock events, the MachineState will immediately call setNext to inform the listener of the next ClockListener in the chain. This should be stored by this method so that the clockEvent method above can call the next listener in the chain, and the getNext method below can return the next listener.

 
  /** 
   * Return the next event handler in the chain. 
   * @return The next event handler in the chain
   */
   public ClockListener getNext() {

   }

This method is used by the MachineState to handle chains of clockListeners, and should return the next listener in the chain - set by the setNext method above.

Before a clock listener can be notified of clock events, it must be added to the simulator's MachineState object. When a Plugin is closed, or no longer needs to respond to clock events, it should remove the clockListener from the MachineState. The following two methods are defined in MachineState to add and remove listeners:

 
  /**
   * Add a chained clock listener to this machine. If the new listener
   * has already been added, this will do nothing.
   * @param newListener The clock listener to add to the chain..
   */
   public void addClockListener( ChainedClockListener newListener )

To add a clock listener, and:

 
  /**
   * Remove a chained clock listener from this machine..
   * @param aListener The event handler to remove to the chain..
   */
   public void removeClockListener( ChainedClockListener aListener )

To remove it.

Why Two Interfaces?

To ensure that processing of many ClockListeners is as efficient as possible, two interfaces are provided. The basic Clock Listener interface does not need to concern itself with any other clock listeners, and simply handles clock events. miSim DE will always have a Clock Listener defined, and call this after each instruction in 'Accurate' simulation. Each additional Clock Listener (for instance a Plugin, or the BreakpointManager which is implemented as a ClockListener) must implement the ChainedClockListener interface. The ChainedClockListener is guaranteed to be one of a number of ClockListeners, and must call the next in the chain to process the clock event. This means that the simulator can call the ClockListener at the head of the chain and that can call the next without requiring any tests. The last Listener in the chain implements only the ClockListener interface (as it must be the last in the chain), and doesn't need to pass on the clock event.


PortMapper Class

The PortMapper class can be used when a Plugin has many connections to the microcontroller, and needs to allow the user to join them in different ways. A PortMapper is expensive (slow) to create, but then can translate signals into and out of the microcontroller relatively quickly. If there are only one or two connections to be managed, however, it is likely to be much quicker to handle them directly. As example of a Plugin the is well suited to using the PortMapper, the LCD Plugin has three control signals and either four or eight bi-directional data signals that must be mapped onto the microcontroller's pins. Infact, the PortMapper was written for the LCD Plugin, but with a generalised interface allowing other Plugins to use it.

To develop using the PortMapper, it is necessary to understand how it behaves. Again, the best example of this is the LCD Plugin and both that and how to use the PortMapper from the user's perspective is explained on the first Plugins Page - See 'Configuring Plugins' and 'LCD Plugin'. The Config string is used to create a new PortMapper, which then provides methods to examine which ports, pins and signals are mapped between the Plugin and the microcontroller. The most significant methods for the port mapper are 'prepare', 'read' and 'writeToPort'. 'Prepare' and 'read' are used together, when a Plugin wishes to read information from the microcontroller. 'Prepare' stores the microcontroller's outputs in the PortMapper so that subsequent calls to 'read' can read out individual bits, or collections of bits. 'WriteToPort' writes data from the Plugin to the port's inputs.

As the PortMapper class is complex, and many of the methods are important, this manual will not attempt to list and describe them all. The Class and methods are all documented in the Javadocs for miSim DE, and this is an ideal place to start when developing Plugins.

Index Next