diff options
Diffstat (limited to 'trunk/src/emu/machine/z8536.c')
-rw-r--r-- | trunk/src/emu/machine/z8536.c | 1344 |
1 files changed, 1344 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..34b9a935b4e --- /dev/null +++ b/trunk/src/emu/machine/z8536.c @@ -0,0 +1,1344 @@ +/********************************************************************** + + Zilog Z8536 Counter/Timer and Parallel I/O emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +/* + + TODO: + + - interrupts + - vector + - status affects vector + - IE/IP/IUS + - acknowledge + - daisy chain + - port I/O + - counters/timers + +*/ + +#include "emu.h" +#include "z8536.h" +#include "machine/devhelpr.h" + + +// device type definition +const device_type Z8536 = &device_creator<z8536_device>; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +// 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 +}; + + +// 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 +}; + +static const char *PMS_PTS[] = { "Bit", "Input", "Output", "Bidirectional" }; + + +// pattern mode specification +enum +{ + PMS_DISABLE = 0, + PMS_AND, + PMS_OR, + PMS_OR_PEV +}; + +static const char *PMS_PMS[] = { "Disabled", "AND", "OR", "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 +}; + +static const char *CTMS_DCS[] = { "Pulse", "One-shot", "Square Wave", "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_DTE 0x01 // deskew timer enable +#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 +//************************************************************************** + +//------------------------------------------------- +// get_interrupt_vector - +//------------------------------------------------- + +inline void z8536_device::get_interrupt_vector() +{ + UINT8 vector = 0xff; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_MIE) + { + if ((m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) + { + vector = m_register[COUNTER_TIMER_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_CT_VIS) + { + vector = (vector & 0xf9) | 0; + } + } + else if ((m_register[PORT_A_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) + { + vector = m_register[PORT_A_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_PA_VIS) + { + vector &= 0xf1; + + if (((m_register[PORT_A_MODE_SPECIFICATION] & PMS_PMS_MASK) >> 1) == PMS_OR_PEV) + { + if (m_match[PORT_A] & 0x80) vector |= 7 << 1; + else if (m_match[PORT_A] & 0x40) vector |= 6 << 1; + else if (m_match[PORT_A] & 0x20) vector |= 5 << 1; + else if (m_match[PORT_A] & 0x10) vector |= 4 << 1; + else if (m_match[PORT_A] & 0x08) vector |= 3 << 1; + else if (m_match[PORT_A] & 0x04) vector |= 2 << 1; + else if (m_match[PORT_A] & 0x02) vector |= 1 << 1; + else if (m_match[PORT_A] & 0x01) vector |= 0 << 1; + } + else + { + vector |= (m_register[PORT_A_COMMAND_AND_STATUS] & 0x0e); + } + } + } + else if ((m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) + { + vector = m_register[COUNTER_TIMER_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_CT_VIS) + { + vector = (vector & 0xf9) | 2; + } + } + else if ((m_register[PORT_B_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) + { + vector = m_register[PORT_B_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_PB_VIS) + { + vector &= 0xf1; + + if (((m_register[PORT_B_MODE_SPECIFICATION] & PMS_PMS_MASK) >> 1) == PMS_OR_PEV) + { + if (m_match[PORT_B] & 0x80) vector |= 7 << 1; + else if (m_match[PORT_B] & 0x40) vector |= 6 << 1; + else if (m_match[PORT_B] & 0x20) vector |= 5 << 1; + else if (m_match[PORT_B] & 0x10) vector |= 4 << 1; + else if (m_match[PORT_B] & 0x08) vector |= 3 << 1; + else if (m_match[PORT_B] & 0x04) vector |= 2 << 1; + else if (m_match[PORT_B] & 0x02) vector |= 1 << 1; + else if (m_match[PORT_B] & 0x01) vector |= 0 << 1; + } + else + { + vector |= (m_register[PORT_B_COMMAND_AND_STATUS] & 0x0e); + } + } + } + else if ((m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) + { + vector = m_register[COUNTER_TIMER_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_CT_VIS) + { + vector = (vector & 0xf9) | 4; + } + } + } + + m_register[CURRENT_VECTOR] = vector; +} + + +//------------------------------------------------- +// check_interrupt - check interrupt status +//------------------------------------------------- + +inline void z8536_device::check_interrupt() +{ + int state = ASSERT_LINE; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_MIE) + { + if (((m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) || + ((m_register[PORT_A_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) || + ((m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) || + ((m_register[PORT_B_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) || + ((m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE))) + { + state = ASSERT_LINE; + } + else + { + state = CLEAR_LINE; + } + } + else + { + state = CLEAR_LINE; + } + + if (m_int != state) + { + if (LOG) logerror("%s Z8536 '%s' Interrupt: %u\n", machine().describe_context(), tag(), state); + m_int = state; + m_out_int_func(state); + } +} + + +//------------------------------------------------- +// read_register - read from register +//------------------------------------------------- + +inline UINT8 z8536_device::read_register(offs_t offset) +{ + UINT8 data = 0; + + 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; + + case COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE: + case COUNTER_TIMER_2_CURRENT_COUNT_MS_BYTE: + case COUNTER_TIMER_3_CURRENT_COUNT_MS_BYTE: + { + int timer = (offset - COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE) >> 1; + + if (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + timer] & CTCS_RCC) + { + // read frozen value + data = m_register[offset]; + } + else + { + // read current count + data = m_counter[timer] >> 8; + } + } + break; + + case COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE: + case COUNTER_TIMER_2_CURRENT_COUNT_LS_BYTE: + case COUNTER_TIMER_3_CURRENT_COUNT_LS_BYTE: + { + int timer = (offset - COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE) >> 1; + + if (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + timer] & CTCS_RCC) + { + // read frozen value + data = m_register[offset]; + } + else + { + // read current count + data = m_counter[timer] & 0xff; + } + + // clear RCC bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + timer] &= ~CTCS_RCC; + } + break; + + case CURRENT_VECTOR: + get_interrupt_vector(); + data = m_register[offset]; + break; + + default: + data = m_register[offset]; + break; + } + + 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) + { + if (LOG) logerror("%s Z8536 '%s' Reset\n", machine().describe_context(), tag()); + device_reset(); + } + else + { + if (m_state == STATE_RESET) + { + m_state = STATE_0; + } + + if (LOG) + { + if (LOG) logerror("%s Z8536 '%s' Master Interrupt Enable: %u\n", machine().describe_context(), tag(), (data & MICR_MIE) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Disable Lower Chain: %u\n", machine().describe_context(), tag(), (data & MICR_DLC) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' No Vector: %u\n", machine().describe_context(), tag(), (data & MICR_NV) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port A Vector Includes Status: %u\n", machine().describe_context(), tag(), (data & MICR_PA_VIS) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port B Vector Includes Status: %u\n", machine().describe_context(), tag(), (data & MICR_PB_VIS) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer Vector Includes Status: %u\n", machine().describe_context(), tag(), (data & MICR_CT_VIS) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Right Justified Address: %u\n", machine().describe_context(), tag(), (data & MICR_RJA) ? 1 : 0); + } + + m_register[offset] = data; + } + break; + + case MASTER_CONFIGURATION_CONTROL: + if (LOG) + { + if (LOG) logerror("%s Z8536 '%s' Port B Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_PBE) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer 1 Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_CT1E) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer 2 Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_CT2E) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port C and Counter/Timer 3 Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_PCE_CT3E) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port A Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_PAE) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port Link Control: %u\n", machine().describe_context(), tag(), (data & MCCR_PLC) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer Link Controls: %u\n", machine().describe_context(), tag(), data & MCCR_LC_MASK); + } + + m_register[offset] = data; + + for (int counter = 0; counter < 3; counter++) + { + // clear RCC bit if counter disabled + if (!counter_enabled(counter)) m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + counter] &= ~CTCS_RCC; + } + break; + + case PORT_A_INTERRUPT_VECTOR: + if (LOG) logerror("%s Z8536 '%s' Port A Interrupt Vector: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_B_INTERRUPT_VECTOR: + if (LOG) logerror("%s Z8536 '%s' Port B Interrupt Vector: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case COUNTER_TIMER_INTERRUPT_VECTOR: + if (LOG) logerror("%s Z8536 '%s' Counter/Timer Interrupt Vector: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_C_DATA_PATH_POLARITY: + if (LOG) logerror("%s Z8536 '%s' Port C Data Path Polarity: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_C_DATA_DIRECTION: + if (LOG) logerror("%s Z8536 '%s' Port C Data Direction: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_C_SPECIAL_IO_CONTROL: + if (LOG) logerror("%s Z8536 '%s' Port C Special I/O Control: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_A_COMMAND_AND_STATUS: + case PORT_B_COMMAND_AND_STATUS: + { + char port = 'A' + offset - PORT_A_COMMAND_AND_STATUS; + + if (LOG) logerror("%s Z8536 '%s' Port %c Interrupt on Error: %u\n", machine().describe_context(), tag(), port, (data & PCS_IOE) ? 1 : 0); + + switch (data >> 5) + { + case IC_CLEAR_IP_IUS: m_register[offset] &= ~(PCS_IP | PCS_IUS); if (LOG) logerror("%s Z8536 '%s' Port %c Clear IP/IUS\n", machine().describe_context(), tag(), port); break; + case IC_SET_IUS: m_register[offset] |= PCS_IUS; if (LOG) logerror("%s Z8536 '%s' Port %c Set IUS\n", machine().describe_context(), tag(), port); break; + case IC_CLEAR_IUS: m_register[offset] &= ~PCS_IUS; if (LOG) logerror("%s Z8536 '%s' Port %c Clear IUS\n", machine().describe_context(), tag(), port); break; + case IC_SET_IP: m_register[offset] |= PCS_IP; if (LOG) logerror("%s Z8536 '%s' Port %c Set IP\n", machine().describe_context(), tag(), port); break; + case IC_CLEAR_IP: m_register[offset] &= ~PCS_IP; if (LOG) logerror("%s Z8536 '%s' Port %c Clear IP\n", machine().describe_context(), tag(), port); break; + case IC_SET_IE: m_register[offset] |= PCS_IE; if (LOG) logerror("%s Z8536 '%s' Port %c Set IE\n", machine().describe_context(), tag(), port); break; + case IC_CLEAR_IE: m_register[offset] &= ~PCS_IE; if (LOG) logerror("%s Z8536 '%s' Port %c Clear IE\n", machine().describe_context(), tag(), port); break; + } + + m_register[offset] = (m_register[offset] & ~PCS_IOE) | (data & PCS_IOE); + + match_pattern(offset - PORT_A_COMMAND_AND_STATUS); + check_interrupt(); + } + break; + + case COUNTER_TIMER_1_COMMAND_AND_STATUS: + case COUNTER_TIMER_2_COMMAND_AND_STATUS: + case COUNTER_TIMER_3_COMMAND_AND_STATUS: + { + int counter = offset - COUNTER_TIMER_1_COMMAND_AND_STATUS; + + if (LOG) + { + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Trigger Command Bit: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTCS_TCB) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Gate Command Bit: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTCS_GCB) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Read Counter Control: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTCS_RCC) ? 1 : 0); + } + + switch (data >> 5) + { + case IC_CLEAR_IP_IUS: m_register[offset] &= ~(CTCS_IP | CTCS_IUS);if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IP/IUS\n", machine().describe_context(), tag(), counter + 1); break; + case IC_SET_IUS: m_register[offset] |= CTCS_IUS; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Set IUS\n", machine().describe_context(), tag(), counter + 1); break; + case IC_CLEAR_IUS: m_register[offset] &= ~CTCS_IUS; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IUS\n", machine().describe_context(), tag(), counter + 1); break; + case IC_SET_IP: m_register[offset] |= CTCS_IP; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Set IP\n", machine().describe_context(), tag(), counter + 1); break; + case IC_CLEAR_IP: m_register[offset] &= ~CTCS_IP; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IP\n", machine().describe_context(), tag(), counter + 1); break; + case IC_SET_IE: m_register[offset] |= CTCS_IE; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Set IE\n", machine().describe_context(), tag(), counter + 1); break; + case IC_CLEAR_IE: m_register[offset] &= ~CTCS_IE; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IE\n", machine().describe_context(), tag(), counter + 1); break; + } + + // gate command bit + m_register[offset] = (m_register[offset] & ~CTCS_GCB) | (data & CTCS_GCB); + + // trigger command bit + if (data & CTCS_TCB) + { + trigger(counter); + } + + // read counter control + if (counter_enabled(counter) && (data & CTCS_RCC)) + { + // freeze current count register + m_register[offset] |= CTCS_RCC; + m_register[COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE + (counter << 1)] = m_counter[counter] >> 8; + m_register[COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE + (counter << 1)] = m_counter[counter] & 0xff; + } + + check_interrupt(); + } + 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; + + case COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE: + case COUNTER_TIMER_2_TIME_CONSTANT_MS_BYTE: + case COUNTER_TIMER_3_TIME_CONSTANT_MS_BYTE: + if (LOG) + { + int counter = (offset - COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE) >> 1; + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Time Constant MSB: %02x\n", machine().describe_context(), tag(), counter + 1, data); + } + + m_register[offset] = data; + break; + + case COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE: + case COUNTER_TIMER_2_TIME_CONSTANT_LS_BYTE: + case COUNTER_TIMER_3_TIME_CONSTANT_LS_BYTE: + if (LOG) + { + int counter = (offset - COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE) >> 1; + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Time Constant LSB: %02x\n", machine().describe_context(), tag(), counter + 1, data); + } + + m_register[offset] = data; + break; + + case COUNTER_TIMER_1_MODE_SPECIFICATION: + case COUNTER_TIMER_2_MODE_SPECIFICATION: + case COUNTER_TIMER_3_MODE_SPECIFICATION: + if (LOG) + { + int counter = offset - COUNTER_TIMER_1_MODE_SPECIFICATION; + int dcs = data & CTMS_DCS_MASK; + + logerror("%s Z8536 '%s' Counter/Timer %u Mode: %s\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_CSC) ? "Continuous" : "Single Cycle"); + logerror("%s Z8536 '%s' Counter/Timer %u External Output Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_EOE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u External Count Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_ECE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u External Trigger Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_ETE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u External Gate Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_EDE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u Retrigger Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_REB) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u Output Duty Cycle: %s\n", machine().describe_context(), tag(), counter + 1, CTMS_DCS[dcs]); + } + + m_register[offset] = data; + break; + + case PORT_A_MODE_SPECIFICATION: + case PORT_B_MODE_SPECIFICATION: + if (LOG) + { + char port = BIT(offset, 3) ? 'B' : 'A'; + int pts = (data & PMS_PTS_MASK) >> 6; + int pms = (data & PMS_PMS_MASK) >> 1; + + logerror("%s Z8536 '%s' Port %c Port Type: %s\n", machine().describe_context(), tag(), port, PMS_PTS[pts]); + logerror("%s Z8536 '%s' Port %c Interrupt on 2 Bytes: %u\n", machine().describe_context(), tag(), port, (data & PMS_ITB) ? 1 : 0); + logerror("%s Z8536 '%s' Port %c Single Buffer: %u\n", machine().describe_context(), tag(), port, (data & PMS_SB) ? 1 : 0); + logerror("%s Z8536 '%s' Port %c Interrupt on Match Only: %u\n", machine().describe_context(), tag(), port, (data & PMS_IMO) ? 1 : 0); + logerror("%s Z8536 '%s' Port %c Pattern Mode: %s\n", machine().describe_context(), tag(), port, PMS_PMS[pms]); + + if (pts == PTS_BIT) + logerror("%s Z8536 '%s' Port %c Latch on Pattern Match: %u\n", machine().describe_context(), tag(), port, (data & PMS_LPM) ? 1 : 0); + else + logerror("%s Z8536 '%s' Port %c Deskew Timer Enable: %u\n", machine().describe_context(), tag(), port, (data & PMS_DTE) ? 1 : 0); + } + + m_register[offset] = data; + break; + + case PORT_A_HANDSHAKE_SPECIFICATION: + case PORT_B_HANDSHAKE_SPECIFICATION: + // TODO + break; + + case PORT_A_DATA_PATH_POLARITY: + case PORT_B_DATA_PATH_POLARITY: + if (LOG) logerror("%s Z8536 '%s' Port %c Data Path Polarity: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_DATA_DIRECTION: + case PORT_B_DATA_DIRECTION: + if (LOG) logerror("%s Z8536 '%s' Port %c Data Direction: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_SPECIAL_IO_CONTROL: + case PORT_B_SPECIAL_IO_CONTROL: + if (LOG) logerror("%s Z8536 '%s' Port %c Special I/O Control: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_PATTERN_POLARITY: + case PORT_B_PATTERN_POLARITY: + if (LOG) logerror("%s Z8536 '%s' Port %c Pattern Polarity: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_PATTERN_TRANSITION: + case PORT_B_PATTERN_TRANSITION: + if (LOG) logerror("%s Z8536 '%s' Port %c Pattern Transition: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_PATTERN_MASK: + case PORT_B_PATTERN_MASK: + if (LOG) logerror("%s Z8536 '%s' Port %c Pattern Mask: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + match_pattern(BIT(offset, 3)); + check_interrupt(); + break; + + default: + logerror("%s: Z8536 '%s' Unimplemented write %02x to register %u\n", machine().describe_context(), tag(), data, offset); + m_register[offset] = data; + } +} + + +//------------------------------------------------- +// 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); +} + + +//------------------------------------------------- +// counter_enabled - is counter enabled? +//------------------------------------------------- + +inline bool z8536_device::counter_enabled(device_timer_id id) +{ + bool enabled = false; + + switch (id) + { + case TIMER_1: + enabled = (m_register[MASTER_CONFIGURATION_CONTROL] & MCCR_CT1E) ? true : false; + break; + + case TIMER_2: + enabled = (m_register[MASTER_CONFIGURATION_CONTROL] & MCCR_CT2E) ? true : false; + break; + + case TIMER_3: + enabled = (m_register[MASTER_CONFIGURATION_CONTROL] & MCCR_PCE_CT3E) ? true : false; + break; + } + + return enabled; +} + + +//------------------------------------------------- +// counter_external_output - +//------------------------------------------------- + +inline bool z8536_device::counter_external_output(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_EOE) ? true : false; +} + + +//------------------------------------------------- +// counter_external_count - +//------------------------------------------------- + +inline bool z8536_device::counter_external_count(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_ECE) ? true : false; +} + + +//------------------------------------------------- +// counter_external_trigger - +//------------------------------------------------- + +inline bool z8536_device::counter_external_trigger(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_ETE) ? true : false; +} + + +//------------------------------------------------- +// counter_external_gate - +//------------------------------------------------- + +inline bool z8536_device::counter_external_gate(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_EDE) ? true : false; +} + + +//------------------------------------------------- +// counter_gated - +//------------------------------------------------- + +inline bool z8536_device::counter_gated(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_GCB) ? true : false; +} + + +//------------------------------------------------- +// count - count down +//------------------------------------------------- + +inline void z8536_device::count(device_timer_id id) +{ + if (!counter_gated(id)) return; + if (!m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_CIP) return; + + // count down + m_counter[id]--; + + if (m_counter[id] == 0) + { + if (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_IP) + { + // set interrupt error bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] |= CTCS_ERR; + } + else + { + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Interrupt Pending\n", machine().describe_context(), tag(), id + 1); + + // set interrupt pending bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] |= CTCS_IP; + } + + if (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_CSC) + { + // reload counter with time constant + m_counter[id] = (m_register[COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE + (id << 1)] << 8) | m_register[COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE + (id << 1)]; + } + else + { + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Terminal Count\n", machine().describe_context(), tag(), id + 1); + + // clear count in progress bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] &= ~CTCS_CIP; + } + + check_interrupt(); + } +} + + +//------------------------------------------------- +// trigger - +//------------------------------------------------- + +inline void z8536_device::trigger(device_timer_id id) +{ + // ignore triggers during countdown if retrigger is disabled + if (!(m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_REB) && (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_CIP)) return; + + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Trigger\n", machine().describe_context(), tag(), id + 1); + + // load counter with time constant + m_counter[id] = (m_register[COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE + (id << 1)] << 8) | m_register[COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE + (id << 1)]; + + // set count in progress bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] |= CTCS_CIP; +} + + +//------------------------------------------------- +// gate - +//------------------------------------------------- + +inline void z8536_device::gate(device_timer_id id, int state) +{ + // TODO +} + + +//------------------------------------------------- +// match_pattern - +//------------------------------------------------- + +inline void z8536_device::match_pattern(int port) +{ + UINT8 pms = m_register[PORT_A_MODE_SPECIFICATION + (port << 3)]; + UINT8 pm = m_register[PORT_A_PATTERN_MASK + (port << 3)]; + UINT8 ddr = m_register[PORT_A_DATA_DIRECTION + (port << 3)]; + + switch ((pms & PMS_PMS_MASK) >> 1) + { + case PMS_OR_PEV: + m_match[port] = m_input[port] & ddr & pm; + + if (m_match[port]) + { + if (LOG) logerror("%s Z8536 '%s' Port %c Interrupt Pending\n", machine().describe_context(), tag(), 'A' + port); + m_register[PORT_A_COMMAND_AND_STATUS + port] |= PCS_IP; + check_interrupt(); + } + break; + } +} + + +//------------------------------------------------- +// external_port_w - external port write +//------------------------------------------------- + +inline void z8536_device::external_port_w(int port, int bit, int state) +{ + switch (port) + { + case PORT_A: + case PORT_B: + { + UINT8 ddr = m_register[PORT_A_DATA_DIRECTION + (port << 3)]; + + if (!BIT(ddr, bit)) return; + + if (LOG) logerror("%s Z8536 '%s' Port %c Bit %u: %u\n", machine().describe_context(), tag(), 'A' + port, bit, state); + + m_input[port] = (m_input[port] & ~(1 << bit)) | (state << bit); + + match_pattern(port); + } + break; + + case PORT_C: + break; + } +} + + + +//************************************************************************** +// 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_z80daisy_interface(mconfig, *this), + m_int(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// 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() +{ + for (int i = 0; i < 3; i++) + { + m_input[i] = 0; + m_output[i] = 0; + m_buffer[i] = 0; + m_match[i] = 0; + } + + // allocate timer + m_timer = timer_alloc(); + m_timer->adjust(attotime::from_hz(clock() / 2), 0, attotime::from_hz(clock() / 2)); + + // 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_register[PORT_A_COMMAND_AND_STATUS] = PCS_ORE; + m_register[PORT_B_COMMAND_AND_STATUS] = PCS_ORE; + m_register[CURRENT_VECTOR] = 0xff; + + m_pointer = 0; + + check_interrupt(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void z8536_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (counter_enabled(TIMER_1) && !counter_external_count(TIMER_1)) + { + count(TIMER_1); + } + + if (counter_enabled(TIMER_2) && !counter_external_count(TIMER_2)) + { + count(TIMER_2); + } + + if (counter_enabled(TIMER_3) && !counter_external_count(TIMER_3)) + { + count(TIMER_3); + } +} + + + +//************************************************************************** +// DAISY CHAIN INTERFACE +//************************************************************************** + +//------------------------------------------------- +// z80daisy_irq_state - return the overall IRQ +// state for this device +//------------------------------------------------- + +int z8536_device::z80daisy_irq_state() +{ + return 0; +} + + +//------------------------------------------------- +// z80daisy_irq_ack - acknowledge an IRQ and +// return the appropriate vector +//------------------------------------------------- + +int z8536_device::z80daisy_irq_ack() +{ + return intack_r(); +} + + +//------------------------------------------------- +// z80daisy_irq_reti - clear the interrupt +// pending state to allow other interrupts through +//------------------------------------------------- + +void z8536_device::z80daisy_irq_reti() +{ +} + + + +//************************************************************************** +// INTERNAL STATE MANAGEMENT +//************************************************************************** + +//------------------------------------------------- +// 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_r - interrupt acknowledge +//------------------------------------------------- + +int z8536_device::intack_r() +{ + get_interrupt_vector(); + int data = m_register[CURRENT_VECTOR]; + + if (LOG) logerror("%s Z8536 '%s' Interrupt Acknowledge: %02x\n", machine().describe_context(), tag(), data); + + // set interrupt under service bit + if ((m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE)) == (CTCS_IP | CTCS_IE)) + { + m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] |= CTCS_IUS; + } + else if ((m_register[PORT_A_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE)) == (PCS_IP | PCS_IE)) + { + m_register[PORT_A_COMMAND_AND_STATUS] |= PCS_IUS; + } + else if ((m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE)) == (CTCS_IP | CTCS_IE)) + { + m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] |= CTCS_IUS; + } + else if ((m_register[PORT_B_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE)) == (PCS_IP | PCS_IE)) + { + m_register[PORT_B_COMMAND_AND_STATUS] |= PCS_IUS; + } + else if ((m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE)) == (CTCS_IP | CTCS_IE)) + { + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] |= CTCS_IUS; + } + + check_interrupt(); + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_NV) + { + // no vector + data = -1; + } + + return data; +} + + +//------------------------------------------------- +// pa*_w - port A bits 0-7 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::pa0_w ) { external_port_w(PORT_A, 0, state); } +WRITE_LINE_MEMBER( z8536_device::pa1_w ) { external_port_w(PORT_A, 1, state); } +WRITE_LINE_MEMBER( z8536_device::pa2_w ) { external_port_w(PORT_A, 2, state); } +WRITE_LINE_MEMBER( z8536_device::pa3_w ) { external_port_w(PORT_A, 3, state); } +WRITE_LINE_MEMBER( z8536_device::pa4_w ) { external_port_w(PORT_A, 4, state); } +WRITE_LINE_MEMBER( z8536_device::pa5_w ) { external_port_w(PORT_A, 5, state); } +WRITE_LINE_MEMBER( z8536_device::pa6_w ) { external_port_w(PORT_A, 6, state); } +WRITE_LINE_MEMBER( z8536_device::pa7_w ) { external_port_w(PORT_A, 7, state); } + + +//------------------------------------------------- +// pb*_w - port B bits 0-7 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::pb0_w ) { external_port_w(PORT_B, 0, state); } +WRITE_LINE_MEMBER( z8536_device::pb1_w ) { external_port_w(PORT_B, 1, state); } +WRITE_LINE_MEMBER( z8536_device::pb2_w ) { external_port_w(PORT_B, 2, state); } +WRITE_LINE_MEMBER( z8536_device::pb3_w ) { external_port_w(PORT_B, 3, state); } +WRITE_LINE_MEMBER( z8536_device::pb4_w ) { external_port_w(PORT_B, 4, state); } +WRITE_LINE_MEMBER( z8536_device::pb5_w ) { external_port_w(PORT_B, 5, state); } +WRITE_LINE_MEMBER( z8536_device::pb6_w ) { external_port_w(PORT_B, 6, state); } +WRITE_LINE_MEMBER( z8536_device::pb7_w ) { external_port_w(PORT_B, 7, state); } + + +//------------------------------------------------- +// pc*_w - port C bits 0-3 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( z8536_device::pc0_w ) { external_port_w(PORT_C, 0, state); } +WRITE_LINE_MEMBER( z8536_device::pc1_w ) { external_port_w(PORT_C, 1, state); } +WRITE_LINE_MEMBER( z8536_device::pc2_w ) { external_port_w(PORT_C, 2, state); } +WRITE_LINE_MEMBER( z8536_device::pc3_w ) { external_port_w(PORT_C, 3, state); } |