summary refs log tree commit diff stats
path: root/hw/etraxfs_timer.c
diff options
context:
space:
mode:
authoredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-06-09 23:33:30 +0000
committeredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-06-09 23:33:30 +0000
commit5ef98b4742a291c732080c313051b1b36da1707d (patch)
treefe5b289f5af9c9d378f894fc24cef88b2e2d076c /hw/etraxfs_timer.c
parent1b1a38b0aaf3a24b9b8162d8aef9e700a42f8d43 (diff)
downloadfocaccia-qemu-5ef98b4742a291c732080c313051b1b36da1707d.tar.gz
focaccia-qemu-5ef98b4742a291c732080c313051b1b36da1707d.zip
ETRAX: Add NMI support to the watchdog and the interrupt controller.
* Add NMI and GURU exceptions to teh interrupt controller.
* Teach the watchdog timer to signal an NMI before reseting the chip.
* Add etraxfs.h to hold api for etrax device models.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4720 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/etraxfs_timer.c')
-rw-r--r--hw/etraxfs_timer.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 7353d45dec..e996c57f6a 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -46,6 +46,7 @@
 struct fs_timer_t {
 	CPUState *env;
 	qemu_irq *irq;
+	qemu_irq *nmi;
 	target_phys_addr_t base;
 
 	QEMUBH *bh_t0;
@@ -56,6 +57,8 @@ struct fs_timer_t {
 	ptimer_state *ptimer_wd;
 	struct timeval last;
 
+	int wd_hits;
+
 	/* Control registers.  */
 	uint32_t rw_tmr0_div;
 	uint32_t r_tmr0_data;
@@ -129,6 +132,7 @@ static void update_ctrl(struct fs_timer_t *t, int tnum)
 	unsigned int freq_hz;
 	unsigned int div;
 	uint32_t ctrl;
+
 	ptimer_state *timer;
 
 	if (tnum == 0) {
@@ -163,8 +167,8 @@ static void update_ctrl(struct fs_timer_t *t, int tnum)
 
 	D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
 	div = div * TIMER_SLOWDOWN;
-	div >>= 15;
-	freq_hz >>= 15;
+	div >>= 10;
+	freq_hz >>= 10;
 	ptimer_set_freq(timer, freq_hz);
 	ptimer_set_limit(timer, div, 0);
 
@@ -216,7 +220,18 @@ static void timer1_hit(void *opaque)
 
 static void watchdog_hit(void *opaque)
 {
-	qemu_system_reset_request();
+	struct fs_timer_t *t = opaque;
+	if (t->wd_hits == 0) {
+		/* real hw gives a single tick before reseting but we are
+		   a bit friendlier to compensate for our slower execution.  */
+		ptimer_set_count(t->ptimer_wd, 10);
+		ptimer_run(t->ptimer_wd, 1);
+		qemu_irq_raise(t->nmi[0]);
+	}
+	else
+		qemu_system_reset_request();
+
+	t->wd_hits++;
 }
 
 static inline void timer_watchdog_update(struct fs_timer_t *t, uint32_t value)
@@ -237,6 +252,11 @@ static inline void timer_watchdog_update(struct fs_timer_t *t, uint32_t value)
 	D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
 		 wd_en, new_key, wd_key, new_cmd, wd_cnt));
 
+	if (t->wd_hits)
+		qemu_irq_lower(t->nmi[0]);
+
+	t->wd_hits = 0;
+
 	ptimer_set_freq(t->ptimer_wd, 760);
 	if (wd_cnt == 0)
 		wd_cnt = 256;
@@ -320,7 +340,7 @@ static void etraxfs_timer_reset(void *opaque)
 	qemu_irq_lower(t->irq[0]);
 }
 
-void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, 
+void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, qemu_irq *nmi,
 			target_phys_addr_t base)
 {
 	static struct fs_timer_t *t;
@@ -337,6 +357,7 @@ void etraxfs_timer_init(CPUState *env, qemu_irq *irqs,
 	t->ptimer_t1 = ptimer_init(t->bh_t1);
 	t->ptimer_wd = ptimer_init(t->bh_wd);
 	t->irq = irqs;
+	t->nmi = nmi;
 	t->env = env;
 	t->base = base;