home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / timer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-02  |  6.4 KB  |  319 lines

  1. /*
  2.  *  timer.cpp - Time Manager emulation
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. /*
  22.  *  SEE ALSO
  23.  *    Inside Macintosh: Processes, chapter 3 "Time Manager"
  24.  *    Technote 1063: "Inside Macintosh: Processes: Time Manager Addenda"
  25.  */
  26.  
  27. #include <stdio.h>
  28.  
  29. #include "sysdeps.h"
  30. #include "cpu_emulation.h"
  31. #include "main.h"
  32. #include "macos_util.h"
  33. #include "timer.h"
  34.  
  35. #define DEBUG 0
  36. #include "debug.h"
  37.  
  38.  
  39. // Set this to 1 to enable TMQueue management (doesn't work)
  40. #define TM_QUEUE 0
  41.  
  42.  
  43. // Definitions for Time Manager
  44. enum {    // TMTask struct
  45.     tmAddr = 6,
  46.     tmCount = 10,
  47.     tmWakeUp = 14,
  48.     tmReserved = 18
  49. };
  50.  
  51.  
  52. // Array of additional info for each installed TMTask
  53. struct TMDesc {
  54.     uint32 task;        // Mac address of associated TMTask
  55.     tm_time_t wakeup;    // Time this task is scheduled for execution
  56.     bool in_use;        // Flag: descriptor in use
  57. };
  58.  
  59. const int NUM_DESCS = 64;        // Maximum number of descriptors
  60. static TMDesc desc[NUM_DESCS];
  61.  
  62.  
  63. /*
  64.  *  Allocate descriptor for given TMTask in list
  65.  */
  66.  
  67. static int alloc_desc(uint32 tm)
  68. {
  69.     // Search for first free descriptor
  70.     for (int i=0; i<NUM_DESCS; i++)
  71.         if (!desc[i].in_use) {
  72.             desc[i].task = tm;
  73.             desc[i].in_use = true;
  74.             return i;
  75.         }
  76.     return -1;
  77. }
  78.  
  79.  
  80. /*
  81.  *  Free descriptor in list
  82.  */
  83.  
  84. inline static void free_desc(int i)
  85. {
  86.     desc[i].in_use = false;
  87. }
  88.  
  89.  
  90. /*
  91.  *  Find descriptor associated with given TMTask
  92.  */
  93.  
  94. inline static int find_desc(uint32 tm)
  95. {
  96.     for (int i=0; i<NUM_DESCS; i++)
  97.         if (desc[i].in_use && desc[i].task == tm)
  98.             return i;
  99.     return -1;
  100. }
  101.  
  102.  
  103. /*
  104.  *  Enqueue task in Time Manager queue
  105.  */
  106.  
  107. static void enqueue_tm(uint32 tm)
  108. {
  109. #if TM_QUEUE
  110.     uint32 tm_var = ReadMacInt32(0xb30);
  111.     WriteMacInt32(tm + qLink, ReadMacInt32(tm_var));
  112.     WriteMacInt32(tm_var, tm);
  113. #endif
  114. }
  115.  
  116.  
  117. /*
  118.  *  Remove task from Time Manager queue
  119.  */
  120.  
  121. static void dequeue_tm(uint32 tm)
  122. {
  123. #if TM_QUEUE
  124.     uint32 p = ReadMacInt32(0xb30);
  125.     while (p) {
  126.         uint32 next = ReadMacInt32(p + qLink);
  127.         if (next == tm) {
  128.             WriteMacInt32(p + qLink, ReadMacInt32(next + qLink));
  129.             return;
  130.         }
  131.     }
  132. #endif
  133. }
  134.  
  135.  
  136. /*
  137.  *  Initialize Time Manager
  138.  */
  139.  
  140. void TimerInit(void)
  141. {
  142.     // Mark all descriptors as inactive
  143.     for (int i=0; i<NUM_DESCS; i++)
  144.         free_desc(i);
  145. }
  146.  
  147.  
  148. /*
  149.  *  Exit Time Manager
  150.  */
  151.  
  152. void TimerExit(void)
  153. {
  154. }
  155.  
  156.  
  157. /*
  158.  *  Emulator reset, remove all timer tasks
  159.  */
  160.  
  161. void TimerReset(void)
  162. {
  163.     // Mark all descriptors as inactive
  164.     for (int i=0; i<NUM_DESCS; i++)
  165.         free_desc(i);
  166. }
  167.  
  168.  
  169. /*
  170.  *  Insert timer task
  171.  */
  172.  
  173. int16 InsTime(uint32 tm, uint16 trap)
  174. {
  175.     D(bug("InsTime %08lx, trap %04x\n", tm, trap));
  176.     WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x1fff | (trap << 4) & 0x6000);
  177.     if (find_desc(tm) >= 0)
  178.         printf("WARNING: InsTime(): Task re-inserted\n");
  179.     else {
  180.         int i = alloc_desc(tm);
  181.         if (i < 0)
  182.             printf("FATAL: InsTime(): No free Time Manager descriptor\n");
  183.     }
  184.     return 0;
  185. }
  186.  
  187.  
  188. /*
  189.  *  Remove timer task
  190.  */
  191.  
  192. int16 RmvTime(uint32 tm)
  193. {
  194.     D(bug("RmvTime %08lx\n", tm));
  195.  
  196.     // Find descriptor
  197.     int i = find_desc(tm);
  198.     if (i < 0) {
  199.         printf("WARNING: RmvTime(%08x): Descriptor not found\n", tm);
  200.         return 0;
  201.     }
  202.  
  203.     // Task active?
  204.     if (ReadMacInt16(tm + qType) & 0x8000) {
  205.  
  206.         // Yes, make task inactive and remove it from the Time Manager queue
  207.         WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
  208.         dequeue_tm(tm);
  209.  
  210.         // Compute remaining time
  211.         tm_time_t remaining, current;
  212.         timer_current_time(current);
  213.         timer_sub_time(remaining, desc[i].wakeup, current);
  214.         WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining));
  215.     } else
  216.         WriteMacInt32(tm + tmCount, 0);
  217.     D(bug(" tmCount %d\n", ReadMacInt32(tm + tmCount)));
  218.  
  219.     // Free descriptor
  220.     free_desc(i);
  221.     return 0;
  222. }
  223.  
  224.  
  225. /*
  226.  *  Start timer task
  227.  */
  228.  
  229. int16 PrimeTime(uint32 tm, int32 time)
  230. {
  231.     D(bug("PrimeTime %08x, time %d\n", tm, time));
  232.  
  233.     // Find descriptor
  234.     int i = find_desc(tm);
  235.     if (i < 0) {
  236.         printf("FATAL: PrimeTime(): Descriptor not found\n");
  237.         return 0;
  238.     }
  239.  
  240.     // Extended task?
  241.     if (ReadMacInt16(tm + qType) & 0x4000) {
  242.  
  243.         // Convert delay time
  244.         tm_time_t delay;
  245.         timer_mac2host_time(delay, time);
  246.  
  247.         // Yes, tmWakeUp set?
  248.         if (ReadMacInt32(tm + tmWakeUp)) {
  249.  
  250.             //!! PrimeTime(0) means continue previous delay
  251.             // (save wakeup time in RmvTime?)
  252.             if (time == 0) {
  253.                 printf("FATAL: Unsupported PrimeTime(0)\n");
  254.                 return 0;
  255.             }
  256.  
  257.             // Yes, calculate wakeup time relative to last scheduled time
  258.             tm_time_t wakeup;
  259.             timer_add_time(wakeup, desc[i].wakeup, delay);
  260.             desc[i].wakeup = wakeup;
  261.  
  262.         } else {
  263.  
  264.             // No, calculate wakeup time relative to current time
  265.             tm_time_t now;
  266.             timer_current_time(now);
  267.             timer_add_time(desc[i].wakeup, now, delay);
  268.         }
  269.  
  270.         // Set tmWakeUp to indicate that task was scheduled
  271.         WriteMacInt32(tm + tmWakeUp, 0x12345678);
  272.  
  273.     } else {
  274.  
  275.         // Not extended task, calculate wakeup time relative to current time
  276.         tm_time_t delay;
  277.         timer_mac2host_time(delay, time);
  278.         timer_current_time(desc[i].wakeup);
  279.         timer_add_time(desc[i].wakeup, desc[i].wakeup, delay);
  280.     }
  281.  
  282.     // Make task active and enqueue it in the Time Manager queue
  283.     WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000);
  284.     enqueue_tm(tm);
  285.     return 0;
  286. }
  287.  
  288.  
  289. /*
  290.  *  Timer interrupt function (executed as part of 60Hz interrupt)
  291.  */
  292.  
  293. void TimerInterrupt(void)
  294. {
  295.     // Look for active TMTasks that have expired
  296.     tm_time_t now;
  297.     timer_current_time(now);
  298.     for (int i=0; i<NUM_DESCS; i++)
  299.         if (desc[i].in_use) {
  300.             uint32 tm = desc[i].task;
  301.             if ((ReadMacInt16(tm + qType) & 0x8000) && timer_cmp_time(desc[i].wakeup, now) < 0) {
  302.  
  303.                 // Found one, mark as inactive and remove it from the Time Manager queue
  304.                 WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
  305.                 dequeue_tm(tm);
  306.  
  307.                 // Call timer function
  308.                 uint32 addr = ReadMacInt32(tm + tmAddr);
  309.                 if (addr) {
  310.                     D(bug("Calling TimeTask %08lx, addr %08lx\n", tm, addr));
  311.                     M68kRegisters r;
  312.                     r.a[0] = addr;
  313.                     r.a[1] = tm;
  314.                     Execute68k(addr, &r);
  315.                 }
  316.             }
  317.         }
  318. }
  319.