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