summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/latch8.h
blob: ee00fbdc38d679adcd6c7fdb2d3229a86eeeb21b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// license:BSD-3-Clause
// copyright-holders:Couriersud
/**********************************************************************

    8 bit latch interface and emulation

    Generic emulation of 74LS174/175, 74LS259 and other latches.
    Apart from providing synched latch operation, these
    latches can be configured to read their input bitwise from other
    devices as well.

    Please see audio/dkong.c for examples.

**********************************************************************/

#ifndef MAME_MACHINE_LATCH8_H
#define MAME_MACHINE_LATCH8_H

#include "sound/discrete.h"


/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

class latch8_device : public device_t
{
public:
	latch8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);

	/* write & read full byte */

	DECLARE_READ8_MEMBER( read );
	DECLARE_WRITE8_MEMBER( write );

	/* reset the latch */

	DECLARE_WRITE8_MEMBER( reset_w );

	/* read bit x                 */
	/* return (latch >> x) & 0x01 */

	DECLARE_READ_LINE_MEMBER( bit0_r ) { return BIT(m_value, 0); }
	DECLARE_READ_LINE_MEMBER( bit1_r ) { return BIT(m_value, 1); }
	DECLARE_READ_LINE_MEMBER( bit2_r ) { return BIT(m_value, 2); }
	DECLARE_READ_LINE_MEMBER( bit3_r ) { return BIT(m_value, 3); }
	DECLARE_READ_LINE_MEMBER( bit4_r ) { return BIT(m_value, 4); }
	DECLARE_READ_LINE_MEMBER( bit5_r ) { return BIT(m_value, 5); }
	DECLARE_READ_LINE_MEMBER( bit6_r ) { return BIT(m_value, 6); }
	DECLARE_READ_LINE_MEMBER( bit7_r ) { return BIT(m_value, 7); }

	/* read inverted bit x        */
	/* return (latch >> x) & 0x01 */

	DECLARE_READ_LINE_MEMBER( bit0_q_r ) { return BIT(m_value, 0) ^ 1; }
	DECLARE_READ_LINE_MEMBER( bit1_q_r ) { return BIT(m_value, 1) ^ 1; }
	DECLARE_READ_LINE_MEMBER( bit2_q_r ) { return BIT(m_value, 2) ^ 1; }
	DECLARE_READ_LINE_MEMBER( bit3_q_r ) { return BIT(m_value, 3) ^ 1; }
	DECLARE_READ_LINE_MEMBER( bit4_q_r ) { return BIT(m_value, 4) ^ 1; }
	DECLARE_READ_LINE_MEMBER( bit5_q_r ) { return BIT(m_value, 5) ^ 1; }
	DECLARE_READ_LINE_MEMBER( bit6_q_r ) { return BIT(m_value, 6) ^ 1; }
	DECLARE_READ_LINE_MEMBER( bit7_q_r ) { return BIT(m_value, 7) ^ 1; }

	/* write bit x from data into bit determined by offset */
	/* latch = (latch & ~(1<<offset)) | (((data >> x) & 0x01) << offset) */

	DECLARE_WRITE8_MEMBER( bit0_w );
	DECLARE_WRITE8_MEMBER( bit1_w );
	DECLARE_WRITE8_MEMBER( bit2_w );
	DECLARE_WRITE8_MEMBER( bit3_w );
	DECLARE_WRITE8_MEMBER( bit4_w );
	DECLARE_WRITE8_MEMBER( bit5_w );
	DECLARE_WRITE8_MEMBER( bit6_w );
	DECLARE_WRITE8_MEMBER( bit7_w );

	void set_maskout(uint32_t maskout) { m_maskout = maskout; }
	void set_xorvalue(uint32_t xorvalue) { m_xorvalue = xorvalue; }
	void set_nosync(uint32_t nosync) { m_nosync = nosync; }

	template <unsigned N, class Object> devcb_base &set_write_cb(Object &&cb) { return m_write_cb[N].set_callback(std::forward<Object>(cb)); }
	template <unsigned N, class Object> devcb_base &set_read_cb(Object &&cb) { return m_read_cb[N].set_callback(std::forward<Object>(cb)); }
	template <unsigned N> auto write_cb() { return m_write_cb[N].bind(); }
	template <unsigned N> auto read_cb() { return m_read_cb[N].bind(); }

protected:
	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_validity_check(validity_checker &valid) const override;

	TIMER_CALLBACK_MEMBER( timerproc );
	void update(uint8_t new_val, uint8_t mask);
	inline void bitx_w(int bit, offs_t offset, uint8_t data);

private:
	// internal state
	uint8_t            m_value;
	uint8_t            m_has_write;
	uint8_t            m_has_read;

	/* only for byte reads, does not affect bit reads and node_map */
	uint32_t           m_maskout;
	uint32_t           m_xorvalue;  /* after mask */
	uint32_t           m_nosync;

	devcb_write_line   m_write_cb[8];
	devcb_read_line    m_read_cb[8];
};

DECLARE_DEVICE_TYPE(LATCH8, latch8_device)

/***************************************************************************
    DEVICE CONFIGURATION MACROS
***************************************************************************/

/* add device */
#define MCFG_LATCH8_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, LATCH8, 0)

/* Bit mask specifying bits to be masked *out* */
#define MCFG_LATCH8_MASKOUT(_maskout) \
	downcast<latch8_device &>(*device).set_maskout(_maskout);

/* Bit mask specifying bits to be inverted */
#define MCFG_LATCH8_INVERT(_xor) \
	downcast<latch8_device &>(*device).set_xorvalue(_xor);

/* Bit mask specifying bits not needing cpu synchronization. */
#define MCFG_LATCH8_NOSYNC(_nosync) \
	downcast<latch8_device &>(*device).set_nosync(_nosync);

/* Write bit to discrete node */
#define MCFG_LATCH8_WRITE_0(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<0>(DEVCB_##_devcb);

#define MCFG_LATCH8_WRITE_1(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<1>(DEVCB_##_devcb);

#define MCFG_LATCH8_WRITE_2(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<2>(DEVCB_##_devcb);

#define MCFG_LATCH8_WRITE_3(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<3>(DEVCB_##_devcb);

#define MCFG_LATCH8_WRITE_4(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<4>(DEVCB_##_devcb);

#define MCFG_LATCH8_WRITE_5(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<5>(DEVCB_##_devcb);

#define MCFG_LATCH8_WRITE_6(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<6>(DEVCB_##_devcb);

#define MCFG_LATCH8_WRITE_7(_devcb) \
	downcast<latch8_device &>(*device).set_write_cb<7>(DEVCB_##_devcb);

/* Upon read, replace bits by reading from another device handler */
#define MCFG_LATCH8_READ_0(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<0>(DEVCB_##_devcb);

#define MCFG_LATCH8_READ_1(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<1>(DEVCB_##_devcb);

#define MCFG_LATCH8_READ_2(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<2>(DEVCB_##_devcb);

#define MCFG_LATCH8_READ_3(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<3>(DEVCB_##_devcb);

#define MCFG_LATCH8_READ_4(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<4>(DEVCB_##_devcb);

#define MCFG_LATCH8_READ_5(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<5>(DEVCB_##_devcb);

#define MCFG_LATCH8_READ_6(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<6>(DEVCB_##_devcb);

#define MCFG_LATCH8_READ_7(_devcb) \
	downcast<latch8_device &>(*device).set_read_cb<7>(DEVCB_##_devcb);


#endif // MAME_MACHINE_LATCH8_H