630 lines
13 KiB
C++
630 lines
13 KiB
C++
//---------------------------------------------------------------------------
|
|
// NEOPOP : Emulator as in Dreamland
|
|
//
|
|
// Copyright (c) 2001-2002 by neopop_uk
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
// 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. See also the license.txt file for
|
|
// additional informations.
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "neopop.h"
|
|
#include "bios.h"
|
|
#include "mem.h"
|
|
#include "flash.h"
|
|
#include "dma.h"
|
|
#include "interrupt.h"
|
|
|
|
namespace MDFN_IEN_NGP
|
|
{
|
|
|
|
static uint8 CacheIntPrio[0xB]; // Iinterrupt prio registers at 0x0070-0x007a don't have priority readable.
|
|
// This should probably be stored in BIOS work RAM somewhere instead of a separate array, but I don't know where!
|
|
|
|
void BIOSHLE_Reset(void)
|
|
{
|
|
memset(CacheIntPrio, 0, sizeof(CacheIntPrio));
|
|
CacheIntPrio[0] = 0x02;
|
|
CacheIntPrio[1] = 0x32;
|
|
|
|
for (int x = 0; x < 0xB; x++)
|
|
storeB(0x70 + x, CacheIntPrio[x]);
|
|
}
|
|
|
|
/* This is the custom HLE instruction. I considered it was the fastest and
|
|
most streamlined way of intercepting a bios call. The operation performed
|
|
is dependant on the current program counter. */
|
|
|
|
void iBIOSHLE(void)
|
|
{
|
|
//Only works within the bios
|
|
if ((pc & 0xFF0000) != 0xFF0000)
|
|
return;
|
|
|
|
pc--; //Compensate for processing this instruction.
|
|
|
|
cycles = 8; //TODO: Correct cycle counts (or approx?)
|
|
|
|
//if(pc != 0xff1222)
|
|
//printf("SPOON: %08x\n", pc);
|
|
|
|
switch (pc & 0xffffff)
|
|
{
|
|
|
|
//default: printf("SPOON: %08x\n", pc); break;
|
|
//VECT_SHUTDOWN
|
|
case 0xFF27A2:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
if (a != 0xBAADC0DE)
|
|
system_debug_message("VECT_SHUTDOWN: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
|
|
system_debug_stop();
|
|
#endif
|
|
{
|
|
//Cheap bit of code to stop the message appearing repeatedly.
|
|
uint32 a = pop32();
|
|
if (a != 0xBAADC0DE)
|
|
MDFN_printf("IDS_POWER");
|
|
push32(0xBAADC0DE); //Sure is!
|
|
}
|
|
|
|
return; //Don't pop a return address, stay here
|
|
|
|
//VECT_CLOCKGEARSET
|
|
case 0xFF1030:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_CLOCKGEARSET: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
//MDFN_printf("%d\n", rCodeB(0x35));
|
|
//TODO
|
|
// if (rCodeB(0x35) > 0)
|
|
// system_message("Unsupported clock gear %d set\nPlease inform the author", rCodeB(0x35));
|
|
|
|
break;
|
|
|
|
//VECT_RTCGET
|
|
case 0xFF1440:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_RTCGET: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
|
|
if (rCodeL(0x3C) < 0xC000)
|
|
{
|
|
//Copy data from hardware area
|
|
storeB(rCodeL(0x3C) + 0, loadB(0x91));
|
|
storeB(rCodeL(0x3C) + 1, loadB(0x92));
|
|
storeB(rCodeL(0x3C) + 2, loadB(0x93));
|
|
storeB(rCodeL(0x3C) + 3, loadB(0x94));
|
|
storeB(rCodeL(0x3C) + 4, loadB(0x95));
|
|
storeB(rCodeL(0x3C) + 5, loadB(0x96));
|
|
storeB(rCodeL(0x3C) + 6, loadB(0x97));
|
|
}
|
|
|
|
break;
|
|
|
|
//?
|
|
//case 0xFF12B4:
|
|
// break;
|
|
|
|
//VECT_INTLVSET
|
|
case 0xFF1222:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_INTLVSET: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
|
|
{
|
|
|
|
uint8 level = rCodeB(0x35); //RB3
|
|
uint8 interrupt = rCodeB(0x34); //RC3
|
|
|
|
// 0 - Interrupt from RTC alarm
|
|
// 1 - Interrupt from the Z80 CPU
|
|
// 2 - Interrupt from the 8 bit timer 0
|
|
// 3 - Interrupt from the 8 bit timer 1
|
|
// 4 - Interrupt from the 8 bit timer 2
|
|
// 5 - Interrupt from the 8 bit timer 3
|
|
// 6 - End of transfer interrupt from DMA channel 0
|
|
// 7 - End of transfer interrupt from DMA channel 1
|
|
// 8 - End of transfer interrupt from DMA channel 2
|
|
// 9 - End of transfer interrupt from DMA channel 3
|
|
|
|
switch (interrupt)
|
|
{
|
|
case 0x00:
|
|
CacheIntPrio[0x0] = (CacheIntPrio[0x0] & 0xf0) | (level & 0x07);
|
|
storeB(0x70, CacheIntPrio[0x0]);
|
|
break;
|
|
|
|
case 0x01:
|
|
CacheIntPrio[0x1] = (CacheIntPrio[0x1] & 0x0f) | ((level & 0x07) << 4);
|
|
storeB(0x71, CacheIntPrio[0x1]);
|
|
break;
|
|
|
|
case 0x02:
|
|
CacheIntPrio[0x3] = (CacheIntPrio[0x3] & 0xf0) | (level & 0x07);
|
|
storeB(0x73, CacheIntPrio[0x3]);
|
|
break;
|
|
|
|
case 0x03:
|
|
CacheIntPrio[0x3] = (CacheIntPrio[0x3] & 0x0f) | ((level & 0x07) << 4);
|
|
storeB(0x73, CacheIntPrio[0x3]);
|
|
break;
|
|
|
|
case 0x04:
|
|
CacheIntPrio[0x4] = (CacheIntPrio[0x4] & 0xf0) | (level & 0x07);
|
|
storeB(0x74, CacheIntPrio[0x4]);
|
|
break;
|
|
|
|
case 0x05:
|
|
CacheIntPrio[0x4] = (CacheIntPrio[0x4] & 0x0f) | ((level & 0x07) << 4);
|
|
storeB(0x74, CacheIntPrio[0x4]);
|
|
break;
|
|
|
|
case 0x06:
|
|
CacheIntPrio[0x9] = (CacheIntPrio[0x9] & 0xf0) | (level & 0x07);
|
|
storeB(0x79, CacheIntPrio[0x9]);
|
|
break;
|
|
|
|
case 0x07:
|
|
CacheIntPrio[0x9] = (CacheIntPrio[0x9] & 0x0f) | ((level & 0x07) << 4);
|
|
storeB(0x79, CacheIntPrio[0x9]);
|
|
break;
|
|
|
|
case 0x08:
|
|
CacheIntPrio[0xa] = (CacheIntPrio[0xa] & 0xf0) | (level & 0x07);
|
|
storeB(0x7a, CacheIntPrio[0xa]);
|
|
break;
|
|
|
|
case 0x09:
|
|
CacheIntPrio[0xa] = (CacheIntPrio[0xa] & 0x0f) | ((level & 0x07) << 4);
|
|
storeB(0x7a, CacheIntPrio[0xa]);
|
|
break;
|
|
default:
|
|
puts("DOH");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
//VECT_SYSFONTSET
|
|
case 0xFF8D8A:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_SYSFONTSET: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
{
|
|
uint8 a, b, c, j;
|
|
uint16 i, dst = 0xA000;
|
|
|
|
b = rCodeB(0x30) >> 4;
|
|
a = rCodeB(0x30) & 3;
|
|
|
|
for (i = 0; i < 0x800; i++)
|
|
{
|
|
c = ngpc_bios[0x8DCF + i];
|
|
|
|
for (j = 0; j < 8; j++, c <<= 1)
|
|
{
|
|
uint16 data16;
|
|
|
|
data16 = loadW(dst);
|
|
data16 <<= 2;
|
|
storeW(dst, data16);
|
|
|
|
if (c & 0x80)
|
|
storeB(dst, loadB(dst) | a);
|
|
else
|
|
storeB(dst, loadB(dst) | b);
|
|
}
|
|
|
|
dst += 2;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//VECT_FLASHWRITE
|
|
case 0xFF6FD8:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_FLASHWRITE: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
{
|
|
uint32 i, bank = 0x200000;
|
|
|
|
//Select HI rom?
|
|
if (rCodeB(0x30) == 1)
|
|
bank = 0x800000;
|
|
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
system_debug_message("VECT_FLASHWRITE: Copy %06X -> %06X, %d bytes",
|
|
rCodeL(0x3C), rCodeL(0x38) + bank, rCodeW(0x34) * 256);
|
|
#endif
|
|
|
|
memory_flash_error = FALSE;
|
|
memory_unlock_flash_write = TRUE;
|
|
//Copy as 32 bit values for speed
|
|
for (i = 0; i < rCodeW(0x34) * 64ul; i++)
|
|
storeL(rCodeL(0x38) + bank + (i * 4), loadL(rCodeL(0x3C) + (i * 4)));
|
|
memory_unlock_flash_write = FALSE;
|
|
|
|
if (memory_flash_error)
|
|
{
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
system_debug_message("VECT_FLASHWRITE: Error");
|
|
#endif
|
|
rCodeB(0x30) = 0xFF; //RA3 = SYS_FAILURE
|
|
}
|
|
else
|
|
{
|
|
uint32 address = rCodeL(0x38);
|
|
if (rCodeB(0x30) == 1)
|
|
address += 0x800000;
|
|
else
|
|
address += 0x200000;
|
|
|
|
//Save this data to an external file
|
|
flash_write(address, rCodeW(0x34) * 256);
|
|
|
|
rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//VECT_FLASHALLERS
|
|
case 0xFF7042:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_FLASHALLERS: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
//TODO
|
|
rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS
|
|
break;
|
|
|
|
//VECT_FLASHERS
|
|
case 0xFF7082:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_FLASHERS: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
system_debug_message("VECT_FLASHERS: bank %d, block %d (?)", rCodeB(0x30), rCodeB(0x35));
|
|
#endif
|
|
//TODO
|
|
rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS
|
|
break;
|
|
|
|
//VECT_ALARMSET
|
|
case 0xFF149B:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_ALARMSET: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
//TODO
|
|
rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS
|
|
break;
|
|
|
|
//?
|
|
//case 0xFF1033: break;
|
|
|
|
//VECT_ALARMDOWNSET
|
|
case 0xFF1487:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_ALARMDOWNSET: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
//TODO
|
|
rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS
|
|
break;
|
|
|
|
//?
|
|
//case 0xFF731F: break;
|
|
|
|
//VECT_FLASHPROTECT
|
|
case 0xFF70CA:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_FLASHPROTECT: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
//TODO
|
|
rCodeB(0x30) = 0; //RA3 = SYS_SUCCESS
|
|
break;
|
|
|
|
//VECT_GEMODESET
|
|
case 0xFF17C4:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_bios)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_GEMODESET: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
//TODO
|
|
break;
|
|
|
|
//?
|
|
//case 0xFF1032: break;
|
|
|
|
//VECT_COMINIT
|
|
case 0xFF2BBD:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMINIT: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
// Nothing to do.
|
|
rCodeB(0x30) = 0; //RA3 = COM_BUF_OK
|
|
break;
|
|
|
|
//VECT_COMSENDSTART
|
|
case 0xFF2C0C:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMSENDSTART: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
// Nothing to do.
|
|
break;
|
|
|
|
//VECT_COMRECIVESTART
|
|
case 0xFF2C44:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMRECIVESTART: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
// Nothing to do.
|
|
break;
|
|
|
|
//VECT_COMCREATEDATA
|
|
case 0xFF2C86:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMCREATEDATA: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
{
|
|
//Write the byte
|
|
uint8 data = rCodeB(0x35);
|
|
system_comms_write(data);
|
|
}
|
|
|
|
//Restore $PC after BIOS-HLE instruction
|
|
pc = pop32();
|
|
|
|
TestIntHDMA(11, 0x18);
|
|
|
|
//Always COM_BUF_OK because the write call always succeeds.
|
|
rCodeB(0x30) = 0x0; //RA3 = COM_BUF_OK
|
|
return;
|
|
|
|
//VECT_COMGETDATA
|
|
case 0xFF2CB4:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMGETDATA: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
{
|
|
uint8 data;
|
|
|
|
if (system_comms_read(&data))
|
|
{
|
|
rCodeB(0x30) = 0; //COM_BUF_OK
|
|
rCodeB(0x35) = data;
|
|
|
|
pc = pop32();
|
|
|
|
//Comms. Read interrupt
|
|
storeB(0x50, data);
|
|
TestIntHDMA(12, 0x19);
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
rCodeB(0x30) = 1; //COM_BUF_EMPTY
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//VECT_COMONRTS
|
|
case 0xFF2D27:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMONRTS: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
storeB(0xB2, 0);
|
|
break;
|
|
|
|
//VECT_COMOFFRTS
|
|
case 0xFF2D33:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMOFFRTS: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
storeB(0xB2, 1);
|
|
break;
|
|
|
|
//VECT_COMSENDSTATUS
|
|
case 0xFF2D3A:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMSENDSTATUS: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
// Nothing to do.
|
|
rCodeW(0x30) = 0; //Send Buffer Count, never any pending data!
|
|
break;
|
|
|
|
//VECT_COMRECIVESTATUS
|
|
case 0xFF2D4E:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMRECIVESTATUS: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
|
|
// Receive Buffer Count
|
|
rCodeW(0x30) = system_comms_read(NULL);
|
|
|
|
break;
|
|
|
|
//VECT_COMCREATEBUFDATA
|
|
case 0xFF2D6C:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMCREATEBUFDATA: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
pc = pop32();
|
|
|
|
while (rCodeB(0x35) > 0)
|
|
{
|
|
uint8 data;
|
|
data = loadB(rCodeL(0x3C));
|
|
|
|
//Write data from (XHL3++)
|
|
system_comms_write(data);
|
|
rCodeL(0x3C)++; //Next data
|
|
|
|
rCodeB(0x35)--; //RB3 = Count Left
|
|
}
|
|
|
|
TestIntHDMA(11, 0x18);
|
|
return;
|
|
|
|
//VECT_COMGETBUFDATA
|
|
case 0xFF2D85:
|
|
#ifdef NEOPOP_DEBUG
|
|
if (filter_comms)
|
|
{
|
|
uint32 a = pop32();
|
|
system_debug_message("VECT_COMGETBUFDATA: called before %06X", a);
|
|
push32(a);
|
|
}
|
|
#endif
|
|
{
|
|
pc = pop32();
|
|
|
|
while (rCodeB(0x35) > 0)
|
|
{
|
|
uint8 data;
|
|
|
|
if (system_comms_read(&data))
|
|
{
|
|
//Read data into (XHL3++)
|
|
storeB(rCodeL(0x3C), data);
|
|
rCodeL(0x3C)++; //Next data
|
|
rCodeB(0x35)--; //RB3 = Count Left
|
|
|
|
//Comms. Read interrupt
|
|
storeB(0x50, data);
|
|
TestIntHDMA(12, 0x19);
|
|
return;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//RET
|
|
pc = pop32();
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|