openMSX
RomPanasonic.cc
Go to the documentation of this file.
1#include "RomPanasonic.hh"
2#include "PanasonicMemory.hh"
3#include "MSXMotherBoard.hh"
4#include "DeviceConfig.hh"
5#include "SRAM.hh"
6#include "CacheLine.hh"
7#include "one_of.hh"
8#include "ranges.hh"
9#include "serialize.hh"
10#include "xrange.hh"
11#include <memory>
12
13namespace openmsx {
14
15const unsigned SRAM_BASE = 0x80;
16const unsigned RAM_BASE = 0x180;
17
19 : Rom8kBBlocks(config, std::move(rom_))
20 , panasonicMem(getMotherBoard().getPanasonicMemory())
21{
22 unsigned sramSize = config.getChildDataAsInt("sramsize", 0);
23 if (sramSize) {
24 sram = std::make_unique<SRAM>(
25 getName() + " SRAM", sramSize * 1024, config);
26 }
27
28 if (config.getChildDataAsBool("sram-mirrored", false)) {
29 maxSRAMBank = SRAM_BASE + 8;
30 } else {
31 maxSRAMBank = SRAM_BASE + (sramSize / 8);
32 }
33
34 // Inform base class about PanasonicMemory (needed for serialization).
35 // This relies on the order of MSXDevice instantiation, the PanasonicRam
36 // device must be create before this one. (In the hardwareconfig.xml
37 // we added a device-reference from this device to the PanasonicRam
38 // device, this should protected against wrong future edits in the
39 // config file).
40 setExtraMemory({panasonicMem.getRamBlock(0), panasonicMem.getRamSize()});
41
42 reset(EmuTime::dummy());
43}
44
45void RomPanasonic::reset(EmuTime::param /*time*/)
46{
47 control = 0;
48 ranges::fill(bankSelect, 0);
49 for (auto region : xrange(8)) {
50 setRom(region, 0);
51 }
53}
54
55byte RomPanasonic::peekMem(word address, EmuTime::param time) const
56{
57 if ((control & 0x04) && (0x7FF0 <= address) && (address < 0x7FF8)) {
58 // read mapper state (lower 8 bit)
59 return bankSelect[address & 7] & 0xFF;
60 } else if ((control & 0x10) && (address == 0x7FF8)) {
61 // read mapper state (9th bit)
62 byte result = 0;
63 for (int i = 7; i >= 0; i--) {
64 result <<= 1;
65 if (bankSelect[i] & 0x100) {
66 result++;
67 }
68 }
69 return result;
70 } else if ((control & 0x08) && (address == 0x7FF9)) {
71 // read control byte
72 return control;
73 } else {
74 return Rom8kBBlocks::peekMem(address, time);
75 }
76}
77
78byte RomPanasonic::readMem(word address, EmuTime::param time)
79{
80 return RomPanasonic::peekMem(address, time);
81}
82
83const byte* RomPanasonic::getReadCacheLine(word address) const
84{
85 if ((0x7FF0 & CacheLine::HIGH) == address) {
86 // TODO check mirrored
87 return nullptr;
88 } else {
89 return Rom8kBBlocks::getReadCacheLine(address);
90 }
91}
92
93void RomPanasonic::writeMem(word address, byte value, EmuTime::param /*time*/)
94{
95 if ((0x6000 <= address) && (address < 0x7FF0)) {
96 // set mapper state (lower 8 bits)
97 auto region = (address & 0x1C00) >> 10;
98 if (region == one_of(5, 6)) region ^= 3;
99 auto selectedBank = bankSelect[region];
100 auto newBank = (selectedBank & ~0xFF) | value;
101 changeBank(region, newBank);
102 } else if (address == 0x7FF8) {
103 // set mapper state (9th bit)
104 for (auto region : xrange(8)) {
105 if (value & 1) {
106 changeBank(region, bankSelect[region] | 0x100);
107 } else {
108 changeBank(region, bankSelect[region] & ~0x100);
109 }
110 value >>= 1;
111 }
112 } else if (address == 0x7FF9) {
113 // write control byte
114 control = value;
115 } else {
116 // Tested on real FS-A1GT:
117 // SRAM/RAM can be written to from all regions, including e.g.
118 // address 0x7ff0. (I didn't actually test 0xc000-0xffff).
119 auto region = address >> 13;
120 auto selectedBank = bankSelect[region];
121 if (sram && (SRAM_BASE <= selectedBank) &&
122 (selectedBank < maxSRAMBank)) {
123 // SRAM
124 auto block = selectedBank - SRAM_BASE;
125 sram->write((block * 0x2000) | (address & 0x1FFF), value);
126 } else if (RAM_BASE <= selectedBank) {
127 // RAM
128 const_cast<byte*>(bankPtr[region])[address & 0x1FFF] = value;
129 }
130 }
131}
132
134{
135 if ((0x6000 <= address) && (address < 0x8000)) {
136 // mapper select (low/high), control
137 return nullptr;
138 } else {
139 auto region = address >> 13;
140 auto selectedBank = bankSelect[region];
141 if (sram && (SRAM_BASE <= selectedBank) &&
142 (selectedBank < maxSRAMBank)) {
143 // SRAM
144 return nullptr;
145 } else if (RAM_BASE <= selectedBank) {
146 // RAM
147 return const_cast<byte*>(&bankPtr[region][address & 0x1FFF]);
148 } else {
149 return unmappedWrite.data();
150 }
151 }
152}
153
154void RomPanasonic::changeBank(unsigned region, unsigned bank)
155{
156 if (bank == bankSelect[region]) {
157 return;
158 }
159 bankSelect[region] = bank;
160
161 if (sram && (SRAM_BASE <= bank) && (bank < maxSRAMBank)) {
162 // SRAM
163 auto offset = (bank - SRAM_BASE) * size_t(0x2000);
164 if (auto sramSize = sram->size(); offset >= sramSize) {
165 offset &= (sramSize - 1);
166 }
167 // TODO RomBlock debuggable is only 8 bits, here bank is 9 bits
168 setBank(region, &sram->operator[](offset), narrow_cast<byte>(bank));
169 } else if (panasonicMem.getRamSize() && (RAM_BASE <= bank)) {
170 // RAM
171 // TODO RomBlock debuggable is only 8 bits, here bank is 9 bits
172 setBank(region, panasonicMem.getRamBlock(bank - RAM_BASE), narrow_cast<byte>(bank));
173 } else {
174 // ROM
175 setRom(region, bank);
176 }
177 invalidateDeviceWCache(0x2000 * region, 0x2000); // 'R' is already handled
178 if (region == 3) {
179 // don't pre-fill [0x7ff0, 0x7fff]
181 }
182}
183
184template<typename Archive>
185void RomPanasonic::serialize(Archive& ar, unsigned /*version*/)
186{
187 ar.template serializeBase<Rom8kBBlocks>(*this);
188 ar.serialize("bankSelect", bankSelect,
189 "control", control);
190}
193
194} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
bool getChildDataAsBool(std::string_view name, bool defaultValue=false) const
int getChildDataAsInt(std::string_view name, int defaultValue) const
void invalidateDeviceRCache()
Definition MSXDevice.hh:215
void invalidateDeviceWCache()
Definition MSXDevice.hh:216
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition MSXDevice.cc:375
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
unsigned getRamSize() const
byte * getRamBlock(unsigned block)
Note that this is always unchecked RAM! There is no UMR detection when accessing Ram in DRAM mode or ...
void setBank(unsigned region, const byte *adr, byte block)
Sets the memory visible for reading in a certain region.
Definition RomBlocks.cc:78
void setExtraMemory(std::span< const byte > mem)
Inform this base class of extra mappable memory block.
Definition RomBlocks.cc:98
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition RomBlocks.cc:60
std::unique_ptr< SRAM > sram
Definition RomBlocks.hh:85
void setRom(unsigned region, unsigned block)
Selects a block of the ROM image for reading in a certain region.
Definition RomBlocks.cc:104
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition RomBlocks.cc:72
std::array< const byte *, NUM_BANKS > bankPtr
Definition RomBlocks.hh:84
void serialize(Archive &ar, unsigned version)
void reset(EmuTime::param time) override
This method is called on reset.
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
RomPanasonic(const DeviceConfig &config, Rom &&rom)
byte * getWriteCacheLine(word address) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
constexpr unsigned HIGH
Definition CacheLine.hh:10
constexpr unsigned SIZE
Definition CacheLine.hh:7
This file implemented 3 utility functions:
Definition Autofire.cc:11
const unsigned SRAM_BASE
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
const unsigned RAM_BASE
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:315
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)
Definition xrange.hh:132