1 // license:BSD-3-Clause
2 // copyright-holders:Patrick Mackinlay
3 
4 /*
5  * An implementation of the MCT-ADR device found in Microsoft Jazz/MIPS
6  * ARCSystem 100 architecture systems. This device was originally designed
7  * by Microsoft, and then implemented and used in various forms by MIPS,
8  * Olivetti, LSI Logic, NEC, Acer and others.
9  *
10  * Specific implementations/derivatives include:
11  *
12  *   LSI Logic R4030/R4230
13  *   NEC μPD31432
14  *   ALI M6101-A1
15  *
16  * References:
17  *
18  *   https://datasheet.datasheetarchive.com/originals/scans/Scans-054/DSAIH000102184.pdf
19  *   https://github.com/torvalds/linux/tree/master/arch/mips/jazz/
20  *   http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/arc/jazz/
21  *
22  *   https://www.linux-mips.org/archives/riscy/1993-08/msg00064.html
23  *   https://www.linux-mips.org/archives/riscy/1993-08/msg00069.html
24  *
25  * TODO
26  *   - proper width dma
27  *   - dma address translation errors
28  *   - I/O cache
29  *   - revision 2 device
30  */
31 
32 #include "emu.h"
33 #include "mct_adr.h"
34 
35 #define VERBOSE 0
36 #include "logmacro.h"
37 
38 DEFINE_DEVICE_TYPE(MCT_ADR, mct_adr_device, "mct_adr", "MCT-ADR Address Path Controller")
39 
mct_adr_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)40 mct_adr_device::mct_adr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
41 	: device_t(mconfig, MCT_ADR, tag, owner, clock)
42 	, device_memory_interface(mconfig, *this)
43 	, m_io_config("io", ENDIANNESS_LITTLE, 32, 32, 0)
44 	, m_dma_config("dma", ENDIANNESS_LITTLE, 32, 32, 0, address_map_constructor(FUNC(mct_adr_device::dma), this))
45 	, m_out_int_dma(*this)
46 	, m_out_int_device(*this)
47 	, m_out_int_timer(*this)
48 	, m_eisa_iack(*this)
49 	, m_dma_r(*this)
50 	, m_dma_w(*this)
51 {
52 }
53 
map(address_map & map)54 void mct_adr_device::map(address_map &map)
55 {
56 	map(0x000, 0x007).lrw32(NAME([this] () { return m_config; }), NAME([this] (u32 data) { m_config = data; }));
57 	map(0x008, 0x00f).lr32([] () { return 1; }, "revision_level");
58 	map(0x010, 0x017).lr32(NAME([this] () { m_dma_interrupt_source &= ~DMA_ADDRESS_ERROR; return m_dma_invalid_address; }));
59 	map(0x018, 0x01f).lrw32(NAME([this] () { return m_trans_tbl_base; }), NAME([this] (u32 data) { LOG("tbl base 0x%08x\n", data); m_trans_tbl_base = data; }));
60 	map(0x020, 0x027).lrw32(NAME([this] () { return m_trans_tbl_limit; }), NAME([this] (u32 data) { LOG("tbl limit 0x%08x\n", data); m_trans_tbl_limit = data; }));
61 	map(0x028, 0x02f).lrw32([] () { return 0; }, "translation_invalidate_r", [] (u32 data) { }, "translation_invalidate_w");
62 	map(0x030, 0x037).lw32(NAME([this] (u32 data) { m_ioc_maint = data; }));
63 	map(0x038, 0x03f).lr32([] () { return 0; }, "remote_failed_address");
64 	map(0x040, 0x047).lr32(NAME([this] () { m_dma_interrupt_source &= ~DMA_PARITY_ERROR; return m_dma_memory_failed_address; }));
65 	map(0x048, 0x04f).lw32(NAME([this] (u32 data) { m_ioc_physical_tag = data; }));
66 	map(0x050, 0x057).lw32(NAME([this] (u32 data) { m_ioc_logical_tag = data; }));
67 	map(0x058, 0x05f).lrw32(
68 			// FIXME: hack to pass diagnostics
69 			[this] ()
70 			{
71 				u32 const data = m_ioc_byte_mask;
72 
73 				if (data == 0xffffffff)
74 					m_ioc_byte_mask = 0;
75 				return data;
76 			}, "io_cache_byte_mask_r",
77 			NAME([this] (u32 data) { m_ioc_byte_mask |= data; }));
78 	map(0x060, 0x067).lw32(
79 			[this] (u32 data)
80 			{
81 				// FIXME: hack to pass diagnostics
82 				if (m_ioc_logical_tag == 0x80000001 && m_ioc_byte_mask == 0x0f0f0f0f)
83 				{
84 					u32 const address = (m_ioc_physical_tag & ~0x1) + ((m_ioc_maint & 0x3) << 3);
85 
86 					space(0).write_dword(address, data);
87 				}
88 			}, "io_cache_buffer_window_lo");
89 	// io_cache_buffer_window_hi
90 	map(0x070, 0x0ef).lrw32(
91 			NAME([this] (offs_t offset) { return m_remote_speed[offset  >> 1]; }),
92 			NAME([this] (offs_t offset, u32 data) { m_remote_speed[offset >> 1] = data; }));
93 	// parity_diagnostic_lo
94 	// parity_diagnostic_hi
95 	map(0x100, 0x1ff).lrw32(
96 			NAME([this] (offs_t offset) { return m_dma_reg[offset >> 1]; }),
97 			[this] (offs_t offset, u32 data)
98 			{
99 				unsigned const reg = offset >> 1;
100 
101 				LOG("dma_reg %d data 0x%08x (%s)\n", offset, data, machine().describe_context());
102 
103 				m_dma_reg[reg] = data;
104 
105 				if ((reg == REG_ENABLE) && (data & DMA_ENABLE))
106 					LOG("dma started address 0x%08x count %d\n", translate_address(m_dma_reg[(0 << 2) + REG_ADDRESS]), m_dma_reg[(0 << 2) + REG_COUNT]);
107 			}, "dma_reg_w");
108 	map(0x200, 0x207).lr32(NAME([this] () { return m_dma_interrupt_source; }));
109 	map(0x208, 0x20f).lr32([] () { return 0; }, "error_type");
110 	map(0x210, 0x217).lrw32(NAME([this] () { return m_memory_refresh_rate; }), NAME([this] (u32 data) { m_memory_refresh_rate = data; }));
111 	// refresh_counter
112 	map(0x220, 0x227).lrw32(NAME([this] () { return m_nvram_protect; }), NAME([this] (u32 data) { LOG("nvram_protect 0x%08x (%s)\n", data, machine().describe_context()); m_nvram_protect = data; }));
113 	map(0x228, 0x22f).lw32(
114 			[this] (u32 data)
115 			{
116 				LOG("timer_w 0x%08x\n", data);
117 
118 				attotime interval = attotime::from_ticks((data + 1) & 0x1ff, 1000);
119 
120 				m_interval_timer->adjust(interval, 0, interval);
121 			}, "interrupt_interval");
122 	map(0x230, 0x237).lr32([this] () { if (m_out_int_timer_asserted) { m_out_int_timer_asserted = false; m_out_int_timer(0); } return m_interval_timer->remaining().as_ticks(1000); }, "interval_timer");
123 	map(0x238, 0x23b).lr32(NAME([this] () { return m_eisa_iack(); }));
124 }
125 
126 // HACK: this address map translates i386 bus master DMA device access (the
127 // SONIC network controller) to DRAM.
memory_space_config() const128 device_memory_interface::space_config_vector mct_adr_device::memory_space_config() const
129 {
130 	return space_config_vector{
131 		std::make_pair(0, &m_io_config),
132 		std::make_pair(1, &m_dma_config)
133 	};
134 }
135 
dma(address_map & map)136 void mct_adr_device::dma(address_map &map)
137 {
138 	map(0x00000000U, 0xffffffffU).rw(FUNC(mct_adr_device::dma_r), FUNC(mct_adr_device::dma_w));
139 }
140 
device_start()141 void mct_adr_device::device_start()
142 {
143 	m_out_int_dma.resolve();
144 	m_out_int_device.resolve();
145 	m_out_int_timer.resolve();
146 	m_eisa_iack.resolve();
147 
148 	m_dma_r.resolve_all_safe(0xff);
149 	m_dma_w.resolve_all_safe();
150 
151 	m_ioc_maint = 0;
152 	m_ioc_physical_tag = 0;
153 	m_ioc_logical_tag = 0;
154 
155 	m_irq_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mct_adr_device::irq_check), this));
156 	m_dma_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mct_adr_device::dma_check), this));
157 	m_interval_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mct_adr_device::interval_timer), this));
158 
159 	m_out_int_timer_asserted = false;
160 	m_out_int_device_asserted = false;
161 }
162 
device_reset()163 void mct_adr_device::device_reset()
164 {
165 	m_config = 0x104; // REV1, REV2 is 0x410
166 	m_trans_tbl_base = 0;
167 	m_trans_tbl_limit = 0;
168 	m_ioc_byte_mask = 0;
169 
170 	for (u32 &val : m_remote_speed)
171 		val = 0x7;
172 
173 	for (u32 &val : m_dma_reg)
174 		val = 0;
175 
176 	m_dma_interrupt_source = 0;
177 	m_memory_refresh_rate = 0x18186;
178 	m_nvram_protect = 0x7;
179 
180 	m_dma_invalid_address = 0;
181 	m_dma_memory_failed_address = 0;
182 
183 	m_isr = 0;
184 	m_imr = 0x10; // firmware diagnostic expects network interrupts to be unmasked at boot
185 
186 	m_interval_timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1));
187 
188 	irq_check(nullptr, 0);
189 }
190 
set_irq_line(int irq,int state)191 void mct_adr_device::set_irq_line(int irq, int state)
192 {
193 	if ((irq != 3) && (m_isr & (1 << irq)) ^ (state << irq))
194 		LOG("set_irq_line %d state %d m_imr 0x%04x\n", irq, state, m_imr);
195 
196 	if (state)
197 		m_isr |= (1 << irq);
198 	else
199 		m_isr &= ~(1 << irq);
200 
201 	m_irq_check->adjust(attotime::zero);
202 }
203 
TIMER_CALLBACK_MEMBER(mct_adr_device::irq_check)204 TIMER_CALLBACK_MEMBER(mct_adr_device::irq_check)
205 {
206 	if (bool(m_isr & m_imr) != m_out_int_device_asserted)
207 	{
208 		m_out_int_device_asserted = bool(m_isr & m_imr);
209 
210 		m_out_int_device(m_out_int_device_asserted ? 1 : 0);
211 	}
212 }
213 
isr_r()214 u16 mct_adr_device::isr_r()
215 {
216 	u16 const pending = m_isr & m_imr;
217 
218 	for (u16 irq = 0; irq < 16; irq++)
219 		if (BIT(pending, irq))
220 			return (irq + 1) << 2;
221 
222 	return 0;
223 }
224 
imr_w(u16 data)225 void mct_adr_device::imr_w(u16 data)
226 {
227 	LOG("imr_w 0x%04x (%s)\n", data, machine().describe_context());
228 
229 	m_imr = data;
230 
231 	m_irq_check->adjust(attotime::zero);
232 }
233 
TIMER_CALLBACK_MEMBER(mct_adr_device::interval_timer)234 TIMER_CALLBACK_MEMBER(mct_adr_device::interval_timer)
235 {
236 	if (m_out_int_timer_asserted)
237 		m_out_int_timer(0);
238 	else
239 		m_out_int_timer_asserted = true;
240 
241 	m_out_int_timer(1);
242 }
243 
set_drq_line(int channel,int state)244 void mct_adr_device::set_drq_line(int channel, int state)
245 {
246 	m_drq_active[channel] = state == ASSERT_LINE;
247 
248 	if (state)
249 		m_dma_check->adjust(attotime::zero);
250 }
251 
TIMER_CALLBACK_MEMBER(mct_adr_device::dma_check)252 TIMER_CALLBACK_MEMBER(mct_adr_device::dma_check)
253 {
254 	bool active = false;
255 
256 	for (int channel = 0; channel < 4; channel++)
257 	{
258 		if (!m_drq_active[channel])
259 			continue;
260 
261 		// reg 0x00: 0x00000011 - mode (ch0) (WIDTH16 | ATIME_80)
262 		// reg 0x20: 0x0000000a - mode (ch1) (WIDTH8 | ATIME_120)
263 		// reg 0x18: 0x00000f20 - address
264 		// reg 0x10: 0x00000024 - count
265 		// reg 0x08: 0x00000001 - enable (ENABLE | !WRITE)
266 
267 		// check channel enabled
268 		if (!(m_dma_reg[(channel << 2) + REG_ENABLE] & DMA_ENABLE))
269 			return;
270 
271 		// check transfer count
272 		if (!m_dma_reg[(channel << 2) + REG_COUNT])
273 			return;
274 
275 		u32 const address = translate_address(m_dma_reg[(channel << 2) + REG_ADDRESS]);
276 
277 		// perform dma transfer
278 		if (m_dma_reg[(channel << 2) + REG_ENABLE] & DMA_DIRECTION)
279 		{
280 			u8 const data = space(0).read_byte(address);
281 
282 			//LOG("dma_w data 0x%02x address 0x%08x\n", data, address);
283 
284 			m_dma_w[channel](data);
285 		}
286 		else
287 		{
288 			u8 const data = m_dma_r[channel]();
289 
290 			//LOG("dma_r data 0x%02x address 0x%08x\n", data, address);
291 
292 			space(0).write_byte(address, data);
293 		}
294 
295 		// increment address, decrement count
296 		m_dma_reg[(channel << 2) + REG_ADDRESS]++;
297 		m_dma_reg[(channel << 2) + REG_COUNT]--;
298 
299 		// set terminal count flag
300 		if (!m_dma_reg[(channel << 2) + REG_COUNT])
301 		{
302 			m_dma_reg[(channel << 2) + REG_ENABLE] |= DMA_TERMINAL_COUNT;
303 
304 			// TODO: dma interrupts
305 			if (m_dma_reg[(channel << 2) + REG_ENABLE] & DMA_INTERRUPT_ENABLE)
306 				logerror("dma interrupt enable - interrupt expected\n");
307 		}
308 
309 		if (m_drq_active[channel])
310 			active = true;
311 	}
312 
313 	if (active)
314 		m_dma_check->adjust(attotime::zero);
315 }
316 
translate_address(u32 logical_address)317 u32 mct_adr_device::translate_address(u32 logical_address)
318 {
319 	u32 page = logical_address >> 12;
320 	if (page < (m_trans_tbl_limit) >> 3)
321 	{
322 		u32 entry_address = (m_trans_tbl_base & 0x7fffffff) + page * 8;
323 
324 		return space(0).read_dword(entry_address) | (logical_address & 0xfff);
325 	}
326 	else
327 	{
328 		logerror("failed to translate address 0x%08x\n", logical_address);
329 
330 		return 0; // FIXME: address error
331 	}
332 }
333 
dma_r(offs_t offset,u32 mem_mask)334 u32 mct_adr_device::dma_r(offs_t offset, u32 mem_mask)
335 {
336 	u32 const address = translate_address(offset << 2);
337 
338 	return space(0).read_dword(address, mem_mask);
339 }
340 
dma_w(offs_t offset,u32 data,u32 mem_mask)341 void mct_adr_device::dma_w(offs_t offset, u32 data, u32 mem_mask)
342 {
343 	u32 const address = translate_address(offset << 2);
344 
345 	space(0).write_dword(address, data, mem_mask);
346 }
347