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

xtPic.cpp (3936B)


      1 #include "xtPic.h"
      2 
      3 #include "xtLcd.h"
      4 
      5 #include "mc68k/mc68k.h"
      6 #include "mc68k/logging.h"
      7 
      8 #include <cassert>
      9 #include <cstdint>
     10 
     11 namespace xt
     12 {
     13 	Pic::Pic(mc68k::Mc68k& _uc, Lcd& _lcd)
     14 	{
     15 		_uc.getQSM().setSpiWriteCallback([&](const uint16_t _data, const uint8_t _index)->uint16_t
     16 		{
     17 			constexpr uint32_t transmitRamAddr = static_cast<uint32_t>(mc68k::PeriphAddress::TransmitRam0);
     18 			constexpr uint32_t receiveRamAddr = static_cast<uint32_t>(mc68k::PeriphAddress::ReceiveRam0);
     19 			constexpr uint32_t receiveRamSize = transmitRamAddr - receiveRamAddr;
     20 			static_assert(receiveRamSize == 32);
     21 
     22 			if(_index == 0)
     23 			{
     24 				// $30 enc 3 switches to multimode?
     25 				// $35 = Osc 1 Semitone
     26 				// $36 = Startwave1
     27 				// $37 = Mix Wave1
     28 
     29 				const uint8_t buttonA = m_spiButtons & 0x3f;
     30 				const uint8_t buttonB = (m_spiButtons>>1) & 0x20;
     31 
     32 				const uint16_t anus[] =
     33 				{
     34 					'M',		// don't care
     35 					'W',		// don't care
     36 					0x30,		// encoder address for encoders 1-4, range 0x30 - 0x57
     37 					0,			// encoder value 1
     38 					0,			// encoder value 2
     39 					0,			// encoder value 3
     40 					0,			// encoder value 4
     41 					0x38,		// encoder address for encoders 5-8, range 0x30 - 0x57
     42 					0,			// encoder value 5
     43 					0,			// encoder value 6
     44 					0,			// encoder value 7
     45 					0,			// encoder value 8
     46 					buttonA,	// Button flags A
     47 					buttonB,	// Button flags B
     48 					255,		// main volume pot
     49 					'x'			// We are an XT
     50 				};
     51 
     52 				for(uint32_t a=0; a<std::size(anus); ++a)
     53 					_uc.write16(a*2 + receiveRamAddr, anus[a]);
     54 			}
     55 
     56 			if(_index == 0)
     57 			{
     58 				m_picCommand0 = _data;
     59 				return 0;
     60 			}
     61 			else if(_index == 1)
     62 			{
     63 				if(m_picCommand0 == 0x10)
     64 				{
     65 					if(_data == 0x80)
     66 						_lcd.resetWritePos();
     67 
     68 					return 0;
     69 				}
     70 			}
     71 
     72 			// PIC Command 0x10 = new write, everything is for the LCD
     73 			// Pic Command 0x18 = continue to write and update LEDs too
     74 
     75 			assert(m_picCommand0 == 0x10 || m_picCommand0 == 0x18);
     76 
     77 			uint8_t lcdChar = m_picCommand0 == 0x10 ? static_cast<uint8_t>(_data) : 0;
     78 
     79 			if(m_picCommand0 == 0x18)
     80 			{
     81 				if(_index == 7)
     82 					m_picHasLedUpdate = _data == 0x14;
     83 
     84 				if(m_picHasLedUpdate)
     85 				{
     86 					switch (_index)
     87 					{
     88 					case 1:
     89 					case 2:
     90 					case 3:
     91 					case 4:
     92 					case 5:
     93 					case 6:
     94 						lcdChar = static_cast<uint8_t>(_data);
     95 						break;
     96 					case 8:
     97 					case 9:
     98 					case 10:
     99 					case 11:
    100 						{
    101 							const auto oldLedState = m_ledState;
    102 							m_ledState &= ~(0xff << ((_index-8) * 8));
    103 							m_ledState |= (_data & 0xff) << ((_index-8) * 8);
    104 							if(oldLedState != m_ledState)
    105 							{
    106 //								MCLOG("LEDs: " << MCHEXN(m_ledState, 4));
    107 								m_cbkLedsDirty();
    108 							}
    109 						}
    110 						break;
    111 					default:
    112 						return 0;
    113 					}
    114 				}
    115 				else
    116 				{
    117 					lcdChar = static_cast<uint8_t>(_data);
    118 				}
    119 			}
    120 			if(lcdChar)
    121 			{
    122 				const auto ch = static_cast<char>(lcdChar);
    123 
    124 				if(_lcd.writeCharacter(ch))
    125 				{
    126 					m_cbkLcdDirty();
    127 					MCLOG("LCD:\n" << _lcd.toString());
    128 				}
    129 
    130 				return 0;
    131 			}
    132 			return 0;
    133 		});
    134 	}
    135 
    136 	Pic::~Pic()	= default;
    137 
    138 	void Pic::setButton(const ButtonType _type, const bool _pressed)
    139 	{
    140 		const auto buttonMask = static_cast<uint8_t>(1 << static_cast<uint8_t>(_type));
    141 
    142 		// inverted on purpose, pressed buttons are 0, released ones 1
    143 		if(_pressed)
    144 			m_spiButtons &= ~buttonMask;
    145 		else
    146 			m_spiButtons |= buttonMask;
    147 	}
    148 
    149 	bool Pic::getButton(ButtonType _button) const
    150 	{
    151 		const auto buttonMask = static_cast<uint8_t>(1 << static_cast<uint8_t>(_button));
    152 
    153 		// inverted on purpose, pressed buttons are 0, released ones 1
    154 		return (m_spiButtons & buttonMask) == 0;
    155 	}
    156 
    157 	void Pic::setLcdDirtyCallback(const DirtyCallback& _cbk)
    158 	{
    159 		m_cbkLcdDirty = _cbk;
    160 		if(!m_cbkLcdDirty)
    161 			m_cbkLcdDirty = [] {};
    162 	}
    163 
    164 	void Pic::setLedsDirtyCallback(const DirtyCallback& _cbk)
    165 	{
    166 		m_cbkLedsDirty = _cbk;
    167 		if(!m_cbkLedsDirty)
    168 			m_cbkLedsDirty = [] {};
    169 	}
    170 
    171 	bool Pic::getLedState(const LedType _led) const
    172 	{
    173 		return m_ledState & (1 << _led);
    174 	}
    175 }