//--------------------------------------------------------------------------- // 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(); } } //=============================================================================