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 "Rom.hh"
29 #include "SRAM.hh"
30 #include "MSXException.hh"
31 #include "serialize.hh"
32 #include "memory.hh"
33 
34 namespace openmsx {
35 
36 RomHalnote::RomHalnote(const DeviceConfig& config, std::unique_ptr<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 = make_unique<SRAM>(getName() + " SRAM", 0x4000, config);
45 }
46 
48 {
49 }
50 
52 {
53  subBanks[0] = subBanks[1] = 0;
54  sramEnabled = false;
55  subMapperEnabled = false;
56 
57  setUnmapped(0);
58  setUnmapped(1);
59  for (int i = 2; i < 6; i++) {
60  setRom(i, 0);
61  }
62  setUnmapped(6);
63  setUnmapped(7);
64 }
65 
66 const byte* RomHalnote::getReadCacheLine(word address) const
67 {
68  if (subMapperEnabled && (0x7000 <= address) && (address < 0x8000)) {
69  // sub-mapper
70  int subBank = address < 0x7800 ? 0 : 1;
71  return &(*rom)[0x80000 + subBanks[subBank] * 0x800 + (address & 0x7FF)];
72  } else {
73  // default mapper implementation
74  return Rom8kBBlocks::getReadCacheLine(address);
75  }
76 }
78 {
79  // all reads are cacheable, reuse that implementation
80  return *RomHalnote::getReadCacheLine(address);
81 }
82 
83 void RomHalnote::writeMem(word address, byte value, EmuTime::param /*time*/)
84 {
85  if (address < 0x4000) {
86  // SRAM region
87  if (sramEnabled) {
88  sram->write(address, value);
89  }
90  } else if (address < 0xC000) {
91  if ((address == 0x77FF) || (address == 0x7FFF)) {
92  // sub-mapper bank switch region
93  int subBank = address < 0x7800 ? 0 : 1;
94  if (subBanks[subBank] != value) {
95  subBanks[subBank] = value;
96  if (subMapperEnabled) {
98  0x7000 + subBank * 0x800, 0x800);
99  }
100  }
101  } else if ((address & 0x1FFF) == 0x0FFF) {
102  // normal bank switch region
103  int bank = address >> 13; // 2-5
104  setRom(bank, value);
105  if (bank == 2) {
106  // sram enable/disable
107  bool newSramEnabled = (value & 0x80) != 0;
108  if (newSramEnabled != sramEnabled) {
109  sramEnabled = newSramEnabled;
110  if (sramEnabled) {
111  setBank(0, &(*sram)[0x0000], value);
112  setBank(1, &(*sram)[0x2000], value);
113  } else {
114  setUnmapped(0);
115  setUnmapped(1);
116  }
117  }
118  } else if (bank == 3) {
119  // sub-mapper enable/disable
120  bool newSubMapperEnabled = (value & 0x80) != 0;
121  if (newSubMapperEnabled != subMapperEnabled) {
122  subMapperEnabled = newSubMapperEnabled;
123  invalidateMemCache(0x7000, 0x1000);
124  }
125  }
126  }
127  }
128 }
129 
131 {
132  if (address < 0x4000) {
133  // SRAM region
134  if (sramEnabled) {
135  return nullptr;
136  }
137  } else if (address < 0xC000) {
138  if (((address & CacheLine::HIGH) == (0x77FF & CacheLine::HIGH)) ||
139  ((address & CacheLine::HIGH) == (0x7FFF & CacheLine::HIGH))) {
140  // sub-mapper bank switch region
141  return nullptr;
142  } else if ((address & 0x1FFF & CacheLine::HIGH) ==
143  (0x0FFF & CacheLine::HIGH)) {
144  // normal bank switch region
145  return nullptr;
146  }
147  }
148  return unmappedWrite;
149 }
150 
151 template<typename Archive>
152 void RomHalnote::serialize(Archive& ar, unsigned /*version*/)
153 {
154  ar.template serializeBase<Rom8kBBlocks>(*this);
155  ar.serialize("subBanks", subBanks);
156  ar.serialize("sramEnabled", sramEnabled);
157  ar.serialize("subMapperEnabled", subMapperEnabled);
158 
159 }
161 REGISTER_MSXDEVICE(RomHalnote, "RomHalnote");
162 
163 } // namespace openmsx