openMSX
NowindInterface.cc
Go to the documentation of this file.
1#include "NowindInterface.hh"
2#include "DiskChanger.hh"
3#include "Clock.hh"
4#include "MSXMotherBoard.hh"
5#include "MSXException.hh"
6#include "narrow.hh"
7#include "serialize.hh"
8#include "serialize_stl.hh"
9#include <cassert>
10#include <functional>
11#include <memory>
12
13namespace openmsx {
14
16 : MSXDevice(config)
17 , rom(getName() + " ROM", "rom", config)
18 , flashConfig(rom.size() / 0x10000, {0x10000, false})
19 , flash(rom, flashConfig, 0x01A4,
21 , host(drives)
22 , basename("nowindX")
23{
24 if ((rom.size() % 0x4000) != 0) {
25 throw MSXException("NowindInterface ROM size must be a multiple of 16kB");
26 }
27 if (rom.size() == 0) {
28 throw MSXException("NowindInterface ROM size cannot be zero");
29 }
30 if (rom.size() > size_t(256 * 0x4000)) {
31 throw MSXException("NowindInterface ROM size cannot be larger than 4MB");
32 }
33
34 nowindsInUse = getMotherBoard().getSharedStuff<NowindsInUse>("nowindsInUse");
35
36 unsigned i = 0;
37 while ((*nowindsInUse)[i]) {
38 if (++i == MAX_NOWINDS) {
39 throw MSXException("Too many nowind interfaces.");
40 }
41 }
42 (*nowindsInUse)[i] = true;
43 basename[6] = char('a' + i);
44
45 command.emplace(basename, getCommandController(), *this);
46
47 // start with one (empty) drive
48 auto drive = command->createDiskChanger(basename, 0, getMotherBoard());
49 drive->createCommand();
50 drives.push_back(std::move(drive));
51
52 reset(EmuTime::dummy());
53}
54
56{
57 unsigned i = basename[6] - 'a';
58 assert((*nowindsInUse)[i]);
59 (*nowindsInUse)[i] = false;
60}
61
62void NowindInterface::reset(EmuTime::param /*time*/)
63{
64 // version 1 didn't change the bank number
65 // version 2 (produced by Sunrise) does reset the bank number
66 bank = 0;
67
68 // Flash state is NOT changed on reset
69 //flash.reset();
70}
71
72byte NowindInterface::peekMem(word address, EmuTime::param /*time*/) const
73{
74 if (((0x2000 <= address) && (address < 0x4000)) ||
75 ((0x8000 <= address) && (address < 0xA000))) {
76 return host.peek();
77 } else if ((0x4000 <= address) && (address < 0xC000)) {
78 // note: range 0x8000-0xA000 is already handled above
79 return flash.peek(bank * 0x4000 + (address & 0x3FFF));
80 } else {
81 return 0xFF;
82 }
83}
84
85byte NowindInterface::readMem(word address, EmuTime::param /*time*/)
86{
87 if (((0x2000 <= address) && (address < 0x4000)) ||
88 ((0x8000 <= address) && (address < 0xA000))) {
89 return host.read();
90 } else if ((0x4000 <= address) && (address < 0xC000)) {
91 // note: range 0x8000-0xA000 is already handled above
92 return flash.read(bank * 0x4000 + (address & 0x3FFF));
93 } else {
94 return 0xFF;
95 }
96}
97
98const byte* NowindInterface::getReadCacheLine(word address) const
99{
100 if (((0x2000 <= address) && (address < 0x4000)) ||
101 ((0x8000 <= address) && (address < 0xA000))) {
102 // nowind region, not cacheable
103 return nullptr;
104 } else if ((0x4000 <= address) && (address < 0xC000)) {
105 // note: range 0x8000-0xA000 is already handled above
106 return flash.getReadCacheLine(bank * 0x4000 + (address & 0x3FFF));
107 } else {
108 return unmappedRead.data();
109 }
110}
111
112void NowindInterface::writeMem(word address, byte value, EmuTime::param time)
113{
114 if (address < 0x4000) {
115 flash.write(bank * 0x4000 + address, value);
116 } else if (((0x4000 <= address) && (address < 0x6000)) ||
117 ((0x8000 <= address) && (address < 0xA000))) {
118 constexpr Clock<1000> clock(EmuTime::zero());
119 host.write(value, clock.getTicksTill(time));
120 } else if (((0x6000 <= address) && (address < 0x8000)) ||
121 ((0xA000 <= address) && (address < 0xC000))) {
122 auto max = narrow<uint8_t>((rom.size() / 0x4000) - 1);
123 bank = (value <= max) ? value : (value & max);
124 invalidateDeviceRCache(0x4000, 0x4000);
125 invalidateDeviceRCache(0xA000, 0x2000);
126 }
127}
128
130{
131 if (address < 0xC000) {
132 // not cacheable
133 return nullptr;
134 } else {
135 return unmappedWrite.data();
136 }
137}
138
139
140template<typename Archive>
141void NowindInterface::serialize(Archive& ar, unsigned /*version*/)
142{
143 ar.template serializeBase<MSXDevice>(*this);
144 ar.serialize("flash", flash);
145 ar.serializeWithID("drives", drives, std::ref(getMotherBoard()));
146 ar.serialize("nowindhost", host,
147 "bank", bank);
148
149 // don't serialize command, rom, basename
150}
153
154} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
void write(size_t address, uint8_t value)
Definition AmdFlash.cc:265
const uint8_t * getReadCacheLine(size_t address) const
Definition AmdFlash.cc:254
uint8_t peek(size_t address) const
Definition AmdFlash.cc:212
uint8_t read(size_t address) const
Definition AmdFlash.cc:248
Represents a clock with a fixed frequency.
Definition Clock.hh:19
constexpr unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
Definition Clock.hh:58
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition MSXDevice.cc:70
void invalidateDeviceRCache()
Definition MSXDevice.hh:215
static std::array< byte, 0x10000 > unmappedRead
Definition MSXDevice.hh:306
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
byte peek() const
Definition NowindHost.cc:54
void write(byte data, unsigned time)
Definition NowindHost.cc:72
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
void reset(EmuTime::param time) override
This method is called on reset.
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
NowindInterface(const DeviceConfig &config)
void serialize(Archive &ar, unsigned version)
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.
auto size() const
Definition Rom.hh:36
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)