mspsim/se/sics/mspsim/core/Watchdog.java

166 lines
5.8 KiB
Java

/**
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of MSPSim.
*
* $Id: $
*
* -----------------------------------------------------------------
*
* Watchdog
*
* Author : Joakim Eriksson
* Created : 22 apr 2008
* Updated : $Date:$
* $Revision:$
*/
package se.sics.mspsim.core;
import se.sics.mspsim.util.Utils;
/**
* @author joakim
*
*/
public class Watchdog extends IOUnit implements SFRModule {
private static final int WDTCTL = 0x120;
private static final int WDTHOLD = 0x80;
private static final int WDTCNTCL = 0x08;
private static final int WDTMSEL = 0x10;
private static final int WDTSSEL = 0x04;
private static final int WDTISx = 0x03;
private static final int WATCHDOG_VECTOR = 10;
private static final int WATCHDOG_INTERRUPT_BIT = 0;
private static final int WATCHDOG_INTERRUPT_VALUE = 1 << WATCHDOG_INTERRUPT_BIT;
private static final int RESET_VECTOR = 15;
private static final int[] DELAY = {
32768, 8192, 512, 64
};
private int wdtctl;
public boolean wdtOn = true;
private boolean hold = false;
private MSP430Core cpu;
// The current "delay" when started/clered (or hold)
private int delay;
// The target time for this timer
private long targetTime;
// Timer ACLK
private boolean sourceACLK = false;
// Timer or WDT mode
private boolean timerMode = false;
private TimeEvent wdtTrigger = new TimeEvent(0, "Watchdog") {
public void execute(long t) {
// System.out.println(getName() + " **** executing update timers at " + t + " cycles=" + core.cycles);
triggerWDT(t);
}
};
public Watchdog(MSP430Core cpu) {
super("Watchdog", cpu.memory, 0x120);
this.cpu = cpu;
cpu.getSFR().registerSFDModule(0, WATCHDOG_INTERRUPT_BIT, this, WATCHDOG_VECTOR);
}
public void interruptServiced(int vector) {
cpu.flagInterrupt(vector, this, false);
}
private void triggerWDT(long time) {
// Here the WDT triggered!!!
if (timerMode) {
SFR sfr = cpu.getSFR();
sfr.setBitIFG(0, WATCHDOG_INTERRUPT_VALUE);
scheduleTimer();
System.out.println("WDT trigger - will set interrupt flag (no reset)");
cpu.generateTrace(System.out);
} else {
System.out.println("WDT trigger - will reset node!");
cpu.generateTrace(System.out);
cpu.flagInterrupt(RESET_VECTOR, this, true);
}
}
public int read(int address, boolean word, long cycles) {
if (address == WDTCTL) return wdtctl | 0x6900;
return 0;
}
public void write(int address, int value, boolean word, long cycles) {
if (address == WDTCTL) {
if ((value >> 8) == 0x5a) {
wdtctl = value & 0xff;
if (DEBUG) log("Wrote to WDTCTL: " + Utils.hex8(wdtctl) + " from $" + Utils.hex(cpu.getPC(), 4));
// Is it on?
wdtOn = (value & 0x80) == 0;
// boolean lastACLK = sourceACLK;
sourceACLK = (value & WDTSSEL) != 0;
if ((value & WDTCNTCL) != 0) {
// Clear timer => reset the delay
delay = DELAY[value & WDTISx];
}
timerMode = (value & WDTMSEL) != 0;
// Start it if it should be started!
if (wdtOn) {
if (DEBUG) log("Setting WDTCNT to count: " + delay);
scheduleTimer();
} else {
// Stop it and remember current "delay" left!
wdtTrigger.remove();
}
} else {
// Trigger reset!!
logw("illegal write to WDTCTL (" + value + ") from $" + Utils.hex(cpu.getPC(), 4)
+ " - reset!!!!");
cpu.flagInterrupt(RESET_VECTOR, this, true);
}
}
}
private void scheduleTimer() {
if (sourceACLK) {
if (DEBUG) log("setting delay in ms (ACLK): " + 1000.0 * delay / cpu.aclkFrq);
targetTime = cpu.scheduleTimeEventMillis(wdtTrigger, 1000.0 * delay / cpu.aclkFrq);
} else {
if (DEBUG) log("setting delay in cycles");
cpu.scheduleCycleEvent(wdtTrigger, targetTime = cpu.cycles + delay);
}
}
public void enableChanged(int reg, int bit, boolean enabled) {
if (DEBUG) log("*** Watchdog module enabled: " + enabled);
}
}