U0 PortNop() {//Innoculous (reads IRQ Mask) which should take fixed time //because it's an ISA-bus standard. It takes 1.0uS-2.0uS. InU8(PIC_1_DATA); } U0 IntCore0TimerHandler(CTask *) {//Called from IntCore0TimerHandler I64 i; if (mp_count > 1) while (LBts(&sys_semas[SEMA_SYS_TIMER], 0)) PAUSE lock counts.jiffies++; counts.timer += SYS_TIMER0_PERIOD + 1; LBtr(&sys_semas[SEMA_SYS_TIMER], 0); for (i = 1; i < mp_count; i++) MPInt(I_TIMER, i); OutU8(PIC_1, PIC_EOI); //Acknowledge PIC Interrupt } I64 SysTimerRead() {//System timer count with overflow already handled. I64 i, res; PUSHFD CLI if (mp_count > 1) while (LBts(&sys_semas[SEMA_SYS_TIMER], 0)) PAUSE OutU8(PIT_CMD, PIT_CMDF_CHANNEL0); //Latch Timer0 if ((i = InU8(PIT_0) + InU8(PIT_0) << 8) == SYS_TIMER0_PERIOD) { if (InU8(PIC_1) & 1) i = -1; } res = counts.timer + SYS_TIMER0_PERIOD - i; LBtr(&sys_semas[SEMA_SYS_TIMER], 0); POPFD return res; } I64 TimeCal() { static I64 time_stamp_start = 0, timer_start = 0; I64 i; if (time_stamp_start) { PUSHFD CLI counts.time_stamp_freq = SYS_TIMER_FREQ * (TSCGet - time_stamp_start); i = SysTimerRead - timer_start; if (!i) SysErr("Timer Cal Error"); else { counts.time_stamp_freq /= i; counts.time_stamp_kHz_freq = counts.time_stamp_freq / 1000; counts.time_stamp_calibrated = TRUE; } POPFD } PUSHFD CLI timer_start = SysTimerRead; time_stamp_start = TSCGet; POPFD return counts.time_stamp_freq; } F64 tS() {//Time since boot in seconds as a float. return SysTimerRead / ToF64(SYS_TIMER_FREQ); } Bool Blink(F64 Hz=2.5) {//Return TRUE, then FALSE, then TRUE at given frequency. if (!Hz) return 0; return ToI64(counts.jiffies * 2 * Hz / JIFFY_FREQ) & 1; } U0 Busy(I64 uS) {//Loosely timed. I64 i; for (i = 0; i < uS; i++) PortNop; } U0 SleepUntil(I64 wake_jiffy) {//Not for power-saving. It is to make a program pause without hogging the CPU. Bool old_idle = LBts(&Fs->task_flags, TASKf_IDLE); Fs->wake_jiffy = wake_jiffy; Yield; LBEqual(&Fs->task_flags, TASKf_IDLE, old_idle); } U0 Sleep(I64 mS) {//Not for power-saving. It is to make a program pause without hogging the CPU. if (!mS) Yield; else SleepUntil(counts.jiffies + mS * JIFFY_FREQ / 1000); } F64 Ona2Freq(I8 ona) {//Ona to freq. Ona=60 is 432.0Hz. if (!ona) return 0; else return 432.0 / 32 * 2.0 ` (ona / 12.0); } I8 Freq2Ona(F64 freq) {//Freq to Ona. 432.0Hz is Ona=60. if (freq > 0) return ClampI64(12 * Log2(32.0 / 432.0 * freq), 1, I8_MAX); else return 0; } U0 Sound(I8 ona=0) {//Play ona, a piano key num. 0 means rest. I64 period; CSoundData *d; if (!Bt(&sys_semas[SEMA_MUTE], 0) && !LBts(&sys_semas[SEMA_SOUND], 0)) { //Mutex. Just throw-out if in use if (!ona) { screencast.ona = ona; OutU8(PCSPKR, InU8(PCSPKR) & ~3); } else if (ona != screencast.ona) { screencast.ona = ona; period = ClampI64(SYS_TIMER_FREQ / Ona2Freq(ona), 1, U16_MAX); //See ::/Doc/PIT.DD. OutU8(PIT_CMD, PIT_CMDF_CHANNEL2 | PIT_CMDF_OPMODE_SQUARE_WAVE | PIT_CMDF_ACCESS_WORD); OutU8(PIT_2, period); OutU8(PIT_2, period.u8[1]); OutU8(PCSPKR, 3 | InU8(PCSPKR)); //enable speaker } if (!IsDebugMode && screencast.record) { d = SysCAlloc(sizeof(CSoundData)); d->ona = ona; d->tS = tS; QueueInsert(d, screencast.sound_head.last); } LBtr(&sys_semas[SEMA_SOUND], 0); } } Bool ScreenCast(Bool val=ON, Bool just_audio=FALSE, U8 *print_format="B:/Tmp/%X.GR") {//WinMgr saves GR files to a dir. Bool old_val; screencast.just_audio = just_audio; if (val) { if (!(old_val = LBtr(&screencast.record, 0))) { Free(screencast.print_format); screencast.print_format = SysStrNew(print_format); screencast.t0_now = Now; screencast.sound_head.tS = screencast.t0_tS = tS; screencast.sound_head.ona = screencast.ona; LBts(&screencast.record, 0); } } else old_val = LBtr(&screencast.record, 0); Sound; return old_val; } U0 SoundReset() {//Fix stuck sound. if (Bt(&sys_semas[SEMA_SOUND], 0)) { Sleep(1); if (Bt(&sys_semas[SEMA_SOUND], 0)) { Sleep(1); LBtr(&sys_semas[SEMA_SOUND], 0); } } Sound; } U0 Beep(I8 ona=62, Bool busy=FALSE) {//Make beep at given ona freq. Sound(ona); if (busy) Busy(500000); else Sleep(500); Sound; if (busy) Busy(200000); else Sleep(200); } Bool Mute(Bool val) {//Turn-off sound. Bool res; if (val) { PUSHFD CLI Sound; res = LBts(&sys_semas[SEMA_MUTE], 0); POPFD } else res = LBtr(&sys_semas[SEMA_MUTE], 0); return res; } Bool IsMute() {//Return is-mute flag. return Bt(&sys_semas[SEMA_MUTE], 0); } Bool Silent(Bool val=ON) {//Turn-off StdOut console text. (Not sound.) return LBEqual(&Fs->display_flags, DISPLAYf_SILENT, val); } Bool IsSilent() {//Return StdOut turned-off? return Bt(&Fs->display_flags, DISPLAYf_SILENT); } Bool SysDebug(Bool val) {//Set SysDebug bit you can use while debugging. return LBEqual(&sys_semas[SEMA_DEBUG], 0, val); } Bool IsSysDebug() {//Return SysDebug bit. return Bt(&sys_semas[SEMA_DEBUG], 0); } Bool Raw(Bool val) {//Set to direct screen, BLACK & WHITE, non-windowed output mode. if (!val) LFBFlush; return !LBEqual(&Fs->display_flags, DISPLAYf_NOT_RAW, !val); } Bool IsRaw() {//Are we in BLACK & WHITE raw screen mode? return !Bt(&Fs->display_flags, DISPLAYf_NOT_RAW); } Bool SingleUser(Bool val) {//Set single-user mode. return LBEqual(&sys_semas[SEMA_SINGLE_USER], 0, val); } Bool IsSingleUser() {//Return single-user mode. return Bt(&sys_semas[SEMA_SINGLE_USER], 0); } Bool DebugMode(Bool val) {//Set debug-mode. return LBEqual(&sys_semas[SEMA_DEBUG_MODE], 0, val); } Bool IsDebugMode() {//Return debug-mode. return Bt(&sys_semas[SEMA_DEBUG_MODE], 0); } U0 ProgressBarsReset(U8 *path=NULL) {//Reset all progress bars to zero. CallExtStr("ProgressBarsRegTf", path); MemSet(sys_progresses, 0, sizeof(sys_progresses)); }