//----------------------------------------------------------------------------// // OS on Kaleid // // // // Desc: PIT Time related functions // // // // // // Copyright © 2018-2020 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include #include #include #include #define COUNTDONE 1 #define PIT_FREQUENCY 1000 // Hz = 1ms static Timer_t Timer[20]; //20 concurrent sleep max static ulong Ticks = 0; static Time_t CurTime; static char TimeFmtBuf[22] = { 0 }; extern bool PsInitialized; // // ISR handler for the Programmable Interval Timer // #pragma GCC push_options #pragma GCC optimize ("O0") static void HandlePIT(ISRFrame_t *regs) { Ticks++; for (uchar i = 0; i < 20; i++) { if (Timer[i].countDown > 0) { Timer[i].countDown--; if (Timer[i].countDown == 0) Timer[i].sema = 1; } KeSendEOItoPIC(0x28); if (PsInitialized && !(Ticks % 100)) { PsSchedOnTick(); } } } #pragma GCC pop_options static Timer_t* KeFindTimerBlock(void) { for(uchar i = 0; i < 20; i++) { if (Timer[i].countDown == 0) return &Timer[i]; } return NULL; } #pragma GCC push_options #pragma GCC optimize ("O0") void KeSleep(uint delay) { Timer_t *timerBlock; if ((timerBlock = (Timer_t*)KeFindTimerBlock()) == NULL) return; timerBlock->countDown = delay * PIT_FREQUENCY / 1000; while (!timerBlock->sema) { KeRelaxCPU(); } timerBlock->sema = 0; } #pragma GCC pop_options #pragma GCC push_options #pragma GCC optimize ("O0") Timer_t *KeSetTimer(uint delay) { Timer_t *timerBlock; if ((timerBlock = (Timer_t*)KeFindTimerBlock()) == NULL) return NULL; timerBlock->countDown = delay * PIT_FREQUENCY / 1000; return timerBlock; } #pragma GCC pop_options int KeGetTimer(Timer_t *timerBlock) { if (!(timerBlock->sema)) { return 0; } else { timerBlock->sema = 0; return 1; } } void KeEnablePIT(void) { ulong flags = KePauseIRQs(); uint divisor = 1193180 / PIT_FREQUENCY; // PIT base frequency / Needed frequency KeRegisterISR(HandlePIT, 0x20); IoWriteByteOnPort(0x43, 0x36); // 0x36 for rate gen IoWriteByteOnPort(0x40, (char)(divisor & 0xFF )); // low byte of freq IoWriteByteOnPort(0x40, (char)((divisor >> 8)& 0xFF)); // high byte of freq // Setting up the IRQ line KeUnmaskIRQ(0); DebugLog("PIT activated with period %d ms\n", 1000/PIT_FREQUENCY); KeRestoreIRQs(flags); KeEnableNMI(); } char *KeFormatCurTime(void) { Time_t *RtcTime = KeGetCurTime(); snprintf(TimeFmtBuf, sizeof(TimeFmtBuf), "%02d/%02d/%04d - %02d:%02d:%02d", RtcTime->day, RtcTime->month, RtcTime->year + RtcTime->century*100, RtcTime->hour, RtcTime->min, RtcTime->sec ); return TimeFmtBuf; } static void UpdateCurTime(void) { ulong frequency = PIT_FREQUENCY; uchar minRemain, hourRemain, dayRemain; CurTime.sec = (uchar)(((ulong)KeGetOriginTime()->sec * frequency + Ticks) / frequency % 60); minRemain = (uchar)(((ulong)KeGetOriginTime()->sec * frequency + Ticks) / (60 * frequency)); CurTime.min = (uchar)(((ulong)KeGetOriginTime()->min + minRemain) % 60); hourRemain = (uchar)(((ulong)KeGetOriginTime()->min + minRemain) / 60); CurTime.hour = (uchar)(((ulong)KeGetOriginTime()->hour + hourRemain) % 24); dayRemain = (uchar)(((ulong)KeGetOriginTime()->hour + hourRemain) / 24); CurTime.day = (uchar)(((ulong)KeGetOriginTime()->day + dayRemain) % 30); } Time_t* KeGetCurTime(void) { UpdateCurTime(); return &CurTime; } void KeSetCurTime(Time_t time) { CurTime = time; } static uint IsLeapYear(uint year) { if (!(year % 4)) { return 0; } return year % 100 == 0 ? (year % 400 == 0) : 1; } static uint DaysInMonth(uint month, uint year) { return (month == 2) ? (28 + IsLeapYear(year)) : 31 - (month - 1) % 7 % 2; } ulong KeGetTimeStamp(void) { Time_t *time = KeGetCurTime(); uint dpy = 365 + IsLeapYear(time->year); uint dim = DaysInMonth(time->month, time->year + time->century * 100); return time->sec + time->min * 60 + time->hour * 60 * 60 + time->day * 24 * 60 * 60 + time->month * dim * 24 * 60 * 60 + (time->year + time->century * 100) * dpy * 24 * 60 * 60; } ulong KeGetTicks(void) { return Ticks; }