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  extraMem = mem;
85  extraSize = size;
86 }
87 
88 template <unsigned BANK_SIZE>
89 void RomBlocks<BANK_SIZE>::setRom(byte region, int block)
90 {
91  // Note: Some cartridges have a number of blocks that is not a power of 2,
92  // for those we have to make an exception for "block < nrBlocks".
93  block = (block < nrBlocks) ? block : block & blockMask;
94  if (block < nrBlocks) {
95  setBank(region, &(*rom)[block * BANK_SIZE], block);
96  } else {
97  setBank(region, unmappedRead, 255);
98  }
99 }
100 
101 // version 1: initial version
102 // version 2: added blockNr
103 template <unsigned BANK_SIZE>
104 template<typename Archive>
105 void RomBlocks<BANK_SIZE>::serialize(Archive& ar, unsigned /*version*/)
106 {
107  // skip MSXRom base class
108  ar.template serializeBase<MSXDevice>(*this);
109 
110  if (sram) ar.serialize("sram", *sram);
111 
112  unsigned offsets[NUM_BANKS];
113  unsigned romSize = rom->getSize();
114  unsigned sramSize = sram ? sram->getSize() : 0;
115  if (ar.isLoader()) {
116  ar.serialize("banks", offsets);
117  for (unsigned i = 0; i < NUM_BANKS; ++i) {
118  if (offsets[i] == unsigned(-1)) {
119  bank[i] = unmappedRead;
120  } else if (offsets[i] < romSize) {
121  bank[i] = &(*rom)[offsets[i]];
122  } else if (offsets[i] < (romSize + sramSize)) {
123  assert(sram);
124  bank[i] = &(*sram)[offsets[i] - romSize];
125  } else if (offsets[i] < (romSize + sramSize + extraSize)) {
126  bank[i] = &extraMem[offsets[i] - romSize - sramSize];
127  } else {
128  // TODO throw
129  UNREACHABLE;
130  }
131  }
132  } else {
133  for (unsigned i = 0; i < NUM_BANKS; ++i) {
134  if (bank[i] == unmappedRead) {
135  offsets[i] = unsigned(-1);
136  } else if ((&(*rom)[0] <= bank[i]) &&
137  (bank[i] <= &(*rom)[romSize - 1])) {
138  offsets[i] = unsigned(bank[i] - &(*rom)[0]);
139  } else if (sram && (&(*sram)[0] <= bank[i]) &&
140  (bank[i] <= &(*sram)[sramSize - 1])) {
141  offsets[i] = unsigned(bank[i] - &(*sram)[0] + romSize);
142  } else if ((extraMem <= bank[i]) &&
143  (bank[i] <= &extraMem[extraSize - 1])) {
144  offsets[i] = unsigned(bank[i] - extraMem + romSize + sramSize);
145  } else {
146  UNREACHABLE;
147  }
148  }
149  ar.serialize("banks", offsets);
150  }
151 
152  // Commented out because versioning doesn't work correct on subclasses
153  // that don't override the serialize() method (e.g. RomPlain)
154  /*if (ar.versionAtLeast(version, 2)) {
155  ar.serialize("blockNr", blockNr);
156  } else {
157  assert(ar.isLoader());
158  // set dummy value, anyway only used for debuggable
159  for (unsigned i = 0; i < NUM_BANKS; ++i) {
160  blockNr[i] = 255;
161  }
162  }*/
163 }
164 
165 template class RomBlocks<0x1000>;
166 template class RomBlocks<0x2000>;
167 template class RomBlocks<0x4000>;
171 
172 } // namespace openmsx
void setRom(byte region, int block)
Selects a block of the ROM image for reading in a certain region.
Definition: RomBlocks.cc:89
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
#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:105
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:82
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