// license:BSD-3-Clause // copyright-holders:Curt Coder /********************************************************************** Zilog Z8036/Z8536 Counter/Timer and Parallel I/O Unit ********************************************************************** _____ _____ AD4 1 |* \_/ | 40 AD3 AD5 2 | | 39 AD2 AD6 3 | | 38 AD1 AD7 4 | | 37 AD0 _DS 5 | | 36 _CS0 R/_W 6 | | 35 CS1 GND 7 | | 34 _AS PB0 8 | | 33 PA0 PB1 9 | | 32 PA1 PB2 10 | Z8036 | 31 PA2 PB3 11 | | 30 PA3 PB4 12 | | 29 PA4 PB5 13 | | 28 PA5 PB6 14 | | 27 PA6 PB7 15 | | 26 PA7 PCLK 16 | | 25 _INTACK IEI 17 | | 24 _INT IEO 18 | | 23 +5 V PC0 19 | | 22 PC3 PC1 20 |_____________| 21 PC2 _____ _____ D4 1 |* \_/ | 40 D3 D5 2 | | 39 D2 D6 3 | | 38 D1 D7 4 | | 37 D0 _RD 5 | | 36 _CE _WR 6 | | 35 A1 GND 7 | | 34 A0 PB0 8 | | 33 PA0 PB1 9 | | 32 PA1 PB2 10 | Z8536 | 31 PA2 PB3 11 | | 30 PA3 PB4 12 | | 29 PA4 PB5 13 | | 28 PA5 PB6 14 | | 27 PA6 PB7 15 | | 26 PA7 PCLK 16 | | 25 _INTACK IEI 17 | | 24 _INT IEO 18 | | 23 +5 V PC0 19 | | 22 PC3 PC1 20 |_____________| 21 PC2 **********************************************************************/ #ifndef MAME_MACHINE_Z8536_H #define MAME_MACHINE_Z8536_H #pragma once #include "machine/z80daisy.h" //************************************************************************** // INTERFACE CONFIGURATION MACROS //************************************************************************** #define MCFG_Z8536_IRQ_CALLBACK(_write) \ downcast(*device).set_irq_wr_callback(DEVCB_##_write); #define MCFG_Z8536_PA_IN_CALLBACK(_read) \ downcast(*device).set_pa_rd_callback(DEVCB_##_read); #define MCFG_Z8536_PA_OUT_CALLBACK(_write) \ downcast(*device).set_pa_wr_callback(DEVCB_##_write); #define MCFG_Z8536_PB_IN_CALLBACK(_read) \ downcast(*device).set_pb_rd_callback(DEVCB_##_read); #define MCFG_Z8536_PB_OUT_CALLBACK(_write) \ downcast(*device).set_pb_wr_callback(DEVCB_##_write); #define MCFG_Z8536_PC_IN_CALLBACK(_read) \ downcast(*device).set_pc_rd_callback(DEVCB_##_read); #define MCFG_Z8536_PC_OUT_CALLBACK(_write) \ downcast(*device).set_pc_wr_callback(DEVCB_##_write); //************************************************************************** // TYPE DEFINITIONS //************************************************************************** // ======================> cio_base_device class cio_base_device : public device_t { public: template devcb_base &set_irq_wr_callback(Object &&cb) { return m_write_irq.set_callback(std::forward(cb)); } template devcb_base &set_pa_rd_callback(Object &&cb) { return m_read_pa.set_callback(std::forward(cb)); } template devcb_base &set_pa_wr_callback(Object &&cb) { return m_write_pa.set_callback(std::forward(cb)); } template devcb_base &set_pb_rd_callback(Object &&cb) { return m_read_pb.set_callback(std::forward(cb)); } template devcb_base &set_pb_wr_callback(Object &&cb) { return m_write_pb.set_callback(std::forward(cb)); } template devcb_base &set_pc_rd_callback(Object &&cb) { return m_read_pc.set_callback(std::forward(cb)); } template devcb_base &set_pc_wr_callback(Object &&cb) { return m_write_pc.set_callback(std::forward(cb)); } DECLARE_WRITE_LINE_MEMBER( pa0_w ) { external_port_w(PORT_A, 0, state); } DECLARE_WRITE_LINE_MEMBER( pa1_w ) { external_port_w(PORT_A, 1, state); } DECLARE_WRITE_LINE_MEMBER( pa2_w ) { external_port_w(PORT_A, 2, state); } DECLARE_WRITE_LINE_MEMBER( pa3_w ) { external_port_w(PORT_A, 3, state); } DECLARE_WRITE_LINE_MEMBER( pa4_w ) { external_port_w(PORT_A, 4, state); } DECLARE_WRITE_LINE_MEMBER( pa5_w ) { external_port_w(PORT_A, 5, state); } DECLARE_WRITE_LINE_MEMBER( pa6_w ) { external_port_w(PORT_A, 6, state); } DECLARE_WRITE_LINE_MEMBER( pa7_w ) { external_port_w(PORT_A, 7, state); } DECLARE_WRITE_LINE_MEMBER( pb0_w ) { external_port_w(PORT_B, 0, state); } DECLARE_WRITE_LINE_MEMBER( pb1_w ) { external_port_w(PORT_B, 1, state); } DECLARE_WRITE_LINE_MEMBER( pb2_w ) { external_port_w(PORT_B, 2, state); } DECLARE_WRITE_LINE_MEMBER( pb3_w ) { external_port_w(PORT_B, 3, state); } DECLARE_WRITE_LINE_MEMBER( pb4_w ) { external_port_w(PORT_B, 4, state); } DECLARE_WRITE_LINE_MEMBER( pb5_w ) { external_port_w(PORT_B, 5, state); } DECLARE_WRITE_LINE_MEMBER( pb6_w ) { external_port_w(PORT_B, 6, state); } DECLARE_WRITE_LINE_MEMBER( pb7_w ) { external_port_w(PORT_B, 7, state); } DECLARE_WRITE_LINE_MEMBER( pc0_w ) { external_port_w(PORT_C, 0, state); } DECLARE_WRITE_LINE_MEMBER( pc1_w ) { external_port_w(PORT_C, 1, state); } DECLARE_WRITE_LINE_MEMBER( pc2_w ) { external_port_w(PORT_C, 2, state); } DECLARE_WRITE_LINE_MEMBER( pc3_w ) { external_port_w(PORT_C, 3, state); } int intack_r(); protected: // construction/destruction cio_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); // 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; bool is_reset() const { return (m_register[MASTER_INTERRUPT_CONTROL] & MICR_RESET) != 0; } enum { TIMER_1 = 0, TIMER_2, TIMER_3 }; // ports enum { PORT_A = 0, PORT_B, PORT_C, CONTROL }; // registers enum { MASTER_INTERRUPT_CONTROL = 0x00, MASTER_CONFIGURATION_CONTROL, PORT_A_INTERRUPT_VECTOR, PORT_B_INTERRUPT_VECTOR, COUNTER_TIMER_INTERRUPT_VECTOR, PORT_C_DATA_PATH_POLARITY, PORT_C_DATA_DIRECTION, PORT_C_SPECIAL_IO_CONTROL, PORT_A_COMMAND_AND_STATUS, PORT_B_COMMAND_AND_STATUS, COUNTER_TIMER_1_COMMAND_AND_STATUS, COUNTER_TIMER_2_COMMAND_AND_STATUS, COUNTER_TIMER_3_COMMAND_AND_STATUS, PORT_A_DATA, PORT_B_DATA, PORT_C_DATA, COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE = 0x10, COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE, COUNTER_TIMER_2_CURRENT_COUNT_MS_BYTE, COUNTER_TIMER_2_CURRENT_COUNT_LS_BYTE, COUNTER_TIMER_3_CURRENT_COUNT_MS_BYTE, COUNTER_TIMER_3_CURRENT_COUNT_LS_BYTE, COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE, COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE, COUNTER_TIMER_2_TIME_CONSTANT_MS_BYTE, COUNTER_TIMER_2_TIME_CONSTANT_LS_BYTE, COUNTER_TIMER_3_TIME_CONSTANT_MS_BYTE, COUNTER_TIMER_3_TIME_CONSTANT_LS_BYTE, COUNTER_TIMER_1_MODE_SPECIFICATION, COUNTER_TIMER_2_MODE_SPECIFICATION, COUNTER_TIMER_3_MODE_SPECIFICATION, CURRENT_VECTOR, PORT_A_MODE_SPECIFICATION = 0x20, PORT_A_HANDSHAKE_SPECIFICATION, PORT_A_DATA_PATH_POLARITY, PORT_A_DATA_DIRECTION, PORT_A_SPECIAL_IO_CONTROL, PORT_A_PATTERN_POLARITY, PORT_A_PATTERN_TRANSITION, PORT_A_PATTERN_MASK, PORT_B_MODE_SPECIFICATION, PORT_B_HANDSHAKE_SPECIFICATION, PORT_B_DATA_PATH_POLARITY, PORT_B_DATA_DIRECTION, PORT_B_SPECIAL_IO_CONTROL, PORT_B_PATTERN_POLARITY, PORT_B_PATTERN_TRANSITION, PORT_B_PATTERN_MASK }; // master interrupt control register enum { MICR_RESET = 0x01, // reset MICR_RJA = 0x02, // right justified address MICR_CT_VIS = 0x04, // counter/timer vector includes status MICR_PB_VIS = 0x08, // port B vector includes status MICR_PA_VIS = 0x10, // port A vector includes status MICR_NV = 0x20, // no vector MICR_DLC = 0x40, // disable lower chain MICR_MIE = 0x80 // master interrupt enable }; // master configuration control register enum { MCCR_LC_MASK = 0x03, // counter/timer link controls MCCR_PAE = 0x04, // port A enable MCCR_PLC = 0x08, // port link control MCCR_PCE_CT3E = 0x10, // port C and counter/timer 3 enable MCCR_CT2E = 0x20, // counter/timer 2 enable MCCR_CT1E = 0x40, // counter/timer 1 enable MCCR_PBE = 0x80 // port B enable }; // port mode specification registers enum { PMS_LPM = 0x01, // latch on pattern match PMS_DTE = 0x01, // deskew timer enable PMS_PMS_MASK = 0x06, // pattern mode specification PMS_IMO = 0x08, // interrupt on match only PMS_SB = 0x10, // single buffer PMS_ITB = 0x20, // interrupt on two bytes PMS_PTS_MASK = 0xc0 // port type select }; // port handshake specification registers enum { PHS_DTS_MASK = 0x07, // deskew time specification PHS_RWS_MASK = 0x38, // request/wait specification PHS_HTS_MASK = 0xc0 // handshake type specification }; // port command and status registers enum { PCS_IOE = 0x01, // interrupt on error PCS_PMF = 0x02, // pattern match flag (read only) PCS_IRF = 0x04, // input register full (read only) PCS_ORE = 0x08, // output register empty (read only) PCS_ERR = 0x10, // interrupt error (read only) PCS_IP = 0x20, // interrupt pending PCS_IE = 0x40, // interrupt enable PCS_IUS = 0x80 // interrupt under service }; // counter/timer mode specification registers enum { CTMS_DCS_MASK = 0x03, // output duty cycle CTMS_REB = 0x04, // retrigger enable bit CTMS_EDE = 0x08, // external gate enable CTMS_ETE = 0x10, // external trigger enable CTMS_ECE = 0x20, // external count enable CTMS_EOE = 0x40, // external output enable CTMS_CSC = 0x80 // continuous/single cycle }; // counter/timer command and status registers enum { CTCS_CIP = 0x01, // count in progress (read only) CTCS_TCB = 0x02, // trigger command bit (write only - read returns 0) CTCS_GCB = 0x04, // gate command bit CTCS_RCC = 0x08, // read counter control (read/set only - cleared by reading CCR LSB) CTCS_ERR = 0x10, // interrupt error (read only) CTCS_IP = 0x20, // interrupt pending CTCS_IE = 0x40, // interrupt enable CTCS_IUS = 0x80 // interrupt under service }; // interrupt control enum { IC_NULL = 0, IC_CLEAR_IP_IUS, IC_SET_IUS, IC_CLEAR_IUS, IC_SET_IP, IC_CLEAR_IP, IC_SET_IE, IC_CLEAR_IE }; // counter/timer link control enum { LC_INDEPENDENT = 0, LC_CT1_GATES_CT2, LC_CT1_TRIGGERS_CT2, LC_CT1_COUNTS_CT2 }; // port type select enum { PTS_BIT = 0, PTS_INPUT, PTS_OUTPUT, PTS_BIDIRECTIONAL }; // pattern mode specification enum { PMS_DISABLE = 0, PMS_AND, PMS_OR, PMS_OR_PEV }; // handshake specification enum { HTS_INTERLOCKED = 0, HTS_STROBED, HTS_PULSED, HTS_3_WIRE }; // request/wait specification enum { RWS_DISABLED = 0, RWS_OUTPUT_WAIT, RWS_INPUT_WAIT = 3, RWS_SPECIAL_REQUEST, RWS_OUTPUT_REQUEST, RWS_INPUT_REQUEST = 7 }; // pattern specification enum { BIT_MASKED_OFF = 0, ANY_TRANSITION, ZERO = 4, ONE, ONE_TO_ZERO, ZERO_TO_ONE }; // output duty cycle enum { DCS_PULSE, DCS_ONE_SHOT, DCS_SQUARE_WAVE, DCS_DO_NOT_USE }; void get_interrupt_vector(); void check_interrupt(); uint8_t read_register(offs_t offset); uint8_t read_register(offs_t offset, uint8_t mask); void write_register(offs_t offset, uint8_t data); void write_register(offs_t offset, uint8_t data, uint8_t mask); bool counter_enabled(device_timer_id id); bool counter_external_output(device_timer_id id); bool counter_external_count(device_timer_id id); bool counter_external_trigger(device_timer_id id); bool counter_external_gate(device_timer_id id); bool counter_gated(device_timer_id id); void count(device_timer_id id); void trigger(device_timer_id id); void gate(device_timer_id id, int state); void match_pattern(int port); void external_port_w(int port, int bit, int state); private: devcb_write_line m_write_irq; devcb_read8 m_read_pa; devcb_write8 m_write_pa; devcb_read8 m_read_pb; devcb_write8 m_write_pb; devcb_read8 m_read_pc; devcb_write8 m_write_pc; // interrupt state int m_irq; // register state uint8_t m_register[48]; // input/output port state uint8_t m_input[3]; uint8_t m_output[3]; uint8_t m_buffer[3]; uint8_t m_match[3]; // timers emu_timer *m_timer; uint16_t m_counter[3]; }; // ======================> z8036_device class z8036_device : public cio_base_device { public: // construction/destruction z8036_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); DECLARE_READ8_MEMBER( read ); DECLARE_WRITE8_MEMBER( write ); }; // ======================> z8536_device class z8536_device : public cio_base_device, public device_z80daisy_interface { public: // construction/destruction z8536_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); DECLARE_READ8_MEMBER( read ); DECLARE_WRITE8_MEMBER( write ); protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; // device_z80daisy_interface overrides virtual int z80daisy_irq_state() override; virtual int z80daisy_irq_ack() override; virtual void z80daisy_irq_reti() override; private: // control state machine bool m_state0; uint8_t m_pointer; }; // device type definition DECLARE_DEVICE_TYPE(Z8036, z8036_device) DECLARE_DEVICE_TYPE(Z8536, z8536_device) #endif // MAME_MACHINE_Z8536_H