openMSX
RomPanasonic.cc
Go to the documentation of this file.
1 #include "RomPanasonic.hh"
2 #include "PanasonicMemory.hh"
3 #include "MSXMotherBoard.hh"
4 #include "DeviceConfig.hh"
5 #include "SRAM.hh"
6 #include "CacheLine.hh"
7 #include "serialize.hh"
8 #include <memory>
9 
10 namespace openmsx {
11 
12 const int SRAM_BASE = 0x80;
13 const int RAM_BASE = 0x180;
14 
16  : Rom8kBBlocks(config, std::move(rom_))
17  , panasonicMem(getMotherBoard().getPanasonicMemory())
18 {
19  unsigned sramSize = config.getChildDataAsInt("sramsize", 0);
20  if (sramSize) {
21  sram = std::make_unique<SRAM>(
22  getName() + " SRAM", sramSize * 1024, config);
23  }
24 
25  if (config.getChildDataAsBool("sram-mirrored", false)) {
26  maxSRAMBank = SRAM_BASE + 8;
27  } else {
28  maxSRAMBank = SRAM_BASE + (sramSize / 8);
29  }
30 
31  // Inform baseclass about PanasonicMemory (needed for serialization).
32  // This relies on the order of MSXDevice instantiation, the PanasonicRam
33  // device must be create before this one. (In the hardwareconfig.xml
34  // we added a device-reference from this device to the PanasonicRam
35  // device, this should protected against wrong future edits in the
36  // config file).
37  setExtraMemory(panasonicMem.getRamBlock(0), panasonicMem.getRamSize());
38 
39  reset(EmuTime::dummy());
40 }
41 
42 void RomPanasonic::reset(EmuTime::param /*time*/)
43 {
44  control = 0;
45  for (int region = 0; region < 8; ++region) {
46  bankSelect[region] = 0;
47  setRom(region, 0);
48  }
50 }
51 
52 byte RomPanasonic::peekMem(word address, EmuTime::param time) const
53 {
54  byte result;
55  if ((control & 0x04) && (0x7FF0 <= address) && (address < 0x7FF8)) {
56  // read mapper state (lower 8 bit)
57  result = bankSelect[address & 7] & 0xFF;
58  } else if ((control & 0x10) && (address == 0x7FF8)) {
59  // read mapper state (9th bit)
60  result = 0;
61  for (int i = 7; i >= 0; i--) {
62  result <<= 1;
63  if (bankSelect[i] & 0x100) {
64  result++;
65  }
66  }
67  } else if ((control & 0x08) && (address == 0x7FF9)) {
68  // read control byte
69  result = control;
70  } else {
71  result = Rom8kBBlocks::peekMem(address, time);
72  }
73  return result;
74 }
75 
76 byte RomPanasonic::readMem(word address, EmuTime::param time)
77 {
78  return RomPanasonic::peekMem(address, time);
79 }
80 
81 const byte* RomPanasonic::getReadCacheLine(word address) const
82 {
83  if ((0x7FF0 & CacheLine::HIGH) == address) {
84  // TODO check mirrored
85  return nullptr;
86  } else {
87  return Rom8kBBlocks::getReadCacheLine(address);
88  }
89 }
90 
91 void RomPanasonic::writeMem(word address, byte value, EmuTime::param /*time*/)
92 {
93  if ((0x6000 <= address) && (address < 0x7FF0)) {
94  // set mapper state (lower 8 bits)
95  int region = (address & 0x1C00) >> 10;
96  if ((region == 5) || (region == 6)) region ^= 3;
97  int selectedBank = bankSelect[region];
98  int newBank = (selectedBank & ~0xFF) | value;
99  changeBank(region, newBank);
100  } else if (address == 0x7FF8) {
101  // set mapper state (9th bit)
102  for (int region = 0; region < 8; region++) {
103  if (value & 1) {
104  changeBank(region, bankSelect[region] | 0x100);
105  } else {
106  changeBank(region, bankSelect[region] & ~0x100);
107  }
108  value >>= 1;
109  }
110  } else if (address == 0x7FF9) {
111  // write control byte
112  control = value;
113  } else {
114  // Tested on real FS-A1GT:
115  // SRAM/RAM can be written to from all regions, including e.g.
116  // address 0x7ff0. (I didn't actually test 0xc000-0xffff).
117  int region = address >> 13;
118  int selectedBank = bankSelect[region];
119  if (sram && (SRAM_BASE <= selectedBank) &&
120  (selectedBank < maxSRAMBank)) {
121  // SRAM
122  int block = selectedBank - SRAM_BASE;
123  sram->write((block * 0x2000) | (address & 0x1FFF), value);
124  } else if (RAM_BASE <= selectedBank) {
125  // RAM
126  const_cast<byte*>(bankPtr[region])[address & 0x1FFF] = value;
127  }
128  }
129 }
130 
132 {
133  if ((0x6000 <= address) && (address < 0x8000)) {
134  // mapper select (low/high), control
135  return nullptr;
136  } else {
137  int region = address >> 13;
138  int selectedBank = bankSelect[region];
139  if (sram && (SRAM_BASE <= selectedBank) &&
140  (selectedBank < maxSRAMBank)) {
141  // SRAM
142  return nullptr;
143  } else if (RAM_BASE <= selectedBank) {
144  // RAM
145  return const_cast<byte*>(&bankPtr[region][address & 0x1FFF]);
146  } else {
147  return unmappedWrite;
148  }
149  }
150 }
151 
152 void RomPanasonic::changeBank(byte region, int bank)
153 {
154  if (bank == bankSelect[region]) {
155  return;
156  }
157  bankSelect[region] = bank;
158 
159  if (sram && (SRAM_BASE <= bank) && (bank < maxSRAMBank)) {
160  // SRAM
161  int offset = (bank - SRAM_BASE) * 0x2000;
162  int sramSize = sram->getSize();
163  if (offset >= sramSize) {
164  offset &= (sramSize - 1);
165  }
166  // TODO romblock debuggable is only 8 bits, here bank is 9 bits
167  setBank(region, &sram->operator[](offset), bank);
168  } else if (panasonicMem.getRamSize() && (RAM_BASE <= bank)) {
169  // RAM
170  // TODO romblock debuggable is only 8 bits, here bank is 9 bits
171  setBank(region, panasonicMem.getRamBlock(bank - RAM_BASE), bank);
172  } else {
173  // ROM
174  setRom(region, bank);
175  }
176  invalidateDeviceWCache(0x2000 * region, 0x2000); // 'R' is already handled
177  if (region == 3) {
178  // don't pre-fill [0x7ff0, 0x7fff]
180  }
181 }
182 
183 template<typename Archive>
184 void RomPanasonic::serialize(Archive& ar, unsigned /*version*/)
185 {
186  ar.template serializeBase<Rom8kBBlocks>(*this);
187  ar.serialize("bankSelect", bankSelect,
188  "control", control);
189 }
191 REGISTER_MSXDEVICE(RomPanasonic, "RomPanasonic");
192 
193 } // namespace openmsx
openmsx::RomBlocks::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: RomBlocks.cc:59
serialize.hh
openmsx::DeviceConfig
Definition: DeviceConfig.hh:19
RomPanasonic.hh
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:293
openmsx::RomBlocks::setBank
void setBank(byte region, const byte *adr, int block)
Sets the memory visible for reading in a certain region.
Definition: RomBlocks.cc:77
openmsx::RomBlocks::setExtraMemory
void setExtraMemory(const byte *mem, unsigned size)
Inform this base class of extra mapable memory block.
Definition: RomBlocks.cc:97
openmsx::RAM_BASE
const int RAM_BASE
Definition: RomPanasonic.cc:13
openmsx::RomBlocks::sram
std::unique_ptr< SRAM > sram
Definition: RomBlocks.hh:83
openmsx::PanasonicMemory::getRamBlock
byte * getRamBlock(unsigned block)
Note that this is always unchecked RAM! There is no UMR detection when accessing Ram in DRAM mode or ...
Definition: PanasonicMemory.cc:87
openmsx::CacheLine::HIGH
constexpr unsigned HIGH
Definition: CacheLine.hh:10
openmsx::RomBlocks::bankPtr
const byte * bankPtr[NUM_BANKS]
Definition: RomBlocks.hh:82
openmsx::RomPanasonic::serialize
void serialize(Archive &ar, unsigned version)
Definition: RomPanasonic.cc:184
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::RomPanasonic::RomPanasonic
RomPanasonic(const DeviceConfig &config, Rom &&rom)
Definition: RomPanasonic.cc:15
openmsx::RomPanasonic
Definition: RomPanasonic.hh:10
openmsx::RomPanasonic::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: RomPanasonic.cc:52
openmsx::RomPanasonic::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: RomPanasonic.cc:131
openmsx::RomBlocks::getReadCacheLine
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: RomBlocks.cc:71
openmsx::RomBlocks::setRom
void setRom(byte region, unsigned block)
Selects a block of the ROM image for reading in a certain region.
Definition: RomBlocks.cc:104
openmsx::MSXDevice::invalidateDeviceWCache
void invalidateDeviceWCache()
Definition: MSXDevice.hh:210
openmsx::RomBlocks
Definition: RomBlocks.hh:13
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::CacheLine::SIZE
constexpr unsigned SIZE
Definition: CacheLine.hh:7
openmsx::SRAM_BASE
const int SRAM_BASE
Definition: RomPanasonic.cc:12
CacheLine.hh
openmsx::Rom
Definition: Rom.hh:20
openmsx::MSXDevice::invalidateDeviceRCache
void invalidateDeviceRCache()
Definition: MSXDevice.hh:209
SRAM.hh
openmsx::RomPanasonic::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: RomPanasonic.cc:42
openmsx::MSXDevice::getName
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:379
openmsx::DeviceConfig::getChildDataAsInt
int getChildDataAsInt(std::string_view name, int defaultValue=0) const
Definition: DeviceConfig.cc:52
openmsx::RomPanasonic::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: RomPanasonic.cc:76
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
openmsx::RomPanasonic::writeMem
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
Definition: RomPanasonic.cc:91
DeviceConfig.hh
PanasonicMemory.hh
openmsx::PanasonicMemory::getRamSize
unsigned getRamSize() const
Definition: PanasonicMemory.hh:32
openmsx::RomPanasonic::getReadCacheLine
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: RomPanasonic.cc:81
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
MSXMotherBoard.hh
openmsx::DeviceConfig::getChildDataAsBool
bool getChildDataAsBool(std::string_view name, bool defaultValue=false) const
Definition: DeviceConfig.cc:56