/* TMClock.c, Copyright (c) by Lukas Ruf, lr@lpr.ch, 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/ia32/TMClock.c,v $ Author(s): Lukas Ruf, lr@lpr.ch Affiliation: ETH Zuerich, TIK Version: $Revision: 1.3 $ Creation Date: Last Date of Change: $Date: 1999/12/13 21:48:34 $ by: $Author: ruf $ $Log: TMClock.c,v $ Revision 1.3 1999/12/13 21:48:34 ruf GNU General Public Licence Update Revision 1.2 1999/06/06 20:55:14 jeker putting everything together for Topsy 2.0 Revision 1.1 1999/05/13 17:05:47 jeker Initial revision */ #include "TMHal.h" #include "TMHalAsm.h" #include "IOHal.h" #include "IODevice.h" #include "TMScheduler.h" #include "Support.h" #include "TMClock.h" #include "SupportAsm.h" #include "Video.h" #include "video.h" #include "Tools.h" typedef struct tTimeS { unsigned char s; /* sec 00..59 */ unsigned char m; /* min 00..59 */ unsigned char h; /* std 00..23 */ unsigned char d; /* day 01..31 */ unsigned char dow; /* day of week 0..7 */ unsigned char mon; /* month 01..12 */ unsigned char y; /* year 00..255 == 1980..1980+255 */ } tTime; static volatile unsigned long _TimerCalled; static volatile unsigned char Rotate[5] = "|/-\\"; static volatile unsigned long Next; static volatile tTime Time; int LeapYear(int pyea) { return ((((pyea % 4 == 0) && (pyea % 100 != 0)) || (pyea % 400 == 0)) ? 1 : 0); } /* Number of Day in Year */ int NumOfDay(int pday, int pmon, int pyea) { int d, e; d = (pmon + 10) / 13; e = pday + (611*(pmon+2))/20 - 2*d - 91; return (e + LeapYear(pyea)*d); } /* Day of Week */ unsigned char DoW(int pyea, int pNumOfDay) { int j, c; j = (pyea - 1) % 100; c = (pyea - 1) / 100; return (28+j+pNumOfDay+(j/4)+(c/4)+5*c) % 7; } int NewMonth(unsigned char pday, unsigned char pmon, unsigned char pyea) { int ldmonth[12] = {31,27,31,30,31,30,31,31,30,31,30,31}; return (pday > (ldmonth[pmon-1]+LeapYear(pyea)*(int)(pmon==2))); } void DispTime() { unsigned char ts[3], tm[3], th[3]; itoa(Time.s,(char*)ts); itoa(Time.m,(char*)tm); itoa(Time.h,(char*)th); if (Time.h < 10) { th[1] = th[0]; th[0] = '0'; th[2] = 0; } if (Time.m < 10) { tm[1] = tm[0]; tm[0] = '0'; tm[2] = 0; } if (Time.s < 10) { ts[1] = ts[0]; ts[0] = '0'; ts[2] = 0; } __printstr((24*80+00)*2,0x1E,th); __printstr((24*80+02)*2,0x1E,(unsigned char*)":"); __printstr((24*80+03)*2,0x1E,tm); __printstr((24*80+05)*2,0x1E,(unsigned char*)":"); __printstr((24*80+06)*2,0x1E,ts); return; } void GetTime() { unsigned char tadd = 0; Time.s = __readRTC(0x00); Time.m = __readRTC(0x02); Time.h = __readRTC(0x04); Time.d = __readRTC(0x07); Time.dow = __readRTC(0x06); Time.mon = __readRTC(0x08); Time.y = __readRTC(0x09); if (Time.h & 0x80) tadd = 12; Time.s = (unsigned char)BCDtoBIN((int)Time.s); Time.m = (unsigned char)BCDtoBIN((int)Time.m); Time.h = (unsigned char)BCDtoBIN((int)(Time.h & 0x7F)); Time.d = (unsigned char)BCDtoBIN((int)Time.d); Time.mon = (unsigned char)BCDtoBIN((int)Time.mon); Time.y = (unsigned char)BCDtoBIN((int)Time.y); Time.h += tadd; DispTime(); return; } void SetEasyWatch() { /* binary + 24h Format */ unsigned char lb = __readRTC(0x0B); lb |= 0x02; /* set 24h-Format */ lb |= 0x80; /* set RTC update disable */ __writeRTC(0x0B,lb); GetTime(); lb &= 0x7F; /* enable update interval */ __writeRTC(0x0B,lb); return; } void SetTime() { __writeRTC(0x00,Time.s); __writeRTC(0x02,Time.m); __writeRTC(0x04,Time.h); return; } void SetDate() { __writeRTC(0x06,Time.dow); __writeRTC(0x07,Time.d); __writeRTC(0x08,Time.mon); __writeRTC(0x09,Time.y); return; } void UpdateTime() { DispTime(); /* RTC is updated by 32378Hz (AT Update Clock) */ Time.s++; if (Time.s > 59) { Time.s = 0; Time.m++; if (Time.m > 59) { Time.m = 0; Time.h++; if (Time.h > 23) { Time.h = 0; Time.d++; Time.dow %= 7; Time.dow ++; if (NewMonth(Time.d,Time.mon,Time.y)) { Time.d = 1; Time.mon++; if (Time.mon > 12) { Time.mon = 1; Time.y++; } } } } } return; } void TimerInit() { _TimerCalled = 0; Next = 0; SetEasyWatch(); printf("Binary Watch Handling Enabled\n"); __endOf_IRQ(T_IR_00); /* Reset Timer Channel 0 Interrupt */ __enable_IRQ(T_IR_00); /* and enable Interrupt Line 0 */ printf("Interrupt Request Line 0x00 (Timer Channel 0) started \n"); return; } unsigned long TimerSeconds() { return (unsigned long) (_TimerCalled / tFREQUENCY); } unsigned long TimerCalled() { return _TimerCalled; } void _TimerISR() { /* Timer Master ISR */ if ((_TimerCalled % (tFREQUENCY >> 2)) == 0) __printchar((24*80+79)*2 ,0x1D,Rotate[(Next++) % 4]); _TimerCalled++; if ((_TimerCalled % tFREQUENCY) == 0) UpdateTime(); return; } /* * This function initializes the clock on the board. */ Error setClockValue( ClockId cId, int period, ClockMode cMode) { /* original Topsy supports only one mode: called RATE GENERATOR */ /* so I simply ignore cMode for init now */ unsigned short ldivisor = (unsigned short)(tFIXRATE * period / 1000); switch (cId) { case CLOCK0 : __timerSet(ldivisor, MODE2_COUNTER0, TIMER0); /* please note: orig. Topsy supports only one setClockValue() call in TMInit.c. The Timer Channel 0 is activated in TimerInit() in this file. */ break; case CLOCK1 : /* NOTE: The PC uses TIMER CHANNEL 1 to generate the Memory Refresh Cycle So, only TIMER0 can be used to simply generate TIMER Interrupts without difficulties. Channel 2 of 8254 is hardwired to Speaker Frequency Output --> so forget it !! */ break; default : break; } return TM_OK; } /* When a clock interrupt is generated, a reset is performed. If not done, * the interrupt is generated at once again and again ... */ void tmResetClockInterrupt(ClockId cId) { /* i386: IRQ is generated. Handled by the __general_IRQHandler the appropriate PIC is resetted. */ } /* 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; }