/********************************************************************** Motorola 6821 PIA interface and emulation **********************************************************************/ #include "6821new.h" /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ typedef struct _pia6821 pia6821; struct _pia6821 { UINT8 in_a; UINT8 in_ca1; UINT8 in_ca2; UINT8 out_a; UINT8 out_ca2; UINT8 port_a_z_mask; UINT8 ddr_a; UINT8 ctl_a; UINT8 irq_a1; UINT8 irq_a2; UINT8 irq_a_state; UINT8 in_b; UINT8 in_cb1; UINT8 in_cb2; UINT8 out_b; UINT8 out_cb2; UINT8 last_out_cb2_z; UINT8 ddr_b; UINT8 ctl_b; UINT8 irq_b1; UINT8 irq_b2; UINT8 irq_b_state; /* variables that indicate if access a line externally - used to for logging purposes ONLY */ UINT8 in_a_pushed; UINT8 out_a_needs_pulled; UINT8 in_ca1_pushed; UINT8 in_ca2_pushed; UINT8 out_ca2_needs_pulled; UINT8 in_b_pushed; UINT8 out_b_needs_pulled; UINT8 in_cb1_pushed; UINT8 in_cb2_pushed; UINT8 out_cb2_needs_pulled; UINT8 logged_port_a_not_connected; UINT8 logged_port_b_not_connected; UINT8 logged_ca1_not_connected; UINT8 logged_ca2_not_connected; UINT8 logged_cb1_not_connected; UINT8 logged_cb2_not_connected; }; /*************************************************************************** MACROS ***************************************************************************/ #define VERBOSE 0 #define LOG(x) do { if (VERBOSE) logerror x; } while (0) #define PIA_IRQ1 (0x80) #define PIA_IRQ2 (0x40) #define IRQ1_ENABLED(c) ( (((c) >> 0) & 0x01)) #define C1_LOW_TO_HIGH(c) ( (((c) >> 1) & 0x01)) #define C1_HIGH_TO_LOW(c) (!(((c) >> 1) & 0x01)) #define OUTPUT_SELECTED(c) ( (((c) >> 2) & 0x01)) #define IRQ2_ENABLED(c) ( (((c) >> 3) & 0x01)) #define STROBE_E_RESET(c) ( (((c) >> 3) & 0x01)) #define STROBE_C1_RESET(c) (!(((c) >> 3) & 0x01)) #define C2_SET(c) ( (((c) >> 3) & 0x01)) #define C2_LOW_TO_HIGH(c) ( (((c) >> 4) & 0x01)) #define C2_HIGH_TO_LOW(c) (!(((c) >> 4) & 0x01)) #define C2_SET_MODE(c) ( (((c) >> 4) & 0x01)) #define C2_STROBE_MODE(c) (!(((c) >> 4) & 0x01)) #define C2_OUTPUT(c) ( (((c) >> 5) & 0x01)) #define C2_INPUT(c) (!(((c) >> 5) & 0x01)) /*************************************************************************** PROTOTYPES ***************************************************************************/ /*************************************************************************** INLINE FUNCTIONS ***************************************************************************/ INLINE pia6821 *get_token(const device_config *device) { assert(device != NULL); assert((device->type == PIA6821) || (device->type == PIA6822)); return (pia6821 *) device->token; } INLINE const pia6821_interface *get_interface(const device_config *device) { assert(device != NULL); assert((device->type == PIA6821) || (device->type == PIA6822)); return (const pia6821_interface *) device->static_config; } /*************************************************************************** IMPLEMENTATION ***************************************************************************/ /*------------------------------------------------- DEVICE_START( pia ) -------------------------------------------------*/ static DEVICE_START( pia ) { pia6821 *p = get_token(device); memset(p, 0, sizeof(*p)); state_save_register_device_item(device, 0, p->in_a); state_save_register_device_item(device, 0, p->in_ca1); state_save_register_device_item(device, 0, p->in_ca2); state_save_register_device_item(device, 0, p->out_a); state_save_register_device_item(device, 0, p->out_ca2); state_save_register_device_item(device, 0, p->port_a_z_mask); state_save_register_device_item(device, 0, p->ddr_a); state_save_register_device_item(device, 0, p->ctl_a); state_save_register_device_item(device, 0, p->irq_a1); state_save_register_device_item(device, 0, p->irq_a2); state_save_register_device_item(device, 0, p->irq_a_state); state_save_register_device_item(device, 0, p->in_b); state_save_register_device_item(device, 0, p->in_cb1); state_save_register_device_item(device, 0, p->in_cb2); state_save_register_device_item(device, 0, p->out_b); state_save_register_device_item(device, 0, p->out_cb2); state_save_register_device_item(device, 0, p->last_out_cb2_z); state_save_register_device_item(device, 0, p->ddr_b); state_save_register_device_item(device, 0, p->ctl_b); state_save_register_device_item(device, 0, p->irq_b1); state_save_register_device_item(device, 0, p->irq_b2); state_save_register_device_item(device, 0, p->irq_b_state); state_save_register_device_item(device, 0, p->in_a_pushed); state_save_register_device_item(device, 0, p->out_a_needs_pulled); state_save_register_device_item(device, 0, p->in_ca1_pushed); state_save_register_device_item(device, 0, p->in_ca2_pushed); state_save_register_device_item(device, 0, p->out_ca2_needs_pulled); state_save_register_device_item(device, 0, p->in_b_pushed); state_save_register_device_item(device, 0, p->out_b_needs_pulled); state_save_register_device_item(device, 0, p->in_cb1_pushed); state_save_register_device_item(device, 0, p->in_cb2_pushed); state_save_register_device_item(device, 0, p->out_cb2_needs_pulled); return DEVICE_START_OK; } /*------------------------------------------------- DEVICE_RESET( pia ) -------------------------------------------------*/ static DEVICE_RESET( pia ) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); memset(p, 0, sizeof(*p)); /* * set default read values. * * ports A,CA1,CA2 default to 1 * ports B,CB1,CB2 are three-state and undefined (set to 0) */ p->in_a = 0xff; p->in_ca1 = TRUE; p->in_ca2 = TRUE; /* clear the IRQs */ if (intf->irq_a_func) (*intf->irq_a_func)(device, FALSE); if (intf->irq_b_func) (*intf->irq_b_func)(device, FALSE); } /*------------------------------------------------- update_interrupts -------------------------------------------------*/ static void update_interrupts(const device_config *device) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); int new_state; /* start with IRQ A */ new_state = (p->irq_a1 && IRQ1_ENABLED(p->ctl_a)) || (p->irq_a2 && IRQ2_ENABLED(p->ctl_a)); if (new_state != p->irq_a_state) { p->irq_a_state = new_state; if (intf->irq_a_func) (*intf->irq_a_func)(device, p->irq_a_state); } /* then do IRQ B */ new_state = (p->irq_b1 && IRQ1_ENABLED(p->ctl_b)) || (p->irq_b2 && IRQ2_ENABLED(p->ctl_b)); if (new_state != p->irq_b_state) { p->irq_b_state = new_state; if (intf->irq_b_func) (*intf->irq_b_func)(device, p->irq_b_state); } } /*------------------------------------------------- get_in_a_value -------------------------------------------------*/ static UINT8 get_in_a_value(const device_config *device) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); UINT8 port_a_data = 0; UINT8 ret; /* update the input */ if (intf->in_a_func) port_a_data = (*intf->in_a_func)(device, 0); else { if (p->in_a_pushed) port_a_data = p->in_a; else { /* mark all pins disconnected */ p->port_a_z_mask = 0xff; if (!p->logged_port_a_not_connected && (p->ddr_a != 0xff)) { logerror("PIA #%s: Warning! No port A read handler. Assuming pins 0x%02X not connected\n", device->tag, p->ddr_a ^ 0xff); p->logged_port_a_not_connected = TRUE; } } } /* - connected pins are always read - disconnected pins read the output buffer in output mode - disconnected pins are HI in input mode */ ret = (~p->port_a_z_mask & port_a_data) | ( p->port_a_z_mask & p->ddr_a & p->out_a) | ( p->port_a_z_mask & ~p->ddr_a); return ret; } /*------------------------------------------------- get_in_b_value -------------------------------------------------*/ static UINT8 get_in_b_value(const device_config *device) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); UINT8 ret; if (p->ddr_b == 0xff) /* all output, just return buffer */ ret = p->out_b; else { UINT8 port_b_data; /* update the input */ if (intf->in_b_func) port_b_data = (*intf->in_b_func)(device, 0); else { if (p->in_b_pushed) port_b_data = p->in_b; else { if (!p->logged_port_b_not_connected && (p->ddr_b != 0xff)) { logerror("PIA #%s: Error! No port B read handler. Three-state pins 0x%02X are undefined\n", device->tag, p->ddr_b ^ 0xff); p->logged_port_b_not_connected = TRUE; } /* undefined -- need to return something */ port_b_data = 0x00; } } /* the DDR determines if the pin or the output buffer is read */ ret = (p->out_b & p->ddr_b) | (port_b_data & ~p->ddr_b); } return ret; } /*------------------------------------------------- get_out_a_value -------------------------------------------------*/ static UINT8 get_out_a_value(const device_config *device) { pia6821 *p = get_token(device); UINT8 ret; if (p->ddr_a == 0xff) /* all output */ ret = p->out_a; else /* input pins don't change */ ret = (p->out_a & p->ddr_a) | (get_in_a_value(device) & ~p->ddr_a); return ret; } /*------------------------------------------------- get_out_b_value -------------------------------------------------*/ static UINT8 get_out_b_value(const device_config *device) { pia6821 *p = get_token(device); /* input pins are high-impedance - we just send them as zeros for backwards compatibility */ return p->out_b & p->ddr_b; } /*------------------------------------------------- set_out_ca2 -------------------------------------------------*/ static void set_out_ca2(const device_config *device, int data) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); if (data != p->out_ca2) { p->out_ca2 = data; /* send to output function */ if (intf->out_ca2_func) (*intf->out_ca2_func)(device, 0, p->out_ca2); else { if (p->out_ca2_needs_pulled) logerror("PIA #%s: Warning! No port CA2 write handler. Previous value has been lost!\n", device->tag); p->out_ca2_needs_pulled = TRUE; } } } /*------------------------------------------------- set_out_cb2 -------------------------------------------------*/ static void set_out_cb2(const device_config *device, int data) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); int z = pianew_get_output_cb2_z(device); if ((data != p->out_cb2) || (z != p->last_out_cb2_z)) { p->out_cb2 = data; p->last_out_cb2_z = z; /* send to output function */ if (intf->out_cb2_func) (*intf->out_cb2_func)(device, 0, p->out_cb2); else { if (p->out_cb2_needs_pulled) logerror("PIA #%s: Warning! No port CB2 write handler. Previous value has been lost!\n", device->tag); p->out_cb2_needs_pulled = TRUE; } } } /*------------------------------------------------- port_a_r -------------------------------------------------*/ static UINT8 port_a_r(const device_config *device) { pia6821 *p = get_token(device); UINT8 ret = get_in_a_value(device); /* IRQ flags implicitly cleared by a read */ p->irq_a1 = FALSE; p->irq_a2 = FALSE; update_interrupts(device); /* CA2 is configured as output and in read strobe mode */ if (C2_OUTPUT(p->ctl_a) && C2_STROBE_MODE(p->ctl_a)) { /* this will cause a transition low */ set_out_ca2(device, FALSE); /* if the CA2 strobe is cleared by the E, reset it right away */ if (STROBE_E_RESET(p->ctl_a)) set_out_ca2(device, TRUE); } LOG(("PIA #%s: port A read = %02X\n", device->tag, ret)); return ret; } /*------------------------------------------------- ddr_a_r -------------------------------------------------*/ static UINT8 ddr_a_r(const device_config *device) { pia6821 *p = get_token(device); UINT8 ret = p->ddr_a; LOG(("PIA #%s: DDR A read = %02X\n", device->tag, ret)); return ret; } /*------------------------------------------------- port_b_r -------------------------------------------------*/ static UINT8 port_b_r(const device_config *device) { pia6821 *p = get_token(device); UINT8 ret = get_in_b_value(device); /* This read will implicitly clear the IRQ B1 flag. If CB2 is in write-strobe mode with CB1 restore, and a CB1 active transition set the flag, clearing it will cause CB2 to go high again. Note that this is different from what happens with port A. */ if (p->irq_b1 && C2_STROBE_MODE(p->ctl_b) && STROBE_C1_RESET(p->ctl_b)) set_out_cb2(device, TRUE); /* IRQ flags implicitly cleared by a read */ p->irq_b1 = FALSE; p->irq_b2 = FALSE; update_interrupts(device); LOG(("PIA #%s: port B read = %02X\n", device->tag, ret)); return ret; } /*------------------------------------------------- ddr_b_r -------------------------------------------------*/ static UINT8 ddr_b_r(const device_config *device) { pia6821 *p = get_token(device); UINT8 ret = p->ddr_b; LOG(("PIA #%s: DDR B read = %02X\n", device->tag, ret)); return ret; } /*------------------------------------------------- control_a_r -------------------------------------------------*/ static UINT8 control_a_r(const device_config *device) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); UINT8 ret; /* update CA1 & CA2 if callback exists, these in turn may update IRQ's */ if (intf->in_ca1_func) pia_ca1_w(device, 0, (*intf->in_ca1_func)(device, 0)); else if (!p->logged_ca1_not_connected && (!p->in_ca1_pushed)) { logerror("PIA #%s: Warning! No CA1 read handler. Assuming pin not connected\n", device->tag); p->logged_ca1_not_connected = TRUE; } if (intf->in_ca2_func) pia_ca2_w(device, 0, (*intf->in_ca2_func)(device, 0)); else if ( !p->logged_ca2_not_connected && C2_INPUT(p->ctl_a) && !p->in_ca2_pushed) { logerror("PIA #%s: Warning! No CA2 read handler. Assuming pin not connected\n", device->tag); p->logged_ca2_not_connected = TRUE; } /* read control register */ ret = p->ctl_a; /* set the IRQ flags if we have pending IRQs */ if (p->irq_a1) ret |= PIA_IRQ1; if (p->irq_a2 && C2_INPUT(p->ctl_a)) ret |= PIA_IRQ2; LOG(("PIA #%s: control A read = %02X\n", device->tag, ret)); return ret; } /*------------------------------------------------- control_b_r -------------------------------------------------*/ static UINT8 control_b_r(const device_config *device) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); UINT8 ret; /* update CB1 & CB2 if callback exists, these in turn may update IRQ's */ if (intf->in_cb1_func) pia_cb1_w(device, 0, (*intf->in_cb1_func)(device, 0)); else if (!p->logged_cb1_not_connected && !p->in_cb1_pushed) { logerror("PIA #%s: Error! no CB1 read handler. Three-state pin is undefined\n", device->tag); p->logged_cb1_not_connected = TRUE; } if (intf->in_cb2_func) pia_cb2_w(device, 0, (*intf->in_cb2_func)(device, 0)); else if (!p->logged_cb2_not_connected && C2_INPUT(p->ctl_b) && !p->in_cb2_pushed) { logerror("PIA #%s: Error! No CB2 read handler. Three-state pin is undefined\n", device->tag); p->logged_cb2_not_connected = TRUE; } /* read control register */ ret = p->ctl_b; /* set the IRQ flags if we have pending IRQs */ if (p->irq_b1) ret |= PIA_IRQ1; if (p->irq_b2 && C2_INPUT(p->ctl_b)) ret |= PIA_IRQ2; LOG(("PIA #%s: control B read = %02X\n", device->tag, ret)); return ret; } /*------------------------------------------------- pia_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_r) { pia6821 *p = get_token(device); UINT8 ret; switch (offset & 0x03) { default: /* impossible */ case 0x00: if (OUTPUT_SELECTED(p->ctl_a)) ret = port_a_r(device); else ret = ddr_a_r(device); break; case 0x01: ret = control_a_r(device); break; case 0x02: if (OUTPUT_SELECTED(p->ctl_b)) ret = port_b_r(device); else ret = ddr_b_r(device); break; case 0x03: ret = control_b_r(device); break; } return ret; } /*------------------------------------------------- pia_alt_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_alt_r) { return pia_r(device, ((offset << 1) & 0x02) | ((offset >> 1) & 0x01)); } /*------------------------------------------------- pianew_get_port_b_z_mask -------------------------------------------------*/ UINT8 pianew_get_port_b_z_mask(const device_config *device) { pia6821 *p = get_token(device); return ~p->ddr_b; } /*------------------------------------------------- send_to_out_a_func -------------------------------------------------*/ static void send_to_out_a_func(const device_config *device, const char* message) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); /* input pins are pulled high */ UINT8 data = get_out_a_value(device); LOG(("PIA #%s: %s = %02X\n", device->tag, message, data)); if (intf->out_a_func) (*intf->out_a_func)(device, 0, data); else { if (p->out_a_needs_pulled) logerror("PIA #%s: Warning! No port A write handler. Previous value has been lost!\n", device->tag); p->out_a_needs_pulled = TRUE; } } /*------------------------------------------------- send_to_out_b_func -------------------------------------------------*/ static void send_to_out_b_func(const device_config *device, const char* message) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); /* input pins are high-impedance - we just send them as zeros for backwards compatibility */ UINT8 data = get_out_b_value(device); LOG(("PIA #%s: %s = %02X\n", device->tag, message, data)); if (intf->out_b_func) (*intf->out_b_func)(device, 0, data); else { if (p->out_b_needs_pulled) logerror("PIA #%s: Warning! No port B write handler. Previous value has been lost!\n", device->tag); p->out_b_needs_pulled = TRUE; } } /*------------------------------------------------- port_a_w -------------------------------------------------*/ static void port_a_w(const device_config *device, UINT8 data) { pia6821 *p = get_token(device); /* buffer the output value */ p->out_a = data; send_to_out_a_func(device, "port A write"); } /*------------------------------------------------- ddr_a_w -------------------------------------------------*/ static void ddr_a_w(const device_config *device, UINT8 data) { pia6821 *p = get_token(device); if (data == 0x00) LOG(("PIA #%s: DDR A write = %02X (input mode)\n", device->tag, data)); else if (data == 0xff) LOG(("PIA #%s: DDR A write = %02X (output mode)\n", device->tag, data)); else LOG(("PIA #%s: DDR A write = %02X (mixed mode)\n", device->tag, data)); if (p->ddr_a != data) { /* DDR changed, call the callback again */ p->ddr_a = data; p->logged_port_a_not_connected = FALSE; send_to_out_a_func(device, "port A write due to DDR change"); } } /*------------------------------------------------- port_b_w -------------------------------------------------*/ static void port_b_w(const device_config *device, UINT8 data) { pia6821 *p = get_token(device); /* buffer the output value */ p->out_b = data; send_to_out_b_func(device, "port B write"); /* CB2 in write strobe mode */ if (C2_STROBE_MODE(p->ctl_b)) { /* this will cause a transition low */ set_out_cb2(device, FALSE); /* if the CB2 strobe is cleared by the E, reset it right away */ if (STROBE_E_RESET(p->ctl_b)) set_out_cb2(device, TRUE); } } /*------------------------------------------------- ddr_b_w -------------------------------------------------*/ static void ddr_b_w(const device_config *device, UINT8 data) { pia6821 *p = get_token(device); if (data == 0x00) LOG(("PIA #%s: DDR B write = %02X (input mode)\n", device->tag, data)); else if (data == 0xff) LOG(("PIA #%s: DDR B write = %02X (output mode)\n", device->tag, data)); else LOG(("PIA #%s: DDR B write = %02X (mixed mode)\n", device->tag, data)); if (p->ddr_b != data) { /* DDR changed, call the callback again */ p->ddr_b = data; p->logged_port_b_not_connected = FALSE; send_to_out_b_func(device, "port B write due to DDR change"); } } /*------------------------------------------------- control_a_w -------------------------------------------------*/ static void control_a_w(const device_config *device, UINT8 data) { pia6821 *p = get_token(device); /* bit 7 and 6 are read only */ data &= 0x3f; LOG(("PIA #%s: control A write = %02X\n", device->tag, data)); /* update the control register */ p->ctl_a = data; /* CA2 is configured as output */ if (C2_OUTPUT(p->ctl_a)) { int temp; if (C2_SET_MODE(p->ctl_a)) /* set/reset mode - bit value determines the new output */ temp = C2_SET(p->ctl_a); else /* strobe mode - output is always high unless strobed */ temp = TRUE; set_out_ca2(device, temp); } /* update externals */ update_interrupts(device); } /*------------------------------------------------- control_b_w -------------------------------------------------*/ static void control_b_w(const device_config *device, UINT8 data) { pia6821 *p = get_token(device); int temp; /* bit 7 and 6 are read only */ data &= 0x3f; LOG(("PIA #%s: control B write = %02X\n", device->tag, data)); /* update the control register */ p->ctl_b = data; if (C2_SET_MODE(p->ctl_b)) /* set/reset mode - bit value determines the new output */ temp = C2_SET(p->ctl_b); else /* strobe mode - output is always high unless strobed */ temp = TRUE; set_out_cb2(device, temp); /* update externals */ update_interrupts(device); } /*------------------------------------------------- pia_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_w) { pia6821 *p = get_token(device); switch (offset & 0x03) { default: /* impossible */ case 0x00: if (OUTPUT_SELECTED(p->ctl_a)) port_a_w(device, data); else ddr_a_w(device, data); break; case 0x01: control_a_w(device, data); break; case 0x02: if (OUTPUT_SELECTED(p->ctl_b)) port_b_w(device, data); else ddr_b_w(device, data); break; case 0x03: control_b_w(device, data); break; } } /*------------------------------------------------- pia_alt_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_alt_w) { pia_w(device, ((offset << 1) & 0x02) | ((offset >> 1) & 0x01), data); } /*------------------------------------------------- pianew_set_port_a_z_mask -------------------------------------------------*/ void pianew_set_port_a_z_mask(const device_config *device, UINT8 data) { pia6821 *p = get_token(device); p->port_a_z_mask = data; } /*------------------------------------------------- pia_porta_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_porta_r) { pia6821 *p = get_token(device); return p->in_a; } /*------------------------------------------------- pianew_set_input_a -------------------------------------------------*/ void pianew_set_input_a(const device_config *device, UINT8 data, UINT8 z_mask) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); assert_always(intf->in_a_func == NULL, "pia_porta_w() called when in_a_func implemented"); LOG(("PIA #%s: set input port A = %02X\n", device->tag, data)); p->in_a = data; p->port_a_z_mask = z_mask; p->in_a_pushed = TRUE; } /*------------------------------------------------- pia_porta_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_porta_w) { pianew_set_input_a(device, data, 0); } /*------------------------------------------------- pianew_get_output_a -------------------------------------------------*/ UINT8 pianew_get_output_a(const device_config *device) { pia6821 *p = get_token(device); p->out_a_needs_pulled = FALSE; return get_out_a_value(device); } /*------------------------------------------------- pia_ca1_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_ca1_r) { pia6821 *p = get_token(device); return p->in_ca1; } /*------------------------------------------------- pia_ca1_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_ca1_w) { pia6821 *p = get_token(device); /* limit the data to 0 or 1 */ data = data ? TRUE : FALSE; LOG(("PIA #%s: set input CA1 = %d\n", device->tag, data)); /* the new state has caused a transition */ if ((p->in_ca1 != data) && ((data && C1_LOW_TO_HIGH(p->ctl_a)) || (!data && C1_HIGH_TO_LOW(p->ctl_a)))) { LOG(("PIA #%s: CA1 triggering\n", device->tag)); /* mark the IRQ */ p->irq_a1 = TRUE; /* update externals */ update_interrupts(device); /* CA2 is configured as output and in read strobe mode and cleared by a CA1 transition */ if (C2_OUTPUT(p->ctl_a) && C2_STROBE_MODE(p->ctl_a) && STROBE_C1_RESET(p->ctl_a)) set_out_ca2(device, TRUE); } /* set the new value for CA1 */ p->in_ca1 = data; p->in_ca1_pushed = TRUE; } /*------------------------------------------------- pia_ca2_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_ca2_r) { pia6821 *p = get_token(device); return p->in_ca2; } /*------------------------------------------------- pia_ca2_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_ca2_w) { pia6821 *p = get_token(device); /* limit the data to 0 or 1 */ data = data ? 1 : 0; LOG(("PIA #%s: set input CA2 = %d\n", device->tag, data)); /* if input mode and the new state has caused a transition */ if (C2_INPUT(p->ctl_a) && (p->in_ca2 != data) && ((data && C2_LOW_TO_HIGH(p->ctl_a)) || (!data && C2_HIGH_TO_LOW(p->ctl_a)))) { LOG(("PIA #%s: CA2 triggering\n", device->tag)); /* mark the IRQ */ p->irq_a2 = TRUE; /* update externals */ update_interrupts(device); } /* set the new value for CA2 */ p->in_ca2 = data; p->in_ca2_pushed = TRUE; } /*------------------------------------------------- pianew_get_output_ca2 -------------------------------------------------*/ int pianew_get_output_ca2(const device_config *device) { pia6821 *p = get_token(device); p->out_ca2_needs_pulled = FALSE; return p->out_ca2; } /*------------------------------------------------- pianew_get_output_ca2_z - version of pianew_get_output_ca2, which takes account of internal pullup resistor -------------------------------------------------*/ int pianew_get_output_ca2_z(const device_config *device) { pia6821 *p = get_token(device); p->out_ca2_needs_pulled = FALSE; // If it's an output, output the bit, if it's an input, it's // pulled up return p->out_ca2 | C2_INPUT(p->ctl_a); } /*------------------------------------------------- pia_portb_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_portb_r) { pia6821 *p = get_token(device); return p->in_b; } /*------------------------------------------------- pia_portb_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_portb_w) { pia6821 *p = get_token(device); const pia6821_interface *intf = get_interface(device); assert_always(intf->in_b_func == NULL, "pia_set_input_b() called when in_b_func implemented"); LOG(("PIA #%s: set input port B = %02X\n", device->tag, data)); p->in_b = data; p->in_b_pushed = TRUE; } /*------------------------------------------------- pianew_get_output_b -------------------------------------------------*/ UINT8 pianew_get_output_b(const device_config *device) { pia6821 *p = get_token(device); p->out_b_needs_pulled = FALSE; return get_out_b_value(device); } /*------------------------------------------------- pia_cb1_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_cb1_r) { pia6821 *p = get_token(device); return p->in_cb1; } /*------------------------------------------------- pia_cb1_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_cb1_w) { pia6821 *p = get_token(device); /* limit the data to 0 or 1 */ data = data ? 1 : 0; LOG(("PIA #%s: set input CB1 = %d\n", device->tag, data)); /* the new state has caused a transition */ if ((p->in_cb1 != data) && ((data && C1_LOW_TO_HIGH(p->ctl_b)) || (!data && C1_HIGH_TO_LOW(p->ctl_b)))) { LOG(("PIA #%s: CB1 triggering\n", device->tag)); /* mark the IRQ */ p->irq_b1 = 1; /* update externals */ update_interrupts(device); /* If CB2 is configured as a write-strobe output which is reset by a CB1 transition, this reset will only happen when a read from port B implicitly clears the IRQ B1 flag. So we handle the CB2 reset there. Note that this is different from what happens with port A. */ } /* set the new value for CB1 */ p->in_cb1 = data; p->in_cb1_pushed = TRUE; } /*------------------------------------------------- pia_cb2_r -------------------------------------------------*/ READ8_DEVICE_HANDLER(pia_cb2_r) { pia6821 *p = get_token(device); return p->in_cb2; } /*------------------------------------------------- pia_cb2_w -------------------------------------------------*/ WRITE8_DEVICE_HANDLER(pia_cb2_w) { pia6821 *p = get_token(device); /* limit the data to 0 or 1 */ data = data ? 1 : 0; LOG(("PIA #%s: set input CB2 = %d\n", device->tag, data)); /* if input mode and the new state has caused a transition */ if (C2_INPUT(p->ctl_b) && (p->in_cb2 != data) && ((data && C2_LOW_TO_HIGH(p->ctl_b)) || (!data && C2_HIGH_TO_LOW(p->ctl_b)))) { LOG(("PIA #%s: CB2 triggering\n", device->tag)); /* mark the IRQ */ p->irq_b2 = 1; /* update externals */ update_interrupts(device); } /* set the new value for CA2 */ p->in_cb2 = data; p->in_cb2_pushed = TRUE; } /*------------------------------------------------- pianew_get_output_cb2 -------------------------------------------------*/ int pianew_get_output_cb2(const device_config *device) { pia6821 *p = get_token(device); p->out_cb2_needs_pulled = FALSE; return p->out_cb2; } /*------------------------------------------------- pianew_get_output_cb2_z -------------------------------------------------*/ int pianew_get_output_cb2_z(const device_config *device) { pia6821 *p = get_token(device); return !C2_OUTPUT(p->ctl_b); } /*------------------------------------------------- pianew_get_irq_a -------------------------------------------------*/ int pianew_get_irq_a(const device_config *device) { pia6821 *p = get_token(device); return p->irq_a_state; } /*------------------------------------------------- pianew_get_irq_b -------------------------------------------------*/ int pianew_get_irq_b(const device_config *device) { pia6821 *p = get_token(device); return p->irq_b_state; } /*------------------------------------------------- DEVICE_SET_INFO( pia ) -------------------------------------------------*/ static DEVICE_SET_INFO( pia ) { switch(state) { } } /*------------------------------------------------- DEVICE_GET_INFO( pia6821 ) -------------------------------------------------*/ DEVICE_GET_INFO(pia6821) { switch (state) { /* --- the following bits of info are returned as 64-bit signed integers --- */ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(pia6821); break; case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break; /* --- the following bits of info are returned as pointers to data or functions --- */ case DEVINFO_FCT_SET_INFO: info->set_info = DEVICE_SET_INFO_NAME(pia); break; case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(pia); break; case DEVINFO_FCT_STOP: /* Nothing */ break; case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(pia); break; /* --- the following bits of info are returned as NULL-terminated strings --- */ case DEVINFO_STR_NAME: strcpy(info->s, "6821 PIA"); break; case DEVINFO_STR_FAMILY: strcpy(info->s, "6821 PIA"); break; case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; case DEVINFO_STR_CREDITS: /* Nothing */ break; } } /*------------------------------------------------- DEVICE_GET_INFO( pia6822 ) -------------------------------------------------*/ DEVICE_GET_INFO(pia6822) { switch (state) { case DEVINFO_STR_NAME: strcpy(info->s, "6822 PIA"); break; default: DEVICE_GET_INFO_CALL(pia6821); break; } }