From: <m97...@us...> - 2011-09-13 19:08:47
|
Revision: 12269 http://openmsx.svn.sourceforge.net/openmsx/?rev=12269&view=rev Author: m9710797 Date: 2011-09-13 19:08:41 +0000 (Tue, 13 Sep 2011) Log Message: ----------- Improve emulation of MoonSound SRAM address space See comments in the code for all the details. But to summarize: - 640kB SRAM configuration has the last 128kB 4x mirrored - SRAM is mapped in different regions of the address space depending on the 'memory type' bit (bit 1 register 2) We now also verify that the ROM used for the moonsound extension is exactly 2MB in size and that the amount of specified SRAM is one of the supported configurations (0, 128, 256, 512, 640, 1024, 2048). Modified Paths: -------------- openmsx/trunk/src/sound/YMF278.cc Modified: openmsx/trunk/src/sound/YMF278.cc =================================================================== --- openmsx/trunk/src/sound/YMF278.cc 2011-09-13 19:08:25 UTC (rev 12268) +++ openmsx/trunk/src/sound/YMF278.cc 2011-09-13 19:08:41 UTC (rev 12269) @@ -14,7 +14,10 @@ #include "SimpleDebuggable.hh" #include "MSXMotherBoard.hh" #include "MemBuffer.hh" +#include "MSXException.hh" +#include "StringOp.hh" #include "serialize.hh" +#include "likely.hh" #include <algorithm> #include <cmath> #include <cstring> @@ -116,6 +119,7 @@ virtual void generateChannels(int** bufs, unsigned num); void writeRegDirect(byte reg, byte data, EmuTime::param time); + unsigned getRamAddress(unsigned addr) const; byte readMem(unsigned address) const; void writeMem(unsigned address, byte value); short getSample(YMF278Slot& op); @@ -141,8 +145,6 @@ const std::auto_ptr<Rom> rom; MemBuffer<byte> ram; - const unsigned endRom; - const unsigned endRam; /** Precalculated attenuation values with some margin for * envelope and pan levels. @@ -878,9 +880,25 @@ , debugMemory (new DebugMemory (*this, motherBoard)) , rom(new Rom(motherBoard, name + " ROM", "rom", config)) , ram(ramSize * 1024) // in kB - , endRom(rom->getSize()) - , endRam(endRom + ram.size()) { + if (rom->getSize() != 0x200000) { // 2MB + throw MSXException( + "Wrong ROM for MoonSound (YMF278). The ROM (usually " + "called yrw801.rom) should have a size of exactly 2MB."); + } + if ((ramSize != 0) && // - - + (ramSize != 128) && // 128kB - + (ramSize != 256) && // 128kB 128kB + (ramSize != 512) && // 512kB - + (ramSize != 640) && // 512kB 128kB + (ramSize != 1024) && // 512kB 512kB + (ramSize != 2048)) { // 512kB 512kB 512kB 512kB + throw MSXException(StringOp::Builder() << + "Wrong sampleram size for MoonSound (YMF278). " + "Got " << ramSize << ", but must be one of " + "0, 128, 256, 512, 640, 1024 or 2048."); + } + memadr = 0; // avoid UMR setInputRate(44100); @@ -923,28 +941,128 @@ fm_l = fm_r = pcm_l = pcm_r = 0; } +// This routine translates an address from the (upper) MoonSound address space +// to an address inside the (linearized) SRAM address space. +// +// The following info is based on measurements on a real MoonSound (v2.0) +// PCB. This PCB can have several possible SRAM configurations: +// 128kB: +// 1 SRAM chip of 128kB, chip enable (/CE) of this SRAM chip is connected to +// the 1Y0 output of a 74LS139 (2-to-4 decoder). The enable input of the +// 74LS139 is connected to YMF278 pin /MCS6 and the 74LS139 1B:1A inputs are +// connected to YMF278 pins MA18:MA17. So the SRAM is selected when /MC6 is +// active and MA18:MA17 == 0:0. +// 256kB: +// 2 SRAM chips of 128kB. First one connected as above. Second one has /CE +// connected to 74LS139 pin 1Y1. So SRAM2 is selected when /MSC6 is active +// and MA18:MA17 == 0:1. +// 512kB: +// 1 SRAM chip of 512kB, /CE connected to /MCS6 +// 640kB: +// 1 SRAM chip of 512kB, /CE connected to /MCS6 +// 1 SRAM chip of 128kB, /CE connected to /MCS7. +// (This means SRAM2 is potentially mirrored over a 512kB region) +// 1024kB: +// 1 SRAM chip of 512kB, /CE connected to /MCS6 +// 1 SRAM chip of 512kB, /CE connected to /MCS7 +// 2048kB: +// 1 SRAM chip of 512kB, /CE connected to /MCS6 +// 1 SRAM chip of 512kB, /CE connected to /MCS7 +// 1 SRAM chip of 512kB, /CE connected to /MCS8 +// 1 SRAM chip of 512kB, /CE connected to /MCS9 +// This configuration is not so easy to create on the v2.0 PCB. So it's +// very rare. +// +// So the /MCS6 and /MCS7 (and /MCS8 and /MCS9 in case of 2048kB) signals are +// used to select the different SRAM chips. The meaning of these signals +// depends on the 'memory access mode'. This mode can be changed at run-time +// via bit 1 in register 2. The following table indicates for which regions +// these signals are active (normally MoonSound should be used with mode=0): +// mode=0 mode=1 +// /MCS6 0x200000-0x27FFFF 0x380000-0x39FFFF +// /MCS7 0x280000-0x2FFFFF 0x3A0000-0x3BFFFF +// /MCS8 0x300000-0x37FFFF 0x3C0000-0x3DFFFF +// /MCS9 0x380000-0x3FFFFF 0x3E0000-0x3FFFFF +// +// (For completeness) MoonSound also has 2MB ROM (YRW801), /CE of this ROM is +// connected to YMF278 /MCS0. In both mode=0 and mode=1 this signal is active +// for the region 0x000000-0x1FFFFF. (But this routine does not handle ROM). +unsigned YMF278Impl::getRamAddress(unsigned addr) const +{ + addr -= 0x200000; // RAM starts at 0x200000 + if (unlikely(regs[2] & 2)) { + // Normally MoonSound is used in 'memory access mode = 0'. But + // in the rare case that mode=1 we adjust the address. + if ((0x180000 <= addr) && (addr <= 0x1FFFFF)) { + addr -= 0x180000; + switch (addr & 0x060000) { + case 0x000000: // [0x380000-0x39FFFF] + // 1st 128kB of SRAM1 + break; + case 0x020000: // [0x3A0000-0x3BFFFF] + if (ram.size() == 256*1024) { + // 2nd 128kB SRAM chip + } else { + // 2nd block of 128kB in SRAM2 + // In case of 512+128, we use mirroring + addr += 0x080000; + } + break; + case 0x040000: // [0x3C0000-0x3DFFFF] + // 3rd 128kB block in SRAM3 + addr += 0x100000; + break; + case 0x060000: // [0x3EFFFF-0x3FFFFF] + // 4th 128kB block in SRAM4 + addr += 0x180000; + break; + } + } else { + addr = unsigned(-1); // unmapped + } + } + if (ram.size() == 640*1024) { + // Verified on real MoonSound cartridge (v2.0): In case of + // 640kB (1x512kB + 1x128kB), the 128kB SRAM chip is 4 times + // visible. None of the other SRAM configurations show similar + // mirroring (because the others are powers of two). + if (addr > 0x080000) { + addr &= ~0x060000; + } + } + return addr; +} + byte YMF278Impl::readMem(unsigned address) const { // Verified on real YMF278: address space wraps at 4MB. address &= 0x3FFFFF; - if (address < endRom) { + if (address < 0x200000) { + // ROM connected to /MCS0 return (*rom)[address]; - } else if (address < endRam) { - return ram[address - endRom]; } else { - return 255; // TODO check + unsigned ramAddr = getRamAddress(address); + if (ramAddr < ram.size()) { + return ram[ramAddr]; + } else { + // unmapped region + return 255; // TODO check + } } } void YMF278Impl::writeMem(unsigned address, byte value) { address &= 0x3FFFFF; - if (address < endRom) { + if (address < 0x200000) { // can't write to ROM - } else if (address < endRam) { - ram[address - endRom] = value; } else { - // can't write to unmapped memory + unsigned ramAddr = getRamAddress(address); + if (ramAddr < ram.size()) { + ram[ramAddr] = value; + } else { + // can't write to unmapped memory + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |