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:
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;