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 auto sramSize = sram->size();
165 if (offset >= sramSize) {
166 offset &= (sramSize - 1);
167 }
168 // TODO RomBlock debuggable is only 8 bits, here bank is 9 bits
169 setBank(region, &sram->operator[](offset), narrow_cast<byte>(bank));
170 } else if (panasonicMem.getRamSize() && (RAM_BASE <= bank)) {
171 // RAM
172 // TODO RomBlock debuggable is only 8 bits, here bank is 9 bits
173 setBank(region, panasonicMem.getRamBlock(bank - RAM_BASE), narrow_cast<byte>(bank));
174 } else {
175 // ROM
176 setRom(region, bank);
177 }
178 invalidateDeviceWCache(0x2000 * region, 0x2000); // 'R' is already handled
179 if (region == 3) {
180 // don't pre-fill [0x7ff0, 0x7fff]
182 }
183}
184
185template<typename Archive>
186void RomPanasonic::serialize(Archive& ar, unsigned /*version*/)
187{
188 ar.template serializeBase<Rom8kBBlocks>(*this);
189 ar.serialize("bankSelect", bankSelect,
190 "control", control);
191}
194
195} // namespace openmsx
Definition: one_of.hh:7
bool getChildDataAsBool(std::string_view name, bool defaultValue=false) const
Definition: DeviceConfig.cc:61
int getChildDataAsInt(std::string_view name, int defaultValue) const
Definition: DeviceConfig.cc:57
void invalidateDeviceRCache()
Definition: MSXDevice.hh:213
void invalidateDeviceWCache()
Definition: MSXDevice.hh:214
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:305
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.
Definition: RomPanasonic.cc:45
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
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.
Definition: RomPanasonic.cc:93
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: RomPanasonic.cc:83
RomPanasonic(const DeviceConfig &config, Rom &&rom)
Definition: RomPanasonic.cc:18
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: RomPanasonic.cc:78
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: RomPanasonic.cc:55
constexpr unsigned HIGH
Definition: CacheLine.hh:10
constexpr unsigned SIZE
Definition: CacheLine.hh:7
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
const unsigned SRAM_BASE
Definition: RomPanasonic.cc:15
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
const unsigned RAM_BASE
Definition: RomPanasonic.cc:16
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:305
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021
constexpr auto xrange(T e)
Definition: xrange.hh:132