From: Michel Pollet <buserror@gmail.com>
Date: Tue, 22 Feb 2011 12:48:31 +0000 (+0000)
Subject: core: Introduce run() and sleep() callbacks
X-Git-Tag: v1.0a7~27
X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=335869fab028466961751b8e2a5a9ebd1ac50d46;p=sx%2Fsimavr.git

core: Introduce run() and sleep() callbacks

It seems that the default 'run_avr' function was penalized by
some tests made that were only useful when gdb was active.

This patch introduces two version of the critical run_avr, one for
"raw" running, and one for gdb.

It also introduces a sleep() callback for similar reasons. Ir can
also be used to run unit testing at 100% speed instead of having
random sleep code during execution.

Signed-off-by: Michel Pollet <buserror@gmail.com>
---

diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c
index d5611ba..e13117d 100644
--- a/simavr/sim/sim_avr.c
+++ b/simavr/sim/sim_avr.c
@@ -45,6 +45,9 @@ int avr_init(avr_t * avr)
 		avr->special_init(avr);
 	if (avr->init)
 		avr->init(avr);
+	// set default (non gdb) fast callbacks
+	avr->run = avr_callback_run_raw;
+	avr->sleep = avr_callback_sleep_raw;
 	avr->state = cpu_Running;
 	avr_reset(avr);	
 	return 0;
@@ -158,13 +161,19 @@ void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
 	memcpy(avr->flash + address, code, size);
 }
 
+void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong)
+{
+	uint32_t usec = avr_cycles_to_usec(avr, howLong);
+	while (avr_gdb_processor(avr, usec))
+		;
+}
 
-int avr_run(avr_t * avr)
+void avr_callback_run_gdb(avr_t * avr)
 {
 	avr_gdb_processor(avr, avr->state == cpu_Stopped);
 
 	if (avr->state == cpu_Stopped)
-		return avr->state;
+		return ;
 
 	// if we are stepping one instruction, we "run" for one..
 	int step = avr->state == cpu_Step;
@@ -201,13 +210,7 @@ int avr_run(avr_t * avr)
 		/*
 		 * try to sleep for as long as we can (?)
 		 */
-		uint32_t usec = avr_cycles_to_usec(avr, sleep);
-	//	printf("sleep usec %d cycles %d\n", usec, sleep);
-		if (avr->gdb) {
-			while (avr_gdb_processor(avr, usec))
-				;
-		} else
-			usleep(usec);
+		avr->sleep(avr, sleep);
 		avr->cycle += 1 + sleep;
 	}
 	// Interrupt servicing might change the PC too, during 'sleep'
@@ -218,6 +221,59 @@ int avr_run(avr_t * avr)
 	if (step)
 		avr->state = cpu_StepDone;
 
+}
+
+void avr_callback_sleep_raw(avr_t * avr, avr_cycle_count_t howLong)
+{
+	uint32_t usec = avr_cycles_to_usec(avr, howLong);
+	usleep(usec);
+}
+
+void avr_callback_run_raw(avr_t * avr)
+{
+
+	uint16_t new_pc = avr->pc;
+
+	if (avr->state == cpu_Running) {
+		new_pc = avr_run_one(avr);
+#if CONFIG_SIMAVR_TRACE
+		avr_dump_state(avr);
+#endif
+	}
+
+	// if we just re-enabled the interrupts...
+	// double buffer the I flag, to detect that edge
+	if (avr->sreg[S_I] && !avr->i_shadow)
+		avr->pending_wait++;
+	avr->i_shadow = avr->sreg[S_I];
+
+	// run the cycle timers, get the suggested sleeo time
+	// until the next timer is due
+	avr_cycle_count_t sleep = avr_cycle_timer_process(avr);
+
+	avr->pc = new_pc;
+
+	if (avr->state == cpu_Sleeping) {
+		if (!avr->sreg[S_I]) {
+			printf("simavr: sleeping with interrupts off, quitting gracefully\n");
+			avr_terminate(avr);
+			exit(0);
+		}
+		/*
+		 * try to sleep for as long as we can (?)
+		 */
+		avr->sleep(avr, sleep);
+		avr->cycle += 1 + sleep;
+	}
+	// Interrupt servicing might change the PC too, during 'sleep'
+	if (avr->state == cpu_Running || avr->state == cpu_Sleeping)
+		avr_service_interrupts(avr);
+}
+
+
+int avr_run(avr_t * avr)
+{
+	avr->run(avr);
 	return avr->state;
 }
 
diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h
index 32426dd..ae1a3ab 100644
--- a/simavr/sim/sim_avr.h
+++ b/simavr/sim/sim_avr.h
@@ -107,6 +107,22 @@ typedef struct avr_t {
 	// called at reset time
 	void (*reset)(struct avr_t * avr);
 
+	/*
+	 * Default AVR core run function.
+	 * Two modes are available, a "raw" run that goes as fast as
+	 * it can, and a "gdb" mode that also watchouts for gdb events
+	 * and is a little bit slower.
+	 */
+	void (*run)(struct avr_t * avr);
+
+	/*
+	 * Sleep default behaviour.
+	 * In "raw" mode, it calls usleep, in gdb mode, it waits
+	 * for howLong for gdb command on it's sockets.
+	 */
+	void (*sleep)(struct avr_t * avr, avr_cycle_count_t howLong);
+
+
 	// Mirror of the SREG register, to facilitate the access to bits
 	// in the opcode decoder.
 	// This array is re-synthetized back/forth when SREG changes
@@ -267,6 +283,15 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr);
 // this might activate gdb server
 void avr_sadly_crashed(avr_t *avr, uint8_t signal);
 
+
+/*
+ * These are callbacks for the two 'main' bahaviour in simavr
+ */
+void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong);
+void avr_callback_run_gdb(avr_t * avr);
+void avr_callback_sleep_raw(avr_t * avr, avr_cycle_count_t howLong);
+void avr_callback_run_raw(avr_t * avr);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/simavr/sim/sim_gdb.c b/simavr/sim/sim_gdb.c
index 9bec4b5..3768022 100644
--- a/simavr/sim/sim_gdb.c
+++ b/simavr/sim/sim_gdb.c
@@ -425,6 +425,9 @@ int avr_gdb_init(avr_t * avr)
 	g->avr = avr;
 	g->s = -1;
 	avr->gdb = g;
+	// change default run behaviour to use the slightly slower versions
+	avr->run = avr_callback_run_gdb;
+	avr->sleep = avr_callback_sleep_gdb;
 	
 	return 0;
 }