/* * Main */ int main(void) { init_tlb(); enable_tlb(); printf("Hello from Nios II!\n"); mutex = altera_avalon_mutex_open(MUTEX_0_NAME); // Initialize the hardware mutex mbox = OSSemCreate(0); // Initialize the message box CriticalFunctionPointers* cp = (CriticalFunctionPointers*)SHARED_MEMORY_BASE; // Wait for monitor to be done initialization of shared variables before retrieving their values while(cp->init_complete == 0); init_cpu1_isr(); // Initialize the ISR // Set the task(only one in this example) int arg_5 = CRITICAL_TASK_PRIORITY; OSTaskCreateExt(preemption_task, &arg_5, &critical_task_stk[TASK_STACKSIZE - 1], CRITICAL_TASK_PRIORITY, CRITICAL_TASK_PRIORITY, critical_task_stk, TASK_STACKSIZE, NULL,0); // Signal that the core has finished initializing altera_avalon_mutex_lock(mutex, 1); // Acquire the hardware mutex { cp->core_ready[1] = 1; } altera_avalon_mutex_unlock(mutex); // Memory // Start OS OSStart(); return 0; }
/* * This is the wrapper for the task that executes rendundantly on both cores * There is one VERY important thing to note. When the critical task begins executing * the value of the stack pointer MUST be the same on both cores. This means that * the wrapper must have the same number of variables declared within its scope (i.e. * onto its stack) before calling the critical task (pt() in this example) */ void preemption_task(void* pdata){ int done = 0; int first = 0; int t_os; CriticalFunctionPointers* cp = (CriticalFunctionPointers*) SHARED_MEMORY_BASE; pt = cp->task[1]; while(1){ // Get initial time, then wait for 2 ticks t_os = OSTimeGet(); OSTimeDly(2 - t_os); //This is a crude way of synchronizing the beginning of the task //on both cores while (done == 0) { altera_avalon_mutex_lock(mutex, 1); //Acquire the hardware mutex { if(first == 0){ cp->checkout[1] = 1; first = 1; } if( cp->checkout[0] == 1){ cp->checkout[0] = 0; done = 1; } } altera_avalon_mutex_unlock(mutex); } // Set default block size for fingerprinting fprint_set_block_size(cp->blocksize[1]); //Context switch is necessary to clear the callee saved registers long registers[8]; context_switch(registers); //Set the global pointer in case of compilation issues related //to global variables set_gp(); //call the critical task pt(cp->args[1]); //restore the original global pointer restore_gp(); //Restore the callee saved registers context_restore(registers); //Get the end time alt_u64 t = alt_timestamp(); //store the end time cp->core_time[1] = t; } }
/* * If CPU1 interrupt goes off, we assume that it has been sent * by the monitor for now and that a task must be executed. * The identity of the task is retrieved from the shared_memory * using the CriticalFunctionPointers data structure. The task is then executed */ static void handle_cpu1_interrupt(void* context) { unsigned short priority; altera_avalon_mutex_lock(mutex, 1); { CriticalFunctionPointers* cp = (CriticalFunctionPointers*)SHARED_MEMORY_BASE; priority = cp->priority[1]; *isr_1_ptr = 0; } altera_avalon_mutex_unlock(mutex); if(priority == CRITICAL_TASK_PRIORITY) OSSemPost(mbox); }
int main() { printf("Hello from cpu_3!\n"); alt_mutex_dev* mutex = altera_avalon_mutex_open( "/dev/mutex_1" ); while(TRUE) { altera_avalon_mutex_lock( mutex, 1 ); if (IORD_8DIRECT(FLAG,0) == 1) { value=IORD_8DIRECT(VALUE,0); printf("Reading from shared memory (safe): %d\n",value); IOWR_8DIRECT(VALUE,0,++value); IOWR_8DIRECT(FLAG,0,0); printf("\tWriting to shared memory (safe): %d\n",value); } altera_avalon_mutex_unlock( mutex ); delay(10); } return 0; }