/* TMClock.c, Copyright 18.3.97 (c) by C. Conrad & G. Fankhauser, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/Threads/mips/TMClock.c,v $ Author(s): C. Conrad & G. Fankhauser Affiliation: ETH Zuerich, TIK Version: $Revision: 1.11 $ Creation Date: 18.3.97 Last Date of Change: $Date: 1999/12/13 21:48:35 $ by: $Author: ruf $ $Log: TMClock.c,v $ Revision 1.11 1999/12/13 21:48:35 ruf GNU General Public Licence Update Revision 1.10 1999/10/21 20:22:30 jeker first commit for the R4k support Revision 1.9 1999/01/08 18:56:35 cjeker more code cleaning, moved tmResetClockInterrupt to the clock interrupt handlers Revision 1.8 1998/06/05 14:37:57 gfa added get/set time Revision 1.7 1998/03/31 17:13:10 gries support for mode4 added Revision 1.6 1997/04/18 16:28:37 conrad *** empty log message *** * Revision 1.5 1997/04/17 11:33:49 conrad * *** empty log message *** * * Revision 1.4 1997/04/17 10:56:16 conrad * use of ioDelayAtLeastCycles between hw accesses * * Revision 1.3 1997/04/14 21:09:10 conrad * *** empty log message *** * * Revision 1.2 1997/04/14 12:32:58 conrad * adding of a function to reset clock interrupts * * Revision 1.1 1997/03/18 17:37:55 conrad * Initial revision * */ #include "TMHal.h" #include "IOHal.h" #include "IODevice.h" #include "TMScheduler.h" #include "Support.h" #include "TMClock.h" /* 8254 Register Addressing structure */ typedef struct TimerRegisters_t{ unsigned char counter0; unsigned char pad1[3]; unsigned char counter1; unsigned char pad2[3]; unsigned char counter2; unsigned char pad3[3]; unsigned char ctrlWord; unsigned char pad4[3]; } TimerRegisters; /* * This function initializes the clock on the board. */ Error setClockValue( ClockId cId, int period, ClockMode cMode) { #ifndef SIMOS TimerRegisters* timerRegisters = (TimerRegisters*)TIMERBASE; unsigned short int initialCount; /* count for counter 0 or 1 */ unsigned short int initialCount2 = 100; /* count for counter 2 */ int frequencyCoeff = 3686 / initialCount2; /* Cristal oscillator frequency: 3.6861 MHz. Period given in [ms], -> #ticks = 1000*period[ms]*freq[MHz]. As there are two cascaded timers (c2-c0 or c2-c1), each counter should ideally have an initial value of sqrt(initialCount) */ initialCount = period * frequencyCoeff; if (cMode == RATEGENERATOR) { /* single mode supported */ switch (cId) { case CLOCK0: timerRegisters->ctrlWord = (unsigned char)MODE2_COUNTER0; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter0 = (unsigned char)initialCount; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter0 = (unsigned char)(initialCount >> 8); ioDelayAtLeastCycles( NBCYCLESFORDELAY); break; case CLOCK1: timerRegisters->ctrlWord = MODE2_COUNTER1; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter1 = (unsigned char)initialCount; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter1 = (unsigned char)(initialCount >> 8); ioDelayAtLeastCycles( NBCYCLESFORDELAY); break; } timerRegisters->ctrlWord = MODE2_COUNTER2; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter2 = (unsigned char)initialCount2; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter2 = (unsigned char)(initialCount2 >> 8); ioDelayAtLeastCycles( NBCYCLESFORDELAY); } else if (cMode == SWTRIGGER) { /* intel 8254 mode4 */ switch (cId) { case CLOCK0: timerRegisters->ctrlWord = (unsigned char)MODE4_COUNTER0; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter0 = (unsigned char)initialCount; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter0 = (unsigned char)(initialCount >> 8); ioDelayAtLeastCycles( NBCYCLESFORDELAY); break; case CLOCK1: timerRegisters->ctrlWord = MODE4_COUNTER1; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter1 = (unsigned char)initialCount; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter1 = (unsigned char)(initialCount >> 8); ioDelayAtLeastCycles( NBCYCLESFORDELAY); break; } timerRegisters->ctrlWord = MODE2_COUNTER2; /* CLOCK2 must use mode2 */ ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter2 = (unsigned char)initialCount2; ioDelayAtLeastCycles( NBCYCLESFORDELAY); timerRegisters->counter2 = (unsigned char)(initialCount2 >> 8); ioDelayAtLeastCycles( NBCYCLESFORDELAY); } #else /* SimOS emulates a preaty sophisticated MAGIC chipset, with support * for 64 interrupt sources and other goodies we don't care about. * To make my life enjoyable, none of those is documented anywhere, * so I just utilize a bare mimimum requied to get the scheduler going. */ if (cId != CLOCK0) PANIC("SimOS does not support timers other than CLOCK0"); /* Set up the interval timer. */ magic_control[MAGIC_PPR_IECENABLE] |= 1 << DEV_IEC_CLOCK; magic_control[MAGIC_PPR_INTERVAL] = TIMESLICE; #endif return TM_OK; } /* When a clock interrupt is generated, the clock must be stoped. So a reset is performed. * If not done, the interrupt is generated at once again and again ... */ void tmResetClockInterrupt(ClockId cId) { #ifndef SIMOS char* x; char y; switch (cId) { case CLOCK0: x = (char*)RESETCINT0; break; case CLOCK1: x = (char*)RESETCINT1; break; default: return; } y = *x; #else /* SIMOS */ if (cId != CLOCK0) PANIC("SimOS does not support timers other than CLOCK0"); magic_control[MAGIC_PPR_IECPENDING] = 1 << DEV_IEC_CLOCK; #endif } /* since we don't have an RTC installed we don't do anything here * otherwise we would calculate the seconds * since January 1st 1998, 00:00, UTC, and return or set them */ unsigned long tmRTClockGetSeconds() { return 0; } void tmRTClockSetSeconds(unsigned long seconds, unsigned long microSeconds) { return; }