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 "one_of.hh"
31 #include "serialize.hh"
32 #include <memory>
33 
34 namespace openmsx {
35 
36 RomHalnote::RomHalnote(const DeviceConfig& config, Rom&& rom_)
37  : Rom8kBBlocks(config, std::move(rom_))
38 {
39  if (rom.getSize() != 0x100000) {
40  throw MSXException(
41  "Rom for HALNOTE mapper must be exactly 1MB in size.");
42  }
43  sram = std::make_unique<SRAM>(getName() + " SRAM", 0x4000, config);
44  reset(EmuTime::dummy());
45 }
46 
47 void RomHalnote::reset(EmuTime::param /*time*/)
48 {
49  subBanks[0] = subBanks[1] = 0;
50  sramEnabled = false;
51  subMapperEnabled = false;
52 
53  setUnmapped(0);
54  setUnmapped(1);
55  for (int i = 2; i < 6; i++) {
56  setRom(i, 0);
57  }
58  setUnmapped(6);
59  setUnmapped(7);
60 }
61 
62 const byte* RomHalnote::getReadCacheLine(word address) const
63 {
64  if (subMapperEnabled && (0x7000 <= address) && (address < 0x8000)) {
65  // sub-mapper
66  int subBank = address < 0x7800 ? 0 : 1;
67  return &rom[0x80000 + subBanks[subBank] * 0x800 + (address & 0x7FF)];
68  } else {
69  // default mapper implementation
70  return Rom8kBBlocks::getReadCacheLine(address);
71  }
72 }
73 byte RomHalnote::readMem(word address, EmuTime::param /*time*/)
74 {
75  // all reads are cacheable, reuse that implementation
76  return *RomHalnote::getReadCacheLine(address);
77 }
78 
79 void RomHalnote::writeMem(word address, byte value, EmuTime::param /*time*/)
80 {
81  if (address < 0x4000) {
82  // SRAM region
83  if (sramEnabled) {
84  sram->write(address, value);
85  }
86  } else if (address < 0xC000) {
87  if (address == one_of(0x77FF, 0x7FFF)) {
88  // sub-mapper bank switch region
89  int subBank = address < 0x7800 ? 0 : 1;
90  if (subBanks[subBank] != value) {
91  subBanks[subBank] = value;
92  if (subMapperEnabled) {
94  0x7000 + subBank * 0x800, 0x800);
95  }
96  }
97  } else if ((address & 0x1FFF) == 0x0FFF) {
98  // normal bank switch region
99  int bank = address >> 13; // 2-5
100  setRom(bank, value);
101  if (bank == 2) {
102  // sram enable/disable
103  bool newSramEnabled = (value & 0x80) != 0;
104  if (newSramEnabled != sramEnabled) {
105  sramEnabled = newSramEnabled;
106  if (sramEnabled) {
107  setBank(0, &(*sram)[0x0000], value);
108  setBank(1, &(*sram)[0x2000], value);
109  } else {
110  setUnmapped(0);
111  setUnmapped(1);
112  }
113  // 'R' is already handled
114  invalidateDeviceWCache(0x0000, 0x4000);
115  }
116  } else if (bank == 3) {
117  // sub-mapper enable/disable
118  subMapperEnabled = (value & 0x80) != 0;
119  if (subMapperEnabled) {
120  invalidateDeviceRCache(0x7000, 0x1000);
121  }
122  }
123  }
124  }
125 }
126 
128 {
129  if (address < 0x4000) {
130  // SRAM region
131  if (sramEnabled) {
132  return nullptr;
133  }
134  } else if (address < 0xC000) {
135  if ((address & CacheLine::HIGH) == one_of(0x77FF & CacheLine::HIGH,
136  0x7FFF & CacheLine::HIGH)) {
137  // sub-mapper bank switch region
138  return nullptr;
139  } else if ((address & 0x1FFF & CacheLine::HIGH) ==
140  (0x0FFF & CacheLine::HIGH)) {
141  // normal bank switch region
142  return nullptr;
143  }
144  }
145  return unmappedWrite;
146 }
147 
148 template<typename Archive>
149 void RomHalnote::serialize(Archive& ar, unsigned /*version*/)
150 {
151  ar.template serializeBase<Rom8kBBlocks>(*this);
152  ar.serialize("subBanks", subBanks,
153  "sramEnabled", sramEnabled,
154  "subMapperEnabled", subMapperEnabled);
155 
156 }
158 REGISTER_MSXDEVICE(RomHalnote, "RomHalnote");
159 
160 } // namespace openmsx
one_of.hh
openmsx::RomHalnote::serialize
void serialize(Archive &ar, unsigned version)
Definition: RomHalnote.cc:149
RomHalnote.hh
serialize.hh
openmsx::RomHalnote::RomHalnote
RomHalnote(const DeviceConfig &config, Rom &&rom)
Definition: RomHalnote.cc:36
openmsx::RomHalnote::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: RomHalnote.cc:73
openmsx::DeviceConfig
Definition: DeviceConfig.hh:19
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:301
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::RomHalnote::getReadCacheLine
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:62
MSXException.hh
openmsx::MSXException
Definition: MSXException.hh:9
openmsx::RomBlocks::sram
std::unique_ptr< SRAM > sram
Definition: RomBlocks.hh:83
openmsx::CacheLine::HIGH
constexpr unsigned HIGH
Definition: CacheLine.hh:10
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::RomHalnote::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: RomHalnote.cc:79
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::RomHalnote
Definition: RomHalnote.hh:8
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
one_of
Definition: one_of.hh:7
openmsx::RomBlocks::setUnmapped
void setUnmapped(byte region)
Select 'unmapped' memory for this region.
Definition: RomBlocks.cc:91
openmsx::RomBlocks
Definition: RomBlocks.hh:13
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
CacheLine.hh
openmsx::MSXRom::rom
Rom rom
Definition: MSXRom.hh:20
openmsx::Rom
Definition: Rom.hh:20
openmsx::MSXDevice::invalidateDeviceRCache
void invalidateDeviceRCache()
Definition: MSXDevice.hh:209
SRAM.hh
openmsx::MSXDevice::getName
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:381
openmsx::RomHalnote::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: RomHalnote.cc:127
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
openmsx::RomHalnote::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: RomHalnote.cc:47
openmsx::Rom::getSize
unsigned getSize() const
Definition: Rom.hh:32
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5