611 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			611 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | /*
 | ||
|  | 	License: Zlib | ||
|  | 	see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details
 | ||
|  | 
 | ||
|  | 	Copyright holder(s): cam900 | ||
|  | 	Ensoniq ES5504/ES5505/ES5506 emulation core | ||
|  | */ | ||
|  | 
 | ||
|  | #ifndef _VGSOUND_EMU_SRC_ES550X_HPP
 | ||
|  | #define _VGSOUND_EMU_SRC_ES550X_HPP
 | ||
|  | 
 | ||
|  | #pragma once
 | ||
|  | 
 | ||
|  | #include "../core/util.hpp"
 | ||
|  | 
 | ||
|  | // ES5504/ES5505/ES5506 interface
 | ||
|  | class es550x_intf : public vgsound_emu_core | ||
|  | { | ||
|  | 	public: | ||
|  | 		es550x_intf() | ||
|  | 			: vgsound_emu_core("es550x_intf") | ||
|  | 		{ | ||
|  | 		} | ||
|  | 
 | ||
|  | 		virtual void e_pin(bool state) {}  // E output
 | ||
|  | 
 | ||
|  | 		virtual void bclk(bool state) {}  // BCLK output (serial specific)
 | ||
|  | 
 | ||
|  | 		virtual void lrclk(bool state) {}  // LRCLK output (serial specific)
 | ||
|  | 
 | ||
|  | 		virtual void wclk(bool state) {}  // WCLK output (serial specific)
 | ||
|  | 
 | ||
|  | 		virtual void irqb(bool state) {}  // irqb output
 | ||
|  | 
 | ||
|  | 		virtual u16 adc_r() { return 0; }  // ADC input
 | ||
|  | 
 | ||
|  | 		virtual void adc_w(u16 data) {}	 // ADC output
 | ||
|  | 
 | ||
|  | 		virtual s16 read_sample(u8 voice, u8 bank, u32 address) { return 0; } | ||
|  | }; | ||
|  | 
 | ||
|  | // Shared functions for ES5504/ES5505/ES5506
 | ||
