openMSX
RomBlocks.cc
Go to the documentation of this file.
1 #include "RomBlocks.hh"
2 #include "SRAM.hh"
3 #include "MSXException.hh"
4 #include "StringOp.hh"
5 #include "serialize.hh"
6 #include "unreachable.hh"
7 
8 namespace openmsx {
9 
10 template<bool C, class T, class F> struct if_log2_ : F {};
11 template< class T, class F> struct if_log2_<true, T, F> : T {};
12 template<unsigned A, unsigned R = 0> struct log2
13  : if_log2_<A == 1, std::integral_constant<int, R>, log2<A / 2, R + 1>> {};
14 
15 template <unsigned BANK_SIZE>
17  const DeviceConfig& config, Rom&& rom_,
18  unsigned debugBankSizeShift)
19  : MSXRom(config, std::move(rom_))
20  , romBlockDebug(
21  *this, blockNr, 0x0000, 0x10000,
22  log2<BANK_SIZE>::value, debugBankSizeShift)
23  , nrBlocks(rom.getSize() / BANK_SIZE)
24 {
25  if ((nrBlocks * BANK_SIZE) != rom.getSize()) {
27  "(uncompressed) ROM image filesize must be a multiple of " <<
28  BANK_SIZE / 1024 << " kB (for this mapper type).");
29  }
30  // by default no extra mappable memory block
31  extraMem = nullptr;
32  extraSize = 0;
33 
34  // Default mask: wraps at end of ROM image.
35  blockMask = nrBlocks - 1;
36  for (unsigned i = 0; i < NUM_BANKS; i++) {
37  setRom(i, 0);
38  }
39 }
40 
41 template <unsigned BANK_SIZE>
43 {
44 }
45 
46 template <unsigned BANK_SIZE>
48 {
49  return bank[address / BANK_SIZE][address & BANK_MASK];
50 }
51 
52 template <unsigned BANK_SIZE>
54 {
55  return &bank[address / BANK_SIZE][address & BANK_MASK];
56 }
57 
58 template <unsigned BANK_SIZE>
59 void RomBlocks<BANK_SIZE>::setBank(byte region, const byte* adr, int block)
60 {
61  assert("address passed to setBank() is not serializable" &&
62  ((adr == unmappedRead) ||
63  ((&rom[0] <= adr) && (adr <= &rom[rom.getSize() - 1])) ||
64  (sram && (&(*sram)[0] <= adr) &&
65  (adr <= &(*sram)[sram->getSize() - 1])) ||
66  ((extraMem <= adr) && (adr <= &extraMem[extraSize - 1]))));
67  bank[region] = adr;
68  blockNr[region] = block; // only for debuggable
69  invalidateMemCache(region * BANK_SIZE, BANK_SIZE);
70 }
71 
72 template <unsigned BANK_SIZE>
74 {
75  setBank(region, unmappedRead, 255);
76 }
77 
78 template <unsigned BANK_SIZE>
80 {
81  extraMem = mem;
82  extraSize = size;
83 }
84 
85 template <unsigned BANK_SIZE>
86 void RomBlocks<BANK_SIZE>::setRom(byte region, int block)
87 {
88  // Note: Some cartridges have a number of blocks that is not a power of 2,
89  // for those we have to make an exception for "block < nrBlocks".
90  block = (block < nrBlocks) ? block : block & blockMask;
91  if (block < nrBlocks) {
92  setBank(region, &rom[block * BANK_SIZE], block);
93  } else {
94  setBank(region, unmappedRead, 255);
95  }
96 }
97 
98 // version 1: initial version
99 // version 2: added blockNr
100 template <unsigned BANK_SIZE>
101 template<typename Archive>
102 void RomBlocks<BANK_SIZE>::serialize(Archive& ar, unsigned /*version*/)
103 {
104  // skip MSXRom base class
105  ar.template serializeBase<MSXDevice>(*this);
106 
107  if (sram) ar.serialize("sram", *sram);
108 
109  unsigned offsets[NUM_BANKS];
110  unsigned romSize = rom.getSize();
111  unsigned sramSize = sram ? sram->getSize() : 0;
112  if (ar.isLoader()) {
113  ar.serialize("banks", offsets);
114  for (unsigned i = 0; i < NUM_BANKS; ++i) {
115  if (offsets[i] == unsigned(-1)) {
116  bank[i] = unmappedRead;
117  } else if (offsets[i] < romSize) {
118  bank[i] = &rom[offsets[i]];
119  } else if (offsets[i] < (romSize + sramSize)) {
120  assert(sram);
121  bank[i] = &(*sram)[offsets[i] - romSize];
122  } else if (offsets[i] < (romSize + sramSize + extraSize)) {
123  bank[i] = &extraMem[offsets[i] - romSize - sramSize];
124  } else {
125  // TODO throw
126  UNREACHABLE;
127  }
128  }
129  } else {
130  for (unsigned i = 0; i < NUM_BANKS; ++i) {
131  if (bank[i] == unmappedRead) {
132  offsets[i] = unsigned(-1);
133  } else if ((&rom[0] <= bank[i]) &&
134  (bank[i] <= &rom[romSize - 1])) {
135  offsets[i] = unsigned(bank[i] - &rom[0]);
136  } else if (sram && (&(*sram)[0] <= bank[i]) &&
137  (bank[i] <= &(*sram)[sramSize - 1])) {
138  offsets[i] = unsigned(bank[i] - &(*sram)[0] + romSize);
139  } else if ((extraMem <= bank[i]) &&
140  (bank[i] <= &extraMem[extraSize - 1])) {
141  offsets[i] = unsigned(bank[i] - extraMem + romSize + sramSize);
142  } else {
143  UNREACHABLE;
144  }
145  }
146  ar.serialize("banks", offsets);
147  }
148 
149  // Commented out because versioning doesn't work correct on subclasses
150  // that don't override the serialize() method (e.g. RomPlain)
151  /*if (ar.versionAtLeast(version, 2)) {
152  ar.serialize("blockNr", blockNr);
153  } else {
154  assert(ar.isLoader());
155  // set dummy value, anyway only used for debuggable
156  for (unsigned i = 0; i < NUM_BANKS; ++i) {
157  blockNr[i] = 255;
158  }
159  }*/
160 }
161 
162 template class RomBlocks<0x1000>;
163 template class RomBlocks<0x2000>;
164 template class RomBlocks<0x4000>;
168 
169 } // namespace openmsx
void setRom(byte region, int block)
Selects a block of the ROM image for reading in a certain region.
Definition: RomBlocks.cc:86
STL namespace.
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading...
Definition: RomBlocks.cc:53
void setBank(byte region, const byte *adr, int block)
Sets the memory visible for reading in a certain region.
Definition: RomBlocks.cc:59
static const unsigned NUM_BANKS
Definition: RomBlocks.hh:17
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: RomBlocks.cc:47
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
unsigned char byte
8 bit unsigned integer
Definition: openmsx.hh:25
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:802
static const unsigned BANK_SIZE
Definition: RomBlocks.hh:16
void setUnmapped(byte region)
Select 'unmapped' memory for this region.
Definition: RomBlocks.cc:73
void serialize(Archive &ar, unsigned version)
Definition: RomBlocks.cc:102
size_t size() const
void setExtraMemory(const byte *mem, unsigned size)
Inform this base class of extra mapable memory block.
Definition: RomBlocks.cc:79
RomBlocks(const DeviceConfig &config, Rom &&rom, unsigned debugBankSizeShift=0)
Constructor.
Definition: RomBlocks.cc:16
unsigned getSize() const
Definition: Rom.hh:32
unsigned short word
16 bit unsigned integer
Definition: openmsx.hh:28
#define UNREACHABLE
Definition: unreachable.hh:35