// // lab2_test.c // #include #include // // structure that monitors the progress of each task. Always stored in external memeory // typedef struct { unsigned char timer; // a cyclic timer that counts from 0 to period-1 and repeats unsigned char period; // constant, number of ticks (not slices) in one period unsigned char phase; // constant, when timer = phase, the task is released unsigned char deadline; // constant, relative deadline in ticks unsigned char time_left;// number of ticks left before deadline (even if task is complete) unsigned char ex_time; // constant, number of ticks of execution time unsigned char work_left;// number of ticks worth of work that temains to be done, 0 = idle } task_desc; // // Declare structures for each task. Salvo provides only 3 // xdata task_desc task_A, task_B, task_C; // // this bit is set on each timer tick (interrupt). // bit tick_flag = 0; // // for clock driven schedules, user sees a "time slice" which holds 2 ticks // #define TICKS_PER_SLICE 2 // // this bit is set during the first tick of a slice (or until WaitForNextTimeSlice returns) // bit slice_flag = 0; // // WaitForNextTimeSlice() // parameters: none // returns: none: // // For clock driven scheduler, this synchronizes the user's schedule with the time slice. // Under normal conditions, a job waits until the tick timer expires, the interrupt sets // the tick flag and possibly the slice flag. If this function is called in the first tick // of a slice it immediately returns. Otherwise it waits for the next slice. // void WaitForNextTimeSlice(void) { while ( slice_flag == 0 ) { } slice_flag = 0; } // // InitTask() // parameters: // t: pointer to task monitoring structure // p: period of the task in ticks // phi: phase of the task in ticks // D: relative deadline of the task in ticks // e: execution time of the task in ticks (how many times JobX() must be called) // returns: // none // Note that all times are measured in ticks, not slices! // void InitTask(task_desc xdata *t, char p, char phi, char D, char e) { t->timer = 0; t->period = p; t->phase = phi, t->work_left = 0; t->time_left = 0; t->deadline = D; t->ex_time = e; } // // this bit is set as a side-effect of calling CheckTask() and tells whether or not // the task should be released on this interrupt. // bit release; // // CheckTask() // parameters: t: pointer to task monitoring structure // returns: none (but the release bit is set or cleared) // // This function is called on each tick for each task to check to see if (1) a deadline // has been missed and (2) whether it is time to release the task. // // If a deadline is missed, the LED on P1.6 is turned off. If a task is released, the // time_left and work_left are set from the deadline and the execution time, respectively. // void CheckTask(task_desc xdata *t) { if ( t->time_left != 0 ) { t->time_left--; if ( t->time_left == 0 && t->work_left > 0) P1 &= 0xbf; // turn off LED } if ( release = (t->timer == t->phase) ) { t->work_left = t->ex_time; t->time_left = t->deadline; } if ( ++t->timer >= t->period ) t->timer = 0; } // // DoJobX() // parameters: none // returns: none // // This function decrements the amount of work left for a task then waits for a tick // interrupt. (That interrupt will check to see the deadline is missed). This function // must be called a predetermined number of times before the deadline or the LED will // turn off. // void DoJobA(void) { tick_flag = 0; if ( task_A.work_left != 0 ) task_A.work_left--; do; while ( !tick_flag ); } void DoJobB(void) { tick_flag = 0; if ( task_B.work_left != 0 ) task_B.work_left--; do; while ( !tick_flag ); } void DoJobC(void) { tick_flag = 0; if ( task_C.work_left != 0 ) task_C.work_left--; do; while ( !tick_flag ); } // // BoarInit() // parameters: none // returns: none // // Initializes the 8051 registers, enables the timer and the timer interrupt. // It then creates semaphores and initializes the task monitoring structures // for the problem at hand. // void BoardInit(void) { // set up port 1 and crossbar WDTCN = 0xde; // disable watchdog WDTCN = 0xad; XBR2 = 0x40; // enable port output // set up timer 0 for 1ms overflow TMOD = 0x02; TH0 = -167; // 1000 Hz for 2 MHz xtal TR0 = 1; IE = 0x82; // enable timer 0 interrupt P1MDOUT = 0x40; P1 = 0xFF; OSCreateBinSem(OSECBP(1),0); OSCreateBinSem(OSECBP(2),0); OSCreateBinSem(OSECBP(3),0); InitTask(&task_A,6,0,6,3); InitTask(&task_B,8,0,4,3); InitTask(&task_C,24,0,24,2); } // // The time variable is here just to make debugging easier. Put it in your // watch and you'll know what time it is whenever you hit a breakpoint. // unsigned int time = 0; // // cyclic tick counter, equals 0 during the first tick of a time slice. // Initialized to TICKS_PER_SLICE-1 so a slice will begin on the first interrupt // unsigned char ticks = TICKS_PER_SLICE-1; // // Timer 0 interrupt // Occurs about once every millisecond (but the crystal is not on so who knows for sure?) // void timer0(void) interrupt 1 { time++; // update the time (debugging only) tick_flag = 1; // always set the tick flag slice_flag = 0; // sometimes set the slice flag, but clear it a at other times // Check each task, if released, signal the semaphores CheckTask(&task_A); if ( release ) OSSignalBinSem(OSECBP(1)); CheckTask(&task_B); if ( release ) OSSignalBinSem(OSECBP(2)); CheckTask(&task_C); if ( release ) OSSignalBinSem(OSECBP(3)); ticks++; // bump the tick timer if ( ticks != TICKS_PER_SLICE ) return; slice_flag = 1; // if this is the beginning of the slice, indicate it ticks = 0; // and reset the tick counter }