obj/log.o \
obj/memory.o \
obj/mmu.o \
- obj/objectp.o \
+ obj/op.o \
obj/settings.o \
obj/state.o \
obj/tom.o \
WriteLog("DSP: DSP -> CPU interrupt\n");
#endif
// This was WRONG
-// Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility?
+// Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
+#warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
{
JERRYSetPendingIRQ(IRQ2_DSP);
DSPReleaseTimeslice();
- m68k_set_irq(7); // Set 68000 NMI...
+ m68k_set_irq(2); // Set 68000 IPL 2...
}
data &= ~CPUINT;
}
GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
if (INT1_WREG & 0x08)
- m68k_set_irq(7); // Generate 68K NMI
+ m68k_set_irq(2); // Generate 68K NMI
TOMResetPIT();
}
//WriteLog("GPU->CPU interrupt\n");
if (TOMIRQEnabled(IRQ_GPU))
{
- if ((TOMIRQEnabled(IRQ_GPU)) && (JaguarInterruptHandlerIsValid(64)))
+//This is the programmer's responsibility, to make sure the handler is valid, not ours!
+// if ((TOMIRQEnabled(IRQ_GPU))// && (JaguarInterruptHandlerIsValid(64)))
{
TOMSetPendingGPUInt();
- m68k_set_irq(7); // Set 68000 NMI
+ m68k_set_irq(2); // Set 68000 IPL 2
GPUReleaseTimeslice();
}
}
void MainWin::closeEvent(QCloseEvent * event)
{
+ JaguarDone();
WriteSettings();
event->accept(); // ignore() if can't close for some reason
}
exit(0);
}//*/
#endif
+
+#if 0
+//001A0110: move.w #$0, $F000E2.l ; Restore Blitter/GPU bus priorities
+//001A015C: rte ; Return from the interrupt
+static bool disassembleGo = false;
+ if (m68kPC == 0x1A0110)
+ {
+ static char buffer[2048];
+ m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
+ WriteLog("--> [M68K IRQ Routine start] %08X: %s", m68kPC, buffer);
+ WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
+ m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
+ m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
+ disassembleGo = true;
+ }
+ else if (m68kPC == 0x1A015C)
+ WriteLog("--> [M68K IRQ Routine end]\n");
+
+ if (disassembleGo)
+ {
+ static char buffer[2048];
+ m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
+ WriteLog("%08X: %s", m68kPC, buffer);
+ WriteLog("\tD0=$%08X, D1=$%08X, D2=$%08X\n",
+ m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
+ }
+#endif
}
#if 0
// Musashi 68000 read/write/IRQ functions
//
+#if 0
+IRQs:
+=-=-=
+
+ IPL Name Vector Control
+ ---------+---------------+---------------+---------------
+ 2 VBLANK IRQ $100 INT1 bit #0
+ 2 GPU IRQ $100 INT1 bit #1
+ 2 HBLANK IRQ $100 INT1 bit #2
+ 2 Timer IRQ $100 INT1 bit #3
+
+ Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
+ and are therefore indistinguishable.
+
+ A typical way to install a LEVEL2 handler for the 68000 would be
+ something like this, you gotta supply "last_line" and "handler".
+ Note that the interrupt is auto vectored thru $100 (not $68)
+
+
+ V_AUTO = $100
+ VI = $F004E
+ INT1 = $F00E0
+ INT2 = $F00E2
+
+ IRQS_HANDLED=$909 ;; VBLANK and TIMER
+
+ move.w #$2700,sr ;; no IRQs please
+ move.l #handler,V_AUTO ;; install our routine
+
+ move.w #last_line,VI ;; scanline where IRQ should occur
+ ;; should be 'odd' BTW
+ move.w #IRQS_HANDLE&$FF,INT1 ;; enable VBLANK + TIMER
+ move.w #$2100,sr ;; enable IRQs on the 68K
+ ...
+
+handler:
+ move.w d0,-(a7)
+ move.w INT1,d0
+ btst.b #0,d0
+ bne.b .no_blank
+
+ ...
+
+.no_blank:
+ btst.b #3,d0
+ beq.b .no_timer
+
+ ...
+
+.no_timer:
+ move.w #IRQS_HANDLED,INT1 ; clear latch, keep IRQ alive
+ move.w #0,INT2 ; let GPU run again
+ move.w (a7)+,d0
+ rte
+
+ As you can see, if you have multiple INT1 interrupts coming in,
+ you need to check the lower byte of INT1, to see which interrupt
+ happened.
+#endif
int irq_ack_handler(int level)
{
- int vector = M68K_INT_ACK_AUTOVECTOR;
+ // Tracing the IPL lines on the Jaguar schematic yields the following:
+ // IPL1 is connected to INTL on TOM (OUT to 68K)
+ // IPL0-2 are also tied to Vcc via 4.7K resistors!
+ // (DINT on TOM goes into DINT on JERRY (IN from Jerry))
+ // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
+ // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
// The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
+ // They aren't, and this causes problems with a, err, specific ROM. :-D
- if (level == 7)
+ if (level == 2)
{
- m68k_set_irq(0); // Clear the IRQ...
- vector = 64; // Set user interrupt #0
+ m68k_set_irq(0); // Clear the IRQ (NOTE: Without this, the BIOS fails)...
+ return 64; // Set user interrupt #0
}
- return vector;
+ return M68K_INT_ACK_AUTOVECTOR;
}
//#define USE_NEW_MMU
if (TOMIRQEnabled(IRQ_VBLANK))
{
- WriteLog("vblank int: enabled\n");
+ WriteLog("video int: enabled\n");
JaguarDasm(JaguarGetHandler(64), 0x200);
}
else
- WriteLog("vblank int: disabled\n");
+ WriteLog("video int: disabled\n");
WriteLog("..................\n");
for(int i=0; i<256; i++)
- WriteLog("handler %03i at $%08X\n", i, (unsigned int)JaguarGetHandler(i));
+ {
+ WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
+ uint32 address = (uint32)JaguarGetHandler(i);
+
+ if (address == 0)
+ WriteLog(".........\n");
+ else
+ WriteLog("$%08X\n", address);
+ }
}
//
WriteLog("\n");//*/
// WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
- WriteLog("Jaguar: Interrupt enable = %02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
- WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
+ WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
+ WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VBLANK))
+ && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
M68K_show_context();
//#endif
+#if 0 // This is drawn already...
+ WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
+ for(uint32 i=0x64; i<=0x7C; i+=4)
+ WriteLog(" #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
+#endif
+
CDROMDone();
GPUDone();
DSPDone();
TOMDone();
JERRYDone();
+
+ // temp, until debugger is in place
+//00802016: jsr $836F1A.l
+//0080201C: jsr $836B30.l
+//00802022: jsr $836B18.l
+//00802028: jsr $8135F0.l
+//00813C1E: jsr $813F76.l
+//00802038: jsr $836D00.l
+//00802098: jsr $8373A4.l
+//008020A2: jsr $83E24A.l
+//008020BA: jsr $83E156.l
+//008020C6: jsr $83E19C.l
+//008020E6: jsr $8445E8.l
+//008020EC: jsr $838C20.l
+//0080211A: jsr $838ED6.l
+//00802124: jsr $89CA56.l
+//0080212A: jsr $802B48.l
+#if 0
+ WriteLog("-------------------------------------------\n");
+ JaguarDasm(0x8445E8, 0x200);
+ WriteLog("-------------------------------------------\n");
+ JaguarDasm(0x838C20, 0x200);
+ WriteLog("-------------------------------------------\n");
+ JaguarDasm(0x838ED6, 0x200);
+ WriteLog("-------------------------------------------\n");
+ JaguarDasm(0x89CA56, 0x200);
+ WriteLog("-------------------------------------------\n");
+ JaguarDasm(0x802B48, 0x200);
+#endif
}
//
// 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(7);
+ m68k_set_irq(2);
}
//if (start_logging)
// We don't have to worry about autovectors & whatnot because the Jaguar
// tells you through its HW registers who sent the interrupt...
tom_set_pending_video_int();
- m68k_set_irq(7);
+ m68k_set_irq(2);
}
TOMExecScanline(vc, true);
// 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(7);
+ m68k_set_irq(2);
}
TOMExecScanline(vc, true);
#include "jaguar.h"
#include "joystick.h"
#include "log.h"
+#include "m68k.h"
//#include "memory.h"
#include "wavetable.h"
uint32 jerryI2SCycles;
uint32 jerryIntPending;
+static uint16 jerryInterruptMask = 0;
+static uint16 jerryPendingInterrupt = 0;
// Private function prototypes
void JERRYResetPIT1(void);
void JERRYPIT1Callback(void)
{
+//WriteLog("JERRY: In PIT1 callback, IRQM=$%04X\n", jerryInterruptMask);
+ if (jerryInterruptMask & IRQ2_TIMER1) // CPU Timer 1 IRQ
+ {
+// Not sure, but I think we don't generate another IRQ if one's already going...
+// But this seems to work... :-/
+ jerryPendingInterrupt |= IRQ2_TIMER1;
+ m68k_set_irq(2); // Generate 68K IPL 2
+ }
+
DSPSetIRQLine(DSPIRQ_TIMER0, ASSERT_LINE); // This does the 'IRQ enabled' checking...
JERRYResetPIT1();
}
void JERRYPIT2Callback(void)
{
+//WriteLog("JERRY: In PIT2 callback, IRQM=$%04X\n", jerryInterruptMask);
+ if (jerryInterruptMask & IRQ2_TIMER2) // CPU Timer 2 IRQ
+ {
+ jerryPendingInterrupt |= IRQ2_TIMER2;
+ m68k_set_irq(2); // Generate 68K IPL 2
+ }
+
DSPSetIRQLine(DSPIRQ_TIMER1, ASSERT_LINE); // This does the 'IRQ enabled' checking...
JERRYResetPIT2();
}
JERRYPIT2Prescaler = 0xFFFF;
JERRYPIT1Divider = 0xFFFF;
JERRYPIT2Divider = 0xFFFF;
+ jerryInterruptMask = 0x0000;
+ jerryPendingInterrupt = 0x0000;
}
void JERRYReset(void)
JERRYPIT2Divider = 0xFFFF;
jerry_timer_1_counter = 0;
jerry_timer_2_counter = 0;
+ jerryInterruptMask = 0x0000;
+ jerryPendingInterrupt = 0x0000;
}
void JERRYDone(void)
bool JERRYIRQEnabled(int irq)
{
// Read the word @ $F10020
- return jerry_ram_8[0x21] & (1 << irq);
+// return jerry_ram_8[0x21] & (1 << irq);
+ return jerryInterruptMask & irq;
}
void JERRYSetPendingIRQ(int irq)
{
// This is the shadow of INT (it's a split RO/WO register)
- jerryIntPending |= (1 << irq);
+// jerryIntPending |= (1 << irq);
+ jerryPendingInterrupt |= irq;
}
//
// else if ((offset >= 0xF10010) && (offset <= 0xF10015))
// return clock_word_read(offset);
else if (offset == 0xF10020)
- return jerryIntPending;
+// return jerryIntPending;
+ return jerryPendingInterrupt;
// else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
// return anajoy_word_read(offset);
else if (offset == 0xF14000)
return;
}//*/
// JERRY -> 68K interrupt enables/latches (need to be handled!)
- else if (offset >= 0xF10020 && offset <= 0xF10023)
+ else if (offset >= 0xF10020 && offset <= 0xF10021)//WAS:23)
{
-WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", data, offset);
+ if (offset == 0xF10020)
+ {
+ // Clear pending interrupts...
+ jerryPendingInterrupt &= ~data;
+ }
+ else if (offset == 0xF10021)
+ jerryInterruptMask = data;
+//WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%02X to $%08X!\n", data, offset);
+//WriteLog("JERRY: (Previous is partially handled... IRQMask=$%04X)\n", jerryInterruptMask);
}
/* else if ((offset >= 0xF17C00) && (offset <= 0xF17C01))
{
{
#ifdef JERRY_DEBUG
WriteLog( "JERRY: Writing word %04X at %06X\n", data, offset);
+#endif
+#if 1
+if (offset == 0xF10000)
+ WriteLog("JERRY: JPIT1 word written by %s: %u\n", whoName[who], data);
+else if (offset == 0xF10002)
+ WriteLog("JERRY: JPIT2 word written by %s: %u\n", whoName[who], data);
+else if (offset == 0xF10004)
+ WriteLog("JERRY: JPIT3 word written by %s: %u\n", whoName[who], data);
+else if (offset == 0xF10006)
+ WriteLog("JERRY: JPIT4 word written by %s: %u\n", whoName[who], data);
+else if (offset == 0xF10010)
+ WriteLog("JERRY: CLK1 word written by %s: %u\n", whoName[who], data);
+else if (offset == 0xF10012)
+ WriteLog("JERRY: CLK2 word written by %s: %u\n", whoName[who], data);
+else if (offset == 0xF10014)
+ WriteLog("JERRY: CLK3 word written by %s: %u\n", whoName[who], data);
+//else if (offset == 0xF10020)
+// WriteLog("JERRY: JINTCTRL word written by %s: $%04X\n", whoName[who], data);
#endif
if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
// JERRY -> 68K interrupt enables/latches (need to be handled!)
else if (offset >= 0xF10020 && offset <= 0xF10022)
{
-WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%04X to $%08X!\n", data, offset);
+ jerryInterruptMask = data & 0xFF;
+ jerryPendingInterrupt &= ~(data >> 8);
+//WriteLog("JERRY: (68K int en/lat - Unhandled!) Tried to write $%04X to $%08X!\n", data, offset);
+//WriteLog("JERRY: (Previous is partially handled... IRQMask=$%04X)\n", jerryInterruptMask);
+ return;
}
/* else if (offset >= 0xF17C00 && offset < 0xF17C02)
{
// 68000 Interrupt bit positions (enabled at $F10020)
-enum { IRQ2_EXTERNAL = 0, IRQ2_DSP, IRQ2_TIMER1, IRQ2_TIMER2, IRQ2_ASI, IRQ2_SSI };
+//enum { IRQ2_EXTERNAL = 0, IRQ2_DSP, IRQ2_TIMER1, IRQ2_TIMER2, IRQ2_ASI, IRQ2_SSI };
+enum { IRQ2_EXTERNAL=0x01, IRQ2_DSP=0x02, IRQ2_TIMER1=0x04, IRQ2_TIMER2=0x08, IRQ2_ASI=0x10, IRQ2_SSI=0x20 };
bool JERRYIRQEnabled(int irq);
void JERRYSetPendingIRQ(int irq);
// JLH 01/16/2010 Created this log ;-)
//
-#include "objectp.h"
+#include "op.h"
#include <stdlib.h>
#include <string.h>
if (p0 & 0x08)
{
- TOMSetPendingObjectInt();
- if (TOMIRQEnabled(IRQ_OPFLAG))// && jaguar_interrupt_handler_is_valid(64))
- m68k_set_irq(7); // Cause an NMI to occur...
+ // We need to check whether these interrupts are enabled or not, THEN
+ // set an IRQ + pending flag if necessary...
+ if (TOMIRQEnabled(IRQ_OPFLAG))
+ {
+ TOMSetPendingObjectInt();
+ m68k_set_irq(2); // Cause a 68K IPL 2 to occur...
+ }
}
return;
#include "log.h"
#include "m68k.h"
//#include "memory.h"
-#include "objectp.h"
+#include "op.h"
#include "settings.h"
#define NEW_TIMER_SYSTEM
#define VDB 0x46
#define VDE 0x48
#define VI 0x4E
+#define PIT0 0x50
+#define PIT1 0x52
#define BG 0x58
#define INT1 0xE0
if (offset == 0xF000E0)
{
+ // For reading, should only return the lower 5 bits...
uint16 data = (tom_jerry_int_pending << 4) | (tom_timer_int_pending << 3)
| (tom_object_int_pending << 2) | (tom_gpu_int_pending << 1)
| (tom_video_int_pending << 0);
tom_timer_int_pending = 0;
if (data & 0x1000)
tom_jerry_int_pending = 0;
+
+// return;
}
else if ((offset >= 0xF02200) && (offset <= 0xF0229F))
{
// Writing to one CLUT writes to the other
offset &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
// Watch out for unaligned writes here! (Not fixed yet)
+#warning "!!! Watch out for unaligned writes here !!! FIX !!!"
SET16(tomRam8, offset, data);
SET16(tomRam8, offset + 0x200, data);
}
WriteLog("TOM: Horizontal Blank End written by %s: %u\n", whoName[who], data);
if (offset == VMODE)
WriteLog("TOM: Video Mode written by %s: %04X. PWIDTH = %u, MODE = %s, flags:%s%s (VC = %u)\n", whoName[who], data, ((data >> 9) & 0x07) + 1, videoMode_to_str[(data & MODE) >> 1], (data & BGEN ? " BGEN" : ""), (data & VARMOD ? " VARMOD" : ""), GET16(tomRam8, VC));
+if (offset == PIT0)
+ WriteLog("TOM: PIT0 written by %s: %u\n", whoName[who], data);
+if (offset == PIT1)
+ WriteLog("TOM: PIT1 written by %s: %u\n", whoName[who], data);
+//if (offset == INT1)
+// WriteLog("TOM: CPU Interrupt Control written by %s: $%04X (%s%s%s%s%s)\n", whoName[who], data, (data & 0x01 ? "Video" : ""), (data & 0x02 ? " GPU" : ""), (data & 0x04 ? " OP" : ""), (data & 0x08 ? " TOMPIT" : ""), (data & 0x10 ? " Jerry" : ""));
// detect screen resolution changes
//This may go away in the future, if we do the virtualized screen thing...
GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // GPUSetIRQLine does the 'IRQ enabled' checking
if (TOMIRQEnabled(IRQ_TIMER))
- m68k_set_irq(7); // Cause a 68000 NMI...
+ m68k_set_irq(2); // Cause a 68000 IPL 2...
TOMResetPIT();
}
// if (INT1_WREG & 0x08)
if (TOMIRQEnabled(IRQ_TIMER))
- m68k_set_irq(7); // Generate 68K NMI
+ m68k_set_irq(2); // Generate a 68K IPL 2...
TOMResetPIT();
}
//uint16 tom_get_scanline(void);
//uint32 tom_getHBlankWidthInPixels(void);
-int TOMIRQEnabled(int irq);
+int TOMIRQEnabled(int irq);
uint16 TOMIRQControlReg(void);
void TOMSetIRQLatch(int irq, int enabled);
void TOMExecPIT(uint32 cycles);