Mercurial > ecos
changeset 38:e7ba79f6d3a8 ecos-sw-1999-09-23
Merge from eCos master repository on 1999-09-23-20:10:25-BST
line wrap: on
line diff
--- a/packages/hal/arm/arch/current/ChangeLog +++ b/packages/hal/arm/arch/current/ChangeLog @@ -1,3 +1,26 @@ +1999-09-21 Gary Thomas <gthomas@cygnus.co.uk> + + * include/hal_arch.h: Remove FIXME about GDB register layout. + + * src/context.S (hal_thread_save_context): Change function prologue + to match APCS more closely (keeps GDB happier). + +1999-09-19 Gary Thomas <gthomas@cygnus.co.uk> + + * src/vectors.S (spurious_IRQ): Make sure interrupts are masked + when switching to IRQ mode. + + * src/hal_misc.c (exception_handler): GDB stubs only take over + memory exceptions. This allows proper handling when an application + has it's own IRQ/FIQ VSR. + +1999-09-13 Gary Thomas <gthomas@cygnus.co.uk> + + * src/vectors.S (handle_IRQ_or_FIQ): Allow spurious interrupts + to be ignored. Some platforms (CL7xxx) have non-debounced + interrupt sources which can vanish before the hardware can be + queried. + 1999-09-11 Jonathan Larmour <jlarmour@cygnus.co.uk> * src/arm_stub.c (__computeSignal): Synchronise return value with
--- a/packages/hal/arm/arch/current/include/arm_stub.h +++ b/packages/hal/arm/arch/current/include/arm_stub.h @@ -34,6 +34,9 @@ enum regnames { #define PS_C 0x20000000 #define PS_V 0x10000000 +#define PS_I CPSR_IRQ_DISABLE +#define PS_F CPSR_FIQ_DISABLE + typedef enum regnames regnames_t; /* Given a trap value TRAP, return the corresponding signal. */
--- a/packages/hal/arm/arch/current/include/hal_arch.h +++ b/packages/hal/arm/arch/current/include/hal_arch.h @@ -184,8 +184,6 @@ asm volatile (" .globl " #_label_ ";" //-------------------------------------------------------------------------- // Thread register state manipulation for GDB support. -// FIX ME!! What does GDB expect? - // GDB expects the registers in this structure: // r0..r10, fp, ip, sp, lr, pc - 4 bytes each // f0..f7 - 12 bytes each (N/A on ARM7)
--- a/packages/hal/arm/arch/current/src/arm.ld +++ b/packages/hal/arm/arch/current/src/arm.ld @@ -61,7 +61,7 @@ GROUP(libtarget.a libgcc.a) .text _vma_ : _lma_ \ { stext = ABSOLUTE(.); \ PROVIDE (__stext = ABSOLUTE(.)); \ - *(.text*) *(.gnu.warning) *(.gnu.linkonce*) *(.init) } \ + *(.text*) *(.gnu.warning) *(.gnu.linkonce*) *(.init) }\ > _region_ \ etext = .; PROVIDE (__etext = .);
--- a/packages/hal/arm/arch/current/src/arm_stub.c +++ b/packages/hal/arm/arch/current/src/arm_stub.c @@ -58,7 +58,6 @@ int __computeSignal (unsigned int trap_n /* Return the trap number corresponding to the last-taken trap. */ -volatile int jifl; int __get_trap_number (void) { // The vector is not not part of the GDB register set so get it
--- a/packages/hal/arm/arch/current/src/context.S +++ b/packages/hal/arm/arch/current/src/context.S @@ -67,8 +67,8 @@ name: FUNC_START(hal_thread_switch_context) mov ip,sp // saved stack pointer - sub sp,sp,#ARMREG_SIZE // make space for saved registers - stmea sp,{r0-r10,fp,ip,lr,pc} + stmfd sp!,{fp,ip,lr,pc} // filler + stmfd sp!,{r0-r10,fp,ip,lr,pc} mrs r2,cpsr str r2,[sp,#armreg_cpsr] str sp,[r1] // return new stack pointer @@ -90,8 +90,8 @@ FUNC_START(hal_thread_load_context) msr cpsr,r0 ldr r0,[fp,#armreg_cpsr] msr spsr,r0 - ldmfd fp,{r0-r10,fp,sp,lr} // also restores saved PSR - movs pc,lr + ldmfd fp,{r0-r10,fp,sp,lr} + movs pc,lr // also restores saved PSR // ------------------------------------------------------------------------------ // HAL longjmp, setjmp implementations
--- a/packages/hal/arm/arch/current/src/hal_misc.c +++ b/packages/hal/arm/arch/current/src/hal_misc.c @@ -70,6 +70,8 @@ extern void *__mem_fault_handler; processing is underway. The only vector that can't be handled this way is the illegal instruction vector which is used for breakpoint/single-step and must be maintained by the stubs at all times. + Note: the interrupt vectors are _not_ preempted as the stubs probably can't + handle them properly. */ #define ARM_VECTORS 8 @@ -82,20 +84,17 @@ static int exception_level; static void __take_over_debug_traps(void) { - int i; - for (i = 0; i < ARM_VECTORS; i++) { - hold_vectors[i] = hardware_vectors[i]; - hardware_vectors[i] = vectors[i]; - } + hold_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH]; + hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH]; + hold_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA]; + hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = vectors[CYGNUM_HAL_VECTOR_ABORT_DATA]; } static void __restore_debug_traps(void) { - int i; - for (i = 0; i < ARM_VECTORS; i++) { - hardware_vectors[i] = hold_vectors[i]; - } + hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = hold_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH]; + hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = hold_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA]; } #endif @@ -114,15 +113,15 @@ exception_handler(HAL_SavedRegisters *re _hal_registers = regs; __handle_exception(); + if (--exception_level == 0) __restore_debug_traps(); + +#elif defined(CYGPKG_KERNEL_EXCEPTIONS) + // We should decode the vector and pass a more appropriate // value as the second argument. For now we simply pass a // pointer to the saved registers. We should also divert // breakpoint and other debug vectors into the debug stubs. - if (--exception_level == 0) __restore_debug_traps(); - -#elif defined(CYGPKG_KERNEL_EXCEPTIONS) - cyg_hal_deliver_exception( regs->vector, (CYG_ADDRWORD)regs ); #else
--- a/packages/hal/arm/arch/current/src/vectors.S +++ b/packages/hal/arm/arch/current/src/vectors.S @@ -480,7 +480,12 @@ call_exception_handler: mrs r0,cpsr // move back to IRQ mode bic r0,r0,#CPSR_MODE_BITS - orr r0,r0,#CPSR_IRQ_MODE + orr r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE + msr cpsr,r0 + nop + nop + + orr r0,r0,#CPSR_IRQ_MODE msr cpsr,r0 mov sp,ip @@ -578,6 +583,10 @@ 10: #endif mov r0,v1 // vector # +#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS + cmp r0,#0 // ignore spurious interrupts + beq spurious_IRQ +#endif // CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS ldr r1,.hal_interrupt_data ldr r1,[r1,v1,lsl #2] // handler data ldr r2,.hal_interrupt_handlers @@ -588,6 +597,10 @@ 10: mov lr,pc // invoke handler (call indirect mov pc,v3 // thru v3) +#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS +spurious_IRQ: +#endif // CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS + #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK // If we are returning from the last nested interrupt, move back // to the thread stack. interrupt_end() must be called on the @@ -620,6 +633,11 @@ 10: ldr sp,[sp,#armreg_sp] mrs r0,cpsr // move back to IRQ mode + orr r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE + msr cpsr,r0 + nop + nop + bic r0,r0,#CPSR_MODE_BITS orr r0,r0,#CPSR_IRQ_MODE msr cpsr,r0
--- a/packages/hal/arm/cl7211/current/ChangeLog +++ b/packages/hal/arm/cl7211/current/ChangeLog @@ -1,3 +1,29 @@ +1999-09-15 Gary Thomas <gthomas@cygnus.co.uk> + + * misc/nand_test.c (nand_exercise): Check "read ID" function. + + * misc/lcd_panel_support.c (lcd_panel_server): Reorg sampling + loop to use a weighted average (try and avoid bad results). + + * misc/kbd_test.c (kbd_exercise): Use new kbd_getc() function. + + * misc/kbd_support.c (kbd_getc): New function. + + * misc/lcd_support.c: Add simple printf() code. + +1999-09-13 Gary Thomas <gthomas@cygnus.co.uk> + + * include/pkgconf/mlt_arm_eb7211_ram.ldi: + * include/pkgconf/mlt_arm_eb7211_ram.mlt: Fix DRAM limits. + +1999-09-12 Gary Thomas <gthomas@cygnus.co.uk> + + * misc/kbd_support.c: New file. Also change to more or less + ignore interrupts since they don't work for many keys! + + * misc/kbd_test.c: Move keyboard support routines to separate + file. + 1999-09-10 Gary Thomas <gthomas@cygnus.co.uk> * include/hal_platform_setup.h: Fix spelling error.
index 54384e59563b3a0492f0e638a3e00cb1fcfe06c4..2c7a2a184b51637e191c514dccbddc5fba971895 GIT binary patch literal 16068 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 Q!}qee$C&-M<woKBZ|qPLBLDyZ
--- a/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.ldi +++ b/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.ldi @@ -32,7 +32,7 @@ MEMORY { - ram : ORIGIN = 0x8000, LENGTH = 0x1b8000 + ram : ORIGIN = 0x8000, LENGTH = 0x00FF8000 } SECTIONS
--- a/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.mlt +++ b/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.mlt @@ -1,5 +1,5 @@ version 0 -region ram 8000 1b8000 0 ! +region ram 8000 ff8000 0 ! section rom_vectors 0 1 0 1 1 1 1 1 8000 8000 text text ! section text 0 1 0 1 0 1 0 1 fini fini ! section fini 0 1 0 1 0 1 0 1 rodata rodata !
new file mode 100644 --- /dev/null +++ b/packages/hal/arm/cl7211/current/misc/kbd_support.c @@ -0,0 +1,455 @@ +//========================================================================== +// +// kbd_support.c +// +// Cirrus CL72xx eval board ASCII keyboard support functions +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Cygnus eCos Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://sourceware.cygnus.com/ecos +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Cygnus Operating System, released +// September 30, 1998. +// +// The Initial Developer of the Original Code is Cygnus. Portions created +// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas +// Date: 1999-05-15 +// Description: Functions used to support ASCII keyboard +//####DESCRIPTIONEND#### + +static char kbd_server_stack[STACK_SIZE]; +static cyg_thread kbd_server_thread_data; +static cyg_handle_t kbd_server_thread_handle; + +static cyg_interrupt kbd_interrupt; +static cyg_handle_t kbd_interrupt_handle; + +static cyg_mbox kbd_events_mbox; +static cyg_handle_t kbd_events_mbox_handle; +static cyg_sem_t kbd_sem; + +static cyg_uint8 col_state[8]; +static cyg_uint8 ext_state[8]; + +static void +kbd_delay(void) +{ + volatile int i; + for (i = 0; i < 250; i++) ; +} + +static void +kbd_scan(void) +{ + int i; + cyg_uint8 port_data, ext_data; + // Turn off drive (de-select) all columns + *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | + SYSCON1_KBD_LOW; + for (i = 0; i < 8; i++) { + // Select column 'i' + *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | + SYSCON1_KBD_COL(i); + // Small pause to let the wires charge up :-) + kbd_delay(); + // Grab the data + col_state[i] = port_data = *(volatile cyg_uint8 *)PADR; + ext_state[i] = ext_data = *(volatile cyg_uint8 *)KBD_PORT; + // De-Select column 'i' + *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | + SYSCON1_KBD_TRISTATE; + // Allow line to gl slack + kbd_delay(); + } + // Turn on drive (select) all columns - necessary to see interrupts + *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | + SYSCON1_KBD_HIGH; +} + +static cyg_uint8 kbd_state[128]; // Known state of each key +static cyg_uint8 kbd_new_state[128]; // Current state of each key + +// Row #1 +#define KBD_Escape 0x00 +#define KBD_F1 0x01 +#define KBD_F2 0x02 +#define KBD_F3 0x03 +#define KBD_F4 0x04 +#define KBD_F5 0x05 +#define KBD_F6 0x06 +#define KBD_F7 0x07 +#define KBD_F8 0x08 +#define KBD_F9 0x09 +#define KBD_F10 0x0A +#define KBD_NumLock 0x0B +#define KBD_SysReq 0x0C +#define KBD_ScrlLock 0x0D +#define KBD_Break 0x0E +// Row #2 +#define KBD_1 0x10 +#define KBD_2 0x11 +#define KBD_3 0x12 +#define KBD_4 0x13 +#define KBD_5 0x14 +#define KBD_6 0x15 +#define KBD_7 0x16 +#define KBD_8 0x17 +#define KBD_9 0x18 +#define KBD_0 0x19 +#define KBD_Hyphen 0x1A +#define KBD_Equals 0x1B +#define KBD_BackSpace 0x1C +#define KBD_Home 0x1D +// Row #3 +#define KBD_Tab 0x20 +#define KBD_Q 0x21 +#define KBD_W 0x22 +#define KBD_E 0x23 +#define KBD_R 0x24 +#define KBD_T 0x25 +#define KBD_Y 0x26 +#define KBD_U 0x27 +#define KBD_I 0x28 +#define KBD_O 0x29 +#define KBD_P 0x2A +#define KBD_LeftBrkt 0x2B +#define KBD_RightBrkt 0x2C +#define KBD_BackSlash 0x2D +#define KBD_PageUp 0x2E +// Row #4 +#define KBD_CapsLock 0x30 +#define KBD_A 0x31 +#define KBD_S 0x32 +#define KBD_D 0x33 +#define KBD_F 0x34 +#define KBD_G 0x35 +#define KBD_H 0x36 +#define KBD_J 0x37 +#define KBD_K 0x38 +#define KBD_L 0x39 +#define KBD_SemiColon 0x3A +#define KBD_Quote 0x3B +#define KBD_Enter 0x3C +#define KBD_PageDown 0x3D +// Row #5 +#define KBD_LeftShift 0x40 +#define KBD_Z 0x41 +#define KBD_X 0x42 +#define KBD_C 0x43 +#define KBD_V 0x44 +#define KBD_B 0x45 +#define KBD_N 0x46 +#define KBD_M 0x47 +#define KBD_Comma 0x48 +#define KBD_Period 0x49 +#define KBD_Slash 0x4A +#define KBD_RightShift 0x4B +#define KBD_UpArrow 0x4C +#define KBD_End 0x4D +// Row #6 +#define KBD_Ctrl 0x50 +#define KBD_Function 0x51 +#define KBD_LeftAlt 0x52 +#define KBD_Accent 0x53 +#define KBD_Space 0x54 +#define KBD_RightAlt 0x55 +#define KBD_Ins 0x56 +#define KBD_Del 0x57 +#define KBD_LeftArrow 0x58 +#define KBD_DownArrow 0x59 +#define KBD_RightArrow 0x5A + +#define KBD_Press 0x80 // Event has this bit when the key is pressed +#define KBD_Empty 0xFF + +// Map column, bit -> keycode +static cyg_uint32 kbd_map[8][16] = { + // Column #0 + {KBD_Escape, KBD_1, KBD_Tab, KBD_CapsLock, + KBD_BackSlash, KBD_Space, KBD_LeftArrow, KBD_UpArrow, + KBD_DownArrow, KBD_RightArrow, KBD_LeftShift, KBD_Ctrl, + KBD_Function, KBD_LeftAlt, KBD_RightAlt, KBD_RightShift }, + // Column #1 + {KBD_F5, KBD_6, KBD_T, KBD_G, + KBD_B, KBD_Slash, KBD_SemiColon, KBD_P, + KBD_Hyphen, KBD_F10, KBD_Empty, KBD_Empty, + KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, + // Column #2 + {KBD_F4, KBD_5, KBD_R, KBD_F, + KBD_V, KBD_Del, KBD_Quote, KBD_LeftBrkt, + KBD_Equals, KBD_NumLock, KBD_Empty, KBD_Empty, + KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, + // Column #3 + {KBD_F3, KBD_4, KBD_E, KBD_D, + KBD_C, KBD_Ins, KBD_Empty, KBD_RightBrkt, + KBD_BackSpace, KBD_SysReq, KBD_Empty, KBD_Empty, + KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, + // Column #4 + {KBD_F2, KBD_3, KBD_W, KBD_S, + KBD_X, KBD_Empty, KBD_Enter, KBD_Empty, + KBD_Empty, KBD_ScrlLock, KBD_Empty, KBD_Empty, + KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, + // Column #5 + {KBD_F1, KBD_2, KBD_Q, KBD_A, + KBD_Z, KBD_End, KBD_PageDown, KBD_PageUp, + KBD_Home, KBD_Break, KBD_Empty, KBD_Empty, + KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, + // Column #6 + {KBD_F6, KBD_7, KBD_Y, KBD_H, + KBD_N, KBD_Period, KBD_L, KBD_O, + KBD_0, KBD_F9, KBD_Empty, KBD_Empty, + KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, + // Column #7 + {KBD_F7, KBD_8, KBD_U, KBD_J, + KBD_M, KBD_Comma, KBD_K, KBD_I, + KBD_9, KBD_F8, KBD_Empty, KBD_Empty, + KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, +}; + +static cyg_uint8 kbd_chars[96] = { + /* 0x00 - 0x0F */ + 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 - 0x1F */ + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08, 0x00, 0x00, 0x00, + /* 0x20 - 0x2F */ + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\', 0x00, 0x00, + /* 0x30 - 0x3F */ + 0x00, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 0x0D, 0x00, 0x00, 0x00, + /* 0x40 - 0x4F */ + 0x00, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x50 - 0x5F */ + 0x00, 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static cyg_uint8 kbd_shifted_chars[96] = { + /* 0x00 - 0x0F */ + '\b', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 - 0x1F */ + '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x08, 0x00, 0x00, 0x00, + /* 0x20 - 0x2F */ + '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '|', 0x00, 0x00, + /* 0x30 - 0x3F */ + 0x00, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', 0x0D, 0x00, 0x00, 0x00, + /* 0x40 - 0x4F */ + 0x00, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x50 - 0x5F */ + 0x00, 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// This ISR is called when the keyboard interrupt occurs +static int +keyboard_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs) +{ + cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_KBDINT); + return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR +} + +// This DSR handles the keyboard [logical] processing +static void +keyboard_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + // Tell the keyboard processing thread to give it a shot + cyg_semaphore_post(&kbd_sem); +} + +static void +kbd_server(cyg_addrword_t p) +{ + int col, bit, key, event, timeout; + diag_printf("KBD server here\n"); + while (TRUE) { + cyg_semaphore_wait(&kbd_sem); + // As long as keys are pressed, scan and update + timeout = 0; + while (TRUE) { + // Wait for 20ms - time to debounce keyboard + cyg_thread_delay(2); + // Scan keyboard + kbd_scan(); + // Reset state + for (key = 0; key < sizeof(kbd_new_state); key++) { + kbd_new_state[key] = 0; + } + // Check state of all keys and send events for those that change + for (col = 0; col < 8; col++) { + for (bit = 0; bit < 8; bit++) { + if (col_state[col] & (1<<bit)) { + key = kbd_map[col][bit]; + if (key != KBD_Empty) { + kbd_new_state[key] = 1; + } + } + if (ext_state[col] & (1<<bit)) { + key = kbd_map[col][bit+8]; + if (key != KBD_Empty) { + kbd_new_state[key] = 1; + } + } + } + } + // Compare new and old (known) states, generate events for changes + // Send events for modifier keys first. + for (key = 0; key < sizeof(kbd_new_state); key++) { + if (kbd_state[key] != kbd_new_state[key]) { + event = 0xFF; + switch (key) { + case KBD_LeftShift: + case KBD_RightShift: + case KBD_Ctrl: + case KBD_LeftAlt: + case KBD_RightAlt: + case KBD_Function: + case KBD_CapsLock: + if (kbd_state[key]) { + // Key going up + event = key; + } else { + // Key going down + event = key + KBD_Press; + } + kbd_state[key] = kbd_new_state[key]; + } + if (event != 0xFF) { + if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) { + diag_printf("KBD event lost: %x\n", event); + } + } + } + } + // First key up events + for (key = 0; key < sizeof(kbd_new_state); key++) { + if (kbd_state[key] != kbd_new_state[key]) { + if (kbd_state[key]) { + // Key going up + event = key; + } else { + // Key going down + event = key + KBD_Press; + } + if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) { + diag_printf("KBD event lost: %x\n", event); + } + } + kbd_state[key] = kbd_new_state[key]; + } + // Clear interrupt (true when keys are pressed) + cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT); +#if 0 + if (*(volatile cyg_uint32 *)INTSR2 & INTSR2_KBDINT) { + timeout = 0; + } else if (++timeout == 5) { + // No keys for 100ms + break; + } +#endif + } + // Allow interrupts to happen again + cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT); + cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT); + } +} + +void +kbd_init(void) +{ + // Initialize environment, setup interrupt handler + cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_KBDINT, + 99, // Priority - what goes here? + 0, // Data item passed to interrupt handler + (cyg_ISR_t *)keyboard_isr, + (cyg_DSR_t *)keyboard_dsr, + &kbd_interrupt_handle, + &kbd_interrupt); + cyg_drv_interrupt_attach(kbd_interrupt_handle); + cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT); + cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT); + // Set up the mbox for keyboard data + cyg_mbox_create(&kbd_events_mbox_handle, &kbd_events_mbox); + // This semaphore is set when there is a keypress + cyg_semaphore_init(&kbd_sem, 0); + // Create a thread whose job it is to de-bounce the keyboard and + // actually process the input, turning it into a series of events + cyg_thread_create(10, // Priority - just a number + kbd_server, // entry + 0, // initial parameter + "KBD_server", // Name + &kbd_server_stack[0], // Stack + STACK_SIZE, // Size + &kbd_server_thread_handle, // Handle + &kbd_server_thread_data // Thread data structure + ); + cyg_thread_resume(kbd_server_thread_handle); // Start it +} + +#define MOD_Shift 0x40 +#define MOD_Ctrl 0x20 +#define MOD_CapsLock 0x10 +static cyg_uint32 kbd_modifiers; + +cyg_uint8 +kbd_getc(void) +{ + cyg_uint8 ch; + cyg_uint32 kbd_event; + while (TRUE) { + kbd_event = (cyg_uint32)cyg_mbox_get(kbd_events_mbox_handle); + switch (kbd_event & 0x7F) { + case KBD_LeftShift: + case KBD_RightShift: + if (kbd_event & KBD_Press) { + kbd_modifiers |= MOD_Shift; + } else { + kbd_modifiers &= ~MOD_Shift; + } + break; + case KBD_Ctrl: + if (kbd_event & KBD_Press) { + kbd_modifiers |= MOD_Ctrl; + } else { + kbd_modifiers &= ~MOD_Ctrl; + } + break; + case KBD_CapsLock: + if (kbd_event & KBD_Press) { + kbd_modifiers ^= MOD_CapsLock; + } + break; + case KBD_LeftAlt: + case KBD_RightAlt: + case KBD_Function: + default: + } + // Return character [if one has arrived] + if (kbd_event & KBD_Press) { + if (kbd_modifiers & (MOD_Shift|MOD_CapsLock)) { + ch = kbd_shifted_chars[kbd_event & 0x7F]; + } else { + ch = kbd_chars[kbd_event & 0x7F]; + } + if (kbd_modifiers & MOD_Ctrl) { + ch &= 0x1F; + } + if (ch) { + return (ch); + } + } + } +}
--- a/packages/hal/arm/cl7211/current/misc/kbd_test.c +++ b/packages/hal/arm/cl7211/current/misc/kbd_test.c @@ -57,14 +57,8 @@ static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; -static char kbd_server_stack[STACK_SIZE]; -static cyg_thread kbd_server_thread_data; -static cyg_handle_t kbd_server_thread_handle; - -static cyg_interrupt kbd_interrupt; -static cyg_handle_t kbd_interrupt_handle; - #include "lcd_support.c" +#include "kbd_support.c" // FUNCTIONS @@ -74,384 +68,18 @@ cyg_test_exit(void) while (TRUE) ; } -static cyg_uint8 col_state[8]; -static cyg_uint8 ext_state[8]; - -static void -kbd_delay(void) -{ - volatile int i; - for (i = 0; i < 250; i++) ; -} - -static void -kbd_scan(void) -{ - int i; - cyg_uint8 port_data, ext_data; - // Turn off drive (de-select) all columns - *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | - SYSCON1_KBD_LOW; - for (i = 0; i < 8; i++) { - // Select column 'i' - *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | - SYSCON1_KBD_COL(i); - // Small pause to let the wires charge up :-) - kbd_delay(); - // Grab the data - col_state[i] = port_data = *(volatile cyg_uint8 *)PADR; - ext_state[i] = ext_data = *(volatile cyg_uint8 *)KBD_PORT; - // De-Select column 'i' - *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | - SYSCON1_KBD_TRISTATE; - // Allow line to gl slack - kbd_delay(); - } - // Turn on drive (select) all columns - necessary to see interrupts - *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) | - SYSCON1_KBD_HIGH; -} - - -static cyg_mbox kbd_events_mbox; -static cyg_handle_t kbd_events_mbox_handle; -static cyg_sem_t kbd_sem; -static cyg_uint8 kbd_state[128]; // Known state of each key -static cyg_uint8 kbd_new_state[128]; // Current state of each key - -#define MOD_Shift 0x40 -#define MOD_Ctrl 0x20 -#define MOD_CapsLock 0x10 -static cyg_uint32 kbd_modifiers; - -// Row #1 -#define KBD_Escape 0x00 -#define KBD_F1 0x01 -#define KBD_F2 0x02 -#define KBD_F3 0x03 -#define KBD_F4 0x04 -#define KBD_F5 0x05 -#define KBD_F6 0x06 -#define KBD_F7 0x07 -#define KBD_F8 0x08 -#define KBD_F9 0x09 -#define KBD_F10 0x0A -#define KBD_NumLock 0x0B -#define KBD_SysReq 0x0C -#define KBD_ScrlLock 0x0D -#define KBD_Break 0x0E -// Row #2 -#define KBD_1 0x10 -#define KBD_2 0x11 -#define KBD_3 0x12 -#define KBD_4 0x13 -#define KBD_5 0x14 -#define KBD_6 0x15 -#define KBD_7 0x16 -#define KBD_8 0x17 -#define KBD_9 0x18 -#define KBD_0 0x19 -#define KBD_Hyphen 0x1A -#define KBD_Equals 0x1B -#define KBD_BackSpace 0x1C -#define KBD_Home 0x1D -// Row #3 -#define KBD_Tab 0x20 -#define KBD_Q 0x21 -#define KBD_W 0x22 -#define KBD_E 0x23 -#define KBD_R 0x24 -#define KBD_T 0x25 -#define KBD_Y 0x26 -#define KBD_U 0x27 -#define KBD_I 0x28 -#define KBD_O 0x29 -#define KBD_P 0x2A -#define KBD_LeftBrkt 0x2B -#define KBD_RightBrkt 0x2C -#define KBD_BackSlash 0x2D -#define KBD_PageUp 0x2E -// Row #4 -#define KBD_CapsLock 0x30 -#define KBD_A 0x31 -#define KBD_S 0x32 -#define KBD_D 0x33 -#define KBD_F 0x34 -#define KBD_G 0x35 -#define KBD_H 0x36 -#define KBD_J 0x37 -#define KBD_K 0x38 -#define KBD_L 0x39 -#define KBD_SemiColon 0x3A -#define KBD_Quote 0x3B -#define KBD_Enter 0x3C -#define KBD_PageDown 0x3D -// Row #5 -#define KBD_LeftShift 0x40 -#define KBD_Z 0x41 -#define KBD_X 0x42 -#define KBD_C 0x43 -#define KBD_V 0x44 -#define KBD_B 0x45 -#define KBD_N 0x46 -#define KBD_M 0x47 -#define KBD_Comma 0x48 -#define KBD_Period 0x49 -#define KBD_Slash 0x4A -#define KBD_RightShift 0x4B -#define KBD_UpArrow 0x4C -#define KBD_End 0x4D -// Row #6 -#define KBD_Ctrl 0x50 -#define KBD_Function 0x51 -#define KBD_LeftAlt 0x52 -#define KBD_Accent 0x53 -#define KBD_Space 0x54 -#define KBD_RightAlt 0x55 -#define KBD_Ins 0x56 -#define KBD_Del 0x57 -#define KBD_LeftArrow 0x58 -#define KBD_DownArrow 0x59 -#define KBD_RightArrow 0x5A - -#define KBD_Press 0x80 // Event has this bit when the key is pressed -#define KBD_Empty 0xFF - -// Map column, bit -> keycode -static cyg_uint32 kbd_map[8][16] = { - // Column #0 - {KBD_Escape, KBD_1, KBD_Tab, KBD_CapsLock, - KBD_BackSlash, KBD_Space, KBD_LeftArrow, KBD_UpArrow, - KBD_DownArrow, KBD_RightArrow, KBD_LeftShift, KBD_Ctrl, - KBD_Function, KBD_LeftAlt, KBD_RightAlt, KBD_RightShift }, - // Column #1 - {KBD_F5, KBD_6, KBD_T, KBD_G, - KBD_B, KBD_Slash, KBD_SemiColon, KBD_P, - KBD_Hyphen, KBD_F10, KBD_Empty, KBD_Empty, - KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, - // Column #2 - {KBD_F4, KBD_5, KBD_R, KBD_F, - KBD_V, KBD_Del, KBD_Quote, KBD_LeftBrkt, - KBD_Equals, KBD_NumLock, KBD_Empty, KBD_Empty, - KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, - // Column #3 - {KBD_F3, KBD_4, KBD_E, KBD_D, - KBD_C, KBD_Ins, KBD_Empty, KBD_RightBrkt, - KBD_BackSpace, KBD_SysReq, KBD_Empty, KBD_Empty, - KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, - // Column #4 - {KBD_F2, KBD_3, KBD_W, KBD_S, - KBD_X, KBD_Empty, KBD_Enter, KBD_Empty, - KBD_Empty, KBD_ScrlLock, KBD_Empty, KBD_Empty, - KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, - // Column #5 - {KBD_F1, KBD_2, KBD_Q, KBD_A, - KBD_Z, KBD_End, KBD_PageDown, KBD_PageUp, - KBD_Home, KBD_Break, KBD_Empty, KBD_Empty, - KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, - // Column #6 - {KBD_F6, KBD_7, KBD_Y, KBD_H, - KBD_N, KBD_Period, KBD_L, KBD_O, - KBD_Empty, KBD_F9, KBD_Empty, KBD_Empty, - KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, - // Column #7 - {KBD_F7, KBD_8, KBD_U, KBD_J, - KBD_M, KBD_Comma, KBD_K, KBD_I, - KBD_Empty, KBD_F8, KBD_Empty, KBD_Empty, - KBD_Empty, KBD_Empty, KBD_Empty, KBD_Empty }, -}; - -static cyg_uint8 kbd_chars[96] = { - /* 0x00 - 0x0F */ - 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x10 - 0x1F */ - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08, 0x00, 0x00, 0x00, - /* 0x20 - 0x2F */ - '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\', 0x00, 0x00, - /* 0x30 - 0x3F */ - 0x00, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 0x0D, 0x00, 0x00, 0x00, - /* 0x40 - 0x4F */ - 0x00, 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x50 - 0x5F */ - 0x00, 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static cyg_uint8 kbd_shifted_chars[96] = { - /* 0x00 - 0x0F */ - '\b', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x10 - 0x1F */ - '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x08, 0x00, 0x00, 0x00, - /* 0x20 - 0x2F */ - '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '|', 0x00, 0x00, - /* 0x30 - 0x3F */ - 0x00, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', 0x0D, 0x00, 0x00, 0x00, - /* 0x40 - 0x4F */ - 0x00, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x50 - 0x5F */ - 0x00, 0x00, 0x00, 0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -// This ISR is called when the keyboard interrupt occurs -int -keyboard_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs) -{ - cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_KBDINT); - return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR -} - -// This DSR handles the keyboard [logical] processing -void -keyboard_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) -{ - // Tell the keyboard processing thread to give it a shot - cyg_semaphore_post(&kbd_sem); -} - -static void -kbd_server(cyg_addrword_t p) -{ - int col, bit, key, event, timeout; - diag_printf("KBD server here\n"); - // This semaphore is set when there is a keypress - cyg_semaphore_init(&kbd_sem, 0); - while (TRUE) { - cyg_semaphore_wait(&kbd_sem); - // As long as keys are pressed, scan and update - timeout = 0; - while (TRUE) { - // Wait for 20ms - time to debounce keyboard - cyg_thread_delay(2); - // Scan keyboard - kbd_scan(); - // Reset state - for (key = 0; key < sizeof(kbd_new_state); key++) { - kbd_new_state[key] = 0; - } - // Check state of all keys and send events for those that change - for (col = 0; col < 8; col++) { - for (bit = 0; bit < 8; bit++) { - if (col_state[col] & (1<<bit)) { - key = kbd_map[col][bit]; - if (key != KBD_Empty) { - kbd_new_state[key] = 1; - } - } - if (ext_state[col] & (1<<bit)) { - key = kbd_map[col][bit+8]; - if (key != KBD_Empty) { - kbd_new_state[key] = 1; - } - } - } - } - // Compare new and old (known) states, generate events for changes - // Send events for modifier keys first. - for (key = 0; key < sizeof(kbd_new_state); key++) { - if (kbd_state[key] != kbd_new_state[key]) { - event = 0xFF; - switch (key) { - case KBD_LeftShift: - case KBD_RightShift: - case KBD_Ctrl: - case KBD_LeftAlt: - case KBD_RightAlt: - case KBD_Function: - case KBD_CapsLock: - if (kbd_state[key]) { - // Key going up - event = key; - } else { - // Key going down - event = key + KBD_Press; - } - kbd_state[key] = kbd_new_state[key]; - } - if (event != 0xFF) { - if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) { - diag_printf("KBD event lost: %x\n", event); - } - } - } - } - // First key up events - for (key = 0; key < sizeof(kbd_new_state); key++) { - if (kbd_state[key] != kbd_new_state[key]) { - if (kbd_state[key]) { - // Key going up - event = key; - } else { - // Key going down - event = key + KBD_Press; - } - if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) { - diag_printf("KBD event lost: %x\n", event); - } - } - kbd_state[key] = kbd_new_state[key]; - } - // Clear interrupt (true when keys are pressed) - cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT); - if (*(volatile cyg_uint32 *)INTSR2 & INTSR2_KBDINT) { - timeout = 0; - } else if (++timeout == 5) { - // No keys for 100ms - break; - } - } - // Allow interrupts to happen again - cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT); - cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT); - } -} - static void kbd_exercise(cyg_addrword_t p) { - int i; - cyg_uint8 kbd_event, ch; + cyg_uint8 ch; diag_printf("KBD test here!\n"); + // Initialize keyboard driver + kbd_init(); + while (TRUE) { - kbd_event = (cyg_uint8)cyg_mbox_get(kbd_events_mbox_handle); - switch (kbd_event & 0x7F) { - case KBD_LeftShift: - case KBD_RightShift: - if (kbd_event & KBD_Press) { - kbd_modifiers |= MOD_Shift; - } else { - kbd_modifiers &= ~MOD_Shift; - } - break; - case KBD_Ctrl: - if (kbd_event & KBD_Press) { - kbd_modifiers |= MOD_Ctrl; - } else { - kbd_modifiers &= ~MOD_Ctrl; - } - break; - case KBD_CapsLock: - if (kbd_event & KBD_Press) { - kbd_modifiers |= MOD_CapsLock; - } else { - kbd_modifiers &= ~MOD_CapsLock; - } - break; - case KBD_LeftAlt: - case KBD_RightAlt: - case KBD_Function: - default: - } - // Show character - if (kbd_event & KBD_Press) { - if (kbd_modifiers & (MOD_Shift|MOD_CapsLock)) { - ch = kbd_shifted_chars[kbd_event & 0x7F]; - } else { - ch = kbd_chars[kbd_event & 0x7F]; - } - if (ch) { - diag_printf("CH = 0x%x:'%c'\n", ch, ch); - } - } + ch = kbd_getc(); + diag_printf("CH = 0x%x:'%c'\n", ch, ch); } diag_printf("All done!\n"); @@ -461,20 +89,6 @@ kbd_exercise(cyg_addrword_t p) externC void cyg_start( void ) { - // Initialize environment, setup interrupt handler - *(volatile cyg_uint8 *)PADDR = 0x00; // All bits input - cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_KBDINT, - 99, // Priority - what goes here? - 0, // Data item passed to interrupt handler - (cyg_ISR_t *)keyboard_isr, - (cyg_DSR_t *)keyboard_dsr, - &kbd_interrupt_handle, - &kbd_interrupt); - cyg_drv_interrupt_attach(kbd_interrupt_handle); - cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT); - cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT); - // Set up the mbox for keyboard data - cyg_mbox_create(&kbd_events_mbox_handle, &kbd_events_mbox); // Create a main thread, so we can run the scheduler and have time 'pass' cyg_thread_create(11, // Priority - just a number kbd_exercise, // entry @@ -486,18 +100,6 @@ cyg_start( void ) &thread_data // Thread data structure ); cyg_thread_resume(thread_handle); // Start it - // Create another thread whose job it is to de-bounce the keyboard and - // actually process the input, turning it into a series of events - cyg_thread_create(10, // Priority - just a number - kbd_server, // entry - 0, // initial parameter - "KBD_server", // Name - &kbd_server_stack[0], // Stack - STACK_SIZE, // Size - &kbd_server_thread_handle, // Handle - &kbd_server_thread_data // Thread data structure - ); - cyg_thread_resume(kbd_server_thread_handle); // Start it // Let 'em fly... cyg_scheduler_start(); } // cyg_package_start()
new file mode 100644 --- /dev/null +++ b/packages/hal/arm/cl7211/current/misc/lcd_panel_support.c @@ -0,0 +1,213 @@ +//========================================================================== +// +// panel_support.c +// +// Cirrus CL72xx eval board LCD touch panel support code +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Cygnus eCos Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://sourceware.cygnus.com/ecos +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Cygnus Operating System, released +// September 30, 1998. +// +// The Initial Developer of the Original Code is Cygnus. Portions created +// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas +// Date: 1999-09-13 +// Description: Tool used to support the LCD touch panel +//####DESCRIPTIONEND#### + +static char lcd_panel_server_stack[STACK_SIZE]; +static cyg_thread lcd_panel_server_thread_data; +static cyg_handle_t lcd_panel_server_thread_handle; + +static cyg_interrupt lcd_panel_interrupt; +static cyg_handle_t lcd_panel_interrupt_handle; + +static cyg_mbox lcd_panel_events_mbox; +static cyg_handle_t lcd_panel_events_mbox_handle; +static cyg_sem_t lcd_panel_sem; + +#define SYNCIO_TXFRMEN (1<<14) +#define SYNCIO_FRAMELEN(n) (n<<8) +#define ADC_START (1<<7) +#define ADC_CHAN(n) (n<<4) +#define ADC_UNIPOLAR (1<<3) +#define ADC_SINGLE (1<<2) +#define ADC_EXT_CLOCK (3<<0) +#define TOUCH_CTL KBD_PORT + +// FUNCTIONS + +static cyg_uint32 +adc_sample(int chan) +{ + cyg_uint32 val; + *(volatile cyg_uint32 *)SYNCIO = SYNCIO_TXFRMEN | SYNCIO_FRAMELEN(24) | + ADC_START | ADC_CHAN(chan) | ADC_UNIPOLAR | ADC_SINGLE | ADC_EXT_CLOCK; + while (*(volatile cyg_uint32 *)SYSFLG1 & SYSFLG1_SSIBUSY) ; + val = *(volatile cyg_uint32 *)SYNCIO; + return (val & 0xFFFF); +} + +static void +panel_delay(void) +{ + volatile int i; + for (i = 0; i < 800; i++) ; +} + +// This ISR is called when the touch panel interrupt occurs +static int +lcd_panel_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs) +{ + cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EINT2); + return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR +} + +// This DSR starts up the touch panel [logical] processing +static void +lcd_panel_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + // Tell the panel processing thread to give it a shot + cyg_semaphore_post(&lcd_panel_sem); +} + +// Assumption: if the keypress vanishes for 5*20 ms, it probably isn't there +#define LCD_PANEL_TIMEOUT 5 + +static __inline__ int +abs(int x) +{ + if (x < 0) return -x; + return x; +} + +static void +lcd_panel_server(cyg_addrword_t p) +{ + int iX, iY, newX, newY, diffX, diffY, timeout, samples; + cyg_uint32 event; + diag_printf("LCD panel server here\n"); + while (TRUE) { + cyg_semaphore_wait(&lcd_panel_sem); + samples = 0; iX = 0; iY = 0; + // Wait for press to go away (no drag support) + timeout = 0; + while (timeout < LCD_PANEL_TIMEOUT) { + *(volatile cyg_uint8 *)TOUCH_CTL = 0x00; // Disable drives + while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ; + *(volatile cyg_uint8 *)TOUCH_CTL = 0x70; // Idle state (so interrupt works) + cyg_thread_delay(2); // Wait 20 ms + if (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) { + // Still pressed + // Drive TSPY, ground TSMY, and disconnect TSPX and TSMX + *(volatile cyg_uint8 *)TOUCH_CTL = 0x50; + panel_delay(); + newY = adc_sample(2); + // Drive TSPX, ground TSMX, and disconnect TSPY and TSMY + *(volatile cyg_uint8 *)TOUCH_CTL = 0xA0; + panel_delay(); + newX = adc_sample(7); +#if 0 + diag_printf("timeout: %d, ISR: %x, newX: %d, newY: %d\n", + timeout, *(volatile cyg_uint32 *)INTSR1, newX, newY); +#endif + // See if this sample makes any sense + if (samples) { + diffX = abs(iX/samples - newX); + diffY = abs(iY/samples - newY); + if ((diffX <= ((iX/samples)/4)) && + (diffY <= ((iY/samples)/4))) { + samples++; + iX += newX; + iY += newY; + } else { +#if 0 + diag_printf("Discard - newX: %d, X: %d, newY: %d, Y: %d\n", + newX, iX/samples, newY, iY/samples); +#endif + break; + } + } else { + iX = newX; + iY = newY; + samples = 1; + } + timeout = 0; + } else { + timeout++; + } + } + if (samples) { + // Send event to user level + event = (iX/samples)<<16 | (iY/samples); + if (!cyg_mbox_tryput(lcd_panel_events_mbox_handle, (void *)event)) { + diag_printf("LCD event lost: %x\n", event); + } + } + *(volatile cyg_uint8 *)TOUCH_CTL = 0x00; // Disable drives + while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ; + *(volatile cyg_uint8 *)TOUCH_CTL = 0x70; // Idle state (so interrupt works) + cyg_thread_delay(10); + cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2); + } +} + +static void +lcd_panel_init(void) +{ + // Enable touch panel + *(volatile cyg_uint8 *)PEDR |= 0x04; + + // Idle state (so interrupt works) + *(volatile cyg_uint8 *)TOUCH_CTL = 0x70; + + // Enable ADC machinery + *(volatile cyg_uint32 *)SYSCON1 |= SYSCON1_ADC_CLOCK_128kHZ; + + cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EINT2, + 99, // Priority - what goes here? + 0, // Data item passed to interrupt handler + lcd_panel_isr, + lcd_panel_dsr, + &lcd_panel_interrupt_handle, + &lcd_panel_interrupt); + cyg_drv_interrupt_attach(lcd_panel_interrupt_handle); + cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EINT2); + cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2); + // Set up the mbox for panel data + cyg_mbox_create(&lcd_panel_events_mbox_handle, &lcd_panel_events_mbox); + // This semaphore is set when there is a touch + cyg_semaphore_init(&lcd_panel_sem, 0); + // Create a thread whose job it is to de-bounce the keyboard and + // actually process the input, turning it into a series of events + cyg_thread_create(10, // Priority - just a number + lcd_panel_server, // entry + 0, // initial parameter + "LCD_PANEL_server", // Name + &lcd_panel_server_stack[0], // Stack + STACK_SIZE, // Size + &lcd_panel_server_thread_handle, // Handle + &lcd_panel_server_thread_data // Thread data structure + ); + cyg_thread_resume(lcd_panel_server_thread_handle); // Start it +}
--- a/packages/hal/arm/cl7211/current/misc/lcd_support.c +++ b/packages/hal/arm/cl7211/current/misc/lcd_support.c @@ -41,6 +41,8 @@ #define LAST_CHAR 0x7E #define FONT_HEIGHT 8 #define FONT_WIDTH 8 +#define CURSOR_ON 0x5F +#define CURSOR_OFF 0x20 static char font_table[LAST_CHAR-FIRST_CHAR+1][8] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* */ @@ -155,20 +157,21 @@ static char font_table[LAST_CHAR-FIRST_C #define PIXEL_MASK ((1<<PIXELS_PER_BYTE)-1) // Physical screen info -int lcd_depth; // Should be 1, 2, or 4 -int lcd_width = LCD_WIDTH; -int lcd_height = LCD_HEIGHT; -cyg_uint8 *lcd_base = (cyg_uint8 *)0xC0000000; +static int lcd_depth; // Should be 1, 2, or 4 +static int lcd_width = LCD_WIDTH; +static int lcd_height = LCD_HEIGHT; +static cyg_uint8 *lcd_base = (cyg_uint8 *)0xC0000000; // Virtual screen info -int curX = 0; // Last used position -int curY = 0; -int width = LCD_WIDTH / (FONT_WIDTH*NIBBLES_PER_PIXEL); -int height = LCD_HEIGHT / (FONT_HEIGHT*SCREEN_SCALE); -int fg = 0x0F; -int bg = 0x00; +static int curX = 0; // Last used position +static int curY = 0; +static int width = LCD_WIDTH / (FONT_WIDTH*NIBBLES_PER_PIXEL); +static int height = LCD_HEIGHT / (FONT_HEIGHT*SCREEN_SCALE); +static int fg = 0x0F; +static int bg = 0x00; // Functions +static void lcd_drawc(cyg_int8 c, int x, int y); void lcd_on(int depth) @@ -226,7 +229,7 @@ lcd_on(int depth) } // Clear screen -static void +void lcd_clear(void) { cyg_int8 *ptr = lcd_base; @@ -235,6 +238,21 @@ lcd_clear(void) *ptr++ = 0; } curX = 0; curY = 0; + lcd_drawc(CURSOR_ON, curX, curY); +} + +// Position cursor +void +lcd_moveto(int X, int Y) +{ + lcd_drawc(CURSOR_OFF, curX, curY); + if (X < 0) X = 0; + if (X >= width) X = width-1; + curX = X; + if (Y < 0) Y = 0; + if (Y >= height) Y = height-1; + curY = Y; + lcd_drawc(CURSOR_ON, curX, curY); } // Render a character at position (X,Y) with current background/foreground @@ -291,9 +309,11 @@ lcd_drawc(cyg_int8 c, int x, int y) } } -static void +// Draw one character at the current position +void lcd_putc(cyg_int8 c) { + lcd_drawc(CURSOR_OFF, curX, curY); switch (c) { case '\r': curX = 0; @@ -308,6 +328,7 @@ lcd_putc(cyg_int8 c) if (curY < 0) curY = 0; curX = width-1; } + break; default: lcd_drawc(c, curX, curY); curX++; @@ -316,5 +337,163 @@ lcd_putc(cyg_int8 c) curX = 0; } } + lcd_drawc(CURSOR_ON, curX, curY); +} + +// Basic LCD 'printf()' support + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#include <stdarg.h> + +#define is_digit(c) ((c >= '0') && (c <= '9')) + +static int +_cvt(unsigned long val, char *buf, long radix, char *digits) +{ + char temp[80]; + char *cp = temp; + int length = 0; + if (val == 0) { + /* Special case */ + *cp++ = '0'; + } else { + while (val) { + *cp++ = digits[val % radix]; + val /= radix; + } + } + while (cp != temp) { + *buf++ = *--cp; + length++; + } + *buf = '\0'; + return (length); } +int +lcd_vprintf(void (*putc)(cyg_int8), const char *fmt0, va_list ap) +{ + char c, sign, *cp; + int left_prec, right_prec, zero_fill, length, pad, pad_on_right; + char buf[32]; + long val; + while ((c = *fmt0++)) { + cp = buf; + length = 0; + if (c == '%') { + c = *fmt0++; + left_prec = right_prec = pad_on_right = 0; + if (c == '-') { + c = *fmt0++; + pad_on_right++; + } + if (c == '0') { + zero_fill = TRUE; + c = *fmt0++; + } else { + zero_fill = FALSE; + } + while (is_digit(c)) { + left_prec = (left_prec * 10) + (c - '0'); + c = *fmt0++; + } + if (c == '.') { + c = *fmt0++; + zero_fill++; + while (is_digit(c)) { + right_prec = (right_prec * 10) + (c - '0'); + c = *fmt0++; + } + } else { + right_prec = left_prec; + } + sign = '\0'; + switch (c) { + case 'd': + case 'x': + case 'X': + val = va_arg(ap, long); + switch (c) { + case 'd': + if (val < 0) { + sign = '-'; + val = -val; + } + length = _cvt(val, buf, 10, "0123456789"); + break; + case 'x': + length = _cvt(val, buf, 16, "0123456789abcdef"); + break; + case 'X': + length = _cvt(val, buf, 16, "0123456789ABCDEF"); + break; + } + break; + case 's': + cp = va_arg(ap, char *); + length = strlen(cp); + break; + case 'c': + c = va_arg(ap, long /*char*/); + (*putc)(c); + continue; + default: + (*putc)('?'); + } + pad = left_prec - length; + if (sign != '\0') { + pad--; + } + if (zero_fill) { + c = '0'; + if (sign != '\0') { + (*putc)(sign); + sign = '\0'; + } + } else { + c = ' '; + } + if (!pad_on_right) { + while (pad-- > 0) { + (*putc)(c); + } + } + if (sign != '\0') { + (*putc)(sign); + } + while (length-- > 0) { + (*putc)(c = *cp++); + if (c == '\n') { + (*putc)('\r'); + } + } + if (pad_on_right) { + while (pad-- > 0) { + (*putc)(' '); + } + } + } else { + (*putc)(c); + if (c == '\n') { + (*putc)('\r'); + } + } + } +} + +int +lcd_printf(char const *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = lcd_vprintf(lcd_putc, fmt, ap); + va_end(ap); + return (ret); +} +
--- a/packages/hal/arm/cl7211/current/misc/panel_test.c +++ b/packages/hal/arm/cl7211/current/misc/panel_test.c @@ -31,7 +31,7 @@ // // Author(s): gthomas // Contributors: gthomas -// Date: 1999-05-15 +// Date: 1999-09-06 // Description: Tool used to test LCD touch panel //####DESCRIPTIONEND#### @@ -56,19 +56,9 @@ static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; -static cyg_interrupt panel_interrupt; -static cyg_handle_t panel_interrupt_handle; #include "lcd_support.c" - -#define SYNCIO_TXFRMEN (1<<14) -#define SYNCIO_FRAMELEN(n) (n<<8) -#define ADC_START (1<<7) -#define ADC_CHAN(n) (n<<4) -#define ADC_UNIPOLAR (1<<3) -#define ADC_SINGLE (1<<2) -#define ADC_EXT_CLOCK (3<<0) -#define TOUCH_CTL KBD_PORT +#include "lcd_panel_support.c" // FUNCTIONS @@ -78,78 +68,20 @@ cyg_test_exit(void) while (TRUE) ; } -static cyg_uint32 -adc_sample(int chan) -{ - cyg_uint32 val; - *(volatile cyg_uint32 *)SYNCIO = SYNCIO_TXFRMEN | SYNCIO_FRAMELEN(24) | - ADC_START | ADC_CHAN(chan) | ADC_UNIPOLAR | ADC_SINGLE | ADC_EXT_CLOCK; - while (*(volatile cyg_uint32 *)SYSFLG1 & SYSFLG1_SSIBUSY) ; - val = *(volatile cyg_uint32 *)SYNCIO; - return val & 0xFFFF; -} - -static void -panel_delay(void) -{ - volatile int i; - for (i = 0; i < 50; i++) ; -} - -// This ISR is called when the touch panel interrupt occurs -int -cyg_hal_panel_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs) -{ - int iX, iY; - cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EINT2); - diag_printf("Touched!\n"); - *(volatile cyg_uint8 *)TOUCH_CTL = 0x50; // Drive TSPY, ground TSMY, and disconnect TSPX and TSMX - panel_delay(); - iY = adc_sample(2); - *(volatile cyg_uint8 *)TOUCH_CTL = 0xA0; // Drive TSPX, ground TSMX, and disconnect TSPY and TSMY - panel_delay(); - iX = adc_sample(7); - diag_printf("X = %d, Y = %d, ISR1: %x\n", iX, iY, *(volatile cyg_uint32 *)INTSR1); - *(volatile cyg_uint8 *)TOUCH_CTL = 0x00; // Disable drives - while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ; - *(volatile cyg_uint8 *)TOUCH_CTL = 0x70; // Idle state (so interrupt works) -// cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2); - return 0; // No need to run DSR -} - static void panel_exercise(cyg_addrword_t p) { - int i, j; + int i; + cyg_uint32 val; + diag_printf("LCD touch panel test here!\n"); - *(volatile cyg_uint8 *)PEDDR = 0x0F; // Register E data direction - *(volatile cyg_uint8 *)PEDR |= 0x04; // Enable touch panel - - diag_printf("PEDR = %x\n", *(volatile cyg_uint8 *)PEDR); - - *(volatile cyg_uint8 *)TOUCH_CTL = 0x70; // Idle state (so interrupt works) - - lcd_on(4); - lcd_clear(); - - *(volatile cyg_uint32 *)SYSCON1 |= SYSCON1_ADC_CLOCK_128kHZ; - - cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EINT2, - 99, // Priority - what goes here? - 0, // Data item passed to interrupt handler - cyg_hal_panel_isr, - 0, - &panel_interrupt_handle, - &panel_interrupt); - cyg_drv_interrupt_attach(panel_interrupt_handle); - cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EINT2); - cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2); + lcd_panel_init(); for (i = 0; i < 50; i++) { diag_printf("Please touch screen now:\n"); - cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2); - cyg_thread_delay(5*100); + val = (cyg_uint32)cyg_mbox_get(lcd_panel_events_mbox_handle); + diag_printf("val = %x, X = %d, Y = %d\n", val, (val>>16), val & 0xFFFF); } diag_printf("All done!\n");
--- a/packages/hal/arm/cl7211/current/src/cl7211_misc.c +++ b/packages/hal/arm/cl7211/current/src/cl7211_misc.c @@ -279,6 +279,8 @@ void hal_hardware_init(void) // reading the hardware a lot, since the interrupt status is split across // three separate registers. +int hal_spurious_ints; + int hal_IRQ_handler(void) { struct regmap *map = hal_interrupt_status_regmap; @@ -291,6 +293,7 @@ int hal_IRQ_handler(void) } map++; // Next interrupt status register } + hal_spurious_ints++; return CYGNUM_HAL_INTERRUPT_unused; // This shouldn't happen! }
--- a/packages/hal/arm/cl7211/current/src/hal_diag.c +++ b/packages/hal/arm/cl7211/current/src/hal_diag.c @@ -86,6 +86,7 @@ #endif #endif + /*---------------------------------------------------------------------------*/ // CL7211 Serial Port (UARTx) for Debug
--- a/packages/hal/arm/cl7211/current/src/plf_stub.c +++ b/packages/hal/arm/cl7211/current/src/plf_stub.c @@ -73,6 +73,7 @@ static cyg_interrupt gdb_interrupt; static cyg_handle_t gdb_interrupt_handle; #endif + //----------------------------------------------------------------------------- #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
--- a/packages/hal/arm/cl7211/current/support/Makefile +++ b/packages/hal/arm/cl7211/current/support/Makefile @@ -3,8 +3,12 @@ # DL_FILES = dl_7211.o io.o +DOWNLOAD_FILES = download_file.o io.o -all: dl_7211 +all: dl_7211 download dl_7211: $(DL_FILES) - $(CC) -o $@ $(DL_FILES) \ No newline at end of file + $(CC) -o $@ $(DL_FILES) + +download: $(DOWNLOAD_FILES) + $(CC) -o $@ $(DOWNLOAD_FILES)
new file mode 100644 --- /dev/null +++ b/packages/hal/arm/cl7211/current/support/download_file.c @@ -0,0 +1,260 @@ +//**************************************************************************** +// +// download_file.c - Send a raw data file to the EB72xx board. +// +// Adapted from the Cirrus Logic 'DOWNLOAD.C' program +// +// Copyright (c) 1999 Cirrus Logic, Inc. +// +// Adapted for Linux by Cygnus Solutions, Inc. +// +//**************************************************************************** +#include <stdio.h> +#include "bootcode.h" + +#define DEFAULT_PORT "/dev/ttyS0" +extern char ReceiveChar(long); +extern void SendChar(long, char); +extern void SetBaud(long, long); +extern int CharRead(long port); +extern void WaitForOutputReady(long port); +extern long OpenPort(char *); + +//**************************************************************************** +// +// WaitFor waits until a specific character is read from the comm port. +// +//**************************************************************************** +void +WaitFor(long lPort, char cWaitChar) +{ + char cChar; + + // + // Wait until we read a specific character from the comm port. + // + while(1) + { + // + // Read a character. + // + cChar = ReceiveChar(lPort); + + // + // Stop waiting if we received the character. + // + if(cChar == cWaitChar) + { + break; + } + } +} + +//**************************************************************************** +// +// This program waits for the '<' character from the boot ROM, sends the boot +// code, waits for the '>' from the boot ROM, waits for the '?' from the boot +// code, changes the serial port rate (preferably to 115200), downloads the +// user data file, and then prints out progress status as the boot code writes +// the user data file to the flash. +// +//**************************************************************************** +void +main(int argc, char *argv[]) +{ + long lPort; + long lRate = 38400; + long lFileSize, lIdx; + char cChar, cFirstChar, *pcFile, cRateChar; + FILE *pFile; + + // + // Make sure that a filename was specified. + // + if(argc < 2) + { + fprintf(stderr, "Usage: download <filename> {<baud rate> {<comm port>}}\n"); + return; + } + + // + // If a baud rate was specified, then read it and make sure it is valid. + // + if(argc > 2) + { + lRate = atoi(argv[2]); + if((lRate != 9600) && (lRate != 19200) && (lRate != 28800) && + (lRate != 38400) && (lRate != 57600) && (lRate != 115200)) + { + fprintf(stderr, "Invalid baud rate.\n"); + return; + } + } + + // + // If a comm port was specified, then read it and make sure it is valid. + // + if(argc > 3) + { + lPort = OpenPort(argv[3]); + } else + { + lPort = OpenPort(DEFAULT_PORT); + } + if (lPort < 0) + { + fprintf(stderr, "Can't open port\n"); + return; + } + + // + // Open the file to be downloaded. + // + pFile = fopen(argv[1], "rb"); + if(!pFile) + { + fprintf(stderr, "Could not open file '%s'.\n", argv[1]); + return; + } + + // + // Get the size of the file. + // + fseek(pFile, 0, SEEK_END); + lFileSize = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + + // + // Allocate memory to hold the file contents. + // + pcFile = (char *)malloc(lFileSize); + if(!pcFile) + { + fprintf(stderr, "Failed to allocate memory for the file.\n"); + return; + } + + // + // Read the contents of the file into memory. + // + if(fread(pcFile, 1, lFileSize, pFile) != lFileSize) + { + fprintf(stderr, "Failed to read file '%s'.\n", argv[1]); + return; + } + + // + // Close the file. + // + fclose(pFile); + + // + // Open the port to the desired baud rate. + // + SetBaud(lPort, lRate); + + // + // Empty out the input queue. + // + while(CharReady(lPort)) + { + cChar = ReceiveChar(lPort); + } + + // + // Tell the user to reset the board. + // + fprintf(stderr, "Waiting for the board to wakeup..."); + + // + // Send a '-' character until we receive back a '?' character. + // + while(1) + { + // + // Send a '-' character. + // + SendChar(lPort, '-'); + + // + // Wait a little bit. + // + for(lIdx = 0; lIdx < 1024 * 1024; lIdx++) + { + } + + // + // See if there is a character waiting to be read. + // + if(CharReady(lPort)) + { + // + // Read the character. + // + cChar = ReceiveChar(lPort); + + // + // Quit waiting if this is a '?'. + // + if(cChar == '?') + { + break; + } + } + } + + // + // Empty out the input queue. + // + while(CharReady(lPort)) + { + cChar = ReceiveChar(lPort); + } + + // + // Send the download file "command" + // + SendChar(lPort, 'D'); + + // + // Send the length of the data file. + // + SendChar(lPort, (char)(lFileSize & 0xFF)); + SendChar(lPort, (char)((lFileSize >> 8) & 0xFF)); + SendChar(lPort, (char)((lFileSize >> 16) & 0xFF)); + SendChar(lPort, (char)((lFileSize >> 24) & 0xFF)); + + // + // Tell the user that we are downloading the file data. + // + fprintf(stderr, "\nDownloading file data...( 0%%)"); + + // + // Send the actual data in the file. + // + for(lIdx = 0; lIdx < lFileSize; lIdx++) + { + // + // Send this byte. + // + SendChar(lPort, pcFile[lIdx]); + + // + // Periodically print out our progress. + // + if((lIdx & 127) == 127) + { + fprintf(stderr, "\b\b\b\b\b%3d%%)", ((lIdx + 1) * 100) / lFileSize); + // + // Read a character from the boot code. + // + cChar = ReceiveChar(lPort); + } + } + + // + // Tell the user we are done. + // + fprintf(stderr, "\nSuccessfully downloaded '%s'.\n", argv[1]); +} +
--- a/packages/hal/common/current/ChangeLog +++ b/packages/hal/common/current/ChangeLog @@ -1,3 +1,15 @@ +1999-09-21 Gary Thomas <gthomas@cygnus.co.uk> + + * src/thread-packets.c: Fix some typos in comments. + +1999-09-13 Gary Thomas <gthomas@cygnus.co.uk> + + * include/pkgconf/hal.h: Add new config option to allow spurious + interrupts to be ignored by the HAL. + + * src/generic-stub.c (__process_packet): Build in version string + (date/time) for stubs in ROM to be returned via 'd' packet. + 1999-09-09 Jonathan Larmour <jlarmour@cygnus.co.uk> * include/pkgconf/hal.h (CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS): Rename
--- a/packages/hal/common/current/include/pkgconf/hal.h +++ b/packages/hal/common/current/include/pkgconf/hal.h @@ -205,6 +205,18 @@ of RAM needed for interrupt decoding tables and code." } + cdl_option CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS { + display "Ignore spurious [fleeting] interrupts" + parent CYGPKG_HAL_COMMON_INTERRUPTS + description " + On some hardware, interrupt sources may not be de-bounced or + de-glitched. Rather than try to handle these interrupts (no + handling may be possible), this option allows the HAL to simply + ignore them. In most cases, if the interrupt is real it will + reoccur in a detectable form." + } + + }}CFG_DATA */ @@ -214,6 +226,7 @@ #undef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING #define CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT #undef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN +#undef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS /* {{CFG_DATA
--- a/packages/hal/common/current/src/generic-stub.c +++ b/packages/hal/common/current/src/generic-stub.c @@ -838,6 +838,11 @@ int case 'd': /* toggle debug flag */ +#ifdef __ECOS__ +#if !defined(CYG_HAL_STARTUP_RAM) // Only for ROM based stubs + strcpy(remcomOutBuffer, "eCos GDB stubs - built " __DATE__ " / " __TIME__); +#endif +#endif // __ECOS__ break; case 'q':
--- a/packages/hal/common/current/src/hal_stub.c +++ b/packages/hal/common/current/src/hal_stub.c @@ -117,6 +117,7 @@ void #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT + #if (HAL_BREAKINST_SIZE == 1) typedef cyg_uint8 t_inst; #elif (HAL_BREAKINST_SIZE == 2) @@ -162,6 +163,7 @@ cyg_hal_gdb_remove_break (target_registe return 0; } + #endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT // Use this function to disable serial interrupts whenever reply
--- a/packages/hal/common/current/src/thread-packets.c +++ b/packages/hal/common/current/src/thread-packets.c @@ -160,7 +160,7 @@ static char * unpack_int(char * buf, int return buf + 8 ; } -/* We are NOT depending upun extensive libraries */ +/* We are NOT depending upon extensive libraries */ static int ishex(char ch,int *val) { if ((ch >= 'a') && (ch <= 'f')) @@ -211,7 +211,7 @@ static char * pack_varlen_hex( n[i] = value & 0x0f ; value = value >> 4 ; } - i = 0 ; /* we had descrmented it to -1 */ + i = 0 ; /* we had decrmented it to -1 */ while (n[i] == 0 ) i++ ; /* drop leading zeroes */ while (i++ < 8) *pkt++ = hexchars[n[i]] ; /* pack the number */ } @@ -336,8 +336,8 @@ static char * pack_threadid(char * pkt, return pkt ; } /* stub_pack_threadid */ -/* UNFORTUNATLY, not all ow the extended debugging system has yet been - converted to 64 but thread referenecces and process identifiers. +/* UNFORTUNATELY, not all of the extended debugging system has yet been + converted to 64 but thread references and process identifiers. These routines do the conversion. An array of bytes is the correct treatment of an opaque identifier. ints have endian issues.
--- a/packages/hal/mips/arch/current/ChangeLog +++ b/packages/hal/mips/arch/current/ChangeLog @@ -1,3 +1,32 @@ +1999-09-17 Jonathan Larmour <jlarmour@cygnus.co.uk> + + * src/vectors.S (__default_exception_vsr): + Rename exception_handler()->cyg_hal_exception_handler() + After all, we will just do a jump rather than a jal into + cyg_hal_exception_handler() + (restore_state): Make the change below (by Hugo) be conditional + on CYG_HAL_USE_ROM_MONITOR_CYGMON. + Add explanatory comment about the additions for Cygmon + + * src/hal_misc.c (hal_default_isr): Use new format HAL_DIAG_IRQ_CHECK() + and check return code is negative; if so, return + (cyg_hal_exception_handler): Rename from exception_handler() + Now return cyg_uint32, but default to returning 0 always + +1999-09-16 Hugo Tyson <hmt@cygnus.co.uk> + + This set of changes with matching ones in jmr3904 comes from Mark + Salter's work to make jmr3904 CygMon talk Ethernet. + + * src/vectors.S (restore_state): Call CygMon for exceptions or + unhandled interrupts if CYG_HAL_USE_ROM_MONITOR. This is why the + return value from the ISR is preserved. Don't fully understand + this. + + * src/hal_misc.c (hal_default_isr): Call into hal_diag via + HAL_DIAG_IRQ_CHECK if it's defined and CYG_HAL_USE_ROM_MONITOR. + This lets CygMon check for network interrupts &c. + 1999-09-09 Nick Garnett <nickg@cygnus.co.uk> * include/arch.inc:
--- a/packages/hal/mips/arch/current/src/hal_misc.c +++ b/packages/hal/mips/arch/current/src/hal_misc.c @@ -72,7 +72,7 @@ externC void *__mem_fault_handler; externC cyg_uint8 cyg_hal_mips_process_fpe( HAL_SavedRegisters *regs ); -externC void exception_handler(HAL_SavedRegisters *regs) +externC cyg_uint32 cyg_hal_exception_handler(HAL_SavedRegisters *regs) { #ifdef CYGHWR_HAL_MIPS_FPU // We may be required to emulate certain unimplemented Floating Point @@ -84,7 +84,7 @@ externC void exception_handler(HAL_Saved // the exception successfully. If so, we just return if ( cyg_hal_mips_process_fpe(regs) ) - return; + return 0; } #endif @@ -94,7 +94,7 @@ externC void exception_handler(HAL_Saved // and if so jump to the saved address if (__mem_fault_handler) { regs->pc = (CYG_ADDRWORD)__mem_fault_handler; - return; // Caught an exception inside stubs + return 0; // Caught an exception inside stubs } // Set the pointer to the registers of the current exception @@ -117,7 +117,7 @@ externC void exception_handler(HAL_Saved CYG_FAIL("Exception!!!"); #endif - return; + return 0; } /*------------------------------------------------------------------------*/ @@ -137,6 +137,17 @@ externC cyg_uint32 hal_default_isr(CYG_A if( result != 0 ) return result; } +#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON) +#if defined(HAL_DIAG_IRQ_CHECK) + { + cyg_uint32 ret; + /* let ROM monitor handle unexpected interrupts */ + HAL_DIAG_IRQ_CHECK(vector, ret); + if (ret<=0) + return ret; + } +#endif // def HAL_DIAG_IRQ_CHECK +#endif // def CYG_HAL_USE_ROM_MONITOR #endif CYG_TRACE1(true, "Interrupt: %d", vector);
--- a/packages/hal/mips/arch/current/src/vectors.S +++ b/packages/hal/mips/arch/current/src/vectors.S @@ -377,8 +377,8 @@ FUNC_START(__default_exception_vsr) hal_cpu_except_enable # reenable exceptions - .extern exception_handler - j exception_handler # call C code + .extern cyg_hal_exception_handler + j cyg_hal_exception_handler # call C code move a0,s0 # arg0 = register dump (delay slot) # When the exception handler returns, it will @@ -562,7 +562,7 @@ 8: lw sp,mips_stack_frame_size(sp) # sp = *sp subu sp,sp,mips_stack_frame_size # make a null frame -#endif +#endif #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT @@ -579,7 +579,7 @@ 8: # the register dump, the vector offset and the interrupt number # respectively. - move a0,v0 # put ISR result in arg0 + move s2,v0 la a1,hal_interrupt_objects # interrupt object table add a1,a1,s1 # address of object ptr @@ -589,11 +589,13 @@ 8: .extern interrupt_end jal interrupt_end # call into C to finish off - nop # (delay slot) - + move a0,v0 # put ISR result in arg0 + + move v0,s2 # return value from isr #endif -restore_state: +restore_state: + move k0,v0 # All done, restore CPU state and continue @@ -648,7 +650,36 @@ restore_state: lw $30,(mipsreg_regs+30*4)(sp) # == FP lw $31,(mipsreg_regs+31*4)(sp) # == RA .set at - + + +#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON) + + # If we have a Cygmon that wants to listen to network interrupts, then + # the return code from the earlier call to hal_default_isr() will + # have been negative to indicate this. So we jump into Cygmon here + # because Cygmon requires the processor state to be the same as when + # the interrupt was taken, but with k0 as the exception number. + + bgez k0,1f + nop + # Check for new cygmon + sw k0,(mipsreg_regs+26*4)(sp) # save k0 + la k1,0x80000100 + 41*4 # New cygmon "magic" id + lw k1,0(k1) + lui k0,0x55aa + ori k0,0x4321 + bne k0,k1,1f + + # Need to let cygmon handle this + la k1,0x80000100 + 39*4 # stub entry vector + lw k0,(mipsreg_regs+26*4)(sp) # restore k0 + lw k1,0(k1) + lw sp,(mipsreg_regs+29*4)(sp) # restore SP + sll k0,1 # clear bit 31. + jr k1 + srl k0,1 + 1: +#endif lw k0,mipsreg_pc(sp) # K0 = return PC lw k1,mipsreg_sr(sp) # K1 = saved SR lw sp,(mipsreg_regs+29*4)(sp) # load SP
--- a/packages/hal/mips/tx39/current/ChangeLog +++ b/packages/hal/mips/tx39/current/ChangeLog @@ -1,3 +1,31 @@ +1999-09-17 Jonathan Larmour <jlarmour@cygnus.co.uk> + + * src/hal_diag.c: Only avoid SERIAL0 if CYG_HAL_USE_ROM_MONITOR_CYGMON + since we default to assuming Cygmon + + * include/variant.inc (hal_memc_init): Don't make conditional on + ROM startup - makes sense anyway so that users can change amount + of memory in system + (hal_memc_init_dram): Likewise + + * include/var_arch.h (HAL_DIAG_IRQ_CHECK): Give extra return parameter + rather than relying on this being an expression which evaluates + +1999-09-16 Hugo Tyson <hmt@cygnus.co.uk> + + This set of changes with matching ones in arch comes from Mark + Salter's work to make jmr3904 CygMon talk Ethernet. + + * include/variant.inc: Do not re-initialize and disable all + interrupts if RAM start, this stops networked CygMon working. + Likewise don't re-init memory. + + * src/hal_diag.c: Add alternate hal_diag...() routines that talk + via CygMon so that ethernet debugging works. + + * include/var_arch.h: If CYG_HAL_USE_ROM_MONITOR, export macro for + polling unknown interrupts in CygMon, HAL_DIAG_IRQ_CHECK. + 1999-08-25 Nick Garnett <nickg@cygnus.co.uk> * include/variant.inc: Added clock-speed dependent values for the
--- a/packages/hal/mips/tx39/current/include/var_arch.h +++ b/packages/hal/mips/tx39/current/include/var_arch.h @@ -47,6 +47,16 @@ #include <pkgconf/hal.h> #include <cyg/infra/cyg_type.h> +#ifdef CYG_HAL_USE_ROM_MONITOR_CYGMON +externC int +hal_diag_irq_check(int vector); + +#define HAL_DIAG_IRQ_CHECK(_vector_, _ret_) \ +CYG_MACRO_START \ +_ret_ = hal_diag_irq_check((_vector_)); \ +CYG_MACRO_END +#endif + //-------------------------------------------------------------------------- #endif // CYGONCE_HAL_VAR_ARCH_H // End of var_arch.h
--- a/packages/hal/mips/tx39/current/include/variant.inc +++ b/packages/hal/mips/tx39/current/include/variant.inc @@ -157,10 +157,6 @@ .endm -#if defined(CYG_HAL_STARTUP_ROM) - - # Only do this in ROM configurations. - .macro hal_memc_init_dram # DRAM Configuration la v0, 0xffff8000 @@ -183,11 +179,6 @@ sw v1, 0(v0) .endm -#else - .macro hal_memc_init_dram - .endm -#endif - #define CYGPKG_HAL_MIPS_MEMC_DEFINED #endif @@ -201,12 +192,15 @@ # Set all ILRX registers to 0, masking all external interrupts. .macro hal_intc_init + +#ifndef CYG_HAL_STARTUP_RAM la v0,0xFFFFC010 move v1,zero sw v1,0(v0) sw v1,4(v0) sw v1,8(v0) sw v1,12(v0) +#endif .endm .macro hal_intc_decode vnum
--- a/packages/hal/mips/tx39/current/src/hal_diag.c +++ b/packages/hal/mips/tx39/current/src/hal_diag.c @@ -55,10 +55,12 @@ /*---------------------------------------------------------------------------*/ //#define CYG_KERNEL_DIAG_LCD -#define CYG_KERNEL_DIAG_SERIAL0 +#define CYG_KERNEL_DIAG_SERIAL0 // For ROM start but see immediately below: -#if defined(CYG_HAL_USE_ROM_MONITOR) - +#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON) +#undef CYG_KERNEL_DIAG_SERIAL0 +#undef CYG_KERNEL_DIAG_LCD +#define CYG_KERNEL_DIAG_CYGMON #define CYG_KERNEL_DIAG_GDB #endif @@ -85,7 +87,7 @@ void hal_diag_led(int x) /*---------------------------------------------------------------------------*/ -#ifdef CYG_KERNEL_DIAG_SERIAL0 +#if defined(CYG_KERNEL_DIAG_SERIAL0) || defined(CYG_KERNEL_DIAG_CYGMON) #define DIAG_BASE 0xfffff300 #define DIAG_SLCR (DIAG_BASE+0x00) @@ -192,7 +194,11 @@ void hal_diag_read_char_serial0(char *c) } +#if defined(CYG_KERNEL_DIAG_CYGMON) +void hal_diag_dumb_write_char(char c) +#else void hal_diag_write_char(char c) +#endif { #ifdef CYG_KERNEL_DIAG_GDB #if 0 //defined(CYG_HAL_USE_ROM_MONITOR) @@ -250,8 +256,12 @@ void hal_diag_write_char(char c) if( c1 == '+' ) break; - if( cyg_hal_is_break( &c1 , 1 ) ) - cyg_hal_user_break( NULL ); + { + extern void cyg_hal_user_break(CYG_ADDRWORD *regs); + extern cyg_bool cyg_hal_is_break(char *buf, int size); + if( cyg_hal_is_break( &c1 , 1 ) ) + cyg_hal_user_break( NULL ); + } break; } @@ -272,6 +282,7 @@ void hal_diag_write_char(char c) #endif } + void hal_diag_read_char(char *c) { for(;;) @@ -314,8 +325,263 @@ void hal_diag_read_char(char *c) } } +#endif // defined(CYG_KERNEL_DIAG_SERIAL0) || defined(CYG_KERNEL_DIAG_CYGMON) + + +#if defined(CYG_KERNEL_DIAG_CYGMON) // only + +/* This code has been imported from the BSP module. The definitions have + * been left as-is, even though there was scope for doing more, to avoid + * too much drift from the original sources + */ + +struct bsp_comm_procs { + void *ch_data; + void (*__write)(void *ch_data, const char *buf, int len); + int (*__read)(void *ch_data, char *buf, int len); + void (*__putc)(void *ch_data, char ch); + int (*__getc)(void *ch_data); + int (*__control)(void *ch_data, int func, ...); +}; + +// This is pointed to by entry BSP_NOTVEC_BSP_COMM_PROCS: +typedef struct { + int version; /* version number for future expansion */ + void *__ictrl_table; + void *__exc_table; + void *__dbg_vector; + void *__kill_vector; + struct bsp_comm_procs *__console_procs; + struct bsp_comm_procs *__debug_procs; + void *__flush_dcache; + void *__flush_icache; + void *__cpu_data; + void *__board_data; + void *__sysinfo; + int (*__set_debug_comm)(int __comm_id); + int (*__set_console_comm)(int __comm_id); + int (*__set_serial_baud)(int __comm_id, int baud); + void *__dbg_data; + void (*__reset)(void); + int __console_interrupt_flag; +} bsp_shared_t; + +/* + * Core Exception vectors. + */ +#define BSP_EXC_INT 0 +#define BSP_EXC_TLBMOD 1 +#define BSP_EXC_TLBL 2 +#define BSP_EXC_TLBS 3 +#define BSP_EXC_ADEL 4 +#define BSP_EXC_ADES 5 +#define BSP_EXC_IBE 6 +#define BSP_EXC_DBE 7 +#define BSP_EXC_SYSCALL 8 +#define BSP_EXC_BREAK 9 +#define BSP_EXC_ILL 10 +#define BSP_EXC_CPU 11 +#define BSP_EXC_OV 12 +#define BSP_EXC_TRAP 13 +#define BSP_EXC_VCEI 14 +#define BSP_EXC_FPE 15 +#define BSP_EXC_RSV16 16 +#define BSP_EXC_RSV17 17 +#define BSP_EXC_RSV18 18 +#define BSP_EXC_RSV19 19 +#define BSP_EXC_RSV20 20 +#define BSP_EXC_RSV21 21 +#define BSP_EXC_RSV22 22 +#define BSP_EXC_WATCH 23 +#define BSP_EXC_RSV24 24 +#define BSP_EXC_RSV25 25 +#define BSP_EXC_RSV26 26 +#define BSP_EXC_RSV27 27 +#define BSP_EXC_RSV28 28 +#define BSP_EXC_RSV29 29 +#define BSP_EXC_RSV30 30 +#define BSP_EXC_VCED 31 +/* tx39 debug exception */ +#define BSP_EXC_DEBUG 32 +#define BSP_EXC_TLB 33 +#define BSP_EXC_NMI 34 +/* + * Hack for eCos on tx39 to set an async breakpoint. + */ +#define BSP_VEC_BP_HOOK 35 + +#define BSP_EXC_XTLB 36 +#define BSP_EXC_CACHE 37 + +#define BSP_MAX_EXCEPTIONS 38 + +/* + * Another hack for tx39 eCos compatibility. + */ +#if defined(__CPU_R3900__) +#define BSP_VEC_MT_DEBUG 15 +#else +#define BSP_VEC_MT_DEBUG 38 #endif +#define BSP_VEC_STUB_ENTRY 39 +#define BSP_VEC_BSPDATA 40 +#define BSP_VEC_MAGIC 41 +#define BSP_VEC_IRQ_CHECK 42 + +#define BSP_VEC_PAD 43 +#define NUM_VTAB_ENTRIES 44 + + +#define BSP_MAGIC_VAL 0x55aa4321 + +#define SYS_interrupt 1000 + +// These vectors should be called with: +// +// k0 - Exception Number + +#define CYGMON_VECTOR_TABLE_BASE 0x80000100 +#define CYGMON_VECTOR_TABLE ((CYG_ADDRESS *)CYGMON_VECTOR_TABLE_BASE) + +#if 0 // UNUSED +static int +hal_bsp_set_debug_comm(int arg) +{ + bsp_shared_t *shared; + + shared = (bsp_shared_t *) + (CYGMON_VECTOR_TABLE[ BSP_VEC_BSPDATA ]); + + if (0 != shared->__set_debug_comm) { + return (*(shared->__set_debug_comm))(arg); + } + return 0; +} + +static int +hal_bsp_set_console_comm(int arg) +{ + bsp_shared_t *shared; + + shared = (bsp_shared_t *) + (CYGMON_VECTOR_TABLE[ BSP_VEC_BSPDATA ]); + + if (0 != shared->__set_console_comm) { + return (*(shared->__set_console_comm))(arg); + } + return 0; +} +#endif // 0 UNUSED + +static void bsp_trap(int trap_num); + +static int +hal_bsp_console_write(const void *p, int len) +{ + bsp_shared_t *shared; + struct bsp_comm_procs *com; + int magic; + + /*hal_bsp_set_console_comm(0);*/ + + /* If this is not a BSP-based CygMon, return 0 */ + magic = (int)(CYGMON_VECTOR_TABLE[ BSP_VEC_MAGIC ]); + if (magic != BSP_MAGIC_VAL) + return 0; + + shared = (bsp_shared_t *) + (CYGMON_VECTOR_TABLE[ BSP_VEC_BSPDATA ]); + + com = shared->__console_procs; + + if (0 != com) { + shared->__console_interrupt_flag = 0; + com->__write(com->ch_data, p, len); + if (shared->__console_interrupt_flag) { + /* debug interrupt; stop here */ + bsp_trap(SYS_interrupt); + } + + return 1; + } + return 0; +} + +static void +bsp_trap(int trap_num) +{ + asm("syscall\n"); +} + + +static void +hal_dumb_serial_write(const char *p, int len) +{ + int i; + for ( i = 0 ; i < len; i++ ) { + hal_diag_dumb_write_char(p[i]); + } +} + +void hal_diag_write_char(char c) +{ + static char line[100]; + static int pos = 0; + + // No need to send CRs + if( c == '\r' ) return; + + line[pos++] = c; + + if( c == '\n' || pos == sizeof(line) ) { + CYG_INTERRUPT_STATE old; + + // Disable interrupts. This prevents GDB trying to interrupt us + // while we are in the middle of sending a packet. The serial + // receive interrupt will be seen when we re-enable interrupts + // later. + + HAL_DISABLE_INTERRUPTS(old); + + if ( ! hal_bsp_console_write( line, pos ) ) + // then there is no function registered, just spew it out serial + hal_dumb_serial_write( line, pos ); + + pos = 0; + + // And re-enable interrupts + HAL_RESTORE_INTERRUPTS(old); + + } +} + +int +hal_diag_irq_check(int vector) +{ + typedef int irq_check_fn(int irq_nr); + irq_check_fn *fn = (irq_check_fn *)(CYGMON_VECTOR_TABLE[ BSP_VEC_IRQ_CHECK ]); + int magic; + + + /* If this is not a BSP-based CygMon, return 0 */ + magic = (int)(CYGMON_VECTOR_TABLE[ BSP_VEC_MAGIC ]); + if (magic != BSP_MAGIC_VAL) + return 0; + +#if defined(CYGPKG_HAL_MIPS_TX3904) + /* convert vector to BSP irq number */ + if (vector == 16) + vector = 2; + else + vector += 3; +#endif + + return fn(vector); +} + +#endif // defined(CYG_KERNEL_DIAG_CYGMON) *only* + /*---------------------------------------------------------------------------*/ #if defined(CYGPKG_HAL_MIPS_TX39_JMR3904) && defined(CYG_KERNEL_DIAG_LCD)
--- a/packages/hal/powerpc/arch/current/ChangeLog +++ b/packages/hal/powerpc/arch/current/ChangeLog @@ -1,3 +1,14 @@ +1999-09-23 Jonathan Larmour <jlarmour@cygnus.co.uk> + + * src/hal_misc.c (cyg_hal_exception_handler): Catch exceptions + generated from within the GDB stub so we can recover from bad memory + accesses + Also part of the fix for case 102104 + +1999-09-23 Jesper Skov <jskov@cygnus.co.uk> + Case 102104 + * include/hal_cache.h (HAL_ICACHE_SYNC): Invalidate I cache. + 1999-09-06 Jesper Skov <jskov@cygnus.co.uk> * src/hal_misc.c (hal_null_call):
--- a/packages/hal/powerpc/arch/current/include/hal_cache.h +++ b/packages/hal/powerpc/arch/current/include/hal_cache.h @@ -475,7 +475,8 @@ externC cyg_memdesc_t cyg_hal_mem_map[]; "r" (CYGARC_REG_IC_CMD_IA)) // Synchronize the contents of the cache with memory. -#define HAL_ICACHE_SYNC() +#define HAL_ICACHE_SYNC() \ + HAL_ICACHE_INVALIDATE_ALL() // Query the state of the instruction cache #define HAL_ICACHE_IS_ENABLED(_state_) \
--- a/packages/hal/powerpc/arch/current/src/hal_misc.c +++ b/packages/hal/powerpc/arch/current/src/hal_misc.c @@ -103,11 +103,20 @@ externC void __handle_exception (void); externC HAL_SavedRegisters *_hal_registers; +externC void *__mem_fault_handler; + void cyg_hal_exception_handler(HAL_SavedRegisters *regs) { #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS + // If we caught an exception inside the stubs, see if we were expecting it + // and if so jump to the saved address + if (__mem_fault_handler) { + regs->pc = (CYG_ADDRWORD)__mem_fault_handler; + return; // Caught an exception inside stubs + } + // Set the pointer to the registers of the current exception // context. At entry the GDB stub will expand the // HAL_SavedRegisters structure into a (bigger) register array.
--- a/packages/hal/powerpc/arch/current/src/vectors.S +++ b/packages/hal/powerpc/arch/current/src/vectors.S @@ -378,7 +378,7 @@ 2: .extern hal_MMU_init bl hal_MMU_init - # Enable MMU it so we can safely enable caches. + # Enable MMU so we can safely enable caches. lwi r3,CYG_MSR_NO_INTS # interrupts enabled later sync mtmsr r3
--- a/packages/hal/powerpc/mbx/current/ChangeLog +++ b/packages/hal/powerpc/mbx/current/ChangeLog @@ -1,3 +1,19 @@ +1999-09-20 Hugo Tyson <hmt@cygnus.co.uk> + + * include/pkgconf/hal_powerpc_mbx.h: + (CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH) new config option to + control chip select initialization. + + * src/mbx.S: Take notice of CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH. + + * misc/stubrom.perm: Reference the new option for folks who want + to boot from the 32-bit flash. + +1999-09-13 Gary Thomas <gthomas@cygnus.co.uk> + + * include/pkgconf/hal_powerpc_mbx.h (CYGHWR_HAL_POWERPC_BOARD_SPEED): + Missing default value (wouldn't build sans ConfigTool). + 1999-09-09 Gary Thomas <gthomas@cygnus.co.uk> * include/pkgconf/hal_powerpc_mbx.h (CYGHWR_HAL_POWERPC_MBX_BOARD_SPEED):
--- a/packages/hal/powerpc/mbx/current/include/pkgconf/hal_powerpc_mbx.h +++ b/packages/hal/powerpc/mbx/current/include/pkgconf/hal_powerpc_mbx.h @@ -85,11 +85,29 @@ # setting it to 30, for example, would not work. } + cdl_option CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH { + display "Boot ROM is 32-bit Flash device" + parent CYGPKG_HAL_POWERPC_MBX + type boolean + description " + MBX Development Boards have a socketed 8-bit ROM (AM27F040, + AM29F040 or similar) and a permanently soldered 32-bit flash + device. Which is used for booting is link selectable (refer to + the MBX Series documentation from Motorola). Enable this option + when booting from the 32-bit flash so that the correct memory + timing and access method is initialized. This consideration + does apply to RAM start eCos applications as well as ROM start + or stub ROMs." + } + }}CFG_DATA */ #define CYGHWR_HAL_POWERPC_MBX_STARTUP ram -#define CYGHWR_HAL_POWERPC_MBX_BOARD_SPEED 50 +#define CYGHWR_HAL_POWERPC_BOARD_SPEED 50 + +// Normally, the 8-bit socketed ROM is used +#undef CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH // Real-time clock/counter specifics
--- a/packages/hal/powerpc/mbx/current/misc/stubrom.perm +++ b/packages/hal/powerpc/mbx/current/misc/stubrom.perm @@ -8,6 +8,11 @@ # Where <SOURCEDIR> is the path to your source repository. # (If necessary, make sure the system clock speed is set correctly in # pkgconf/hal_powerpc_mbx.h: 40MHz (MPC821) versus 50MHz (MPC860) by default) +# If you do not have permtest, use the config tool or an editor to make +# the changes listed below to the relevant configuration files. +# If you intend to install the image into the 32-bit flash device instead of +# the 8-bit socketed ROM, set the option CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH +# in hal_powerpc_mbx.h # 3. Run: make # 4. Run: make -C hal/common/current/src/stubrom #
--- a/packages/hal/powerpc/mbx/current/src/mbx.S +++ b/packages/hal/powerpc/mbx/current/src/mbx.S @@ -262,9 +262,14 @@ FUNC_START( hal_hardware_init ) #else lwi r5,0xff800930 #endif +#ifdef CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH + // Then the 32-bit FLASH device is on CS0, the "ROM" is on CS7 + stw r3,BR7(r4) + stw r5,OR7(r4) +#else // Boot from 8-bit ROM - the default, on CS0 stw r3,BR0(r4) stw r5,OR0(r4) - +#endif /* ONBOARD DRAM */ lwi r3,0x00000081 # 32-bit, UPMA lwi r5,0xffc00400 @@ -312,9 +317,14 @@ FUNC_START( hal_hardware_init ) #else lwi r5,0xff800930 #endif +#ifdef CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH + // Then the 32-bit FLASH device is on CS0, the "ROM" is on CS7 + stw r3,BR0(r4) + stw r5,OR0(r4) +#else // Boot from 8-bit ROM - so the 32-bit FLASH is on CS7 stw r3,BR7(r4) stw r5,OR7(r4) - +#endif /* * SYSTEM CLOCK CONTROL REGISTER *
--- a/packages/hal/powerpc/sim/current/ChangeLog +++ b/packages/hal/powerpc/sim/current/ChangeLog @@ -1,3 +1,7 @@ +1999-09-23 Jonathan Larmour <jlarmour@cygnus.co.uk> + + * runtime/tree: Delete. Now obsolete. + 1999-06-11 Hugo Tyson <hmt@cygnus.co.uk> * src/PKGconf.mak: Build the new file.
deleted file mode 100644 --- a/packages/hal/powerpc/sim/current/runtime/tree +++ /dev/null @@ -1,5 +0,0 @@ -/#address-cells 1 -/openprom/init/register/pc 0x100 -/iobus@0xf0000000/reg 0xf0000000 0x01000000 -/iobus/pal@0xf0001000/reg 0xf0001000 32 -
--- a/packages/io/serial/current/src/PKGconf.mak +++ b/packages/io/serial/current/src/PKGconf.mak @@ -40,7 +40,7 @@ endif ifdef CYG_HAL_ARM_AEB EXTRAS_COMPILE += arm/aeb_serial.c endif -ifdef CYG_HAL_ARM_CL7211 +ifdef CYG_HAL_ARM_EB7211 EXTRAS_COMPILE += arm/cl7211_serial.c endif ifdef CYG_HAL_MN10300_AM31
--- a/packages/kernel/current/ChangeLog +++ b/packages/kernel/current/ChangeLog @@ -1,3 +1,25 @@ +1999-09-16 Hugo Tyson <hmt@cygnus.co.uk> + + * tests/tm_basic.cxx (run_mutex_tests): Must unlock mutices before + destroying, given the change below. + + * src/common/kapi.cxx (cyg_cond_destroy): Call the correct + destructor. As it happens, it didn't matter because all these + destructors do is assert the queue is empty, and the queue is the + 2nd word in every case. + (cyg_mutex_destroy): Call the destructor at all, so that + assertions are made. + +1999-09-13 Gary Thomas <gthomas@cygnus.co.uk> + + * src/intr/intr.cxx (call_pending_DSRs_inner): Add assert to check + for valid DSR (before trying to use it). + +1999-09-13 Jesper Skov <jskov@cygnus.co.uk> + + * tests/stress_threads.c: Print out malloc system info. + (print_statistics): Fix buglet. + 1999-09-10 Jesper Skov <jskov@cygnus.co.uk> * tests/stress_threads.c: Print out more info. Reduce dump
--- a/packages/kernel/current/src/common/kapi.cxx +++ b/packages/kernel/current/src/common/kapi.cxx @@ -1005,7 +1005,7 @@ externC void cyg_mutex_init( externC void cyg_mutex_destroy( cyg_mutex_t *mutex ) { - // no need to do anything here + ((Cyg_Mutex *)mutex)->~Cyg_Mutex(); } externC cyg_bool_t cyg_mutex_lock( cyg_mutex_t *mutex ) @@ -1045,7 +1045,7 @@ externC void cyg_cond_init( externC void cyg_cond_destroy( cyg_cond_t *cond ) { - ((Cyg_Counting_Semaphore *)cond)->~Cyg_Counting_Semaphore(); + ((Cyg_Condition_Variable *)cond)->~Cyg_Condition_Variable(); } externC void cyg_cond_wait( cyg_cond_t *cond )
--- a/packages/kernel/current/src/intr/intr.cxx +++ b/packages/kernel/current/src/intr/intr.cxx @@ -147,6 +147,8 @@ Cyg_Interrupt::call_pending_DSRs_inner(v CYG_INSTRUMENT_INTR(CALL_DSR, intr->vector, 0); + CYG_ASSERT( intr->dsr != NULL , "No DSR defined"); + intr->dsr( intr->vector, 1, (CYG_ADDRWORD)intr->data ); } @@ -168,6 +170,8 @@ Cyg_Interrupt::call_pending_DSRs_inner(v intr->dsr_count = 0; HAL_RESTORE_INTERRUPTS(old_intr); + + CYG_ASSERT( intr->dsr != NULL , "No DSR defined"); intr->dsr( intr->vector, count, (CYG_ADDRWORD)intr->data );
--- a/packages/kernel/current/tests/stress_threads.c +++ b/packages/kernel/current/tests/stress_threads.c @@ -165,16 +165,23 @@ volatile int free_handler_pri = 0; volatile int free_handler_id = -1; /* a global variable with which the client and server coordinate */ -int client_makes_request = 0; +volatile int client_makes_request = 0; + +/* if this is true, clients will not make requests */ +volatile int clients_paused = 0; + /* indicates that it's time to print out a report */ -int time_to_report = 0; +volatile int time_to_report = 0; /* print status after a delay of this many secs. */ int time_report_delay; /*** now application-specific variables ***/ /* an array that stores whether the handler threads are in use */ -int handler_thread_in_use[MAX_HANDLERS]; +volatile int handler_thread_in_use[MAX_HANDLERS]; +/* total count of active handlers */ +volatile int handler_thread_in_use_count; + /***** statistics-gathering variables *****/ struct s_statistics { @@ -204,7 +211,8 @@ void sc_thread_create( cyg_thread *thread /* put thread here */ ); -int get_handler_slot(cyg_handle_t current_threadH); +void start_handler(void); +void stop_handler(int handler_id, int handler_pri); void perform_stressful_tasks(void); void permute_array(char a[], int size, int seed); void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp, @@ -251,6 +259,7 @@ main(void) for (i = 0; i < MAX_HANDLERS; ++i) { handler_thread_in_use[i] = 0; } + handler_thread_in_use_count = 0; for (i = 0; i < N_LISTENERS; ++i) { int prio = P_BASE_LISTENER + i; char* name = &thread_name[prio][0]; @@ -327,34 +336,34 @@ void main_program(cyg_addrword_t data) } cyg_mutex_unlock(&free_handler_lock); if (-1 != handler_id) { - // Free the handler resources. This is done outside of the - // free_handler_lock to avoid deadlocks. - cyg_mutex_lock(&handler_slot_lock); { - CYG_ASSERT(1 == priority_in_use[handler_pri], - "Priority not in use!"); - CYG_ASSERT(1 == handler_thread_in_use[handler_id], - "Handler not in use!"); - handler_thread_in_use[handler_id]--; - priority_in_use[handler_pri]--; - - // Finally delete the handler thread. This must be done in a - // loop, waiting for the call to return true. If it returns - // false, go to sleep for a bit, so the killed thread gets a - // chance to run and complete its business. - while (!cyg_thread_delete(handlerH[handler_id])) { - cyg_thread_delay(2); - } - } cyg_mutex_unlock(&handler_slot_lock); + stop_handler(handler_id, handler_pri); } - // Print status if time. + // If it's time to report status or quit, set pause flag and + // keep looping until all handlers have stopped. if (time_to_report) { - time_to_report = 0; - print_statistics(0); + // Pause clients + cyg_mutex_lock(&client_request_lock); { + clients_paused = 1; + } cyg_mutex_unlock(&client_request_lock); + + // When all handlers have stopped, we can print statistics + // knowing that all (handler allocated) resources should have + // been freed. That is, we should be able to determine leaks. + if (0 == handler_thread_in_use_count) { + print_statistics(0); + + // We've done the printing now. Resume the system. + time_to_report = 0; + cyg_mutex_lock(&client_request_lock); { + clients_paused = 0; + } cyg_mutex_unlock(&client_request_lock); + } } #ifdef DEATH_TIME_LIMIT - // Stop test if time. + // Stop test if time. We don't care about resource state here + // since we've only run for a limited time anyway. if (is_dead) { print_statistics(1); CYG_TEST_PASS_FINISH("Kernel thread stress test OK"); @@ -378,7 +387,8 @@ void client_program(cyg_addrword_t data) /* now send a request to the server */ cyg_mutex_lock(&client_request_lock); { - ++client_makes_request; + if (0 == clients_paused) + client_makes_request++; } cyg_mutex_unlock(&client_request_lock); cyg_thread_delay(10+delay); @@ -389,9 +399,6 @@ void client_program(cyg_addrword_t data) take care of the request */ void listener_program(cyg_addrword_t data) { -/* int message = (int) data; */ - int handler_slot; - for (;;) { int make_request = 0; cyg_mutex_lock(&client_request_lock); { @@ -401,27 +408,9 @@ void listener_program(cyg_addrword_t dat } } cyg_mutex_unlock(&client_request_lock); - if (make_request) { - int prio; - char* name; - - handler_slot = get_handler_slot(listenerH[(int) data]); - prio = P_BASE_HANDLER+handler_slot; - - name = &thread_name[prio][0]; - sprintf(name, "handler-%02d/%02d", handler_slot, prio); - - CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!"); - priority_in_use[prio]++; - sc_thread_create(prio, handler_program, - (cyg_addrword_t) handler_slot, - name, (void *) handler_stack[handler_slot], - STACK_SIZE_HANDLER, &handlerH[handler_slot], - &handler_thread_s[handler_slot]); - cyg_thread_resume(handlerH[handler_slot]); - ++statistics.handler_invocation_histogram[handler_slot]; - } - + if (make_request) + start_handler(); + cyg_thread_delay(2 + (rand() % 10)); } } @@ -434,7 +423,6 @@ void handler_program(cyg_addrword_t data cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000))))); - ++statistics.thread_exits; { // Loop until the handler id and priority can be communicated to // the main_program. @@ -456,18 +444,21 @@ void handler_program(cyg_addrword_t data cyg_thread_exit(); } -/* look for an available handler thread */ -int get_handler_slot(cyg_handle_t current_threadH) +/* start a new handler */ +void start_handler(void) { - int i; + int prio; + char* name; + int handler_slot; int found = 0; while (!found) { cyg_mutex_lock(&handler_slot_lock); { - for (i = 0; i < MAX_HANDLERS; ++i) { - if (!handler_thread_in_use[i]) { + for (handler_slot = 0; handler_slot < MAX_HANDLERS;++handler_slot){ + if (!handler_thread_in_use[handler_slot]) { found = 1; - handler_thread_in_use[i]++; + handler_thread_in_use[handler_slot]++; + handler_thread_in_use_count++; break; } } @@ -476,27 +467,66 @@ int get_handler_slot(cyg_handle_t curren cyg_thread_delay(1); } - CYG_ASSERT(1 == handler_thread_in_use[i], "Handler usage count wrong!"); + CYG_ASSERT(1 == handler_thread_in_use[handler_slot], + "Handler usage count wrong!"); + + prio = P_BASE_HANDLER+handler_slot; + CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!"); + priority_in_use[prio]++; + + name = &thread_name[prio][0]; + sprintf(name, "handler-%02d/%02d", handler_slot, prio); + + sc_thread_create(prio, handler_program, + (cyg_addrword_t) handler_slot, + name, (void *) handler_stack[handler_slot], + STACK_SIZE_HANDLER, &handlerH[handler_slot], + &handler_thread_s[handler_slot]); + cyg_thread_resume(handlerH[handler_slot]); + ++statistics.handler_invocation_histogram[handler_slot]; +} - return i; +/* free a locked handler thread */ +void stop_handler(int handler_id, int handler_pri) +{ + // Finally delete the handler thread. This must be done in a + // loop, waiting for the call to return true. If it returns + // false, go to sleep for a bit, so the killed thread gets a + // chance to run and complete its business. + while (!cyg_thread_delete(handlerH[handler_id])) { + cyg_thread_delay(1); + } + ++statistics.thread_exits; + + // Free the handler resources. + cyg_mutex_lock(&handler_slot_lock); { + handler_thread_in_use[handler_id]--; + handler_thread_in_use_count--; + priority_in_use[handler_pri]--; + CYG_ASSERT(0 == priority_in_use[handler_pri], + "Priority not in use!"); + CYG_ASSERT(0 == handler_thread_in_use[handler_id], + "Handler not in use!"); + CYG_ASSERT(0 <= handler_thread_in_use_count, + "Stopped more handlers than was started!"); + } cyg_mutex_unlock(&handler_slot_lock); + } + /* do things which will stress the system */ void perform_stressful_tasks() { #define MAX_MALLOCED_SPACES 100 /* do this many mallocs at most */ #define MALLOCED_BASE_SIZE 1 /* basic size in bytes */ char *spaces[MAX_MALLOCED_SPACES]; - unsigned int i; - - cyg_mutex_t tmp_lock; + int sizes[MAX_MALLOCED_SPACES]; + unsigned int i, j, size; cyg_uint8 pool_space[10][100]; cyg_handle_t mempool_handles[10]; cyg_mempool_fix mempool_objects[10]; - cyg_mutex_init(&tmp_lock); - /* here I use malloc, which uses the kernel's variable memory pools. note that malloc/free is a bit simple-minded here: it does not try to really fragment things, and it does not try to make the @@ -504,8 +534,17 @@ void perform_stressful_tasks() (although I'm about to throw in a yield()) */ for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { ++statistics.malloc_tries; -/* spaces[i] = (char *) malloc(((int)(sqrt(i*2.0))+1)*MALLOCED_BASE_SIZE); */ - spaces[i] = (char *) malloc(((int)i*2.0+1)*MALLOCED_BASE_SIZE); + size = (i*2+1)*MALLOCED_BASE_SIZE; + spaces[i] = (char *) malloc(size); + sizes[i] = size; + + if (spaces[i] != NULL) { + // Fill with a known value (differs between chunk). + for (j = 0; j < size; ++j) { + spaces[i][j] = 0x50 | ((j+i) & 0x0f); + } + } + if (i % (MAX_MALLOCED_SPACES/10) == 0) { cyg_thread_yield(); } @@ -514,11 +553,17 @@ void perform_stressful_tasks() } } + cyg_thread_delay(5); + /* now free it all up */ for (i = 0; i < MAX_MALLOCED_SPACES; ++i) { if (spaces[i] != NULL) { - unsigned int j; - for (j = 0; j < (i*2+1)*MALLOCED_BASE_SIZE; ++j) { + size = sizes[i]; + for (j = 0; j < size; ++j) { + // Validate chunk data. + if ((0x50 | ((j+i) & 0x0f)) != spaces[i][j]) { + printf("Bad byte in chunk\n"); + } spaces[i][j] = 0xAA; /* write a bit pattern */ } free(spaces[i]); @@ -526,6 +571,7 @@ void perform_stressful_tasks() ++statistics.malloc_failures; } } + /* now allocate and then free some fixed-size memory pools; for now this is simple-minded because it does not have many threads sharing the memory pools and racing for memory. */ @@ -543,8 +589,6 @@ void perform_stressful_tasks() cyg_mempool_fix_delete(mempool_handles[i]); } } - - cyg_mutex_destroy(&tmp_lock); } /* report_alarm_func() is invoked as an alarm handler, so it should be @@ -622,7 +666,7 @@ void sc_thread_create( #define MINS_HOUR (60) #define MINS_DAY (60*24) -externC void *cyg_libc_get_pool( void ); +externC void *cyg_libc_get_malloc_pool( void ); void print_statistics(int print_full) { @@ -660,7 +704,8 @@ void print_statistics(int print_full) } printf("\nState dump %d (%d hours, %d minutes) [numbers >>%d]\n", - ++print_count, minutes / MINS_HOUR, minutes, shift_count); + ++print_count, minutes / MINS_HOUR, minutes % MINS_HOUR, + shift_count); cyg_mutex_lock(&statistics_print_lock); { //-------------------------------- @@ -683,24 +728,18 @@ void print_statistics(int print_full) statistics.malloc_tries >>= 1; statistics.malloc_failures >>= 1; } + } cyg_mutex_unlock(&statistics_print_lock); - //-------------------------------- - // System information -#if 0 - // We want to (occasionally) pause the test so all memory is - // freed. Otherwise it's hard to tell if there's a malloc - // leak. - { - cyg_mempool_info mem_info; + //-------------------------------- + // System information + { + cyg_mempool_info mem_info; - cyg_mempool_var_get_info((cyg_handle_t) cyg_libc_get_pool(), - &mem_info); - printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", - mem_info.totalmem, mem_info.freemem, mem_info.maxfree); - } -#endif - - } cyg_mutex_unlock(&statistics_print_lock); + cyg_mempool_var_get_info((cyg_handle_t) cyg_libc_get_malloc_pool(), + &mem_info); + printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", + mem_info.totalmem, mem_info.freemem, mem_info.maxfree); + } // Dump stack status printf(" Stack usage:\n");
--- a/packages/kernel/current/tests/tm_basic.cxx +++ b/packages/kernel/current/tests/tm_basic.cxx @@ -744,6 +744,11 @@ run_mutex_tests(void) } show_times(mutex_ft, nmutexes, "Trylock [locked] mutex"); + // Must unlock mutices before destroying them. + for (i = 0; i < nmutexes; i++) { + cyg_mutex_unlock(&test_mutexes[i]); + } + wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmutexes; i++) { HAL_CLOCK_READ(&mutex_ft[i].start);
--- a/packages/language/c/libc/current/ChangeLog +++ b/packages/language/c/libc/current/ChangeLog @@ -1,3 +1,8 @@ +1999-09-15 Jesper Skov <jskov@cygnus.co.uk> + + * tests/signal/signal2.c (cause_fpe): Try both float and integer + division by zero. + 1999-09-10 Jesper Skov <jskov@cygnus.co.uk> * src/stdlib/malloc.cxx (cyg_libc_get_malloc_pool): Added for
--- a/packages/language/c/libc/current/tests/signal/signal2.c +++ b/packages/language/c/libc/current/tests/signal/signal2.c @@ -108,10 +108,19 @@ cause_memerror(void) // num must always be 0 - do it this way in case the optimizer tries to // get smart -static double +static int cause_fpe(int num) { - return 1.0/num; + double a; + + a = 1.0/num; // Depending on FPU emulation and/or + // the FPU architecture, this may + // cause an exception. + // (float division by zero) + + return ((int)a)/num; // This may cause an exception if + // the architecture supports it. + // (integer division by zero). } // cause_fpe() #endif
