1 // license:BSD-3-Clause
2 // copyright-holders:Nathan Woods
3 /*********************************************************************
4 
5     cococart.h
6 
7     CoCo/Dragon cartridge management
8 
9 *********************************************************************/
10 
11 #ifndef MAME_BUS_COCO_COCOCART_H
12 #define MAME_BUS_COCO_COCOCART_H
13 
14 #pragma once
15 
16 #include "softlist_dev.h"
17 
18 
19 /***************************************************************************
20     TYPE DEFINITIONS
21 ***************************************************************************/
22 
23 // ======================> cococart_base_update_delegate
24 
25 // direct region update handler
26 typedef delegate<void (u8 *)> cococart_base_update_delegate;
27 
28 
29 // ======================> cococart_slot_device
30 class device_cococart_interface;
31 
32 class cococart_slot_device final : public device_t,
33 								public device_single_card_slot_interface<device_cococart_interface>,
34 								public device_image_interface
35 {
36 public:
37 	// output lines on the CoCo cartridge slot
38 	enum class line
39 	{
40 		CART,             // connects to PIA1 CB1
41 		NMI,              // connects to NMI line on CPU
42 		HALT,             // connects to HALT line on CPU
43 		SOUND_ENABLE      // sound enable
44 	};
45 
46 	// since we have a special value "Q" - we have to use a special enum here
47 	enum class line_value
48 	{
49 		CLEAR,
50 		ASSERT,
51 		Q
52 	};
53 
54 	// construction/destruction
55 	template <typename T>
cococart_slot_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock,T && opts,const char * dflt)56 	cococart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&opts, const char *dflt)
57 		: cococart_slot_device(mconfig, tag, owner, clock)
58 	{
59 		option_reset();
60 		opts(*this);
61 		set_default_option(dflt);
62 		set_fixed(false);
63 	}
64 	cococart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
65 
cart_callback()66 	auto cart_callback() { return m_cart_callback.bind(); }
nmi_callback()67 	auto nmi_callback() { return m_nmi_callback.bind(); }
halt_callback()68 	auto halt_callback() { return m_halt_callback.bind(); }
69 
70 	// device-level overrides
71 	virtual void device_start() override;
72 	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
73 
74 	// image-level overrides
75 	virtual image_init_result call_load() override;
get_software_list_loader()76 	virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
77 
image_type()78 	virtual iodevice_t image_type() const noexcept override { return IO_CARTSLOT; }
79 
is_readable()80 	virtual bool is_readable()  const noexcept override { return true; }
is_writeable()81 	virtual bool is_writeable() const noexcept override { return false; }
is_creatable()82 	virtual bool is_creatable() const noexcept override { return false; }
must_be_loaded()83 	virtual bool must_be_loaded() const noexcept override { return false; }
is_reset_on_load()84 	virtual bool is_reset_on_load() const noexcept override { return true; }
image_interface()85 	virtual const char *image_interface() const noexcept override { return "coco_cart"; }
file_extensions()86 	virtual const char *file_extensions() const noexcept override { return "ccc,rom"; }
87 
88 	// slot interface overrides
89 	virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override;
90 
91 	// reading and writing to $C000-$FFEF
92 	u8 cts_read(offs_t offset);
93 	void cts_write(offs_t offset, u8 data);
94 
95 	// reading and writing to $FF40-$FF5F
96 	u8 scs_read(offs_t offset);
97 	void scs_write(offs_t offset, u8 data);
98 
99 	// manipulation of cartridge lines
100 	void set_line_value(line line, line_value value);
101 	void set_line_delay(line line, int cycles);
102 	line_value get_line_value(line line) const;
103 
104 	// hack to support twiddling the Q line
105 	void twiddle_q_lines();
106 
107 	// cart base
108 	u8 *get_cart_base();
109 	u32 get_cart_size();
110 	void set_cart_base_update(cococart_base_update_delegate update);
111 
112 private:
113 	// TIMER_POOL: Must be power of two
114 	static constexpr int TIMER_POOL = 2;
115 
116 	struct coco_cartridge_line
117 	{
118 		emu_timer                   *timer[TIMER_POOL];
119 		int                         timer_index;
120 		int                         delay;
121 		line_value                  value;
122 		int                         line;
123 		int                         q_count;
124 		devcb_write_line *          callback;
125 	};
126 
127 	// configuration
128 	coco_cartridge_line         m_cart_line;
129 	coco_cartridge_line         m_nmi_line;
130 	coco_cartridge_line         m_halt_line;
131 public:
132 	devcb_write_line        m_cart_callback;
133 	devcb_write_line            m_nmi_callback;
134 	devcb_write_line            m_halt_callback;
135 private:
136 	// cartridge
137 	device_cococart_interface   *m_cart;
138 
139 	// methods
140 	void set_line(const char *line_name, coco_cartridge_line &line, line_value value);
141 	void set_line_timer(coco_cartridge_line &line, line_value value);
142 	void twiddle_line_if_q(coco_cartridge_line &line);
143 	static const char *line_value_string(line_value value);
144 };
145 
146 // device type definition
DECLARE_DEVICE_TYPE(COCOCART_SLOT,cococart_slot_device)147 DECLARE_DEVICE_TYPE(COCOCART_SLOT, cococart_slot_device)
148 
149 
150 // ======================> device_cococart_host_interface
151 
152 // this is implemented by the CoCo root device itself and the Multi-Pak interface
153 class device_cococart_host_interface
154 {
155 public:
156 	virtual address_space &cartridge_space() = 0;
157 };
158 
159 
160 // ======================> device_cococart_interface
161 
162 class device_cococart_interface : public device_interface
163 {
164 public:
165 	// construction/destruction
166 	virtual ~device_cococart_interface();
167 
168 	virtual u8 cts_read(offs_t offset);
169 	virtual void cts_write(offs_t offset, u8 data);
170 	virtual u8 scs_read(offs_t offset);
171 	virtual void scs_write(offs_t offset, u8 data);
172 	virtual void set_sound_enable(bool sound_enable);
173 
174 	virtual u8 *get_cart_base();
175 	virtual u32 get_cart_size();
176 	void set_cart_base_update(cococart_base_update_delegate update);
177 	virtual memory_region *get_cart_memregion();
178 
179 protected:
180 	virtual void interface_config_complete() override;
181 	virtual void interface_pre_start() override;
182 
183 	device_cococart_interface(const machine_config &mconfig, device_t &device);
184 
185 	void cart_base_changed(void);
186 
187 	// accessors for containers
owning_slot()188 	cococart_slot_device &owning_slot()     { assert(m_owning_slot); return *m_owning_slot; }
host()189 	device_cococart_host_interface &host()  { assert(m_host); return *m_host; }
190 
191 	// CoCo cartridges can read directly from the address bus.  This is used by a number of
192 	// cartridges (e.g. - Orch-90, Multi-Pak interface) for their control registers, independently
193 	// of the SCS or CTS lines
194 	address_space &cartridge_space();
195 	template <typename R>
install_read_handler(u16 addrstart,u16 addrend,R && rhandler)196 	void install_read_handler(u16 addrstart, u16 addrend, R &&rhandler)
197 	{
198 		address_space &space(cartridge_space());
199 		space.install_read_handler(addrstart, addrend, std::forward<R>(rhandler));
200 	}
201 	template <typename W>
install_write_handler(u16 addrstart,u16 addrend,W && whandler)202 	void install_write_handler(u16 addrstart, u16 addrend, W &&whandler)
203 	{
204 		address_space &space(cartridge_space());
205 		space.install_write_handler(addrstart, addrend, std::forward<W>(whandler));
206 	}
207 	template <typename R, typename W>
install_readwrite_handler(u16 addrstart,u16 addrend,R && rhandler,W && whandler)208 	void install_readwrite_handler(u16 addrstart, u16 addrend, R &&rhandler, W &&whandler)
209 	{
210 		address_space &space(cartridge_space());
211 		space.install_read_handler(addrstart, addrend, std::forward<R>(rhandler));
212 		space.install_write_handler(addrstart, addrend, std::forward<W>(whandler));
213 	}
214 
215 	// setting line values
216 	void set_line_value(cococart_slot_device::line line, cococart_slot_device::line_value value);
set_line_value(cococart_slot_device::line line,bool value)217 	void set_line_value(cococart_slot_device::line line, bool value) { set_line_value(line, value ? cococart_slot_device::line_value::ASSERT : cococart_slot_device::line_value::CLEAR); }
218 
219 	typedef cococart_slot_device::line line;
220 	typedef cococart_slot_device::line_value line_value;
221 
222 private:
223 	cococart_base_update_delegate    m_update;
224 	cococart_slot_device *           m_owning_slot;
225 	device_cococart_host_interface * m_host;
226 };
227 
228 #endif // MAME_BUS_COCO_COCOCART_H
229