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 */ |