|  | class es550x_shared_core : public vgsound_emu_core | ||
|  | { | ||
|  | 		friend class es550x_intf;  // es550x specific memory interface
 | ||
|  | 
 | ||
|  | 	private: | ||
|  | 		const u8 m_max_voices = 32; | ||
|  | 
 | ||
|  | 	protected: | ||
|  | 		// Interrupt bits
 | ||
|  | 		class es550x_irq_t : public vgsound_emu_core | ||
|  | 		{ | ||
|  | 			public: | ||
|  | 				es550x_irq_t() | ||
|  | 					: vgsound_emu_core("es550x_irq") | ||
|  | 					, m_voice(0) | ||
|  | 					, m_irqb(1) | ||
|  | 				{ | ||
|  | 				} | ||
|  | 
 | ||
|  | 				void reset() | ||
|  | 				{ | ||
|  | 					m_voice = 0; | ||
|  | 					m_irqb	= 1; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// setter
 | ||
|  | 				void set(u8 index) | ||
|  | 				{ | ||
|  | 					m_irqb	= 0; | ||
|  | 					m_voice = index & 0x1f; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				void clear() | ||
|  | 				{ | ||
|  | 					m_irqb	= 1; | ||
|  | 					m_voice = 0; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// getter
 | ||
|  | 				inline bool irqb() { return m_irqb; } | ||
|  | 
 | ||
|  | 				inline u8 voice() { return m_voice; } | ||
|  | 
 | ||
|  | 				inline u8 get() { return (m_irqb << 7) | (m_voice & 0x1f); } | ||
|  | 
 | ||
|  | 				u8 m_voice : 5; | ||
|  | 				u8 m_irqb  : 1; | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		// Common voice class
 | ||
|  | 		class es550x_voice_t : public vgsound_emu_core | ||
|  | 		{ | ||
|  | 			private: | ||
|  | 				// Common control bits
 | ||
|  | 				class es550x_control_t : public vgsound_emu_core | ||
|  | 				{ | ||
|  | 					public: | ||
|  | 						es550x_control_t() | ||
|  | 							: vgsound_emu_core("es550x_voice_control") | ||
|  | 							, m_ca(0) | ||
|  | 							, m_adc(0) | ||
|  | 							, m_bs(0) | ||
|  | 							, m_cmpd(0) | ||
|  | 						{ | ||
|  | 						} | ||
|  | 
 | ||
|  | 						void reset() | ||
|  | 						{ | ||
|  | 							m_ca   = 0; | ||
|  | 							m_adc  = 0; | ||
|  | 							m_bs   = 0; | ||
|  | 							m_cmpd = 0; | ||
|  | 						} | ||
|  | 
 | ||
|  | 						// setters
 | ||
|  | 						inline void set_ca(u8 ca) { m_ca = ca & 0xf; } | ||
|  | 
 | ||
|  | 						inline void set_adc(bool adc) { m_adc = adc ? 1 : 0; } | ||
|  | 
 | ||
|  | 						inline void set_bs(u8 bs) { m_bs = bs & 0x3; } | ||
|  | 
 | ||
|  | 						inline void set_cmpd(bool cmpd) { m_cmpd = cmpd ? 1 : 0; } | ||
|  | 
 | ||
|  | 						// getters
 | ||
|  | 						inline u8 ca() { return m_ca; } | ||
|  | 
 | ||
|  | 						inline bool adc() { return m_adc; } | ||
|  | 
 | ||
|  | 						inline u8 bs() { return m_bs; } | ||
|  | 
 | ||
|  | 						inline bool cmpd() { return m_cmpd; } | ||
|  | 
 | ||
|  | 					protected: | ||
|  | 						// Channel assign -
 | ||
|  | 						// 4 bit (16 channel or Bank) for ES5504
 | ||
|  | 						// 2 bit (4 stereo channels) for ES5505
 | ||
|  | 						// 3 bit (6 stereo channels) for ES5506
 | ||
|  | 						u8 m_ca : 4; | ||
|  | 
 | ||
|  | 						// ES5504 Specific
 | ||
|  | 						u8 m_adc : 1;  // Start ADC
 | ||
|  | 
 | ||
|  | 						// ES5505/ES5506 Specific
 | ||
|  | 						u8 m_bs	  : 2;	// Bank bit (1 bit for ES5505, 2 bit for ES5506)
 | ||
|  | 						u8 m_cmpd : 1;	// Use compressed sample format (ES5506)
 | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				// Accumulator
 | ||
|  | 				class es550x_alu_t : public vgsound_emu_core | ||
|  | 				{ | ||
|  | 					public: | ||
|  | 						es550x_alu_t(u8 integer, u8 fraction, bool transwave) | ||
|  | 							: vgsound_emu_core("es550x_voice_alu") | ||
|  | 							, m_integer(integer) | ||
|  | 							, m_fraction(fraction) | ||
|  | 							, m_total_bits(integer + fraction) | ||
|  | 							, m_accum_mask( | ||
|  | 								u32(std::min<u64>(~0, u64(u64(1) << u64(integer + fraction)) - 1))) | ||
|  | 							, m_transwave(transwave) | ||
|  | 							, m_fc(0) | ||
|  | 							, m_start(0) | ||
|  | 							, m_end(0) | ||
|  | 							, m_accum(0) | ||
|  | 							, m_sample({0}) | ||
|  | 						{ | ||
|  | 						} | ||
|  | 
 | ||
|  | 						// configurations
 | ||
|  | 						const u8 m_integer; | ||
|  | 						const u8 m_fraction; | ||
|  | 						const u8 m_total_bits; | ||
|  | 						const u32 m_accum_mask; | ||
|  | 						const bool m_transwave; | ||
|  | 
 | ||
|  | 						// internal states
 | ||
|  | 						void reset(); | ||
|  | 						bool tick(); | ||
|  | 
 | ||
|  | 						void loop_exec(); | ||
|  | 						bool busy(); | ||
|  | 						s32 interpolation(); | ||
|  | 						u32 get_accum_integer(); | ||
|  | 
 | ||
|  | 						void irq_exec(es550x_intf &intf, es550x_irq_t &irqv, u8 index); | ||
|  | 
 | ||
|  | 						void irq_update(es550x_intf &intf, es550x_irq_t &irqv) | ||
|  | 						{ | ||
|  | 							intf.irqb(irqv.irqb() ? false : true); | ||
|  | 						} | ||
|  | 
 | ||
|  | 						// setters
 | ||
|  | 						inline void set_stop0(bool stop0) { m_cr.set_stop0(stop0); } | ||
|  | 
 | ||
|  | 						inline void set_stop1(bool stop1) { m_cr.set_stop1(stop1); } | ||
|  | 
 | ||
|  | 						inline void set_lpe(bool lpe) { m_cr.set_lpe(lpe); } | ||
|  | 
 | ||
|  | 						inline void set_ble(bool ble) { m_cr.set_ble(ble); } | ||
|  | 
 | ||
|  | 						inline void set_irqe(bool irqe) { m_cr.set_irqe(irqe); } | ||
|  | 
 | ||
|  | 						inline void set_dir(bool dir) { m_cr.set_dir(dir); } | ||
|  | 
 | ||
|  | 						inline void set_irq(bool irq) { m_cr.set_irq(irq); } | ||
|  | 
 | ||
|  | 						inline void set_lei(bool lei) { m_cr.set_lei(lei); } | ||
|  | 
 | ||
|  | 						inline void set_stop(u8 stop) { m_cr.set_stop(stop); } | ||
|  | 
 | ||
|  | 						inline void set_loop(u8 loop) { m_cr.set_loop(loop); } | ||
|  | 
 | ||
|  | 						inline void set_fc(u32 fc) { m_fc = fc; } | ||
|  | 
 | ||
|  | 						inline void set_start(u32 start, u32 mask = ~0) | ||
|  | 						{ | ||
|  | 							m_start = (m_start & ~mask) | (start & mask); | ||
|  | 						} | ||
|  | 
 | ||
|  | 						inline void set_end(u32 end, u32 mask = ~0) | ||
|  | 						{ | ||
|  | 							m_end = (m_end & ~mask) | (end & mask); | ||
|  | 						} | ||
|  | 
 | ||
|  | 						inline void set_accum(u32 accum, u32 mask = ~0) | ||
|  | 						{ | ||
|  | 							m_accum = (m_accum & ~mask) | (accum & mask); | ||
|  | 						} | ||
|  | 
 | ||
|  | 						inline void set_sample(u8 slot, s32 sample) { m_sample[slot & 1] = sample; } | ||
|  | 
 | ||
|  | 						// getters
 | ||
|  | 						inline bool stop0() { return m_cr.stop0(); } | ||
|  | 
 | ||
|  | 						inline bool stop1() { return m_cr.stop1(); } | ||
|  | 
 | ||
|  | 						inline bool lpe() { return m_cr.lpe(); } | ||
|  | 
 | ||
|  | 						inline bool ble() { return m_cr.ble(); } | ||
|  | 
 | ||
|  | 						inline bool irqe() { return m_cr.irqe(); } | ||
|  | 
 | ||
|  | 						inline bool dir() { return m_cr.dir(); } | ||
|  | 
 | ||
|  | 						inline bool irq() { return m_cr.irq(); } | ||
|  | 
 | ||
|  | 						inline bool lei() { return m_cr.lei(); } | ||
|  | 
 | ||
|  | 						inline u8 stop() { return m_cr.stop(); } | ||
|  | 
 | ||
|  | 						inline u8 loop() { return m_cr.loop(); } | ||
|  | 
 | ||
|  | 						inline u32 fc() { return m_fc; } | ||
|  | 
 | ||
|  | 						inline u32 start() { return m_start; } | ||
|  | 
 | ||
|  | 						inline u32 end() { return m_end; } | ||
|  | 
 | ||
|  | 						inline u32 accum() { return m_accum; } | ||
|  | 
 | ||
|  | 						inline s32 sample(u8 slot) { return m_sample[slot & 1]; } | ||
|  | 
 | ||
|  | 					private: | ||
|  | 						class es550x_alu_cr_t : public vgsound_emu_core | ||
|  | 						{ | ||
|  | 							public: | ||
|  | 								es550x_alu_cr_t() | ||
|  | 									: vgsound_emu_core("es550x_voice_alu_cr") | ||
|  | 									, m_stop0(0) | ||
|  | 									, m_stop1(0) | ||
|  | 									, m_lpe(0) | ||
|  | 									, m_ble(0) | ||
|  | 									, m_irqe(0) | ||
|  | 									, m_dir(0) | ||
|  | 									, m_irq(0) | ||
|  | 									, m_lei(0) | ||
|  | 								{ | ||
|  | 								} | ||
|  | 
 | ||
|  | 								void reset() | ||
|  | 								{ | ||
|  | 									m_stop0 = 0; | ||
|  | 									m_stop1 = 0; | ||
|  | 									m_lpe	= 0; | ||
|  | 									m_ble	= 0; | ||
|  | 									m_irqe	= 0; | ||
|  | 									m_dir	= 0; | ||
|  | 									m_irq	= 0; | ||
|  | 									m_lei	= 0; | ||
|  | 								} | ||
|  | 
 | ||
|  | 								// setters
 | ||
|  | 								inline void set_stop0(bool stop0) { m_stop0 = stop0 ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_stop1(bool stop1) { m_stop1 = stop1 ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_lpe(bool lpe) { m_lpe = lpe ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_ble(bool ble) { m_ble = ble ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_irqe(bool irqe) { m_irqe = irqe ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_dir(bool dir) { m_dir = dir ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_irq(bool irq) { m_irq = irq ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_lei(bool lei) { m_lei = lei ? 1 : 0; } | ||
|  | 
 | ||
|  | 								inline void set_stop(u8 stop) | ||
|  | 								{ | ||
|  | 									m_stop0 = (stop >> 0) & 1; | ||
|  | 									m_stop1 = (stop >> 1) & 1; | ||
|  | 								} | ||
|  | 
 | ||
|  | 								inline void set_loop(u8 loop) | ||
|  | 								{ | ||
|  | 									m_lpe = (loop >> 0) & 1; | ||
|  | 									m_ble = (loop >> 1) & 1; | ||
|  | 								} | ||
|  | 
 | ||
|  | 								// getters
 | ||
|  | 								inline bool stop0() { return m_stop0; } | ||
|  | 
 | ||
|  | 								inline bool stop1() { return m_stop1; } | ||
|  | 
 | ||
|  | 								inline bool lpe() { return m_lpe; } | ||
|  | 
 | ||
|  | 								inline bool ble() { return m_ble; } | ||
|  | 
 | ||
|  | 								inline bool irqe() { return m_irqe; } | ||
|  | 
 | ||
|  | 								inline bool dir() { return m_dir; } | ||
|  | 
 | ||
|  | 								inline bool irq() { return m_irq; } | ||
|  | 
 | ||
|  | 								inline bool lei() { return m_lei; } | ||
|  | 
 | ||
|  | 								inline u8 stop() { return (m_stop0 << 0) | (m_stop1 << 1); } | ||
|  | 
 | ||
|  | 								inline u8 loop() { return (m_lpe << 0) | (m_ble << 1); } | ||
|  | 
 | ||
|  | 							private: | ||
|  | 								u8 m_stop0 : 1;	 // Stop with ALU
 | ||
|  | 								u8 m_stop1 : 1;	 // Stop with processor
 | ||
|  | 								u8 m_lpe   : 1;	 // Loop enable
 | ||
|  | 								u8 m_ble   : 1;	 // Bidirectional loop enable
 | ||
|  | 								u8 m_irqe  : 1;	 // IRQ enable
 | ||
|  | 								u8 m_dir   : 1;	 // Playback direction
 | ||
|  | 								u8 m_irq   : 1;	 // IRQ bit
 | ||
|  | 								u8 m_lei   : 1;	 // Loop end ignore (ES5506 specific)
 | ||
|  | 						}; | ||
|  | 
 | ||
|  | 						es550x_alu_cr_t m_cr; | ||
|  | 						// Frequency -
 | ||
|  | 						// 6 integer, 9 fraction for ES5504/ES5505
 | ||
|  | 						// 6 integer, 11 fraction for ES5506
 | ||
|  | 						u32 m_fc	= 0; | ||
|  | 						u32 m_start = 0;  // Start register
 | ||
|  | 						u32 m_end	= 0;  // End register
 | ||
|  | 
 | ||
|  | 						// Accumulator -
 | ||
|  | 						// 20 integer, 9 fraction for ES5504/ES5505
 | ||
|  | 						// 21 integer, 11 fraction for ES5506
 | ||
|  | 						u32 m_accum = 0; | ||
|  | 						// Samples
 | ||
|  | 						std::array<s32, 2> m_sample = {0}; | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				// Filter
 | ||
|  | 				class es550x_filter_t : public vgsound_emu_core | ||
|  | 				{ | ||
|  | 					public: | ||
|  | 						es550x_filter_t() | ||
|  | 							: vgsound_emu_core("es550x_voice_filter") | ||
|  | 							, m_lp(0) | ||
|  | 							, m_k2(0) | ||
|  | 							, m_k1(0) | ||
|  | 						{ | ||
|  | 							for (std::array<s32, 2> &elem : m_o) | ||
|  | 							{ | ||
|  | 								std::fill(elem.begin(), elem.end(), 0); | ||
|  | 							} | ||
|  | 						} | ||
|  | 
 | ||
|  | 						void reset(); | ||
|  | 						void tick(s32 in); | ||
|  | 
 | ||
|  | 						// setters
 | ||
|  | 						inline void set_lp(u8 lp) { m_lp = lp & 3; } | ||
|  | 
 | ||
|  | 						inline void set_k2(s32 k2) { m_k2 = k2; } | ||
|  | 
 | ||
|  | 						inline void set_k1(s32 k1) { m_k1 = k1; } | ||
|  | 
 | ||
|  | 						inline void set_o1_1(s32 o1_1) { m_o[1][0] = o1_1; } | ||
|  | 
 | ||
|  | 						inline void set_o2_1(s32 o2_1) { m_o[2][0] = o2_1; } | ||
|  | 
 | ||
|  | 						inline void set_o2_2(s32 o2_2) { m_o[2][1] = o2_2; } | ||
|  | 
 | ||
|  | 						inline void set_o3_1(s32 o3_1) { m_o[3][0] = o3_1; } | ||
|  | 
 | ||
|  | 						inline void set_o3_2(s32 o3_2) { m_o[3][1] = o3_2; } | ||
|  | 
 | ||
|  | 						inline void set_o4_1(s32 o4_1) { m_o[4][0] = o4_1; } | ||
|  | 
 | ||
|  | 						// getters
 | ||
|  | 						inline u8 lp() { return m_lp; } | ||
|  | 
 | ||
|  | 						inline s32 k2() { return m_k2; } | ||
|  | 
 | ||
|  | 						inline s32 k1() { return m_k1; } | ||
|  | 
 | ||
|  | 						inline s32 o1_1() { return m_o[1][0]; } | ||
|  | 
 | ||
|  | 						inline s32 o2_1() { return m_o[2][0]; } | ||
|  | 
 | ||
|  | 						inline s32 o2_2() { return m_o[2][1]; } | ||
|  | 
 | ||
|  | 						inline s32 o3_1() { return m_o[3][0]; } | ||
|  | 
 | ||
|  | 						inline s32 o3_2() { return m_o[3][1]; } | ||
|  | 
 | ||
|  | 						inline s32 o4_1() { return m_o[4][0]; } | ||
|  | 
 | ||
|  | 					private: | ||
|  | 						void lp_exec(s32 coeff, s32 in, s32 out); | ||
|  | 						void hp_exec(s32 coeff, s32 in, s32 out); | ||
|  | 
 | ||
|  | 						// Registers
 | ||
|  | 						u8 m_lp = 0;  // Filter mode
 | ||
|  | 						// Filter coefficient registers
 | ||
|  | 						// 12 bit for filter calculation, 4
 | ||
|  | 						// LSBs are used for fine control of ramp increment for
 | ||
|  | 						// hardware envelope (ES5506)
 | ||
|  | 						s32 m_k2 = 0;  // Filter coefficient 2
 | ||
|  | 						s32 m_k1 = 0;  // Filter coefficient 1
 | ||
|  | 
 | ||
|  | 						// Filter storage registers
 | ||
|  | 						std::array<std::array<s32, 2>, 5> m_o; | ||
|  | 				}; | ||
|  | 
 | ||
|  | 			public: | ||
|  | 				es550x_voice_t(std::string tag, u8 integer, u8 fraction, bool transwave) | ||
|  | 					: vgsound_emu_core(tag) | ||
|  | 					, m_cr(es550x_control_t()) | ||
|  | 					, m_alu(integer, fraction, transwave) | ||
|  | 					, m_filter(es550x_filter_t()) | ||
|  | 				{ | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// internal state
 | ||
|  | 				virtual void reset(); | ||
|  | 				virtual void fetch(u8 voice, u8 cycle) = 0; | ||
|  | 				virtual void tick(u8 voice)			   = 0; | ||
|  | 
 | ||
|  | 				void irq_update(es550x_intf &intf, es550x_irq_t &irqv) | ||
|  | 				{ | ||
|  | 					m_alu.irq_update(intf, irqv); | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// Getters
 | ||
|  | 				es550x_control_t &cr() { return m_cr; } | ||
|  | 
 | ||
|  | 				es550x_alu_t &alu() { return m_alu; } | ||
|  | 
 | ||
|  | 				es550x_filter_t &filter() { return m_filter; } | ||
|  | 
 | ||
|  | 			protected: | ||
|  | 				es550x_control_t m_cr; | ||
|  | 				es550x_alu_t m_alu; | ||
|  | 				es550x_filter_t m_filter; | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		// Host interfaces
 | ||
|  | 		class host_interface_flag_t : public vgsound_emu_core | ||
|  | 		{ | ||
|  | 			public: | ||
|  | 				host_interface_flag_t() | ||
|  | 					: vgsound_emu_core("es550x_host_interface_flag") | ||
|  | 					, m_host_access(0) | ||
|  | 					, m_host_access_strobe(0) | ||
|  | 					, m_rw(0) | ||
|  | 					, m_rw_strobe(0) | ||
|  | 				{ | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// Accessors
 | ||
|  | 				void reset() | ||
|  | 				{ | ||
|  | 					m_host_access		 = 0; | ||
|  | 					m_host_access_strobe = 0; | ||
|  | 					m_rw				 = 0; | ||
|  | 					m_rw_strobe			 = 0; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// Setters
 | ||
|  | 				void set_strobe(bool rw) | ||
|  | 				{ | ||
|  | 					m_rw_strobe			 = rw ? 1 : 0; | ||
|  | 					m_host_access_strobe = 1; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				void clear_strobe() { m_host_access_strobe = 0; } | ||
|  | 
 | ||
|  | 				void clear_host_access() { m_host_access = 0; } | ||
|  | 
 | ||
|  | 				void update_strobe() | ||
|  | 				{ | ||
|  | 					m_rw		  = m_rw_strobe; | ||
|  | 					m_host_access = m_host_access_strobe; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// Getters
 | ||
|  | 				bool host_access() { return m_host_access; } | ||
|  | 
 | ||
|  | 				bool rw() { return m_rw; } | ||
|  | 
 | ||
|  | 			private: | ||
|  | 				u8 m_host_access		: 1;  // Host access trigger
 | ||
|  | 				u8 m_host_access_strobe : 1;  // Host access strobe
 | ||
|  | 				u8 m_rw					: 1;  // R/W state
 | ||
|  | 				u8 m_rw_strobe			: 1;  // R/W strobe
 | ||
|  | 		}; | ||
|  | 
 | ||
|  | 	public: | ||
|  | 		// internal state
 | ||
|  | 		virtual void reset(); | ||
|  | 
 | ||
|  | 		virtual void tick() {} | ||
|  | 
 | ||
|  | 		// clock outputs
 | ||
|  | 		inline bool _cas() { return m_cas.current_edge(); } | ||
|  | 
 | ||
|  | 		inline bool _cas_rising_edge() { return m_cas.rising_edge(); } | ||
|  | 
 | ||
|  | 		inline bool _cas_falling_edge() { return m_cas.falling_edge(); } | ||
|  | 
 | ||
|  | 		inline bool e() { return m_e.current_edge(); } | ||
|  | 
 | ||
|  | 		inline bool e_rising_edge() { return m_e.rising_edge(); } | ||
|  | 
 | ||
|  | 		inline bool e_falling_edge() { return m_e.falling_edge(); } | ||
|  | 
 | ||
|  | 		//-----------------------------------------------------------------
 | ||
|  | 		//
 | ||
|  | 		//	for preview/debug purpose only, not for serious emulators
 | ||
|  | 		//
 | ||
|  | 		//-----------------------------------------------------------------
 | ||
|  | 
 | ||
|  | 		// voice cycle
 | ||
|  | 		inline u8 voice_cycle() { return m_voice_cycle; } | ||
|  | 
 | ||
|  | 		// voice update flag
 | ||
|  | 		inline bool voice_update() { return m_voice_update; } | ||
|  | 
 | ||
|  | 		inline bool voice_end() { return m_voice_end; } | ||
|  | 
 | ||
|  | 	protected: | ||
|  | 		// constructor
 | ||
|  | 		es550x_shared_core(std::string tag, const u8 voice, es550x_intf &intf) | ||
|  | 			: vgsound_emu_core(tag) | ||
|  | 			, m_max_voices(voice) | ||
|  | 			, m_intf(intf) | ||
|  | 			, m_host_intf(host_interface_flag_t()) | ||
|  | 			, m_ha(0) | ||
|  | 			, m_hd(0) | ||
|  | 			, m_page(0) | ||
|  | 			, m_irqv(es550x_irq_t()) | ||
|  | 			, m_active(m_max_voices - 1) | ||
|  | 			, m_voice_cycle(0) | ||
|  | 			, m_voice_fetch(0) | ||
|  | 			, m_voice_update(0) | ||
|  | 			, m_voice_end(0) | ||
|  | 			, m_clkin(clock_pulse_t<s8>(1, 0)) | ||
|  | 			, m_cas(clock_pulse_t<s8>(2, 1)) | ||
|  | 			, m_e(clock_pulse_t<s8>(4, 0)) | ||
|  | 		{ | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Constants
 | ||
|  | 		virtual inline u8 max_voices() { return m_max_voices; } | ||
|  | 
 | ||
|  | 		// Shared registers, functions
 | ||
|  | 		virtual void voice_tick() {}  // voice tick
 | ||
|  | 
 | ||
|  | 		es550x_intf &m_intf;				// es550x specific memory interface
 | ||
|  | 		host_interface_flag_t m_host_intf;	// Host interface flag
 | ||
|  | 		u8 m_ha	  = 0;						// Host address (4 bit)
 | ||
|  | 		u16 m_hd  = 0;		  // Host data (16 bit for ES5504/ES5505, 8 bit for ES5506)
 | ||
|  | 		u8 m_page = 0;		  // Page
 | ||
|  | 		es550x_irq_t m_irqv;  // Voice interrupt vector registers
 | ||
|  | 
 | ||
|  | 		// Internal states
 | ||
|  | 		u8 m_active = 31;			  // Activated voices
 | ||
|  | 									  // -1, ~25 for ES5504,
 | ||
|  | 									  // ~32 for ES5505/ES5506
 | ||
|  | 		u8 m_voice_cycle	= 0;	  // Voice cycle
 | ||
|  | 		u8 m_voice_fetch	= 0;	  // Voice fetch cycle
 | ||
|  | 		bool m_voice_update = false;  // Voice update flag
 | ||
|  | 		bool m_voice_end	= false;  // End of one voice cycle flag
 | ||
|  | 		clock_pulse_t<s8> m_clkin;	  // CLKIN clock
 | ||
|  | 		clock_pulse_t<s8> m_cas;	  // /CAS clock (CLKIN / 4), falling edge of
 | ||
|  | 									  // CLKIN trigger this clock
 | ||
|  | 		clock_pulse_t<s8> m_e;		  // E clock (CLKIN / 8),
 | ||
|  | 									  // falling edge of CLKIN trigger this clock
 | ||
|  | }; | ||
|  | 
 | ||
|  | #endif
 |