diff options
Diffstat (limited to 'trunk/src/emu/machine/z8536.c')
-rw-r--r-- | trunk/src/emu/machine/z8536.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/z8536.c b/trunk/src/emu/machine/z8536.c new file mode 100644 index 00000000000..979dce43e91 --- /dev/null +++ b/trunk/src/emu/machine/z8536.c @@ -0,0 +1,596 @@ +/********************************************************************** + + Zilog Z8536 Counter/Timer and Parallel I/O emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "emu.h" +#include "z8536.h" +#include "machine/devhelpr.h" + + +// device type definition +const device_type Z8536 = &device_creator<z8536_device>; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +// states +enum +{ + STATE_RESET = -1, + STATE_0, + STATE_1 +}; + + +// ports +enum +{ + PORT_C = 0, + PORT_B, + PORT_A, + CONTROL +}; + + +// registers +enum +{ + MASTER_INTERRUPT_CONTROL = 0, + 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, + 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, + 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 +}; + + +// 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_VECTOR +}; + + +// 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 +}; + + +// master interrupt control register +#define MICR_RESET 0x01 // reset +#define MICR_RJA 0x02 // right justified address +#define MICR_CT_VIS 0x04 // counter/timer vector includes status +#define MICR_PB_VIS 0x08 // port B vector includes status +#define MICR_PA_VIS 0x10 // port A vector includes status +#define MICR_NV 0x20 // no vector +#define MICR_DLC 0x40 // disable lower chain +#define MICR_MIE 0x80 // master interrupt enable + + +// master configuration control register +#define MCCR_LC_MASK 0x03 // counter/timer link controls +#define MCCR_PAE 0x04 // port A enable +#define MCCR_PLC 0x08 // port link control +#define MCCR_PCE_CT3E 0x10 // port C and counter/timer 3 enable +#define MCCR_CT2E 0x20 // counter/timer 2 enable +#define MCCR_CT1E 0x40 // counter/timer 1 enable +#define MCCR_PBE 0x80 // port B enable + + +// port mode specification registers +#define PMS_LPM 0x01 // latch on pattern match +#define PMS_PMS_MASK 0x06 // pattern mode specification +#define PMS_IMO 0x08 // interrupt on match only +#define PMS_SB 0x10 // single buffer +#define PMS_ITB 0x20 // interrupt on two bytes +#define PMS_PTS_MASK 0xc0 // port type select + + +// port handshake specification registers +#define PHS_DTS_MASK 0x07 // deskew time specification +#define PHS_RWS_MASK 0x38 // request/wait specification +#define PHS_HTS_MASK 0xc0 // handshake type specification + + +// port command and status registers +#define PCS_IOE 0x01 // interrupt on error +#define PCS_PMF 0x02 // pattern match flag (read only) +#define PCS_IRF 0x04 // input register full (read only) +#define PCS_ORE 0x08 // output register empty (read only) +#define PCS_ERR 0x10 // interrupt error (read only) +#define PCS_IP 0x20 // interrupt pending +#define PCS_IE 0x40 // interrupt enable +#define PCS_IUS 0x80 // interrupt under service + + +// counter/timer mode specification registers +#define CTMS_DCS_MASK 0x03 // output duty cycle +#define CTMS_REB 0x04 // retrigger enable bit +#define CTMS_EDE 0x08 // external gate enable +#define CTMS_ETE 0x10 // external trigger enable +#define CTMS_ECE 0x20 // external count enable +#define CTMS_EOE 0x40 // external output enable +#define CTMS_CSC 0x80 // continuous single cycle + + +// counter/timer command and status registers +#define CTCS_CIP 0x01 // count in progress (read only) +#define CTCS_TCB 0x02 // trigger command bit (write only - read returns 0) +#define CTCS_GCB 0x04 // gate command bit +#define CTCS_RCC 0x08 // read counter control (read/set only - cleared by reading CCR LSB) +#define CTCS_ERR 0x10 // interrupt error (read only) +#define CTCS_IP 0x20 // interrupt pending +#define CTCS_IE 0x40 // interrupt enable +#define CTCS_IUS 0x80 // interrupt under service + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_register - read from register +//------------------------------------------------- + +inline UINT8 z8536_device::read_register(offs_t offset) +{ + UINT8 data = 0; + + data = m_register[offset]; // HACK + + switch (offset) + { + case PORT_A_DATA: + data = m_in_pa_func(0); + break; + + case PORT_B_DATA: + data = m_in_pb_func(0); + break; + + case PORT_C_DATA: + data = 0xf0 | (m_in_pc_func(0) & 0x0f); + break; + + default: + logerror("Z8536 '%s' Unimplemented read from register %u\n", tag(), offset); + } + + return data; +} + + +//------------------------------------------------- +// read_register - masked read from register +//------------------------------------------------- + +inline UINT8 z8536_device::read_register(offs_t offset, UINT8 mask) +{ + return read_register(offset) & mask; +} + + +//------------------------------------------------- +// write_register - write to register +//------------------------------------------------- + +inline void z8536_device::write_register(offs_t offset, UINT8 data) +{ + switch (offset) + { + case MASTER_INTERRUPT_CONTROL: + if (data & MICR_RESET) + { + device_reset(); + } + else if (m_state == STATE_RESET) + { + m_state = STATE_0; + } + break; + + case PORT_A_DATA: + m_out_pa_func(0, data); + break; + + case PORT_B_DATA: + m_out_pb_func(0, data); + break; + + case PORT_C_DATA: + { + UINT8 mask = (data & 0xf0) | (data >> 4); + + m_output[PORT_C] = (m_output[PORT_C] & mask) | ((data & 0x0f) & (mask ^ 0xff)); + + m_out_pc_func(0, m_output[PORT_C]); + } + break; + + default: + logerror("Z8536 '%s' Unimplemented write %02x to register %u\n", tag(), data, offset); + } + + m_register[offset] = data; // HACK +} + + +//------------------------------------------------- +// write_register - masked write to register +//------------------------------------------------- + +inline void z8536_device::write_register(offs_t offset, UINT8 data, UINT8 mask) +{ + UINT8 combined_data = (data & mask) | (m_register[offset] & (mask ^ 0xff)); + + write_register(offset, combined_data); +} + + +//------------------------------------------------- +// count - +//------------------------------------------------- + +inline void z8536_device::count(device_timer_id id) +{ +} + + +//------------------------------------------------- +// trigger - +//------------------------------------------------- + +inline void z8536_device::trigger(device_timer_id id) +{ +} + + +//------------------------------------------------- +// gate - +//------------------------------------------------- + +inline void z8536_device::gate(device_timer_id id) +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z8536_device - constructor +//------------------------------------------------- + +z8536_device::z8536_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z8536, "Zilog Z8536", tag, owner, clock) +{ +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void z8536_device::device_config_complete() +{ + // inherit a copy of the static data + const z8536_interface *intf = reinterpret_cast<const z8536_interface *>(static_config()); + if (intf != NULL) + *static_cast<z8536_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_out_int_cb, 0, sizeof(m_out_int_cb)); + memset(&m_in_pa_cb, 0, sizeof(m_in_pa_cb)); + memset(&m_out_pa_cb, 0, sizeof(m_out_pa_cb)); + memset(&m_in_pb_cb, 0, sizeof(m_in_pb_cb)); + memset(&m_out_pb_cb, 0, sizeof(m_out_pb_cb)); + memset(&m_in_pc_cb, 0, sizeof(m_in_pc_cb)); + memset(&m_out_pc_cb, 0, sizeof(m_out_pc_cb)); + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z8536_device::device_start() +{ + // allocate timers + m_timer[TIMER_1] = timer_alloc(TIMER_1); + m_timer[TIMER_2] = timer_alloc(TIMER_2); + m_timer[TIMER_3] = timer_alloc(TIMER_3); + + // resolve callbacks + m_out_int_func.resolve(m_out_int_cb, *this); + m_in_pa_func.resolve(m_in_pa_cb, *this); + m_out_pa_func.resolve(m_out_pa_cb, *this); + m_in_pb_func.resolve(m_in_pb_cb, *this); + m_out_pb_func.resolve(m_out_pb_cb, *this); + m_in_pc_func.resolve(m_in_pc_cb, *this); + m_out_pc_func.resolve(m_out_pc_cb, *this); +} + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void z8536_device::device_reset() +{ + m_state = STATE_RESET; + + for (int i = 0; i < 48; i++) + { + m_register[i] = 0; + } + + m_register[MASTER_INTERRUPT_CONTROL] = MICR_RESET; + m_pointer = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void z8536_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_1: + count(TIMER_1); + break; + + case TIMER_2: + count(TIMER_2); + break; + + case TIMER_3: + count(TIMER_3); + break; + } +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( z8536_device::read ) +{ + UINT8 data = 0; + + if (m_state == STATE_RESET) + { + // read RESET bit + data = read_register(m_pointer, 0x01); + } + else + { + switch (offset & 0x03) + { + case PORT_C: + data = read_register(PORT_C_DATA); + break; + + case PORT_B: + data = read_register(PORT_B_DATA); + break; + + case PORT_A: + data = read_register(PORT_A_DATA); + break; + + case CONTROL: + switch (m_state) + { + case STATE_1: + m_state = STATE_0; + // fallthru + case STATE_0: + data = read_register(m_pointer); + break; + } + break; + } + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( z8536_device::write ) +{ + if (m_state == STATE_RESET) + { + // write RESET bit + write_register(m_pointer, data, 0x01); + } + else + { + switch (offset & 0x03) + { + case PORT_C: + write_register(PORT_C_DATA, data); + break; + + case PORT_B: + write_register(PORT_B_DATA, data); + break; + + case PORT_A: + write_register(PORT_A_DATA, data); + break; + + case CONTROL: + switch (m_state) + { + case STATE_0: + m_pointer = data; + m_state = STATE_1; + break; + + case STATE_1: + write_register(m_pointer, data); + m_state = STATE_0; + } + break; + } + } +} + + +//------------------------------------------------- +// intack_w - interrupt acknowledge +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::intack_w ) +{ +} + + +//------------------------------------------------- +// pb*_w - port B bits 0-7 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::pb0_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb1_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb2_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb3_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb4_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb5_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb6_w ) { } +WRITE_LINE_MEMBER( z8536_device::pb7_w ) { } + + +//------------------------------------------------- +// pc*_w - port C bits 0-3 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::pc0_w ) { } +WRITE_LINE_MEMBER( z8536_device::pc1_w ) { } +WRITE_LINE_MEMBER( z8536_device::pc2_w ) { } +WRITE_LINE_MEMBER( z8536_device::pc3_w ) { } |