Implemented exceptions and timer management functions to remove dependencies from newlib

This commit is contained in:
afpr
2014-03-19 14:11:19 +00:00
parent d88f47c3bf
commit 1c6536f33c
5 changed files with 93 additions and 33 deletions

View File

@@ -22,10 +22,6 @@
#include <rtems.h> #include <rtems.h>
#include <bsp.h> #include <bsp.h>
#include <machine/patmos.h>
#include <machine/exceptions.h>
#include <machine/rtc.h>
void Clock_exit( void ); void Clock_exit( void );
rtems_isr Clock_isr( rtems_vector_number vector )__attribute__((naked)); rtems_isr Clock_isr( rtems_vector_number vector )__attribute__((naked));
@@ -52,10 +48,9 @@ uint32_t Clock_isrs; /* ISRs until next tick */
rtems_device_major_number rtems_clock_major = ~0; rtems_device_major_number rtems_clock_major = ~0;
rtems_device_minor_number rtems_clock_minor; rtems_device_minor_number rtems_clock_minor;
/* cycles from RTEMS start to Install_clock routine */
uint64_t cycles_offset; /* usecs from RTEMS start to Install_clock routine */
/* CPU frequency in MHZ */ uint64_t usecs_bias;
uint32_t freq;
/* timestamp of the last tick in usec */ /* timestamp of the last tick in usec */
uint64_t usec_offset; uint64_t usec_offset;
@@ -67,6 +62,36 @@ rtems_isr_entry Old_ticker;
void Clock_exit( void ); void Clock_exit( void );
/*
* Get the current RTC microsecond value
*/
uint64_t get_cpu_usecs(void) {
unsigned ulo, uhi;
_iodev_ptr_t hi_usec = (_iodev_ptr_t)(__PATMOS_RTC_TIME_UP_ADDR);
_iodev_ptr_t lo_usec = (_iodev_ptr_t)(__PATMOS_RTC_TIME_LOW_ADDR);
// Order is important here
ulo = *lo_usec;
uhi = *hi_usec;
return (((unsigned long long) uhi) << 32) | ulo;
}
/*
* Set the timeout for the clock timer. The RTC will trigger an interrupt once
* the cycle counter reaches the given value.
*/
static inline void arm_usec_timer(uint64_t timestamp) {
_iodev_ptr_t hi_usec = (_iodev_ptr_t)(__PATMOS_RTC_TIME_UP_ADDR);
_iodev_ptr_t lo_usec = (_iodev_ptr_t)(__PATMOS_RTC_TIME_LOW_ADDR);
// Order is important here
*lo_usec = (unsigned)timestamp;
*hi_usec = (unsigned)(timestamp>>32);
}
void set_usec_timer (uint64_t time_warp) void set_usec_timer (uint64_t time_warp)
{ {
@@ -78,21 +103,9 @@ void set_usec_timer (uint64_t time_warp)
arm_usec_timer(usec_offset); arm_usec_timer(usec_offset);
} }
uint32_t get_cpu_freq_mhz(void)
{
return get_cpu_freq()/1000000;
}
uint32_t bsp_clock_nanoseconds_since_last_tick(void) uint32_t bsp_clock_nanoseconds_since_last_tick(void)
{ {
/*uint64_t volatile cycles_since_first_tick = (uint64_t)Clock_driver_ticks*rtems_configuration_get_microseconds_per_tick()*freq; uint64_t nsecs = (get_cpu_usecs() - usecs_bias - Clock_driver_ticks*rtems_configuration_get_microseconds_per_tick())*1000;
uint64_t volatile cycles_since_program_start = get_cpu_cycles();
uint64_t volatile cycles_since_last_tick = cycles_since_program_start - cycles_since_first_tick - cycles_offset;
uint64_t volatile microseconds_since_last_tick = cycles_since_last_tick*1000;
uint64_t nsecs = microseconds_since_last_tick / ((uint64_t)freq);*/
uint64_t nsecs = ((get_cpu_cycles() - ((uint64_t)Clock_driver_ticks*rtems_configuration_get_microseconds_per_tick()*freq) - cycles_offset)
* 1000) / ((uint64_t)freq);
return (uint32_t) nsecs; return (uint32_t) nsecs;
} }
@@ -324,13 +337,14 @@ void Install_clock(
Clock_driver_ticks = 0; Clock_driver_ticks = 0;
Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000; Clock_isrs = rtems_configuration_get_microseconds_per_tick() / 1000;
exc_register(EXC_INTR_USEC, (uint32_t)clock_isr); // set the isr routine
set_exc_handler(EXC_INTR_USEC, (uint32_t)clock_isr);
// clear pending flags // clear pending flags
intr_clear_all_pending(); intr_clear_all_pending();
// unmask interrupt // unmask interrupt
intr_unmask(EXC_INTR_USEC); intr_unmask(EXC_INTR_USEC);
// enable interrupts // enable interrupts
intr_enable(); patmos_enable_interrupts();
#if defined(Clock_driver_nanoseconds_since_last_tick) #if defined(Clock_driver_nanoseconds_since_last_tick)
rtems_clock_set_nanoseconds_extension( rtems_clock_set_nanoseconds_extension(
@@ -338,19 +352,15 @@ void Install_clock(
); );
#endif #endif
freq = get_cpu_freq_mhz();
/* /*
* reset the cpu_cycles count to determine clock_nanoseconds_since_last_tick * reset the cpu_usecs count to determine clock_nanoseconds_since_last_tick
*/ */
cycles_offset = get_cpu_cycles(); usecs_bias = get_cpu_usecs();
usec_offset = get_cpu_usecs(); usec_offset = get_cpu_usecs();
set_usec_timer(rtems_configuration_get_microseconds_per_tick()); set_usec_timer(rtems_configuration_get_microseconds_per_tick());
/* /*
* Schedule the clock cleanup routine to execute if the application exits. * Schedule the clock cleanup routine to execute if the application exits.
*/ */

View File

@@ -118,6 +118,8 @@ extern char _uart_base; /* linker symbol giving the address of the UART */
extern char _timer_base; /* linker symbol giving the address of the RTC */ extern char _timer_base; /* linker symbol giving the address of the RTC */
extern uint64_t get_cpu_usecs (void);
extern void set_usec_timer (uint64_t time_warp); extern void set_usec_timer (uint64_t time_warp);
/* Address to access the cycle counter low register of the RTC */ /* Address to access the cycle counter low register of the RTC */

View File

@@ -18,8 +18,6 @@
#include <bsp.h> #include <bsp.h>
#include <machine/rtc.h>
bool benchmark_timer_find_average_overhead; bool benchmark_timer_find_average_overhead;
#define AVG_OVERHEAD 0 /* It typically takes 0 microseconds */ #define AVG_OVERHEAD 0 /* It typically takes 0 microseconds */
@@ -33,7 +31,7 @@ void benchmark_timer_initialize(void)
/* /*
* Timer runs long and accurate enough not to require an interrupt. * Timer runs long and accurate enough not to require an interrupt.
*/ */
timer_offset = get_cpu_cycles(); timer_offset = get_cpu_usecs();
} }
int benchmark_timer_read(void) int benchmark_timer_read(void)
@@ -44,7 +42,7 @@ int benchmark_timer_read(void)
* Read the timer and see how many clicks it has been since we started. * Read the timer and see how many clicks it has been since we started.
*/ */
total = (get_cpu_cycles() - timer_offset)/get_cpu_freq_mhz(); total = get_cpu_usecs() - timer_offset;
if ( benchmark_timer_find_average_overhead == true ) if ( benchmark_timer_find_average_overhead == true )
return total; /* in one microsecond units */ return total; /* in one microsecond units */

