1 // license:BSD-3-Clause
2 // copyright-holders:R. Belmont
3 /***************************************************************************
4 
5   a2bus.h - Apple II slot bus and card emulation
6 
7   by R. Belmont
8 
9 ***************************************************************************/
10 
11 #ifndef MAME_BUS_A2BUS_A2BUS_H
12 #define MAME_BUS_A2BUS_A2BUS_H
13 
14 #pragma once
15 
16 #include <utility>
17 
18 
19 // /INH special addresses
20 #define INH_START_INVALID   0xffff
21 #define INH_END_INVALID     0x0000
22 
23 // /INH types
24 #define INH_NONE            0x00
25 #define INH_READ            0x01
26 #define INH_WRITE           0x02
27 
28 // 7M = XTAL(14'318'181) / 2 or XTAL(28'636'363) / 4 (for IIgs)
29 static constexpr uint32_t A2BUS_7M_CLOCK = 7159090;
30 
31 //**************************************************************************
32 //  TYPE DEFINITIONS
33 //**************************************************************************
34 
35 class a2bus_device;
36 class device_a2bus_card_interface;
37 
38 class a2bus_slot_device : public device_t, public device_single_card_slot_interface<device_a2bus_card_interface>
39 {
40 public:
41 	// construction/destruction
42 	template <typename T, typename U>
a2bus_slot_device(const machine_config & mconfig,const char * tag,device_t * owner,T && a2bus_tag,U && opts,const char * dflt)43 	a2bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&a2bus_tag, U &&opts, const char *dflt)
44 		: a2bus_slot_device(mconfig, tag, owner, A2BUS_7M_CLOCK, std::forward<T>(a2bus_tag), std::forward<U>(opts), dflt)
45 	{
46 	}
47 	template <typename T, typename U>
a2bus_slot_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock,T && a2bus_tag,U && opts,const char * dflt)48 	a2bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&a2bus_tag, U &&opts, const char *dflt)
49 		: a2bus_slot_device(mconfig, tag, owner, clock)
50 	{
51 		option_reset();
52 		opts(*this);
53 		set_default_option(dflt);
54 		set_fixed(false);
55 		m_a2bus.set_tag(std::forward<T>(a2bus_tag));
56 	}
57 	a2bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = A2BUS_7M_CLOCK);
58 
59 protected:
60 	a2bus_slot_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
61 
62 	// device-level overrides
63 	virtual void device_resolve_objects() override;
64 	virtual void device_start() override;
65 
66 	// configuration
67 	required_device<a2bus_device> m_a2bus;
68 };
69 
70 // device type definition
DECLARE_DEVICE_TYPE(A2BUS_SLOT,a2bus_slot_device)71 DECLARE_DEVICE_TYPE(A2BUS_SLOT, a2bus_slot_device)
72 
73 
74 // ======================> a2bus_device
75 class a2bus_device : public device_t
76 {
77 	// multi-card devices need to access m_device_list, so they get friended here.
78 	friend class a2bus_mcms2_device;
79 public:
80 	// construction/destruction
81 	a2bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
82 
83 	// inline configuration
84 	template <typename T> void set_space(T &&tag, int spacenum) { m_maincpu_space.set_tag(std::forward<T>(tag), spacenum); }
85 	auto irq_w() { return m_out_irq_cb.bind(); }
86 	auto nmi_w() { return m_out_nmi_cb.bind(); }
87 	auto inh_w() { return m_out_inh_cb.bind(); }
88 	auto dma_w() { return m_out_dma_cb.bind(); }
89 
90 	void add_a2bus_card(int slot, device_a2bus_card_interface *card);
91 	device_a2bus_card_interface *get_a2bus_card(int slot);
92 	uint8_t get_a2bus_irq_mask();
93 	uint8_t get_a2bus_nmi_mask();
94 
95 	void set_irq_line(int state, int slot);
96 	void set_nmi_line(int state, int slot);
97 	void set_dma_line(int state);
98 	void recalc_inh(int slot);
99 	uint8_t dma_r(uint16_t offset);
100 	void dma_w(uint16_t offset, uint8_t data);
101 
102 	DECLARE_WRITE_LINE_MEMBER( irq_w );
103 	DECLARE_WRITE_LINE_MEMBER( nmi_w );
104 
105 protected:
106 	a2bus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
107 
108 	// device-level overrides
109 	virtual void device_resolve_objects() override;
110 	virtual void device_start() override;
111 	virtual void device_reset() override;
112 
113 	// internal state
114 	required_address_space m_maincpu_space;
115 
116 	devcb_write_line    m_out_irq_cb;
117 	devcb_write_line    m_out_nmi_cb;
118 	devcb_write8        m_out_inh_cb;
119 	devcb_write_line    m_out_dma_cb;
120 
121 	device_a2bus_card_interface *m_device_list[8];
122 
123 	uint8_t m_slot_irq_mask;
124 	uint8_t m_slot_nmi_mask;
125 };
126 
127 
128 // device type definition
DECLARE_DEVICE_TYPE(A2BUS,a2bus_device)129 DECLARE_DEVICE_TYPE(A2BUS, a2bus_device)
130 
131 // ======================> device_a2bus_card_interface
132 
133 // class representing interface-specific live a2bus card
134 class device_a2bus_card_interface : public device_interface
135 {
136 	friend class a2bus_device;
137 public:
138 	// construction/destruction
139 	virtual ~device_a2bus_card_interface();
140 
141 	virtual uint8_t read_c0nx(uint8_t offset) { device().logerror("a2bus: unhandled read at C0n%x\n", offset); return 0; }       // C0nX - /DEVSEL
142 	virtual void write_c0nx(uint8_t offset, uint8_t data) { device().logerror("a2bus: unhandled write %02x to C0n%x\n", data, offset); }
143 	virtual uint8_t read_cnxx(uint8_t offset) { return 0; }       // CnXX - /IOSEL
144 	virtual void write_cnxx(uint8_t offset, uint8_t data) { device().logerror("a2bus: unhandled write %02x to Cn%02x\n", data, offset); }
145 	virtual uint8_t read_c800(uint16_t offset) { return 0; }      // C800 - /IOSTB
146 	virtual void write_c800(uint16_t offset, uint8_t data) {device().logerror("a2bus: unhandled write %02x to %04x\n", data, offset + 0xc800); }
147 	virtual bool take_c800() { return true; }   // override and return false if your card doesn't take over the c800 space
148 	virtual uint8_t read_inh_rom(uint16_t offset) { return 0; }
149 	virtual void write_inh_rom(uint16_t offset, uint8_t data) { }
150 	virtual uint16_t inh_start() { return INH_START_INVALID; }
151 	virtual uint16_t inh_end() { return INH_END_INVALID; }
152 	virtual int inh_type() { return INH_NONE; }
153 
154 	device_a2bus_card_interface *next() const { return m_next; }
155 
156 	// inline configuration
157 	void set_a2bus(a2bus_device *a2bus, const char *slottag) { m_a2bus = a2bus; m_a2bus_slottag = slottag; }
158 	template <typename T> void set_onboard(T &&a2bus) { m_a2bus_finder.set_tag(std::forward<T>(a2bus)); m_a2bus_slottag = device().tag(); }
159 
160 	uint8_t slot_dma_read(uint16_t offset) { return m_a2bus->dma_r(offset); }
161 	void slot_dma_write(uint16_t offset, uint8_t data) { m_a2bus->dma_w(offset, data); }
162 
163 protected:
164 	uint32_t get_slotromspace() { return 0xc000 | (m_slot<<8); }      // return Cn00 address for this slot
165 	uint32_t get_slotiospace() { return 0xc080 + (m_slot<<4); }       // return C0n0 address for this slot
166 
167 	void raise_slot_irq() { m_a2bus->set_irq_line(ASSERT_LINE, m_slot); }
168 	void lower_slot_irq() { m_a2bus->set_irq_line(CLEAR_LINE, m_slot); }
169 	void raise_slot_nmi() { m_a2bus->set_nmi_line(ASSERT_LINE, m_slot); }
170 	void lower_slot_nmi() { m_a2bus->set_nmi_line(CLEAR_LINE, m_slot); }
171 	void recalc_slot_inh() { m_a2bus->recalc_inh(m_slot); }
172 	void raise_slot_dma() { m_a2bus->set_dma_line(ASSERT_LINE); }
173 	void lower_slot_dma() { m_a2bus->set_dma_line(CLEAR_LINE); }
174 
175 	device_a2bus_card_interface(const machine_config &mconfig, device_t &device);
176 
177 	virtual void interface_validity_check(validity_checker &valid) const override;
178 	virtual void interface_pre_start() override;
179 
180 	int slotno() const { assert(m_a2bus); return m_slot; }
181 	a2bus_device &a2bus() { assert(m_a2bus); return *m_a2bus; }
182 
183 private:
184 	optional_device<a2bus_device> m_a2bus_finder;
185 	a2bus_device *m_a2bus;
186 	const char *m_a2bus_slottag;
187 	int m_slot;
188 	device_a2bus_card_interface *m_next;
189 };
190 
191 #endif  // MAME_BUS_A2BUS_A2BUS_H
192