gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 4d574948cfea1c3aa6e13c1871175ddacfe6cbda
parent 40ed5bf08ddd88959c2db31d7191fafb88a0d7c7
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Tue,  4 Mar 2025 21:57:08 +0100

rework AM29 flash impl, fixes Xenia stuck in "Reorganising Memory"

Diffstat:
Mdoc/changelog.txt | 1+
Msource/hardwareLib/am29f.cpp | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msource/hardwareLib/am29f.h | 24++++++++++++++++++------
Msource/mqLib/mqmc.h | 2+-
Msource/xtLib/CMakeLists.txt | 1+
Asource/xtLib/xtFlash.cpp | 28++++++++++++++++++++++++++++
Asource/xtLib/xtFlash.h | 18++++++++++++++++++
Msource/xtLib/xtUc.h | 5++---
8 files changed, 137 insertions(+), 39 deletions(-)

diff --git a/doc/changelog.txt b/doc/changelog.txt @@ -12,6 +12,7 @@ Xenia: wavetables - [Fix] Checksum of exported patches was incorrect due to bug in documentation +- [Fix] Emulator might get stuck while "Reorganising Memory" 1.4.3 diff --git a/source/hardwareLib/am29f.cpp b/source/hardwareLib/am29f.cpp @@ -7,7 +7,7 @@ namespace hwLib { - Am29f::Am29f(uint8_t* _buffer, const size_t _size, bool _useWriteEnable, bool _bitreversedCmdAddr): m_buffer(_buffer), m_size(_size), m_useWriteEnable(_useWriteEnable), m_bitreverseCmdAddr(_bitreversedCmdAddr) + Am29f::Am29f(uint8_t* _buffer, const size_t _size, const bool _useWriteEnable, const bool _bitreversedCmdAddr) : m_buffer(_buffer), m_size(_size), m_useWriteEnable(_useWriteEnable), m_bitreverseCmdAddr(_bitreversedCmdAddr) { auto br = [&](uint16_t x) { @@ -78,7 +78,70 @@ namespace hwLib } } - void Am29f::execCommand(const CommandType _command, uint32_t _addr, const uint16_t _data) + bool Am29f::eraseSector(const uint32_t _addr, const size_t _sizeInKb) const + { + if (!_sizeInKb) + return false; + + MCLOG("Erasing Sector at " << MCHEX(_addr) << ", size " << MCHEX(1024 * _sizeInKb)); + + for(size_t i = _addr; i< _addr + _sizeInKb * 1024; ++i) + m_buffer[i] = 0xff; + + return true; + } + + bool Am29f::eraseSector1Mbit(const uint32_t _addr) const + { + switch (_addr) + { + case 0x00000: + case 0x04000: + case 0x08000: + case 0x0C000: + case 0x10000: + case 0x14000: + case 0x18000: + case 0x1C000: return eraseSector(_addr, 16); + default: return false; + } + } + + bool Am29f::eraseSector2MbitTopBoot(const uint32_t _addr) const + { + switch (_addr) + { + case 0x00000: + case 0x10000: + case 0x20000: return eraseSector(_addr, 64); + case 0x30000: return eraseSector(_addr, 32); + case 0x38000: + case 0x3a000: return eraseSector(_addr, 8); + case 0x3c000: return eraseSector(_addr, 16); + default: return false; + } + } + + bool Am29f::eraseSector4MbitTopBoot(const uint32_t _addr) const + { + switch (_addr) + { + case 0x00000: + case 0x10000: + case 0x20000: + case 0x30000: + case 0x40000: + case 0x50000: + case 0x60000: + case 0x70000: return eraseSector(_addr, 64); + case 0x78000: + case 0x7a000: return eraseSector(_addr, 8); + case 0x7c000: return eraseSector(_addr, 16); + default: return false; + } + } + + void Am29f::execCommand(const CommandType _command, uint32_t _addr, const uint16_t _data) const { switch (_command) { @@ -87,35 +150,11 @@ namespace hwLib break; case CommandType::SectorErase: { - size_t sectorSizekB = 0; - switch (_addr) + if (!eraseSector(_addr)) { - case 0x00000: sectorSizekB = 16; break; - case 0x04000: - case 0x06000: sectorSizekB = 8; break; - case 0x08000: sectorSizekB = 32; break; - case 0x10000: - case 0x20000: - case 0x30000: - case 0x40000: - case 0x50000: - case 0x60000: - case 0x70000: sectorSizekB = 64; break; - case 0x78000: - case 0x7A000: - case 0x7C000: - // mq sends erase commands for a flash with top boot block even though a chip with bottom boot block is installed - _addr = 0x70000; - sectorSizekB = 64; - break; - default: - MCLOG("Unable to erase sector at " << MCHEX(_addr) << ", out of bounds!"); - return; + assert(false); + MCLOG("Unable to erase sector at " << MCHEX(_addr) << ", unable to determine sector size!"); } - - MCLOG("Erasing Sector at " << MCHEX(_addr) << ", size " << MCHEX(1024 * sectorSizekB)); - for(size_t i = _addr; i< _addr + sectorSizekB * 1024; ++i) - m_buffer[i] = 0xff; } break; case CommandType::Program: diff --git a/source/hardwareLib/am29f.h b/source/hardwareLib/am29f.h @@ -29,6 +29,7 @@ namespace hwLib }; explicit Am29f(uint8_t* _buffer, size_t _size, bool _useWriteEnable, bool _bitreversedCmdAddr); + virtual ~Am29f() = default; void writeEnable(bool _writeEnable) { @@ -37,22 +38,33 @@ namespace hwLib void write(uint32_t _addr, uint16_t _data); + bool eraseSector(uint32_t _addr, size_t _sizeInKb) const; + + virtual bool eraseSector(const uint32_t _addr) const + { + return eraseSector4MbitTopBoot(_addr); + } + + bool eraseSector1Mbit(uint32_t _addr) const; + bool eraseSector2MbitTopBoot(uint32_t _addr) const; + bool eraseSector4MbitTopBoot(uint32_t _addr) const; + private: bool writeEnabled() const { return !m_useWriteEnable || m_writeEnable; } - static constexpr uint16_t bitreverse(uint16_t x) + static constexpr uint16_t bitreverse(uint16_t _x) { - x = ((x & 0xaaaau) >> 1) | static_cast<uint16_t>((x & 0x5555u) << 1); - x = ((x & 0xccccu) >> 2) | static_cast<uint16_t>((x & 0x3333u) << 2); - x = ((x & 0xf0f0u) >> 4) | static_cast<uint16_t>((x & 0x0f0fu) << 4); + _x = ((_x & 0xaaaau) >> 1) | static_cast<uint16_t>((_x & 0x5555u) << 1); + _x = ((_x & 0xccccu) >> 2) | static_cast<uint16_t>((_x & 0x3333u) << 2); + _x = ((_x & 0xf0f0u) >> 4) | static_cast<uint16_t>((_x & 0x0f0fu) << 4); - return ((x & 0xff00) >> 8) | static_cast<uint16_t>((x & 0x00ff) << 8); + return ((_x & 0xff00) >> 8) | static_cast<uint16_t>((_x & 0x00ff) << 8); } - void execCommand(CommandType _command, uint32_t _addr, uint16_t _data); + void execCommand(CommandType _command, uint32_t _addr, uint16_t _data) const; uint8_t* m_buffer; const size_t m_size; diff --git a/source/mqLib/mqmc.h b/source/mqLib/mqmc.h @@ -67,7 +67,7 @@ namespace mqLib const ROM& m_rom; std::vector<uint8_t> m_romRuntimeData; - std::unique_ptr<hwLib::Am29f> m_flash; + std::unique_ptr<hwLib::Am29f> m_flash; // Its a MX 29F400TTC-70 which is a 4MBit (512kx8) AM29 compatible flash with top boot block LCD m_lcd; Buttons m_buttons; Leds m_leds; diff --git a/source/xtLib/CMakeLists.txt b/source/xtLib/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES xtButtons.cpp xtButtons.h xtDevice.cpp xtDevice.h xtDSP.cpp xtDSP.h + xtFlash.cpp xtFlash.h xtHardware.cpp xtHardware.h xtId.cpp xtId.h xtLcd.cpp xtLcd.h diff --git a/source/xtLib/xtFlash.cpp b/source/xtLib/xtFlash.cpp @@ -0,0 +1,28 @@ +#include "xtFlash.h" + +#include <cassert> + +namespace xt +{ + Flash::Flash(uint8_t* _buffer, const size_t _size, const bool _useWriteEnable, const bool _bitreversedCmdAddr) : hwLib::Am29f(_buffer, _size, _useWriteEnable, _bitreversedCmdAddr) + { + } + + bool Flash::eraseSector(const uint32_t _addr) const + { + switch (_addr) + { + case 0x00000*2: + case 0x04000*2: + case 0x08000*2: + case 0x0C000*2: + case 0x10000*2: + case 0x14000*2: + case 0x18000*2: + case 0x1C000*2: return Am29f::eraseSector(_addr, 32); + default: + assert(false); + return false; + } + } +} diff --git a/source/xtLib/xtFlash.h b/source/xtLib/xtFlash.h @@ -0,0 +1,18 @@ +#pragma once + +#include "hardwareLib/am29f.h" + +namespace xt +{ + // XT uses two times AM29F010 which is 128k * 8. + // However, they are connected in interleaved mode, forming one 256k * 8 + // For this to work, we invent a 2mbit flash without boot block that can do sector erases in 16k blocks as + // that is what is used in the XT + class Flash final : public hwLib::Am29f + { + public: + explicit Flash(uint8_t* _buffer, size_t _size, bool _useWriteEnable, bool _bitreversedCmdAddr); + + bool eraseSector(uint32_t _addr) const override; + }; +} diff --git a/source/xtLib/xtUc.h b/source/xtLib/xtUc.h @@ -1,6 +1,7 @@ #pragma once #include "xtButtons.h" +#include "xtFlash.h" #include "xtLcd.h" #include "xtLeds.h" #include "xtPic.h" @@ -9,8 +10,6 @@ #include "mc68k/mc68k.h" #include "mc68k/hdi08periph.h" -#include "hardwareLib/am29f.h" - namespace xt { class Rom; @@ -51,7 +50,7 @@ namespace xt std::array<uint8_t, g_romSize> m_romRuntimeData; xtHdi08A m_hdiA; - hwLib::Am29f m_flash; // Its a MX 29F400TTC-70 which is a 4MBit (512kx8) AM29 compatible flash with top boot block + Flash m_flash; Pic m_pic; Lcd m_lcd;