FreeCalypso > hg > freecalypso-sw
changeset 138:85994b210f6a
nuc-fw cleanup: old Nucleus demo (w/o TI fw framework) moved out of the way
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Mon, 11 Nov 2013 10:17:08 +0000 |
parents | 5fe5559003b7 |
children | 771d9fda7630 |
files | nuc-fw/Makefile nuc-fw/cfgmagic/processconf.sh nuc-fw/nucdemo/Makefile nuc-fw/nucdemo/demo.c nuc-fw/nucleus/Makefile nuc-fw/nucleus/calirq.h nuc-fw/nucleus/caltimer.h nuc-fw/nucleus/debug-chases/README nuc-fw/nucleus/debug-chases/tct.S.dbg nuc-fw/nucleus/debug-chases/tms.c.dbg nuc-fw/nucleus/debug-chases/tmse.c.dbg nuc-fw/nucleus/demo/calirq.h nuc-fw/nucleus/demo/caltimer.h nuc-fw/nucleus/demo/demo.c nuc-fw/nucleus/demo/irqshell.S nuc-fw/nucleus/demo/nucdemo.Makefile nuc-fw/nucleus/demo/sdc.c nuc-fw/nucleus/demo/tmcal.c nuc-fw/nucleus/irqshell.S nuc-fw/nucleus/sdc.c nuc-fw/nucleus/tmcal.c |
diffstat | 21 files changed, 6410 insertions(+), 2342 deletions(-) [+] |
line wrap: on
line diff
--- a/nuc-fw/Makefile Mon Nov 11 09:56:23 2013 +0000 +++ b/nuc-fw/Makefile Mon Nov 11 10:17:08 2013 +0000 @@ -1,4 +1,4 @@ -SUBDIR= bsp finlink include nucdemo nucleus riviera serial sprintf sysglue +SUBDIR= bsp finlink include nucleus riviera serial sprintf sysglue default: config.stamp ${MAKE} ${MFLAGS} -f Makefile.build $@
--- a/nuc-fw/cfgmagic/processconf.sh Mon Nov 11 09:56:23 2013 +0000 +++ b/nuc-fw/cfgmagic/processconf.sh Mon Nov 11 10:17:08 2013 +0000 @@ -46,9 +46,9 @@ # Once we get some actual functionality, the following definitions # will likely depend on the target and feature configuration, -# but for now all we have is a FreeNucleus RTOS demo. +# but for now all we have is a Riviera skeleton. -BUILD_COMPONENTS="bsp nucdemo nucleus riviera serial sprintf sysglue" +BUILD_COMPONENTS="bsp nucleus riviera serial sprintf sysglue" export_to_mk BUILD_COMPONENTS BUILD_DEFAULT_IMAGE=ramImage
--- a/nuc-fw/nucdemo/Makefile Mon Nov 11 09:56:23 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -CC= arm-elf-gcc -CFLAGS= -O2 -fno-builtin -mthumb-interwork -mthumb -CPPFLAGS=-I../nucleus - -OBJS= demo.o - -all: ${OBJS} - -clean: - rm -f *.[oa] *errs
--- a/nuc-fw/nucdemo/demo.c Mon Nov 11 09:56:23 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,530 +0,0 @@ -/* Include Nucleus C-Library file */ -//#include "ncl\inc\nu_ncl.h" - -/* Include necessary Nucleus PLUS files. */ -#include "nucleus.h" - -/* Define serial output/input functionality. To disable serial I/O, - replace NU_TRUE with NU_FALSE */ - -#define NU_SERIAL_OUTPUT NU_TRUE -#define NU_SERIAL_INPUT NU_TRUE - -#if (NU_SERIAL_OUTPUT) -#include "nu_sd.h" /* Nucleus Serial Driver interface */ -#endif - -/* Define Application data structures. */ - -NU_TASK Task_0; -NU_TASK Task_1; -NU_TASK Task_2; -NU_TASK Task_3; -NU_TASK Task_4; -NU_TASK Task_5; -NU_QUEUE Queue_0; -NU_SEMAPHORE Semaphore_0; -NU_EVENT_GROUP Event_Group_0; -NU_MEMORY_POOL System_Memory; - - -/* Allocate global counters. */ -UNSIGNED Task_Time; -UNSIGNED Task_2_messages_received; -UNSIGNED Task_2_invalid_messages; -UNSIGNED Task_1_messages_sent; -NU_TASK *Who_has_the_resource; -UNSIGNED Event_Detections; - -#if (NU_SERIAL_OUTPUT) -NU_SERIAL_PORT port; -#endif - -#ifdef NU_FIQ_DEMO -UINT32 FIQ_Count; -#endif - -extern UNSIGNED TMD_System_Clock; - -/* Define prototypes for function references. */ -VOID task_0(UNSIGNED argc, VOID *argv); -VOID task_1(UNSIGNED argc, VOID *argv); -VOID task_2(UNSIGNED argc, VOID *argv); -VOID task_3_and_4(UNSIGNED argc, VOID *argv); -VOID task_5(UNSIGNED argc, VOID *argv); -CHAR buffer[12]; /* temp buffer for Itoa conversion */ -INT n; /* strlen */ - - - -/* Define the Application_Initialize routine that determines the initial - Nucleus PLUS application environment. */ - -void Application_Initialize(void *first_available_memory) -{ - -VOID *pointer; -STATUS status; - - /* Create a system memory pool that will be used to allocate task stacks, - queue areas, etc. */ - status = NU_Create_Memory_Pool(&System_Memory, "SYSMEM", - first_available_memory, 25000, 50, NU_FIFO); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create each task in the system. */ - - /* Create task 0. */ - NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); - status = NU_Create_Task(&Task_0, "TASK 0", task_0, 0, NU_NULL, pointer, 2000, 1, 20, - NU_PREEMPT, NU_START); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create task 1. */ - NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); - status = NU_Create_Task(&Task_1, "TASK 1", task_1, 0, NU_NULL, pointer, 2000, 10, 5, - NU_PREEMPT, NU_START); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create task 2. */ - NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); - status = NU_Create_Task(&Task_2, "TASK 2", task_2, 0, NU_NULL, pointer, 2000, 10, 5, - NU_PREEMPT, NU_START); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create task 3. Note that task 4 uses the same instruction area. */ - NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); - status = NU_Create_Task(&Task_3, "TASK 3", task_3_and_4, 0, NU_NULL, pointer, - 2000, 5, 0, NU_PREEMPT, NU_START); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create task 4. Note that task 3 uses the same instruction area. */ - NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); - status = NU_Create_Task(&Task_4, "TASK 4", task_3_and_4, 0, NU_NULL, pointer, - 2000, 5, 0, NU_PREEMPT, NU_START); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create task 5. */ - NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); - status = NU_Create_Task(&Task_5, "TASK 5", task_5, 0, NU_NULL, pointer, 2000, 7, 0, - NU_PREEMPT, NU_START); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - - /* Create communication queue. */ - NU_Allocate_Memory(&System_Memory, &pointer, 100*sizeof(UNSIGNED), - NU_NO_SUSPEND); - status = NU_Create_Queue(&Queue_0, "QUEUE 0", pointer, 100, NU_FIXED_SIZE, 1, - NU_FIFO); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create synchronization semaphore. */ - status = NU_Create_Semaphore(&Semaphore_0, "SEM 0", 1, NU_FIFO); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - /* Create event flag group. */ - status = NU_Create_Event_Group(&Event_Group_0, "EVGROUP0"); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - - -} - -/* Define the system timer task. More complicated systems might use a - routine like this to perform periodic message sending and other time - oriented functions. */ - - -void task_0(UNSIGNED argc, VOID *argv) -{ - -STATUS status; - - -#if (NU_SERIAL_OUTPUT) -CHAR msg[40]; -INT i; - -CHAR ch; -#endif /* NU_SERIAL_OUTPUT */ - - -#if (NU_SERIAL_OUTPUT) - /* Init the serial port. */ - port.com_port = DEFAULT_UART_PORT; - port.baud_rate = DEFAULT_UART_BAUD; - port.data_bits = DEFAULT_UART_DATA; - port.stop_bits = DEFAULT_UART_STOP; - port.parity = DEFAULT_UART_PARITY; - port.data_mode = DEFAULT_UART_MODE; - port.communication_mode = SERIAL_MODE; - port.sd_buffer_size = DEFAULT_UART_BUFFER; - - status = NU_SD_Init_Port (&port); - if (status != NU_SUCCESS) - { - ERC_System_Error(status); - } - -#endif /* NU_SERIAL_OUTPUT */ - - - /* Access argc and argv just to avoid compilation warnings. */ - status = (STATUS) argc + (STATUS) argv; - - /* Set the clock to 0. This clock ticks every 18 system timer ticks. */ - Task_Time = 0; - - while(1) - { - - /* Sleep for 100 timer ticks. The value of the tick is programmable - in INT.S and is relative to the speed of the target system. */ - NU_Sleep(100); - -#if (NU_SERIAL_OUTPUT) - NU_SD_Put_String("\n\r****************************************", &port); - NU_SD_Put_String("***************************************\n\r", &port); - NU_SD_Put_String(NU_Release_Information(), &port); - NU_SD_Put_String("\n\r", &port); - - NU_SD_Put_String("****************************************", &port); - NU_SD_Put_String("***************************************\n\n\r", &port); - NU_SD_Put_String("System Variable Status: \n\n\r", &port); - - strcpy(msg, "Task 0 time: "); - sprintf(buffer, "%lu", Task_Time); - n = strlen(buffer); - if (n>=8) - { - strcat(msg, buffer); - strcat(msg, "\n\r"); - } - else - { - for (i=0;i<(8-n);i++) - strcat(msg, " "); - strcat(msg, buffer); - strcat(msg, "\n\r"); - } - - NU_SD_Put_String(msg, &port); - - strcpy(msg, "Event detections: "); - sprintf(buffer, "%lu", Event_Detections); - n = strlen(buffer); - if (n>=8) - { - strcat(msg, buffer); - strcat(msg, "\n\n\n\r"); - } - else - { - for (i=0;i<(8-n);i++) - strcat(msg, " "); - strcat(msg, buffer); - strcat(msg, "\n\n\n\r"); - } - - NU_SD_Put_String(msg, &port); - - strcpy(msg, "Task 1 messages sent: "); - sprintf(buffer, "%lu", Task_1_messages_sent); - n = strlen(buffer); - if (n>=8) - { - strcat(msg, buffer); - strcat(msg, "\n\r"); - } - else - { - for (i=0;i<(8-n);i++) - strcat(msg, " "); - strcat(msg, buffer); - strcat(msg, "\n\r"); - } - - NU_SD_Put_String(msg, &port); - - strcpy(msg, "Task 2 messages received: "); - sprintf(buffer, "%lu", Task_2_messages_received); - n = strlen(buffer); - if (n>=8) - { - strcat(msg, buffer); - strcat(msg, "\n\n\r"); - } - else - { - for (i=0;i<(8-n);i++) - strcat(msg, " "); - strcat(msg, buffer); - strcat(msg, "\n\n\r"); - } - - NU_SD_Put_String(msg, &port); - - strcpy(msg, "Task 2 invalid messages: "); - sprintf(buffer, "%lu", Task_2_invalid_messages); - n = strlen(buffer); - if (n>=8) - { - strcat(msg, buffer); - strcat(msg, "\n\n\r"); - } - else - { - for (i=0;i<(8-n);i++) - strcat(msg, " "); - strcat(msg, buffer); - strcat(msg, "\n\n\r"); - } - - NU_SD_Put_String(msg, &port); - - if (Who_has_the_resource == &Task_3) - NU_SD_Put_String("Who has the resource: Task 3", &port); - else if (Who_has_the_resource == &Task_4) - NU_SD_Put_String("Who has the resource: Task 4", &port); - else - NU_SD_Put_String("Who has the resource: Nobody", &port); - NU_SD_Put_String("\n\n\n\r", &port); - - strcpy(msg, "Timer Interrupts: "); - sprintf(buffer, "%lu", TMD_System_Clock); - n = strlen(buffer); - if (n>=8) - { - strcat(msg, buffer); - strcat(msg, "\n\n\r"); - } - else - { - for (i=0;i<(8-n);i++) - strcat(msg, " "); - strcat(msg, buffer); - strcat(msg, "\n\n\r"); - } - - NU_SD_Put_String(msg, &port); - - NU_SD_Put_String("Buffer: ", &port); - -#if (NU_SERIAL_INPUT) - while (NU_SD_Data_Ready(&port)) - { - ch = NU_SD_Get_Char(&port); - NU_SD_Put_Char(ch, &port); - } -#endif /* NU_SERIAL_INPUT */ - - - NU_SD_Put_String("\n\n\r", &port); - - -#endif /* NU_SERIAL_OUTPUT */ - /* Increment the time. */ - Task_Time++; - - /* Set an event flag to lift the suspension on task 5. */ - status = NU_Set_Events(&Event_Group_0, 1, NU_OR); - - } - -} - - -/* Define the queue sending task. Note that the only things that cause - this task to suspend are queue full conditions and the time slice - specified in the configuration file. */ - -void task_1(UNSIGNED argc, VOID *argv) -{ - -STATUS status; -UNSIGNED Send_Message; - - /* Access argc and argv just to avoid compilation warnings. */ - status = (STATUS) argc + (STATUS) argv; - - /* Initialize the message counter. */ - Task_1_messages_sent = 0; - - /* Initialize the message contents. The receiver will examine the - message contents for errors. */ - Send_Message = 0; - - while(1) - { - - /* Send the message to Queue_0, which task 2 reads from. Note - that if the destination queue fills up this task suspends until - room becomes available. */ - status = NU_Send_To_Queue(&Queue_0, &Send_Message, 1, NU_SUSPEND); - - /* Determine if the message was sent successfully. */ - if (status == NU_SUCCESS) - Task_1_messages_sent++; - - /* Modify the contents of the next message to send. */ - Send_Message++; - } -} - - -/* Define the queue receiving task. Note that the only things that cause - this task to suspend are queue empty conditions and the time slice - specified in the configuration file. */ - -void task_2(UNSIGNED argc, VOID *argv) -{ - -STATUS status; -UNSIGNED Receive_Message; -UNSIGNED received_size; -UNSIGNED message_expected; - - /* Access argc and argv just to avoid compilation warnings. */ - status = (STATUS) argc + (STATUS) argv; - - /* Initialize the message counter. */ - Task_2_messages_received = 0; - - /* Initialize the message error counter. */ - Task_2_invalid_messages = 0; - - /* Initialize the message contents to expect. */ - message_expected = 0; - - while(1) - { - - /* Retrieve a message from Queue_0, which task 1 writes to. Note - that if the source queue is empty this task suspends until - something becomes available. */ - status = NU_Receive_From_Queue(&Queue_0, &Receive_Message, 1, - &received_size, NU_SUSPEND); - - /* Determine if the message was received successfully. */ - if (status == NU_SUCCESS) - Task_2_messages_received++; - - /* Check the contents of the message against what this task - is expecting. */ - if ((received_size != 1) || - (Receive_Message != message_expected)) - Task_2_invalid_messages++; - - /* Modify the expected contents of the next message. */ - message_expected++; - } -} - - -/* Tasks 3 and 4 want a single resource. Once one of the tasks gets the - resource, it keeps it for 100 clock ticks before releasing it. During - this time the other task suspends waiting for the resource. Note that - both task 3 and 4 use the same instruction areas but have different - stacks. */ - -void task_3_and_4(UNSIGNED argc, VOID *argv) -{ - -STATUS status; - - /* Access argc and argv just to avoid compilation warnings. */ - status = (STATUS) argc + (STATUS) argv; - - /* Loop to allocate and deallocate the resource. */ - while(1) - { - - /* Allocate the resource. Suspend until it becomes available. */ - status = NU_Obtain_Semaphore(&Semaphore_0, NU_SUSPEND); - - /* If the status is successful, show that this task owns the - resource. */ - if (status == NU_SUCCESS) - { - - Who_has_the_resource = NU_Current_Task_Pointer(); - - /* Sleep for 100 ticks to cause the other task to suspend on - the resource. */ - NU_Sleep(100); - - /* Release the semaphore. */ - NU_Release_Semaphore(&Semaphore_0); - } - } -} - - -/* Define the task that waits for the event to be set by task 0. */ - -void task_5(UNSIGNED argc, VOID *argv) -{ - -STATUS status; -UNSIGNED event_group; - - /* Access argc and argv just to avoid compilation warnings. */ - status = (STATUS) argc + (STATUS) argv; - - /* Initialize the event detection counter. */ - Event_Detections = 0; - - /* Continue this process forever. */ - while(1) - { - /* Wait for an event and consume it. */ - status = NU_Retrieve_Events(&Event_Group_0, 1, NU_OR_CONSUME, - &event_group, NU_SUSPEND); - - /* If the status is okay, increment the counter. */ - if (status == NU_SUCCESS) - { - Event_Detections++; - - } - } -} - - -#ifdef NU_FIQ_DEMO -void FIQ_LISR(VOID) -{ - FIQ_Count++; -} -#endif - -
--- a/nuc-fw/nucleus/Makefile Mon Nov 11 09:56:23 2013 +0000 +++ b/nuc-fw/nucleus/Makefile Mon Nov 11 10:17:08 2013 +0000 @@ -5,7 +5,7 @@ RANLIB= arm-elf-ranlib IOBJS= csc.o erc.o pmc.o pmce.o pmd.o smc.o smce.o smd.o tcc.o tcce.o tcd.o \ - tct.o tmc.o tmd.o tms.o tmse.o tmt.o #irqshell.o + tct.o tmc.o tmd.o tms.o tmse.o tmt.o XTOBJS= dmc.o dmce.o dmd.o dmf.o dmi.o dms.o erd.o eri.o evc.o evce.o evd.o \ evf.o evi.o hic.o hid.o hii.o inc.o ioc.o ioce.o iod.o iof.o ioi.o \ @@ -13,7 +13,6 @@ pid.o pif.o pii.o pis.o pise.o pmf.o pmi.o quc.o quce.o qud.o quf.o \ qui.o qus.o quse.o rlc.o rld.o smf.o smi.o sms.o smse.o tcf.o tcfe.o \ tci.o tcs.o tcse.o tmf.o tmi.o -# sdc.o tmcal.o XOBJS= ${XTOBJS} init.o AOBJS= ${IOBJS} init.o @@ -21,9 +20,8 @@ HDRS= asm_defs.h cs_defs.h cs_extr.h dm_defs.h dm_extr.h er_defs.h er_extr.h \ ev_defs.h ev_extr.h hi_defs.h hi_extr.h in_defs.h in_extr.h io_defs.h \ io_extr.h mb_defs.h mb_extr.h nu_sd.h nucleus.h pi_defs.h pi_extr.h \ - pm_defs.h pm_extr.h profiler.h qu_defs.h qu_extr.h sd_defs.h sd_extr.h \ - sm_defs.h sm_extr.h tc_defs.h tc_extr.h tm_defs.h tm_extr.h \ - calirq.h caltimer.h + pm_defs.h pm_extr.h profiler.h qu_defs.h qu_extr.h sm_defs.h sm_extr.h \ + tc_defs.h tc_extr.h tm_defs.h tm_extr.h all: libplus.iram.a libplus.xip.a
--- a/nuc-fw/nucleus/calirq.h Mon Nov 11 09:56:23 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Definitions for Calypso IRQ numbers and the related registers - * Added to the FreeNucleus Calypso port by Spacefalcon the Outlaw. - * - * This header is usable from both .c and .S source files. - */ - -#ifndef _CALYPSO_IRQ_H -#define _CALYPSO_IRQ_H - -#define IRQ_WATCHDOG 0 -#define IRQ_TIMER1 1 -#define IRQ_TIMER2 2 -#define IRQ_TSP_RX 3 -#define IRQ_TPU_FRAME 4 -#define IRQ_TPU_PAGE 5 -#define IRQ_SIMCARD 6 -#define IRQ_UART_MODEM 7 -#define IRQ_KEYPAD_GPIO 8 -#define IRQ_RTC_TIMER 9 -#define IRQ_RTC_ALARM_I2C 10 -#define IRQ_ULPD_GAUGING 11 -#define IRQ_EXTERNAL 12 -#define IRQ_SPI 13 -#define IRQ_DMA 14 -#define IRQ_API 15 -#define IRQ_SIM_DETECT 16 -#define IRQ_EXTERNAL_FIQ 17 -#define IRQ_UART_IRDA 18 -#define IRQ_ULPD_GSM_TIMER 19 -#define IRQ_GEA 20 - -#define MAX_IRQ_NUM 20 - -#define INTH_BASE_ADDR 0xFFFFFA00 - -#ifdef __ASSEMBLER__ - -/* - * Assembly source with cpp - * - * The most convenient way to access registers like these from ARM - * assembly is to load the base address of the register block in some - * ARM register, using only one ldr rN, =xxx instruction and only one - * literal pool entry, and then access various registers in the block - * from the same base using the immediate offset addressing mode. - * - * Here we define the offsets for the usage scenario above. - */ - -#define IT_REG1 0x00 -#define IT_REG2 0x02 -#define MASK_IT_REG1 0x08 -#define MASK_IT_REG2 0x0A -#define IRQ_NUM 0x10 -#define FIQ_NUM 0x12 -#define IRQ_CTRL 0x14 -#define ILR_OFFSET 0x20 - -#else - -/* - * C source - * - * For access from C, we define the layout of the INTH register block - * as a struct, and then define a pleudo-global-var for easy "volatile" - * access. - */ - -struct inth_regs { - unsigned short it_reg1; - unsigned short it_reg2; - unsigned short pad1[2]; - unsigned short mask_it_reg1; - unsigned short mask_it_reg2; - unsigned short pad2[2]; - unsigned short irq_num; - unsigned short fiq_num; - unsigned short irq_ctrl; - unsigned short pad3[5]; - unsigned short ilr_irq[MAX_IRQ_NUM+1]; -}; - -#define INTH_REGS (*(volatile struct inth_regs *) INTH_BASE_ADDR) - -/* - * C code can now access INTH registers like this: - * - * old_mask = INTH_REGS.mask_it_reg1; - * INTH_REGS.mask_it_reg1 = new_mask; - */ - -#endif - -#endif /* _CALYPSO_IRQ_H */
--- a/nuc-fw/nucleus/caltimer.h Mon Nov 11 09:56:23 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Definitions for Calypso general-purpose timer registers - * Added to the FreeNucleus Calypso port by Spacefalcon the Outlaw. - * - * This header is usable from both .c and .S source files. - */ - -#ifndef _CALYPSO_TIMER_H -#define _CALYPSO_TIMER_H - -#define TIMER1_BASE_ADDR 0xFFFE3800 -#define TIMER2_BASE_ADDR 0xFFFE6800 - -#ifdef __ASSEMBLER__ - -/* - * Assembly source with cpp - * - * The most convenient way to access registers like these from ARM - * assembly is to load the base address of the register block in some - * ARM register, using only one ldr rN, =xxx instruction and only one - * literal pool entry, and then access various registers in the block - * from the same base using the immediate offset addressing mode. - * - * Here we define the offsets for the usage scenario above. - */ - -#define CNTL_TIM 0x00 -#define LOAD_TIM 0x02 -#define READ_TIM 0x04 - -#else - -/* - * C source - * - * For access from C, we define the layout of each timer register block - * as a struct, and then define a pleudo-global-var for easy "volatile" - * access to each of the 2 timers. - */ - -struct timer_regs { - unsigned char cntl; - unsigned char pad; - unsigned short load; - unsigned short read; -}; - -#define TIMER1_REGS (*(volatile struct timer_regs *) TIMER1_BASE_ADDR) -#define TIMER2_REGS (*(volatile struct timer_regs *) TIMER2_BASE_ADDR) - -#endif - -/* CNTL register bit definitions */ -#define CNTL_START 0x01 -#define CNTL_AUTO_RELOAD 0x02 -#define CNTL_CLOCK_ENABLE 0x20 - -#endif /* include guard */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/debug-chases/README Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,4 @@ +During some of my debug sessions (wild goose chases after difficult bugs) +I hacked the bloody hell out of some Nucleus modules, trying to instrument +them to catch the bugs I was after. This directory is a stash-away place +for such ugly hacks.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/debug-chases/tct.S.dbg Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,3002 @@ +/* + ************************************************************************ + * + * Copyright Mentor Graphics Corporation 2002 + * All Rights Reserved. + * + * THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS + * THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS + * SUBJECT TO LICENSE TERMS. + * + ************************************************************************ + ************************************************************************ + * + * FILE NAME VERSION + * + * tct.s Nucleus PLUS\ARM925\Code Composer 1.14.1 + * + * COMPONENT + * + * TC - Thread Control + * + * DESCRIPTION + * + * This file contains the target processor dependent routines for + * performing target-dependent scheduling functions. + * + * FUNCTIONS + * + * TCT_Control_Interrupts Enable / disable interrupts + * by changing + * TCD_Interrupt_Level + * TCT_Local_Control_Interrupts Enable/disable interrupts + * by not changing + * TCD_Interrupt_Level + * TCT_Restore_Interrupts Restores interrupts to the + * level in TCD_Interrupt_Level + * TCT_Build_Task_Stack Build initial task stack + * TCT_Build_HISR_Stack Build initial HISR stack + * TCT_Build_Signal_Frame Build signal handler frame + * TCT_Check_Stack Check current stack + * TCT_Schedule Schedule the next thread + * TCT_Control_To_Thread Transfer control to a thread + * TCT_Control_To_System Transfer control from thread + * TCT_Signal_Exit Exit from signal handler + * TCT_Current_Thread Returns a pointer to current + * thread + * TCT_Set_Execute_Task Sets TCD_Execute_Task under + * protection from interrupts + * TCT_Protect Protect critical section + * TCT_Unprotect Unprotect critical section + * TCT_Unprotect_Specific Release specific protection + * TCT_Set_Current_Protect Set the thread's current + * protection field + * TCT_Protect_Switch Switch to protected thread + * TCT_Schedule_Protected Schedule the protected thread + * TCT_Interrupt_Context_Save Save interrupted context + * TCT_Interrupt_Context_Restore Restore interrupted context + * TCT_Activate_HISR Activate a HISR + * TCT_HISR_Shell HISR execution shell + * + * DEPENDENCIES + * + * cs_extr.h Common Service functions + * tc_extr.h Thread Control functions + * + * HISTORY + * + * NAME DATE REMARKS + * + * B. Ronquillo 08-28-2002 Released version 1.14.1 + * + ************************************************************************ + */ + +#define NU_SOURCE_FILE + +/* + ****************************** + * INCLUDE ASSEMBLY CONSTANTS * + ****************************** + * Define constants used in low-level initialization. + */ + +#include "asm_defs.h" + + .code 32 + +/* TCT_System_Limit is a global variable defined in this module */ + + .comm TCT_System_Limit,4,4 + + .text + +/* + ********************************** + * LOCAL VARIABLE DECLARATIONS * + ********************************** + * Define pointers to system variables so their addresses may be obtained in a + * pc-relative manner. + */ + +System_Limit: + .word TCT_System_Limit + +Int_Level: + .word TCD_Interrupt_Level + +Task_Shell: + .word TCC_Task_Shell + +HISR_Shell: + .word TCT_HISR_Shell + +Signal_Shell: + .word TCC_Signal_Shell + +Current_Thread: + .word TCD_Current_Thread + +Execute_HISR: + .word TCD_Execute_HISR + +Execute_Task: + .word TCD_Execute_Task + +Time_Slice: + .word TMD_Time_Slice + +Slice_State: + .word TMD_Time_Slice_State + +System_Stack: + .word TCD_System_Stack + +Int_Count: + .word TCD_Interrupt_Count + +HISR_Tails: + .word TCD_Active_HISR_Tails + +HISR_Heads: + .word TCD_Active_HISR_Heads + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Control_Interrupts + * + * DESCRIPTION + * + * This function enables and disables interrupts as specified by + * the caller. Interrupts disabled by this call are left disabled + * until the another call is made to enable them. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * new_level New interrupt enable level + * + * OUTPUTS + * + * old_level Previous interrupt enable + * level + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Lockout interrupts while setting + * up the new level, resutling in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * M. Trippi 02-03-1997 Masked the return value to only + * return the interrupt bits. + * (SPR0252) + * + ************************************************************************ + */ + +@INT TCT_Control_Interrupts (INT new_level) +@{ + + .globl TCT_Control_Interrupts +TCT_Control_Interrupts: + +@INT old_level; Old interrupt level + +@ lock out all interrupts before any checking or changing + +@ Obtain the current interrupt lockout posture. +@ old_level = TCD_Interrupt_Level; + +@ Setup new interrupt lockout posture. +@ TCD_Interrupt_Level = new_level; + +@ renable interrupts for the specified lockout + +@ Return old interrupt lockout level. +@ return(old_level); + + MRS r2,CPSR @ Pickup current CPSR + ORR r2,r2,#LOCKOUT @ Build lockout CPSR + MSR CPSR,r2 @ Lockout interrupts temporarily + LDR r1, Int_Level @ Pickup interrupt level + LDR r3,[r1, #0] @ Pickup current interrupt lockout + BIC r2,r2,#LOCK_MSK @ Clear lockout mask + ORR r2,r2,r0 @ Build new CPSR with appropriate + @ interrupts locked out + STR r0,[r1,#0] @ Save current lockout + MSR CPSR,r2 @ Setup new CPSR lockout bits + AND r0,r3,#LOCK_MSK @ Return previous lockout (SPR0252) + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Local_Control_Interrupts + * + * DESCRIPTION + * + * This function enables and disables interrupts as specified by + * the caller. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * new_level New interrupt enable level + * + * OUTPUTS + * + * old_level Previous interrupt enable + * level + * + * HISTORY + * + * NAME DATE REMARKS + * + * C. Meredith 03-01-1994 Created initial version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * M. Trippi 02-03-1997 Masked the return value to only + * return the interrupt bits. + * (SPR0252) + * + ************************************************************************ + */ + +@INT TCT_Local_Control_Interrupts (INT new_level) +@{ + + .globl TCT_Local_Control_Interrupts +TCT_Local_Control_Interrupts: + +@INT old_level; Old interrupt level + +@ read in the old level +@ old_level = current interrupt level of processor; + + MRS r2,CPSR @ Pickup current CPSR + MOV r3,r2 @ save the old level + +@ clear out the old level and set the new level +@ current interrupt level of processor &= ~LOCKOUT; +@ current interrupt level of processor |= new_level; + + BIC r2,r2,#LOCK_MSK @ Clear all current interrupts + ORR r2,r2,r0 @ Build new CPSR with new + @ interrupt level + MSR CPSR,r2 @ Setup new CPSR interrupt bits + +@ Return old interrupt lockout level. +@ return(old_level); + + AND r0,r3,#LOCK_MSK @ Return previous lockout (SPR0252) + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Restore_Interrupts + * + * DESCRIPTION + * + * This function restores interrupts to that specified in the global + * TCD_Interrupt_Level variable. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * None. + * + * OUTPUTS + * + * None. + * + * HISTORY + * + * NAME DATE REMARKS + * + * C. Meredith 03-01-1994 Created initial version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Restore_Interrupts (VOID) +@{ + + .globl TCT_Restore_Interrupts +TCT_Restore_Interrupts: + +@ Lock out all interrupts before any checking or changing +@ Obtain the current interrupt lockout posture. +@ Reload the level base on the TCD_Interrupt_Level variable + + MRS r1,CPSR @ Pickup current CPSR + MOV r2,r1 @ save the CPSR value + ORR r1,r1,#LOCKOUT @ Build lockout CPSR + MSR CPSR,r1 @ Lockout interrupts temporarily + BIC r2,r2,#LOCK_MSK @ Clear current interrupt levels + LDR r1,Int_Level @ Load address of TCD_Interrupt_Level + LDR r0,[r1, #0] @ Pickup current interrupt lockout + ORR r2,r2,r0 @ Build new CPSR with appropriate + @ interrupts locked out + MSR CPSR,r2 @ Setup new CPSR lockout bits + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Build_Task_Stack + * + * DESCRIPTION + * + * This function builds an initial stack frame for a task. The + * initial stack contains information concerning initial values of + * registers and the task's point of entry. Furthermore, the + * initial stack frame is in the same form as an interrupt stack + * frame. + * + * CALLED BY + * + * TCC_Create_Task Create a new task + * TCC_Reset_Task Reset the specified task + * + * CALLS + * + * None + * + * INPUTS + * + * task Task control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Build_Task_Stack(TC_TCB *task) +@{ + + .globl TCT_Build_Task_Stack +TCT_Build_Task_Stack: + + @ Pickup the stack base. +@ REG_Stack_Base = (BYTE_PTR) task -> tc_stack_start; + + LDR r2,[r0,#0x24] @ Pickup the stack starting address + + @ Pickup the stack size. +@ REG_Stack_Size = task -> tc_stack_size; + + LDR r1,[r0,#0x30] @ Pickup the stack size in bytes + + @ Calculate the stack ending address. +@ REG_Stack_End = REG_Stack_Base + REG_Stack_Size - 1; + + ADD r3,r1,r2 @ Compute the beginning of stack + BIC r3,r3,#3 @ Insure word alignment + SUB r3,r3,#4 @ Reserve a word + + @ Save the stack ending address. +@ task -> tc_stack_end = REG_Stack_End; + + STR r3,[r0,#0x28] @ Save the stack ending address + + @ Reference the task shell. +@ REG_Function_Ptr = (VOID *) TCC_Task_Shell; + +@ Build an initial stack. This initial stack frame facilitates an +@ interrupt return to the TCC_Task_Shell function, which in turn +@ invokes the application task. The initial stack frame has the +@ following format: + +@ (Lower Address) Stack Top -> 1 (Interrupt stack type) +@ CPSR Saved CPSR +@ r0 Saved r0 +@ r1 Saved r1 +@ r2 Saved r2 +@ r3 Saved r3 +@ r4 Saved r4 +@ r5 Saved r5 +@ r6 Saved r6 +@ r7 Saved r7 +@ r8 Saved r8 +@ r9/sb Saved r9/sl +@ r10/sl Saved r10/sl +@ fp Saved fp +@ r12 Saved r12 +@ r13 Saved r13 +@ r14 Saved r14 +@ (Higher Address) Stack Bottom-> r15 Saved r15 + + + LDR r2, Task_Shell @ Pickup address of shell entry + STR r2,[r3], #-4 @ Store entry address on stack + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r14 + ADD r2,r3,#8 @ Compute initial r13 + STR r2,[r3], #-4 @ Store initial r13 (Stack Bottom) + STR r2,[r3], #-4 @ Store initial r12 + STR r2,[r3], #-4 @ Store initial fp + LDR r2,[r0,#0x24] @ Pickup the stack starting address + STR r2,[r3], #-4 @ Store initial r10/sl + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r9/sb + STR r2,[r3], #-4 @ Store initial r8 + STR r2,[r3], #-4 @ Store initial r7 + STR r2,[r3], #-4 @ Store initial r6 + STR r2,[r3], #-4 @ Store initial r5 + STR r2,[r3], #-4 @ Store initial r4 + STR r2,[r3], #-4 @ Store initial r3 + STR r2,[r3], #-4 @ Store initial r2 + STR r2,[r3], #-4 @ Store initial r1 + STR r2,[r3], #-4 @ Store initial r0 + MSR CPSR_f,r2 @ Clear the flags + MRS r2,CPSR @ Pickup the CPSR + BIC r2,r2,#LOCK_MSK @ Clear initial interrupt lockout + STR r2,[r3], #-4 @ Store CPSR on the initial stack + MOV r2,#1 @ Build interrupt stack type (1) + STR r2,[r3, #0] @ Store stack type on the top + + @ Save the minimum amount of remaining stack memory. +@ task -> tc_stack_minimum = REG_Stack_Size - 72; + + MOV r2,#72 @ Size of interrupt stack frame + SUB r1,r1,r2 @ Compute minimum available bytes + STR r1,[r0, #0x34] @ Save in minimum stack area + + @ Save the new stack pointer into the task's control block. +@ task -> tc_stack_pointer = (VOID *) Stack_Top; + + STR r3,[r0, #0x2C] @ Save stack pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Build_HISR_Stack + * + * DESCRIPTION + * + * This function builds an HISR stack frame that allows quick + * scheduling of the HISR. + * + * CALLED BY + * + * TCC_Create_HISR Create HISR function + * + * CALLS + * + * None + * + * INPUTS + * + * hisr HISR control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Build_HISR_Stack(TC_HCB *hisr) +@{ + + .globl TCT_Build_HISR_Stack +TCT_Build_HISR_Stack: + + @ Pickup the stack base. +@ REG_Stack_Base = (BYTE_PTR) hisr -> tc_stack_start; + + LDR r2,[r0,#0x24] @ Pickup the stack starting address + + @ Pickup the stack size. +@ REG_Stack_Size = hisr -> tc_stack_size; + + LDR r1,[r0,#0x30] @ Pickup the stack size in bytes + + @ Calculate the stack ending address. +@ REG_Stack_End = REG_Stack_Base + REG_Stack_Size; + + ADD r3,r1,r2 @ Compute the beginning of stack + BIC r3,r3,#3 @ Insure word alignment + SUB r3,r3,#4 @ Reserve a word + + @ Save the stack ending address. +@ hisr -> tc_stack_end = REG_Stack_End; + + STR r3,[r0,#0x28] @ Save the stack ending address + + @ Reference the HISR shell. +@ REG_Function_Ptr = (VOID *) TCT_HISR_Shell; + +@ Build an initial stack. This initial stack frame facilitates an +@ solicited return to the TCT_HISR_Shell function, which in turn +@ invokes the appropriate HISR. The initial HISR stack frame has the +@ following format: + +@ (Lower Address) Stack Top -> 0 (Solicited stack type) +@ !!FOR THUMB ONLY!! 0/0x20 Saved state mask +@ r4 Saved r4 +@ r5 Saved r5 +@ r6 Saved r6 +@ r7 Saved r7 +@ r8 Saved r8 +@ r9/sb Saved r9/sl +@ r10/sl Saved r10/sl +@ fp Saved fp +@ r12 Saved r12 +@ (Higher Address) Stack Bottom-> r15 Saved r15 + + + LDR r2,HISR_Shell @ Pickup address of shell entry + STR r2,[r3], #-4 @ Store entry address on stack + ADD r2,r3,#4 @ Compute initial r13 + STR r2,[r3], #-4 @ Store initial r12 + STR r2,[r3], #-4 @ Store initial fp + LDR r2,[r0,#0x24] @ Pickup the stack starting address + STR r2,[r3], #-4 @ Store initial r10/sl + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r9/sb + STR r2,[r3], #-4 @ Store initial r8 + STR r2,[r3], #-4 @ Store initial r7 + STR r2,[r3], #-4 @ Store initial r6 + STR r2,[r3], #-4 @ Store initial r5 + STR r2,[r3], #-4 @ Store initial r4 +#if 1 /* was .if THUMB */ + STR r2,[r3], #-4 @ Store initial state mask +#endif + STR r2,[r3, #0] @ Store solicited stack type on the + @ top of the stack + + @ Save the minimum amount of remaining stack memory. +@ hisr -> tc_stack_minimum = REG_Stack_Size - (ARM)44 or (THUMB)48; + +#if 1 /* was .if THUMB */ + MOV r2,#48 @ Size of solicited stack frame +#else + MOV r2,#44 @ Size of solicited stack frame +#endif + + SUB r1,r1,r2 @ Compute minimum available bytes + STR r1,[r0, #0x34] @ Save in minimum stack area + + @ Save the new stack pointer into the task's control block. +@ hisr -> tc_stack_pointer = (VOID *) Stack_Top; + + STR r3,[r0, #0x2C] @ Save stack pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Build_Signal_Frame + * + * DESCRIPTION + * + * This function builds a frame on top of the task's stack to + * cause the task's signal handler to execute the next time + * the task is executed. + * + * CALLED BY + * + * TCC_Send_Signals Send signals to a task + * + * CALLS + * + * None + * + * INPUTS + * + * task Task control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Build_Signal_Frame(TC_TCB *task) +@{ + + .globl TCT_Build_Signal_Frame +TCT_Build_Signal_Frame: + + @ Pickup the stack pointer. +@ REG_Stack_Ptr = (BYTE_PTR) task -> tc_stack_pointer; + + LDR r3,[r0,#0x2c] @ Pickup the current stack pointer + + @ Reference the Signal shell. +@ REG_Function_Ptr = (VOID *) TCC_Signal_Shell; + +@ Build a signal stack. This signal stack frame facilitates an +@ solicited return to the TCC_Signal_Shell function, which in turn +@ invokes the appropriate signal handler. The initial HISR stack frame +@ has the following format: + +@ (Lower Address) Stack Top -> 0 (Solicited stack type) +@ !!FOR THUMB ONLY!! 0/0x20 Saved state mask +@ r4 Saved r4 +@ r5 Saved r5 +@ r6 Saved r6 +@ r7 Saved r7 +@ r8 Saved r8 +@ r9/sb Saved r9/sl +@ r10/sl Saved r10/sl +@ fp Saved fp +@ r12 Saved r12 +@ (Higher Address) Stack Bottom-> r15 Saved r15 + + + LDR r2,Signal_Shell @ Pickup address of shell entry + SUB r3,r3,#4 + STR r2,[r3], #-4 @ Store entry address on stack + ADD r2,r3,#4 @ Compute initial r13 + STR r2,[r3], #-4 @ Store initial r12 + STR r2,[r3], #-4 @ Store initial fp + LDR r2,[r0,#0x24] @ Pickup the stack starting address + STR r2,[r3], #-4 @ Store initial r10/sl + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r9/sb + STR r2,[r3], #-4 @ Store initial r8 + STR r2,[r3], #-4 @ Store initial r7 + STR r2,[r3], #-4 @ Store initial r6 + STR r2,[r3], #-4 @ Store initial r5 + STR r2,[r3], #-4 @ Store initial r4 +#if 0 + MOV r1,#0x20 @ Get initial state mask + STR r1,[r3], #-4 @ Store initial state mask +#else + STR r2,[r3], #-4 @ TCC_Signal_Shell is an ARM proc +#endif + + STR r2,[r3, #0] @ Store solicited stack type on the + @ top of the stack + + @ Save the new stack pointer into the task's control block. +@ task -> tc_stack_pointer = (VOID *) (REG_Stack_Ptr - REG_Stack_Size); + + STR r3,[r0, #0x2C] @ Save stack pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Check_Stack + * + * DESCRIPTION + * + * This function checks the current stack for overflow conditions. + * Additionally, this function keeps track of the minimum amount + * of stack space for the calling thread and returns the current + * available stack space. + * + * CALLED BY + * + * TCC_Send_Signals Send signals to a task + * + * CALLS + * + * ERC_System_Error System error handler + * + * INPUTS + * + * None + * + * OUTPUTS + * + * available bytes in stack + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@UNSIGNED TCT_Check_Stack(void) +@{ + + .globl TCT_Check_Stack +TCT_Check_Stack: + +@TC_TCB *thread; +@UNSIGNED remaining; + + @ Pickup the current task/HISR pointer. +@ thread = (TC_TCB *) TCD_Current_Thread; + + LDR r0,Current_Thread @ Pickup address of thread pointer + LDR r0,[r0,#0] @ Pickup thread pointer + + @ Determine if there is a current thread. +@ if (thread) +@ { + + CMP r0,#0 @ Determine if a thread is active + MOV r3,#0 @ Default remaining value + BEQ TCT_Skip_Stack_Check @ If NU_NULL, skip stack checking + + @ Determine if the stack pointers are out of range. +@ if ((thread -> tc_stack_pointer < thread -> tc_stack_start) || +@ (thread -> tc_stack_pointer > thread -> tc_stack_end)) + + LDR r2,[r0,#0x24] @ Pickup start of stack area + CMP r13,r2 @ Compare with current stack ptr + BLT TCT_Stack_Range_Error @ If less, stack is out of range + LDR r1,[r0,#0x28] @ Pickup end of stack area + CMP r13,r1 @ Compare with current stack ptr + BLE TCT_Stack_Range_Okay @ If less, stack range is okay + + @ Stack overflow condition exits. +@ ERC_System_Error(NU_STACK_OVERFLOW); + +TCT_Stack_Range_Error: + + STR r14,[r13, #4]! @ Store r14 on the stack + MOV r0,#3 @ Build NU_STACK_OVERFLOW code + BL ERC_System_Error @ Call system error handler. Note: + @ control is not returned! + @ Examine stack to find return + @ address of this routine. + +TCT_Stack_Range_Okay: + + @ Calculate the amount of available space on the stack. +@ remaining = (BYTE_PTR) thread -> tc_stack_pointer - +@ (BYTE_PTR) thread -> tc_stack_start; + + SUB r3,r13,r2 @ Calculate remaining stack size + + @ Determine if there is enough memory on the stack to save all of the + @ registers. +@ if (remaining < 80) + + CMP r3,#80 @ Is there enough room for an + @ interrupt frame? + BCS TCT_No_Stack_Error @ If so, no stack overflow yet + + @ Stack overflow condition is about to happen. +@ ERC_System_Error(NU_STACK_OVERFLOW); + + STR r14,[r13, #4]! @ Store r14 on the stack + MOV r0,#3 @ Build NU_STACK_OVERFLOW code + BL ERC_System_Error @ Call system error handler. Note: + @ control is not returned! + @ Examine stack to find return + @ address of this routine. + +TCT_No_Stack_Error: + + @ Determine if this is a new minimum amount of stack space. +@ if (remaining < thread -> tc_stack_minimum) + + LDR r2,[r0,#0x34] + CMP r3,r2 + STRCC r3,[r0,#0x34] + + @ Save the new stack minimum. +@ thread -> tc_stack_minimum = remaining; +@ } +@ else + + @ Set the remaining bytes to 0. +@ remaining = 0; + + @ Return the remaining number of bytes on the stack. +@ return(remaining); + +TCT_Skip_Stack_Check: + MOV r0,r3 @ Return remaining bytes + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Schedule + * + * DESCRIPTION + * + * This function waits for a thread to become ready. Once a thread + * is ready, this function initiates a transfer of control to that + * thread. + * + * CALLED BY + * + * INC_Initialize Main initialization routine + * + * CALLS + * + * TCT_Control_To_Thread Transfer control to a thread + * + * INPUTS + * + * TCD_Execute_Task Pointer to task to execute + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Schedule(void) +@{ + + .globl TCT_Schedule +TCT_Schedule: + + @ Restore interrupts according to the value contained in +@ TCD_Interrupt_Level. + + LDR r1,Int_Level @ Build address of interrupt level + MRS r0,CPSR @ Pickup current CPSR + LDR r2,[r1, #0] @ Pickup current interrupt lockout + BIC r0,r0,#LOCK_MSK @ Clear the interrupt lockout bits + ORR r0,r0,r2 @ Build new interrupt lockout CPSR + MSR CPSR,r0 @ Setup new CPSR + LDR r2,Execute_HISR @ Pickup TCD_Execute_HISR address + LDR r3,Execute_Task @ Pickup TCD_Execute_Task address + +#ifdef INCLUDE_PROVIEW +@ Nucleus ProView Hook +@ We check if upon entering TCT_Schedule we already have a task to excute. +@ if not, we start IDLE. + LDR r0,[r2, #0] @ Pickup highest priority HISR ptr + CMP r0,#0 @ Is there a HISR active? + BNE TCT_Schedule_Thread @ Found an HISR + LDR r0,[r3, #0] @ Pickup highest priority Task ptr + CMP r0,#0 @ Is there a task active? + BNE TCT_Schedule_Thread @ If not, start IDLE. + STR r2,[r13, #-4]! @ Save r2 on the stack + STR r3,[r13, #-4]! @ Save r3 on the stack + BL _NU_Idle_Hook + LDR r3,[r13], #4 @ Recover r2 + LDR r2,[r13], #4 @ Recover r3 +#endif + + + @ Wait until a thread (task or HISR) is available to execute. +@ do +@ { +TCT_Schedule_Loop: + +@ } while ((!TCD_Execute_HISR) && (!TCD_Execute_Task)); + + LDR r0,[r2, #0] @ Pickup highest priority HISR ptr + CMP r0,#0 @ Is there a HISR active? + BNE TCT_Schedule_Thread @ Found an HISR + LDR r0,[r3, #0] @ Pickup highest priority Task ptr + CMP r0,#0 @ Is there a task active? + BNE TCT_Schedule_Thread +@ stmfd r13!,{r2-r3} +@ BL freecalypso_nucidle_dbghook +@ ldmfd r13!,{r2-r3} + B TCT_Schedule_Loop + + @ Yes, either a task or an HISR is ready to execute. Lockout + @ interrupts while the thread is transferred to. + +TCT_Schedule_Thread: + MRS r1,CPSR @ Pickup CPSR again + ORR r1,r1,#LOCKOUT @ Build interrupt lockout value + MSR CPSR,r1 @ Lockout interrupts + +@ Transfer control to the thread by falling through to the following +@ routine. +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Control_To_Thread + * + * DESCRIPTION + * + * This function transfers control to the specified thread. Each + * time control is transferred to a thread, its scheduled counter + * is incremented. Additionally, time-slicing for task threads is + * enabled in this routine. The TCD_Current_Thread pointer is + * setup by this function. + * + * CALLED BY + * + * TCT_Schedule Indirectly called + * TCT_Protect Protection task switch + * + * CALLS + * + * None + * + * INPUTS + * + * thread Thread control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Control_To_Thread(TC_TCB *thread) +@{ +TCT_Control_To_Thread: + + @ Setup the current thread pointer. +@ TCD_Current_Thread = (VOID *) thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r2,[r0, #0x1c] @ Pickup scheduled count + STR r0,[r1, #0] @ Setup current thread pointer + + @ Increment the thread scheduled counter. +@ thread -> tc_scheduled++; + + LDR r3,[r0, #0x20] @ Pickup time slice value + ADD r2,r2,#1 @ Increment the scheduled count + STR r2,[r0, #0x1c] @ Store new scheduled count + + @ Check for time slice option. +@ if (thread -> tc_cur_time_slice) +@ { + CMP r3,#0 @ Is there a time slice? + BEQ TCT_No_Start_TS_1 @ If 0, there is no time slice + + @ Start a time slice. +@ TMD_Time_Slice = thread -> tc_cur_time_slice; +@ TMD_Time_Slice_State = 0; + + LDR r2,Time_Slice @ Pickup address of TMD_Time_Slice + LDR r1,Slice_State @ Pickup address of + @ TMD_Time_Slice_State + STR r3,[r2, #0] @ Setup the time slice + MOV r2,#0 @ Build active state flag + STR r2,[r1,#0] @ Set the active flag +@ } +TCT_No_Start_TS_1: +#ifdef INCLUDE_PROVIEW +@ Nucleus ProView Hook + + STR r0,[r13, #-4]! @ Save r0 on the stack + BL _NU_Schedule_Task_Hook @ Branch to RTView + LDR r0,[r13], #4 @ Recover return address +#endif + + + @ Pickup the stack pointer and resume the thread. +@ REG_Stack_Ptr = thread -> tc_stack_pointer; + + LDR r13,[r0, #0x2c] @ Switch to thread's stack pointer + +@ Pop off the saved information associated with the thread. After we +@ determine which type of stack is present. A 1 on the top of the +@ stack indicates an interrupt stack, while a 0 on the top of the +@ stack indicates a solicited type of stack. + +@ Remember that the interrupt level that is restored must represent +@ the interrupt level in TCD_Interrupt_Level. + + LDR r1,[r13], #4 @ Pop off the stack type + CMP r1,#1 @ See if it is an interrupt stack + BEQ TCT_Interrupt_Resume @ If so, an interrupt resume of + @ thread is required + LDR r1, Int_Level @ Pickup address of interrupt + @ lockout + MRS r0,CPSR @ Pickup current CPSR + BIC r0,r0,#LOCK_MSK @ Clear lockout mask + + BIC r0,r0,#0x80000000 + + + LDR r2,[r1, #0] @ Pickup interrupt lockout mask + ORR r0,r0,r2 @ Build new interrupt lockout mask +#if 1 /* was .if THUMB */ + LDR r2,[r13], #4 @ Pop off the state mask + ORR r0,r0,r2 @ Set appropriate state +#endif + MSR SPSR,r0 @ Place it into the SPSR + LDMIA r13!,{r4-r12,r15}^ @ A solicited return is required. + @ This type of return only + @ recovers r4-r13 & r15 +TCT_Interrupt_Resume: + LDR r0,[r13], #4 @ Pop off the CPSR + LDR r1,Int_Level @ Pickup address of interrupt + @ lockout + BIC r0,r0,#LOCK_MSK @ Clear lockout mask + LDR r2,[r1, #0] @ Pickup interrupt lockout mask + ORR r0,r0,r2 @ Build new interrupt lockout mask + MSR SPSR,r0 @ Place it into the SPSR + LDMIA r13,{r0-r15}^ @ Recover all registers and resume + @ at point of interrupt +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Control_To_System + * + * DESCRIPTION + * + * This function returns control from a thread to the system. Note + * that this service is called in a solicited manner, i.e. it is + * not called from an interrupt thread. Registers required by the + * compiler to be preserved across function boundaries are saved by + * this routine. Note that this is usually a sub-set of the total + * number of available registers. + * + * CALLED BY + * + * Other Components + * + * CALLS + * + * TCT_Schedule Schedule the next thread + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, resulting in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Control_To_System(void) +@{ + + .globl TCT_Control_To_System +TCT_Control_To_System: + + @ Lockout interrupts. + + MRS r0,CPSR @ Pickup current CPSR + ORR r0,r0,#LOCKOUT @ Build interrupt lockout value + MSR CPSR,r0 @ Lockout interrupts + + @ Save a minimal context of the thread. + + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack +#if 1 /* was .if THUMB */ + MOV r2,r14 @ Determine what state the caller + MOV r2,r2,LSL #31 @ was in and build an + MOV r2,r2,LSR #26 @ appropriate state mask + STR r2,[r13, #-4]! @ Place it on the stack +#endif + + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value + STR r2,[r13, #-4]! @ Place it on the top of the stack + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r0,[r1, #0] @ Pickup current thread pointer + + @ Clear the current thread control block pointer. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + +@ Check to see if a time slice is active. If so, copy the original time +@ slice into the current time slice field of the task's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_1 @ If non-active, don't disable + + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice +@ } +TCT_No_Stop_TS_1: + + @ Save off the current stack pointer in the control block. +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + STR r13,[r0, #0x2c] @ Save the thread's stack pointer + + @ Clear the task's current protection. +@ (REG_Thread_Ptr -> tc_current_protect) -> tc_tcb_pointer = NU_NULL; +@ REG_Thread_Ptr -> tc_current_protect = NU_NULL; + + LDR r1,[r0, #0x38] @ Pickup current thread pointer + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0x38] @ Clear the protect pointer field + STR r2,[r1, #0] @ Release the actual protection + + @ Switch to the system stack. +@ REG_Stack_Ptr = TCD_System_Stack; + + LDR r1, System_Stack @ Pickup address of stack pointer + LDR r2, System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Finished, return to the scheduling loop. + + B TCT_Schedule @ Return to scheduling loop +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Signal_Exit + * + * DESCRIPTION + * + * This function exits from a signal handler. The primary purpose + * of this function is to clear the scheduler protection and switch + * the stack pointer back to the normal task's stack pointer. + * + * CALLED BY + * + * TCC_Signal_Shell Signal handling shell func + * + * CALLS + * + * TCT_Schedule Scheduler + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, resulting in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Signal_Exit(void) +@{ + + .globl TCT_Signal_Exit +TCT_Signal_Exit: + + @ Lockout interrupts. + + MRS r3,CPSR @ Pickup current CPSR + ORR r3,r3,#LOCKOUT @ Build lockout value + MSR CPSR,r3 @ Lockout interrupts + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup address of thread pointer + MOV r2,#0 @ Build NU_NULL value + LDR r0,[r1,#0] @ Pickup current thread pointer + + @ Clear the current thread control block. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Clear current thread pointer + + @ Check to see if a time slice is active. If so, copy the original time + @ slice into the current time slice field of the task's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_2 @ If non-active, don't disable + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice +@ } +TCT_No_Stop_TS_2: + + @ Switch back to the saved stack. The saved stack pointer was saved + @ before the signal frame was built. +@ REG_Thread_Ptr -> tc_stack_pointer = +@ REG_Thread_Ptr -> tc_saved_stack_ptr; + + LDR r1,[r0, #0x3c] @ Pickup saved stack pointer + STR r1,[r0, #0x2c] @ Place in current stack pointer + + @ Clear the task's current protection. +@ (REG_Thread_Ptr -> tc_current_protect) -> tc_tcb_pointer = NU_NULL; +@ REG_Thread_Ptr -> tc_current_protect = NU_NULL; + + LDR r1,[r0, #0x38] @ Pickup current thread pointer + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0x38] @ Clear the protect pointer field + STR r2,[r1, #0] @ Release the actual protection + + @ Switch to the system stack. +@ REG_Stack_Ptr = (BYTE_PTR) TCD_System_Stack; + + LDR r1, System_Stack @ Pickup address of stack pointer + LDR r2, System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Finished, return to the scheduling loop. + + B TCT_Schedule @ Return to scheduling loop +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Current_Thread + * + * DESCRIPTION + * + * This function returns the current thread pointer. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * Pointer to current thread + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID *TCT_Current_Thread(void) +@{ + + .globl TCT_Current_Thread +TCT_Current_Thread: + + @ Return the current thread pointer. +@ return(TCD_Current_Thread); + + LDR r0, Current_Thread @ Pickup address of thread pointer + LDR r0,[r0, #0] @ Pickup current thread pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Set_Execute_Task + * + * DESCRIPTION + * + * This function sets the current task to execute variable under + * protection against interrupts. + * + * CALLED BY + * + * TCC Scheduling Routines + * + * CALLS + * + * None + * + * INPUTS + * + * task Pointer to task control block + * + * OUTPUTS + * + * TCD_Execute_Task Modified variable + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Set_Execute_Task(TC_TCB *task) +@{ + + .globl TCT_Set_Execute_Task +TCT_Set_Execute_Task: + + @ Now setup the TCD_Execute_Task pointer. +@ TCD_Execute_Task = task; + + LDR r1, Execute_Task @ Pickup execute task ptr address + STR r0,[r1,#0] @ Setup new task to execute + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Protect + * + * DESCRIPTION + * + * This function protects against multiple thread access. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * protect Pointer to protection block + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Protect(TC_PROTECT *protect) +@{ + + .globl TCT_Protect +TCT_Protect: + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if it is non-NULL + BEQ TCT_Skip_Protect @ If NULL, skip protection + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + + @ Wait until the protect structure is available. +@ while (protect -> tc_tcb_pointer != NU_NULL) +@ { + +TCT_Protect_Loop: + LDR r1,[r0, #0] @ Pickup protection owner field + CMP r1,#0 @ Is there any protection? + BEQ TCT_Protect_Available @ If NU_NULL, no current protection + + @ Protection structure is not available. + + @ Indicate that another thread is waiting. +@ protect -> tc_thread_waiting = 1; + + MOV r2,#1 @ Build thread waiting flag + STR r2,[r0, #4] @ Set waiting field + + @ Directly schedule the thread waiting. +@ TCT_Schedule_Protected(protect -> tc_tcb_pointer); + + STR r0,[r13, #-4]! @ Save r0 on the stack + STR r14,[r13, #-4]! @ Save r14 on the stack + MOV r0,r3 @ Place current thread into r0 + BL TCT_Schedule_Protected @ Call routine to schedule the + @ owner of the thread + + LDR r14,[r13], #4 @ Recover saved r14 + LDR r0,[r13], #4 @ Recover saved r0 + + @ Lockout interrupts. + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + B TCT_Protect_Loop @ Examine protect flags again +@ } +TCT_Protect_Available: + + @ Protection structure is available. + + @ Indicate that this thread owns the protection. +@ protect -> tc_tcb_pointer = TCD_Current_Thread; + + STR r3,[r0, #0] @ Indicate calling thread owns this + @ protection + + @ Clear the thread waiting flag. +@ protect -> tc_thread_waiting = 0; + + MOV r2,#0 @ Clear value + STR r2,[r0, #4] @ Clear the thread waiting flag + +@ Save the protection pointer in the thread's control block. Note +@ that both task and HISR threads share the same control block +@ format. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; +@ REG_Thread_Ptr -> tc_current_protect = protect; + + STR r0,[r3, #0x38] @ Setup current protection + + @ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately +@ } + +TCT_Skip_Protect: + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Unprotect + * + * DESCRIPTION + * + * This function releases protection of the currently active + * thread. If the caller is not an active thread, then this + * request is ignored. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Unprotect(void) +@{ + + .globl TCT_Unprotect +TCT_Unprotect: + + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if it is non-NULL + BEQ TCT_Skip_Unprotect @ If NULL, skip unprotection + + @ Setup a thread control block pointer. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + @ Determine if there is a currently active protection. +@ if (REG_Thread_Ptr -> tc_current_protect) +@ { + + LDR r0,[r3, #0x38] @ Pickup current protect field + CMP r0,#0 @ Is there a protection in force? + BEQ TCT_Skip_Unprotect @ If not, nothing is protected + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + + @ Yes, this thread still has this protection structure. +@ REG_Protect_Ptr = REG_Thread_Ptr -> tc_current_protect; + + @ Is there a higher priority thread waiting for the protection + @ structure? +@ if (REG_Protect_Ptr -> tc_thread_waiting) + + LDR r2,[r0, #4] @ Pickup thread waiting flag + CMP r2,#0 @ Are there any threads waiting? + BEQ TCT_Not_Waiting_Unpr @ If not, just release protection + +@ Transfer control to the system. Note that this +@ automatically clears the current protection and it returns +@ to the caller of this routine instead of this routine. +@ TCT_Control_To_System(); + + B TCT_Control_To_System @ Return control to the system + +@ else +@ { +TCT_Not_Waiting_Unpr: + + @ Clear the protection. +@ REG_Thread_Ptr -> tc_current_protect = NU_NULL; +@ REG_Protect_Ptr -> tc_tcb_pointer = NU_NULL; + + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0] @ Release the protection + STR r2,[r3, #0x38] @ Clear protection pointer in the + @ control block + +@ } + +TCT_Not_Protected: + @ Restore interrupts again. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + +@ } +@ } +TCT_Skip_Unprotect: + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Unprotect_Specific + * + * DESCRIPTION + * + * This function releases a specific protection structure. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * protect Pointer to protection block + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, corrected bug + * using protect ptr, resulting + * in version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID Specific(TC_PROTECT *protect) +@{ + + .globl TCT_Unprotect_Specific +TCT_Unprotect_Specific: + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if it is non-NULL + BEQ TCT_Skip_Unprot_Spec @ If NULL, skip unprotect specific + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + + @ Clear the protection pointer. +@ protect -> tc_tcb_pointer = NU_NULL; + + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0] @ Clear protection ownership + + @ Determine if a thread is waiting. +@ if (protect -> tc_thread_waiting) +@ { + + LDR r1,[r0, #4] @ Pickup the waiting field + CMP r1,#0 @ Is there another thread waiting? + BEQ TCT_Not_Waiting_Unspec @ No, restore interrupts and return + + @ A higher-priority thread is waiting. + + @ Save a minimal context of the thread. + + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack + +#if 1 /* was .if THUMB */ + MOV r2,r14 @ Determine what state the caller + MOV r2,r2,LSL #31 @ was in and build an + MOV r2,r2,LSR #26 @ appropriate state mask + STR r2,[r13, #-4]! @ Place it on the stack +#endif + + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value + STR r2,[r13, #-4]! @ Place it on the top of the stack + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r0,[r1, #0] @ Pickup current thread pointer + + @ Clear the current thread control block pointer. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + + @ Check to see if a time slice is active. If so, copy the + @ original time slice into the current time slice field of the + @ thread's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_3 @ If non-active, don't disable + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = +@ REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to + @ NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice +@ } + +TCT_No_Stop_TS_3: + + @ Save off the current stack pointer in the control block. +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + STR r13,[r0, #0x2c] @ Save the thread's stack pointer + + @ Switch to the system stack. +@ REG_Stack_Ptr = TCD_System_Stack; + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Finished, return to the scheduling loop. + + B TCT_Schedule @ Return to scheduling loop + +@ } +@ else +@ { +TCT_Not_Waiting_Unspec: + + @ No higher-priority thread is waiting. + +@ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + +@ } +@ } + +TCT_Skip_Unprot_Spec: + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Set_Current_Protect + * + * DESCRIPTION + * + * This function sets the current protection field of the current + * thread's control block to the specified protection pointer. + * + * CALLED BY + * + * TCC_Resume_Task Resume task function + * + * CALLS + * + * None + * + * INPUTS + * + * protect Pointer to protection block + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Set_Current_Protect(TC_PROTECT *protect) +@{ + + .globl TCT_Set_Current_Protect +TCT_Set_Current_Protect: + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if a thread is + @ active + + @ Point at the current thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + @ Modify the current protection. +@ REG_Thread_Ptr -> tc_current_protect = protect; + + STRNE r0,[r3, #0x38] @ Setup new protection +@ } + + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Protect_Switch + * + * DESCRIPTION + * + * This function waits until a specific task no longer has any + * protection associated with it. This is necessary since task's + * cannot be suspended or terminated unless they have released all + * of their protection. + * + * CALLED BY + * + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * thread Pointer to thread control blk + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Protect_Switch(VOID *thread) +@{ + + .globl TCT_Protect_Switch +TCT_Protect_Switch: + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + +@ REG_Thread_Ptr = (TC_TCB *) thread; + + @ Wait until the specified task has no protection associated with it. +@ while (REG_Thread_Ptr -> tc_current_protect) +@ { + + LDR r1,[r0, #0x38] @ Pickup protection of specified + @ thread + CMP r1,#0 @ Does the specified thread have + @ an active protection? + BEQ TCT_Switch_Done @ If not, protect switch is done + + @ Let the task run again in an attempt to clear its protection. + + @ Indicate that a higher priority thread is waiting. +@ (REG_Thread_Ptr -> tc_current_protect) -> tc_thread_waiting = 1; + + MOV r2,#1 @ Build waiting flag value + STR r2,[r1, #4] @ Set waiting flag of the + @ protection owned by the other + @ thread + + @ Directly schedule the thread waiting. +@ TCT_Schedule_Protected((REG_Thread_Ptr -> tc_current_protect) +@ -> tc_tcb_pointer); + + LDR r2,Current_Thread @ Pickup current thread ptr address + STR r0,[r13, #-4]! @ Save r0 on the stack + STR r14,[r13, #-4]! @ Save r14 on the stack + MOV r1,r0 @ Move new thread into r1 + LDR r0,[r2, #0] @ Pickup current thread pointer + BL TCT_Schedule_Protected @ Call routine to schedule the + @ owner of the thread + + LDR r14,[r13], #4 @ Recover saved r14 + LDR r0,[r13], #4 @ Recover saved r0 + + @ Lockout interrupts. + + B TCT_Protect_Switch @ Branch to top of routine and + @ start over +@ } +TCT_Switch_Done: + + @ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Schedule_Protected + * + * DESCRIPTION + * + * This function saves the minimal context of the thread and then + * directly schedules the thread that has protection over the + * the thread that called this routine. + * + * CALLED BY + * + * TCT_Protect + * TCT_Protect_Switch + * + * CALLS + * + * TCT_Control_To_Thread Transfer control to protected + * thread + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, resulting in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Schedule_Protected(VOID *thread) +@{ + + .globl TCT_Schedule_Protected +TCT_Schedule_Protected: + + @ Interrupts are already locked out by the caller. + + @ Save minimal context required by the system. + + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack + +#if 1 /* was .if THUMB */ + MOV r2,r14 @ Determine what state the caller + MOV r2,r2,LSL #31 @ was in and build an + MOV r2,r2,LSR #26 @ appropriate state mask + STR r2,[r13, #-4]! @ Place it on the stack +#endif + + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value + STR r2,[r13, #-4]! @ Place it on the top of the stack + MOV r4,r1 @ Save thread to schedule + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + + @ Clear the current thread control block. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + + @ Check to see if a time slice is active. If so, copy the original time + @ slice into the current time slice field of the task's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_4 @ If non-active, don't disable + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice + +@ } +TCT_No_Stop_TS_4: + + @ Save off the current stack pointer in the control block. +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + STR r13,[r0, #0x2c] @ Save the thread's stack pointer + + @ Switch to the system stack. +@ TCD_System_Stack = (VOID *) REG_Stack_Ptr; + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Transfer control to the specified thread directly. +@ TCT_Control_To_Thread(thread); + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MOV r0,r4 @ Indicate thread to schedule + MSR CPSR,r1 @ Setup CPSR appropriately + ORR r1,r1,#LOCKOUT @ Build lockout value again + MSR CPSR,r1 @ Lockout interrupts again + B TCT_Control_To_Thread @ Schedule the thread indirectly +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Interrupt_Context_Save + * + * DESCRIPTION + * + * This function saves the interrupted thread's context. Nested + * interrupts are also supported. If a task or HISR thread was + * interrupted, the stack pointer is switched to the system stack + * after the context is saved. + * + * CALLED BY + * + * Application ISRs Assembly language ISRs + * INT_Interrupt_Shell Interrupt handler shell + * + * CALLS + * + * None + * + * INPUTS + * + * vector Interrupt's vector number + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * D. Driscoll 01-04-2002 Released version 1.13.3. + * Updated to handle nested / + * prioritized IRQs + ************************************************************************ + */ + +@VOID TCT_Interrupt_Context_Save(INT vector) +@{ + + .globl TCT_Interrupt_Context_Save +TCT_Interrupt_Context_Save: + @ Determine if this is a nested interrupt. + LDR r1,Int_Count @ Pickup address of interrupt count + LDR r2,[r1, #0] @ Pickup interrupt counter + ADD r2,r2,#1 @ Add 1 to interrupt counter + STR r2,[r1, #0] @ Store new interrupt counter value + CMP r2,#1 @ Is it nested? + BEQ TCT_Not_Nested_Save @ No + +@ Nested interrupt. Save complete context on the current stack. +TCT_Nested_Save: + +/* No longer needed in the FreeCalypso version, as we can use r0 instead. */ +#if 0 +@ 1. Save another register on the exception stack so we have enough to work with + STMDB r13!,{r5} +#endif + +@ 2. Save the necessary exception registers into r1-r3 + MOV r1,r13 @ Put the exception r13 into r1 + MOV r2,r14 @ Move the return address for the caller + @ of this function into r2 + MRS r3,spsr @ Put the exception spsr into r3 + +@ 3. Adjust the exception stack pointer for future exceptions + ADD r13,r13,#20 @ r13 reset to pre-interrupt value + +@ 4. Switch CPU modes to save context on system stack + MRS r0,CPSR @ Pickup the current CPSR + BIC r0,r0,#MODE_MASK @ Clear the mode bits + + ORR r0,r0,#SUP_MODE @ Change to supervisor mode (SVD) + + MSR CPSR,r0 @ Switch modes (IRQ->SVC) + +@ 5. Store the SVC r13 into r5 so the r13 can be saved as is. +@ FreeCalyspo: using r0 instead + MOV r0,r13 + +@ 6. Save the exception return address on the stack (r15). + STMDB r0!,{r4} + +@ 7. Save r5-r14 on stack (used to be r6-r14) + STMDB r0!,{r5-r14} + +@ 8. Switch back to using r13 now that the original r13 has been saved. + MOV r13,r0 + +/* no longer relevant */ +#if 0 +@ 9. Get r5 and exception enable registers off of exception stack and +@ save r5 (stored in r4) back to the system stack. + LDMIA r1!,{r4-r5} + STMDB r13!,{r4} + MOV r4,r5 @ Put exception enable value into r4 +#endif + +@ 10. Get the rest of the registers off the exception stack and +@ save them onto the system stack. + LDMIA r1!,{r5-r8,r11} @ Get r0-r4 off exception stack + STMDB r13!,{r5-r8,r11} @ Put r0-r4 on system stack + +/* no longer relevant */ +#if 0 +@ 11. Store the exception enable value back on the exception stack. + STMDB r1,{r4} +#endif + +@ 12. Save the SPSR on the system stack (CPSR) + STMDB r13!,{r3} + +/* TI's approach to interrupt handling does not support re-enabling here */ +#if 0 +@ 13. Re-enable interrupts + MRS r1,CPSR + BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) + MSR CPSR,r1 +#endif + + BX r2 @ Return to calling ISR +@ } +@ else +@ { +TCT_Not_Nested_Save: + + @ Determine if a thread was interrupted. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r1,[r1, #0] @ Pickup the current thread pointer + CMP r1,#0 @ Is it NU_NULL? + BEQ TCT_Idle_Context_Save @ If no, no real save is necessary + + + @ Yes, a thread was interrupted. Save complete context on the + @ thread's stack. + +/* No longer needed in the FreeCalypso version, as we can use r0 instead. */ +#if 0 +@ 1. Save another register on the exception stack so we have enough to work with + STMDB r13!,{r5} +#endif + +@ 2. Save the necessary exception registers into r1-r3 + MOV r1,r13 @ Put the exception r13 into r1 + MOV r2,r14 @ Move the return address for the caller + @ of this function into r2 + MRS r3,spsr @ Put the exception spsr into r3 + +@ 3. Adjust the exception stack pointer for future exceptions + ADD r13,r13,#20 @ r13 reset to pre-interrupt value + +@ 4. Switch CPU modes to save context on system stack + MRS r0,CPSR @ Pickup the current CPSR + BIC r0,r0,#MODE_MASK @ Clear the mode bits + + ORR r0,r0,#SUP_MODE @ Change to supervisor mode (SVD) + + MSR CPSR,r0 @ Switch modes (IRQ->SVC) + +@ 5. Store the SVC r13 into r5 so the r13 can be saved as is. +@ FreeCalyspo: using r0 instead + MOV r0,r13 + +@ 6. Save the exception return address on the stack (r15). + STMDB r0!,{r4} + +@ 7. Save r5-r14 on stack (used to be r6-r14) + STMDB r0!,{r5-r14} + +@ 8. Switch back to using r13 now that the original r13 has been saved. + MOV r13,r0 + +/* no longer relevant */ +#if 0 +@ 9. Get r5 and exception enable registers off of exception stack and +@ save r5 (stored in r4) back to the system stack. + LDMIA r1!,{r4-r5} + STMDB r13!,{r4} + MOV r4,r5 @ Put exception enable value into r4 +#endif + +@ 10. Get the rest of the registers off the exception stack and +@ save them onto the system stack. + LDMIA r1!,{r5-r8,r11} @ Get r0-r4 off exception stack + STMDB r13!,{r5-r8,r11} @ Put r0-r4 on system stack + +/* no longer relevant */ +#if 0 +@ 11. Store the exception enable value back on the exception stack. + STMDB r1,{r4} +#endif + +@ 12. Save the SPSR on the system stack (CPSR) + STMDB r13!,{r3} + +@ 13. Save stack type to the task stack (1=interrupt stack) + MOV r1,#1 @ Interrupt stack type + STMDB r13!,{r1} + + @ Save the thread's stack pointer in the control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + STR r13,[r3, #TC_STACK_POINTER] @ Save stack pointer + + @ Switch to the system stack. +@ REG_Stack_Ptr = TCD_System_Stack + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r3,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r3, #0] @ Setup system stack limit + +/* TI's approach to interrupt handling does not support re-enabling here */ +#if 0 + @ Re-enable interrupts + MRS r1,CPSR + BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) + MSR CPSR,r1 +#endif + +@ Return to caller ISR. + + BX r2 @ Return to caller ISR + +@ } + +TCT_Idle_Context_Save: + + MOV r2,r14 @ Save r14 in r2 +@ LDR r3,[r13] @ Get exception enable value from stack + ADD r13,r13,#20 @ Adjust exception r13 for future interrupts +@ STR r3,[r13] @ Put exception enable value back on stack + + MRS r1,CPSR @ Pickup current CPSR + BIC r1,r1,#MODE_MASK @ Clear the current mode +@ BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) @ Re-enable interrupts + + ORR r1,r1,#SUP_MODE @ Prepare to switch to supervisor + @ mode (SVC) + MSR CPSR,r1 @ Switch to supervisor mode (SVC) + + BX r2 @ Return to caller ISR + +@ } +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Interrupt_Context_Restore + * + * DESCRIPTION + * + * This function restores the interrupt context if a nested + * interrupt condition is present. Otherwise, this routine + * transfers control to the scheduling function. + * + * CALLED BY + * + * Application ISRs Assembly language ISRs + * INT_Interrupt_Shell Interrupt handler shell + * + * CALLS + * + * TCT_Schedule Thread scheduling function + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * D. Driscoll 01-04-2002 Released version 1.13.3. + * Updated to handle nested / + * prioritized IRQs + * + ************************************************************************ + */ + +@VOID TCT_Interrupt_Context_Restore(void) +@{ + + .globl TCT_Interrupt_Context_Restore +TCT_Interrupt_Context_Restore: + @ It is assumed that anything pushed on the stack by ISRs has been + @ removed upon entry into this routine. + + @ Decrement and check for nested interrupt conditions. +@ if (--TCD_Interrupt_Count) +@ { + + LDR r1,Int_Count @ Pickup address of interrupt count + LDR r2,[r1, #0] @ Pickup interrupt counter + SUB r2,r2,#1 @ Decrement interrupt counter + STR r2,[r1, #0] @ Store interrupt counter + CMP r2,#0 + BEQ TCT_Not_Nested_Restore + + @ Restore previous context. + + LDR r1,[r13], #4 @ Pickup the saved CPSR + + MSR SPSR,r1 @ Place into saved SPSR + LDMIA r13,{r0-r15}^ @ Return to the point of interrupt + +@ } +@ else +@ { + +TCT_Not_Nested_Restore: + + @ Determine if a thread is active. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r0,[r1, #0] @ Pickup current thread pointer + CMP r0,#0 @ Determine if a thread is active + BEQ TCT_Idle_Context_Restore @ If not, idle system restore + + @ Clear the current thread pointer. +@ TCD_Current_Thread = NU_NULL + + MOV r2,#0 @ Build NU_NULL value + STR r2,[r1, #0] @ Set current thread ptr to NU_NULL + + @ Determine if a time slice is active. If so, the remaining + @ time left on the time slice must be saved in the task's + @ control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r3,Slice_State @ Pickup time slice state address + LDR r1,[r3, #0] @ Pickup time slice state + CMP r1,#0 @ Determine if time slice active + BNE TCT_Idle_Context_Restore @ If not, skip time slice reset + + @ Pickup the remaining portion of the time slice and save it + @ in the task's control block. +@ REG_Thread_Ptr -> tc_cur_time_slice = TMD_Time_Slice +@ TMD_Time_Slice_State = 1 + + LDR r2,Time_Slice @ Pickup address of time slice left + MOV r1,#1 @ Build disable time slice value + LDR r2,[r2, #0] @ Pickup remaining time slice + STR r1,[r3, #0] @ Disable time slice + STR r2,[r0, #TC_CUR_TIME_SLICE] @ Store remaining time slice + +@ } +@ } +TCT_Idle_Context_Restore: + + @ Reset the system stack pointer. + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Return to scheduler. + + B TCT_Schedule @ Return to scheduling loop + +@ } +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Activate_HISR + * + * DESCRIPTION + * + * This function activates the specified HISR. If the HISR is + * already activated, the HISR's activation count is simply + * incremented. Otherwise, the HISR is placed on the appropriate + * HISR priority list in preparation for execution. + * + * CALLED BY + * + * Application LISRs + * + * CALLS + * + * None + * + * INPUTS + * + * hisr Pointer to HISR to activate + * + * OUTPUTS + * + * NU_SUCCESS Successful completion + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@STATUS TCT_Activate_HISR(TC_HCB *hisr) +@{ + + .globl TCT_Activate_HISR +TCT_Activate_HISR: + +@INT priority; + + + @ Lockout interrupts. + + STR r4,[r13, #-4]! @ Save r4 + MRS r4,CPSR @ Pickup current CPSR + ORR r1,r4,#LOCKOUT @ Build interrupt lockout value + MSR CPSR,r1 @ Lockout interrupts + + @ Determine if the HISR is already active. +@ if (hisr -> tc_activation_count) +@ { + + LDR r1,[r0,#0x40] @ Pickup current activation count + CMP r1,#0 @ Is it the first activation? + BEQ TCT_First_Activate @ Yes, place it on the correct list + + @ Increment the activation count. Make sure that it does not go + @ to zero. +@ hisr -> tc_activation_count++; + + ADDS r1,r1,#1 @ Increment the activation count + STR r1,[r0,#0x40] @ Store new activation count + +@ if (hisr -> tc_activation_count == 0) + +@ hisr -> tc_activation_count = 0xFFFFFFFFUL; + + MVNEQ r1,#0 @ If counter rolled-over reset + STREQ r1,[r0,#0x40] @ Store all ones count + B TCT_Activate_Done @ Finished with activation +@ } +@ else +@ { +TCT_First_Activate: + + + @ Set the activation count to 1. +@ hisr -> tc_activation_count = 1; + + MOV r1,#1 @ Initial activation count + STR r1,[r0,#0x40] @ Store initial activation count + + @ Pickup the HISR's priority. +@ priority = hisr -> tc_priority; + + @ Determine if there is something in the given priority list. +@ if (TCD_Active_HISR_Tails[priority]) +@ { + + LDRB r1,[r0,#0x1a] @ Pickup priority of HISR + LDR r2,HISR_Tails @ Pickup tail pointer base + LDR r3,[r2,r1,LSL #2] @ Pickup tail pointer for priority + CMP r3,#0 @ Is this first HISR at priority? + BEQ TCT_First_HISR @ No, append to end of HISR list + + @ Something is already on this list. Add after the tail. +@ (TCD_Active_HISR_Tails[priority]) -> tc_active_next = hisr; +@ TCD_Active_HISR_Tails[priority] = hisr; + + STR r0,[r3,#0x3c] @ Setup the active next pointer + STR r0,[r2,r1,LSL #2] @ Setup the tail pointer + B TCT_Activate_Done @ Finished with activate processing +@ } +@ else +@ { +TCT_First_HISR: + + @ Nothing is on this list. +@ TCD_Active_HISR_Heads[priority] = hisr; +@ TCD_Active_HISR_Tails[priority] = hisr; + + LDR r3,HISR_Heads @ Pickup address of head pointers + STR r0,[r2,r1,LSL #2] @ Set tail pointer to this HISR + STR r0,[r3,r1,LSL #2] @ Set head pointer to this HISR + + @ Determine the highest priority HISR. +@ if (TCD_Active_HISR_Heads[0]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[0]; +@ else if (TCD_Active_HISR_Heads[1]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[1]; +@ else +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[2]; + + LDR r1,[r3,#0] @ Pickup priority 0 head pointer + LDR r0,Execute_HISR @ Build address to execute HISR ptr + CMP r1,#0 @ Is priority 0 active? + LDREQ r1,[r3,#4] @ If not, pickup priority 1 head + CMPEQ r1,#0 @ Is priority 1 active? + LDREQ r1,[r3,#8] @ Else, must be priority 2 active + STR r1,[r0,#0] @ Store which ever priority is the + @ active one +@ } +@ } +TCT_Activate_Done: + + MSR CPSR,r4 @ Restore interrupt lockout + LDR r4,[r13], #4 @ Restore corrupted r4 + +@ return(NU_SUCCESS); + + MOV r0,#0 @ Always return NU_SUCCESS + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_HISR_Shell + * + * DESCRIPTION + * + * This function is the execution shell of each and every HISR. If + * the HISR has completed its processing, this shell routine exits + * back to the system. Otherwise, it sequentially calls the HISR + * routine until the activation count goes to zero. + * + * CALLED BY + * + * HISR Scheduling + * + * CALLS + * + * hisr -> tc_entry Actual entry function of HISR + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_HISR_Shell(void) +@{ + .globl TCT_HISR_Shell +TCT_HISR_Shell: + + @ Point at the HISR. +@ REG_HISR_Ptr = (TC_HCB *) TCD_Current_Thread; + + LDR r0,Current_Thread @ Build address of thread pointer + LDR r5,[r0, #0] @ Pickup control block pointer + +@ do +@ { +TCT_HISR_Loop: + + @ Call the HISR's entry routine. +@ (*(REG_HISR_Ptr -> tc_entry)) (); + +/* old TMS470 code: + + .if THUMB = 0 + + MOV r14,r15 ; Setup return value + LDR r15,[r5,#44h] ; Call HISR entry function + .else + LDR r4,[r5,#44h] ; Get HISR entry function + TST r4,#1 ; See if calling Thumb or ARM + BNE Thumbsec + MOV r14,r15 ; Setup return value + BX r4 + B ARMCODE +Thumbsec: + ADD r14, r15, #1 + BX r4 + .state16 +ThumbAfterHisr + MOV r1, r15 + BX r1 + .state32 + .endif +*/ + + /* new code for the GNU style of ARM/Thumb interworking */ + ldr r4, [r5, #TC_HISR_ENTRY] + mov lr, pc + bx r4 + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Build interrupt lockout + MSR CPSR,r1 @ Lockout interrupts + + @ On return, decrement the activation count and check to see if + @ it is 0. Once it reaches 0, the HISR should be made inactive. +@ REG_HISR_Ptr -> tc_activation_count--; + + + LDR r0,[r5, #0x40] @ Pickup current activation count + SUBS r0,r0,#1 @ Subtract and set condition codes + STR r0,[r5, #0x40] @ Store new activation count + BEQ TCT_HISR_Finished @ Finished processing HISR + + @ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + B TCT_HISR_Loop @ Return to HISR loop +@ } +@ while (REG_HISR_Ptr -> tc_activation_count); + +TCT_HISR_Finished: + + @ At this point, the HISR needs to be made inactive. + + @ Determine if this is the only HISR on the given priority list. +@ if (REG_HISR_Ptr == TCD_Active_HISR_Tails[REG_HISR_Ptr -> tc_priority]) +@ { + + LDR r14,HISR_Tails @ Pickup tail pointers address + LDRB r3,[r5,#0x1a] @ Pickup priority + LDR r6,[r14,r3,LSL #2] @ Pickup this priority tail pointer + LDR r2,Execute_HISR @ Build address to execute HISR ptr + MOV r12,#0 @ Clear r12 + LDR r1,HISR_Heads @ Pickup head pointers address + CMP r6,r5 @ Is this priority tail the same as + @ the current HISR? + BNE TCT_More_HISRs @ If not, more HISRs at this + @ priority + + @ The only HISR on the list. Clean up the list and check for the + @ highest priority HISR. +@ TCD_Active_HISR_Heads[REG_HISR_Ptr -> tc_priority] = NU_NULL; +@ TCD_Active_HISR_Tails[REG_HISR_Ptr -> tc_priority] = NU_NULL; + + STR r12,[r1,r3,LSL #2] @ Set head pointer to NU_NULL + STR r12,[r14,r3,LSL #2] @ Set tail pointer to NU_NULL + + @ Determine the highest priority HISR. +@ if (TCD_Active_HISR_Heads[0]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[0]; +@ else if (TCD_Active_HISR_Heads[1]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[1]; +@ else +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[2]; + + LDR r3,[r1,#0] @ Pickup priority 0 head pointer + CMP r3,#0 @ Is there an HISR active? + LDREQ r3,[r1,#4] @ If not, pickup priority 1 pointer + CMPEQ r3,#0 @ Is there an HISR active? + LDREQ r3,[r1,#8] @ If not, pickup priority 2 pointer + STR r3,[r2,#0] @ Setup execute HISR pointer + B TCT_HISR_Exit @ Exit HISR processing +@ } +@ else +@ { + +TCT_More_HISRs: + + @ Move the head pointer to the next HISR in the list. +@ TCD_Active_HISR_Heads[REG_HISR_Ptr -> tc_priority] = +@ REG_HISR_Ptr -> tc_active_next; + + @ Also set the TCD_Execute_HISR pointer. +@ TCD_Execute_HISR = REG_HISR_Ptr -> tc_active_next; + + LDR r14,[r5,#0x3c] @ Pickup next HISR to activate + STR r14,[r1,r3,LSL #2] @ Setup new head pointer + STR r14,[r2, #0] @ Setup execute HISR pointer +@ } + +TCT_HISR_Exit: + + @ Build fake return to the top of this loop. The next time the HISR + @ is activated, it will return to the top of this function. + + LDR r14,HISR_Shell @ Pickup address of shell entry + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value +#if 1 /* was .if THUMB */ + STR r2,[r13, #-4]! @ Save state mask +#endif + STR r2,[r13, #-4]! @ Place it on the top of the stack + + @ Clear the current thread control block. +@ TCD_Current_Thread = NU_NULL; + + LDR r1,Current_Thread @ Pickup current thread ptr address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + + @ Save off the current stack pointer in the control block. +@ REG_HISR_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + + STR r13,[r5, #0x2c] @ Save the thread's stack pointer + + + @ Switch to the system stack. +@ REG_Stack_Ptr = (BYTE_PTR) TCD_System_Stack; + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Transfer control to the main scheduling loop. + + B TCT_Schedule @ Return to main scheduling loop +@} + +/* FreeCalypso addition, used by riviera/rvf/rvf_task.c: */ + .globl INT_Check_IRQ_Mask +INT_Check_IRQ_Mask: + MRS r0,CPSR + BX lr +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/debug-chases/tms.c.dbg Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,637 @@ +/*************************************************************************/ +/* */ +/* Copyright Mentor Graphics Corporation 2002 */ +/* All Rights Reserved. */ +/* */ +/* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ +/* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ +/* SUBJECT TO LICENSE TERMS. */ +/* */ +/*************************************************************************/ + +/*************************************************************************/ +/* */ +/* FILE NAME VERSION */ +/* */ +/* tms.c Nucleus PLUS 1.14 */ +/* */ +/* COMPONENT */ +/* */ +/* TM - Timer Management */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains supplemental routines for the timer */ +/* management component. */ +/* */ +/* DATA STRUCTURES */ +/* */ +/* None */ +/* */ +/* FUNCTIONS */ +/* */ +/* TMS_Create_Timer Create an application timer */ +/* TMS_Delete_Timer Delete an application timer */ +/* TMS_Reset_Timer Reset application timer */ +/* TMS_Control_Timer Enable/Disable application */ +/* timer */ +/* */ +/* DEPENDENCIES */ +/* */ +/* cs_extr.h Common Service functions */ +/* tc_extr.h Thread Control functions */ +/* tm_extr.h Timer functions */ +/* hi_extr.h History functions */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1994 Created initial version 1.1 from */ +/* previous version of TMC.C */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* 04-17-1996 updated to version 1.2 */ +/* 03-24-1998 Released version 1.3. */ +/* 03-26-1999 Released 1.11m (new release */ +/* numbering scheme) */ +/* 04-17-2002 Released version 1.13m */ +/* 11-07-2002 Released version 1.14 */ +/*************************************************************************/ +#define NU_SOURCE_FILE + + +#include "cs_extr.h" /* Common service functions */ +#include "tc_extr.h" /* Thread control functions */ +#include "tm_extr.h" /* Timer functions */ +#include "hi_extr.h" /* History functions */ +#include "profiler.h" /* ProView interface */ + + +/* Define external inner-component global data references. */ + +extern CS_NODE *TMD_Created_Timers_List; +extern UNSIGNED TMD_Total_Timers; +extern TM_TCB *TMD_Active_Timers_List; +extern INT TMD_Active_List_Busy; +extern TC_PROTECT TMD_Created_List_Protect; + + +/* Define internal function prototypes. */ + +VOID TMC_Start_Timer(TM_TCB *timer, UNSIGNED time); +VOID TMC_Stop_Timer(TM_TCB *timer); + + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMS_Create_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an application timer and places it on the */ +/* list of created timers. The timer is activated if designated by */ +/* the enable parameter. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* TMSE_Create_Timer Error checking shell */ +/* */ +/* CALLS */ +/* */ +/* CSC_Place_On_List Add node to linked-list */ +/* [HIC_Make_History_Entry] Make entry in history log */ +/* [TCT_Check_Stack] Stack checking function */ +/* TCT_Protect Data structure protect */ +/* TCT_Unprotect Un-protect data structure */ +/* TMS_Control_Timer Enable the new timer */ +/* */ +/* INPUTS */ +/* */ +/* timer_ptr Timer control block pointer */ +/* name Timer name */ +/* expiration_routine Timer expiration routine */ +/* id Timer expiration ID */ +/* initial_time Initial expiration time */ +/* reschedule_time Reschedule expiration time */ +/* enable Automatic enable option */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_SUCCESS */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Changed function prototype, */ +/* resulting in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMS_Create_Timer(NU_TIMER *timer_ptr, CHAR *name, + VOID (*expiration_routine)(UNSIGNED), UNSIGNED id, + UNSIGNED initial_time, UNSIGNED reschedule_time, OPTION enable) +{ + +R1 TM_APP_TCB *timer; /* Timer control block ptr */ +INT i; /* Working index variable */ +NU_SUPERV_USER_VARIABLES + + /* Switch to supervisor mode */ + NU_SUPERVISOR_MODE(); + + /* Move input timer pointer into internal pointer. */ + timer = (TM_APP_TCB *) timer_ptr; + + +#ifdef NU_ENABLE_STACK_CHECK + + /* Call stack checking function to check for an overflow condition. */ + TCT_Check_Stack(); + +#endif + +#ifdef NU_ENABLE_HISTORY + + /* Make an entry that corresponds to this function in the system history + log. */ + HIC_Make_History_Entry(NU_CREATE_TIMER_ID, (UNSIGNED) timer, + (UNSIGNED) name, (UNSIGNED) expiration_routine); + +#endif + + /* First, clear the timer ID just in case it is an old Timer + Control Block. */ + timer -> tm_id = 0; + + /* Fill in the timer name. */ + for (i = 0; i < NU_MAX_NAME; i++) + timer -> tm_name[i] = name[i]; + + /* Load the timer with the appropriate values. */ + timer -> tm_expiration_routine = expiration_routine; + timer -> tm_expiration_id = id; + timer -> tm_expirations = 0; + timer -> tm_initial_time = initial_time; + timer -> tm_reschedule_time = reschedule_time; + timer -> tm_actual_timer.tm_timer_type = TM_APPL_TIMER; + timer -> tm_enabled = NU_FALSE; + + /* Initialize link pointers. */ + timer -> tm_created.cs_previous = NU_NULL; + timer -> tm_created.cs_next = NU_NULL; + timer -> tm_actual_timer.tm_next_timer = NU_NULL; + timer -> tm_actual_timer.tm_previous_timer= NU_NULL; + timer -> tm_actual_timer.tm_information = (VOID *) timer; + + /* Protect against access to the list of created timers. */ + TCT_Protect(&TMD_Created_List_Protect); + + /* At this point the timer is completely built. The ID can now be + set and it can be linked into the created timer list. */ + timer -> tm_id = TM_TIMER_ID; + + /* Link the timer into the list of created timers and increment the + total number of timers in the system. */ + CSC_Place_On_List(&TMD_Created_Timers_List, &(timer -> tm_created)); + TMD_Total_Timers++; + +#ifdef INCLUDE_PROVIEW + _RTProf_DumpTimer(RT_PROF_CREATE_TIMER,timer,RT_PROF_OK); +#endif + + /* Release protection against access to the list of created timers. */ + TCT_Unprotect(); + + /* Determine if the timer should be enabled. */ + if (enable == NU_ENABLE_TIMER) + + /* Activate the timer. */ + TMS_Control_Timer(timer_ptr, NU_ENABLE_TIMER); + + /* Return to user mode */ + NU_USER_MODE(); + + /* Return successful completion. */ + return(NU_SUCCESS); +} + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMS_Delete_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes an application timer and removes it from */ +/* the list of created timers. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* TMSE_Delete_Timer Error checking shell */ +/* */ +/* CALLS */ +/* */ +/* CSC_Remove_From_List Remove node from list */ +/* [HIC_Make_History_Entry] Make entry in history log */ +/* [TCT_Check_Stack] Stack checking function */ +/* TCT_Protect Protect created list */ +/* TCT_System_Protect Protect active list */ +/* TCT_Unprotect Release protection */ +/* */ +/* INPUTS */ +/* */ +/* timer_ptr Timer control block pointer */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_NOT_DISABLED Timer not disabled first */ +/* NU_SUCCESS */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Modified protection logic to use */ +/* system protection, changed */ +/* function prototype, resulting */ +/* in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMS_Delete_Timer(NU_TIMER *timer_ptr) +{ + +TM_APP_TCB *timer; /* Timer control block ptr */ +STATUS status; /* Completion status */ +NU_SUPERV_USER_VARIABLES + + /* Switch to supervisor mode */ + NU_SUPERVISOR_MODE(); + + /* Move input timer pointer into internal pointer. */ + timer = (TM_APP_TCB *) timer_ptr; + + +#ifdef NU_ENABLE_STACK_CHECK + + /* Call stack checking function to check for an overflow condition. */ + TCT_Check_Stack(); + +#endif + +#ifdef NU_ENABLE_HISTORY + + /* Make an entry that corresponds to this function in the system history + log. */ + HIC_Make_History_Entry(NU_DELETE_TIMER_ID, (UNSIGNED) timer, + (UNSIGNED) 0, (UNSIGNED) 0); + +#endif + + /* Initialize the status. */ + status = NU_SUCCESS; + + /* Use system protect to protect the active timer list temporarily. */ + TCT_System_Protect(); + + /* Determine if the timer is currently disabled. */ + if (timer -> tm_enabled) + { + /* Error, indicate to the caller that the timer is currently active. */ + status = NU_NOT_DISABLED; + +#ifdef INCLUDE_PROVIEW + _RTProf_DumpTimer(RT_PROF_DELETE_TIMER,timer,RT_PROF_FAIL); +#endif + + } + else + { + /* Clear the timer ID. */ + timer -> tm_id = 0; + +#ifdef INCLUDE_PROVIEW + _RTProf_DumpTimer(RT_PROF_DELETE_TIMER,timer,RT_PROF_OK); +#endif /* INCLUDE_PROVIEW */ + + } + + /* Release protection. */ + TCT_Unprotect(); + + /* Determine if an error was detected. */ + if (status == NU_SUCCESS) + { + + /* Protect against access to the list of created timers. */ + TCT_Protect(&TMD_Created_List_Protect); + + /* Remove the timer from the list of created timers. */ + CSC_Remove_From_List(&TMD_Created_Timers_List, &(timer -> tm_created)); + + /* Decrement the total number of created timers. */ + TMD_Total_Timers--; + + /* Release protection against access to the list of created timers. */ + TCT_Unprotect(); + } + + /* Return to user mode */ + NU_USER_MODE(); + + /* Return completion status. */ + return(status); +} + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMS_Reset_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resets the specified application timer. Note that */ +/* the timer must be in a disabled state prior to this call. The */ +/* timer is activated after it is reset if the enable parameter */ +/* specifies automatic activation. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* TMSE_Reset_Timer Error checking shell */ +/* */ +/* CALLS */ +/* */ +/* [HIC_Make_History_Entry] Make entry in history log */ +/* [TCT_Check_Stack] Stack checking function */ +/* TCT_System_Protect Protect active list */ +/* TCT_Unprotect Release protection */ +/* TMS_Control_Timer Enable/disable timer */ +/* */ +/* INPUTS */ +/* */ +/* timer_ptr Timer control block pointer */ +/* expiration_routine Timer expiration routine */ +/* initial_time Initial expiration time */ +/* reschedule_time Reschedule expiration time */ +/* enable Automatic enable option */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_NOT_DISABLED Timer not disabled first */ +/* NU_SUCCESS Successful completion */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Modified protection logic to use */ +/* system protection, changed */ +/* function prototype, resulting */ +/* in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMS_Reset_Timer(NU_TIMER *timer_ptr, + VOID (*expiration_routine)(UNSIGNED), + UNSIGNED initial_time, UNSIGNED reschedule_time, OPTION enable) +{ + +R1 TM_APP_TCB *timer; /* Timer control block ptr */ +STATUS status; /* Completion status */ +NU_SUPERV_USER_VARIABLES +static char dbgstr[512]; + + sprintf(dbgstr, "* TMS_Reset_Timer(): timer_ptr=%08x, expiration_routine=%08x, initial_time=%x, reschedule_time=%x, enable=%x", + (unsigned)timer_ptr, (unsigned)expiration_routine, + (unsigned)initial_time, (unsigned)reschedule_time, + (unsigned)enable); + freecalypso_raw_dbgout(dbgstr); + + /* Switch to supervisor mode */ + NU_SUPERVISOR_MODE(); + + /* Move input timer pointer into internal pointer. */ + timer = (TM_APP_TCB *) timer_ptr; + + +#ifdef NU_ENABLE_STACK_CHECK + + /* Call stack checking function to check for an overflow condition. */ + TCT_Check_Stack(); + +#endif + +#ifdef NU_ENABLE_HISTORY + + /* Make an entry that corresponds to this function in the system history + log. */ + HIC_Make_History_Entry(NU_RESET_TIMER_ID, (UNSIGNED) timer, + (UNSIGNED) expiration_routine, (UNSIGNED) initial_time); + +#endif + + /* Protect against access to the active timer list. */ + TCT_System_Protect(); + + /* Determine if this timer is active. An active timer cannot be + reset. */ + if (timer -> tm_enabled) + { + + /* Indicate that the timer is active by returning the proper status. */ + status = NU_NOT_DISABLED; + +#ifdef INCLUDE_PROVIEW + _RTProf_DumpTimer(RT_PROF_RESET_TIMER,timer,RT_PROF_FAIL); +#endif /* INCLUDE_PROVIEW */ + + } + else + { + + /* Load the timer with the appropriate values. */ + timer -> tm_expiration_routine = expiration_routine; + timer -> tm_expirations = 0; + timer -> tm_initial_time = initial_time; + timer -> tm_reschedule_time = reschedule_time; + + /* Indicate successful completion status. */ + status = NU_SUCCESS; +#ifdef INCLUDE_PROVIEW + _RTProf_DumpTimer(RT_PROF_RESET_TIMER,timer,RT_PROF_OK); +#endif /* INCLUDE_PROVIEW */ + + } + + /* Release protection. */ + TCT_Unprotect(); + + /* Determine if the timer needs to be enabled. */ + if ((status == NU_SUCCESS) && (enable == NU_ENABLE_TIMER)) + + /* Activate the timer. */ + TMS_Control_Timer(timer_ptr, NU_ENABLE_TIMER); + + /* Return to user mode */ + NU_USER_MODE(); + + /* Return completion status. */ + return(status); +} + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMS_Control_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function either enables or disables the specified timer. */ +/* If the timer is already in the desired state, simply leave it */ +/* alone. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* TMSE_Control_Timer Error checking shell */ +/* */ +/* CALLS */ +/* */ +/* [HIC_Make_History_Entry] Make entry in history log */ +/* [TCT_Check_Stack] Stack checking function */ +/* TCT_System_Protect Protect the active list */ +/* TCT_Unprotect Release protection */ +/* TMC_Start_Timer Start a timer */ +/* TMC_Stop_Timer Stop a timer */ +/* */ +/* INPUTS */ +/* */ +/* app_timer Timer control block pointer */ +/* enable Disable/enable timer option */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_SUCCESS If service is successful */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Modified protection logic to use */ +/* system protection, changed */ +/* function prototype, resulting */ +/* in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMS_Control_Timer(NU_TIMER *app_timer, OPTION enable) +{ + +R1 TM_APP_TCB *timer; /* Timer control block ptr */ +TM_TCB *timer_ptr; /* Actual timer pointer */ +UNSIGNED time; /* Variable to hold request */ +NU_SUPERV_USER_VARIABLES + + /* Switch to supervisor mode */ + NU_SUPERVISOR_MODE(); + + /* Move input timer pointer into internal pointer. */ + timer = (TM_APP_TCB *) app_timer; + + +#ifdef NU_ENABLE_STACK_CHECK + + /* Call stack checking function to check for an overflow condition. */ + TCT_Check_Stack(); + +#endif + +#ifdef NU_ENABLE_HISTORY + + /* Make an entry that corresponds to this function in the system history + log. */ + HIC_Make_History_Entry(NU_CONTROL_TIMER_ID, (UNSIGNED) timer, + (UNSIGNED) enable, (UNSIGNED) 0); + +#endif + + /* Protect against simultaneous access to the active timer list. */ + TCT_System_Protect(); + + /* Setup pointer to actual timer part of the control block. */ + timer_ptr = &(timer -> tm_actual_timer); + + /* Determine what type of request is present. */ + if ((enable == NU_ENABLE_TIMER) && (!timer -> tm_enabled)) + { + + /* Enable timer request is present and timer is currently disabled. */ + + /* Determine how to setup the remaining field in the actual timer. */ + if (timer -> tm_expirations) + + /* Use reschedule time since this timer has expired previously. */ + time = timer -> tm_reschedule_time; + else + + /* Use initial time since this timer has never expired. */ + time = timer -> tm_initial_time; + + /* Mark the application timer as enabled. */ + timer -> tm_enabled = NU_TRUE; + + /* Call the start timer routine to actually start the timer. */ + TMC_Start_Timer(&(timer -> tm_actual_timer), time); + } + else if ((enable == NU_DISABLE_TIMER) && (timer -> tm_enabled)) + { + + /* Disable timer request is present and timer is currently enabled. */ + TMC_Stop_Timer(timer_ptr); + + /* Mark the timer as disabled. */ + timer -> tm_enabled = NU_FALSE; + } + +#ifdef INCLUDE_PROVIEW + _RTProf_DumpTimer(RT_PROF_CONTROL_TIMER,timer,RT_PROF_OK); +#endif /* INCLUDE_PROVIEW */ + /* Release protection. */ + TCT_Unprotect(); + + /* Return to user mode */ + NU_USER_MODE(); + + /* Return the completion status. */ + return(NU_SUCCESS); +} + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/debug-chases/tmse.c.dbg Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,427 @@ +/*************************************************************************/ +/* */ +/* Copyright Mentor Graphics Corporation 2002 */ +/* All Rights Reserved. */ +/* */ +/* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ +/* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ +/* SUBJECT TO LICENSE TERMS. */ +/* */ +/*************************************************************************/ + +/*************************************************************************/ +/* */ +/* FILE NAME VERSION */ +/* */ +/* tmse.c Nucleus PLUS 1.14 */ +/* */ +/* COMPONENT */ +/* */ +/* TM - Timer Management */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains the error checking routines for the functions */ +/* in the Timer component. This permits easy removal of error */ +/* checking logic when it is not needed. */ +/* */ +/* DATA STRUCTURES */ +/* */ +/* None */ +/* */ +/* FUNCTIONS */ +/* */ +/* TMSE_Create_Timer Create an application timer */ +/* TMSE_Delete_Timer Delete an application timer */ +/* TMSE_Reset_Timer Reset application timer */ +/* TMSE_Control_Timer Enable/Disable application */ +/* timer */ +/* */ +/* DEPENDENCIES */ +/* */ +/* cs_extr.h Common Service functions */ +/* tm_extr.h Timer functions */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Changed names of error checking */ +/* shell to match new conventions, */ +/* resulting in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* 04-17-1996 updated to version 1.2 */ +/* 03-24-1998 Released version 1.3 */ +/* 04-17-2002 Released version 1.13m */ +/* 11-07-2002 Released version 1.14 */ +/*************************************************************************/ +#define NU_SOURCE_FILE + + +#include "cs_extr.h" /* Common service functions */ +#include "tm_extr.h" /* Timer functions */ + + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMSE_Create_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the parameters supplied */ +/* to the create timer function. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* CALLS */ +/* */ +/* TMS_Create_Timer Actual create timer function */ +/* */ +/* INPUTS */ +/* */ +/* timer_ptr Timer control block pointer */ +/* name Timer name */ +/* expiration_routine Timer expiration routine */ +/* id Timer expiration ID */ +/* initial_time Initial expiration time */ +/* reschedule_time Reschedule expiration time */ +/* enable Automatic enable option */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_INVALID_TIMER Indicates timer pointer is */ +/* NULL */ +/* NU_INVALID_FUNCTION Indicates timer expiration */ +/* function pointer is NULL */ +/* NU_INVALID_ENABLE Indicates enable parameter */ +/* is invalid */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Changed function interface, */ +/* resulting in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMSE_Create_Timer(NU_TIMER *timer_ptr, CHAR *name, + VOID (*expiration_routine)(UNSIGNED), UNSIGNED id, + UNSIGNED initial_time, UNSIGNED reschedule_time, OPTION enable) +{ + +TM_APP_TCB *timer; /* Timer control block ptr */ +STATUS status; /* Completion status */ + + + /* Move input timer pointer into internal pointer. */ + timer = (TM_APP_TCB *) timer_ptr; + + /* Check the parameters to the create timer function. */ + if ((timer == NU_NULL) || (timer -> tm_id == TM_TIMER_ID)) + + /* Invalid timer pointer. */ + status = NU_INVALID_TIMER; + + else if (expiration_routine == NU_NULL) + + /* Invalid expiration function pointer. */ + status = NU_INVALID_FUNCTION; + + else if (initial_time == 0) + + /* Invalid time value. */ + status = NU_INVALID_OPERATION; + + + else if ((enable != NU_ENABLE_TIMER) && (enable != NU_DISABLE_TIMER)) + + /* Invalid enable parameter. */ + status = NU_INVALID_ENABLE; + + else + + /* Call the actual create timer function. */ + status = TMS_Create_Timer(timer_ptr, name, expiration_routine, id, + initial_time, reschedule_time, enable); + + /* Return the completion status. */ + return(status); +} + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMSE_Delete_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the parameters supplied */ +/* to the delete timer function. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* CALLS */ +/* */ +/* TMS_Delete_Timer Actual delete timer function */ +/* */ +/* INPUTS */ +/* */ +/* timer_ptr Timer control block pointer */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_INVALID_TIMER Indicates the timer pointer */ +/* is NULL or not a timer */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Changed function interface, */ +/* resulting in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMSE_Delete_Timer(NU_TIMER *timer_ptr) +{ + +TM_APP_TCB *timer; /* Timer control block ptr */ +STATUS status; /* Completion status */ + + + /* Move input timer pointer into internal pointer. */ + timer = (TM_APP_TCB *) timer_ptr; + + /* Check the parameters to the delete timer function. */ + if (timer == NU_NULL) + + /* Invalid timer pointer. */ + status = NU_INVALID_TIMER; + + else if (timer -> tm_id != TM_TIMER_ID) + + /* Invalid timer pointer. */ + status = NU_INVALID_TIMER; + + else + + /* Call the actual delete timer function. */ + status = TMS_Delete_Timer(timer_ptr); + + /* Return completion status. */ + return(status); +} + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMSE_Reset_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the parameters supplied */ +/* to the reset timer function. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* CALLS */ +/* */ +/* TMS_Reset_Timer Actual reset timer function */ +/* */ +/* INPUTS */ +/* */ +/* timer_ptr Timer control block pointer */ +/* expiration_routine Timer expiration routine */ +/* initial_time Initial expiration time */ +/* reschedule_time Reschedule expiration time */ +/* enable Automatic enable option */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_INVALID_TIMER Indicates timer pointer is */ +/* invalid */ +/* NU_INVALID_FUNCTION Indicates that expiration */ +/* function pointer is NULL */ +/* NU_INVALID_ENABLE Indicates enable parameter */ +/* is invalid */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Changed function interface, */ +/* resulting in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMSE_Reset_Timer(NU_TIMER *timer_ptr, + VOID (*expiration_routine)(UNSIGNED), + UNSIGNED initial_time, UNSIGNED reschedule_time, OPTION enable) +{ + +TM_APP_TCB *timer; /* Timer contorl block ptr */ +STATUS status; /* Completion status */ +static char dbgstr[512]; + + sprintf(dbgstr, "* TMSE_Reset_Timer(): timer_ptr=%08x, expiration_routine=%08x, initial_time=%x, reschedule_time=%x, enable=%x", + (unsigned)timer_ptr, (unsigned)expiration_routine, + (unsigned)initial_time, (unsigned)reschedule_time, + (unsigned)enable); + freecalypso_raw_dbgout(dbgstr); + + /* Move input timer pointer into internal pointer. */ + timer = (TM_APP_TCB *) timer_ptr; + + /* Check the parameters to the reset timer function. */ + if (timer == NU_NULL) + + /* Invalid timer pointer. */ + status = NU_INVALID_TIMER; + + else if (timer -> tm_id != TM_TIMER_ID) { + + sprintf(dbgstr, "* TMSE_Reset_Timer: invalid tm_id=%08x", + (unsigned)timer->tm_id); + freecalypso_raw_dbgout(dbgstr); + + /* Invalid timer pointer. */ + status = NU_INVALID_TIMER; + } + else if (initial_time == 0) + + /* Invalid time value. */ + status = NU_INVALID_OPERATION; + + + else if (expiration_routine == NU_NULL) + + /* Invalid expiration function pointer. */ + status = NU_INVALID_FUNCTION; + + else if ((enable != NU_ENABLE_TIMER) && (enable != NU_DISABLE_TIMER)) + + /* Invalid enable parameter. */ + status = NU_INVALID_ENABLE; + + else + + /* Call the actual reset timer function. */ + status = TMS_Reset_Timer(timer_ptr, expiration_routine, initial_time, + reschedule_time, enable); + + sprintf(dbgstr, "* TMSE_Reset_Timer result: %d", (int)status); + freecalypso_raw_dbgout(dbgstr); + + /* Return completion status. */ + return(status); +} + + +/*************************************************************************/ +/* */ +/* FUNCTION */ +/* */ +/* TMSE_Control_Timer */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the parameters supplied */ +/* to the control timer function. */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* CALLS */ +/* */ +/* TMS_Control_Timer Actual control timer function*/ +/* */ +/* INPUTS */ +/* */ +/* timer_ptr Timer control block pointer */ +/* enable Disable/enable timer option */ +/* */ +/* OUTPUTS */ +/* */ +/* NU_INVALID_TIMER Indicates the timer pointer */ +/* is invalid */ +/* NU_INVALID_ENABLE Indicates enable parameter */ +/* is invalid */ +/* */ +/* HISTORY */ +/* */ +/* DATE REMARKS */ +/* */ +/* 03-01-1993 Created initial version 1.0 */ +/* 04-19-1993 Verified version 1.0 */ +/* 03-01-1994 Changed function interface, */ +/* resulting in version 1.1 */ +/* */ +/* 03-18-1994 Verified version 1.1 */ +/* */ +/*************************************************************************/ +STATUS TMSE_Control_Timer(NU_TIMER *timer_ptr, OPTION enable) +{ + +TM_APP_TCB *timer; /* Timer control block ptr */ +STATUS status; /* Completion status */ + + + /* Move input timer pointer to internal pointer. */ + timer = (TM_APP_TCB *) timer_ptr; + + /* Check the parameters to the reset timer function. */ + if (timer == NU_NULL) + + /* Invalid timer pointer. */ + status = NU_INVALID_TIMER; + + else if (timer -> tm_id != TM_TIMER_ID) + + /* Invalid timer pointer. */ + status = NU_INVALID_TIMER; + + else if ((enable != NU_ENABLE_TIMER) && (enable != NU_DISABLE_TIMER)) + + /* Invalid enable parameter. */ + status = NU_INVALID_ENABLE; + + else + + /* Call actual control timer function. */ + status = TMS_Control_Timer(timer_ptr, enable); + + /* Return completion status. */ + return(status); +} + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/demo/calirq.h Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,95 @@ +/* + * Definitions for Calypso IRQ numbers and the related registers + * Added to the FreeNucleus Calypso port by Spacefalcon the Outlaw. + * + * This header is usable from both .c and .S source files. + */ + +#ifndef _CALYPSO_IRQ_H +#define _CALYPSO_IRQ_H + +#define IRQ_WATCHDOG 0 +#define IRQ_TIMER1 1 +#define IRQ_TIMER2 2 +#define IRQ_TSP_RX 3 +#define IRQ_TPU_FRAME 4 +#define IRQ_TPU_PAGE 5 +#define IRQ_SIMCARD 6 +#define IRQ_UART_MODEM 7 +#define IRQ_KEYPAD_GPIO 8 +#define IRQ_RTC_TIMER 9 +#define IRQ_RTC_ALARM_I2C 10 +#define IRQ_ULPD_GAUGING 11 +#define IRQ_EXTERNAL 12 +#define IRQ_SPI 13 +#define IRQ_DMA 14 +#define IRQ_API 15 +#define IRQ_SIM_DETECT 16 +#define IRQ_EXTERNAL_FIQ 17 +#define IRQ_UART_IRDA 18 +#define IRQ_ULPD_GSM_TIMER 19 +#define IRQ_GEA 20 + +#define MAX_IRQ_NUM 20 + +#define INTH_BASE_ADDR 0xFFFFFA00 + +#ifdef __ASSEMBLER__ + +/* + * Assembly source with cpp + * + * The most convenient way to access registers like these from ARM + * assembly is to load the base address of the register block in some + * ARM register, using only one ldr rN, =xxx instruction and only one + * literal pool entry, and then access various registers in the block + * from the same base using the immediate offset addressing mode. + * + * Here we define the offsets for the usage scenario above. + */ + +#define IT_REG1 0x00 +#define IT_REG2 0x02 +#define MASK_IT_REG1 0x08 +#define MASK_IT_REG2 0x0A +#define IRQ_NUM 0x10 +#define FIQ_NUM 0x12 +#define IRQ_CTRL 0x14 +#define ILR_OFFSET 0x20 + +#else + +/* + * C source + * + * For access from C, we define the layout of the INTH register block + * as a struct, and then define a pleudo-global-var for easy "volatile" + * access. + */ + +struct inth_regs { + unsigned short it_reg1; + unsigned short it_reg2; + unsigned short pad1[2]; + unsigned short mask_it_reg1; + unsigned short mask_it_reg2; + unsigned short pad2[2]; + unsigned short irq_num; + unsigned short fiq_num; + unsigned short irq_ctrl; + unsigned short pad3[5]; + unsigned short ilr_irq[MAX_IRQ_NUM+1]; +}; + +#define INTH_REGS (*(volatile struct inth_regs *) INTH_BASE_ADDR) + +/* + * C code can now access INTH registers like this: + * + * old_mask = INTH_REGS.mask_it_reg1; + * INTH_REGS.mask_it_reg1 = new_mask; + */ + +#endif + +#endif /* _CALYPSO_IRQ_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/demo/caltimer.h Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,59 @@ +/* + * Definitions for Calypso general-purpose timer registers + * Added to the FreeNucleus Calypso port by Spacefalcon the Outlaw. + * + * This header is usable from both .c and .S source files. + */ + +#ifndef _CALYPSO_TIMER_H +#define _CALYPSO_TIMER_H + +#define TIMER1_BASE_ADDR 0xFFFE3800 +#define TIMER2_BASE_ADDR 0xFFFE6800 + +#ifdef __ASSEMBLER__ + +/* + * Assembly source with cpp + * + * The most convenient way to access registers like these from ARM + * assembly is to load the base address of the register block in some + * ARM register, using only one ldr rN, =xxx instruction and only one + * literal pool entry, and then access various registers in the block + * from the same base using the immediate offset addressing mode. + * + * Here we define the offsets for the usage scenario above. + */ + +#define CNTL_TIM 0x00 +#define LOAD_TIM 0x02 +#define READ_TIM 0x04 + +#else + +/* + * C source + * + * For access from C, we define the layout of each timer register block + * as a struct, and then define a pleudo-global-var for easy "volatile" + * access to each of the 2 timers. + */ + +struct timer_regs { + unsigned char cntl; + unsigned char pad; + unsigned short load; + unsigned short read; +}; + +#define TIMER1_REGS (*(volatile struct timer_regs *) TIMER1_BASE_ADDR) +#define TIMER2_REGS (*(volatile struct timer_regs *) TIMER2_BASE_ADDR) + +#endif + +/* CNTL register bit definitions */ +#define CNTL_START 0x01 +#define CNTL_AUTO_RELOAD 0x02 +#define CNTL_CLOCK_ENABLE 0x20 + +#endif /* include guard */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/demo/demo.c Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,530 @@ +/* Include Nucleus C-Library file */ +//#include "ncl\inc\nu_ncl.h" + +/* Include necessary Nucleus PLUS files. */ +#include "nucleus.h" + +/* Define serial output/input functionality. To disable serial I/O, + replace NU_TRUE with NU_FALSE */ + +#define NU_SERIAL_OUTPUT NU_TRUE +#define NU_SERIAL_INPUT NU_TRUE + +#if (NU_SERIAL_OUTPUT) +#include "nu_sd.h" /* Nucleus Serial Driver interface */ +#endif + +/* Define Application data structures. */ + +NU_TASK Task_0; +NU_TASK Task_1; +NU_TASK Task_2; +NU_TASK Task_3; +NU_TASK Task_4; +NU_TASK Task_5; +NU_QUEUE Queue_0; +NU_SEMAPHORE Semaphore_0; +NU_EVENT_GROUP Event_Group_0; +NU_MEMORY_POOL System_Memory; + + +/* Allocate global counters. */ +UNSIGNED Task_Time; +UNSIGNED Task_2_messages_received; +UNSIGNED Task_2_invalid_messages; +UNSIGNED Task_1_messages_sent; +NU_TASK *Who_has_the_resource; +UNSIGNED Event_Detections; + +#if (NU_SERIAL_OUTPUT) +NU_SERIAL_PORT port; +#endif + +#ifdef NU_FIQ_DEMO +UINT32 FIQ_Count; +#endif + +extern UNSIGNED TMD_System_Clock; + +/* Define prototypes for function references. */ +VOID task_0(UNSIGNED argc, VOID *argv); +VOID task_1(UNSIGNED argc, VOID *argv); +VOID task_2(UNSIGNED argc, VOID *argv); +VOID task_3_and_4(UNSIGNED argc, VOID *argv); +VOID task_5(UNSIGNED argc, VOID *argv); +CHAR buffer[12]; /* temp buffer for Itoa conversion */ +INT n; /* strlen */ + + + +/* Define the Application_Initialize routine that determines the initial + Nucleus PLUS application environment. */ + +void Application_Initialize(void *first_available_memory) +{ + +VOID *pointer; +STATUS status; + + /* Create a system memory pool that will be used to allocate task stacks, + queue areas, etc. */ + status = NU_Create_Memory_Pool(&System_Memory, "SYSMEM", + first_available_memory, 25000, 50, NU_FIFO); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create each task in the system. */ + + /* Create task 0. */ + NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); + status = NU_Create_Task(&Task_0, "TASK 0", task_0, 0, NU_NULL, pointer, 2000, 1, 20, + NU_PREEMPT, NU_START); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create task 1. */ + NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); + status = NU_Create_Task(&Task_1, "TASK 1", task_1, 0, NU_NULL, pointer, 2000, 10, 5, + NU_PREEMPT, NU_START); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create task 2. */ + NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); + status = NU_Create_Task(&Task_2, "TASK 2", task_2, 0, NU_NULL, pointer, 2000, 10, 5, + NU_PREEMPT, NU_START); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create task 3. Note that task 4 uses the same instruction area. */ + NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); + status = NU_Create_Task(&Task_3, "TASK 3", task_3_and_4, 0, NU_NULL, pointer, + 2000, 5, 0, NU_PREEMPT, NU_START); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create task 4. Note that task 3 uses the same instruction area. */ + NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); + status = NU_Create_Task(&Task_4, "TASK 4", task_3_and_4, 0, NU_NULL, pointer, + 2000, 5, 0, NU_PREEMPT, NU_START); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create task 5. */ + NU_Allocate_Memory(&System_Memory, &pointer, 2000, NU_NO_SUSPEND); + status = NU_Create_Task(&Task_5, "TASK 5", task_5, 0, NU_NULL, pointer, 2000, 7, 0, + NU_PREEMPT, NU_START); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + + /* Create communication queue. */ + NU_Allocate_Memory(&System_Memory, &pointer, 100*sizeof(UNSIGNED), + NU_NO_SUSPEND); + status = NU_Create_Queue(&Queue_0, "QUEUE 0", pointer, 100, NU_FIXED_SIZE, 1, + NU_FIFO); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create synchronization semaphore. */ + status = NU_Create_Semaphore(&Semaphore_0, "SEM 0", 1, NU_FIFO); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + /* Create event flag group. */ + status = NU_Create_Event_Group(&Event_Group_0, "EVGROUP0"); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + + +} + +/* Define the system timer task. More complicated systems might use a + routine like this to perform periodic message sending and other time + oriented functions. */ + + +void task_0(UNSIGNED argc, VOID *argv) +{ + +STATUS status; + + +#if (NU_SERIAL_OUTPUT) +CHAR msg[40]; +INT i; + +CHAR ch; +#endif /* NU_SERIAL_OUTPUT */ + + +#if (NU_SERIAL_OUTPUT) + /* Init the serial port. */ + port.com_port = DEFAULT_UART_PORT; + port.baud_rate = DEFAULT_UART_BAUD; + port.data_bits = DEFAULT_UART_DATA; + port.stop_bits = DEFAULT_UART_STOP; + port.parity = DEFAULT_UART_PARITY; + port.data_mode = DEFAULT_UART_MODE; + port.communication_mode = SERIAL_MODE; + port.sd_buffer_size = DEFAULT_UART_BUFFER; + + status = NU_SD_Init_Port (&port); + if (status != NU_SUCCESS) + { + ERC_System_Error(status); + } + +#endif /* NU_SERIAL_OUTPUT */ + + + /* Access argc and argv just to avoid compilation warnings. */ + status = (STATUS) argc + (STATUS) argv; + + /* Set the clock to 0. This clock ticks every 18 system timer ticks. */ + Task_Time = 0; + + while(1) + { + + /* Sleep for 100 timer ticks. The value of the tick is programmable + in INT.S and is relative to the speed of the target system. */ + NU_Sleep(100); + +#if (NU_SERIAL_OUTPUT) + NU_SD_Put_String("\n\r****************************************", &port); + NU_SD_Put_String("***************************************\n\r", &port); + NU_SD_Put_String(NU_Release_Information(), &port); + NU_SD_Put_String("\n\r", &port); + + NU_SD_Put_String("****************************************", &port); + NU_SD_Put_String("***************************************\n\n\r", &port); + NU_SD_Put_String("System Variable Status: \n\n\r", &port); + + strcpy(msg, "Task 0 time: "); + sprintf(buffer, "%lu", Task_Time); + n = strlen(buffer); + if (n>=8) + { + strcat(msg, buffer); + strcat(msg, "\n\r"); + } + else + { + for (i=0;i<(8-n);i++) + strcat(msg, " "); + strcat(msg, buffer); + strcat(msg, "\n\r"); + } + + NU_SD_Put_String(msg, &port); + + strcpy(msg, "Event detections: "); + sprintf(buffer, "%lu", Event_Detections); + n = strlen(buffer); + if (n>=8) + { + strcat(msg, buffer); + strcat(msg, "\n\n\n\r"); + } + else + { + for (i=0;i<(8-n);i++) + strcat(msg, " "); + strcat(msg, buffer); + strcat(msg, "\n\n\n\r"); + } + + NU_SD_Put_String(msg, &port); + + strcpy(msg, "Task 1 messages sent: "); + sprintf(buffer, "%lu", Task_1_messages_sent); + n = strlen(buffer); + if (n>=8) + { + strcat(msg, buffer); + strcat(msg, "\n\r"); + } + else + { + for (i=0;i<(8-n);i++) + strcat(msg, " "); + strcat(msg, buffer); + strcat(msg, "\n\r"); + } + + NU_SD_Put_String(msg, &port); + + strcpy(msg, "Task 2 messages received: "); + sprintf(buffer, "%lu", Task_2_messages_received); + n = strlen(buffer); + if (n>=8) + { + strcat(msg, buffer); + strcat(msg, "\n\n\r"); + } + else + { + for (i=0;i<(8-n);i++) + strcat(msg, " "); + strcat(msg, buffer); + strcat(msg, "\n\n\r"); + } + + NU_SD_Put_String(msg, &port); + + strcpy(msg, "Task 2 invalid messages: "); + sprintf(buffer, "%lu", Task_2_invalid_messages); + n = strlen(buffer); + if (n>=8) + { + strcat(msg, buffer); + strcat(msg, "\n\n\r"); + } + else + { + for (i=0;i<(8-n);i++) + strcat(msg, " "); + strcat(msg, buffer); + strcat(msg, "\n\n\r"); + } + + NU_SD_Put_String(msg, &port); + + if (Who_has_the_resource == &Task_3) + NU_SD_Put_String("Who has the resource: Task 3", &port); + else if (Who_has_the_resource == &Task_4) + NU_SD_Put_String("Who has the resource: Task 4", &port); + else + NU_SD_Put_String("Who has the resource: Nobody", &port); + NU_SD_Put_String("\n\n\n\r", &port); + + strcpy(msg, "Timer Interrupts: "); + sprintf(buffer, "%lu", TMD_System_Clock); + n = strlen(buffer); + if (n>=8) + { + strcat(msg, buffer); + strcat(msg, "\n\n\r"); + } + else + { + for (i=0;i<(8-n);i++) + strcat(msg, " "); + strcat(msg, buffer); + strcat(msg, "\n\n\r"); + } + + NU_SD_Put_String(msg, &port); + + NU_SD_Put_String("Buffer: ", &port); + +#if (NU_SERIAL_INPUT) + while (NU_SD_Data_Ready(&port)) + { + ch = NU_SD_Get_Char(&port); + NU_SD_Put_Char(ch, &port); + } +#endif /* NU_SERIAL_INPUT */ + + + NU_SD_Put_String("\n\n\r", &port); + + +#endif /* NU_SERIAL_OUTPUT */ + /* Increment the time. */ + Task_Time++; + + /* Set an event flag to lift the suspension on task 5. */ + status = NU_Set_Events(&Event_Group_0, 1, NU_OR); + + } + +} + + +/* Define the queue sending task. Note that the only things that cause + this task to suspend are queue full conditions and the time slice + specified in the configuration file. */ + +void task_1(UNSIGNED argc, VOID *argv) +{ + +STATUS status; +UNSIGNED Send_Message; + + /* Access argc and argv just to avoid compilation warnings. */ + status = (STATUS) argc + (STATUS) argv; + + /* Initialize the message counter. */ + Task_1_messages_sent = 0; + + /* Initialize the message contents. The receiver will examine the + message contents for errors. */ + Send_Message = 0; + + while(1) + { + + /* Send the message to Queue_0, which task 2 reads from. Note + that if the destination queue fills up this task suspends until + room becomes available. */ + status = NU_Send_To_Queue(&Queue_0, &Send_Message, 1, NU_SUSPEND); + + /* Determine if the message was sent successfully. */ + if (status == NU_SUCCESS) + Task_1_messages_sent++; + + /* Modify the contents of the next message to send. */ + Send_Message++; + } +} + + +/* Define the queue receiving task. Note that the only things that cause + this task to suspend are queue empty conditions and the time slice + specified in the configuration file. */ + +void task_2(UNSIGNED argc, VOID *argv) +{ + +STATUS status; +UNSIGNED Receive_Message; +UNSIGNED received_size; +UNSIGNED message_expected; + + /* Access argc and argv just to avoid compilation warnings. */ + status = (STATUS) argc + (STATUS) argv; + + /* Initialize the message counter. */ + Task_2_messages_received = 0; + + /* Initialize the message error counter. */ + Task_2_invalid_messages = 0; + + /* Initialize the message contents to expect. */ + message_expected = 0; + + while(1) + { + + /* Retrieve a message from Queue_0, which task 1 writes to. Note + that if the source queue is empty this task suspends until + something becomes available. */ + status = NU_Receive_From_Queue(&Queue_0, &Receive_Message, 1, + &received_size, NU_SUSPEND); + + /* Determine if the message was received successfully. */ + if (status == NU_SUCCESS) + Task_2_messages_received++; + + /* Check the contents of the message against what this task + is expecting. */ + if ((received_size != 1) || + (Receive_Message != message_expected)) + Task_2_invalid_messages++; + + /* Modify the expected contents of the next message. */ + message_expected++; + } +} + + +/* Tasks 3 and 4 want a single resource. Once one of the tasks gets the + resource, it keeps it for 100 clock ticks before releasing it. During + this time the other task suspends waiting for the resource. Note that + both task 3 and 4 use the same instruction areas but have different + stacks. */ + +void task_3_and_4(UNSIGNED argc, VOID *argv) +{ + +STATUS status; + + /* Access argc and argv just to avoid compilation warnings. */ + status = (STATUS) argc + (STATUS) argv; + + /* Loop to allocate and deallocate the resource. */ + while(1) + { + + /* Allocate the resource. Suspend until it becomes available. */ + status = NU_Obtain_Semaphore(&Semaphore_0, NU_SUSPEND); + + /* If the status is successful, show that this task owns the + resource. */ + if (status == NU_SUCCESS) + { + + Who_has_the_resource = NU_Current_Task_Pointer(); + + /* Sleep for 100 ticks to cause the other task to suspend on + the resource. */ + NU_Sleep(100); + + /* Release the semaphore. */ + NU_Release_Semaphore(&Semaphore_0); + } + } +} + + +/* Define the task that waits for the event to be set by task 0. */ + +void task_5(UNSIGNED argc, VOID *argv) +{ + +STATUS status; +UNSIGNED event_group; + + /* Access argc and argv just to avoid compilation warnings. */ + status = (STATUS) argc + (STATUS) argv; + + /* Initialize the event detection counter. */ + Event_Detections = 0; + + /* Continue this process forever. */ + while(1) + { + /* Wait for an event and consume it. */ + status = NU_Retrieve_Events(&Event_Group_0, 1, NU_OR_CONSUME, + &event_group, NU_SUSPEND); + + /* If the status is okay, increment the counter. */ + if (status == NU_SUCCESS) + { + Event_Detections++; + + } + } +} + + +#ifdef NU_FIQ_DEMO +void FIQ_LISR(VOID) +{ + FIQ_Count++; +} +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/demo/irqshell.S Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,584 @@ +/* + * FreeNucleus Calypso port by Michael Spacefalcon + * + * This assembly module contains IRQ handler shell + * and some closely related support functions. + * + * The approach to IRQ handling implemented in the present version + * is exactly the same as was found in XVilka's original nucleus_plus.tar.gz + * code targeting OMAP1510. I personally consider it very dumb and + * suboptimal, but the present version is merely a proof of concept - + * changing as little as possible from our starting point will (hopefully) + * make it easier to get this code to compile, link and maybe even run. + */ + +#include "asm_defs.h" +#include "calirq.h" + + .code 32 + +/* + ********************************** + * GLOBAL VARIABLE DECLARATIONS * + ********************************** + */ + + .data + +@ Define vector table used by INT_IRQ to branch to necessary ISR + + .globl INT_IRQ_Vectors +INT_IRQ_Vectors: + .word INT_Interrupt_Shell @ Vector 0 + .word INT_Interrupt_Shell @ Vector 1 + .word INT_Timer_Interrupt @ Vector 2 - TIMER2 + .word INT_Interrupt_Shell @ Vector 3 + .word INT_Interrupt_Shell @ Vector 4 + .word INT_Interrupt_Shell @ Vector 5 + .word INT_Interrupt_Shell @ Vector 6 + .word INT_Interrupt_Shell @ Vector 7 + .word INT_Interrupt_Shell @ Vector 8 + .word INT_Interrupt_Shell @ Vector 9 + .word INT_Interrupt_Shell @ Vector 10 + .word INT_Interrupt_Shell @ Vector 11 + .word INT_Interrupt_Shell @ Vector 12 + .word INT_Interrupt_Shell @ Vector 13 + .word INT_Interrupt_Shell @ Vector 14 + .word INT_Interrupt_Shell @ Vector 15 + .word INT_Interrupt_Shell @ Vector 16 + .word INT_Interrupt_Shell @ Vector 17 + .word INT_Interrupt_Shell @ Vector 18 + .word INT_Interrupt_Shell @ Vector 19 + .word INT_Interrupt_Shell @ Vector 20 + +@ Define the order in which the interrupts will be executed by software(INT_IRQ) +@ Level 1 Interrupt Handler + .globl INT_IRQ_Priority +INT_IRQ_Priority: + .word 0 + .word 1 + .word 2 + .word 3 + .word 4 + .word 5 + .word 6 + .word 7 + .word 8 + .word 9 + .word 10 + .word 11 + .word 12 + .word 13 + .word 14 + .word 15 + .word 16 + .word 17 + .word 18 + .word 19 + .word 20 +INT_Priority_End: + + .text + +/* + ************************************************************************ + * + * FUNCTION + * + * INT_Setup_Vector + * + * DESCRIPTION + * + * This function sets up the specified vector with the new vector + * value. The previous vector value is returned to the caller. + * + * + * Major Revision: + * + * M. Kyle Craig, Accelerated Technology, Inc. + * + * + * + * CALLED BY + * + * Application + * TCC_Register_LISR Register LISR for vector + * + * CALLS + * + * None + * + * INPUTS + * + * vector Vector number to setup + * new Pointer to new assembly + * language ISR + * + * OUTPUTS + * + * old vector contents + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 08-27-1994 Created initial version 1.0 + * D. Lamie 08-27-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID *INT_Setup_Vector(INT vector, VOID *new) +@{ + + .globl INT_Setup_Vector +INT_Setup_Vector: + +@VOID *old_vector; /* Old interrupt vector */ +@VOID **vector_table; /* Pointer to vector table */ + +@ Calculate the starting address of the actual vector table. +@ vector_table = (VOID **) 0; + +@ Pickup the old interrupt vector. +@ old_vector = vector_table[vector]; +@ +@ Setup the new interrupt vector. +@ vector_table[vector] = new; +@ +@ Return the old interrupt vector. +@ return(old_vector); + + + LDR r2, =INT_IRQ_Vectors @ Load the vector table address + MOV r0, r0, LSL #2 @ Multiply vector by 4 to get offset into table + LDR r3, [r2,r0] @ Load the old pointer + STR r1, [r2,r0] @ Store the new pointer into the vector table + + MOV r0, r3 @ Put the old pointer into the return register + + BX lr @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * INT_Retrieve_Shell + * + * DESCRIPTION + * + * This function retrieves the pointer to the shell interrupt + * service routine. The shell interrupt service routine calls + * the LISR dispatch routine. + * + * + * Major Revision: + * + * M. Kyle Craig, Accelerated Technology, Inc. + * + * + * + * CALLED BY + * + * TCC_Register_LISR Register LISR for vector + * + * CALLS + * + * None + * + * INPUTS + * + * vector Vector number to setup + * + * OUTPUTS + * + * shell pointer + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 08-27-1994 Created initial version 1.0 + * D. Lamie 08-27-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID *INT_Retrieve_Shell(INT vector) +@{ + + .globl INT_Retrieve_Shell +INT_Retrieve_Shell: + + @ Return the LISR Shell interrupt routine. + @ return(INT_Vectors[vector]); + + LDR r1, =INT_IRQ_Vectors @ Load the vector table address + MOV r0, r0, LSL #2 @ Multiply vector by 4 to get offset into table + LDR r0, [r1,r0] @ Load interrupt handler pointer into return register + + BX lr @ Return to caller + + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * _INT_IRQ + * + * DESCRIPTION + * + * This routine is the board-specific section for + * level 1 interrupt handling + * + * CALLED BY + * + * None + * + * CALLS + * + * TMT_Timer_Interrupt + * + * INPUTS + * + * None + * + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * B. Ronquillo 05-10-00 Created initial version 1.0 + * + ************************************************************************ + */ + + .globl _INT_IRQ +_INT_IRQ: + + STMDB sp!,{r0-r4} @ Save r0-r4 on temporary IRQ stack + SUB lr,lr,#4 @ Adjust IRQ return address + +/* + ******************************** + * Begin Hardware Specific Code * + ******************************** + */ + + LDR r3, =INTH_BASE_ADDR @ load Interrupt Control Base + @ Get enable register value + @ original instr was: LDR r4, [r3,#INT_CNTRL_MIR] + @ but on the Calypso we have to read two 16-bit regs + ldrh r0, [r3, #MASK_IT_REG1] + ldrh r1, [r3, #MASK_IT_REG2] + @ now combine them into a 32-bit word in r4 for the old code to work as-is + orr r4, r0, r1, lsl #16 + +/* + ****************************** + * End Hardware Specific Code * + ****************************** + */ + + STMDB sp!,{r4} @ Put the enable register value on the IRQ stack + MVN r4,#0 @ Start with 0xFFFFFFFF to allow nesting of interrupts + +/* + ******************************** + * Begin Hardware Specific Code * + ******************************** + */ + + @ Read Pending reg + @ original instr was: LDR r2, [r3,#INT_CNTRL_ITR] + @ do the same trick as we did for the mask regs + ldrh r0, [r3, #IT_REG1] + ldrh r1, [r3, #IT_REG2] + orr r2, r0, r1, lsl #16 + +/* + ****************************** + * End Hardware Specific Code * + ****************************** + */ + + LDR r3, =INT_IRQ_Priority @ Get the Priority table address + +IRQ_VECTOR_LOOP: + LDR r0, [r3,#0] @ Load first vector to be checked from priority table + MOV r1, #1 @ Build mask + MOV r1, r1, LSL r0 @ Use vector number to set mask to correct bit position + TST r1, r2 @ Test if pending bit is set + BNE IRQ_VECTOR_FOUND @ If bit is set, branch to found section... + + BIC r4,r4,r1 @ Clear mask bit to keep higher priority ints active + ADD r3, r3, #4 @ Move to next word in the priority table + LDR r0, =INT_Priority_End @ Load the end address for the priority table + CMP r0, r3 @ Make sure not at the end of the table (shouldn't happen!) + BNE IRQ_VECTOR_LOOP @ Continue to loop if not at the end of the table + + @ No bits in pending register set, restore registers and exit interrupt servicing + ADD sp,sp,#4 @ Adjust sp above IRQ enable value + LDMIA sp!,{r0-r4} @ Restore r0-r4 + STMDB sp!,{lr} @ Put return address for IRQ on stack + LDMIA sp!,{pc}^ @ return to the point of the exception and restore SPSR + +IRQ_VECTOR_FOUND: + +/* + ******************************** + * Begin Hardware Specific Code * + ******************************** + */ + + LDR r3, =INTH_BASE_ADDR @ load Interrupt Control Base + + MVN r2, r1 @ Get the inverse of the interrupt vector + @ Write a zero to the interrupt being handled (IT_REGn) + cmp r0, #16 + strloh r2, [r3, #IT_REG1] + mov r2, r2, lsr #16 + strhsh r2, [r3, #IT_REG2] + + @ Read the Mask reg - just like we did before + ldrh r1, [r3, #MASK_IT_REG1] + ldrh r2, [r3, #MASK_IT_REG2] + orr r2, r1, r2, lsl #16 + @ was LDR r2, [r3,#INT_CNTRL_MIR] + + ORR r4, r2, r4 @ Turn off lower priority pending bits and currently masked bits + + @ write both mask registers + @ was STR r4, [r3,#INT_CNTRL_MIR] + strh r4, [r3, #MASK_IT_REG1] + mov r1, r4, lsr #16 + strh r1, [r3, #MASK_IT_REG2] + + MOV r1, #1 @ Clear the pending interrupt + STRH r1, [r3,#IRQ_CTRL] @ by writing a 1 to the Control Reg + +/* + ****************************** + * End Hardware Specific Code * + ****************************** + */ + + LDR r3, =INT_IRQ_Vectors @ Get IRQ vector table address + MOV r2, r0, LSL #2 @ Multiply vector by 4 to get offset into table + ADD r3, r3, r2 @ Adjust vector table address to correct offset + LDR r2, [r3,#0] @ Load branch address from vector table + + MOV PC, r2 @ Jump to correct branch location based on vector table + +@ END: INT_IRQ + +/* + ************************************************************************ + * + * FUNCTION + * + * INT_Interrupt_Shell + * + * DESCRIPTION + * + * Handles all interrupts which use NU_Register_LISR. + * + * + * CALLED BY + * + * INT_IRQ + * + * CALLS + * + * TCT_Dispatch_LISR + * TCT_Interrupt_Context_Restore + * + * INPUTS + * + * vector (register r0) + * + * OUTPUTS + * + * None + ************************************************************************ + */ + + .globl INT_Interrupt_Shell +INT_Interrupt_Shell: + + MOV r4,lr @ Put IRQ return address into r4 + + BL TCT_Interrupt_Context_Save + + BL TCC_Dispatch_LISR + + MRS r1,CPSR @ Pickup current CPSR + BIC r1,r1,#MODE_MASK @ Clear the mode bits + ORR r1,r1,#(IRQ_MODE_OR_LOCKOUT) @ Set the IRQ mode bits and Lockout interrupts + MSR CPSR,r1 @ Lockout interrupts/change to IRQ mode + +/* + ******************************** + * Begin Hardware Specific Code * + ******************************** + */ + LDMIA sp!,{r1} @ Get IRQ enable value off IRQ stack + + LDR r2, =INTH_BASE_ADDR @ Get IRQ0 base register address + @ write it into both mask regs + @was STR r1,[r2,#INT_CNTRL_MIR] + strh r1, [r2, #MASK_IT_REG1] + mov r1, r1, lsr #16 + strh r1, [r2, #MASK_IT_REG2] +/* + ****************************** + * End Hardware Specific Code * + ****************************** + */ + + MRS r1,CPSR @ Pickup current CPSR + BIC r1,r1,#MODE_MASK @ Clear the mode bits + ORR r1,r1,#SUP_MODE @ Set the SVC mode bits + MSR CPSR,r1 @ Change to SVC mode + + B TCT_Interrupt_Context_Restore + +/* + ************************************************************************ + * + * FUNCTION + * + * INT_Timer_Interrupt + * + * DESCRIPTION + * + * This routine is the board-specific section of the timer + * interrupt handling + * + * CALLED BY + * + * None + * + * CALLS + * + * TMT_Timer_Interrupt + * + * INPUTS + * + * None + * + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * B.Ronquillo 05-10-00 Created initial version 1.0 + * + ************************************************************************ + */ + + .globl INT_Timer_Interrupt +INT_Timer_Interrupt: + +/* + ******************************** + * Begin Hardware Specific Code * + ******************************** + * Clear the pending timer interrupt + * + * This is done in the INT_IRQ function by writing a zero to the + * timer bit. + * + ****************************** + * End Hardware Specific Code * + ****************************** + */ + + MOV r4,lr @ Put IRQ return address into r4 + + BL TCT_Interrupt_Context_Save + + BL TMT_Timer_Interrupt @ Call the timer interrupt + @ processing. + + MRS r1,CPSR @ Pickup current CPSR + BIC r1,r1,#MODE_MASK @ Clear the mode bits + ORR r1,r1,#IRQ_MODE @ Set the IRQ mode bits + MSR CPSR,r1 @ Change to IRQ mode + +/* + ******************************** + * Begin Hardware Specific Code * + ******************************** + */ + LDMIA sp!,{r1} @ Get IRQ enable value off IRQ stack + + LDR r2, =INTH_BASE_ADDR @ Get IRQ0 base register address + @ write it into both mask regs + @was STR r1,[r2,#INT_CNTRL_MIR] + strh r1, [r2, #MASK_IT_REG1] + mov r1, r1, lsr #16 + strh r1, [r2, #MASK_IT_REG2] +/* + ****************************** + * End Hardware Specific Code * + ****************************** + */ + + MRS r1,CPSR @ Pickup current CPSR + BIC r1,r1,#MODE_MASK @ Clear the mode bits + ORR r1,r1,#SUP_MODE @ Set the SVC mode bits + MSR CPSR,r1 @ Change to SVC mode + + B TCT_Interrupt_Context_Restore + +@} +@ End of INT_Timer_Interrupt + +/* + * INT_Interrupt_Init function written by Michael Spacefalcon + * for the FreeNucleus Calypso port - takes the place of + * INT_Install_Vector_Table, called from INT_Initialize. + */ + + .globl INT_Interrupt_Init +INT_Interrupt_Init: + +@ first mask all interrupts in the INTH + + ldr r0, =INTH_BASE_ADDR + mvn r1, #0 + strh r1, [r0, #MASK_IT_REG1] + strh r1, [r0, #MASK_IT_REG2] + +@ now install our IRQ vector into the magic IRAM jump table slot + + ldr r0, =_INT_IRQ + mov r1, #0x800000 + str r0, [r1, #0x14] + +@ we are done! + bx lr + +/* + * Need to define an INT_Vectors_Loaded() function + * that returns 1. + */ + .globl INT_Vectors_Loaded +INT_Vectors_Loaded: + mov r0, #1 + bx lr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/demo/nucdemo.Makefile Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,10 @@ +CC= arm-elf-gcc +CFLAGS= -O2 -fno-builtin -mthumb-interwork -mthumb +CPPFLAGS=-I../nucleus + +OBJS= demo.o + +all: ${OBJS} + +clean: + rm -f *.[oa] *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/demo/sdc.c Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,1033 @@ +/************************************************************************** +* +* Copyright Mentor Graphics Corporation 2002 +* All Rights Reserved. +* +* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS +* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS +* SUBJECT TO LICENSE TERMS. +* +*************************************************************************** +*************************************************************************** +* +* FILE NAME VERSION +* +* sdc.c Nucleus PLUS\ARM925\Code Composer 1.14.1 +* +* DESCRIPTION +* +* This file contains the Serial Driver specific functions. +* +* DATA STRUCTURES +* +* SD_PORT * : An array of pointers to serial port structures. +* +* FUNCTIONS +* +* SDC_Init_Port +* SDC_Date_Ready +* SDC_Put_String +* SDC_LISR +* SDC_Get_Char +* SDC_Put_Char +* SDC_Set_Baud_Rate +* +* DEPENDENCIES +* +* nucleus.h +* sd_defs.h +* sd_extr.h +* target.h +* protocol.h +* externs.h +* ppp.h +* +* HISTORY +* +* NAME DATE REMARKS +* +* B. Ronquillo 08-28-2002 Released version 1.14.1 +****************************************************************************/ + +#include "nucleus.h" +#include "sd_defs.h" +#include "sd_extr.h" +#include "calirq.h" + +#ifdef NU_ENABLE_PPP + +#include "net\target.h" +#include "net\inc\externs.h" +#include "net\inc\tcp_errs.h" +#include "ppp\inc\ppp.h" + +#endif /* NU_ENABLE_PPP */ + +extern NU_MEMORY_POOL System_Memory; + +/* Define a small array to hold pointers to the two UART data + structures. This is used by the LISR to find the correct + data structure for the interrupt being handled. */ +SD_PORT *SDC_Port_List[SD_MAX_UARTS]; + + +/* Define prototypes for functions local to this module. */ + + /**************** Begin Port Specific Section **************/ +#ifdef GRAFIX_MOUSE +extern NU_HISR Mouse_HISR; +#endif + /**************** End Port Specific Section **************/ + +static VOID SDC_Set_Baud_Rate(UINT32, SD_PORT *); +/*************************************************************************** +* FUNCTION +* +* SDC_Init_Port +* +* DESCRIPTION +* +* This function intializes the COM port that will be used for PPP +* communications. +* +* +* INPUTS +* +* SD_PORT * : device initialization structure. +* +* OUTPUTS +* +* STATUS : Returns NU_SUCCESS if successful initialization, +* else a negative value is returned. +* +****************************************************************************/ +STATUS SDC_Init_Port(SD_PORT *uart) +{ +STATUS status = NU_SUCCESS; +INT32 int_level, /* old interrupt level */ + tInt; +UINT8 temp_byte; +UINT32 temp_word, int_val; +CHAR sem_name[8]; +static INT num_ports = 0; +VOID (*old_lisr)(INT); /* old LISR */ + +#ifdef GRAFIX_MOUSE + if ((uart->communication_mode == SERIAL_MODE) || + (uart->communication_mode == SERIAL_MOUSE)) +#else + if (uart->communication_mode == SERIAL_MOUSE) + { + status = NU_INVALID_MOUSE_MODE; + } + else if (uart->communication_mode == SERIAL_MODE) +#endif + + { + + /* Check for max allowed UARTS. */ + if (num_ports >= SD_MAX_UARTS) + + /* We have already initialized the max allowed UARTS. */ + status = NU_UART_LIST_FULL; + } + + if (status != NU_SUCCESS) + return (status); + + /* Check the supplied parity */ + else if ((uart->parity != SD_PARITY_NONE) && + (uart->parity != SD_PARITY_EVEN) && + (uart->parity != SD_PARITY_ODD)) + + /* The supplied parity is not valid */ + status = NU_INVALID_PARITY; + + /* Check the supplied number of data bits */ + else if ((uart->data_bits != SD_DATA_BITS_7) && + (uart->data_bits != SD_DATA_BITS_8)) + + /* The supplied data bits value is not valid */ + status = NU_INVALID_DATA_BITS; + + /* Check the supplied number of stop bits */ + else if ((uart->stop_bits != SD_STOP_BITS_1) && + (uart->stop_bits != SD_STOP_BITS_2)) + + /* The supplied stop bits value is not valid */ + status = NU_INVALID_STOP_BITS; + + /* Verify the baud rate is within acceptable range */ + else if ((uart->baud_rate < 300) || (uart->baud_rate > 115200)) + + /* The baud rate is out of range */ + status = NU_INVALID_BAUD; + + /************** Begin Port Specific Section ****************/ + + /* Validate the com port. */ + else if ((uart->com_port == SD_UART1) || + (uart->com_port == SD_UART2)) + { + /* Handle UARTA */ + if (uart->com_port == SD_UART_MODEM) + { + /* Set the vector inside this structure */ + uart->vector = IRQ_UART_MODEM; + + /* Set the base address for this UART. */ + uart->base_address = SD_UART_MODEM_BASE; + } + else /* Otherwise handle UARTB. */ + { + /* Set the vector inside this structure */ + uart->vector = IRQ_UART_IRDA; + + /* Set the base address for this UART. */ + uart->base_address = SD_UART_IRDA_BASE; + } + } + else + + /************** End Port Specific Section **************/ + + /* Not a supported port. */ + status = NU_INVALID_COM_PORT; + +#ifdef GRAFIX_MOUSE + if ((uart->communication_mode == SERIAL_MODE) || + (uart->communication_mode == SERIAL_MOUSE)) +#else + if (uart->communication_mode == SERIAL_MODE) +#endif + + { + /* Make sure the port was valid and the LISR was + registered. Then create the semaphore used to make + the SD_Put_String service thread safe. */ + if (status == NU_SUCCESS) + { + /* Allocate memory for the semaphore control block. */ + status = NU_Allocate_Memory(&System_Memory,(VOID**) &uart->sd_semaphore, + sizeof(NU_SEMAPHORE), NU_NO_SUSPEND); + +#if 0 +/* original code */ + for(tInt=0; tInt < sizeof(NU_SEMAPHORE); tInt++) + /* Fixed SPR 211. Changed type from (UINT32) to (CHAR *) */ + SD_OUTBYTE((CHAR *) uart->sd_semaphore + tInt, 0x00); +#else + bzero(uart->sd_semaphore, sizeof(NU_SEMAPHORE)); +#endif + + if (status == NU_SUCCESS) + { + /* Build the name. */ + sem_name[0] = 's'; + sem_name[1] = 'e'; + sem_name[2] = 'r'; + sem_name[3] = 'i'; + sem_name[4] = 'a'; + sem_name[5] = 'l'; + sem_name[6] = '_'; + sem_name[7] = (CHAR)(0x30 + num_ports); + + status = NU_Create_Semaphore (uart->sd_semaphore, sem_name, + 1, NU_FIFO); + } + } + + /* Make sure all the above was completed. Then store off this + UART stucture and initialize the chip. */ + if (status == NU_SUCCESS) + { + SDC_Port_List[num_ports++] = uart; + } + } + + if (status == NU_SUCCESS) + { + /* Allocate memory for the data buffers. PPP only requires a TX + buffer so the allocation will be a little different for PPP mode. */ +#ifdef GRAFIX_MOUSE + if ((uart->communication_mode == SERIAL_MODE) || + (uart->communication_mode == SERIAL_MOUSE)) +#else + if (uart->communication_mode == SERIAL_MODE) +#endif + + { + status = NU_Allocate_Memory (&System_Memory,(VOID**) &uart->tx_buffer, + (2 * uart->sd_buffer_size), NU_NO_SUSPEND); + + /* Set the RX buffer to just past the TX buffer. */ + uart->rx_buffer = (CHAR *)(uart->tx_buffer + uart->sd_buffer_size); + } + else + { + status = NU_Allocate_Memory (&System_Memory,(VOID**) &uart->tx_buffer, + uart->sd_buffer_size, NU_NO_SUSPEND); + } + + if (status == NU_SUCCESS) + { + /* Setup the RX SD buffer */ + uart->rx_buffer_read = uart->rx_buffer_write = 0; + + uart->rx_buffer_status = NU_BUFFER_EMPTY; + + /* Setup the TX SD buffer */ + uart->tx_buffer_read = uart->tx_buffer_write = 0; + uart->tx_buffer_status = NU_BUFFER_EMPTY; + } + } + + if (status == NU_SUCCESS) + { + /* Disable interrupts */ + int_level = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS); + + /* Initialize the UART */ + + /************** Begin Port Specific Section *************/ + + /* Configure the Mode Definition Register */ + /* Set the serial port to UART mode */ + SD_OUTBYTE(uart->base_address + MDR_OFFSET, MDR_UART_MODE); + + /* Reset the TX/RX FIFOs */ + SD_OUTBYTE(uart->base_address + FCR_OFFSET, FCR_FIFO_RESET); + + /* Setup baud rate */ + SDC_Set_Baud_Rate(uart->baud_rate, uart); + + /* Set the modem control register. Set DTR, RTS to output to LOW, + and set INT output pin to normal operating mode */ + SD_OUTBYTE (uart->base_address + MCR_OFFSET, (MCR_DTR_LOW | MCR_RTS_LOW)); + + /* Setup parity, data bits, and stop bits */ + SD_OUTBYTE (uart->base_address + LCR_OFFSET, + (LCR_NO_BREAK|uart->parity|uart->data_bits|uart->stop_bits )); + + /* Setup Fifo trigger level and enable FIFO */ + SD_OUTBYTE (uart->base_address + FCR_OFFSET, 0); + + /* Register the interrupt handler for the UART receiver */ + status = NU_Register_LISR(uart->vector, SDC_LISR, &old_lisr); + + if (status == NU_SUCCESS) + { + /* Enable the RX interrupts */ + SD_OUTBYTE (uart->base_address + IER_OFFSET, IER_RX_HOLDING_REG); + + if(uart->com_port == SD_UART_MODEM) + { + /* Enable the UART interrupt globally */ + INTH_REGS.ilr_irq[IRQ_UART_MODEM] = 0x7C; + INTH_REGS.mask_it_reg1 &= ~(1 << IRQ_UART_MODEM); + } + else /* Handle UART B */ + { + /* Enable the UART interrupt globally */ + INTH_REGS.ilr_irq[IRQ_UART_IRDA] = 0x7C; + INTH_REGS.mask_it_reg2 &= ~(1 << (IRQ_UART_IRDA - 16)); + } + + } + + /************** End Port Specific Section *************/ + + + /* Initialize the error counters. */ + uart->parity_errors = + uart->frame_errors = + uart->overrun_errors = + uart->busy_errors = + uart->general_errors = 0; + + /* Restore interrupts to previous level */ + NU_Local_Control_Interrupts(int_level); + } + + return (status); +} +/*************************************************************************** +* FUNCTION +* +* SDC_Put_Char +* +* DESCRIPTION +* +* This writes a character out to the serial port. +* +* INPUTS +* +* UINT8 : Character to to be written to the serial port. +* SD_PORT * : Serial port to send the char to. +* +* OUTPUTS +* +* none +* +****************************************************************************/ +VOID SDC_Put_Char(UINT8 ch, SD_PORT *uart) +{ +INT int_level; /* old interrupt level */ +UINT32 temp_long; + +#ifdef GRAFIX_MOUSE + if ((uart->communication_mode == SERIAL_MODE) || + (uart->communication_mode == SERIAL_MOUSE)) +#else + if (uart->communication_mode == SERIAL_MODE) +#endif + + { + /* If the buffer is full wait for it to empty a little. */ + while (uart->tx_buffer_status == NU_BUFFER_FULL); + + /* Disable interrupts */ + int_level = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS); + + /* Check the transmit buffer status. If it has data already + just add this byte to the buffer. */ + if ( uart->tx_buffer_status != NU_BUFFER_EMPTY) + { + /* Add byte to buffer. */ + uart->tx_buffer[uart->tx_buffer_write++] = ch; + + /* Check for wrap of buffer. */ + if(uart->tx_buffer_write == uart->sd_buffer_size) + uart->tx_buffer_write = 0; + + /* Check for full buffer. */ + if (uart->tx_buffer_write == uart->tx_buffer_read) + uart->tx_buffer_status = NU_BUFFER_FULL; + + /* Restore interrupts to previous level */ + NU_Local_Control_Interrupts(int_level); + } + else + { + /* Otherwise send the data. */ + + /* Restore interrupts to previous level */ + NU_Local_Control_Interrupts(int_level); + + /* Add byte to buffer. */ + uart->tx_buffer[uart->tx_buffer_write++] = ch; + + /* Check for wrap of buffer. */ + if(uart->tx_buffer_write == uart->sd_buffer_size) + uart->tx_buffer_write = 0; + + /* Set status */ + uart->tx_buffer_status = NU_BUFFER_DATA; + + /**************** Begin Port Specific Section **************/ + + /* Wait until the transmitter buffer is empty */ + while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); + + /* Transmit the character */ + SD_OUTBYTE (uart->base_address + THR_OFFSET, ch); + + /* Enable the TX interrupts */ + temp_long = SD_INBYTE (uart->base_address + IER_OFFSET); + temp_long |= IER_TX_HOLDING_REG; + SD_OUTBYTE (uart->base_address + IER_OFFSET, temp_long); + + } + + } /* endif mode */ + else + { + /* Wait until the transmitter buffer is empty */ + while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); + + /* Transmit the character */ + SD_OUTBYTE (uart->base_address + THR_OFFSET, ch); + +#ifndef PPP_POLLED_TX + + /* Enable the TX interrupts */ + temp_long = SD_INBYTE (uart->base_address + IER_OFFSET); + temp_long |= IER_TX_HOLDING_REG; + SD_OUTBYTE (uart->base_address + IER_OFFSET, temp_long); + +#endif /* PPP_POLLED_TX */ + + + } + + /***************** End Port Specific Section ***************/ + +} + +/*************************************************************************** +* FUNCTION +* +* SDC_LISR +* +* DESCRIPTION +* +* This is the entry function for the receive ISR that services the UART +* in the ARM925. +* +* INPUTS +* +* INT : Interrupt vector +* +* OUTPUTS +* +* none +* +****************************************************************************/ +VOID SDC_LISR(INT vector) +{ + +SD_PORT *uart; +CHAR receive; +UINT8 status; +UINT8 int_status; +UINT8 vector_found = NU_FALSE; +UINT8 ier_val; + + +#ifdef NU_ENABLE_PPP +DV_DEVICE_ENTRY *device; +#endif /* NU_ENABLE_PPP */ + + for(receive = 0 ; (SDC_Port_List[receive] != NU_NULL) && + (receive < SD_MAX_UARTS) && !vector_found ; receive++) + { + /* See if we found one. Better have since we got an interrupt + from one. */ + if (SDC_Port_List[receive] -> vector == vector) + { + /* Point our local structure to it. */ + uart = SDC_Port_List[receive]; + vector_found = NU_TRUE; + } + } + +#ifdef NU_ENABLE_PPP + + /* Find the device for this interrupt */ + if ( (device = DEV_Get_Dev_For_Vector(vector)) != NU_NULL) + { + /* Get the address of the uart structure for this device. */ + uart = &((PPP_LAYER *) device->ppp_layer)->uart; + vector_found = NU_TRUE; + } + +#endif /* NU_ENABLE_PPP */ + + if (vector_found == NU_TRUE) + { + /**************** Begin Port Specific Section **************/ + + /* Get the interrupt status register value */ + int_status = SD_INBYTE(uart->base_address + IIR_OFFSET); + + /* Loop until all interrupts are processed */ + while (!(int_status & IIR_PENDING)) + { + /* Check for a receive interrupt */ + if (((int_status & IIR_RX_LINE_STAT) ==IIR_RX_LINE_STAT) || + ((int_status & IIR_RX_RDY) ==IIR_RX_RDY) || + ((int_status & IIR_RX_TIMEOUT) ==IIR_RX_TIMEOUT) ) + { + /* Process every character in the receive FIFO */ + status = SD_INBYTE(uart->base_address + LSR_OFFSET); + + while (status & LSR_RX_DATA_READY) + { + /* Get character from receive FIFO */ + receive = SD_INBYTE (uart->base_address + RHR_OFFSET); + + /* Check if receive character has errors */ + if (status & (LSR_FRAMING_ERROR | LSR_PARITY_ERROR)) + { + /* Increment parity errors if necessary */ + uart->parity_errors += ((status & LSR_PARITY_ERROR) == LSR_PARITY_ERROR); + + /* Increment framing errors if necessary */ + uart->frame_errors += ((status & LSR_FRAMING_ERROR) == LSR_FRAMING_ERROR); + } + else // no framing or parity errors + { + /* Increment overrun errors if necessary */ + uart->overrun_errors += ((status & LSR_RX_DATA_READY) == LSR_RX_DATA_READY); + + /* Switch based on UART mode */ + switch(uart->communication_mode) + { + case SERIAL_MODE: + + if (uart->rx_buffer_status != NU_BUFFER_FULL) + { + + /* Put the character into the buffer */ + uart->rx_buffer[uart->rx_buffer_write++] = receive; + + /* Check for wrap of buffer. */ + if(uart->rx_buffer_write == uart->sd_buffer_size) + uart->rx_buffer_write = 0; + + /* Set status field based on latest character */ + if (uart->rx_buffer_write == uart->rx_buffer_read) + uart->rx_buffer_status = NU_BUFFER_FULL; + else + uart->rx_buffer_status = NU_BUFFER_DATA; + } + else + uart->busy_errors++; + + break; + +#ifdef NU_ENABLE_PPP + /* call PPP processing functions */ + + case MDM_NETWORK_COMMUNICATION: + /* Call this devices receive routine */ + device->dev_receive(device); + break; + + case MDM_TERMINAL_COMMUNICATION: + default: + MDM_Receive(device); + break; +#endif /* NU_ENABLE_PPP */ + } + } + + /* Check the rx buffer status again... */ + status = SD_INBYTE(uart->base_address + LSR_OFFSET); + + } + + } // if ((status & IIR_TYPE_MASK) == IIR_Rx_Rdy) + + + int_status = SD_INBYTE(uart->base_address + IER_OFFSET); + + if (int_status & IER_TX_HOLDING_REG) + { + if (uart->communication_mode == SERIAL_MODE) + { + /* Bump the read pointer past the byte that was just + transmitted. */ + ++(uart->tx_buffer_read); + + /* Check for wrap of buffer. */ + if(uart->tx_buffer_read == uart->sd_buffer_size) + uart->tx_buffer_read = 0; + + /* Update the status. */ + if (uart->tx_buffer_write == uart->tx_buffer_read) + { + uart->tx_buffer_status = NU_BUFFER_EMPTY; + + /* Since it is now empty disable the TX interrupt! */ + ier_val = SD_INBYTE(uart->base_address + IER_OFFSET); + ier_val &= ~IER_TX_HOLDING_REG; + SD_OUTBYTE(uart->base_address + IER_OFFSET, ier_val); + } + else + { + + /* Wait until the transmitter buffer is empty */ + while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); + + /* Send the next byte in the queue. */ + SD_OUTBYTE(uart->base_address + THR_OFFSET, uart->tx_buffer[uart->tx_buffer_read]); + + /* Update the status. */ + uart->tx_buffer_status = NU_BUFFER_DATA; + } + } +#ifdef NU_ENABLE_PPP + else + { +#ifndef PPP_POLLED_TX + /* Check for a transmit interrupt. */ + /* Is there another byte in the TX buffer to send? */ + if (uart->tx_buffer_read != uart->tx_buffer_write) + { + /* Wait until the transmitter buffer is empty */ + while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); + + /* Send the next byte in the queue. */ + SD_OUTBYTE (uart->base_address + THR_OFFSET, uart->tx_buffer[uart->tx_buffer_read++]); + + /* Check for wrap of buffer. */ + uart->tx_buffer_read %= uart->sd_buffer_size; + } + else + { + + /* Since it is now empty disable the TX interrupt! */ + ier_val = SD_INBYTE (uart->base_address + IER_OFFSET); + ier_val &= ~IER_TX_HOLDING_REG; + SD_OUTBYTE (uart->base_address + IER_OFFSET, ier_val); + + /* Only activate the HISR if we are tranmitting + network data. */ + if (uart->communication_mode == MDM_NETWORK_COMMUNICATION) + { + /* Add this device to the list of PPP devices that have finished + sending a packet. */ + _ppp_tx_dev_ptr_queue [_ppp_tx_dev_ptr_queue_write++] = device; + + /* Activate the HISR that will take care of processing the + next packet in queue, if one is ready. */ + NU_Activate_HISR (&PPP_TX_HISR); + + /* Check for wrap of ring buffer. */ + + _ppp_tx_dev_ptr_queue_write %= PPP_MAX_TX_QUEUE_PTRS; + + } + } +#endif /* PPP_POLLED_TX */ + } +#endif /* NU_ENABLE_PPP */ + } + + /* Get the interrupt status register value */ + int_status = SD_INBYTE(uart->base_address + IIR_OFFSET); + } + + /**************** End Port Specific Section **************/ + + /* No port is associated with the vector */ + } + else + { + ERC_System_Error(NU_UNHANDLED_INTERRUPT); + } +} + +/**************************************************************************** +* FUNCTION +* +* SDC_Set_Baud_Rate +* +* DESCRIPTION +* +* This function sets the UART buad rate. +* +* INPUTS +* +* UINT32 : The new baud rate. +* SD_PORT * : Serial port to set the baud rate. +* +* OUTPUTS +* +* none +* +****************************************************************************/ +VOID SDC_Set_Baud_Rate(UINT32 baud_rate, SD_PORT *uart) +{ + UNSIGNED baud_div; + UINT32 temp_long; + + /**************** Begin Port Specific Section **************/ + + /* Write to the divisor latch bit to enable the DLH and DLL registers */ + temp_long = SD_INBYTE(uart->base_address + LCR_OFFSET); + SD_OUTBYTE (uart->base_address + LCR_OFFSET, LCR_DIV_EN); + + /* Set the baud rate */ + baud_div = 115200 * 7 / uart->baud_rate; + + /* Put LSB in DLL Reg */ + SD_OUTBYTE (uart->base_address + DLL_OFFSET, baud_div); + + /* Put MSB in DLH Reg */ + SD_OUTBYTE (uart->base_address + DLH_OFFSET, (baud_div >> 8)); + + /* Disable the Divisor Latch bit */ + SD_OUTBYTE (uart->base_address + LCR_OFFSET, temp_long & ~LCR_DIV_EN); + /**************** End Port Specific Section ****************/ + +} +/**************************************************************************** +* FUNCTION +* +* SDC_Get_Char +* +* DESCRIPTION +* +* This function reads the last received character from the UART. +* +* INPUTS +* +* SD_PORT * : Serial port to get the char from. +* +* OUTPUTS +* +* CHAR : Character read +* +****************************************************************************/ +CHAR SDC_Get_Char(SD_PORT *uart) +{ + CHAR ch = NU_NULL; + +#ifdef GRAFIX_MOUSE + if ((uart->communication_mode == SERIAL_MODE) || + (uart->communication_mode == SERIAL_MOUSE)) +#else + if (uart->communication_mode == SERIAL_MODE) +#endif + + { + if ((uart->rx_buffer_status == NU_BUFFER_FULL) || + (uart->rx_buffer_status == NU_BUFFER_DATA)) + { + /* Store the character to be returned */ + ch = uart->rx_buffer[uart->rx_buffer_read++]; + + /* If read pointer is at end, wrap it around */ + if (uart->rx_buffer_read == uart->sd_buffer_size) + uart->rx_buffer_read = 0; + + /* Set the status to reflect removal of the character */ + if (uart->rx_buffer_write == uart->rx_buffer_read) + uart->rx_buffer_status = NU_BUFFER_EMPTY; + else + uart->rx_buffer_status = NU_BUFFER_DATA; + } + + return (ch); + } /* endif mode */ + +#ifdef NU_ENABLE_PPP + else if (uart->communication_mode == MDM_TERMINAL_COMMUNICATION || + uart->communication_mode == MDM_NETWORK_COMMUNICATION) + + /**************** Begin Port Specific Section **************/ + + return ((UINT8)SD_INBYTE (uart->base_address + RHR_OFFSET)); + + /**************** End Port Specific Section ****************/ + +#endif /* NU_ENABLE_PPP */ + + /* Execution should never reach this point, this return was added + in response to the 'implicit return' compiler warning */ + + return (ch); +} + +/**************************************************************************** +* FUNCTION +* +* SDC_Carrier +* +* DESCRIPTION +* +* This function checks for a carrier. +* +* INPUTS +* +* none +* +* OUTPUTS +* +* STATUS : The status of the detection. +* +****************************************************************************/ +STATUS SDC_Carrier(SD_PORT *uart) +{ + return (NU_TRUE); +} + +/**************************************************************************** + Note: All functions below this point are generic and should not require + any changes to support other UARTS. + ****************************************************************************/ + +/**************************************************************************** +* FUNCTION +* +* SDC_Put_String +* +* DESCRIPTION +* +* This writes a null-terminated string out to the serial port. +* +* INPUTS +* +* CHAR * : String to be written to the serial port. +* SD_PORT * : Serial port to send the string to. +* +* OUTPUTS +* +* none +* +****************************************************************************/ +VOID SDC_Put_String(CHAR *str, SD_PORT *uart) +{ + + /* Grab the semaphore so that strings between threads + do not get mixed. */ + if (NU_Obtain_Semaphore(uart->sd_semaphore, NU_SUSPEND) == NU_SUCCESS) + { + + /* Send out the string. */ + for (; *str != 0; str++) + SDC_Put_Char(*str, uart); + + /* Allow other threads to use this service. */ + NU_Release_Semaphore (uart->sd_semaphore); + } + +} + + +/**************************************************************************** +* FUNCTION +* +* SDC_Data_Ready +* +* DESCRIPTION +* +* This function checks to see if there are any characters in the +* receive buffer. A status value is returned indicating whether +* characters are present in the receive buffer. +* +* INPUTS +* +* SD_PORT * : Serial port to check for data. +* +* OUTPUTS +* +* STATUS The status indicates the +* presence of characters. +* +****************************************************************************/ +STATUS SDC_Data_Ready(SD_PORT *port) +{ + /* Check the status. */ + if((port->rx_buffer_status == NU_BUFFER_FULL) || + (port->rx_buffer_status == NU_BUFFER_DATA)) + + return (NU_TRUE); + + else + + return (NU_FALSE); +} + +/**************************************************************************** +* FUNCTION +* +* SDC_Change_Communication_Mode +* +* DESCRIPTION +* +* This function switches the serial port between terminal mode and +* network mode. The mode affects how incoming characters are directed. +* +* INPUTS +* +* INT : The mode of operation desired. +* +* OUTPUTS +* +* none +* +****************************************************************************/ +VOID SDC_Change_Communication_Mode(INT mode, SD_PORT *uart) +{ + uart->communication_mode = mode; + +} /* SDC_Change_Communication_Mode */ + +/**************************************************************************** +* FUNCTION +* +* SDC_Reset +* +* DESCRIPTION +* +* This function intializes the data variables associated with a UART +* +* INPUTS +* +* SD_PORT * : Serial port to reset +* +* OUTPUTS +* +* STATUS : Returns URT_SUCCESS if successful initialization, +* else a negative value is returned. +* +****************************************************************************/ +VOID SDC_Reset (SD_PORT *uart) +{ + /* Ini the error counters */ + uart->frame_errors = 0; + uart->overrun_errors = 0; + uart->parity_errors = 0; + uart->busy_errors = 0; + uart->general_errors = 0; +} + +/*************************************************************************** +* FUNCTION +* +* URT_Init_Port +* +* DESCRIPTION +* +* This function intializes the data variables associated with a UART +* +* INPUTS +* +* SD_PORT * : Serial port to reset +* +* OUTPUTS +* +* STATUS : Returns URT_SUCCESS if successful initialization, +* else a negative value is returned. +* +****************************************************************************/ +#ifdef NU_ENABLE_PPP +STATUS URT_Init_Port(DV_DEVICE_ENTRY *device) +{ + SD_PORT *uart; + STATUS ret_status; + + /* Get a pointer to the UART layer of this device. */ + uart = &((PPP_LAYER *) device->ppp_layer)->uart; + + /* Init the serial port, copy init parameters from the device + structure. */ + uart->com_port = device->dev_com_port; + uart->baud_rate = device->dev_baud_rate; + uart->data_bits = device->dev_data_bits; + uart->stop_bits = device->dev_stop_bits; + uart->parity = device->dev_parity; + uart->data_mode = device->dev_data_mode; + uart->vector = device->dev_vect; + uart->driver_options = device->dev_driver_options; + uart->communication_mode = MDM_TERMINAL_COMMUNICATION; + uart->sd_buffer_size = (2 * (PPP_MTU + PPP_FCS_SIZE + + PPP_MAX_PROTOCOL_SIZE + PPP_MAX_ADDR_CONTROL_SIZE)); + + /* Init the port */ + ret_status = NU_SD_Init_Port (uart); + + if (ret_status == NU_SUCCESS) + { + /* Copy the vector back into the device entry just in case + the UART driver changed it. */ + device->dev_vect = uart->vector; + } + + return (ret_status); + +} +#endif /* NU_ENABLE_PPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuc-fw/nucleus/demo/tmcal.c Mon Nov 11 10:17:08 2013 +0000 @@ -0,0 +1,23 @@ +/* + * FreeNucleus port by Spacefalcon the Outlaw + * + * This module implements the INT_Timer_Initialize() function + * for the proof-of-concept Calypso port. + * + * TIMER2 configuration is based on that used by OsmocomBB. + */ + +#include "calirq.h" +#include "caltimer.h" + +void +INT_Timer_Initialize() +{ + /* program the timer */ + TIMER2_REGS.cntl = CNTL_CLOCK_ENABLE; + TIMER2_REGS.load = 4062; + TIMER2_REGS.cntl = CNTL_CLOCK_ENABLE | CNTL_AUTO_RELOAD | CNTL_START; + /* now let it interrupt */ + INTH_REGS.ilr_irq[IRQ_TIMER2] = 0x7E; + INTH_REGS.mask_it_reg1 &= ~(1 << IRQ_TIMER2); +}
--- a/nuc-fw/nucleus/irqshell.S Mon Nov 11 09:56:23 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,584 +0,0 @@ -/* - * FreeNucleus Calypso port by Michael Spacefalcon - * - * This assembly module contains IRQ handler shell - * and some closely related support functions. - * - * The approach to IRQ handling implemented in the present version - * is exactly the same as was found in XVilka's original nucleus_plus.tar.gz - * code targeting OMAP1510. I personally consider it very dumb and - * suboptimal, but the present version is merely a proof of concept - - * changing as little as possible from our starting point will (hopefully) - * make it easier to get this code to compile, link and maybe even run. - */ - -#include "asm_defs.h" -#include "calirq.h" - - .code 32 - -/* - ********************************** - * GLOBAL VARIABLE DECLARATIONS * - ********************************** - */ - - .data - -@ Define vector table used by INT_IRQ to branch to necessary ISR - - .globl INT_IRQ_Vectors -INT_IRQ_Vectors: - .word INT_Interrupt_Shell @ Vector 0 - .word INT_Interrupt_Shell @ Vector 1 - .word INT_Timer_Interrupt @ Vector 2 - TIMER2 - .word INT_Interrupt_Shell @ Vector 3 - .word INT_Interrupt_Shell @ Vector 4 - .word INT_Interrupt_Shell @ Vector 5 - .word INT_Interrupt_Shell @ Vector 6 - .word INT_Interrupt_Shell @ Vector 7 - .word INT_Interrupt_Shell @ Vector 8 - .word INT_Interrupt_Shell @ Vector 9 - .word INT_Interrupt_Shell @ Vector 10 - .word INT_Interrupt_Shell @ Vector 11 - .word INT_Interrupt_Shell @ Vector 12 - .word INT_Interrupt_Shell @ Vector 13 - .word INT_Interrupt_Shell @ Vector 14 - .word INT_Interrupt_Shell @ Vector 15 - .word INT_Interrupt_Shell @ Vector 16 - .word INT_Interrupt_Shell @ Vector 17 - .word INT_Interrupt_Shell @ Vector 18 - .word INT_Interrupt_Shell @ Vector 19 - .word INT_Interrupt_Shell @ Vector 20 - -@ Define the order in which the interrupts will be executed by software(INT_IRQ) -@ Level 1 Interrupt Handler - .globl INT_IRQ_Priority -INT_IRQ_Priority: - .word 0 - .word 1 - .word 2 - .word 3 - .word 4 - .word 5 - .word 6 - .word 7 - .word 8 - .word 9 - .word 10 - .word 11 - .word 12 - .word 13 - .word 14 - .word 15 - .word 16 - .word 17 - .word 18 - .word 19 - .word 20 -INT_Priority_End: - - .text - -/* - ************************************************************************ - * - * FUNCTION - * - * INT_Setup_Vector - * - * DESCRIPTION - * - * This function sets up the specified vector with the new vector - * value. The previous vector value is returned to the caller. - * - * - * Major Revision: - * - * M. Kyle Craig, Accelerated Technology, Inc. - * - * - * - * CALLED BY - * - * Application - * TCC_Register_LISR Register LISR for vector - * - * CALLS - * - * None - * - * INPUTS - * - * vector Vector number to setup - * new Pointer to new assembly - * language ISR - * - * OUTPUTS - * - * old vector contents - * - * HISTORY - * - * NAME DATE REMARKS - * - * W. Lamie 08-27-1994 Created initial version 1.0 - * D. Lamie 08-27-1994 Verified version 1.0 - * - ************************************************************************ - */ - -@VOID *INT_Setup_Vector(INT vector, VOID *new) -@{ - - .globl INT_Setup_Vector -INT_Setup_Vector: - -@VOID *old_vector; /* Old interrupt vector */ -@VOID **vector_table; /* Pointer to vector table */ - -@ Calculate the starting address of the actual vector table. -@ vector_table = (VOID **) 0; - -@ Pickup the old interrupt vector. -@ old_vector = vector_table[vector]; -@ -@ Setup the new interrupt vector. -@ vector_table[vector] = new; -@ -@ Return the old interrupt vector. -@ return(old_vector); - - - LDR r2, =INT_IRQ_Vectors @ Load the vector table address - MOV r0, r0, LSL #2 @ Multiply vector by 4 to get offset into table - LDR r3, [r2,r0] @ Load the old pointer - STR r1, [r2,r0] @ Store the new pointer into the vector table - - MOV r0, r3 @ Put the old pointer into the return register - - BX lr @ Return to caller - -@} - -/* - ************************************************************************ - * - * FUNCTION - * - * INT_Retrieve_Shell - * - * DESCRIPTION - * - * This function retrieves the pointer to the shell interrupt - * service routine. The shell interrupt service routine calls - * the LISR dispatch routine. - * - * - * Major Revision: - * - * M. Kyle Craig, Accelerated Technology, Inc. - * - * - * - * CALLED BY - * - * TCC_Register_LISR Register LISR for vector - * - * CALLS - * - * None - * - * INPUTS - * - * vector Vector number to setup - * - * OUTPUTS - * - * shell pointer - * - * HISTORY - * - * NAME DATE REMARKS - * - * W. Lamie 08-27-1994 Created initial version 1.0 - * D. Lamie 08-27-1994 Verified version 1.0 - * - ************************************************************************ - */ - -@VOID *INT_Retrieve_Shell(INT vector) -@{ - - .globl INT_Retrieve_Shell -INT_Retrieve_Shell: - - @ Return the LISR Shell interrupt routine. - @ return(INT_Vectors[vector]); - - LDR r1, =INT_IRQ_Vectors @ Load the vector table address - MOV r0, r0, LSL #2 @ Multiply vector by 4 to get offset into table - LDR r0, [r1,r0] @ Load interrupt handler pointer into return register - - BX lr @ Return to caller - - -@} - -/* - ************************************************************************ - * - * FUNCTION - * - * _INT_IRQ - * - * DESCRIPTION - * - * This routine is the board-specific section for - * level 1 interrupt handling - * - * CALLED BY - * - * None - * - * CALLS - * - * TMT_Timer_Interrupt - * - * INPUTS - * - * None - * - * - * OUTPUTS - * - * None - * - * HISTORY - * - * NAME DATE REMARKS - * - * B. Ronquillo 05-10-00 Created initial version 1.0 - * - ************************************************************************ - */ - - .globl _INT_IRQ -_INT_IRQ: - - STMDB sp!,{r0-r4} @ Save r0-r4 on temporary IRQ stack - SUB lr,lr,#4 @ Adjust IRQ return address - -/* - ******************************** - * Begin Hardware Specific Code * - ******************************** - */ - - LDR r3, =INTH_BASE_ADDR @ load Interrupt Control Base - @ Get enable register value - @ original instr was: LDR r4, [r3,#INT_CNTRL_MIR] - @ but on the Calypso we have to read two 16-bit regs - ldrh r0, [r3, #MASK_IT_REG1] - ldrh r1, [r3, #MASK_IT_REG2] - @ now combine them into a 32-bit word in r4 for the old code to work as-is - orr r4, r0, r1, lsl #16 - -/* - ****************************** - * End Hardware Specific Code * - ****************************** - */ - - STMDB sp!,{r4} @ Put the enable register value on the IRQ stack - MVN r4,#0 @ Start with 0xFFFFFFFF to allow nesting of interrupts - -/* - ******************************** - * Begin Hardware Specific Code * - ******************************** - */ - - @ Read Pending reg - @ original instr was: LDR r2, [r3,#INT_CNTRL_ITR] - @ do the same trick as we did for the mask regs - ldrh r0, [r3, #IT_REG1] - ldrh r1, [r3, #IT_REG2] - orr r2, r0, r1, lsl #16 - -/* - ****************************** - * End Hardware Specific Code * - ****************************** - */ - - LDR r3, =INT_IRQ_Priority @ Get the Priority table address - -IRQ_VECTOR_LOOP: - LDR r0, [r3,#0] @ Load first vector to be checked from priority table - MOV r1, #1 @ Build mask - MOV r1, r1, LSL r0 @ Use vector number to set mask to correct bit position - TST r1, r2 @ Test if pending bit is set - BNE IRQ_VECTOR_FOUND @ If bit is set, branch to found section... - - BIC r4,r4,r1 @ Clear mask bit to keep higher priority ints active - ADD r3, r3, #4 @ Move to next word in the priority table - LDR r0, =INT_Priority_End @ Load the end address for the priority table - CMP r0, r3 @ Make sure not at the end of the table (shouldn't happen!) - BNE IRQ_VECTOR_LOOP @ Continue to loop if not at the end of the table - - @ No bits in pending register set, restore registers and exit interrupt servicing - ADD sp,sp,#4 @ Adjust sp above IRQ enable value - LDMIA sp!,{r0-r4} @ Restore r0-r4 - STMDB sp!,{lr} @ Put return address for IRQ on stack - LDMIA sp!,{pc}^ @ return to the point of the exception and restore SPSR - -IRQ_VECTOR_FOUND: - -/* - ******************************** - * Begin Hardware Specific Code * - ******************************** - */ - - LDR r3, =INTH_BASE_ADDR @ load Interrupt Control Base - - MVN r2, r1 @ Get the inverse of the interrupt vector - @ Write a zero to the interrupt being handled (IT_REGn) - cmp r0, #16 - strloh r2, [r3, #IT_REG1] - mov r2, r2, lsr #16 - strhsh r2, [r3, #IT_REG2] - - @ Read the Mask reg - just like we did before - ldrh r1, [r3, #MASK_IT_REG1] - ldrh r2, [r3, #MASK_IT_REG2] - orr r2, r1, r2, lsl #16 - @ was LDR r2, [r3,#INT_CNTRL_MIR] - - ORR r4, r2, r4 @ Turn off lower priority pending bits and currently masked bits - - @ write both mask registers - @ was STR r4, [r3,#INT_CNTRL_MIR] - strh r4, [r3, #MASK_IT_REG1] - mov r1, r4, lsr #16 - strh r1, [r3, #MASK_IT_REG2] - - MOV r1, #1 @ Clear the pending interrupt - STRH r1, [r3,#IRQ_CTRL] @ by writing a 1 to the Control Reg - -/* - ****************************** - * End Hardware Specific Code * - ****************************** - */ - - LDR r3, =INT_IRQ_Vectors @ Get IRQ vector table address - MOV r2, r0, LSL #2 @ Multiply vector by 4 to get offset into table - ADD r3, r3, r2 @ Adjust vector table address to correct offset - LDR r2, [r3,#0] @ Load branch address from vector table - - MOV PC, r2 @ Jump to correct branch location based on vector table - -@ END: INT_IRQ - -/* - ************************************************************************ - * - * FUNCTION - * - * INT_Interrupt_Shell - * - * DESCRIPTION - * - * Handles all interrupts which use NU_Register_LISR. - * - * - * CALLED BY - * - * INT_IRQ - * - * CALLS - * - * TCT_Dispatch_LISR - * TCT_Interrupt_Context_Restore - * - * INPUTS - * - * vector (register r0) - * - * OUTPUTS - * - * None - ************************************************************************ - */ - - .globl INT_Interrupt_Shell -INT_Interrupt_Shell: - - MOV r4,lr @ Put IRQ return address into r4 - - BL TCT_Interrupt_Context_Save - - BL TCC_Dispatch_LISR - - MRS r1,CPSR @ Pickup current CPSR - BIC r1,r1,#MODE_MASK @ Clear the mode bits - ORR r1,r1,#(IRQ_MODE_OR_LOCKOUT) @ Set the IRQ mode bits and Lockout interrupts - MSR CPSR,r1 @ Lockout interrupts/change to IRQ mode - -/* - ******************************** - * Begin Hardware Specific Code * - ******************************** - */ - LDMIA sp!,{r1} @ Get IRQ enable value off IRQ stack - - LDR r2, =INTH_BASE_ADDR @ Get IRQ0 base register address - @ write it into both mask regs - @was STR r1,[r2,#INT_CNTRL_MIR] - strh r1, [r2, #MASK_IT_REG1] - mov r1, r1, lsr #16 - strh r1, [r2, #MASK_IT_REG2] -/* - ****************************** - * End Hardware Specific Code * - ****************************** - */ - - MRS r1,CPSR @ Pickup current CPSR - BIC r1,r1,#MODE_MASK @ Clear the mode bits - ORR r1,r1,#SUP_MODE @ Set the SVC mode bits - MSR CPSR,r1 @ Change to SVC mode - - B TCT_Interrupt_Context_Restore - -/* - ************************************************************************ - * - * FUNCTION - * - * INT_Timer_Interrupt - * - * DESCRIPTION - * - * This routine is the board-specific section of the timer - * interrupt handling - * - * CALLED BY - * - * None - * - * CALLS - * - * TMT_Timer_Interrupt - * - * INPUTS - * - * None - * - * - * OUTPUTS - * - * None - * - * HISTORY - * - * NAME DATE REMARKS - * - * B.Ronquillo 05-10-00 Created initial version 1.0 - * - ************************************************************************ - */ - - .globl INT_Timer_Interrupt -INT_Timer_Interrupt: - -/* - ******************************** - * Begin Hardware Specific Code * - ******************************** - * Clear the pending timer interrupt - * - * This is done in the INT_IRQ function by writing a zero to the - * timer bit. - * - ****************************** - * End Hardware Specific Code * - ****************************** - */ - - MOV r4,lr @ Put IRQ return address into r4 - - BL TCT_Interrupt_Context_Save - - BL TMT_Timer_Interrupt @ Call the timer interrupt - @ processing. - - MRS r1,CPSR @ Pickup current CPSR - BIC r1,r1,#MODE_MASK @ Clear the mode bits - ORR r1,r1,#IRQ_MODE @ Set the IRQ mode bits - MSR CPSR,r1 @ Change to IRQ mode - -/* - ******************************** - * Begin Hardware Specific Code * - ******************************** - */ - LDMIA sp!,{r1} @ Get IRQ enable value off IRQ stack - - LDR r2, =INTH_BASE_ADDR @ Get IRQ0 base register address - @ write it into both mask regs - @was STR r1,[r2,#INT_CNTRL_MIR] - strh r1, [r2, #MASK_IT_REG1] - mov r1, r1, lsr #16 - strh r1, [r2, #MASK_IT_REG2] -/* - ****************************** - * End Hardware Specific Code * - ****************************** - */ - - MRS r1,CPSR @ Pickup current CPSR - BIC r1,r1,#MODE_MASK @ Clear the mode bits - ORR r1,r1,#SUP_MODE @ Set the SVC mode bits - MSR CPSR,r1 @ Change to SVC mode - - B TCT_Interrupt_Context_Restore - -@} -@ End of INT_Timer_Interrupt - -/* - * INT_Interrupt_Init function written by Michael Spacefalcon - * for the FreeNucleus Calypso port - takes the place of - * INT_Install_Vector_Table, called from INT_Initialize. - */ - - .globl INT_Interrupt_Init -INT_Interrupt_Init: - -@ first mask all interrupts in the INTH - - ldr r0, =INTH_BASE_ADDR - mvn r1, #0 - strh r1, [r0, #MASK_IT_REG1] - strh r1, [r0, #MASK_IT_REG2] - -@ now install our IRQ vector into the magic IRAM jump table slot - - ldr r0, =_INT_IRQ - mov r1, #0x800000 - str r0, [r1, #0x14] - -@ we are done! - bx lr - -/* - * Need to define an INT_Vectors_Loaded() function - * that returns 1. - */ - .globl INT_Vectors_Loaded -INT_Vectors_Loaded: - mov r0, #1 - bx lr
--- a/nuc-fw/nucleus/sdc.c Mon Nov 11 09:56:23 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1033 +0,0 @@ -/************************************************************************** -* -* Copyright Mentor Graphics Corporation 2002 -* All Rights Reserved. -* -* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS -* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS -* SUBJECT TO LICENSE TERMS. -* -*************************************************************************** -*************************************************************************** -* -* FILE NAME VERSION -* -* sdc.c Nucleus PLUS\ARM925\Code Composer 1.14.1 -* -* DESCRIPTION -* -* This file contains the Serial Driver specific functions. -* -* DATA STRUCTURES -* -* SD_PORT * : An array of pointers to serial port structures. -* -* FUNCTIONS -* -* SDC_Init_Port -* SDC_Date_Ready -* SDC_Put_String -* SDC_LISR -* SDC_Get_Char -* SDC_Put_Char -* SDC_Set_Baud_Rate -* -* DEPENDENCIES -* -* nucleus.h -* sd_defs.h -* sd_extr.h -* target.h -* protocol.h -* externs.h -* ppp.h -* -* HISTORY -* -* NAME DATE REMARKS -* -* B. Ronquillo 08-28-2002 Released version 1.14.1 -****************************************************************************/ - -#include "nucleus.h" -#include "sd_defs.h" -#include "sd_extr.h" -#include "calirq.h" - -#ifdef NU_ENABLE_PPP - -#include "net\target.h" -#include "net\inc\externs.h" -#include "net\inc\tcp_errs.h" -#include "ppp\inc\ppp.h" - -#endif /* NU_ENABLE_PPP */ - -extern NU_MEMORY_POOL System_Memory; - -/* Define a small array to hold pointers to the two UART data - structures. This is used by the LISR to find the correct - data structure for the interrupt being handled. */ -SD_PORT *SDC_Port_List[SD_MAX_UARTS]; - - -/* Define prototypes for functions local to this module. */ - - /**************** Begin Port Specific Section **************/ -#ifdef GRAFIX_MOUSE -extern NU_HISR Mouse_HISR; -#endif - /**************** End Port Specific Section **************/ - -static VOID SDC_Set_Baud_Rate(UINT32, SD_PORT *); -/*************************************************************************** -* FUNCTION -* -* SDC_Init_Port -* -* DESCRIPTION -* -* This function intializes the COM port that will be used for PPP -* communications. -* -* -* INPUTS -* -* SD_PORT * : device initialization structure. -* -* OUTPUTS -* -* STATUS : Returns NU_SUCCESS if successful initialization, -* else a negative value is returned. -* -****************************************************************************/ -STATUS SDC_Init_Port(SD_PORT *uart) -{ -STATUS status = NU_SUCCESS; -INT32 int_level, /* old interrupt level */ - tInt; -UINT8 temp_byte; -UINT32 temp_word, int_val; -CHAR sem_name[8]; -static INT num_ports = 0; -VOID (*old_lisr)(INT); /* old LISR */ - -#ifdef GRAFIX_MOUSE - if ((uart->communication_mode == SERIAL_MODE) || - (uart->communication_mode == SERIAL_MOUSE)) -#else - if (uart->communication_mode == SERIAL_MOUSE) - { - status = NU_INVALID_MOUSE_MODE; - } - else if (uart->communication_mode == SERIAL_MODE) -#endif - - { - - /* Check for max allowed UARTS. */ - if (num_ports >= SD_MAX_UARTS) - - /* We have already initialized the max allowed UARTS. */ - status = NU_UART_LIST_FULL; - } - - if (status != NU_SUCCESS) - return (status); - - /* Check the supplied parity */ - else if ((uart->parity != SD_PARITY_NONE) && - (uart->parity != SD_PARITY_EVEN) && - (uart->parity != SD_PARITY_ODD)) - - /* The supplied parity is not valid */ - status = NU_INVALID_PARITY; - - /* Check the supplied number of data bits */ - else if ((uart->data_bits != SD_DATA_BITS_7) && - (uart->data_bits != SD_DATA_BITS_8)) - - /* The supplied data bits value is not valid */ - status = NU_INVALID_DATA_BITS; - - /* Check the supplied number of stop bits */ - else if ((uart->stop_bits != SD_STOP_BITS_1) && - (uart->stop_bits != SD_STOP_BITS_2)) - - /* The supplied stop bits value is not valid */ - status = NU_INVALID_STOP_BITS; - - /* Verify the baud rate is within acceptable range */ - else if ((uart->baud_rate < 300) || (uart->baud_rate > 115200)) - - /* The baud rate is out of range */ - status = NU_INVALID_BAUD; - - /************** Begin Port Specific Section ****************/ - - /* Validate the com port. */ - else if ((uart->com_port == SD_UART1) || - (uart->com_port == SD_UART2)) - { - /* Handle UARTA */ - if (uart->com_port == SD_UART_MODEM) - { - /* Set the vector inside this structure */ - uart->vector = IRQ_UART_MODEM; - - /* Set the base address for this UART. */ - uart->base_address = SD_UART_MODEM_BASE; - } - else /* Otherwise handle UARTB. */ - { - /* Set the vector inside this structure */ - uart->vector = IRQ_UART_IRDA; - - /* Set the base address for this UART. */ - uart->base_address = SD_UART_IRDA_BASE; - } - } - else - - /************** End Port Specific Section **************/ - - /* Not a supported port. */ - status = NU_INVALID_COM_PORT; - -#ifdef GRAFIX_MOUSE - if ((uart->communication_mode == SERIAL_MODE) || - (uart->communication_mode == SERIAL_MOUSE)) -#else - if (uart->communication_mode == SERIAL_MODE) -#endif - - { - /* Make sure the port was valid and the LISR was - registered. Then create the semaphore used to make - the SD_Put_String service thread safe. */ - if (status == NU_SUCCESS) - { - /* Allocate memory for the semaphore control block. */ - status = NU_Allocate_Memory(&System_Memory,(VOID**) &uart->sd_semaphore, - sizeof(NU_SEMAPHORE), NU_NO_SUSPEND); - -#if 0 -/* original code */ - for(tInt=0; tInt < sizeof(NU_SEMAPHORE); tInt++) - /* Fixed SPR 211. Changed type from (UINT32) to (CHAR *) */ - SD_OUTBYTE((CHAR *) uart->sd_semaphore + tInt, 0x00); -#else - bzero(uart->sd_semaphore, sizeof(NU_SEMAPHORE)); -#endif - - if (status == NU_SUCCESS) - { - /* Build the name. */ - sem_name[0] = 's'; - sem_name[1] = 'e'; - sem_name[2] = 'r'; - sem_name[3] = 'i'; - sem_name[4] = 'a'; - sem_name[5] = 'l'; - sem_name[6] = '_'; - sem_name[7] = (CHAR)(0x30 + num_ports); - - status = NU_Create_Semaphore (uart->sd_semaphore, sem_name, - 1, NU_FIFO); - } - } - - /* Make sure all the above was completed. Then store off this - UART stucture and initialize the chip. */ - if (status == NU_SUCCESS) - { - SDC_Port_List[num_ports++] = uart; - } - } - - if (status == NU_SUCCESS) - { - /* Allocate memory for the data buffers. PPP only requires a TX - buffer so the allocation will be a little different for PPP mode. */ -#ifdef GRAFIX_MOUSE - if ((uart->communication_mode == SERIAL_MODE) || - (uart->communication_mode == SERIAL_MOUSE)) -#else - if (uart->communication_mode == SERIAL_MODE) -#endif - - { - status = NU_Allocate_Memory (&System_Memory,(VOID**) &uart->tx_buffer, - (2 * uart->sd_buffer_size), NU_NO_SUSPEND); - - /* Set the RX buffer to just past the TX buffer. */ - uart->rx_buffer = (CHAR *)(uart->tx_buffer + uart->sd_buffer_size); - } - else - { - status = NU_Allocate_Memory (&System_Memory,(VOID**) &uart->tx_buffer, - uart->sd_buffer_size, NU_NO_SUSPEND); - } - - if (status == NU_SUCCESS) - { - /* Setup the RX SD buffer */ - uart->rx_buffer_read = uart->rx_buffer_write = 0; - - uart->rx_buffer_status = NU_BUFFER_EMPTY; - - /* Setup the TX SD buffer */ - uart->tx_buffer_read = uart->tx_buffer_write = 0; - uart->tx_buffer_status = NU_BUFFER_EMPTY; - } - } - - if (status == NU_SUCCESS) - { - /* Disable interrupts */ - int_level = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS); - - /* Initialize the UART */ - - /************** Begin Port Specific Section *************/ - - /* Configure the Mode Definition Register */ - /* Set the serial port to UART mode */ - SD_OUTBYTE(uart->base_address + MDR_OFFSET, MDR_UART_MODE); - - /* Reset the TX/RX FIFOs */ - SD_OUTBYTE(uart->base_address + FCR_OFFSET, FCR_FIFO_RESET); - - /* Setup baud rate */ - SDC_Set_Baud_Rate(uart->baud_rate, uart); - - /* Set the modem control register. Set DTR, RTS to output to LOW, - and set INT output pin to normal operating mode */ - SD_OUTBYTE (uart->base_address + MCR_OFFSET, (MCR_DTR_LOW | MCR_RTS_LOW)); - - /* Setup parity, data bits, and stop bits */ - SD_OUTBYTE (uart->base_address + LCR_OFFSET, - (LCR_NO_BREAK|uart->parity|uart->data_bits|uart->stop_bits )); - - /* Setup Fifo trigger level and enable FIFO */ - SD_OUTBYTE (uart->base_address + FCR_OFFSET, 0); - - /* Register the interrupt handler for the UART receiver */ - status = NU_Register_LISR(uart->vector, SDC_LISR, &old_lisr); - - if (status == NU_SUCCESS) - { - /* Enable the RX interrupts */ - SD_OUTBYTE (uart->base_address + IER_OFFSET, IER_RX_HOLDING_REG); - - if(uart->com_port == SD_UART_MODEM) - { - /* Enable the UART interrupt globally */ - INTH_REGS.ilr_irq[IRQ_UART_MODEM] = 0x7C; - INTH_REGS.mask_it_reg1 &= ~(1 << IRQ_UART_MODEM); - } - else /* Handle UART B */ - { - /* Enable the UART interrupt globally */ - INTH_REGS.ilr_irq[IRQ_UART_IRDA] = 0x7C; - INTH_REGS.mask_it_reg2 &= ~(1 << (IRQ_UART_IRDA - 16)); - } - - } - - /************** End Port Specific Section *************/ - - - /* Initialize the error counters. */ - uart->parity_errors = - uart->frame_errors = - uart->overrun_errors = - uart->busy_errors = - uart->general_errors = 0; - - /* Restore interrupts to previous level */ - NU_Local_Control_Interrupts(int_level); - } - - return (status); -} -/*************************************************************************** -* FUNCTION -* -* SDC_Put_Char -* -* DESCRIPTION -* -* This writes a character out to the serial port. -* -* INPUTS -* -* UINT8 : Character to to be written to the serial port. -* SD_PORT * : Serial port to send the char to. -* -* OUTPUTS -* -* none -* -****************************************************************************/ -VOID SDC_Put_Char(UINT8 ch, SD_PORT *uart) -{ -INT int_level; /* old interrupt level */ -UINT32 temp_long; - -#ifdef GRAFIX_MOUSE - if ((uart->communication_mode == SERIAL_MODE) || - (uart->communication_mode == SERIAL_MOUSE)) -#else - if (uart->communication_mode == SERIAL_MODE) -#endif - - { - /* If the buffer is full wait for it to empty a little. */ - while (uart->tx_buffer_status == NU_BUFFER_FULL); - - /* Disable interrupts */ - int_level = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS); - - /* Check the transmit buffer status. If it has data already - just add this byte to the buffer. */ - if ( uart->tx_buffer_status != NU_BUFFER_EMPTY) - { - /* Add byte to buffer. */ - uart->tx_buffer[uart->tx_buffer_write++] = ch; - - /* Check for wrap of buffer. */ - if(uart->tx_buffer_write == uart->sd_buffer_size) - uart->tx_buffer_write = 0; - - /* Check for full buffer. */ - if (uart->tx_buffer_write == uart->tx_buffer_read) - uart->tx_buffer_status = NU_BUFFER_FULL; - - /* Restore interrupts to previous level */ - NU_Local_Control_Interrupts(int_level); - } - else - { - /* Otherwise send the data. */ - - /* Restore interrupts to previous level */ - NU_Local_Control_Interrupts(int_level); - - /* Add byte to buffer. */ - uart->tx_buffer[uart->tx_buffer_write++] = ch; - - /* Check for wrap of buffer. */ - if(uart->tx_buffer_write == uart->sd_buffer_size) - uart->tx_buffer_write = 0; - - /* Set status */ - uart->tx_buffer_status = NU_BUFFER_DATA; - - /**************** Begin Port Specific Section **************/ - - /* Wait until the transmitter buffer is empty */ - while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); - - /* Transmit the character */ - SD_OUTBYTE (uart->base_address + THR_OFFSET, ch); - - /* Enable the TX interrupts */ - temp_long = SD_INBYTE (uart->base_address + IER_OFFSET); - temp_long |= IER_TX_HOLDING_REG; - SD_OUTBYTE (uart->base_address + IER_OFFSET, temp_long); - - } - - } /* endif mode */ - else - { - /* Wait until the transmitter buffer is empty */ - while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); - - /* Transmit the character */ - SD_OUTBYTE (uart->base_address + THR_OFFSET, ch); - -#ifndef PPP_POLLED_TX - - /* Enable the TX interrupts */ - temp_long = SD_INBYTE (uart->base_address + IER_OFFSET); - temp_long |= IER_TX_HOLDING_REG; - SD_OUTBYTE (uart->base_address + IER_OFFSET, temp_long); - -#endif /* PPP_POLLED_TX */ - - - } - - /***************** End Port Specific Section ***************/ - -} - -/*************************************************************************** -* FUNCTION -* -* SDC_LISR -* -* DESCRIPTION -* -* This is the entry function for the receive ISR that services the UART -* in the ARM925. -* -* INPUTS -* -* INT : Interrupt vector -* -* OUTPUTS -* -* none -* -****************************************************************************/ -VOID SDC_LISR(INT vector) -{ - -SD_PORT *uart; -CHAR receive; -UINT8 status; -UINT8 int_status; -UINT8 vector_found = NU_FALSE; -UINT8 ier_val; - - -#ifdef NU_ENABLE_PPP -DV_DEVICE_ENTRY *device; -#endif /* NU_ENABLE_PPP */ - - for(receive = 0 ; (SDC_Port_List[receive] != NU_NULL) && - (receive < SD_MAX_UARTS) && !vector_found ; receive++) - { - /* See if we found one. Better have since we got an interrupt - from one. */ - if (SDC_Port_List[receive] -> vector == vector) - { - /* Point our local structure to it. */ - uart = SDC_Port_List[receive]; - vector_found = NU_TRUE; - } - } - -#ifdef NU_ENABLE_PPP - - /* Find the device for this interrupt */ - if ( (device = DEV_Get_Dev_For_Vector(vector)) != NU_NULL) - { - /* Get the address of the uart structure for this device. */ - uart = &((PPP_LAYER *) device->ppp_layer)->uart; - vector_found = NU_TRUE; - } - -#endif /* NU_ENABLE_PPP */ - - if (vector_found == NU_TRUE) - { - /**************** Begin Port Specific Section **************/ - - /* Get the interrupt status register value */ - int_status = SD_INBYTE(uart->base_address + IIR_OFFSET); - - /* Loop until all interrupts are processed */ - while (!(int_status & IIR_PENDING)) - { - /* Check for a receive interrupt */ - if (((int_status & IIR_RX_LINE_STAT) ==IIR_RX_LINE_STAT) || - ((int_status & IIR_RX_RDY) ==IIR_RX_RDY) || - ((int_status & IIR_RX_TIMEOUT) ==IIR_RX_TIMEOUT) ) - { - /* Process every character in the receive FIFO */ - status = SD_INBYTE(uart->base_address + LSR_OFFSET); - - while (status & LSR_RX_DATA_READY) - { - /* Get character from receive FIFO */ - receive = SD_INBYTE (uart->base_address + RHR_OFFSET); - - /* Check if receive character has errors */ - if (status & (LSR_FRAMING_ERROR | LSR_PARITY_ERROR)) - { - /* Increment parity errors if necessary */ - uart->parity_errors += ((status & LSR_PARITY_ERROR) == LSR_PARITY_ERROR); - - /* Increment framing errors if necessary */ - uart->frame_errors += ((status & LSR_FRAMING_ERROR) == LSR_FRAMING_ERROR); - } - else // no framing or parity errors - { - /* Increment overrun errors if necessary */ - uart->overrun_errors += ((status & LSR_RX_DATA_READY) == LSR_RX_DATA_READY); - - /* Switch based on UART mode */ - switch(uart->communication_mode) - { - case SERIAL_MODE: - - if (uart->rx_buffer_status != NU_BUFFER_FULL) - { - - /* Put the character into the buffer */ - uart->rx_buffer[uart->rx_buffer_write++] = receive; - - /* Check for wrap of buffer. */ - if(uart->rx_buffer_write == uart->sd_buffer_size) - uart->rx_buffer_write = 0; - - /* Set status field based on latest character */ - if (uart->rx_buffer_write == uart->rx_buffer_read) - uart->rx_buffer_status = NU_BUFFER_FULL; - else - uart->rx_buffer_status = NU_BUFFER_DATA; - } - else - uart->busy_errors++; - - break; - -#ifdef NU_ENABLE_PPP - /* call PPP processing functions */ - - case MDM_NETWORK_COMMUNICATION: - /* Call this devices receive routine */ - device->dev_receive(device); - break; - - case MDM_TERMINAL_COMMUNICATION: - default: - MDM_Receive(device); - break; -#endif /* NU_ENABLE_PPP */ - } - } - - /* Check the rx buffer status again... */ - status = SD_INBYTE(uart->base_address + LSR_OFFSET); - - } - - } // if ((status & IIR_TYPE_MASK) == IIR_Rx_Rdy) - - - int_status = SD_INBYTE(uart->base_address + IER_OFFSET); - - if (int_status & IER_TX_HOLDING_REG) - { - if (uart->communication_mode == SERIAL_MODE) - { - /* Bump the read pointer past the byte that was just - transmitted. */ - ++(uart->tx_buffer_read); - - /* Check for wrap of buffer. */ - if(uart->tx_buffer_read == uart->sd_buffer_size) - uart->tx_buffer_read = 0; - - /* Update the status. */ - if (uart->tx_buffer_write == uart->tx_buffer_read) - { - uart->tx_buffer_status = NU_BUFFER_EMPTY; - - /* Since it is now empty disable the TX interrupt! */ - ier_val = SD_INBYTE(uart->base_address + IER_OFFSET); - ier_val &= ~IER_TX_HOLDING_REG; - SD_OUTBYTE(uart->base_address + IER_OFFSET, ier_val); - } - else - { - - /* Wait until the transmitter buffer is empty */ - while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); - - /* Send the next byte in the queue. */ - SD_OUTBYTE(uart->base_address + THR_OFFSET, uart->tx_buffer[uart->tx_buffer_read]); - - /* Update the status. */ - uart->tx_buffer_status = NU_BUFFER_DATA; - } - } -#ifdef NU_ENABLE_PPP - else - { -#ifndef PPP_POLLED_TX - /* Check for a transmit interrupt. */ - /* Is there another byte in the TX buffer to send? */ - if (uart->tx_buffer_read != uart->tx_buffer_write) - { - /* Wait until the transmitter buffer is empty */ - while (!(SD_INBYTE (uart->base_address + LSR_OFFSET) & LSR_TX_HOLD_EMPTY)); - - /* Send the next byte in the queue. */ - SD_OUTBYTE (uart->base_address + THR_OFFSET, uart->tx_buffer[uart->tx_buffer_read++]); - - /* Check for wrap of buffer. */ - uart->tx_buffer_read %= uart->sd_buffer_size; - } - else - { - - /* Since it is now empty disable the TX interrupt! */ - ier_val = SD_INBYTE (uart->base_address + IER_OFFSET); - ier_val &= ~IER_TX_HOLDING_REG; - SD_OUTBYTE (uart->base_address + IER_OFFSET, ier_val); - - /* Only activate the HISR if we are tranmitting - network data. */ - if (uart->communication_mode == MDM_NETWORK_COMMUNICATION) - { - /* Add this device to the list of PPP devices that have finished - sending a packet. */ - _ppp_tx_dev_ptr_queue [_ppp_tx_dev_ptr_queue_write++] = device; - - /* Activate the HISR that will take care of processing the - next packet in queue, if one is ready. */ - NU_Activate_HISR (&PPP_TX_HISR); - - /* Check for wrap of ring buffer. */ - - _ppp_tx_dev_ptr_queue_write %= PPP_MAX_TX_QUEUE_PTRS; - - } - } -#endif /* PPP_POLLED_TX */ - } -#endif /* NU_ENABLE_PPP */ - } - - /* Get the interrupt status register value */ - int_status = SD_INBYTE(uart->base_address + IIR_OFFSET); - } - - /**************** End Port Specific Section **************/ - - /* No port is associated with the vector */ - } - else - { - ERC_System_Error(NU_UNHANDLED_INTERRUPT); - } -} - -/**************************************************************************** -* FUNCTION -* -* SDC_Set_Baud_Rate -* -* DESCRIPTION -* -* This function sets the UART buad rate. -* -* INPUTS -* -* UINT32 : The new baud rate. -* SD_PORT * : Serial port to set the baud rate. -* -* OUTPUTS -* -* none -* -****************************************************************************/ -VOID SDC_Set_Baud_Rate(UINT32 baud_rate, SD_PORT *uart) -{ - UNSIGNED baud_div; - UINT32 temp_long; - - /**************** Begin Port Specific Section **************/ - - /* Write to the divisor latch bit to enable the DLH and DLL registers */ - temp_long = SD_INBYTE(uart->base_address + LCR_OFFSET); - SD_OUTBYTE (uart->base_address + LCR_OFFSET, LCR_DIV_EN); - - /* Set the baud rate */ - baud_div = 115200 * 7 / uart->baud_rate; - - /* Put LSB in DLL Reg */ - SD_OUTBYTE (uart->base_address + DLL_OFFSET, baud_div); - - /* Put MSB in DLH Reg */ - SD_OUTBYTE (uart->base_address + DLH_OFFSET, (baud_div >> 8)); - - /* Disable the Divisor Latch bit */ - SD_OUTBYTE (uart->base_address + LCR_OFFSET, temp_long & ~LCR_DIV_EN); - /**************** End Port Specific Section ****************/ - -} -/**************************************************************************** -* FUNCTION -* -* SDC_Get_Char -* -* DESCRIPTION -* -* This function reads the last received character from the UART. -* -* INPUTS -* -* SD_PORT * : Serial port to get the char from. -* -* OUTPUTS -* -* CHAR : Character read -* -****************************************************************************/ -CHAR SDC_Get_Char(SD_PORT *uart) -{ - CHAR ch = NU_NULL; - -#ifdef GRAFIX_MOUSE - if ((uart->communication_mode == SERIAL_MODE) || - (uart->communication_mode == SERIAL_MOUSE)) -#else - if (uart->communication_mode == SERIAL_MODE) -#endif - - { - if ((uart->rx_buffer_status == NU_BUFFER_FULL) || - (uart->rx_buffer_status == NU_BUFFER_DATA)) - { - /* Store the character to be returned */ - ch = uart->rx_buffer[uart->rx_buffer_read++]; - - /* If read pointer is at end, wrap it around */ - if (uart->rx_buffer_read == uart->sd_buffer_size) - uart->rx_buffer_read = 0; - - /* Set the status to reflect removal of the character */ - if (uart->rx_buffer_write == uart->rx_buffer_read) - uart->rx_buffer_status = NU_BUFFER_EMPTY; - else - uart->rx_buffer_status = NU_BUFFER_DATA; - } - - return (ch); - } /* endif mode */ - -#ifdef NU_ENABLE_PPP - else if (uart->communication_mode == MDM_TERMINAL_COMMUNICATION || - uart->communication_mode == MDM_NETWORK_COMMUNICATION) - - /**************** Begin Port Specific Section **************/ - - return ((UINT8)SD_INBYTE (uart->base_address + RHR_OFFSET)); - - /**************** End Port Specific Section ****************/ - -#endif /* NU_ENABLE_PPP */ - - /* Execution should never reach this point, this return was added - in response to the 'implicit return' compiler warning */ - - return (ch); -} - -/**************************************************************************** -* FUNCTION -* -* SDC_Carrier -* -* DESCRIPTION -* -* This function checks for a carrier. -* -* INPUTS -* -* none -* -* OUTPUTS -* -* STATUS : The status of the detection. -* -****************************************************************************/ -STATUS SDC_Carrier(SD_PORT *uart) -{ - return (NU_TRUE); -} - -/**************************************************************************** - Note: All functions below this point are generic and should not require - any changes to support other UARTS. - ****************************************************************************/ - -/**************************************************************************** -* FUNCTION -* -* SDC_Put_String -* -* DESCRIPTION -* -* This writes a null-terminated string out to the serial port. -* -* INPUTS -* -* CHAR * : String to be written to the serial port. -* SD_PORT * : Serial port to send the string to. -* -* OUTPUTS -* -* none -* -****************************************************************************/ -VOID SDC_Put_String(CHAR *str, SD_PORT *uart) -{ - - /* Grab the semaphore so that strings between threads - do not get mixed. */ - if (NU_Obtain_Semaphore(uart->sd_semaphore, NU_SUSPEND) == NU_SUCCESS) - { - - /* Send out the string. */ - for (; *str != 0; str++) - SDC_Put_Char(*str, uart); - - /* Allow other threads to use this service. */ - NU_Release_Semaphore (uart->sd_semaphore); - } - -} - - -/**************************************************************************** -* FUNCTION -* -* SDC_Data_Ready -* -* DESCRIPTION -* -* This function checks to see if there are any characters in the -* receive buffer. A status value is returned indicating whether -* characters are present in the receive buffer. -* -* INPUTS -* -* SD_PORT * : Serial port to check for data. -* -* OUTPUTS -* -* STATUS The status indicates the -* presence of characters. -* -****************************************************************************/ -STATUS SDC_Data_Ready(SD_PORT *port) -{ - /* Check the status. */ - if((port->rx_buffer_status == NU_BUFFER_FULL) || - (port->rx_buffer_status == NU_BUFFER_DATA)) - - return (NU_TRUE); - - else - - return (NU_FALSE); -} - -/**************************************************************************** -* FUNCTION -* -* SDC_Change_Communication_Mode -* -* DESCRIPTION -* -* This function switches the serial port between terminal mode and -* network mode. The mode affects how incoming characters are directed. -* -* INPUTS -* -* INT : The mode of operation desired. -* -* OUTPUTS -* -* none -* -****************************************************************************/ -VOID SDC_Change_Communication_Mode(INT mode, SD_PORT *uart) -{ - uart->communication_mode = mode; - -} /* SDC_Change_Communication_Mode */ - -/**************************************************************************** -* FUNCTION -* -* SDC_Reset -* -* DESCRIPTION -* -* This function intializes the data variables associated with a UART -* -* INPUTS -* -* SD_PORT * : Serial port to reset -* -* OUTPUTS -* -* STATUS : Returns URT_SUCCESS if successful initialization, -* else a negative value is returned. -* -****************************************************************************/ -VOID SDC_Reset (SD_PORT *uart) -{ - /* Ini the error counters */ - uart->frame_errors = 0; - uart->overrun_errors = 0; - uart->parity_errors = 0; - uart->busy_errors = 0; - uart->general_errors = 0; -} - -/*************************************************************************** -* FUNCTION -* -* URT_Init_Port -* -* DESCRIPTION -* -* This function intializes the data variables associated with a UART -* -* INPUTS -* -* SD_PORT * : Serial port to reset -* -* OUTPUTS -* -* STATUS : Returns URT_SUCCESS if successful initialization, -* else a negative value is returned. -* -****************************************************************************/ -#ifdef NU_ENABLE_PPP -STATUS URT_Init_Port(DV_DEVICE_ENTRY *device) -{ - SD_PORT *uart; - STATUS ret_status; - - /* Get a pointer to the UART layer of this device. */ - uart = &((PPP_LAYER *) device->ppp_layer)->uart; - - /* Init the serial port, copy init parameters from the device - structure. */ - uart->com_port = device->dev_com_port; - uart->baud_rate = device->dev_baud_rate; - uart->data_bits = device->dev_data_bits; - uart->stop_bits = device->dev_stop_bits; - uart->parity = device->dev_parity; - uart->data_mode = device->dev_data_mode; - uart->vector = device->dev_vect; - uart->driver_options = device->dev_driver_options; - uart->communication_mode = MDM_TERMINAL_COMMUNICATION; - uart->sd_buffer_size = (2 * (PPP_MTU + PPP_FCS_SIZE + - PPP_MAX_PROTOCOL_SIZE + PPP_MAX_ADDR_CONTROL_SIZE)); - - /* Init the port */ - ret_status = NU_SD_Init_Port (uart); - - if (ret_status == NU_SUCCESS) - { - /* Copy the vector back into the device entry just in case - the UART driver changed it. */ - device->dev_vect = uart->vector; - } - - return (ret_status); - -} -#endif /* NU_ENABLE_PPP */
--- a/nuc-fw/nucleus/tmcal.c Mon Nov 11 09:56:23 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -/* - * FreeNucleus port by Spacefalcon the Outlaw - * - * This module implements the INT_Timer_Initialize() function - * for the proof-of-concept Calypso port. - * - * TIMER2 configuration is based on that used by OsmocomBB. - */ - -#include "calirq.h" -#include "caltimer.h" - -void -INT_Timer_Initialize() -{ - /* program the timer */ - TIMER2_REGS.cntl = CNTL_CLOCK_ENABLE; - TIMER2_REGS.load = 4062; - TIMER2_REGS.cntl = CNTL_CLOCK_ENABLE | CNTL_AUTO_RELOAD | CNTL_START; - /* now let it interrupt */ - INTH_REGS.ilr_irq[IRQ_TIMER2] = 0x7E; - INTH_REGS.mask_it_reg1 &= ~(1 << IRQ_TIMER2); -}