]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/clock.cpp
Misc. small fixes/changes.
[virtualjaguar] / src / clock.cpp
index 8ca3bc1d2f9d3a5f7c71a7e160f6d1bdf029c018..f4ef41963c9a1fc8010c16667d3eedd1fac0b3b0 100644 (file)
 //
-// Clock handler
+// System time handlers
 //
-// by cal2
-// GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
-// Cleanups by James L. Hammons
+// by James L. Hammons
 //
+// STILL TO DO:
+//
+// - Handling for an event that occurs NOW
+//
+
+//#include <SDL.h>
+//#include "SDL.h"
+//#include "SDL_opengl.h"
+//#include "jaguar.h"
+//#include "m68k.h"
+//#include "gpu.h"
+//#include "dsp.h"
+//#include "settings.h"
+//#include "video.h"
+#include "log.h"
+#include "clock.h"
+
+#define EVENT_LIST_SIZE       512
+
+/*
+// Current execution path:
+
+do
+{
+       HandleJoystick
+
+       // Execute one frame
 
-#include "jaguar.h"
+    for(int i=0; i<numLines; i++)
+    {
+               ExecuteM68K
+               ExecutePITs
+               ExecuteGPU
+               ExecuteDSP
+               // Render Scanline
+               CallObjectProcessor
+               MoveLineBufToBackBuf
+    }
 
+       RenderBackbuffer
+}
+while (true)
+
+// What we need to do:
 
-void clock_init(void)
+Set up timers (frame [for native render--on vblank interval?], OP line, PITs)
+
+do
 {
-       clock_reset();
+       double timeToNextEvent = GetTimeToNextEvent();
+
+       m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
+       GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+       DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+
+       HandleNextEvent();
 }
+while (true)
+
+
+*/
+
+// Now, a bit of weirdness: It seems that the number of lines displayed on the screen
+// makes the effective refresh rate either 30 or 25 Hz!
 
-void clock_reset(void)
+// NOTE ABOUT TIMING SYSTEM DATA STRUCTURES:
+
+// A queue won't work for this system because we can't guarantee that an event will go
+// in with a time that is later than the ones already queued up. So we just use a simple
+// list.
+
+// Although if we used an insertion sort we could, but it wouldn't work for adjusting
+// times...
+
+struct Event
+{
+    bool valid;
+    double eventTime;
+    void (* timerCallback)(void);
+};
+
+Event eventList[EVENT_LIST_SIZE];
+uint32 nextEvent;
+
+void InitializeEventList(void)
 {
+    for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
+        eventList[i].valid = false;
 }
 
-void clock_done(void)
+//We just slap the next event into the list, no checking, no nada...
+void SetCallbackTime(void (* callback)(void), double time)
 {
+    for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
+    {
+        if (!eventList[i].valid)
+        {
+//WriteLog("SCT: Found callback slot #%u...\n", i);
+            eventList[i].timerCallback = callback;
+            eventList[i].eventTime = time;
+            eventList[i].valid = true;
+
+            return;
+        }
+    }
+
+    WriteLog("SetCallbackTime() failed to find an empty slot in the list!\n");
 }
 
-void clock_byte_write(uint32 offset, uint8 data)
+void RemoveCallback(void (* callback)(void))
 {
+    for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
+    {
+        if (eventList[i].valid && eventList[i].timerCallback == callback)
+        {
+            eventList[i].valid = false;
+
+            return;
+        }
+    }
 }
 
-void clock_word_write(uint32 offset, uint16 data)
+void AdjustCallbackTime(void (* callback)(void), double time)
 {
+    for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
+    {
+        if (eventList[i].valid && eventList[i].timerCallback == callback)
+        {
+            eventList[i].eventTime = time;
+
+            return;
+        }
+    }
 }
 
-uint8 clock_byte_read(uint32 offset)
+double GetTimeToNextEvent(void)
 {
-       return 0xFF;
+    double time = 0;
+    bool firstTime = true;
+
+    for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
+    {
+        if (eventList[i].valid)
+        {
+            if (firstTime)
+                time = eventList[i].eventTime, nextEvent = i, firstTime = false;
+            else
+            {
+                if (eventList[i].eventTime < time)
+                    time = eventList[i].eventTime, nextEvent = i;
+            }
+        }
+    }
+
+    return time;
 }
 
-uint16 clock_word_read(uint32 offset)
+void HandleNextEvent(void)
 {
-       return 0xFFFF;
+    double elapsedTime = eventList[nextEvent].eventTime;
+    void (* event)(void) = eventList[nextEvent].timerCallback;
+
+    for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
+        if (eventList[i].valid)
+            eventList[i].eventTime -= elapsedTime;
+
+    eventList[nextEvent].valid = false;      // Remove event from list...
+
+    (*event)();
 }
+
+
+/*
+void OPCallback(void)
+{
+    DoFunkyOPStuffHere();
+
+    SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
+}
+
+void VICallback(void)
+{
+    double oneFrameInUsec = 16666.66666666;
+    SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
+}
+
+void JaguarInit(void)
+{
+    double oneFrameInUsec = 16666.66666666;
+    SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
+    SetCallbackTime(OPCallback, );
+}
+
+void JaguarExec(void)
+{
+    while (true)
+    {
+        double timeToNextEvent = GetTimeToNextEvent();
+
+        m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
+        GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+        DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+
+        if (!HandleNextEvent())
+            break;
+    }
+}
+
+// NOTES: The timers count RISC cycles, and when the dividers count down to zero they can interrupt either the DSP and/or CPU.
+
+// NEW:
+// TOM Programmable Interrupt Timer handler
+// NOTE: TOM's PIT is only enabled if the prescaler is != 0
+//       The PIT only generates an interrupt when it counts down to zero, not when loaded!
+
+void TOMResetPIT()
+{
+    // Need to remove previous timer from the queue, if it exists...
+    RemoveCallback(TOMPITCallback);
+
+    if (TOMPITPrescaler)
+    {
+        double usecs = (TOMPITPrescaler + 1) * (TOMPITDivider + 1) * RISC_CYCLE_IN_USEC;
+        SetCallbackTime(TOMPITCallback, usecs);
+    }
+}
+
+void TOMPITCallback(void)
+{
+    INT1_RREG |= 0x08;                         // Set TOM PIT interrupt pending
+    GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE);  // It does the 'IRQ enabled' checking
+
+    if (INT1_WREG & 0x08)
+        m68k_set_irq(7);                       // Generate 68K NMI
+
+    TOMResetPIT();
+}
+
+// Small problem with this approach: If a timer interrupt is already pending,
+// the pending timer needs to be replaced with the new one! (Taken care of above, BTW...)
+
+TOMWriteWord(uint32 address, uint16 data)
+{
+    if (address == PIT0)
+    {
+        TOMPITPrescaler = data;
+        TOMResetPIT();
+    }
+    else if (address == PIT1)
+    {
+        TOMPITDivider = data;
+        TOMResetPIT();
+    }
+}
+
+*/