View File

@@ -20,6 +20,8 @@
#include <rtems.h> #include <rtems.h>
#include <bsp.h> #include <bsp.h>
#include "exceptions.h"
/* /*
* Enable interrupts * Enable interrupts
*/ */
@@ -33,3 +35,27 @@ void patmos_enable_interrupts(void){
void patmos_disable_interrupts(void){ void patmos_disable_interrupts(void){
EXC_STATUS &= ~1; EXC_STATUS &= ~1;
} }
/*
* Register a function as exception handler.
* n - The exception to register the function for
* fun - The exception handler
*/
void set_exc_handler(unsigned n, exc_handler_t fun){
EXC_VEC(n) = (unsigned)fun;
}
/*
* Clear the pending flag of all interrupts
*/
void intr_clear_all_pending(void){
EXC_PEND = 0;
}
/*
* Unmask a particular interrupts
* n - The interrupt to be unmasked
*/
void intr_unmask(unsigned n){
EXC_MASK |= (1 << n);
}

View File

@@ -14,10 +14,34 @@
#ifndef __PATMOS_EXCEPTIONS_h #ifndef __PATMOS_EXCEPTIONS_h
#define __PATMOS_EXCEPTIONS_h #define __PATMOS_EXCEPTIONS_h
/*
* The exception handler type
*/
typedef void (*exc_handler_t)(void);
/*
* The exception vector array
*/
#define EXC_VEC(I) (((_IODEV exc_handler_t volatile * const)(&_excunit_base+0x80))[I])
/*
* Various named exception vector entry numbers
*/
#define EXC_ILLEGAL_OP 0
#define EXC_ILLEGAL_ADDRESS 1
#define EXC_INTR_CLOCK 16
#define EXC_INTR_USEC 17
void patmos_enable_interrupts(void); void patmos_enable_interrupts(void);
void patmos_disable_interrupts(void); void patmos_disable_interrupts(void);
void set_exc_handler(unsigned n, exc_handler_t fun);
void intr_clear_all_pending(void);
void intr_unmask(unsigned n);
#endif #endif
/* end of include file */ /* end of include file */