/* Cygne * * Copyright notice for this file: * Copyright (C) 2002 Dox dox@space.pl * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "system.h" #include #include #include namespace MDFN_IEN_WSWAN { void Memory::Write20(uint32 A, uint8 V) { uint32 offset, bank; offset = A & 0xffff; bank = (A>>16) & 0xF; if(!bank) /*RAM*/ { sys->sound.CheckRAMWrite(offset); wsRAM[offset] = V; sys->gfx.InvalidByAddr(offset); if(offset>=0xfe00) /*WSC palettes*/ sys->gfx.PaletteRAMWrite(offset, V); } else if(bank == 1) /* SRAM */ { if(sram_size) { wsSRAM[(offset | (BankSelector[1] << 16)) & (sram_size - 1)] = V; } } } uint8 Memory::Read20(uint32 A) { uint32 offset, bank; offset = A & 0xFFFF; bank = (A >> 16) & 0xF; switch(bank) { case 0: return wsRAM[offset]; case 1: if(sram_size) { return wsSRAM[(offset | (BankSelector[1] << 16)) & (sram_size - 1)]; } else return(0); case 2: case 3: return wsCartROM[offset+((BankSelector[bank]&((rom_size>>16)-1))<<16)]; default: { uint8 bank_num = ((BankSelector[0] & 0xF) << 4) | (bank & 0xf); bank_num &= (rom_size >> 16) - 1; return(wsCartROM[(bank_num << 16) | offset]); } } } void Memory::CheckDMA() { if(DMAControl & 0x80) { while(DMALength) { Write20(DMADest, Read20(DMASource)); DMASource++; // = ((DMASource + 1) & 0xFFFF) | (DMASource & 0xFF0000); //if(!(DMASource & 0xFFFF)) puts("Warning: DMA source bank crossed."); DMADest = ((DMADest + 1) & 0xFFFF) | (DMADest & 0xFF0000); DMALength--; } } DMAControl &= ~0x80; } void Memory::CheckSoundDMA() { if(SoundDMAControl & 0x80) { if(SoundDMALength) { uint8 zebyte = Read20(SoundDMASource); if(SoundDMAControl & 0x08) zebyte ^= 0x80; if(SoundDMAControl & 0x10) sys->sound.Write(0x95, zebyte); // Pick a port, any port?! else sys->sound.Write(0x89, zebyte); SoundDMASource++; // = ((SoundDMASource + 1) & 0xFFFF) | (SoundDMASource & 0xFF0000); //if(!(SoundDMASource & 0xFFFF)) puts("Warning: Sound DMA source bank crossed."); SoundDMALength--; } if(!SoundDMALength) SoundDMAControl &= ~0x80; } } uint8 Memory::readport(uint32 number) { number &= 0xFF; if(number >= 0x80 && number <= 0x9F) return(sys->sound.Read(number)); else if(number <= 0x3F || (number >= 0xA0 && number <= 0xAF) || (number == 0x60)) return(sys->gfx.Read(number)); else if((number >= 0xBA && number <= 0xBE) || (number >= 0xC4 && number <= 0xC8)) return(sys->eeprom.Read(number)); else if(number >= 0xCA && number <= 0xCB) return(sys->rtc.Read(number)); else switch(number) { //default: printf("Read: %04x\n", number); break; case 0x40: return(DMASource >> 0); case 0x41: return(DMASource >> 8); case 0x42: return(DMASource >> 16); case 0x43: return(DMADest >> 16); case 0x44: return(DMADest >> 0); case 0x45: return(DMADest >> 8); case 0x46: return(DMALength >> 0); case 0x47: return(DMALength >> 8); case 0x48: return(DMAControl); case 0xB0: case 0xB2: case 0xB6: return(sys->interrupt.Read(number)); case 0xC0: return(BankSelector[0] | 0x20); case 0xC1: return(BankSelector[1]); case 0xC2: return(BankSelector[2]); case 0xC3: return(BankSelector[3]); case 0x4a: return(SoundDMASource >> 0); case 0x4b: return(SoundDMASource >> 8); case 0x4c: return(SoundDMASource >> 16); case 0x4e: return(SoundDMALength >> 0); case 0x4f: return(SoundDMALength >> 8); case 0x52: return(SoundDMAControl); case 0xB1: return(CommData); case 0xb3: { uint8 ret = CommControl & 0xf0; if(CommControl & 0x80) ret |= 0x4; // Send complete return(ret); } case 0xb5: { Lagged = false; if (ButtonHook) ButtonHook(); uint8 ret = (ButtonWhich << 4) | ButtonReadLatch; return(ret); } } if(number >= 0xC8) return language ? 0xD1 : 0xD0; //return(0xD0 | language); // is this right? return(0); } void Memory::writeport(uint32 IOPort, uint8 V) { IOPort &= 0xFF; if(IOPort >= 0x80 && IOPort <= 0x9F) { sys->sound.Write(IOPort, V); } else if((IOPort >= 0x00 && IOPort <= 0x3F) || (IOPort >= 0xA0 && IOPort <= 0xAF) || (IOPort == 0x60)) { sys->gfx.Write(IOPort, V); } else if((IOPort >= 0xBA && IOPort <= 0xBE) || (IOPort >= 0xC4 && IOPort <= 0xC8)) sys->eeprom.Write(IOPort, V); else if(IOPort >= 0xCA && IOPort <= 0xCB) sys->rtc.Write(IOPort, V); else switch(IOPort) { //default: printf("%04x %02x\n", IOPort, V); break; case 0x40: DMASource &= 0xFFFF00; DMASource |= (V << 0); break; case 0x41: DMASource &= 0xFF00FF; DMASource |= (V << 8); break; case 0x42: DMASource &= 0x00FFFF; DMASource |= ((V & 0x0F) << 16); break; case 0x43: DMADest &= 0x00FFFF; DMADest |= ((V & 0x0F) << 16); break; case 0x44: DMADest &= 0xFFFF00; DMADest |= (V << 0); break; case 0x45: DMADest &= 0xFF00FF; DMADest |= (V << 8); break; case 0x46: DMALength &= 0xFF00; DMALength |= (V << 0); break; case 0x47: DMALength &= 0x00FF; DMALength |= (V << 8); break; case 0x48: DMAControl = V; //if(V&0x80) // printf("DMA%02x: %08x %08x %08x\n", V, DMASource, DMADest, DMALength); CheckDMA(); break; case 0x4a: SoundDMASource &= 0xFFFF00; SoundDMASource |= (V << 0); break; case 0x4b: SoundDMASource &= 0xFF00FF; SoundDMASource |= (V << 8); break; case 0x4c: SoundDMASource &= 0x00FFFF; SoundDMASource |= (V << 16); break; //case 0x4d: break; // Unused? case 0x4e: SoundDMALength &= 0xFF00; SoundDMALength |= (V << 0); break; case 0x4f: SoundDMALength &= 0x00FF; SoundDMALength |= (V << 8); break; //case 0x50: break; // Unused? //case 0x51: break; // Unused? case 0x52: SoundDMAControl = V; //if(V & 0x80) printf("Sound DMA: %02x, %08x %08x\n", V, SoundDMASource, SoundDMALength); break; case 0xB0: case 0xB2: case 0xB6: sys->interrupt.Write(IOPort, V); break; case 0xB1: CommData = V; break; case 0xB3: CommControl = V & 0xF0; break; case 0xb5: ButtonWhich = V >> 4; // Lagged = false; // why was this being set here? ButtonReadLatch = 0; if(ButtonWhich & 0x4) /*buttons*/ ButtonReadLatch |= ((WSButtonStatus >> 8) << 1) & 0xF; if(ButtonWhich & 0x2) /* H/X cursors */ ButtonReadLatch |= WSButtonStatus & 0xF; if(ButtonWhich & 0x1) /* V/Y cursors */ ButtonReadLatch |= (WSButtonStatus >> 4) & 0xF; break; case 0xC0: BankSelector[0] = V & 0xF; break; case 0xC1: BankSelector[1] = V; break; case 0xC2: BankSelector[2] = V; break; case 0xC3: BankSelector[3] = V; break; } } Memory::~Memory() { if (wsCartROM) { std::free(wsCartROM); wsCartROM = nullptr; } if (wsSRAM) { std::free(wsSRAM); wsSRAM = nullptr; } } void Memory::Init(const SyncSettings &settings) { char tmpname[17]; std::memcpy(tmpname, settings.name, 16); tmpname[16] = 0; language = settings.language; // WSwan_EEPROMInit() will also clear wsEEPROM sys->eeprom.Init(tmpname, settings.byear, settings.bmonth, settings.bday, settings.sex, settings.blood); if(sram_size) { wsSRAM = (uint8*)malloc(sram_size); memset(wsSRAM, 0, sram_size); } } void Memory::Reset() { memset(wsRAM, 0, 65536); wsRAM[0x75AC] = 0x41; wsRAM[0x75AD] = 0x5F; wsRAM[0x75AE] = 0x43; wsRAM[0x75AF] = 0x31; wsRAM[0x75B0] = 0x6E; wsRAM[0x75B1] = 0x5F; wsRAM[0x75B2] = 0x63; wsRAM[0x75B3] = 0x31; std::memset(BankSelector, 0, sizeof(BankSelector)); ButtonWhich = 0; ButtonReadLatch = 0; DMASource = 0; DMADest = 0; DMALength = 0; DMAControl = 0; SoundDMASource = 0; SoundDMALength = 0; SoundDMAControl = 0; CommControl = 0; CommData = 0; } SYNCFUNC(Memory) { NSS(wsRAM); //NSS(rom_size); //PSS(wsCartROM, rom_size); NSS(sram_size); PSS(wsSRAM, sram_size); NSS(WSButtonStatus); NSS(Lagged); NSS(ButtonWhich); NSS(ButtonReadLatch); NSS(DMASource); NSS(DMADest); NSS(DMALength); NSS(DMAControl); NSS(SoundDMASource); NSS(SoundDMALength); NSS(SoundDMAControl); NSS(BankSelector); NSS(CommControl); NSS(CommData); NSS(language); } }