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