/* * timer.cpp - Time Manager emulation * * Basilisk II (C) 1997-2008 Christian Bauer * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * SEE ALSO * Inside Macintosh: Processes, chapter 3 "Time Manager" * Technote 1063: "Inside Macintosh: Processes: Time Manager Addenda" */ #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "timer.h" #define DEBUG 0 #include "debug.h" // Set this to 1 to enable TMQueue management (doesn't work) #define TM_QUEUE 0 // Definitions for Time Manager enum { // TMTask struct tmAddr = 6, tmCount = 10, tmWakeUp = 14, tmReserved = 18 }; // Array of additional info for each installed TMTask struct TMDesc { uint32 task; // Mac address of associated TMTask tm_time_t wakeup; // Time this task is scheduled for execution bool in_use; // Flag: descriptor in use }; const int NUM_DESCS = 64; // Maximum number of descriptors static TMDesc desc[NUM_DESCS]; /* * Allocate descriptor for given TMTask in list */ static int alloc_desc(uint32 tm) { // Search for first free descriptor for (int i=0; i= 0) printf("WARNING: InsTime(): Task re-inserted\n"); else { int i = alloc_desc(tm); if (i < 0) printf("FATAL: InsTime(): No free Time Manager descriptor\n"); } return 0; } /* * Remove timer task */ int16 RmvTime(uint32 tm) { D(bug("RmvTime %08lx\n", tm)); // Find descriptor int i = find_desc(tm); if (i < 0) { printf("WARNING: RmvTime(%08x): Descriptor not found\n", tm); return 0; } // Task active? if (ReadMacInt16(tm + qType) & 0x8000) { // Yes, make task inactive and remove it from the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); dequeue_tm(tm); // Compute remaining time tm_time_t remaining, current; timer_current_time(current); timer_sub_time(remaining, desc[i].wakeup, current); WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining)); } else WriteMacInt32(tm + tmCount, 0); D(bug(" tmCount %d\n", ReadMacInt32(tm + tmCount))); // Free descriptor free_desc(i); return 0; } /* * Start timer task */ int16 PrimeTime(uint32 tm, int32 time) { D(bug("PrimeTime %08x, time %d\n", tm, time)); // Find descriptor int i = find_desc(tm); if (i < 0) { printf("FATAL: PrimeTime(): Descriptor not found\n"); return 0; } // Extended task? if (ReadMacInt16(tm + qType) & 0x4000) { // Convert delay time tm_time_t delay; timer_mac2host_time(delay, time); // Yes, tmWakeUp set? if (ReadMacInt32(tm + tmWakeUp)) { //!! PrimeTime(0) means continue previous delay // (save wakeup time in RmvTime?) if (time == 0) printf("WARNING: Unsupported PrimeTime(0)\n"); // Yes, calculate wakeup time relative to last scheduled time tm_time_t wakeup; timer_add_time(wakeup, desc[i].wakeup, delay); desc[i].wakeup = wakeup; } else { // No, calculate wakeup time relative to current time tm_time_t now; timer_current_time(now); timer_add_time(desc[i].wakeup, now, delay); } // Set tmWakeUp to indicate that task was scheduled WriteMacInt32(tm + tmWakeUp, 0x12345678); } else { // Not extended task, calculate wakeup time relative to current time tm_time_t delay; timer_mac2host_time(delay, time); timer_current_time(desc[i].wakeup); timer_add_time(desc[i].wakeup, desc[i].wakeup, delay); } // Make task active and enqueue it in the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000); enqueue_tm(tm); return 0; } /* * Timer interrupt function (executed as part of 60Hz interrupt) */ void TimerInterrupt(void) { // Look for active TMTasks that have expired tm_time_t now; timer_current_time(now); for (int i=0; i