openMSX
RomHalnote.cc
Go to the documentation of this file.
1 /*
2  * HALNOTE mapper
3  *
4  * This info is extracted from the romMapperHalnote.c source in blueMSX,
5  * implemented by white_cat.
6  *
7  * This is a 1024kB mapper, it's divided in 128 pages of 8kB. The last 512kB
8  * can also be mapped as 256 pages of 2kB. There is 16kB SRAM.
9  *
10  * Main bankswitch registers:
11  * bank 0, region: [0x4000-0x5FFF], switch addr: 0x4FFF
12  * bank 1, region: [0x6000-0x7FFF], switch addr: 0x6FFF
13  * bank 2, region: [0x8000-0x9FFF], switch addr: 0x8FFF
14  * bank 3, region: [0xA000-0xBFFF], switch addr: 0xAFFF
15  * Sub-bankswitch registers:
16  * bank 0, region: [0x7000-0x77FF], switch addr: 0x77FF
17  * bank 1, region: [0x7800-0x7FFF], switch addr: 0x7FFF
18  * Note that the two sub-banks overlap with main bank 1!
19  *
20  * The upper bit (0x80) of the first two main bankswitch registers are special:
21  * bank 0, bit7 SRAM enabled in [0x0000-0x3FFF] (1=enabled)
22  * bank 1, bit7 submapper enabled in [0x7000-0x7FFF] (1=enabled)
23  * If enabled, the submapper shadows (part of) main bank 1.
24  */
25 
26 #include "RomHalnote.hh"
27 #include "CacheLine.hh"
28 #include "SRAM.hh"
29 #include "MSXException.hh"
30 #include "serialize.hh"
31 #include <memory>
32 
33 namespace openmsx {
34 
35 RomHalnote::RomHalnote(const DeviceConfig& config, Rom&& rom_)
36  : Rom8kBBlocks(config, std::move(rom_))
37 {
38  if (rom.getSize() != 0x100000) {
39  throw MSXException(
40  "Rom for HALNOTE mapper must be exactly 1MB in size.");
41  }
42  sram = std::make_unique<SRAM>(getName() + " SRAM", 0x4000, config);
43  reset(EmuTime::dummy());
44 }
45 
46 void RomHalnote::reset(EmuTime::param /*time*/)
47 {
48  subBanks[0] = subBanks[1] = 0;
49  sramEnabled = false;
50  subMapperEnabled = false;
51 
52  setUnmapped(0);
53  setUnmapped(1);
54  for (int i = 2; i < 6; i++) {
55  setRom(i, 0);
56  }
57  setUnmapped(6);
58  setUnmapped(7);
59 }
60 
61 const byte* RomHalnote::getReadCacheLine(word address) const
62 {
63  if (subMapperEnabled && (0x7000 <= address) && (address < 0x8000)) {
64  // sub-mapper
65  int subBank = address < 0x7800 ? 0 : 1;
66  return &rom[0x80000 + subBanks[subBank] * 0x800 + (address & 0x7FF)];
67  } else {
68  // default mapper implementation
69  return Rom8kBBlocks::getReadCacheLine(address);
70  }
71 }
72 byte RomHalnote::readMem(word address, EmuTime::param /*time*/)
73 {
74  // all reads are cacheable, reuse that implementation
75  return *RomHalnote::getReadCacheLine(address);
76 }
77 
78 void RomHalnote::writeMem(word address, byte value, EmuTime::param /*time*/)
79 {
80  if (address < 0x4000) {
81  // SRAM region
82  if (sramEnabled) {
83  sram->write(address, value);
84  }
85  } else if (address < 0xC000) {
86  if ((address == 0x77FF) || (address == 0x7FFF)) {
87  // sub-mapper bank switch region
88  int subBank = address < 0x7800 ? 0 : 1;
89  if (subBanks[subBank] != value) {
90  subBanks[subBank] = value;
91  if (subMapperEnabled) {
93  0x7000 + subBank * 0x800, 0x800);
94  }
95  }
96  } else if ((address & 0x1FFF) == 0x0FFF) {
97  // normal bank switch region
98  int bank = address >> 13; // 2-5
99  setRom(bank, value);
100  if (bank == 2) {
101  // sram enable/disable
102  bool newSramEnabled = (value & 0x80) != 0;
103  if (newSramEnabled != sramEnabled) {
104  sramEnabled = newSramEnabled;
105  if (sramEnabled) {
106  setBank(0, &(*sram)[0x0000], value);
107  setBank(1, &(*sram)[0x2000], value);
108  } else {
109  setUnmapped(0);
110  setUnmapped(1);
111  }
112  }
113  } else if (bank == 3) {
114  // sub-mapper enable/disable
115  bool newSubMapperEnabled = (value & 0x80) != 0;
116  if (newSubMapperEnabled != subMapperEnabled) {
117  subMapperEnabled = newSubMapperEnabled;
118  invalidateMemCache(0x7000, 0x1000);
119  }
120  }
121  }
122  }
123 }
124 
126 {
127  if (address < 0x4000) {
128  // SRAM region
129  if (sramEnabled) {
130  return nullptr;
131  }
132  } else if (address < 0xC000) {
133  if (((address & CacheLine::HIGH) == (0x77FF & CacheLine::HIGH)) ||
134  ((address & CacheLine::HIGH) == (0x7FFF & CacheLine::HIGH))) {
135  // sub-mapper bank switch region
136  return nullptr;
137  } else if ((address & 0x1FFF & CacheLine::HIGH) ==
138  (0x0FFF & CacheLine::HIGH)) {
139  // normal bank switch region
140  return nullptr;
141  }
142  }
143  return unmappedWrite;
144 }
145 
146 template<typename Archive>
147 void RomHalnote::serialize(Archive& ar, unsigned /*version*/)
148 {
149  ar.template serializeBase<Rom8kBBlocks>(*this);
150  ar.serialize("subBanks", subBanks,
151  "sramEnabled", sramEnabled,
152  "subMapperEnabled", subMapperEnabled);
153 
154 }
156 REGISTER_MSXDEVICE(RomHalnote, "RomHalnote");
157 
158 } // namespace openmsx
void setRom(byte region, unsigned block)
Selects a block of the ROM image for reading in a certain region.
Definition: RomBlocks.cc:98
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
STL namespace.
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:374
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: RomHalnote.cc:72
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
void setBank(byte region, const byte *adr, int block)
Sets the memory visible for reading in a certain region.
Definition: RomBlocks.cc:71
void reset(EmuTime::param time) override
This method is called on reset.
Definition: RomHalnote.cc:46
void serialize(Archive &ar, unsigned version)
Definition: RomHalnote.cc:147
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
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:65
unsigned getSize() const
Definition: Rom.hh:32
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
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: RomHalnote.cc:78
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing...
Definition: RomHalnote.cc:125
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:275
void setUnmapped(byte region)
Select &#39;unmapped&#39; memory for this region.
Definition: RomBlocks.cc:85
std::unique_ptr< SRAM > sram
Definition: RomBlocks.hh:82
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading...
Definition: RomHalnote.cc:61
RomHalnote(const DeviceConfig &config, Rom &&rom)
Definition: RomHalnote.cc:35
void invalidateMemCache(word start, unsigned size)
Invalidate CPU memory-mapping cache.
Definition: MSXDevice.cc:458