openMSX
ROMHunterMk2.cc
Go to the documentation of this file.
1 #include "ROMHunterMk2.hh"
2 #include "serialize.hh"
3 #include <cassert>
4 
5 /*
6 
7 As reverse engineered by BiFi:
8 
9 At 0x3FFF is a configuration register.
10 bit 1: page 1 control:
11  0: ROM hunter ROM in page 1 for READs, writes ignored (default)
12  1: writes go to RAM in page 1, mapper switching disabled
13 bits 2 and 0 is a mapper selector:
14  00 = ASCII16 (default),
15  01 = ASCII8,
16  11 = Konami,
17  10 = unknown (seems to be some Konami 16K variant)
18 bit 3: RAM write protect:
19  0: write enable (default)
20  1: write protect; also sets reads in page 1 to RAM (and not ROM)
21 
22 When the ROM loads a MegaROM, bit 1 is left on 0. But for plain ROMs, it is set
23 to 1.
24 */
25 
26 namespace openmsx {
27 
29  : MSXRom(config, std::move(rom_))
30  , ram(config, getName() + " RAM", "ROM Hunter Mk 2 RAM", 0x40000)
31 {
33 }
34 
35 void ROMHunterMk2::reset(EmuTime::param /*time*/)
36 {
37  configReg = 0;
38  for (int i = 0; i < 4; ++i) {
39  bankRegs[i] = 0;
40  }
41  invalidateDeviceRCache(); // flush all to be sure
42 }
43 
44 unsigned ROMHunterMk2::getRamAddr(unsigned addr) const
45 {
46  unsigned page = (addr >> 13) - 2;
47  assert(page < 4);
48  unsigned bank = bankRegs[page];
49  return (bank * 0x2000) + (addr & 0x1FFF);
50 }
51 
52 const byte* ROMHunterMk2::getReadCacheLine(word addr) const
53 {
54  // reads outside [0x4000, 0xC000) return 0xFF
55  if ((addr < 0x4000) || (0xC000 <= addr)) {
56  return unmappedRead;
57  }
58 
59  // if bit 3 is 0, reads from page 1 come from the ROM, else from the RAM
60  if (((configReg & 0b1000) == 0) && (addr < 0x8000)) {
61  return &rom[addr & 0x1FFF];
62  } else {
63  return &ram[getRamAddr(addr)];
64  }
65 }
66 
67 byte ROMHunterMk2::peekMem(word addr, EmuTime::param /*time*/) const
68 {
69  return *getReadCacheLine(addr);
70 }
71 
72 byte ROMHunterMk2::readMem(word addr, EmuTime::param time)
73 {
74  return peekMem(addr, time); // reads have no side effects
75 }
76 
77 void ROMHunterMk2::writeMem(word addr, byte value, EmuTime::param /*time*/)
78 {
79  // config register at address 0x3FFF
80  if (addr == 0x3FFF) {
81  configReg = value;
82  invalidateDeviceRCache(0x4000, 0x8000);
83  return;
84  }
85 
86  // ignore (other) writes outside [0x4000, 0xC000)
87  if ((addr < 0x4000) || (0xC000 <= addr)) {
88  return;
89  }
90 
91  // address is calculated before writes to other regions take effect
92  unsigned ramAddr = getRamAddr(addr);
93 
94  // only write mapper registers if bit 1 is not set
95  if ((configReg & 0b10) == 0) {
96  // (possibly) write to bank registers
97  switch (configReg & 0b101) {
98  case 0b000: {
99  // ASCII-16
100  // Implemented similarly as the (much later) MFR SCC+,
101  // TODO did we verify that ROMHunterMk2 behaves the same?
102  //
103  // ASCII-16 uses all 4 bank registers and one bank
104  // switch changes 2 registers at once. This matters
105  // when switching mapper mode, because the content of
106  // the bank registers is unchanged after a switch.
107  const byte maskedValue = value & 0xF;
108  if ((0x6000 <= addr) && (addr < 0x6800)) {
109  bankRegs[0] = 2 * maskedValue + 0;
110  bankRegs[1] = 2 * maskedValue + 1;
111  invalidateDeviceRCache(0x4000, 0x4000);
112  }
113  if ((0x7000 <= addr) && (addr < 0x7800)) {
114  bankRegs[2] = 2 * maskedValue + 0;
115  bankRegs[3] = 2 * maskedValue + 1;
116  invalidateDeviceRCache(0x8000, 0x4000);
117  }
118  break;
119  }
120  case 0b001:
121  // ASCII-8
122  if ((0x6000 <= addr) && (addr < 0x8000)) {
123  byte bank = (addr >> 11) & 0x03;
124  bankRegs[bank] = value & 0x1F;
125  invalidateDeviceRCache(0x4000 + 0x2000 * bank, 0x2000);
126  }
127  break;
128  case 0b101:
129  // Konami
130  if ((0x6000 <= addr) && (addr < 0xC000)) {
131  unsigned bank = (addr >> 13) - 2;
132  bankRegs[bank] = value & 0x1F;
133  invalidateDeviceRCache(0x4000 + 0x2000 * bank, 0x2000);
134  }
135  break;
136  case 0b100:
137  // TODO how does this configuration behave?
138  break;
139  }
140  }
141 
142  // write to RAM, if not write-protected
143  if ((configReg & 0b1000) == 0) {
144  // if write to [0x8000, 0xC000), just do it
145  // if write to [0x4000, 0x8000), only do it if bit 1 is set
146  if ((addr >= 0x8000) || ((configReg & 0b10) == 0b10)) {
147  ram[ramAddr] = value;
148  }
149  }
150 }
151 
153 {
154  return nullptr;
155 }
156 
157 template<typename Archive>
158 void ROMHunterMk2::serialize(Archive& ar, unsigned /*version*/)
159 {
160  // skip MSXRom base class
161  ar.template serializeBase<MSXDevice>(*this);
162  ar.serialize("ram", ram,
163  "configReg", configReg,
164  "bankRegs", bankRegs);
165 }
168 
169 } // namespace openmsx
serialize.hh
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::MSXRom
Definition: MSXRom.hh:10
openmsx::ROMHunterMk2::getReadCacheLine
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: ROMHunterMk2.cc:52
openmsx::ROMHunterMk2::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: ROMHunterMk2.cc:67
openmsx::ROMHunterMk2::serialize
void serialize(Archive &ar, unsigned version)
Definition: ROMHunterMk2.cc:158
openmsx::ROMHunterMk2
Definition: ROMHunterMk2.hh:10
openmsx::Keys::getName
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:740
openmsx::MSXDevice::getCurrentTime
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:131
openmsx::ROMHunterMk2::ROMHunterMk2
ROMHunterMk2(const DeviceConfig &config, Rom &&rom)
Definition: ROMHunterMk2.cc:28
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::ROMHunterMk2::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: ROMHunterMk2.cc:152
openmsx::MSXRom::rom
Rom rom
Definition: MSXRom.hh:20
openmsx::Rom
Definition: Rom.hh:21
openmsx::MSXDevice::invalidateDeviceRCache
void invalidateDeviceRCache()
Definition: MSXDevice.hh:209
openmsx::ROMHunterMk2::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: ROMHunterMk2.cc:35
openmsx::MSXDevice::unmappedRead
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:300
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
ROMHunterMk2.hh
openmsx::ROMHunterMk2::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: ROMHunterMk2.cc:77
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::ROMHunterMk2::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: ROMHunterMk2.cc:72