openMSX
AmdFlash.hh
Go to the documentation of this file.
1#ifndef AMDFLASH_HH
2#define AMDFLASH_HH
3
4#include "serialize_meta.hh"
5
6#include "cstd.hh"
7#include "narrow.hh"
8#include "power_of_two.hh"
9#include "ranges.hh"
10#include "static_vector.hh"
11
12#include <cstddef>
13#include <cstdint>
14#include <memory>
15#include <span>
16#include <vector>
17
18namespace openmsx {
19
20class MSXMotherBoard;
21class Rom;
22class SRAM;
23class DeviceConfig;
24
26{
27public:
28 // See JEDEC JEP106 https://www.jedec.org/standards-documents/docs/jep-106ab
29 enum class ManufacturerID : uint8_t {
30 AMD = 0x01,
31 STM = 0x20,
32 };
33
34 struct AutoSelect {
36 static_vector<uint8_t, 2> device; // single-byte or double-byte (0x7E prefix)
37 uint16_t extraCode = 0x0000; // code at 3rd index
38 uint16_t undefined = 0xFFFF; // undefined values
39 bool oddZero : 1 = false; // odd bytes are zero, not mirrored
40 size_t readMask = 0x03; // read address mask
41
42 constexpr void validate() const {
43 // check parity
44 assert(std::popcount(to_underlying(manufacturer)) & 1);
45 // extended marker is not part of ID
46 assert(device.size() > 0 && device[0] != 0x7E);
47 }
48 };
49
50 enum class DeviceInterface : uint16_t {
51 x8 = 0x0000,
52 x8x16 = 0x0002,
53 };
54
55 struct Region {
56 size_t count = 0;
58 };
59
60 struct Geometry {
61 constexpr Geometry(DeviceInterface deviceInterface_, std::initializer_list<Region> regions_,
62 int writeProtectPinRange_ = 0)
63 : deviceInterface(deviceInterface_)
64 , regions(regions_)
65 , writeProtectPinRange(writeProtectPinRange_)
66 , size(sum(regions, [](Region r) { return r.count * r.size; }))
67 // Originally sum(regions, &Region::count), but seems to mis-compile to 0 on MSVC.
68 // It looks like sum with projection doesn’t work at compile-time in MSVC 2022?
69 // https://developercommunity.visualstudio.com/t/wrong-code-bug-in-constexpr-evaluation/10673004
70 , sectorCount(sum(regions, [](Region r) { return r.count; })) {}
73 int writeProtectPinRange; // sectors protected by WP#, negative: from top
76
77 constexpr void validate() const {
78 assert(ranges::all_of(regions, [](const auto& region) { return region.count > 0; }));
79 assert(narrow_cast<unsigned>(cstd::abs(writeProtectPinRange)) <= sectorCount);
80 }
81 };
82
83 struct Program {
84 bool fastCommand : 1 = false;
85 bool bufferCommand : 1 = false;
86 bool shortAbortReset : 1 = false;
88
89 constexpr void validate() const {
90 assert(!fastCommand || pageSize > 1);
91 assert(!bufferCommand || pageSize > 1);
93 }
94 };
95
96 struct CFI {
97 bool command : 1 = false;
98 bool withManufacturerDevice : 1 = false; // < 0x10 contains mfr / device
99 bool withAutoSelect : 1 = false; // < 0x10 contains autoselect
100 bool exitCommand : 1 = false; // also exit by writing 0xFF
101 size_t commandMask = 0xFF; // command address mask
102 size_t readMask = 0x7F; // read address mask
124 struct Version {
125 uint8_t major = 0;
126 uint8_t minor = 0;
127 } version = {};
128 uint8_t addressSensitiveUnlock : 2 = 0;
129 uint8_t siliconRevision : 6 = 0;
130 uint8_t eraseSuspend = 0;
131 uint8_t sectorProtect = 0;
135 uint8_t burstMode = 0;
136 uint8_t pageMode = 0;
137 struct Supply {
138 uint8_t minAcc = 0;
139 uint8_t maxAcc = 0;
140 } supply = {};
141 uint8_t bootBlockFlag = 0;
142 uint8_t programSuspend = 0;
144
145 constexpr void validate() const {
146 assert(!command || primaryAlgorithm.version.major == 1);
147 }
148 };
149
150 struct Misc {
151 bool statusCommand : 1 = false;
152 bool continuityCommand : 1 = false;
153
154 constexpr void validate() const {
156 }
157 };
158
159 struct Chip {
163 CFI cfi = {};
164 Misc misc = {};
165
166 constexpr void validate() const {
170 cfi.validate();
171 misc.validate();
172 }
173 };
174
176 constexpr ValidatedChip(const Chip& chip_) : chip(chip_) {
177 chip.validate();
178 }
179 const Chip chip;
180 };
181
197 AmdFlash(const Rom& rom, const ValidatedChip& chip,
198 std::span<const bool> writeProtectSectors,
199 const DeviceConfig& config);
200 AmdFlash(const std::string& name, const ValidatedChip& chip,
201 std::span<const bool> writeProtectSectors,
202 const DeviceConfig& config);
204
205 void reset();
212 void setVppWpPinLow(bool value) { vppWpPinLow = value; }
213
214 [[nodiscard]] power_of_two<size_t> size() const { return chip.geometry.size; }
215 [[nodiscard]] uint8_t read(size_t address);
216 [[nodiscard]] uint8_t peek(size_t address) const;
217 void write(size_t address, uint8_t value);
218 [[nodiscard]] const uint8_t* getReadCacheLine(size_t address) const;
219
220 template<typename Archive>
221 void serialize(Archive& ar, unsigned version);
222
223//private:
225 size_t addr;
226 uint8_t value;
227
228 auto operator<=>(const AddressValue&) const = default;
229
230 template<typename Archive>
231 void serialize(Archive& ar, unsigned version);
232 };
233
234 enum class State { IDLE, IDENT, CFI, STATUS, PRGERR };
235
236 struct Sector {
237 size_t address;
240 ptrdiff_t writeAddress = -1;
241 const uint8_t* readAddress = nullptr;
242
243 std::weak_ordering operator<=>(const Sector& sector) const { return address <=> sector.address; }
244 bool operator==(const Sector& sector) const { return address == sector.address; }
245 };
246
247private:
248 AmdFlash(const std::string& name, const ValidatedChip& chip,
249 const Rom* rom, std::span<const bool> writeProtectSectors,
250 const DeviceConfig& config);
251
252 [[nodiscard]] size_t getSectorIndex(size_t address) const;
253 [[nodiscard]] Sector& getSector(size_t address) { return sectors[getSectorIndex(address)]; };
254 [[nodiscard]] const Sector& getSector(size_t address) const { return sectors[getSectorIndex(address)]; };
255
256 void softReset();
257 [[nodiscard]] uint16_t peekAutoSelect(size_t address, uint16_t undefined = 0xFFFF) const;
258 [[nodiscard]] uint16_t peekCFI(size_t address) const;
259
260 void setState(State newState);
261 [[nodiscard]] bool checkCommandReset();
262 [[nodiscard]] bool checkCommandLongReset();
263 [[nodiscard]] bool checkCommandCFIQuery();
264 [[nodiscard]] bool checkCommandCFIExit();
265 [[nodiscard]] bool checkCommandStatusRead();
266 [[nodiscard]] bool checkCommandStatusClear();
267 [[nodiscard]] bool checkCommandEraseSector();
268 [[nodiscard]] bool checkCommandEraseChip();
269 [[nodiscard]] bool checkCommandProgramHelper(size_t numBytes, std::span<const uint8_t> cmdSeq);
270 [[nodiscard]] bool checkCommandProgram();
271 [[nodiscard]] bool checkCommandDoubleByteProgram();
272 [[nodiscard]] bool checkCommandQuadrupleByteProgram();
273 [[nodiscard]] bool checkCommandBufferProgram();
274 [[nodiscard]] bool checkCommandAutoSelect();
275 [[nodiscard]] bool checkCommandContinuityCheck();
276 [[nodiscard]] bool partialMatch(std::span<const uint8_t> dataSeq) const;
277
278 [[nodiscard]] bool isWritable(const Sector& sector) const;
279
280public:
281 static constexpr unsigned MAX_CMD_SIZE = 5 + 256; // longest command is BufferProgram
282
283private:
284 MSXMotherBoard& motherBoard;
285 std::unique_ptr<SRAM> ram;
286 const Chip& chip;
287 std::vector<Sector> sectors;
289 State state = State::IDLE;
290 uint8_t status = 0x80;
291 bool vppWpPinLow = false; // true = protection on
292};
294
295namespace AmdFlashChip
296{
298 using enum AmdFlash::ManufacturerID;
300
301 // AMD AM29F040
302 static constexpr ValidatedChip AM29F040 = {{
303 .autoSelect{.manufacturer = AMD, .device{0xA4}, .extraCode = 0x01},
304 .geometry{DeviceInterface::x8, {{8, 0x10000}}},
305 }};
306
307 // AMD AM29F016
308 static constexpr ValidatedChip AM29F016 = {{
309 .autoSelect{.manufacturer = AMD, .device{0xAD}},
310 .geometry{DeviceInterface::x8, {{32, 0x10000}}},
311 }};
312
313 // Numonyx M29W800DB
314 static constexpr ValidatedChip M29W800DB = {{
315 .autoSelect{.manufacturer = STM, .device{0x5B}},
316 .geometry{DeviceInterface::x8x16, {{1, 0x4000}, {2, 0x2000}, {1, 0x8000}, {15, 0x10000}}},
317 .cfi{
318 .command = true,
319 .systemInterface{{0x27, 0x36, 0x00, 0x00}, {16, 1, 1024, 1}, {16, 1, 8, 1}},
320 .primaryAlgorithm{{1, 0}, 0, 0, 2, 1, 1, 4, 0, 0, 0},
321 },
322 }};
323
324 // Micron M29W640GB
325 static constexpr ValidatedChip M29W640GB = {{
326 .autoSelect{.manufacturer = STM, .device{0x10, 0x00}, .extraCode = 0x0008, .undefined = 0, .oddZero = true, .readMask = 0x7F},
327 .geometry{DeviceInterface::x8x16, {{8, 0x2000}, {127, 0x10000}}, 2},
328 .program{.fastCommand = true, .bufferCommand = true, .shortAbortReset = true, .pageSize = 32},
329 .cfi{
330 .command = true, .withManufacturerDevice = true, .commandMask = 0xFFF, .readMask = 0xFF,
331 .systemInterface{{0x27, 0x36, 0xB5, 0xC5}, {16, 1, 1024, 1}, {16, 1, 8, 1}},
332 .primaryAlgorithm{{1, 3}, 0, 0, 2, 4, 1, 4, 0, 0, 1, {0xB5, 0xC5}, 0x02, 1},
333 },
334 }};
335
336 // Infineon / Cypress / Spansion S29GL064S70TFI040
337 static constexpr ValidatedChip S29GL064S70TFI040 = {{
338 .autoSelect{.manufacturer = AMD, .device{0x10, 0x00}, .extraCode = 0xFF0A, .readMask = 0x0F},
339 .geometry{DeviceInterface::x8x16, {{8, 0x2000}, {127, 0x10000}}, 2},
340 .program{.bufferCommand = true, .pageSize = 256},
341 .cfi{
342 .command = true, .withAutoSelect = true, .exitCommand = true, .commandMask = 0xFF, .readMask = 0x7F,
343 .systemInterface{{0x27, 0x36, 0x00, 0x00}, {256, 256, 512, 65536}, {8, 8, 2, 1}},
344 .primaryAlgorithm{{1, 3}, 0, 8, 2, 1, 0, 8, 0, 0, 2, {0xB5, 0xC5}, 0x02, 1},
345 },
346 .misc {.statusCommand = true, .continuityCommand = true},
347 }};
348}
349
350} // namespace openmsx
351
352#endif
static constexpr unsigned MAX_CMD_SIZE
Definition AmdFlash.hh:281
void write(size_t address, uint8_t value)
Definition AmdFlash.cc:456
void serialize(Archive &ar, unsigned version)
Definition AmdFlash.cc:740
const uint8_t * getReadCacheLine(size_t address) const
Definition AmdFlash.cc:444
void setVppWpPinLow(bool value)
Setting the Vpp/WP# pin LOW enables a certain kind of write protection of some sectors.
Definition AmdFlash.hh:212
uint8_t read(size_t address)
Definition AmdFlash.cc:432
power_of_two< size_t > size() const
Definition AmdFlash.hh:214
uint8_t peek(size_t address) const
Definition AmdFlash.cc:186
constexpr size_t size() const noexcept
constexpr T abs(T t)
Definition cstd.hh:17
AmdFlash::ValidatedChip ValidatedChip
Definition AmdFlash.hh:297
This file implemented 3 utility functions:
Definition Autofire.cc:11
constexpr bool all_of(InputRange &&range, UnaryPredicate pred)
Definition ranges.hh:188
#define SERIALIZE_CLASS_VERSION(CLASS, VERSION)
constexpr auto sum(InputRange &&range, Proj proj={})
Definition stl.hh:245
constexpr auto to_underlying(E e) noexcept
Definition stl.hh:465
void serialize(Archive &ar, unsigned version)
Definition AmdFlash.cc:730
auto operator<=>(const AddressValue &) const =default
ManufacturerID manufacturer
Definition AmdFlash.hh:35
constexpr void validate() const
Definition AmdFlash.hh:42
static_vector< uint8_t, 2 > device
Definition AmdFlash.hh:36
struct openmsx::AmdFlash::CFI::PrimaryAlgorithm::Supply supply
struct openmsx::AmdFlash::CFI::PrimaryAlgorithm::Version version
struct openmsx::AmdFlash::CFI::SystemInterface::Supply supply
struct openmsx::AmdFlash::CFI::SystemInterface::MaxTimeoutMultiplier maxTimeoutMult
struct openmsx::AmdFlash::CFI::SystemInterface::TypicalTimeout typTimeout
struct openmsx::AmdFlash::CFI::SystemInterface systemInterface
struct openmsx::AmdFlash::CFI::PrimaryAlgorithm primaryAlgorithm
constexpr void validate() const
Definition AmdFlash.hh:145
constexpr void validate() const
Definition AmdFlash.hh:166
constexpr Geometry(DeviceInterface deviceInterface_, std::initializer_list< Region > regions_, int writeProtectPinRange_=0)
Definition AmdFlash.hh:61
static_vector< Region, 4 > regions
Definition AmdFlash.hh:72
DeviceInterface deviceInterface
Definition AmdFlash.hh:71
constexpr void validate() const
Definition AmdFlash.hh:77
power_of_two< size_t > size
Definition AmdFlash.hh:74
constexpr void validate() const
Definition AmdFlash.hh:154
constexpr void validate() const
Definition AmdFlash.hh:89
power_of_two< size_t > pageSize
Definition AmdFlash.hh:87
power_of_two< size_t > size
Definition AmdFlash.hh:57
power_of_two< size_t > size
Definition AmdFlash.hh:238
std::weak_ordering operator<=>(const Sector &sector) const
Definition AmdFlash.hh:243
bool operator==(const Sector &sector) const
Definition AmdFlash.hh:244
const uint8_t * readAddress
Definition AmdFlash.hh:241
constexpr ValidatedChip(const Chip &chip_)
Definition AmdFlash.hh:176
A constexpr power_of_two struct for power of two numbers, with compact storage and built-in value cor...