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