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

am29f.cpp (4008B)


      1 #include "am29f.h"
      2 
      3 #include <cassert>
      4 
      5 #include "mc68k/logging.h"
      6 #include "mc68k/mc68k.h"
      7 
      8 namespace hwLib
      9 {
     10 	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)
     11 	{
     12 		auto br = [&](uint16_t x)
     13 		{
     14 			return m_bitreverseCmdAddr ? static_cast<uint16_t>(bitreverse(x) >> 4) : x;
     15 		};
     16 
     17 		// Chip Erase
     18 		m_commands.push_back({{{br(0x555),0xAA}, {br(0x2AA),0x55}, {br(0x555),0x80}, {br(0x555),0xAA}, {br(0x2AA),0x55}, {br(0x555),0x10}}});
     19 
     20 		// Sector Erase
     21 		m_commands.push_back({{{br(0x555),0xAA}, {br(0x2AA),0x55}, {br(0x555),0x80}, {br(0x555),0xAA}, {br(0x2AA),0x55}}});
     22 
     23 		// Program
     24 		m_commands.push_back({{{br(0x555),0xAA}, {br(0x2AA),0x55}, {br(0x555),0xA0}}});
     25 	}
     26 
     27 	void Am29f::write(const uint32_t _addr, const uint16_t _data)
     28 	{
     29 		const auto reset = [this]()
     30 		{
     31 			m_currentBusCycle = 0;
     32 			m_currentCommand = -1;
     33 		};
     34 
     35 		if(!writeEnabled())
     36 		{
     37 			reset();
     38 			return;
     39 		}
     40 
     41 		bool anyMatch = false;
     42 
     43 		const auto d = _data & 0xff;
     44 		const auto a = _addr & 0xfff;
     45 		
     46 		for (size_t i=0; i<m_commands.size(); ++i)
     47 		{
     48 			auto& cycles = m_commands[i].cycles;
     49 
     50 			if(m_currentBusCycle < cycles.size())
     51 			{
     52 				const auto& c = cycles[m_currentBusCycle];
     53 
     54 				if(c.addr == a && c.data == d)
     55 				{
     56 					anyMatch = true;
     57 
     58 					if(m_currentBusCycle == cycles.size() - 1)
     59 						m_currentCommand = static_cast<int32_t>(i);
     60 				}
     61 			}
     62 		}
     63 
     64 		if(!anyMatch)
     65 		{
     66 			if(m_currentCommand >= 0)
     67 			{
     68 				const auto c = static_cast<CommandType>(m_currentCommand);
     69 
     70 				execCommand(c, _addr, _data);
     71 			}
     72 
     73 			reset();
     74 		}
     75 		else
     76 		{
     77 			++m_currentBusCycle;
     78 		}
     79 	}
     80 
     81 	bool Am29f::eraseSector(const uint32_t _addr, const size_t _sizeInKb) const
     82 	{
     83 		if (!_sizeInKb)
     84 			return false;
     85 
     86 		MCLOG("Erasing Sector at " << MCHEX(_addr) << ", size " << MCHEX(1024 * _sizeInKb));
     87 
     88 		for(size_t i = _addr; i< _addr + _sizeInKb * 1024; ++i)
     89 			m_buffer[i] = 0xff;
     90 
     91 		return true;
     92 	}
     93 
     94 	bool Am29f::eraseSector1Mbit(const uint32_t _addr) const
     95 	{
     96 		switch (_addr)
     97 		{
     98 			case 0x00000:
     99 			case 0x04000:
    100 			case 0x08000:
    101 			case 0x0C000:
    102 			case 0x10000:
    103 			case 0x14000:
    104 			case 0x18000:
    105 			case 0x1C000:	return eraseSector(_addr, 16);
    106 			default:		return false;
    107 		}
    108 	}
    109 
    110 	bool Am29f::eraseSector2MbitTopBoot(const uint32_t _addr) const
    111 	{
    112 		switch (_addr)
    113 		{
    114 			case 0x00000:
    115 			case 0x10000:
    116 			case 0x20000:	return eraseSector(_addr, 64);
    117 			case 0x30000:	return eraseSector(_addr, 32);
    118 			case 0x38000:
    119 			case 0x3a000:	return eraseSector(_addr, 8);
    120 			case 0x3c000:	return eraseSector(_addr, 16);
    121 			default:		return false;
    122 		}
    123 	}
    124 
    125 	bool Am29f::eraseSector4MbitTopBoot(const uint32_t _addr) const
    126 	{
    127 		switch (_addr)
    128 		{
    129 			case 0x00000:
    130 			case 0x10000:
    131 			case 0x20000:
    132 			case 0x30000:
    133 			case 0x40000:
    134 			case 0x50000:
    135 			case 0x60000:
    136 			case 0x70000:	return eraseSector(_addr, 64);
    137 			case 0x78000:
    138 			case 0x7a000:	return eraseSector(_addr, 8);
    139 			case 0x7c000:	return eraseSector(_addr, 16);
    140 			default:		return false;
    141 		}
    142 	}
    143 
    144 	void Am29f::execCommand(const CommandType _command, uint32_t _addr, const uint16_t _data) const
    145 	{
    146 		switch (_command)
    147 		{
    148 		case CommandType::ChipErase:
    149 			assert(false);
    150 			break;
    151 		case CommandType::SectorErase:
    152 			{
    153 				if (!eraseSector(_addr))
    154 				{
    155 					assert(false);
    156 					MCLOG("Unable to erase sector at " << MCHEX(_addr) << ", unable to determine sector size!");
    157 				}
    158 			}
    159 			break;
    160 		case CommandType::Program:
    161 			{
    162 				if(_addr >= m_size)
    163 					return;
    164 #if defined(_DEBUG) && defined(_WIN32)
    165 				MCLOG("Programming word at " << MCHEX(_addr) << ", value " << MCHEXN(_data, 4));
    166 #endif
    167 				const auto old = mc68k::memoryOps::readU16(m_buffer, _addr);
    168 				// "A bit cannot be programmed from a 0 back to a 1"
    169 				const auto v = _data & old;
    170 				mc68k::memoryOps::writeU16(m_buffer, _addr, v);
    171 	//			assert(v == _data);
    172 				break;
    173 			}
    174 		case CommandType::Invalid: 
    175 		default: 
    176 			assert(false);
    177 			break;
    178 		}
    179 	}
    180 }