From ac7d5ef06a6d6e8d84abbd1f0b82162725f98326 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 11 May 1995 17:39:37 +0000 Subject: Initial revision --- c/src/lib/libcpu/README | 14 ++ c/src/lib/libcpu/hppa1.1/clock/clock.c | 220 ++++++++++++++++++ c/src/lib/libcpu/hppa1.1/runway/runway.h | 37 +++ c/src/lib/libcpu/hppa1.1/semaphore/semaphore.c | 308 +++++++++++++++++++++++++ c/src/lib/libcpu/hppa1.1/semaphore/semaphore.h | 84 +++++++ c/src/lib/libcpu/hppa1.1/timer/timer.c | 62 +++++ 6 files changed, 725 insertions(+) create mode 100644 c/src/lib/libcpu/README create mode 100644 c/src/lib/libcpu/hppa1.1/clock/clock.c create mode 100644 c/src/lib/libcpu/hppa1.1/runway/runway.h create mode 100644 c/src/lib/libcpu/hppa1.1/semaphore/semaphore.c create mode 100644 c/src/lib/libcpu/hppa1.1/semaphore/semaphore.h create mode 100644 c/src/lib/libcpu/hppa1.1/timer/timer.c (limited to 'c/src/lib/libcpu') diff --git a/c/src/lib/libcpu/README b/c/src/lib/libcpu/README new file mode 100644 index 0000000000..e7e293660c --- /dev/null +++ b/c/src/lib/libcpu/README @@ -0,0 +1,14 @@ +# +# $Id$ +# + +This is the README file for libcpu. + +This directory contains reusable libraries which are CPU dependent but not +target board dependent. For example, the HPPA has an on chip interval timer +which may be used by all HPPA bsp's. + +Another example might be the Intel i960CA has on-chip DMA which could be +supported in a library and placed in lib/libcpu/i960. This level of support +will make it easier for others developing embedded applications on a given +CPU. diff --git a/c/src/lib/libcpu/hppa1.1/clock/clock.c b/c/src/lib/libcpu/hppa1.1/clock/clock.c new file mode 100644 index 0000000000..62bb8e2826 --- /dev/null +++ b/c/src/lib/libcpu/hppa1.1/clock/clock.c @@ -0,0 +1,220 @@ +/* Clock + * + * This routine initializes the interval timer on the + * PA-RISC CPU. The tick frequency is specified by the bsp. + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * $Id$ + */ + +#include +#include + +#include /* for atexit() */ + +extern rtems_cpu_table Cpu_table; /* owned by BSP */ + +typedef unsigned long long hppa_click_count_t; + +/* + * CPU_HPPA_CLICKS_PER_TICK is either a #define or an rtems_unsigned32 + * allocated and set by bsp_start() + */ + +#ifndef CPU_HPPA_CLICKS_PER_TICK +extern rtems_unsigned32 CPU_HPPA_CLICKS_PER_TICK; +#endif + +volatile rtems_unsigned32 Clock_driver_ticks; +rtems_unsigned32 Clock_isrs; /* ISRs until next tick */ + +rtems_unsigned32 most_recent_itimer_value; + +rtems_unsigned64 Clock_clicks; /* running total of cycles */ + +rtems_unsigned32 Clock_clicks_interrupt; + +rtems_device_driver Clock_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp, + rtems_id tid, + rtems_unsigned32 *rval +) +{ + Install_clock(Clock_isr); +} + +void +ReInstall_clock(rtems_isr_entry new_clock_isr) +{ + rtems_unsigned32 isrlevel = 0; + + rtems_interrupt_disable(isrlevel); + (void) set_vector( + new_clock_isr, + HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, + 1 + ); + rtems_interrupt_enable(isrlevel); +} + +/* + * read itimer and update Clock_clicks as appropriate + */ + +rtems_unsigned32 +Clock_read_itimer() +{ + rtems_unsigned32 isrlevel; + rtems_unsigned32 itimer_value; + rtems_unsigned32 wrap_count; + rtems_unsigned32 recent_count; + + rtems_interrupt_disable(isrlevel); + + wrap_count = (Clock_clicks & 0xFFFFFFFF00000000ULL) >> 32; + recent_count = (rtems_unsigned32) Clock_clicks; + + itimer_value = get_itimer(); + + if (itimer_value < recent_count) + wrap_count++; + Clock_clicks = (((rtems_unsigned64) wrap_count) << 32) + itimer_value; + + rtems_interrupt_enable(isrlevel); + + return itimer_value; +} + + +void Install_clock(rtems_isr_entry clock_isr) +{ + Clock_driver_ticks = 0; + Clock_clicks_interrupt = 0; + Clock_clicks = 0; + + Clock_isrs = BSP_Configuration.microseconds_per_tick / 1000; + + if (BSP_Configuration.ticks_per_timeslice) + { + /* + * initialize the interval here + * First tick is set to right amount of time in the future + * Future ticks will be incremented over last value set + * in order to provide consistent clicks in the face of + * interrupt overhead + */ + + Clock_clicks_interrupt = Clock_read_itimer() + CPU_HPPA_CLICKS_PER_TICK; + set_itimer((rtems_unsigned32) Clock_clicks_interrupt); + + (void) set_vector(clock_isr, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1); + } + atexit(Clock_exit); +} + +rtems_isr +Clock_isr(rtems_vector_number vector) +{ + rtems_unsigned32 clicks_til_next_interrupt; + rtems_unsigned32 itimer_value; + + /* + * setup for next interrupt; making sure the new value is reasonably + * in the future.... in case we lost out on an interrupt somehow + */ + + itimer_value = Clock_read_itimer(); + Clock_clicks_interrupt += CPU_HPPA_CLICKS_PER_TICK; + + /* + * how far away is next interrupt *really* + * It may be a long time; this subtraction works even if + * Clock_clicks_interrupt < Clock_clicks_low_order via + * the miracle of unsigned math. + */ + clicks_til_next_interrupt = Clock_clicks_interrupt - itimer_value; + + /* + * If it is too soon then bump it up. + * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small. + * But setting it low is useful for debug, so... + */ + + if (clicks_til_next_interrupt < 400) + { + Clock_clicks_interrupt = itimer_value + 1000; + /* XXX: count these! this should be rare */ + } + + /* + * If it is too late, that means we missed the interrupt somehow. + * Rather than wait 35-50s for a wrap, we just fudge it here. + */ + + if (clicks_til_next_interrupt > CPU_HPPA_CLICKS_PER_TICK) + { + Clock_clicks_interrupt = itimer_value + 1000; + /* XXX: count these! this should never happen :-) */ + } + + set_itimer((rtems_unsigned32) Clock_clicks_interrupt); + + Clock_driver_ticks++; + + if (Clock_isrs == 1) + { + rtems_clock_tick(); + Clock_isrs = BSP_Configuration.microseconds_per_tick / 10000; + if (Clock_isrs == 0) + Clock_isrs = 1; + } + else + Clock_isrs--; +} + +/* + * Called via atexit() + * Remove the clock interrupt handler by setting handler to NULL + */ + +void +Clock_exit(void) +{ + if ( BSP_Configuration.ticks_per_timeslice ) + { + (void) set_vector(0, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1); + } +} + +/* + * spin delay for specified number of microseconds + * used by RTEMS delay macro + */ + +void +Clock_delay(rtems_unsigned32 microseconds) +{ + rtems_unsigned64 future_time; + + (void) Clock_read_itimer(); + future_time = Clock_clicks + + ((rtems_unsigned64) microseconds) * + Cpu_table.itimer_clicks_per_microsecond; + + for (;;) + { + (void) Clock_read_itimer(); + if (future_time <= Clock_clicks) + break; + } +} + diff --git a/c/src/lib/libcpu/hppa1.1/runway/runway.h b/c/src/lib/libcpu/hppa1.1/runway/runway.h new file mode 100644 index 0000000000..41aafe26ef --- /dev/null +++ b/c/src/lib/libcpu/hppa1.1/runway/runway.h @@ -0,0 +1,37 @@ +/* + * File: $RCSfile$ + * Project: PixelFlow + * Created: 94/11/29 + * RespEngr: tony bennett + * Revision: $Revision$ + * Last Mod: $Date$ + * + * Description: + * definitions specific to the runway bus + * + * TODO: + * Add lots more. + * + * $Id$ + */ + +#ifndef _INCLUDE_RUNWAY_H +#define _INCLUDE_RUNWAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define HPPA_RUNWAY_PROC_HPA_BASE ((void *) 0xFFFA0000) + +/* given a processor number, where is its HPA? */ +#define HPPA_RUNWAY_HPA(cpu) \ + ((rtems_unsigned32) (HPPA_RUNWAY_PROC_HPA_BASE + ((cpu) * 0x2000))) + +#define HPPA_RUNWAY_REG_IO_EIR_OFFSET 0x000 + +#ifdef __cplusplus +} +#endif + +#endif /* ! _INCLUDE_RUNWAY_H */ diff --git a/c/src/lib/libcpu/hppa1.1/semaphore/semaphore.c b/c/src/lib/libcpu/hppa1.1/semaphore/semaphore.c new file mode 100644 index 0000000000..aa8b768b3a --- /dev/null +++ b/c/src/lib/libcpu/hppa1.1/semaphore/semaphore.c @@ -0,0 +1,308 @@ +/* + * File: $RCSfile$ + * Project: PixelFlow + * Created: 94/11/29 + * RespEngr: tony bennett + * Revision: $Revision$ + * Last Mod: $Date$ + * + * COPYRIGHT (c) 1994 by Division Incorporated + * + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: + * permission to use, copy, modify, and distribute this file + * for any purpose is hereby granted without fee, provided that + * the above copyright notice and this notice appears in all + * copies, and that the name of Division Incorporated not be + * used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Division Incorporated makes no representations about the + * suitability of this software for any purpose. + * + * Description: + * HPPA fast spinlock semaphores based on LDCWX instruction. + * These semaphores are not known to RTEMS. + * + * TODO: + * Put node number in high 16 bits of flag?? + * XXX: Need h_s_deallocate + * + * $Id$ + */ + +#include + +#include "semaphore.h" + +/* + * Report fatal semaphore error + */ + +#define SEM_FATAL_ERROR(sp) rtems_fatal_error_occurred((rtems_unsigned32) sp) + +#define SEM_CHECK(sp) do { \ + if (((sp) == 0) || (int) (sp) & 0xf) \ + { \ + SEM_FATAL_ERROR(sp); \ + } \ + } while (0) + +/* + * Init a semaphore to be free + */ + +#define SEM_FREE_INIT(sp) \ + do { \ + (sp)->lock = 1; \ + (sp)->flags = 0; \ + (sp)->owner_tcb = 0; \ + } while (0) + +/* + * Grab a semaphore recording its owner. + */ + +#define SEM_MARK_GRABBED(sp) \ + do { \ + (sp)->owner_tcb = _Thread_Executing; \ + } while (0) + +/* + * Mark the semaphore busy + */ + +#define SEM_MARK_BUSY(sp) ((sp)->flags |= HPPA_SEM_IN_USE) + +/* + * Is a semaphore available? + */ + +#define SEM_IS_AVAILABLE(sp) ((sp)->owner_tcb == 0) + +/* + * The pool control semaphore is the first in the pool + */ + +#define SEM_CONTROL (&hppa_semaphore_pool[0]) +#define SEM_FIRST (&hppa_semaphore_pool[1]) + +#define SEM_PRIVATE(cookie) rtems_interrupt_disable(cookie) + +#define SEM_PUBLIC(cookie) rtems_interrupt_enable(cookie) + + +/* + * Control variables for the pool + */ + +hppa_semaphore_t *hppa_semaphore_pool; /* ptr to first */ +int hppa_semaphores; +int hppa_semaphores_available; + +void +hppa_semaphore_pool_initialize(void *pool_base, + int pool_size) +{ + hppa_semaphore_t *sp; + int align_factor; + rtems_unsigned32 isr_level; + + /* + * round pool_base up to be a multiple of SEM_ALIGN + */ + + align_factor = SEM_ALIGN - (((int) pool_base) & (SEM_ALIGN-1)); + if (align_factor != SEM_ALIGN) + { + pool_base += align_factor; + pool_size -= align_factor; + } + + /* + * How many can the pool hold? + * Assumes the semaphores are SEM_ALIGN bytes each + */ + + if (sizeof(hppa_semaphore_t) != SEM_ALIGN) + rtems_fatal_error_occurred(RTEMS_INVALID_SIZE); + + pool_size &= ~(SEM_ALIGN - 1); + + SEM_PRIVATE(isr_level); + + hppa_semaphore_pool = pool_base; + hppa_semaphores = pool_size / SEM_ALIGN; + + /* + * If we are node0, then init all in the pool + */ + + if (cpu_number == 0) + { + /* + * Tell other cpus we are not done, jic + */ + SEM_CONTROL->user = rtems_build_name('!', 'D', 'N', 'E'); + + for (sp=SEM_FIRST; sp < &hppa_semaphore_pool[hppa_semaphores]; sp++) + SEM_FREE_INIT(sp); + SEM_FREE_INIT(SEM_CONTROL); + } + + /* + * Tell other cpus we are done, or wait for it to be done if on another cpu + */ + + if (cpu_number == 0) + SEM_CONTROL->user = rtems_build_name('D', 'O', 'N', 'E'); + else + while (SEM_CONTROL->user != rtems_build_name('D', 'O', 'N', 'E')) + ; + + hppa_semaphores_available = hppa_semaphores; + + SEM_PUBLIC(isr_level); +} + +/* + * Function: hppa_semaphore_acquire + * Created: 94/11/29 + * RespEngr: tony bennett + * + * Description: + * Acquire a semaphore. Will spin on the semaphore unless + * 'flag' says not to. + * + * Parameters: + * + * + * Returns: + * 0 -- if did not acquire + * non-zero -- if acquired semaphore + * (actually this is the spin count) + * + * Notes: + * There is no requirement that the semaphore be within the pool + * + * Deficiencies/ToDo: + * + */ + + +rtems_unsigned32 +hppa_semaphore_acquire(hppa_semaphore_t *sp, + int flag) +{ + rtems_unsigned32 lock_value; + rtems_unsigned32 spin_count = 1; + + SEM_CHECK(sp); + + for (;;) + { + HPPA_ASM_LDCWS(0, 0, sp, lock_value); + + if (lock_value) /* we now own the lock */ + { + SEM_MARK_GRABBED(sp); + return spin_count ? spin_count : ~0; /* jic */ + } + + if (flag & HPPA_SEM_NO_SPIN) + return 0; + + spin_count++; + } +} + +void +hppa_semaphore_release(hppa_semaphore_t *sp) +{ + SEM_CHECK(sp); + + if (sp->owner_tcb != _Thread_Executing) + SEM_FATAL_ERROR("owner mismatch"); + + sp->lock = 1; +} + + +/* + * Function: hppa_semaphore_allocate + * Created: 94/11/29 + * RespEngr: tony bennett + * + * Description: + * Get a pointer to a semaphore. + * + * Parameters: + * which -- if 0, then allocate a free semaphore from the pool + * if non-zero, then return pointer to that one, even + * if it is already busy. + * + * Returns: + * successful -- pointer to semaphore + * NULL otherwise + * + * Notes: + * + * + * Deficiencies/ToDo: + * + * + */ + +hppa_semaphore_t * +hppa_semaphore_allocate(rtems_unsigned32 which, + int flag) +{ + hppa_semaphore_t *sp = 0; + + /* + * grab the control semaphore + */ + + if (hppa_semaphore_acquire(SEM_CONTROL, 0) == 0) + SEM_FATAL_ERROR("could not grab control semaphore"); + + /* + * Find a free one and init it + */ + + if (which) + { + if (which >= hppa_semaphores) + SEM_FATAL_ERROR("requested non-existent semaphore"); + sp = &hppa_semaphore_pool[which]; + + /* + * if it is "free", then mark it claimed now. + * If it is not free then we are done. + */ + + if (SEM_IS_AVAILABLE(sp)) + goto allmine; + } + else for (sp = SEM_FIRST; + sp < &hppa_semaphore_pool[hppa_semaphores]; + sp++) + { + if (SEM_IS_AVAILABLE(sp)) + { +allmine: SEM_FREE_INIT(sp); + SEM_MARK_BUSY(sp); + if ( ! (flag & HPPA_SEM_INITIALLY_FREE)) + SEM_MARK_GRABBED(sp); + break; + } + } + + /* + * Free up the control semaphore + */ + + hppa_semaphore_release(SEM_CONTROL); + + return sp; +} + diff --git a/c/src/lib/libcpu/hppa1.1/semaphore/semaphore.h b/c/src/lib/libcpu/hppa1.1/semaphore/semaphore.h new file mode 100644 index 0000000000..04f709cf64 --- /dev/null +++ b/c/src/lib/libcpu/hppa1.1/semaphore/semaphore.h @@ -0,0 +1,84 @@ +/* + * File: $RCSfile$ + * Project: PixelFlow + * Created: 94/11/29 + * RespEngr: tony e bennett + * Revision: $Revision$ + * Last Mod: $Date$ + * + * COPYRIGHT (c) 1994 by Division Incorporated + * + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: + * permission to use, copy, modify, and distribute this file + * for any purpose is hereby granted without fee, provided that + * the above copyright notice and this notice appears in all + * copies, and that the name of Division Incorporated not be + * used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Division Incorporated makes no representations about the + * suitability of this software for any purpose. + * + * Description: + * HPPA fast spinlock semaphores based on LDCWX instruction. + * These semaphores are not known to RTEMS. + * + * TODO: + * + * $Id$ + */ + +#ifndef _INCLUDE_SEMAPHORE_H +#define _INCLUDE_SEMAPHORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure has hardware requirements. + * LDCWX opcode requires 16byte alignment for the lock + * 'lock' must be first member of structure. + */ + +#define SEM_ALIGN 16 + +typedef volatile struct { + + rtems_unsigned32 lock __attribute__ ((aligned (SEM_ALIGN))); + + rtems_unsigned32 flags; + + void *owner_tcb; /* for debug/commentary only */ + + rtems_unsigned32 user; /* for use by user */ + +} hppa_semaphore_t; + +/* + * Values for flags + */ + +#define HPPA_SEM_IN_USE 0x0001 /* semaphore owned by somebody */ +#define HPPA_SEM_NO_SPIN 0x0002 /* don't spin if unavailable */ +#define HPPA_SEM_INITIALLY_FREE 0x0004 /* init it to be free */ + +/* + * Caller specifiable flags + */ + +#define HPPA_SEM_CALLER_FLAGS (HPPA_SEM_NO_SPIN | HPPA_SEM_INITIALLY_FREE) + +void hppa_semaphore_pool_initialize(void *pool_base, int pool_size); + +rtems_unsigned32 hppa_semaphore_acquire(hppa_semaphore_t *sp, int flag); + +void hppa_semaphore_release(hppa_semaphore_t *sp); + +hppa_semaphore_t *hppa_semaphore_allocate(rtems_unsigned32 which, int flag); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _INCLUDE_SEMAPHORE_H */ diff --git a/c/src/lib/libcpu/hppa1.1/timer/timer.c b/c/src/lib/libcpu/hppa1.1/timer/timer.c new file mode 100644 index 0000000000..caa04bd282 --- /dev/null +++ b/c/src/lib/libcpu/hppa1.1/timer/timer.c @@ -0,0 +1,62 @@ +/* timer.c + * + * This file manages the interval timer on the PA-RISC. + * + * NOTE: It is important that the timer start/stop overhead be + * determined when porting or modifying this code. + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * $Id$ + */ + +#include + +volatile rtems_unsigned32 Timer_starting; +rtems_boolean Timer_driver_Find_average_overhead; + +void Timer_initialize() +{ + Timer_starting = get_itimer(); +} + +#define AVG_OVERHEAD 0 /* It typically takes 3.0 microseconds */ + /* (6 countdowns) to start/stop the timer. */ +#define LEAST_VALID 1 /* Don't trust a value lower than this */ + +int Read_timer() +{ + rtems_unsigned32 clicks; + rtems_unsigned32 total; + + clicks = get_itimer(); + + total = clicks - Timer_starting; + + if ( Timer_driver_Find_average_overhead == 1 ) + return total; /* in XXX microsecond units */ + + else { + if ( total < LEAST_VALID ) + return 0; /* below timer resolution */ + return (total - AVG_OVERHEAD); + } +} + +rtems_status_code Empty_function( void ) +{ + return RTEMS_SUCCESSFUL; +} + +void Set_find_average_overhead( + rtems_boolean find_flag +) +{ + Timer_driver_Find_average_overhead = find_flag; +} -- cgit v1.2.3