int init_sys(void) { SCB->CCR |= SCB_CCR_STKALIGN_Msk; // enable double word stack alignment PSP_array[0] = ((unsigned int)task0_stack) + (sizeof task0_stack) - 16*4; // top of stack HW32_REG((PSP_array[0] + (14<<2))) = (unsigned long)task0; // initial Program Counter HW32_REG((PSP_array[0] + (15<<2))) = 0x01000000; // initial PSR PSP_array[1] = ((unsigned int)task1_stack) + (sizeof task1_stack) - 16*4; HW32_REG((PSP_array[1] + (14<<2))) = (unsigned long)task1; HW32_REG((PSP_array[1] + (15<<2))) = 0x01000000; curr_task = 0; __set_PSP((PSP_array[curr_task] + 16*4)); // set PSP to top of stack NVIC_SetPriority(PendSV_IRQn, 0xFF); SysTick_Config(168000); __set_CONTROL(0x3); __ISB(); task0(); /*while(1) { stop_cpu; }; */ }
int unused_addresses_test_single(unsigned int address) { if (HW32_REG(address) != 0) return (1); HW32_REG(address) = 0xFFFFFFFF; if (HW32_REG(address) != 0) return (1); else return (0); }
/* Use ID value to detect if the system controller is present */ int sysctrl_id_check(void) { /* CMSDK SysCtrl part ID range from 826 to 829 */ #define HW32_REG(ADDRESS) (*((volatile unsigned long *)(ADDRESS))) if ((HW32_REG(CMSDK_SYSCTRL_BASE + 0xFE0) < 0x26) || (HW32_REG(CMSDK_SYSCTRL_BASE + 0xFE0) > 0x29) || (HW32_REG(CMSDK_SYSCTRL_BASE + 0xFE4) != 0xB8)) return 1; /* part ID does not match */ else return 0; }
int gpio0_id_check(void) { unsigned char gpio_id; gpio_id = HW8_REG(CMSDK_GPIO0_BASE + 0xFE8) & 0x07; if ((HW32_REG(CMSDK_GPIO0_BASE + 0xFE0) != 0x20) || (HW32_REG(CMSDK_GPIO0_BASE + 0xFE4) != 0xB8) || (gpio_id != 0x03)) return 1; /* part ID & ARM ID does not match */ else return 0; }
/*! \brief C part of the SVC exception handler SVC 0 is initializing the OS and starting the scheduler. Each thread stack frame is initialized. \param svc_args Used to extract the SVC number */ void SVC_Handler_C(unsigned int * svc_args) { uint8_t svc_number; svc_number = ((char *) svc_args[6])[-2]; // Memory[(Stacked PC)-2] // marking kernel as busy kernel_busy = 1; switch(svc_number) { //************* SVC( 0 ) OS Start case (0): // OS start // Starting the task scheduler //TWP playing a trick here!? by making curr = next, will make next's stack and current's stack the same stack! // will save (garbage) current register values, and then immediately restore them as next's initial values :-) curr_task = rtr_q_h; // Switch to head ready-to-run task (Current task) // when current task was put in RTRQ its state was set to RUNNING svc_exc_return = HW32_REG(( curr_task->stack_p )); // Return to thread with PSP __set_PSP(( (uint32_t) curr_task->stack_p + 10*4)); // Set PSP to @R0 of task 0 exception stack frame NVIC_SetPriority(PendSV_IRQn, 0xFF); // Set PendSV to lowest possible priority if (SysTick_Config(os_sysTickTicks) != 0) // 1000 Hz SysTick interrupt on 16MHz core clock { stop_cpu2; // Impossible SysTick_Config number of ticks } __set_CONTROL(0x3); // Switch to use Process Stack, unprivileged state __ISB(); // Execute ISB after changing CONTROL (architectural recommendation) break; //************* SVC( 1 ) Thread Yield case (1): // Thread Yield if (curr_task != rtr_q_h) { // Context switching needed ScheduleContextSwitch(); } __ISB(); break; //************* SVC( 2 ) Stack Frame Allocation for First Launch //TWPV6: no longer used! Functionality moved to osThreadCreate ... case left here (for now) case (2): // Stack Allocation __ISB(); break; default: #if ((ENABLE_KERNEL_PRINTF) && (ENABLE_KERNEL_PRINTF == 1)) printf("ERROR: Unknown SVC service number\n\r"); printf("- SVC number 0x%x\n\r", svc_number); #endif stop_cpu2; break; } // end switch // marking kernel as normal kernel_busy = 0; }
int sram_test_word(unsigned int test_addr) { int result=0; // This will only work if result and temp are not store in address being tested int temp; __disable_irq(); // Make sure interrupt will not affect the result of the test temp = HW32_REG(test_addr); // save data /* Use consistence memory access size in checking so that it work with both little endian and big endian configs */ HW32_REG(test_addr)=0x00000000; if (HW32_REG(test_addr)!=0x00000000) result++; HW16_REG(test_addr)=0xFFFF; if (HW16_REG(test_addr)!=0xFFFF) result++; HW8_REG(test_addr+3)=0x12; HW8_REG(test_addr+2)=0xFF; if (HW8_REG(test_addr+3)!=0x12) result++; if (HW8_REG(test_addr+2)!=0xFF) result++; HW8_REG(test_addr )=0x00; HW8_REG(test_addr+1)=0x00; if (HW8_REG(test_addr )!=0x00) result++; if (HW8_REG(test_addr+1)!=0x00) result++; HW16_REG(test_addr+2)=0xFE00; if (HW16_REG(test_addr+2)!=0xFE00) result++; HW32_REG(test_addr)=0x00000000; if (HW32_REG(test_addr)!=0x00000000) result++; HW32_REG(test_addr) = temp; // restore data __enable_irq(); // re-enable IRQ if (result !=0) printf ("ERROR: Memory location test failed at %x\n", test_addr); return result; }
/* ----------------------------------------------------------------- */ void HardFault_Handler(void) { unsigned int dummy; /* dummy variable for read that trigger hardfault */ puts("[Hard fault handler]"); puts("- trigger fault again to enter lockup"); /* Trigger lockup */ dummy=HW32_REG(BAD_ADDRESS); puts ("ERROR: Lockup not triggered"); UartEndSimulation(); /* Simulation stops in UartEndSimulation */ }
/* Check the ID register value in offset 0xFC0 to 0xFFC (last 16 words, last 12 are IDs) */ int SysCtrl_ID_Check(const unsigned char id_array[], unsigned int offset) { int i; /* loop counter */ unsigned long expected_val, actual_val; unsigned long compare_mask; int mismatch = 0; int id_is_zero = 0; unsigned long test_addr; /* Check the peripheral ID and component ID */ for (i=0;i<16;i++) { test_addr = offset + 4*i + 0xFC0; expected_val = (int) id_array[i]; actual_val = HW32_REG(test_addr); if (actual_val == 0) id_is_zero++; // Check if all ID are zero at the end /* create mask to ignore version numbers */ if (i==10) { compare_mask = 0xF0;} // mask out version field else if (i==11) { compare_mask = 0xFF;} // mask out ECO field and patch field else { compare_mask = 0x00;} // compare whole value if (i==8) { /* The part number of the example system controller in CMSDK can be 26 to 29 */ if ((actual_val<0x26)||(actual_val>0x29)) { printf ("Difference found: %x, expected 0x26 to 0x29, actual %x\n", test_addr, actual_val); mismatch++; } } else { if ((expected_val & (~compare_mask)) != (actual_val & (~compare_mask))) { printf ("Difference found: %x, expected %x, actual %x\n", test_addr, expected_val, actual_val); mismatch++; } } // end_if_i_eq_8 } // end_for if (id_is_zero == 16) { puts (" All ID values are 0 : device not present\n"); return 2; } else if (mismatch> 0) { puts (" ID value mismatch(es) : device unknown\n"); return 1; } else { puts (" All ID values matched : device present\n"); return 0; } }
/* Second part of the main test program - execute after SYSRESETREQ reset */ void main_prog_part_2(void) { int result=0; unsigned int read_data; puts("- Self reset completed"); read_data = CMSDK_SYSCON->RSTINFO; printf (" SYSCON->RSTINFO = %x\n", read_data); if (read_data != CMSDK_SYSCON_RSTINFO_SYSRESETREQ_Msk) result++; puts("- Clear reset info"); CMSDK_SYSCON->RSTINFO = CMSDK_SYSCON_RSTINFO_SYSRESETREQ_Msk; read_data = CMSDK_SYSCON->RSTINFO; printf (" SYSCON->RSTINFO = %x\n", read_data); if (read_data != 0) result++; if (result != 0) { puts ("ERROR: reset info register value incorrect.\n"); } else { puts ("SYSRESETREQ test done\nNow test reset caused by lockup\n"); } /* Test Lockup reset */ CMSDK_SYSCON->RESETOP = CMSDK_SYSCON_LOCKUPRST_RESETOP_Msk; read_data = CMSDK_SYSCON->RESETOP; if (read_data != CMSDK_SYSCON_LOCKUPRST_RESETOP_Msk) { puts ("ERROR: reset option register value incorrect.\n"); UartEndSimulation(); } read_data = CMSDK_SYSCON->RSTINFO; if (read_data != 0) { puts ("ERROR: reset info register value incorrect.\n"); UartEndSimulation(); } /* Trigger hard fault */ read_data=HW32_REG(BAD_ADDRESS); puts ("ERROR: Hard fault not triggered"); UartEndSimulation(); /* Simulation stops in UartEndSimulation */ return; }
/*! \brief C part of the SVC exception handler SVC 0 is initializing the OS and starting the scheduler. Each thread stack frame is initialized. \param svc_args Used to extract the SVC number */ void SVC_Handler_C(unsigned int * svc_args) { uint8_t svc_number, i; svc_number = ((char *) svc_args[6])[-2]; // Memory[(Stacked PC)-2] // marking kernel as busy kernel_busy = 1; switch(svc_number) { case (0): // OS start // Starting the task scheduler // Update thread to be run based on priority scheduler(); curr_task = next_task; // Switch to head ready-to-run task (Current task) th_q_h = curr_task; th_q[curr_task]->status = TH_RUNNING; if (PSP_array[curr_task] == NULL) { // Stack not allocated for current task, allocating i = curr_task; th_q[i]->stack_p = (uint32_t) task_stack[i]; PSP_array[i] = ((unsigned int) th_q[i]->stack_p) + (th_q[i]->stack_size) - 18*4; HW32_REG((PSP_array[i] + (16<<2))) = (unsigned long) th_q[i]->start_p; // initial Program Counter HW32_REG((PSP_array[i] + (17<<2))) = 0x01000000; // initial xPSR HW32_REG((PSP_array[i] )) = 0xFFFFFFFDUL; // initial EXC_RETURN HW32_REG((PSP_array[i] + ( 1<<2))) = 0x3;// initial CONTROL : unprivileged, PSP th_q[i]->stack_p = PSP_array[i]; } svc_exc_return = HW32_REG((PSP_array[curr_task])); // Return to thread with PSP __set_PSP((PSP_array[curr_task] + 10*4)); // Set PSP to @R0 of task 0 exception stack frame NVIC_SetPriority(PendSV_IRQn, 0xFF); // Set PendSV to lowest possible priority if (SysTick_Config(os_sysTickTicks) != 0) // 1000 Hz SysTick interrupt on 16MHz core clock { stop_cpu2; // Impossible SysTick_Config number of ticks } __set_CONTROL(0x3); // Switch to use Process Stack, unprivileged state __ISB(); // Execute ISB after changing CONTROL (architectural recommendation) break; case (1): // Thread Yield // Run scheduler to determine if a context switch is needed scheduler(); if (curr_task != next_task) { // Context switching needed ScheduleContextSwitch(); } __ISB(); break; case (2): // Stack Allocation // Create stack frame for thread i = svc_args[0]; th_q[i]->stack_p = (uint32_t) task_stack[i]; PSP_array[i] = ((unsigned int) th_q[i]->stack_p) + (th_q[i]->stack_size) - 18*4; HW32_REG((PSP_array[i] + (16<<2))) = (unsigned long) th_q[i]->start_p; // initial Program Counter HW32_REG((PSP_array[i] + (17<<2))) = 0x01000000; // initial xPSR HW32_REG((PSP_array[i] )) = 0xFFFFFFFDUL; // initial EXC_RETURN HW32_REG((PSP_array[i] + ( 1<<2))) = 0x3;// initial CONTROL : unprivileged, PSP th_q[i]->stack_p = PSP_array[i]; __ISB(); break; default: #if ((ENABLE_KERNEL_PRINTF) && (ENABLE_KERNEL_PRINTF == 1)) printf("ERROR: Unknown SVC service number\n\r"); printf("- SVC number 0x%x\n\r", svc_number); #endif stop_cpu2; break; } // end switch // marking kernel as normal kernel_busy = 0; }
/* Simple test for APB test slave */ int APB_test_slave_Check(unsigned int offset) { /* The APB test slave has got only one 32-bit register in the first four addresses. For each word, the wait state increase based on PADDR[3:2]. The test slave is also able to generate error responses at offset 0x0F0 to 0xFC. */ int mismatch = 0; int fault_err = 0; int i; // Read/Write test to data_register HW32_REG(offset) = 0xFFFFFFFF; if ((HW32_REG(offset)) !=0xFFFFFFFF) mismatch ++; HW32_REG(offset) = 0x00000000; if ((HW32_REG(offset)) !=0x00000000) mismatch ++; HW32_REG(offset) = 0x12345678; if ((HW32_REG(offset)) !=0x12345678) mismatch ++; HW16_REG(offset) = 0x5678; /* Use consistent access size. This is required to allow the test to run in big endian */ if ((HW16_REG(offset)) !=0x5678) mismatch ++; HW16_REG(offset+2) = 0x1234; /* Use consistent access size.*/ if ((HW16_REG(offset+2)) !=0x1234) mismatch ++; HW8_REG(offset) = 0x78; /* Use consistent access size between read and write.*/ HW8_REG(offset+1) = 0x56; HW8_REG(offset+2) = 0x34; HW8_REG(offset+3) = 0x12; if ((HW8_REG(offset)) !=0x78) mismatch ++; if ((HW8_REG(offset+1)) !=0x56) mismatch ++; if ((HW8_REG(offset+2)) !=0x34) mismatch ++; if ((HW8_REG(offset+3)) !=0x12) mismatch ++; HW16_REG(offset+4) = 0xFFFF; // Value = 0x1234FFFF if ((HW16_REG(offset+8)) !=0xFFFF) mismatch ++; HW16_REG(offset+6) = 0x0000; // Value = 0x0000FFFF if ((HW16_REG(offset+4)) !=0xFFFF) mismatch ++; if ((HW16_REG(offset+6)) !=0x0000) mismatch ++; HW8_REG(offset+8) = 0xA5; // Value = 0x0000FFA5 if ((HW8_REG(offset+8)) !=0xA5) mismatch ++; HW8_REG(offset+0xD) = 0xC3; // Value = 0x0000C3A5 if ((HW8_REG(offset+0xD)) !=0xC3) mismatch ++; HW16_REG(offset+0xE)= 0xC53A;// Value = 0xC53AC3A5 if ((HW16_REG(offset+0xE)) !=0xC53A) mismatch ++; /* Testing of error response from APB test slave */ for (i=0; i<4; i++) { temp_data=0; hardfault_expected = 1; hardfault_occurred = 0; address_test_write((offset + 0xF0 + (i<<2)), 0x0); if (hardfault_occurred==0) fault_err++; hardfault_occurred = 0; temp_data=address_test_read(offset + 0xF0 + (i<<2)); if (hardfault_occurred==0) fault_err++; } hardfault_expected = 0; hardfault_occurred = 0; if (mismatch>0) { puts (" Data mismatch in APB test slave\n"); return 1;} if (fault_err>0){ puts (" Fault mismatch in APB test slave\n"); return 1;} else puts (" APB test slave test passed\n"); return 0; }