trunk/src/mame/machine/315-5296.c
| r32645 | r32646 | |
| 1 | | /********************************************************************** |
| 2 | | |
| 3 | | Sega 315-5296 I/O chip |
| 4 | | |
| 5 | | Sega 100-pin QFP, with 8 bidirectional I/O ports, and 3 output pins. |
| 6 | | It also has chip select(/FMCS) and clock(CKOT) for a peripheral device. |
| 7 | | Commonly used from the late 80s up until Sega Model 2. |
| 8 | | |
| 9 | | The I/O chip has 64 addresses: |
| 10 | | $00-0F : I/O ports, security, configuration registers |
| 11 | | $10-1F : Unused (no effect when read or written) |
| 12 | | $20-3F : Unused (enables /FMCS output, eg. to YM2151 /CS) |
| 13 | | |
| 14 | | On System 16 derivatives, the unused locations return the 68000 prefetch |
| 15 | | value off the bus when read. |
| 16 | | |
| 17 | | |
| 18 | | TODO: |
| 19 | | - complete emulation of CNT register |
| 20 | | |
| 21 | | **********************************************************************/ |
| 22 | | |
| 23 | | #include "machine/315-5296.h" |
| 24 | | |
| 25 | | |
| 26 | | const device_type SEGA_315_5296 = &device_creator<sega_315_5296_device>; |
| 27 | | |
| 28 | | //------------------------------------------------- |
| 29 | | // sega_315_5296_device - constructor |
| 30 | | //------------------------------------------------- |
| 31 | | |
| 32 | | sega_315_5296_device::sega_315_5296_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 33 | | : device_t(mconfig, SEGA_315_5296, "Sega 315-5296", tag, owner, clock, "315-5296", __FILE__), |
| 34 | | m_in_pa_cb(*this), |
| 35 | | m_in_pb_cb(*this), |
| 36 | | m_in_pc_cb(*this), |
| 37 | | m_in_pd_cb(*this), |
| 38 | | m_in_pe_cb(*this), |
| 39 | | m_in_pf_cb(*this), |
| 40 | | m_in_pg_cb(*this), |
| 41 | | m_in_ph_cb(*this), |
| 42 | | m_out_pa_cb(*this), |
| 43 | | m_out_pb_cb(*this), |
| 44 | | m_out_pc_cb(*this), |
| 45 | | m_out_pd_cb(*this), |
| 46 | | m_out_pe_cb(*this), |
| 47 | | m_out_pf_cb(*this), |
| 48 | | m_out_pg_cb(*this), |
| 49 | | m_out_ph_cb(*this), |
| 50 | | m_out_cnt0_cb(*this), |
| 51 | | m_out_cnt1_cb(*this), |
| 52 | | m_out_cnt2_cb(*this) |
| 53 | | { |
| 54 | | } |
| 55 | | |
| 56 | | //------------------------------------------------- |
| 57 | | // device_start - device-specific startup |
| 58 | | //------------------------------------------------- |
| 59 | | |
| 60 | | void sega_315_5296_device::device_start() |
| 61 | | { |
| 62 | | // resolve callbacks |
| 63 | | m_in_pa_cb.resolve_safe(0xff); m_in_port_cb[0] = &m_in_pa_cb; |
| 64 | | m_in_pb_cb.resolve_safe(0xff); m_in_port_cb[1] = &m_in_pb_cb; |
| 65 | | m_in_pc_cb.resolve_safe(0xff); m_in_port_cb[2] = &m_in_pc_cb; |
| 66 | | m_in_pd_cb.resolve_safe(0xff); m_in_port_cb[3] = &m_in_pd_cb; |
| 67 | | m_in_pe_cb.resolve_safe(0xff); m_in_port_cb[4] = &m_in_pe_cb; |
| 68 | | m_in_pf_cb.resolve_safe(0xff); m_in_port_cb[5] = &m_in_pf_cb; |
| 69 | | m_in_pg_cb.resolve_safe(0xff); m_in_port_cb[6] = &m_in_pg_cb; |
| 70 | | m_in_ph_cb.resolve_safe(0xff); m_in_port_cb[7] = &m_in_ph_cb; |
| 71 | | |
| 72 | | m_out_pa_cb.resolve_safe(); m_out_port_cb[0] = &m_out_pa_cb; |
| 73 | | m_out_pb_cb.resolve_safe(); m_out_port_cb[1] = &m_out_pb_cb; |
| 74 | | m_out_pc_cb.resolve_safe(); m_out_port_cb[2] = &m_out_pc_cb; |
| 75 | | m_out_pd_cb.resolve_safe(); m_out_port_cb[3] = &m_out_pd_cb; |
| 76 | | m_out_pe_cb.resolve_safe(); m_out_port_cb[4] = &m_out_pe_cb; |
| 77 | | m_out_pf_cb.resolve_safe(); m_out_port_cb[5] = &m_out_pf_cb; |
| 78 | | m_out_pg_cb.resolve_safe(); m_out_port_cb[6] = &m_out_pg_cb; |
| 79 | | m_out_ph_cb.resolve_safe(); m_out_port_cb[7] = &m_out_ph_cb; |
| 80 | | |
| 81 | | m_out_cnt0_cb.resolve_safe(); m_out_cnt_cb[0] = &m_out_cnt0_cb; |
| 82 | | m_out_cnt1_cb.resolve_safe(); m_out_cnt_cb[1] = &m_out_cnt1_cb; |
| 83 | | m_out_cnt2_cb.resolve_safe(); m_out_cnt_cb[2] = &m_out_cnt2_cb; |
| 84 | | |
| 85 | | // register for savestates |
| 86 | | save_item(NAME(m_output_latch)); |
| 87 | | save_item(NAME(m_cnt)); |
| 88 | | save_item(NAME(m_dir)); |
| 89 | | } |
| 90 | | |
| 91 | | //------------------------------------------------- |
| 92 | | // device_reset - device-specific reset |
| 93 | | //------------------------------------------------- |
| 94 | | |
| 95 | | void sega_315_5296_device::device_reset() |
| 96 | | { |
| 97 | | // all ports are set to input |
| 98 | | m_dir = 0; |
| 99 | | |
| 100 | | // clear output ports |
| 101 | | memset(m_output_latch, 0, sizeof(m_output_latch)); |
| 102 | | m_cnt = 0; |
| 103 | | |
| 104 | | for (int i = 0; i < 8; i++) |
| 105 | | (*m_out_port_cb[i])((offs_t)i, 0); |
| 106 | | for (int i = 0; i < 3; i++) |
| 107 | | (*m_out_cnt_cb[i])(0); |
| 108 | | } |
| 109 | | |
| 110 | | |
| 111 | | //------------------------------------------------- |
| 112 | | |
| 113 | | READ8_MEMBER( sega_315_5296_device::read ) |
| 114 | | { |
| 115 | | offset &= 0x3f; |
| 116 | | |
| 117 | | switch (offset) |
| 118 | | { |
| 119 | | // port A to H |
| 120 | | case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: |
| 121 | | // if the port is configured as an output, return the last thing written |
| 122 | | if (m_dir & 1 << offset) |
| 123 | | return m_output_latch[offset]; |
| 124 | | |
| 125 | | // otherwise, return an input port |
| 126 | | return (*m_in_port_cb[offset])(offset); |
| 127 | | |
| 128 | | // 'SEGA' protection |
| 129 | | case 0x8: |
| 130 | | return 'S'; |
| 131 | | case 0x9: |
| 132 | | return 'E'; |
| 133 | | case 0xa: |
| 134 | | return 'G'; |
| 135 | | case 0xb: |
| 136 | | return 'A'; |
| 137 | | |
| 138 | | // CNT register & mirror |
| 139 | | case 0xc: case 0xe: |
| 140 | | return m_cnt; |
| 141 | | |
| 142 | | // port direction register & mirror |
| 143 | | case 0xd: case 0xf: |
| 144 | | return m_dir; |
| 145 | | |
| 146 | | default: |
| 147 | | break; |
| 148 | | } |
| 149 | | |
| 150 | | return 0xff; |
| 151 | | } |
| 152 | | |
| 153 | | |
| 154 | | WRITE8_MEMBER( sega_315_5296_device::write ) |
| 155 | | { |
| 156 | | offset &= 0x3f; |
| 157 | | |
| 158 | | switch (offset) |
| 159 | | { |
| 160 | | // port A to H |
| 161 | | case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: |
| 162 | | // if the port is configured as an output, write it |
| 163 | | if (m_dir & 1 << offset) |
| 164 | | (*m_out_port_cb[offset])(offset, data); |
| 165 | | |
| 166 | | m_output_latch[offset] = data; |
| 167 | | break; |
| 168 | | |
| 169 | | // CNT register |
| 170 | | case 0xe: |
| 171 | | // d0-2: CNT0-2 output pins |
| 172 | | // note: When CNT2 is configured as clock output, bit 2 of this register has |
| 173 | | // no effect on the output level of CNT2. |
| 174 | | for (int i = 0; i < 3; i++) |
| 175 | | (*m_out_cnt_cb[i])(data >> i & 1); |
| 176 | | |
| 177 | | // d3: CNT2 output mode (1= Clock output, 0= Programmable output) |
| 178 | | // d4,5: CNT2 clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2) |
| 179 | | // d6,7: CKOT clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2) |
| 180 | | // TODO.. |
| 181 | | m_cnt = data; |
| 182 | | break; |
| 183 | | |
| 184 | | // port direction register |
| 185 | | case 0xf: |
| 186 | | // refresh output ports if the direction changed |
| 187 | | for (int i = 0; i < 8; i++) |
| 188 | | { |
| 189 | | if ((m_dir ^ data) & (1 << i)) |
| 190 | | (*m_out_port_cb[i])((offs_t)i, (data & 1 << i) ? m_output_latch[i] : 0); |
| 191 | | } |
| 192 | | |
| 193 | | m_dir = data; |
| 194 | | break; |
| 195 | | |
| 196 | | default: |
| 197 | | break; |
| 198 | | } |
| 199 | | } |
trunk/src/mame/machine/315-5296.h
| r32645 | r32646 | |
| 1 | | /********************************************************************** |
| 2 | | |
| 3 | | Sega 315-5296 I/O chip |
| 4 | | |
| 5 | | Copyright MAME Team. |
| 6 | | Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | | |
| 8 | | **********************************************************************/ |
| 9 | | |
| 10 | | #pragma once |
| 11 | | |
| 12 | | #ifndef _SEGA_315_5296_H |
| 13 | | #define _SEGA_315_5296_H |
| 14 | | |
| 15 | | #include "emu.h" |
| 16 | | |
| 17 | | |
| 18 | | //************************************************************************** |
| 19 | | // INTERFACE CONFIGURATION MACROS |
| 20 | | //************************************************************************** |
| 21 | | |
| 22 | | // A to H 8-bit input ports |
| 23 | | #define MCFG_315_5296_IN_PORTA_CB(_devcb) \ |
| 24 | | devcb = &sega_315_5296_device::set_in_pa_callback(*device, DEVCB_##_devcb); |
| 25 | | #define MCFG_315_5296_IN_PORTB_CB(_devcb) \ |
| 26 | | devcb = &sega_315_5296_device::set_in_pb_callback(*device, DEVCB_##_devcb); |
| 27 | | #define MCFG_315_5296_IN_PORTC_CB(_devcb) \ |
| 28 | | devcb = &sega_315_5296_device::set_in_pc_callback(*device, DEVCB_##_devcb); |
| 29 | | #define MCFG_315_5296_IN_PORTD_CB(_devcb) \ |
| 30 | | devcb = &sega_315_5296_device::set_in_pd_callback(*device, DEVCB_##_devcb); |
| 31 | | #define MCFG_315_5296_IN_PORTE_CB(_devcb) \ |
| 32 | | devcb = &sega_315_5296_device::set_in_pe_callback(*device, DEVCB_##_devcb); |
| 33 | | #define MCFG_315_5296_IN_PORTF_CB(_devcb) \ |
| 34 | | devcb = &sega_315_5296_device::set_in_pf_callback(*device, DEVCB_##_devcb); |
| 35 | | #define MCFG_315_5296_IN_PORTG_CB(_devcb) \ |
| 36 | | devcb = &sega_315_5296_device::set_in_pg_callback(*device, DEVCB_##_devcb); |
| 37 | | #define MCFG_315_5296_IN_PORTH_CB(_devcb) \ |
| 38 | | devcb = &sega_315_5296_device::set_in_ph_callback(*device, DEVCB_##_devcb); |
| 39 | | |
| 40 | | // A to H 8-bit output ports |
| 41 | | #define MCFG_315_5296_OUT_PORTA_CB(_devcb) \ |
| 42 | | devcb = &sega_315_5296_device::set_out_pa_callback(*device, DEVCB_##_devcb); |
| 43 | | #define MCFG_315_5296_OUT_PORTB_CB(_devcb) \ |
| 44 | | devcb = &sega_315_5296_device::set_out_pb_callback(*device, DEVCB_##_devcb); |
| 45 | | #define MCFG_315_5296_OUT_PORTC_CB(_devcb) \ |
| 46 | | devcb = &sega_315_5296_device::set_out_pc_callback(*device, DEVCB_##_devcb); |
| 47 | | #define MCFG_315_5296_OUT_PORTD_CB(_devcb) \ |
| 48 | | devcb = &sega_315_5296_device::set_out_pd_callback(*device, DEVCB_##_devcb); |
| 49 | | #define MCFG_315_5296_OUT_PORTE_CB(_devcb) \ |
| 50 | | devcb = &sega_315_5296_device::set_out_pe_callback(*device, DEVCB_##_devcb); |
| 51 | | #define MCFG_315_5296_OUT_PORTF_CB(_devcb) \ |
| 52 | | devcb = &sega_315_5296_device::set_out_pf_callback(*device, DEVCB_##_devcb); |
| 53 | | #define MCFG_315_5296_OUT_PORTG_CB(_devcb) \ |
| 54 | | devcb = &sega_315_5296_device::set_out_pg_callback(*device, DEVCB_##_devcb); |
| 55 | | #define MCFG_315_5296_OUT_PORTH_CB(_devcb) \ |
| 56 | | devcb = &sega_315_5296_device::set_out_ph_callback(*device, DEVCB_##_devcb); |
| 57 | | |
| 58 | | // CNT output pins |
| 59 | | #define MCFG_315_5296_OUT_CNT0_CB(_devcb) \ |
| 60 | | devcb = &sega_315_5296_device::set_out_cnt0_callback(*device, DEVCB_##_devcb); |
| 61 | | #define MCFG_315_5296_OUT_CNT1_CB(_devcb) \ |
| 62 | | devcb = &sega_315_5296_device::set_out_cnt1_callback(*device, DEVCB_##_devcb); |
| 63 | | #define MCFG_315_5296_OUT_CNT2_CB(_devcb) \ |
| 64 | | devcb = &sega_315_5296_device::set_out_cnt2_callback(*device, DEVCB_##_devcb); |
| 65 | | |
| 66 | | |
| 67 | | //************************************************************************** |
| 68 | | // TYPE DEFINITIONS |
| 69 | | //************************************************************************** |
| 70 | | |
| 71 | | // ======================> sega_315_5296_device |
| 72 | | |
| 73 | | class sega_315_5296_device : public device_t |
| 74 | | { |
| 75 | | public: |
| 76 | | sega_315_5296_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 77 | | |
| 78 | | // static configuration helpers |
| 79 | | template<class _Object> static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pa_cb.set_callback(object); } |
| 80 | | template<class _Object> static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pb_cb.set_callback(object); } |
| 81 | | template<class _Object> static devcb_base &set_in_pc_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pc_cb.set_callback(object); } |
| 82 | | template<class _Object> static devcb_base &set_in_pd_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pd_cb.set_callback(object); } |
| 83 | | template<class _Object> static devcb_base &set_in_pe_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pe_cb.set_callback(object); } |
| 84 | | template<class _Object> static devcb_base &set_in_pf_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pf_cb.set_callback(object); } |
| 85 | | template<class _Object> static devcb_base &set_in_pg_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pg_cb.set_callback(object); } |
| 86 | | template<class _Object> static devcb_base &set_in_ph_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_ph_cb.set_callback(object); } |
| 87 | | |
| 88 | | template<class _Object> static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pa_cb.set_callback(object); } |
| 89 | | template<class _Object> static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pb_cb.set_callback(object); } |
| 90 | | template<class _Object> static devcb_base &set_out_pc_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pc_cb.set_callback(object); } |
| 91 | | template<class _Object> static devcb_base &set_out_pd_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pd_cb.set_callback(object); } |
| 92 | | template<class _Object> static devcb_base &set_out_pe_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pe_cb.set_callback(object); } |
| 93 | | template<class _Object> static devcb_base &set_out_pf_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pf_cb.set_callback(object); } |
| 94 | | template<class _Object> static devcb_base &set_out_pg_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pg_cb.set_callback(object); } |
| 95 | | template<class _Object> static devcb_base &set_out_ph_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_ph_cb.set_callback(object); } |
| 96 | | |
| 97 | | template<class _Object> static devcb_base &set_out_cnt0_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_cnt0_cb.set_callback(object); } |
| 98 | | template<class _Object> static devcb_base &set_out_cnt1_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_cnt1_cb.set_callback(object); } |
| 99 | | template<class _Object> static devcb_base &set_out_cnt2_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_cnt2_cb.set_callback(object); } |
| 100 | | |
| 101 | | DECLARE_READ8_MEMBER( read ); |
| 102 | | DECLARE_WRITE8_MEMBER( write ); |
| 103 | | |
| 104 | | protected: |
| 105 | | // device-level overrides |
| 106 | | virtual void device_start(); |
| 107 | | virtual void device_reset(); |
| 108 | | |
| 109 | | private: |
| 110 | | devcb_read8 m_in_pa_cb; |
| 111 | | devcb_read8 m_in_pb_cb; |
| 112 | | devcb_read8 m_in_pc_cb; |
| 113 | | devcb_read8 m_in_pd_cb; |
| 114 | | devcb_read8 m_in_pe_cb; |
| 115 | | devcb_read8 m_in_pf_cb; |
| 116 | | devcb_read8 m_in_pg_cb; |
| 117 | | devcb_read8 m_in_ph_cb; |
| 118 | | |
| 119 | | devcb_write8 m_out_pa_cb; |
| 120 | | devcb_write8 m_out_pb_cb; |
| 121 | | devcb_write8 m_out_pc_cb; |
| 122 | | devcb_write8 m_out_pd_cb; |
| 123 | | devcb_write8 m_out_pe_cb; |
| 124 | | devcb_write8 m_out_pf_cb; |
| 125 | | devcb_write8 m_out_pg_cb; |
| 126 | | devcb_write8 m_out_ph_cb; |
| 127 | | |
| 128 | | devcb_write_line m_out_cnt0_cb; |
| 129 | | devcb_write_line m_out_cnt1_cb; |
| 130 | | devcb_write_line m_out_cnt2_cb; |
| 131 | | |
| 132 | | devcb_read8 *m_in_port_cb[8]; |
| 133 | | devcb_write8 *m_out_port_cb[8]; |
| 134 | | devcb_write_line *m_out_cnt_cb[3]; |
| 135 | | |
| 136 | | UINT8 m_output_latch[8]; |
| 137 | | UINT8 m_cnt; |
| 138 | | UINT8 m_dir; |
| 139 | | }; |
| 140 | | |
| 141 | | // device type definition |
| 142 | | extern const device_type SEGA_315_5296; |
| 143 | | |
| 144 | | |
| 145 | | #endif /* _SEGA_315_5296_H */ |
trunk/src/mame/machine/315_5296.c
| r0 | r32646 | |
| 1 | /********************************************************************** |
| 2 | |
| 3 | Sega 315-5296 I/O chip |
| 4 | |
| 5 | Sega 100-pin QFP, with 8 bidirectional I/O ports, and 3 output pins. |
| 6 | It also has chip select(/FMCS) and clock(CKOT) for a peripheral device. |
| 7 | Commonly used from the late 80s up until Sega Model 2. |
| 8 | |
| 9 | The I/O chip has 64 addresses: |
| 10 | $00-0F : I/O ports, security, configuration registers |
| 11 | $10-1F : Unused (no effect when read or written) |
| 12 | $20-3F : Unused (enables /FMCS output, eg. to YM2151 /CS) |
| 13 | |
| 14 | On System 16 derivatives, the unused locations return the 68000 prefetch |
| 15 | value off the bus when read. |
| 16 | |
| 17 | |
| 18 | TODO: |
| 19 | - complete emulation of CNT register |
| 20 | |
| 21 | **********************************************************************/ |
| 22 | |
| 23 | #include "machine/315_5296.h" |
| 24 | |
| 25 | |
| 26 | const device_type SEGA_315_5296 = &device_creator<sega_315_5296_device>; |
| 27 | |
| 28 | //------------------------------------------------- |
| 29 | // sega_315_5296_device - constructor |
| 30 | //------------------------------------------------- |
| 31 | |
| 32 | sega_315_5296_device::sega_315_5296_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 33 | : device_t(mconfig, SEGA_315_5296, "Sega 315-5296", tag, owner, clock, "315-5296", __FILE__), |
| 34 | m_in_pa_cb(*this), |
| 35 | m_in_pb_cb(*this), |
| 36 | m_in_pc_cb(*this), |
| 37 | m_in_pd_cb(*this), |
| 38 | m_in_pe_cb(*this), |
| 39 | m_in_pf_cb(*this), |
| 40 | m_in_pg_cb(*this), |
| 41 | m_in_ph_cb(*this), |
| 42 | m_out_pa_cb(*this), |
| 43 | m_out_pb_cb(*this), |
| 44 | m_out_pc_cb(*this), |
| 45 | m_out_pd_cb(*this), |
| 46 | m_out_pe_cb(*this), |
| 47 | m_out_pf_cb(*this), |
| 48 | m_out_pg_cb(*this), |
| 49 | m_out_ph_cb(*this), |
| 50 | m_out_cnt0_cb(*this), |
| 51 | m_out_cnt1_cb(*this), |
| 52 | m_out_cnt2_cb(*this) |
| 53 | { |
| 54 | } |
| 55 | |
| 56 | //------------------------------------------------- |
| 57 | // device_start - device-specific startup |
| 58 | //------------------------------------------------- |
| 59 | |
| 60 | void sega_315_5296_device::device_start() |
| 61 | { |
| 62 | // resolve callbacks |
| 63 | m_in_pa_cb.resolve_safe(0xff); m_in_port_cb[0] = &m_in_pa_cb; |
| 64 | m_in_pb_cb.resolve_safe(0xff); m_in_port_cb[1] = &m_in_pb_cb; |
| 65 | m_in_pc_cb.resolve_safe(0xff); m_in_port_cb[2] = &m_in_pc_cb; |
| 66 | m_in_pd_cb.resolve_safe(0xff); m_in_port_cb[3] = &m_in_pd_cb; |
| 67 | m_in_pe_cb.resolve_safe(0xff); m_in_port_cb[4] = &m_in_pe_cb; |
| 68 | m_in_pf_cb.resolve_safe(0xff); m_in_port_cb[5] = &m_in_pf_cb; |
| 69 | m_in_pg_cb.resolve_safe(0xff); m_in_port_cb[6] = &m_in_pg_cb; |
| 70 | m_in_ph_cb.resolve_safe(0xff); m_in_port_cb[7] = &m_in_ph_cb; |
| 71 | |
| 72 | m_out_pa_cb.resolve_safe(); m_out_port_cb[0] = &m_out_pa_cb; |
| 73 | m_out_pb_cb.resolve_safe(); m_out_port_cb[1] = &m_out_pb_cb; |
| 74 | m_out_pc_cb.resolve_safe(); m_out_port_cb[2] = &m_out_pc_cb; |
| 75 | m_out_pd_cb.resolve_safe(); m_out_port_cb[3] = &m_out_pd_cb; |
| 76 | m_out_pe_cb.resolve_safe(); m_out_port_cb[4] = &m_out_pe_cb; |
| 77 | m_out_pf_cb.resolve_safe(); m_out_port_cb[5] = &m_out_pf_cb; |
| 78 | m_out_pg_cb.resolve_safe(); m_out_port_cb[6] = &m_out_pg_cb; |
| 79 | m_out_ph_cb.resolve_safe(); m_out_port_cb[7] = &m_out_ph_cb; |
| 80 | |
| 81 | m_out_cnt0_cb.resolve_safe(); m_out_cnt_cb[0] = &m_out_cnt0_cb; |
| 82 | m_out_cnt1_cb.resolve_safe(); m_out_cnt_cb[1] = &m_out_cnt1_cb; |
| 83 | m_out_cnt2_cb.resolve_safe(); m_out_cnt_cb[2] = &m_out_cnt2_cb; |
| 84 | |
| 85 | // register for savestates |
| 86 | save_item(NAME(m_output_latch)); |
| 87 | save_item(NAME(m_cnt)); |
| 88 | save_item(NAME(m_dir)); |
| 89 | } |
| 90 | |
| 91 | //------------------------------------------------- |
| 92 | // device_reset - device-specific reset |
| 93 | //------------------------------------------------- |
| 94 | |
| 95 | void sega_315_5296_device::device_reset() |
| 96 | { |
| 97 | // all ports are set to input |
| 98 | m_dir = 0; |
| 99 | |
| 100 | // clear output ports |
| 101 | memset(m_output_latch, 0, sizeof(m_output_latch)); |
| 102 | m_cnt = 0; |
| 103 | |
| 104 | for (int i = 0; i < 8; i++) |
| 105 | (*m_out_port_cb[i])((offs_t)i, 0); |
| 106 | for (int i = 0; i < 3; i++) |
| 107 | (*m_out_cnt_cb[i])(0); |
| 108 | } |
| 109 | |
| 110 | |
| 111 | //------------------------------------------------- |
| 112 | |
| 113 | READ8_MEMBER( sega_315_5296_device::read ) |
| 114 | { |
| 115 | offset &= 0x3f; |
| 116 | |
| 117 | switch (offset) |
| 118 | { |
| 119 | // port A to H |
| 120 | case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: |
| 121 | // if the port is configured as an output, return the last thing written |
| 122 | if (m_dir & 1 << offset) |
| 123 | return m_output_latch[offset]; |
| 124 | |
| 125 | // otherwise, return an input port |
| 126 | return (*m_in_port_cb[offset])(offset); |
| 127 | |
| 128 | // 'SEGA' protection |
| 129 | case 0x8: |
| 130 | return 'S'; |
| 131 | case 0x9: |
| 132 | return 'E'; |
| 133 | case 0xa: |
| 134 | return 'G'; |
| 135 | case 0xb: |
| 136 | return 'A'; |
| 137 | |
| 138 | // CNT register & mirror |
| 139 | case 0xc: case 0xe: |
| 140 | return m_cnt; |
| 141 | |
| 142 | // port direction register & mirror |
| 143 | case 0xd: case 0xf: |
| 144 | return m_dir; |
| 145 | |
| 146 | default: |
| 147 | break; |
| 148 | } |
| 149 | |
| 150 | return 0xff; |
| 151 | } |
| 152 | |
| 153 | |
| 154 | WRITE8_MEMBER( sega_315_5296_device::write ) |
| 155 | { |
| 156 | offset &= 0x3f; |
| 157 | |
| 158 | switch (offset) |
| 159 | { |
| 160 | // port A to H |
| 161 | case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: |
| 162 | // if the port is configured as an output, write it |
| 163 | if (m_dir & 1 << offset) |
| 164 | (*m_out_port_cb[offset])(offset, data); |
| 165 | |
| 166 | m_output_latch[offset] = data; |
| 167 | break; |
| 168 | |
| 169 | // CNT register |
| 170 | case 0xe: |
| 171 | // d0-2: CNT0-2 output pins |
| 172 | // note: When CNT2 is configured as clock output, bit 2 of this register has |
| 173 | // no effect on the output level of CNT2. |
| 174 | for (int i = 0; i < 3; i++) |
| 175 | (*m_out_cnt_cb[i])(data >> i & 1); |
| 176 | |
| 177 | // d3: CNT2 output mode (1= Clock output, 0= Programmable output) |
| 178 | // d4,5: CNT2 clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2) |
| 179 | // d6,7: CKOT clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2) |
| 180 | // TODO.. |
| 181 | m_cnt = data; |
| 182 | break; |
| 183 | |
| 184 | // port direction register |
| 185 | case 0xf: |
| 186 | // refresh output ports if the direction changed |
| 187 | for (int i = 0; i < 8; i++) |
| 188 | { |
| 189 | if ((m_dir ^ data) & (1 << i)) |
| 190 | (*m_out_port_cb[i])((offs_t)i, (data & 1 << i) ? m_output_latch[i] : 0); |
| 191 | } |
| 192 | |
| 193 | m_dir = data; |
| 194 | break; |
| 195 | |
| 196 | default: |
| 197 | break; |
| 198 | } |
| 199 | } |
trunk/src/mame/machine/315_5296.h
| r0 | r32646 | |
| 1 | /********************************************************************** |
| 2 | |
| 3 | Sega 315-5296 I/O chip |
| 4 | |
| 5 | Copyright MAME Team. |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | |
| 8 | **********************************************************************/ |
| 9 | |
| 10 | #pragma once |
| 11 | |
| 12 | #ifndef _SEGA_315_5296_H |
| 13 | #define _SEGA_315_5296_H |
| 14 | |
| 15 | #include "emu.h" |
| 16 | |
| 17 | |
| 18 | //************************************************************************** |
| 19 | // INTERFACE CONFIGURATION MACROS |
| 20 | //************************************************************************** |
| 21 | |
| 22 | // A to H 8-bit input ports |
| 23 | #define MCFG_315_5296_IN_PORTA_CB(_devcb) \ |
| 24 | devcb = &sega_315_5296_device::set_in_pa_callback(*device, DEVCB_##_devcb); |
| 25 | #define MCFG_315_5296_IN_PORTB_CB(_devcb) \ |
| 26 | devcb = &sega_315_5296_device::set_in_pb_callback(*device, DEVCB_##_devcb); |
| 27 | #define MCFG_315_5296_IN_PORTC_CB(_devcb) \ |
| 28 | devcb = &sega_315_5296_device::set_in_pc_callback(*device, DEVCB_##_devcb); |
| 29 | #define MCFG_315_5296_IN_PORTD_CB(_devcb) \ |
| 30 | devcb = &sega_315_5296_device::set_in_pd_callback(*device, DEVCB_##_devcb); |
| 31 | #define MCFG_315_5296_IN_PORTE_CB(_devcb) \ |
| 32 | devcb = &sega_315_5296_device::set_in_pe_callback(*device, DEVCB_##_devcb); |
| 33 | #define MCFG_315_5296_IN_PORTF_CB(_devcb) \ |
| 34 | devcb = &sega_315_5296_device::set_in_pf_callback(*device, DEVCB_##_devcb); |
| 35 | #define MCFG_315_5296_IN_PORTG_CB(_devcb) \ |
| 36 | devcb = &sega_315_5296_device::set_in_pg_callback(*device, DEVCB_##_devcb); |
| 37 | #define MCFG_315_5296_IN_PORTH_CB(_devcb) \ |
| 38 | devcb = &sega_315_5296_device::set_in_ph_callback(*device, DEVCB_##_devcb); |
| 39 | |
| 40 | // A to H 8-bit output ports |
| 41 | #define MCFG_315_5296_OUT_PORTA_CB(_devcb) \ |
| 42 | devcb = &sega_315_5296_device::set_out_pa_callback(*device, DEVCB_##_devcb); |
| 43 | #define MCFG_315_5296_OUT_PORTB_CB(_devcb) \ |
| 44 | devcb = &sega_315_5296_device::set_out_pb_callback(*device, DEVCB_##_devcb); |
| 45 | #define MCFG_315_5296_OUT_PORTC_CB(_devcb) \ |
| 46 | devcb = &sega_315_5296_device::set_out_pc_callback(*device, DEVCB_##_devcb); |
| 47 | #define MCFG_315_5296_OUT_PORTD_CB(_devcb) \ |
| 48 | devcb = &sega_315_5296_device::set_out_pd_callback(*device, DEVCB_##_devcb); |
| 49 | #define MCFG_315_5296_OUT_PORTE_CB(_devcb) \ |
| 50 | devcb = &sega_315_5296_device::set_out_pe_callback(*device, DEVCB_##_devcb); |
| 51 | #define MCFG_315_5296_OUT_PORTF_CB(_devcb) \ |
| 52 | devcb = &sega_315_5296_device::set_out_pf_callback(*device, DEVCB_##_devcb); |
| 53 | #define MCFG_315_5296_OUT_PORTG_CB(_devcb) \ |
| 54 | devcb = &sega_315_5296_device::set_out_pg_callback(*device, DEVCB_##_devcb); |
| 55 | #define MCFG_315_5296_OUT_PORTH_CB(_devcb) \ |
| 56 | devcb = &sega_315_5296_device::set_out_ph_callback(*device, DEVCB_##_devcb); |
| 57 | |
| 58 | // CNT output pins |
| 59 | #define MCFG_315_5296_OUT_CNT0_CB(_devcb) \ |
| 60 | devcb = &sega_315_5296_device::set_out_cnt0_callback(*device, DEVCB_##_devcb); |
| 61 | #define MCFG_315_5296_OUT_CNT1_CB(_devcb) \ |
| 62 | devcb = &sega_315_5296_device::set_out_cnt1_callback(*device, DEVCB_##_devcb); |
| 63 | #define MCFG_315_5296_OUT_CNT2_CB(_devcb) \ |
| 64 | devcb = &sega_315_5296_device::set_out_cnt2_callback(*device, DEVCB_##_devcb); |
| 65 | |
| 66 | |
| 67 | //************************************************************************** |
| 68 | // TYPE DEFINITIONS |
| 69 | //************************************************************************** |
| 70 | |
| 71 | // ======================> sega_315_5296_device |
| 72 | |
| 73 | class sega_315_5296_device : public device_t |
| 74 | { |
| 75 | public: |
| 76 | sega_315_5296_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 77 | |
| 78 | // static configuration helpers |
| 79 | template<class _Object> static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pa_cb.set_callback(object); } |
| 80 | template<class _Object> static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pb_cb.set_callback(object); } |
| 81 | template<class _Object> static devcb_base &set_in_pc_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pc_cb.set_callback(object); } |
| 82 | template<class _Object> static devcb_base &set_in_pd_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pd_cb.set_callback(object); } |
| 83 | template<class _Object> static devcb_base &set_in_pe_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pe_cb.set_callback(object); } |
| 84 | template<class _Object> static devcb_base &set_in_pf_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pf_cb.set_callback(object); } |
| 85 | template<class _Object> static devcb_base &set_in_pg_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_pg_cb.set_callback(object); } |
| 86 | template<class _Object> static devcb_base &set_in_ph_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_in_ph_cb.set_callback(object); } |
| 87 | |
| 88 | template<class _Object> static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pa_cb.set_callback(object); } |
| 89 | template<class _Object> static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pb_cb.set_callback(object); } |
| 90 | template<class _Object> static devcb_base &set_out_pc_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pc_cb.set_callback(object); } |
| 91 | template<class _Object> static devcb_base &set_out_pd_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pd_cb.set_callback(object); } |
| 92 | template<class _Object> static devcb_base &set_out_pe_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pe_cb.set_callback(object); } |
| 93 | template<class _Object> static devcb_base &set_out_pf_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pf_cb.set_callback(object); } |
| 94 | template<class _Object> static devcb_base &set_out_pg_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_pg_cb.set_callback(object); } |
| 95 | template<class _Object> static devcb_base &set_out_ph_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_ph_cb.set_callback(object); } |
| 96 | |
| 97 | template<class _Object> static devcb_base &set_out_cnt0_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_cnt0_cb.set_callback(object); } |
| 98 | template<class _Object> static devcb_base &set_out_cnt1_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_cnt1_cb.set_callback(object); } |
| 99 | template<class _Object> static devcb_base &set_out_cnt2_callback(device_t &device, _Object object) { return downcast<sega_315_5296_device &>(device).m_out_cnt2_cb.set_callback(object); } |
| 100 | |
| 101 | DECLARE_READ8_MEMBER( read ); |
| 102 | DECLARE_WRITE8_MEMBER( write ); |
| 103 | |
| 104 | protected: |
| 105 | // device-level overrides |
| 106 | virtual void device_start(); |
| 107 | virtual void device_reset(); |
| 108 | |
| 109 | private: |
| 110 | devcb_read8 m_in_pa_cb; |
| 111 | devcb_read8 m_in_pb_cb; |
| 112 | devcb_read8 m_in_pc_cb; |
| 113 | devcb_read8 m_in_pd_cb; |
| 114 | devcb_read8 m_in_pe_cb; |
| 115 | devcb_read8 m_in_pf_cb; |
| 116 | devcb_read8 m_in_pg_cb; |
| 117 | devcb_read8 m_in_ph_cb; |
| 118 | |
| 119 | devcb_write8 m_out_pa_cb; |
| 120 | devcb_write8 m_out_pb_cb; |
| 121 | devcb_write8 m_out_pc_cb; |
| 122 | devcb_write8 m_out_pd_cb; |
| 123 | devcb_write8 m_out_pe_cb; |
| 124 | devcb_write8 m_out_pf_cb; |
| 125 | devcb_write8 m_out_pg_cb; |
| 126 | devcb_write8 m_out_ph_cb; |
| 127 | |
| 128 | devcb_write_line m_out_cnt0_cb; |
| 129 | devcb_write_line m_out_cnt1_cb; |
| 130 | devcb_write_line m_out_cnt2_cb; |
| 131 | |
| 132 | devcb_read8 *m_in_port_cb[8]; |
| 133 | devcb_write8 *m_out_port_cb[8]; |
| 134 | devcb_write_line *m_out_cnt_cb[3]; |
| 135 | |
| 136 | UINT8 m_output_latch[8]; |
| 137 | UINT8 m_cnt; |
| 138 | UINT8 m_dir; |
| 139 | }; |
| 140 | |
| 141 | // device type definition |
| 142 | extern const device_type SEGA_315_5296; |
| 143 | |
| 144 | |
| 145 | #endif /* _SEGA_315_5296_H */ |