#include "dac.h"
#include "SDL.h"
-//#include "gui.h"
+#include "cdrom.h"
+#include "dsp.h"
+#include "event.h"
+#include "jerry.h"
#include "jaguar.h"
#include "log.h"
#include "m68k.h"
//#include "memory.h"
#include "settings.h"
+
//#define DEBUG_DAC
-#define BUFFER_SIZE 0x10000 // Make the DAC buffers 64K x 16 bits
+#define BUFFER_SIZE 0x10000 // Make the DAC buffers 64K x 16 bits
+#define DAC_AUDIO_RATE 48000 // Set the audio rate to 48 KHz
// Jaguar memory locations
// Global variables
-//uint16 lrxd, rrxd; // I2S ports (into Jaguar)
+//uint16 lrxd, rrxd; // I2S ports (into Jaguar)
// Local variables
// endian when looking at the sample buffer, i.e., no need to worry about it.
static uint16 DACBuffer[BUFFER_SIZE];
-static uint8 SCLKFrequencyDivider = 19; // Default is roughly 22 KHz (20774 Hz in NTSC mode)
+static uint8 SCLKFrequencyDivider = 19; // Default is roughly 22 KHz (20774 Hz in NTSC mode)
/*static*/ uint16 serialMode = 0;
// Private function prototypes
void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
+void SDLSoundCallbackNew(void * userdata, Uint8 * buffer, int length);
+void DSPSampleCallback(void);
+
//
// Initialize the SDL sound system
return;
}
+#ifdef NEW_DAC_CODE
+ desired.freq = DAC_AUDIO_RATE;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = 2048;
+ desired.callback = SDLSoundCallbackNew;
+#else
// memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
// DACBuffer = (uint16 *)memory_malloc(BUFFER_SIZE * sizeof(uint16), "DAC buffer");
// desired.samples = 4096; // Let's try a 4K buffer (can always go lower)
desired.samples = 2048; // Let's try a 2K buffer (can always go lower)
desired.callback = SDLSoundCallback;
+#endif
if (SDL_OpenAudio(&desired, NULL) < 0) // NULL means SDL guarantees what we want
WriteLog("DAC: Failed to initialize SDL sound...\n");
{
SDLSoundInitialized = true;
DACReset();
- SDL_PauseAudio(false); // Start playback!
- WriteLog("DAC: Successfully initialized.\n");
+ SDL_PauseAudio(false); // Start playback!
+ WriteLog("DAC: Successfully initialized. Sample rate: %u\n", desired.freq);
}
+
+ ltxd = lrxd = desired.silence;
+
+ uint32_t riscClockRate = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL);
+ uint32_t cyclesPerSample = riscClockRate / DAC_AUDIO_RATE;
+ WriteLog("DAC: RISC clock = %u, cyclesPerSample = %u\n", riscClockRate, cyclesPerSample);
}
+
//
// Reset the sound buffer FIFOs
//
void DACReset(void)
{
LeftFIFOHeadPtr = LeftFIFOTailPtr = 0, RightFIFOHeadPtr = RightFIFOTailPtr = 1;
+ ltxd = lrxd = desired.silence;
}
+
//
// Close down the SDL sound subsystem
//
// SDL callback routine to fill audio buffer
//
// Note: The samples are packed in the buffer in 16 bit left/16 bit right pairs.
+// Also, length is the length of the buffer in BYTES
+//
+//static double timePerSample = 0;
+static Uint8 * sampleBuffer;
+static int bufferIndex = 0;
+static int numberOfSamples = 0;
+static bool bufferDone = false;
+void SDLSoundCallbackNew(void * userdata, Uint8 * buffer, int length)
+{
+ // 1st, check to see if the DSP is running. If not, fill the buffer with L/RXTD and exit.
+
+ if (!DSPIsRunning())
+ {
+ for(int i=0; i<(length/2); i+=2)
+ {
+ ((uint16_t *)buffer)[i + 0] = ltxd;
+ ((uint16_t *)buffer)[i + 1] = rtxd;
+ }
+
+ return;
+ }
+
+ // The length of time we're dealing with here is 1/48000 s, so we multiply this
+ // by the number of cycles per second to get the number of cycles for one sample.
+ uint32_t riscClockRate = (vjs.hardwareTypeNTSC ? RISC_CLOCK_RATE_NTSC : RISC_CLOCK_RATE_PAL);
+ uint32_t cyclesPerSample = riscClockRate / DAC_AUDIO_RATE;
+ // This is the length of time
+// timePerSample = (1000000.0 / (double)riscClockRate) * ();
+
+ // Now, run the DSP for that length of time for each sample we need to make
+
+#if 0
+ for(int i=0; i<(length/2); i+=2)
+ {
+//This stuff is from the old Jaguar execute loop. New stuff is timer based...
+//which means we need to figure that crap out, and how to make it work here.
+//Seems like we need two separate timing queues. Tho not sure how to make that work here...
+//Maybe like the "frameDone" in JaguarExecuteNew() in jaguar.cpp?
+// JERRYExecPIT(cyclesPerSample);
+// JERRYI2SExec(cyclesPerSample);
+// BUTCHExec(cyclesPerSample);
+
+ if (vjs.DSPEnabled)
+ {
+ if (vjs.usePipelinedDSP)
+ DSPExecP2(cyclesPerSample);
+ else
+ DSPExec(cyclesPerSample);
+ }
+
+ ((uint16_t *)buffer)[i + 0] = ltxd;
+ ((uint16_t *)buffer)[i + 1] = rtxd;
+ }
+#else
+ bufferIndex = 0;
+ sampleBuffer = buffer;
+ numberOfSamples = length / 2;
+ bufferDone = false;
+
+ SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY);
+
+ // These timings are tied to NTSC, need to fix that in event.cpp/h!
+ do
+ {
+ double timeToNextEvent = GetTimeToNextEvent(EVENT_JERRY);
+
+ if (vjs.DSPEnabled)
+ {
+ if (vjs.usePipelinedDSP)
+ DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent));
+ else
+ DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+ }
+
+ HandleNextEvent(EVENT_JERRY);
+ }
+ while (!bufferDone);
+
+ // We do this to prevent problems with trying to write past the end of the buffer...
+// RemoveCallback(DSPSampleCallback);
+#endif
+}
+
+
+void DSPSampleCallback(void)
+{
+ ((uint16_t *)sampleBuffer)[bufferIndex + 0] = ltxd;
+ ((uint16_t *)sampleBuffer)[bufferIndex + 1] = rtxd;
+ bufferIndex += 2;
+
+ if (bufferIndex == numberOfSamples)
+ {
+ bufferDone = true;
+ return;
+ }
+
+ SetCallbackTime(DSPSampleCallback, 1000000.0 / (double)DAC_AUDIO_RATE, EVENT_JERRY);
+}
+#if 0
+ frameDone = false;
+
+ do
+ {
+ double timeToNextEvent = GetTimeToNextEvent();
+//WriteLog("JEN: Time to next event (%u) is %f usec (%u RISC cycles)...\n", nextEvent, timeToNextEvent, USEC_TO_RISC_CYCLES(timeToNextEvent));
+
+ m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
+
+ if (vjs.GPUEnabled)
+ GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+
+#ifndef NEW_DAC_CODE
+ if (vjs.DSPEnabled)
+ {
+ if (vjs.usePipelinedDSP)
+ DSPExecP2(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Pipelined DSP execution (3 stage)...
+ else
+ DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
+ }
+#endif
+
+ HandleNextEvent();
+ }
+ while (!frameDone);
+#endif
+
+
+//
+// SDL callback routine to fill audio buffer
+//
+// Note: The samples are packed in the buffer in 16 bit left/16 bit right pairs.
+// Also, length is the length of the buffer in BYTES
//
void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
{
// WriteLog("DAC: Silence...!\n");
}
+
//
// Calculate the frequency of SCLK * 32 using the divider
//
return systemClockFrequency / (32 * (2 * (SCLKFrequencyDivider + 1)));
}
+
static int oldFreq = 0;
void DACSetNewFrequency(int freq)
{
+#ifdef NEW_DAC_CODE
+#else
if (freq == oldFreq)
return;
if (SDLSoundInitialized)
SDL_PauseAudio(false); // Start playback!
+#endif
}
+
//
// LTXD/RTXD/SCLK/SMODE ($F1A148/4C/50/54)
//
DACWriteWord(offset - 3, (uint16)data);
}
+
void DACWriteWord(uint32 offset, uint16 data, uint32 who/*= UNKNOWN*/)
{
if (offset == LTXD + 2)
{
if (!SDLSoundInitialized)
return;
+
+#ifdef NEW_DAC_CODE
+ ltxd = data;
+#else
// Spin until buffer has been drained (for too fast processors!)...
//Small problem--if Head == 0 and Tail == buffer end, then this will fail... !!! FIX !!!
//[DONE]
LeftFIFOTailPtr = (LeftFIFOTailPtr + 2) % BUFFER_SIZE;
DACBuffer[LeftFIFOTailPtr] = data;
SDL_UnlockAudio();
+#endif
}
else if (offset == RTXD + 2)
{
RTail=DB, RHead=60D9, BUFFER_SIZE-1=FFFF
From while: Tail=60DA, Head=60D8
*/
+#ifdef NEW_DAC_CODE
+ rtxd = data;
+#else
#warning Spinlock problem--!!! FIX !!!
#warning Odd: The right FIFO is empty, but the left FIFO is full!
// Spin until buffer has been drained (for too fast processors!)...
else
WriteLog("DAC: Ran into FIFO's right tail pointer!\n");
#endif*/
+#endif
}
else if (offset == SCLK + 2) // Sample rate
{
if ((uint8)data != SCLKFrequencyDivider)
{
SCLKFrequencyDivider = (uint8)data;
+#ifdef NEW_DAC_CODE
+#else
//Of course a better way would be to query the hardware to find the upper limit...
if (data > 7) // Anything less than 8 is too high!
{
if (SDLSoundInitialized)
SDL_PauseAudio(false); // Start playback!
}
+#endif
}
}
else if (offset == SMODE + 2)
}
}
+
//
// LRXD/RRXD/SSTAT ($F1A148/4C/50)
//
return 0xFF;
}
+
//static uint16 fakeWord = 0;
uint16 DACReadWord(uint32 offset, uint32 who/*= UNKNOWN*/)
{
#ifndef __DAC_H__
#define __DAC_H__
+//this is here, because we have to compensate in more than just dac.cpp...
+#define NEW_DAC_CODE // New code paths!
+
//#include "types.h"
#include "memory.h"
// GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
}
+bool DSPIsRunning(void)
+{
+ return (DSP_RUNNING ? true : false);
+}
+
void DSPInit(void)
{
// memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
void DSPWriteWord(uint32 offset, uint16 data, uint32 who = UNKNOWN);
void DSPWriteLong(uint32 offset, uint32 data, uint32 who = UNKNOWN);
void DSPReleaseTimeslice(void);
+bool DSPIsRunning(void);
void DSPExecP(int32 cycles);
void DSPExecP2(int32 cycles);
#include "event.h"
#include "log.h"
+#include "types.h"
-#define EVENT_LIST_SIZE 512
-/*
-// Current execution path:
-
-do
-{
- HandleJoystick
-
- // Execute one frame
-
- for(int i=0; i<numLines; i++)
- {
- ExecuteM68K
- ExecutePITs
- ExecuteGPU
- ExecuteDSP
- // Render Scanline
- CallObjectProcessor
- MoveLineBufToBackBuf
- }
-
- RenderBackbuffer
-}
-while (true)
+//#define EVENT_LIST_SIZE 512
+#define EVENT_LIST_SIZE 32
-// What we need to do:
-
-Set up timers (frame [for native render--on vblank interval?], OP line, PITs)
-
-do
-{
- 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!
struct Event
{
- bool valid;
- double eventTime;
- void (* timerCallback)(void);
+ bool valid;
+ int eventType;
+ double eventTime;
+ void (* timerCallback)(void);
};
-Event eventList[EVENT_LIST_SIZE];
-uint32 nextEvent;
+
+static Event eventList[EVENT_LIST_SIZE];
+static Event eventListJERRY[EVENT_LIST_SIZE];
+static uint32_t nextEvent;
+static uint32_t nextEventJERRY;
+static uint32_t numberOfEvents;
+
void InitializeEventList(void)
{
- for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
- eventList[i].valid = false;
+ for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
+ {
+ eventList[i].valid = false;
+ eventListJERRY[i].valid = false;
+ }
+
+ numberOfEvents = 0;
+ WriteLog("EVENT: Cleared event list.\n");
}
-//We just slap the next event into the list, no checking, no nada...
-void SetCallbackTime(void (* callback)(void), double time)
+
+// Set callback time in µs. This is fairly arbitrary, but works well enough for our purposes.
+//We just slap the next event into the list in the first available slot, no checking, no nada...
+void SetCallbackTime(void (* callback)(void), double time, int type/*= EVENT_MAIN*/)
{
- 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");
+ if (type == EVENT_MAIN)
+ {
+ for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
+ {
+ if (!eventList[i].valid)
+ {
+//WriteLog("EVENT: Found callback slot #%u...\n", i);
+ eventList[i].timerCallback = callback;
+ eventList[i].eventTime = time;
+ eventList[i].eventType = type;
+ eventList[i].valid = true;
+ numberOfEvents++;
+
+ return;
+ }
+ }
+
+ WriteLog("EVENT: SetCallbackTime() failed to find an empty slot in the main list (%u events)!\n", numberOfEvents);
+ }
+ else
+ {
+ for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
+ {
+ if (!eventListJERRY[i].valid)
+ {
+//WriteLog("EVENT: Found callback slot #%u...\n", i);
+ eventListJERRY[i].timerCallback = callback;
+ eventListJERRY[i].eventTime = time;
+ eventListJERRY[i].eventType = type;
+ eventListJERRY[i].valid = true;
+ numberOfEvents++;
+
+ return;
+ }
+ }
+
+ WriteLog("EVENT: SetCallbackTime() failed to find an empty slot in the main list (%u events)!\n", numberOfEvents);
+ }
}
+
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;
- }
- }
+ for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
+ {
+ if (eventList[i].valid && eventList[i].timerCallback == callback)
+ {
+ eventList[i].valid = false;
+ numberOfEvents--;
+
+ return;
+ }
+ else if (eventListJERRY[i].valid && eventListJERRY[i].timerCallback == callback)
+ {
+ eventListJERRY[i].valid = false;
+ numberOfEvents--;
+
+ return;
+ }
+ }
}
+
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;
- }
- }
+ for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
+ {
+ if (eventList[i].valid && eventList[i].timerCallback == callback)
+ {
+ eventList[i].eventTime = time;
+
+ return;
+ }
+ else if (eventListJERRY[i].valid && eventListJERRY[i].timerCallback == callback)
+ {
+ eventListJERRY[i].eventTime = time;
+
+ return;
+ }
+ }
}
-double GetTimeToNextEvent(void)
-{
- 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;
-}
-void HandleNextEvent(void)
+//
+// Since our list is unordered WRT time, we have to search it to find the next event
+// Returns time to next event & sets nextEvent to that event
+//
+double GetTimeToNextEvent(int type/*= EVENT_MAIN*/)
{
- 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;
+#if 0
+ 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;
+ }
+ }
+ }
+#else
+ if (type == EVENT_MAIN)
+ {
+ double time = eventList[0].eventTime;
+ nextEvent = 0;
+
+ for(uint32_t i=1; i<EVENT_LIST_SIZE; i++)
+ {
+ if (eventList[i].valid && (eventList[i].eventTime < time))
+ {
+ time = eventList[i].eventTime;
+ nextEvent = i;
+ }
+ }
+
+ return time;
+ }
+ else
+ {
+ double time = eventListJERRY[0].eventTime;
+ nextEventJERRY = 0;
+
+ for(uint32_t i=1; i<EVENT_LIST_SIZE; i++)
+ {
+ if (eventListJERRY[i].valid && (eventListJERRY[i].eventTime < time))
+ {
+ time = eventListJERRY[i].eventTime;
+ nextEventJERRY = i;
+ }
+ }
+
+ return time;
+ }
+#endif
+}
- eventList[nextEvent].valid = false; // Remove event from list...
- (*event)();
+void HandleNextEvent(int type/*= EVENT_MAIN*/)
+{
+ if (type == EVENT_MAIN)
+ {
+ double elapsedTime = eventList[nextEvent].eventTime;
+ void (* event)(void) = eventList[nextEvent].timerCallback;
+
+ for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
+ {
+ //We can skip the check & just subtract from everything, since the check is probably
+ //just as heavy as the code after and we won't use the elapsed time from an invalid event anyway.
+ // if (eventList[i].valid)
+ eventList[i].eventTime -= elapsedTime;
+ }
+
+ eventList[nextEvent].valid = false; // Remove event from list...
+ numberOfEvents--;
+
+ (*event)();
+ }
+ else
+ {
+ double elapsedTime = eventListJERRY[nextEventJERRY].eventTime;
+ void (* event)(void) = eventListJERRY[nextEventJERRY].timerCallback;
+
+ for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
+ {
+ //We can skip the check & just subtract from everything, since the check is probably
+ //just as heavy as the code after and we won't use the elapsed time from an invalid event anyway.
+ // if (eventList[i].valid)
+ eventListJERRY[i].eventTime -= elapsedTime;
+ }
+
+ eventListJERRY[nextEventJERRY].valid = false; // Remove event from list...
+ numberOfEvents--;
+
+ (*event)();
+ }
}
/*
void OPCallback(void)
{
- DoFunkyOPStuffHere();
+ DoFunkyOPStuffHere();
- SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
+ SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
}
void VICallback(void)
{
- double oneFrameInUsec = 16666.66666666;
- SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
+ double oneFrameInUsec = 16666.66666666;
+ SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
}
void JaguarInit(void)
{
- double oneFrameInUsec = 16666.66666666;
- SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
- SetCallbackTime(OPCallback, );
+ double oneFrameInUsec = 16666.66666666;
+ SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
+ SetCallbackTime(OPCallback, );
}
void JaguarExec(void)
{
- while (true)
- {
- double timeToNextEvent = GetTimeToNextEvent();
+ while (true)
+ {
+ double timeToNextEvent = GetTimeToNextEvent();
- m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
- GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
- DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+ m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
+ GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+ DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
- if (!HandleNextEvent())
- break;
- }
+ 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.
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);
- }
+ // 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
+ 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(2); // Generate 68K NMI
+ if (INT1_WREG & 0x08)
+ m68k_set_irq(2); // Generate 68K NMI
- TOMResetPIT();
+ TOMResetPIT();
}
// Small problem with this approach: If a timer interrupt is already pending,
TOMWriteWord(uint32 address, uint16 data)
{
- if (address == PIT0)
- {
- TOMPITPrescaler = data;
- TOMResetPIT();
- }
- else if (address == PIT1)
- {
- TOMPITDivider = data;
- TOMResetPIT();
- }
+ if (address == PIT0)
+ {
+ TOMPITPrescaler = data;
+ TOMResetPIT();
+ }
+ else if (address == PIT1)
+ {
+ TOMPITDivider = data;
+ TOMResetPIT();
+ }
}
*/
#ifndef __EVENT_H__
#define __EVENT_H__
-#include "types.h"
+enum { EVENT_MAIN, EVENT_JERRY };
+//NTSC Timings...
#define RISC_CYCLE_IN_USEC 0.03760684198
#define M68K_CYCLE_IN_USEC (RISC_CYCLE_IN_USEC * 2)
+//PAL Timings
+#define RISC_CYCLE_PAL_IN_USEC 0.03760260812
+#define M68K_CYCLE_PAL_IN_USEC (RISC_CYCLE_PAL_IN_USEC * 2)
#define HORIZ_PERIOD_IN_USEC_NTSC 63.555555555
#define HORIZ_PERIOD_IN_USEC_PAL 64.0
#define USEC_TO_M68K_CYCLES(u) (uint32)(((u) / M68K_CYCLE_IN_USEC) + 0.5)
void InitializeEventList(void);
-void SetCallbackTime(void (* callback)(void), double time);
+void SetCallbackTime(void (* callback)(void), double time, int type = EVENT_MAIN);
void RemoveCallback(void (* callback)(void));
void AdjustCallbackTime(void (* callback)(void), double time);
-double GetTimeToNextEvent(void);
-void HandleNextEvent(void);
+double GetTimeToNextEvent(int type = EVENT_MAIN);
+void HandleNextEvent(int type = EVENT_MAIN);
#endif // __EVENT_H__
}
}
+#warning "!!! Need to check the window geometry to see if the positions are legal !!!"
+// i.e., someone could drag it to another screen, close it, then disconnect that screen
void MainWin::ReadSettings(void)
{
QSettings settings("Underground Software", "Virtual Jaguar");
WriteLog(" ROMPath = \"%s\"\n", vjs.ROMPath);
WriteLog("AlpineROMPath = \"%s\"\n", vjs.alpineROMPath);
WriteLog(" absROMPath = \"%s\"\n", vjs.absROMPath);
+WriteLog("Pipelined DSP = %s\n", (vjs.usePipelinedDSP ? "ON" : "off"));
// Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, *
vjs.p1KeyBindings[BUTTON_U] = settings.value("p1k_up", Qt::Key_S).toInt();
}
//
-// Musashi 68000 read/write/IRQ functions
+// Custom UAE 68000 read/write/IRQ functions
//
#if 0
void RenderCallback(void);
void JaguarReset(void)
{
+ // New timer base code stuffola...
+ InitializeEventList();
//Need to change this so it uses the single RAM space and load the BIOS
//into it somewhere...
//Also, have to change this here and in JaguarReadXX() currently
WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
lowerField = false; // Reset the lower field flag
- // New timer base code stuffola...
- InitializeEventList();
// SetCallbackTime(ScanlineCallback, 63.5555);
// SetCallbackTime(ScanlineCallback, 31.77775);
SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
// JaguarDasm(0x800800, 0x1000);
}
-//
-// Main Jaguar execution loop (1 frame)
-//
-void JaguarExecute(uint32 * backbuffer, bool render)
-{
- uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
- uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
-//Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
-//Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
-
-// uint16 vdb = TOMReadWord(0xF00046, JAGUAR);
-//Note: This is the *definite* end of the display, though VDE *might* be less than this...
-// uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
-//It seems that they mean it when they say that VDE is the end of object processing.
-//However, we need to be able to tell the OP (or TOM) that we've reached the end of the
-//buffer and not to write any more pixels... !!! FIX !!!
-// uint16 vde = TOMReadWord(0xF00048, JAGUAR);
-
- uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
- uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
-//Not sure the above is correct, since the number of lines and timings given in the JTRM
-//seem to indicate the refresh rate is *half* the above...
-// uint16 refreshRate = (vjs.hardwareTypeNTSC ? 30 : 25);
- // Should these be hardwired or read from VP? Yes, from VP!
- // Err, actually, they should be hardwired, and hardwired to a set # of
- // lines as well...
- uint32 M68KCyclesPerScanline = m68kClockRate / (vp * refreshRate);
- uint32 RISCCyclesPerScanline = m68kClockRate / (vp * refreshRate);
-
-/*extern int effect_start;
-if (effect_start)
- WriteLog("JagExe: VP=%u, VI=%u, CPU CPS=%u, GPU CPS=%u\n", vp, vi, M68KCyclesPerScanline, RISCCyclesPerScanline);//*/
-
-//extern int start_logging;
- for(uint16 i=0; i<vp; i++)
- {
- // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
- TOMWriteWord(0xF00004, (TOMReadWord(0xF00004, JAGUAR) + 1) & 0x7FF, JAGUAR);
- TOMWriteWord(0xF00006, i, JAGUAR); // Write the VC
-
-//Not sure if this is correct...
-//Seems to be, kinda. According to the JTRM, this should only fire on odd lines in non-interlace mode...
-//Which means that it normally wouldn't go when it's zero.
- if (i == vi && i > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
- {
- // We don't have to worry about autovectors & whatnot because the Jaguar
- // tells you through its HW registers who sent the interrupt...
- TOMSetPendingVideoInt();
- m68k_set_irq(2);
- }
-
-//if (start_logging)
-// WriteLog("About to execute M68K (%u)...\n", i);
- m68k_execute(M68KCyclesPerScanline);
-//if (start_logging)
-// WriteLog("About to execute TOM's PIT (%u)...\n", i);
- TOMExecPIT(RISCCyclesPerScanline);
-//if (start_logging)
-// WriteLog("About to execute JERRY's PIT (%u)...\n", i);
- JERRYExecPIT(RISCCyclesPerScanline);
-//if (start_logging)
-// WriteLog("About to execute JERRY's SSI (%u)...\n", i);
- JERRYI2SExec(RISCCyclesPerScanline);
- BUTCHExec(RISCCyclesPerScanline);
-//if (start_logging)
-// WriteLog("About to execute GPU (%u)...\n", i);
- if (vjs.GPUEnabled)
- GPUExec(RISCCyclesPerScanline);
-
- if (vjs.DSPEnabled)
- {
- if (vjs.usePipelinedDSP)
- DSPExecP2(RISCCyclesPerScanline); // Pipelined DSP execution (3 stage)...
- else
- DSPExec(RISCCyclesPerScanline); // Ordinary non-pipelined DSP
-// DSPExecComp(RISCCyclesPerScanline); // Comparison core
- }
-
-//if (start_logging)
-// WriteLog("About to execute OP (%u)...\n", i);
- TOMExecHalfline(i, render);
- }
-}
// Temp debugging stuff
fclose(fp);
}
+
uint8 * GetRamPtr(void)
{
return jaguarMainRAM;
}
+
//
// New Jaguar execution stack
// This executes 1 frame's worth of code.
if (vjs.GPUEnabled)
GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
+#ifndef NEW_DAC_CODE
if (vjs.DSPEnabled)
{
if (vjs.usePipelinedDSP)
else
DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent)); // Ordinary non-pipelined DSP
}
+#endif
HandleNextEvent();
}
while (!frameDone);
}
+
#define USE_CORRECT_PAL_TIMINGS
// A lot of confusion comes from here...
// The thing to keep in mind is that the VC is advanced every HALF line, regardless
#endif
}
+
// This isn't currently used, but maybe it should be...
/*
Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
#include "wavetable.h"
//Note that 44100 Hz requires samples every 22.675737 usec.
-#define NEW_TIMER_SYSTEM
//#define JERRY_DEBUG
/*static*/ uint8 jerry_ram_8[0x10000];
static uint16 jerryInterruptMask = 0;
static uint16 jerryPendingInterrupt = 0;
+
// Private function prototypes
void JERRYResetPIT1(void);
void JERRYPIT2Callback(void);
void JERRYI2SCallback(void);
-//This approach is probably wrong, since the timer is continuously counting down, though
-//it might only be a problem if the # of interrupts generated is greater than 1--the M68K's
-//timeslice should be running during that phase... (The DSP needs to be aware of this!)
-
-//This is only used by the old system, so once the new timer system is working this
-//should be safe to nuke.
-void JERRYI2SExec(uint32 cycles)
-{
-#ifndef NEW_TIMER_SYSTEM
-#warning "externed var in source--should be in header file. !!! FIX !!!"
- extern uint16 serialMode; // From DAC.CPP
- if (serialMode & 0x01) // INTERNAL flag (JERRY is master)
- {
-
- // Why is it called this? Instead of SCLK? Shouldn't this be read from DAC.CPP???
-//Yes, it should. !!! FIX !!!
- JERRYI2SInterruptDivide &= 0xFF;
-
- if (JERRYI2SInterruptTimer == -1)
- {
- // We don't have to divide the RISC clock rate by this--the reason is a bit
- // convoluted. Will put explanation here later...
-// What's needed here is to find the ratio of the frequency to the number of clock cycles
-// in one second. For example, if the sample rate is 44100, we divide the clock rate by
-// this: 26590906 / 44100 = 602 cycles.
-// Which means, every 602 cycles that go by we have to generate an interrupt.
- jerryI2SCycles = 32 * (2 * (JERRYI2SInterruptDivide + 1));
- }
-
- JERYI2SInterruptTimer -= cycles;
- if (JERRYI2SInterruptTimer <= 0)
- {
-//This is probably wrong as well (i.e., need to check enable lines)... !!! FIX !!!
- DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE);
- JERRYI2SInterruptTimer += jerryI2SCycles;
-#ifdef JERRY_DEBUG
- if (JERRYI2SInterruptTimer < 0)
- WriteLog("JERRY: Missed generating an interrupt (missed %u)!\n", (-JERRYI2SInterruptTimer / jerryI2SCycles) + 1);
-#endif
- }
- }
- else // JERRY is slave to external word clock
- {
- // This is just a temporary kludge to see if the CD bus mastering works
- // I.e., this is totally faked...!
-// The whole interrupt system is pretty much borked and is need of an overhaul.
-// What we need is a way of handling these interrupts when they happen instead of
-// scanline boundaries the way it is now.
- JERRYI2SInterruptTimer -= cycles;
- if (JERRYI2SInterruptTimer <= 0)
- {
-//This is probably wrong as well (i.e., need to check enable lines)... !!! FIX !!! [DONE]
- if (ButchIsReadyToSend())//Not sure this is right spot to check...
- {
-// return GetWordFromButchSSI(offset, who);
- SetSSIWordsXmittedFromButch();
- DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE);
- }
- JERRYI2SInterruptTimer += 602;
- }
- }
-#else
- RemoveCallback(JERRYI2SCallback);
- JERRYI2SCallback();
-#endif
-}
-
-//NOTE: This is only used by the old execution core. Safe to nuke once it's stable.
-void JERRYExecPIT(uint32 cycles)
-{
-//This is wrong too: Counters are *always* spinning! !!! FIX !!! [DONE]
-// if (jerry_timer_1_counter)
- jerry_timer_1_counter -= cycles;
-
- if (jerry_timer_1_counter <= 0)
- {
-//Also, it can generate a CPU interrupt as well... !!! FIX !!! or does it? Maybe it goes Timer->GPU->CPU?
- DSPSetIRQLine(DSPIRQ_TIMER0, ASSERT_LINE); // This does the 'IRQ enabled' checking...
-// JERRYResetPIT1();
- jerry_timer_1_counter += (JERRYPIT1Prescaler + 1) * (JERRYPIT1Divider + 1);
- }
-
-//This is wrong too: Counters are *always* spinning! !!! FIX !!! [DONE]
-// if (jerry_timer_2_counter)
- jerry_timer_2_counter -= cycles;
-
- if (jerry_timer_2_counter <= 0)
- {
-//Also, it can generate a CPU interrupt as well... !!! FIX !!! or does it? Maybe it goes Timer->GPU->CPU?
- DSPSetIRQLine(DSPIRQ_TIMER1, ASSERT_LINE); // This does the 'IRQ enabled' checking...
-// JERRYResetPIT2();
- jerry_timer_2_counter += (JERRYPIT2Prescaler + 1) * (JERRYPIT2Divider + 1);
- }
-}
void JERRYResetI2S(void)
{
JERRYI2SInterruptTimer = -1;
}
+
void JERRYResetPIT1(void)
{
-#ifndef NEW_TIMER_SYSTEM
-/* if (!JERRYPIT1Prescaler || !JERRYPIT1Divider)
- jerry_timer_1_counter = 0;
- else//*/
-//Small problem with this approach: Overflow if both are = $FFFF. !!! FIX !!!
- jerry_timer_1_counter = (JERRYPIT1Prescaler + 1) * (JERRYPIT1Divider + 1);
-
-// if (jerry_timer_1_counter)
-// WriteLog("jerry: reseting timer 1 to 0x%.8x (%i)\n",jerry_timer_1_counter,jerry_timer_1_counter);
-
-#else
RemoveCallback(JERRYPIT1Callback);
if (JERRYPIT1Prescaler | JERRYPIT1Divider)
{
double usecs = (float)(JERRYPIT1Prescaler + 1) * (float)(JERRYPIT1Divider + 1) * RISC_CYCLE_IN_USEC;
- SetCallbackTime(JERRYPIT1Callback, usecs);
+ SetCallbackTime(JERRYPIT1Callback, usecs, EVENT_JERRY);
}
-#endif
}
+
void JERRYResetPIT2(void)
{
-#ifndef NEW_TIMER_SYSTEM
-/* if (!JERRYPIT2Prescaler || !JERRYPIT2Divider)
- {
- jerry_timer_2_counter = 0;
- return;
- }
- else//*/
- jerry_timer_2_counter = (JERRYPIT2Prescaler + 1) * (JERRYPIT2Divider + 1);
-
-// if (jerry_timer_2_counter)
-// WriteLog("jerry: reseting timer 2 to 0x%.8x (%i)\n",jerry_timer_2_counter,jerry_timer_2_counter);
-
-#else
RemoveCallback(JERRYPIT2Callback);
if (JERRYPIT1Prescaler | JERRYPIT1Divider)
{
double usecs = (float)(JERRYPIT2Prescaler + 1) * (float)(JERRYPIT2Divider + 1) * RISC_CYCLE_IN_USEC;
- SetCallbackTime(JERRYPIT2Callback, usecs);
+ SetCallbackTime(JERRYPIT2Callback, usecs, EVENT_JERRY);
}
-#endif
}
+
// This is the cause of the regressions in Cybermorph and Missile Command 3D...
// Solution: Probably have to check the DSP enable bit before sending these thru.
//#define JERRY_NO_IRQS
JERRYResetPIT1();
}
+
void JERRYPIT2Callback(void)
{
#ifndef JERRY_NO_IRQS
JERRYResetPIT2();
}
+
void JERRYI2SCallback(void)
{
// Why is it called this? Instead of SCLK? Shouldn't this be read from DAC.CPP???
{
DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE); // This does the 'IRQ enabled' checking...
double usecs = (float)jerryI2SCycles * RISC_CYCLE_IN_USEC;
- SetCallbackTime(JERRYI2SCallback, usecs);
+ SetCallbackTime(JERRYI2SCallback, usecs, EVENT_JERRY);
}
else // JERRY is slave to external word clock
{
DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE);
}
- SetCallbackTime(JERRYI2SCallback, 22.675737);
+ SetCallbackTime(JERRYI2SCallback, 22.675737, EVENT_JERRY);
}
}
void JERRYInit(void)
{
JoystickInit();
- DACInit();
memcpy(&jerry_ram_8[0xD000], waveTableROM, 0x1000);
JERRYPIT1Prescaler = 0xFFFF;
JERRYPIT2Divider = 0xFFFF;
jerryInterruptMask = 0x0000;
jerryPendingInterrupt = 0x0000;
+
+ DACInit();
}
+
void JERRYReset(void)
{
JoystickReset();
EepromReset();
JERRYResetI2S();
- DACReset();
memset(jerry_ram_8, 0x00, 0xD000); // Don't clear out the Wavetable ROM...!
JERRYPIT1Prescaler = 0xFFFF;
jerry_timer_2_counter = 0;
jerryInterruptMask = 0x0000;
jerryPendingInterrupt = 0x0000;
+
+ DACReset();
}
+
void JERRYDone(void)
{
WriteLog("JERRY: M68K Interrupt control ($F10020) = %04X\n", GET16(jerry_ram_8, 0x20));
EepromDone();
}
+
bool JERRYIRQEnabled(int irq)
{
// Read the word @ $F10020
return jerryInterruptMask & irq;
}
+
void JERRYSetPendingIRQ(int irq)
{
// This is the shadow of INT (it's a split RO/WO register)
jerryPendingInterrupt |= irq;
}
+
//
// JERRY byte access (read)
//
//under the new system... !!! FIX !!!
else if ((offset >= 0xF10036) && (offset <= 0xF1003D))
{
-#ifndef NEW_TIMER_SYSTEM
-// jerry_timer_1_counter = (JERRYPIT1Prescaler + 1) * (JERRYPIT1Divider + 1);
- uint32 counter1Hi = (jerry_timer_1_counter / (JERRYPIT1Divider + 1)) - 1;
- uint32 counter1Lo = (jerry_timer_1_counter % (JERRYPIT1Divider + 1)) - 1;
- uint32 counter2Hi = (jerry_timer_2_counter / (JERRYPIT2Divider + 1)) - 1;
- uint32 counter2Lo = (jerry_timer_2_counter % (JERRYPIT2Divider + 1)) - 1;
-
- switch(offset & 0x0F)
- {
- case 6:
-// return JERRYPIT1Prescaler >> 8;
- return counter1Hi >> 8;
- case 7:
-// return JERRYPIT1Prescaler & 0xFF;
- return counter1Hi & 0xFF;
- case 8:
-// return JERRYPIT1Divider >> 8;
- return counter1Lo >> 8;
- case 9:
-// return JERRYPIT1Divider & 0xFF;
- return counter1Lo & 0xFF;
- case 10:
-// return JERRYPIT2Prescaler >> 8;
- return counter2Hi >> 8;
- case 11:
-// return JERRYPIT2Prescaler & 0xFF;
- return counter2Hi & 0xFF;
- case 12:
-// return JERRYPIT2Divider >> 8;
- return counter2Lo >> 8;
- case 13:
-// return JERRYPIT2Divider & 0xFF;
- return counter2Lo & 0xFF;
- }
-#else
WriteLog("JERRY: Unhandled timer read (BYTE) at %08X...\n", offset);
-#endif
}
// else if (offset >= 0xF10010 && offset <= 0xF10015)
// return clock_byte_read(offset);
return jerry_ram_8[offset & 0xFFFF];
}
+
//
// JERRY word access (read)
//
//in the jerry_timer_n_counter variables... !!! FIX !!! [DONE]
else if ((offset >= 0xF10036) && (offset <= 0xF1003D))
{
-#ifndef NEW_TIMER_SYSTEM
-// jerry_timer_1_counter = (JERRYPIT1Prescaler + 1) * (JERRYPIT1Divider + 1);
- uint32 counter1Hi = (jerry_timer_1_counter / (JERRYPIT1Divider + 1)) - 1;
- uint32 counter1Lo = (jerry_timer_1_counter % (JERRYPIT1Divider + 1)) - 1;
- uint32 counter2Hi = (jerry_timer_2_counter / (JERRYPIT2Divider + 1)) - 1;
- uint32 counter2Lo = (jerry_timer_2_counter % (JERRYPIT2Divider + 1)) - 1;
-
- switch(offset & 0x0F)
- {
- case 6:
-// return JERRYPIT1Prescaler;
- return counter1Hi;
- case 8:
-// return JERRYPIT1Divider;
- return counter1Lo;
- case 10:
-// return JERRYPIT2Prescaler;
- return counter2Hi;
- case 12:
-// return JERRYPIT2Divider;
- return counter2Lo;
- }
- // Unaligned word reads???
-#else
WriteLog("JERRY: Unhandled timer read (WORD) at %08X...\n", offset);
-#endif
}
// else if ((offset >= 0xF10010) && (offset <= 0xF10015))
// return clock_word_read(offset);
return ((uint16)jerry_ram_8[offset+0] << 8) | jerry_ram_8[offset+1];
}
+
//
// JERRY byte access (write)
//
JERRYI2SInterruptDivide = (JERRYI2SInterruptDivide & 0xFF00) | (uint32)data;
JERRYI2SInterruptTimer = -1;
-#ifndef NEW_TIMER_SYSTEM
- jerry_i2s_exec(0);
-#else
RemoveCallback(JERRYI2SCallback);
JERRYI2SCallback();
-#endif
// return;
}
// LTXD/RTXD/SCLK/SMODE $F1A148/4C/50/54 (really 16-bit registers...)
}
else if (offset >= 0xF10000 && offset <= 0xF10007)
{
-#ifndef NEW_TIMER_SYSTEM
- switch (offset & 0x07)
- {
- case 0:
- JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0x00FF) | (data << 8);
- JERRYResetPIT1();
- break;
- case 1:
- JERRYPIT1Prescaler = (JERRYPIT1Prescaler & 0xFF00) | data;
- JERRYResetPIT1();
- break;
- case 2:
- JERRYPIT1Divider = (JERRYPIT1Divider & 0x00FF) | (data << 8);
- JERRYResetPIT1();
- break;
- case 3:
- JERRYPIT1Divider = (JERRYPIT1Divider & 0xFF00) | data;
- JERRYResetPIT1();
- break;
- case 4:
- JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0x00FF) | (data << 8);
- JERRYResetPIT2();
- break;
- case 5:
- JERRYPIT2Prescaler = (JERRYPIT2Prescaler & 0xFF00) | data;
- JERRYResetPIT2();
- break;
- case 6:
- JERRYPIT2Divider = (JERRYPIT2Divider & 0x00FF) | (data << 8);
- JERRYResetPIT2();
- break;
- case 7:
- JERRYPIT2Divider = (JERRYPIT2Divider & 0xFF00) | data;
- JERRYResetPIT2();
- }
-#else
WriteLog("JERRY: Unhandled timer write (BYTE) at %08X...\n", offset);
-#endif
return;
}
/* else if ((offset >= 0xF10010) && (offset <= 0xF10015))
jerry_ram_8[offset & 0xFFFF] = data;
}
+
//
// JERRY word access (write)
//
//This should *only* be enabled when SMODE has its INTERNAL bit set! !!! FIX !!!
JERRYI2SInterruptDivide = (uint8)data;
JERRYI2SInterruptTimer = -1;
-#ifndef NEW_TIMER_SYSTEM
- jerry_i2s_exec(0);
-#else
RemoveCallback(JERRYI2SCallback);
JERRYI2SCallback();
-#endif
DACWriteWord(offset, data, who);
return;
}
else if (offset >= 0xF10000 && offset <= 0xF10007)
{
-//#ifndef NEW_TIMER_SYSTEM
-#if 1
switch(offset & 0x07)
{
case 0:
JERRYResetPIT2();
}
// Need to handle (unaligned) cases???
-#else
-WriteLog("JERRY: Unhandled timer write %04X (WORD) at %08X by %s...\n", data, offset, whoName[who]);
-#endif
+
return;
}
/* else if (offset >= 0xF10010 && offset < 0xF10016)
// Actually, considering that "byteswap.h" doesn't exist elsewhere, the above
// is probably our best bet here. Just need to rename them to ESAFExx().
+// Look at <endian.h> and see if that header is portable or not.
+
uint16 & memcon1 = *((uint16 *)&jagMemSpace[0xF00000]);
uint16 & memcon2 = *((uint16 *)&jagMemSpace[0xF00002]);
uint16 & hc = *((uint16 *)&jagMemSpace[0xF00004]);