diff options
author | fulivi <fulivi@users.noreply.github.com> | 2020-07-02 20:04:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-02 14:04:21 -0400 |
commit | 729b27d7c1b78bc70a443bc6281585501b34ffcd (patch) | |
tree | 3579c9f48d90d77c8083c7de89df3c04bf556d05 /src/devices | |
parent | 50baacce8b98bc561213e07e61c505394176b6c4 (diff) |
hp_ipc: added beeper (#6893)
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/machine/cop452.cpp | 350 | ||||
-rw-r--r-- | src/devices/machine/cop452.h | 96 |
2 files changed, 446 insertions, 0 deletions
diff --git a/src/devices/machine/cop452.cpp b/src/devices/machine/cop452.cpp new file mode 100644 index 00000000000..cd3e1cb9ecb --- /dev/null +++ b/src/devices/machine/cop452.cpp @@ -0,0 +1,350 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +/*************************************************************************** + + cop452.h + + Frequency generator & counter + +***************************************************************************/ + +#include "emu.h" +#include "cop452.h" + +// Debugging +//#define VERBOSE LOG_GENERAL +#define VERBOSE 0 +#include "logmacro.h" + +// Device type definition +DEFINE_DEVICE_TYPE(COP452, cop452_device, "COP452", "National Semiconductor COP452 frequency generator") + +cop452_device::cop452_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) +: device_t(mconfig , COP452 , tag , owner , clock) + , m_out_handlers(*this) +{ +} + +WRITE_LINE_MEMBER(cop452_device::cs_w) +{ + m_cs = state; + if (m_cs) { + // CS removed + m_spi_state = 0; + m_sr = 0; + } +} + +WRITE_LINE_MEMBER(cop452_device::sk_w) +{ + if (!m_cs && !m_sk && state) { + // Rising edge on SK + LOG("bit %d %u\n" , m_di , m_spi_state); + if (m_spi_state == 0 && m_di) { + // Got start bit + m_spi_state = 1; + } else if (m_spi_state >= 1 && m_spi_state < 6) { + // Shifting instruction in + m_sr = (m_sr << 1) | m_di; + m_spi_state++; + if (m_spi_state == 6) { + LOG("Inst = %x\n" , m_sr); + m_spi_state = 22; + unsigned idx = !BIT(m_sr , 0); + char reg = idx ? 'B' : 'A'; + switch (m_sr) { + case 0b00000: + case 0b00001: + // LDRA/B + LOG("LDR%c\n" , reg); + m_spi_state = 6; + m_reg[ idx ] = 0; + break; + + case 0b00010: + case 0b00011: + // RDRA/B + // TODO: not implemented ATM + LOG("RDR%c\n" , reg); + break; + + case 0b00100: + case 0b00101: + // TRCA/B + LOG("TRC%c\n" , reg); + m_cnt[ idx ] = m_reg[ idx ]; + set_timer(idx); + break; + + case 0b00110: + case 0b00111: + // TCRA/B + // TODO: + LOG("TCR%c\n" , reg); + break; + + case 0b01000: + // CK1 + LOG("CK1\n"); + m_clk_div_4 = false; + break; + + case 0b01001: + // CK4 + LOG("CK4\n"); + m_clk_div_4 = true; + break; + + default: + if (m_sr & 0b10000) { + // LDM + m_mode = m_sr & 0b01111; + LOG("LDM %x\n" , m_mode); + set_timer(0); + set_timer(1); + if (m_mode == MODE_NUMBER_PULSES) { + // Always start with OA = 1 + set_output(0 , true); + } else if (m_mode == MODE_WHITE_NOISE || + m_mode == MODE_GATED_WHITE) { + // Preset bit 15 & 16 of register A when entering + // white noise modes + m_reg[ 0 ] |= 0x8000; + m_regA_b16 = true; + } + } else { + // Unknown instruction + LOG("Unknown instruction\n"); + } + break; + } + } + } else if (m_spi_state >= 6 && m_spi_state < 22) { + // Loading A/B register + unsigned idx = !BIT(m_sr , 0); + char reg = idx ? 'B' : 'A'; + m_reg[ idx ] = (m_reg[ idx ] << 1) | m_di; + m_spi_state++; + if (m_spi_state == 22) { + LOG("REG%c = %04x\n" , reg , m_reg[ idx ]); + } + } + } + m_sk = state; +} + +WRITE_LINE_MEMBER(cop452_device::di_w) +{ + m_di = state; +} + +READ_LINE_MEMBER(cop452_device::do_r) +{ + // TODO: + return 0; +} + +void cop452_device::device_start() +{ + m_out_handlers.resolve_all_safe(); + + m_timers[ 0 ] = timer_alloc(0); + m_timers[ 1 ] = timer_alloc(1); + + save_item(NAME(m_mode)); + save_item(NAME(m_clk_div_4)); + save_item(NAME(m_cs)); + save_item(NAME(m_sk)); + save_item(NAME(m_di)); + save_item(NAME(m_out)); + save_item(NAME(m_regA_b16)); + save_item(NAME(m_reg)); + save_item(NAME(m_cnt)); + save_item(NAME(m_spi_state)); + save_item(NAME(m_sr)); +} + +void cop452_device::device_reset() +{ + // Set reset mode + m_mode = MODE_RESET; + m_clk_div_4 = true; + m_out[ 0 ] = m_out[ 1 ] = true; + set_output(0 , false); + set_output(1 , false); + m_spi_state = 0; + m_sr = 0; + m_timers[ 0 ]->reset(); + m_timers[ 1 ]->reset(); +} + +void cop452_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + attotime target = attotime::never; + + switch (m_mode) { + case MODE_DUAL_FREQ: + toggle_n_reload(id); + target = counts_to_attotime(m_cnt[ id ]); + break; + + case MODE_TRIG_PULSE: + // TODO: NOT IMPLEMENTED + break; + + case MODE_NUMBER_PULSES: + if (id == 0) { + toggle_n_reload(0); + target = counts_to_attotime(m_cnt[ 0 ]); + if (!m_out[ 0 ]) { + // It seems that cnt B decrements each time OA goes low + if (m_cnt[ 1 ] != 0) { + m_cnt[ 1 ]--; + } else { + // End of pulse train + toggle_n_reload(1); + m_mode = MODE_RESET; + target = attotime::never; + } + } + } + break; + + case MODE_DUTY_CYCLE: + // TODO: NOT IMPLEMENTED + break; + + case MODE_FREQ_COUNT: + // TODO: NOT IMPLEMENTED + break; + + case MODE_DUAL_COUNT: + // TODO: NOT IMPLEMENTED + break; + + case MODE_WAVE_MEAS: + // TODO: NOT IMPLEMENTED + break; + + case MODE_TRIG_COUNT: + // TODO: NOT IMPLEMENTED + break; + + case MODE_WHITE_NOISE: + case MODE_GATED_WHITE: + { + if (id == 0) { + // Reg A & its 17th bit (m_regA_b16) form a 17-bit LFSR + // LFSR uses X^17+X^14+1 polynomial to generate a pseudo-random + // maximal-length sequence + bool feedback = m_regA_b16 ^ BIT(m_reg[ 0 ] , 13); + m_regA_b16 = BIT(m_reg[ 0 ] , 15); + m_reg[ 0 ] <<= 1; + m_reg[ 0 ] |= feedback; + } else { + toggle_n_reload(1); + } + bool new_out_0 = m_regA_b16; + if (m_mode == MODE_GATED_WHITE) { + new_out_0 &= m_out[ 1 ]; + } + set_output(0 , new_out_0); + } + break; + + default: + break; + } + + timer.adjust(target); +} + +attotime cop452_device::counts_to_attotime(unsigned counts) const +{ + if (m_clk_div_4) { + return clocks_to_attotime((counts + 1) * 4); + } else { + return clocks_to_attotime(counts + 1); + } +} + +void cop452_device::set_timer(unsigned idx) +{ + attotime target = attotime::never; + + switch (m_mode) { + case MODE_DUAL_FREQ: + // Cnt A & B count independently + target = counts_to_attotime(m_cnt[ idx ]); + break; + + case MODE_TRIG_PULSE: + // TODO: NOT IMPLEMENTED + break; + + case MODE_NUMBER_PULSES: + // Cnt A generates OA frequency + // Cnt B counts the periods to output + if (idx == 0) { + target = counts_to_attotime(m_cnt[ 0 ]); + } + break; + + case MODE_DUTY_CYCLE: + // TODO: NOT IMPLEMENTED + break; + + case MODE_FREQ_COUNT: + // TODO: NOT IMPLEMENTED + break; + + case MODE_DUAL_COUNT: + // TODO: NOT IMPLEMENTED + break; + + case MODE_WAVE_MEAS: + // TODO: NOT IMPLEMENTED + break; + + case MODE_TRIG_COUNT: + // TODO: NOT IMPLEMENTED + break; + + case MODE_WHITE_NOISE: + case MODE_GATED_WHITE: + // Cnt A is not used. Timer 0 expires once per internal clock period. + // Cnt B generates squarewave signal on OB + if (idx == 0) { + target = counts_to_attotime(0); + } else { + target = counts_to_attotime(m_cnt[ 1 ]); + } + break; + + default: + break; + } + + m_timers[ idx ]->adjust(target); +} + +void cop452_device::set_output(unsigned idx , bool state) +{ + if (m_out[ idx ] != state) { + m_out[ idx ] = state; + LOG("OUT %u=%d @%s\n" , idx , state , machine().time().as_string()); + m_out_handlers[ idx ](state); + } +} + +void cop452_device::toggle_output(unsigned idx) +{ + set_output(idx , !m_out[ idx ]); +} + +void cop452_device::toggle_n_reload(unsigned idx) +{ + // Toggle output OA/OB and reload its associated counter + toggle_output(idx); + m_cnt[ idx ] = m_reg[ idx ]; +} diff --git a/src/devices/machine/cop452.h b/src/devices/machine/cop452.h new file mode 100644 index 00000000000..f4981be72f3 --- /dev/null +++ b/src/devices/machine/cop452.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +/*************************************************************************** + + cop452.h + + Frequency generator & counter + +**************************************************************************** + ____ ____ + ZO 1 |* \_/ | 14 ZI + OA 2 | | 13 DO + INB 3 | | 12 DI + ENB 4 | COP452 | 11 SK + OB 5 | | 10 CS/ + Vcc 6 | | 9 GND + CKO 7 |___________| 8 CKI + +***************************************************************************/ + +#ifndef MAME_MACHINE_COP452_H +#define MAME_MACHINE_COP452_H + +#pragma once + +class cop452_device : public device_t +{ +public: + cop452_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + + // SPI I/O + DECLARE_WRITE_LINE_MEMBER(cs_w); + DECLARE_WRITE_LINE_MEMBER(sk_w); + DECLARE_WRITE_LINE_MEMBER(di_w); + DECLARE_READ_LINE_MEMBER(do_r); + + // Signal outputs + auto oa_w() { return m_out_handlers[ 0 ].bind(); } + auto ob_w() { return m_out_handlers[ 1 ].bind(); } + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + +private: + // Index 0 is for "A" side, 1 is for "B" side + devcb_write_line::array<2> m_out_handlers; + + // Timers + emu_timer *m_timers[ 2 ]; + + // State + uint8_t m_mode; + bool m_clk_div_4; + bool m_cs; + bool m_sk; + bool m_di; + bool m_out[ 2 ]; + bool m_regA_b16; + uint16_t m_reg[ 2 ]; + uint16_t m_cnt[ 2 ]; + // 0 : idle + // 1..5 : shifting instruction in + // 6..21: shifting register in + // >= 22: done + unsigned m_spi_state; + uint8_t m_sr; + + // Operating modes + enum : uint8_t { + MODE_DUAL_FREQ, // 0000 Dual frequency + MODE_TRIG_PULSE, // 0001 Triggered pulse + MODE_NUMBER_PULSES, // 0010 Number of pulses + MODE_DUTY_CYCLE, // 0011 Duty cycle + MODE_FREQ_COUNT, // 0100 Frequency and count + MODE_DUAL_COUNT, // 0101 Dual count + MODE_WAVE_MEAS, // 0110 Waveform measurement + MODE_TRIG_COUNT, // 0111 Triggered pulse and count + MODE_WHITE_NOISE, // 1000 White noise & frequency + MODE_GATED_WHITE, // 1001 Gated white noise + MODE_RESET = 15 // 1111 Reset + }; + + attotime counts_to_attotime(unsigned counts) const; + void set_timer(unsigned idx); + void set_output(unsigned idx , bool state); + void toggle_output(unsigned idx); + void toggle_n_reload(unsigned idx); +}; + +// device type definition +DECLARE_DEVICE_TYPE(COP452, cop452_device) + +#endif // MAME_MACHINE_COP452_H |