1 // license:BSD-3-Clause
2 // copyright-holders:Vas Crabb
3 /***************************************************************************
4 
5     WE|AT&T DSP16 series emulator
6 
7     There are three basic functional units:
8     * XAAU: ROM Address Arithmetic Unit
9       - Four 16-bit address registers (pc, pt, pr, pi)
10       - One 12-bit increment register (i)
11       - One 12-bit adder
12     * YAAU: RAM Address Arithmetic Unit
13       - Four 9-bit or 16-bit pointer registers (r0, r1, r2, r3)
14       - Two 9-bit or 16-bit increment registers (j, k)
15       - Two 9-bit or 16-bit array boundary registers (rb, re)
16       - One 9-bit or 16-bit adder
17     * DAU: Data Arithmetic Unit
18       - One 16-bit multiplier register (x)
19       - One 32-bit source register (y)
20       - One 32-bit product register (p)
21       - Two 36-bit accumulators (a0, a1)
22       - Three 8-bit counter registers (c0, c1, c2)
23       - One 7-bit control register (auc)
24       - One 16-bit status register (psw)
25       - One 16*16->32 multiplier
26       - One 36-bit ALU
27       - One 36->16 extract/saturate unit
28 
29     The instruction set allows for explicit parallelism.  It's possible
30     to issue a multiply, and ALU operation, a RAM/ROM transfer, and a
31     pointer postmodification in a single instruction.
32 
33     There's a 15-word "cache" that the DSP can execute from without the
34     cost of instruction fetches.  There's an instruction to cache the
35     next N instructions and repeat them M times, and an instruction to
36     execute the currently cached instructions M times.  Interrupts are
37     not serviced while executing from cache, and not all instructions
38     can be cached.
39 
40     One ROM load and one RAM load/store can be issued per machine cycle.
41     Normally the DSP will overlap fetch/decode for the next instruction
42     with execution of the current instruction.  However, when executing
43     from cache, the DSP doesn't need to fetch instructions from ROM so
44     it can overlap a data fetch for the next instruction with execution
45     of the current instruction.  A RAM store can only occur in the
46     second machine cycle of an instruction.
47 
48     When loading the cache, all but the last instruction loaded into the
49     cache run with with normal timings.  The last instruction always
50     executes in two cycles.  The second cycle is necessary to ensure the
51     DSP has an opportunity to overlap a data fetch for the first cached
52     instruction if necessary.  On the final iteration, the last cached
53     instruction runs with normal timings, allowing the DSP to overlap
54     the fetch for the next instruction to be executed from ROM.
55 
56     There's a buffered full duplex synchronous serial transceiver, and
57     a strobed parallel port.  Both have have interrupt capability and
58     configurable timing.
59 
60     The parallel port consists of sixteen bidirectional data lines
61     (PDB00-PDB15), a single peripheral select line (PSEL), a single
62     bidirectional input strobe line (PIDS), and a single bidirectional
63     output strobe line (PODS).  In active mode, reading the port yields
64     the current value in the input register and initiates a read.
65 
66     TODO:
67     * PSW overflow bits - are they sticky, how are they reset?
68     * Clarify rounding behaviour (F2 1011)
69     * Random condition (CON 01000/01001)
70     * Clarify serial behaviour
71     * Serial input
72     * More serial I/O signals
73     * Parallel I/O S/C mode
74     * More complete low-level parallel I/O hooks
75 
76 ***************************************************************************/
77 
78 #include "emu.h"
79 #include "dsp16.h"
80 #include "dsp16core.ipp"
81 #include "dsp16rc.h"
82 
83 #include "debugger.h"
84 
85 #include <functional>
86 #include <limits>
87 
88 #define LOG_GENERAL     (1U << 0)
89 #define LOG_INT         (1U << 1)
90 #define LOG_SIO         (1U << 2)
91 #define LOG_PIO         (1U << 3)
92 
93 //#define VERBOSE (LOG_GENERAL | LOG_INT | LOG_SIO | LOG_PIO)
94 //#define LOG_OUTPUT_STREAM std::cout
95 #include "logmacro.h"
96 
97 #define LOGINT(...)     LOGMASKED(LOG_INT, __VA_ARGS__)
98 #define LOGSIO(...)     LOGMASKED(LOG_SIO, __VA_ARGS__)
99 #define LOGPIO(...)     LOGMASKED(LOG_PIO, __VA_ARGS__)
100 
101 
102 /***************************************************************************
103     DEVICE TYPE DEFINITIONS
104 ***************************************************************************/
105 
106 DEFINE_DEVICE_TYPE(DSP16, dsp16_device, "dsp16", "WE|AT&T DSP16")
107 DEFINE_DEVICE_TYPE(DSP16A, dsp16a_device, "dsp16a", "WE|AT&T DSP16A")
108 
109 
110 /***************************************************************************
111     DSP16 SERIES BASE IMPLEMENTATION
112 ***************************************************************************/
113 
114 ALLOW_SAVE_TYPE(dsp16_device_base::cache);
115 ALLOW_SAVE_TYPE(dsp16_device_base::phase);
116 ALLOW_SAVE_TYPE(dsp16_device_base::flags);
117 ALLOW_SAVE_TYPE(dsp16_device_base::sio_flags);
118 
WRITE_LINE_MEMBER(dsp16_device_base::exm_w)119 WRITE_LINE_MEMBER(dsp16_device_base::exm_w)
120 {
121 	if (bool(state) != bool(m_exm_in))
122 	{
123 		m_exm_in = state ? 1U : 0U;
124 		if (started())
125 			external_memory_enable(*m_spaces[AS_PROGRAM], !m_exm_in);
126 	}
127 }
128 
129 /***********************************************************************
130     high-level passive parallel I/O handlers
131 ***********************************************************************/
132 
pio_r()133 u16 dsp16_device_base::pio_r()
134 {
135 	if (!pio_pods_active())
136 	{
137 		LOGPIO("DSP16: PIO host read PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, m_pio_pdx_out, m_st_pcbase);
138 		if (!pio_pods_status())
139 			LOGINT("DSP16: set PODS flag (PC = %04X)\n", m_st_pcbase);
140 		m_pio_pioc |= u16(1) << 1;
141 		return m_pio_pdx_out;
142 	}
143 	else
144 	{
145 		logerror("DSP16: warning: PIO host read in active mode - returning line status (PC = %04X)\n", m_st_pcbase);
146 		// TODO: improve this when low-level interface is more complete
147 		return !m_pods_out ? m_pio_pdx_out : 0xffffU;
148 	}
149 }
150 
pio_w(u16 data)151 void dsp16_device_base::pio_w(u16 data)
152 {
153 	if (!pio_pids_active())
154 	{
155 		LOGPIO("DSP16: PIO host write PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, data, m_st_pcbase);
156 		if (!pio_pids_status())
157 			LOGINT("DSP16: set PIDS flag (PC = %04X)\n", m_st_pcbase);
158 		m_pio_pioc |= u16(1) << 2;
159 		m_pio_pdx_in = data;
160 	}
161 	else
162 	{
163 		logerror("DSP16: warning: ignoring PIO host write in active mode (PC = %04X)\n", m_st_pcbase);
164 	}
165 }
166 
167 /***********************************************************************
168     construction/destruction
169 ***********************************************************************/
170 
dsp16_device_base(machine_config const & mconfig,device_type type,char const * tag,device_t * owner,u32 clock,u8 yaau_bits,address_map_constructor && data_map)171 dsp16_device_base::dsp16_device_base(
172 		machine_config const &mconfig,
173 		device_type type,
174 		char const *tag,
175 		device_t *owner,
176 		u32 clock,
177 		u8 yaau_bits,
178 		address_map_constructor &&data_map)
179 	: cpu_device(mconfig, type, tag, owner, clock)
180 	, m_iack_cb(*this)
181 	, m_ick_cb(*this), m_ild_cb(*this)
182 	, m_do_cb(*this), m_ock_cb(*this), m_old_cb(*this), m_ose_cb(*this)
183 	, m_pio_r_cb(*this), m_pio_w_cb(*this), m_pdb_w_cb(*this), m_psel_cb(*this), m_pids_cb(*this), m_pods_cb(*this)
184 	, m_space_config{
185 			{ "rom", ENDIANNESS_BIG, 16, 16, -1, address_map_constructor(FUNC(dsp16_device_base::program_map), this) },
186 			{ "ram", ENDIANNESS_BIG, 16, yaau_bits, -1, std::move(data_map) },
187 			{ "exm", ENDIANNESS_BIG, 16, 16, -1 } }
188 	, m_yaau_bits(yaau_bits)
189 	, m_workram(*this, "workram"), m_spaces{ nullptr, nullptr, nullptr }, m_workram_mask(0U)
__anone163da9e0102(core_state *core) 190 	, m_drc_cache(CACHE_SIZE), m_core(nullptr, [] (core_state *core) { core->~core_state(); }), m_recompiler()
191 	, m_cache_mode(cache::NONE), m_phase(phase::PURGE), m_int_enable{ 0U, 0U }, m_flags(FLAGS_NONE), m_cache_ptr(0U), m_cache_limit(0U), m_cache_iterations(0U)
192 	, m_exm_in(1U), m_int_in(CLEAR_LINE), m_iack_out(1U)
193 	, m_ick_in(1U), m_ild_in(CLEAR_LINE), m_do_out(1U), m_ock_in(1U), m_old_in(CLEAR_LINE), m_ose_out(1U)
194 	, m_psel_out(0U), m_pids_out(1U), m_pods_out(1U)
195 	, m_sio_sioc(0U), m_sio_obuf(0U), m_sio_osr(0U), m_sio_ofsr(0U)
196 	, m_sio_clk(1U), m_sio_clk_div(0U), m_sio_clk_res(0U), m_sio_ld(1U), m_sio_ld_div(0U), m_sio_flags(SIO_FLAGS_NONE)
197 	, m_pio_pioc(0U), m_pio_pdx_in(0U), m_pio_pdx_out(0U), m_pio_pids_cnt(0U), m_pio_pods_cnt(0U)
198 	, m_cache_pcbase(0U), m_st_pcbase(0U), m_st_genflags(0U), m_st_yh(0), m_st_ah{ 0, 0 }, m_st_yl(0U), m_st_al{ 0U, 0U }
199 {
200 }
201 
202 /***********************************************************************
203     device_t implementation
204 ***********************************************************************/
205 
device_resolve_objects()206 void dsp16_device_base::device_resolve_objects()
207 {
208 	m_iack_cb.resolve_safe();
209 
210 	m_ick_cb.resolve_safe();
211 	m_ild_cb.resolve_safe();
212 	m_do_cb.resolve_safe();
213 	m_ock_cb.resolve_safe();
214 	m_old_cb.resolve_safe();
215 	m_ose_cb.resolve_safe();
216 
217 	m_pio_r_cb.resolve();
218 	m_pio_w_cb.resolve_safe();
219 	m_pdb_w_cb.resolve_safe();
220 	m_psel_cb.resolve_safe();
221 	m_pids_cb.resolve_safe();
222 	m_pods_cb.resolve_safe();
223 }
224 
device_start()225 void dsp16_device_base::device_start()
226 {
227 	m_core.reset(reinterpret_cast<core_state *>(m_drc_cache.alloc_near(sizeof(core_state))));
228 	new (m_core.get()) core_state(m_yaau_bits);
229 	set_icountptr(m_core->icount);
230 
231 	m_spaces[AS_PROGRAM] = &space(AS_PROGRAM);
232 	m_spaces[AS_DATA] = &space(AS_DATA);
233 	m_spaces[AS_IO] = &space(AS_IO);
234 	m_spaces[AS_PROGRAM]->cache(m_pcache);
235 	m_workram_mask = u16((m_workram.bytes() >> 1) - 1);
236 
237 	if (allow_drc())
238 		m_recompiler.reset(new recompiler(*this, 0)); // TODO: what are UML flags for?
239 
240 	state_add(STATE_GENPC, "PC", m_core->xaau_pc);
241 	state_add(STATE_GENPCBASE, "CURPC", m_st_pcbase).noshow();
242 	state_add(STATE_GENFLAGS, "GENFLAGS", m_st_genflags).mask(0x0fU).noshow().callexport().formatstr("%16s");
243 	state_add(DSP16_PT, "PT", m_core->xaau_pt);
244 	state_add(DSP16_PR, "PR", m_core->xaau_pr);
245 	state_add(DSP16_PI, "PI", m_core->xaau_pi);
246 	state_add(DSP16_I, "I", m_core->xaau_i).mask((s16(1) << 12) - 1).callimport();
247 	state_add(DSP16_R0, "R0", m_core->yaau_r[0]).mask(m_core->yaau_mask);
248 	state_add(DSP16_R1, "R1", m_core->yaau_r[1]).mask(m_core->yaau_mask);
249 	state_add(DSP16_R2, "R2", m_core->yaau_r[2]).mask(m_core->yaau_mask);
250 	state_add(DSP16_R3, "R3", m_core->yaau_r[3]).mask(m_core->yaau_mask);
251 	state_add(DSP16_RB, "RB", m_core->yaau_rb).mask(m_core->yaau_mask);
252 	state_add(DSP16_RE, "RE", m_core->yaau_re).mask(m_core->yaau_mask);
253 	state_add(DSP16_J, "J", m_core->yaau_j).mask(m_core->yaau_mask).callimport();
254 	state_add(DSP16_K, "K", m_core->yaau_k).mask(m_core->yaau_mask).callimport();
255 	state_add(DSP16_X, "X", m_core->dau_x);
256 	state_add(DSP16_Y, "Y", m_core->dau_y);
257 	state_add(DSP16_P, "P", m_core->dau_p);
258 	state_add(DSP16_A0, "A0", m_core->dau_a[0]).mask(DAU_A_MASK).callimport();
259 	state_add(DSP16_A1, "A1", m_core->dau_a[1]).mask(DAU_A_MASK).callimport();
260 	state_add(DSP16_C0, "C0", m_core->dau_c[0]);
261 	state_add(DSP16_C1, "C1", m_core->dau_c[1]);
262 	state_add(DSP16_C2, "C2", m_core->dau_c[2]);
263 	state_add(DSP16_AUC, "AUC", m_core->dau_auc).mask(0x7fU);
264 	state_add(DSP16_PSW, "PSW", m_core->dau_psw).callimport().callexport();
265 	state_add(DSP16_YH, "YH", m_st_yh).noshow().callimport().callexport();
266 	state_add(DSP16_A0H, "A0H", m_st_ah[0]).noshow().callimport().callexport();
267 	state_add(DSP16_A1H, "A1H", m_st_ah[1]).noshow().callimport().callexport();
268 	state_add(DSP16_YL, "YL", m_st_yl).noshow().callimport().callexport();
269 	state_add(DSP16_A0L, "A0L", m_st_al[0]).noshow().callimport().callexport();
270 	state_add(DSP16_A1L, "A1L", m_st_al[1]).noshow().callimport().callexport();
271 
272 	m_core->register_save_items(*this);
273 
274 	save_item(NAME(m_cache_mode));
275 	save_item(NAME(m_phase));
276 	save_item(NAME(m_int_enable));
277 	save_item(NAME(m_flags));
278 	save_item(NAME(m_cache_ptr));
279 	save_item(NAME(m_cache_limit));
280 	save_item(NAME(m_cache_iterations));
281 	save_item(NAME(m_cache));
282 	save_item(NAME(m_rom_data));
283 
284 	save_item(NAME(m_exm_in));
285 	save_item(NAME(m_int_in));
286 	save_item(NAME(m_iack_out));
287 
288 	save_item(NAME(m_ick_in));
289 	save_item(NAME(m_ild_in));
290 	save_item(NAME(m_do_out));
291 	save_item(NAME(m_ock_in));
292 	save_item(NAME(m_old_in));
293 	save_item(NAME(m_ose_out));
294 
295 	save_item(NAME(m_psel_out));
296 	save_item(NAME(m_pids_out));
297 	save_item(NAME(m_pods_out));
298 
299 	save_item(NAME(m_sio_sioc));
300 	save_item(NAME(m_sio_obuf));
301 	save_item(NAME(m_sio_osr));
302 	save_item(NAME(m_sio_ofsr));
303 	save_item(NAME(m_sio_clk));
304 	save_item(NAME(m_sio_clk_div));
305 	save_item(NAME(m_sio_clk_res));
306 	save_item(NAME(m_sio_ld));
307 	save_item(NAME(m_sio_ld_div));
308 	save_item(NAME(m_sio_flags));
309 
310 	save_item(NAME(m_pio_pioc));
311 	save_item(NAME(m_pio_pdx_in));
312 	save_item(NAME(m_pio_pdx_out));
313 	save_item(NAME(m_pio_pids_cnt));
314 	save_item(NAME(m_pio_pods_cnt));
315 
316 	save_item(NAME(m_cache_pcbase));
317 	save_item(NAME(m_st_pcbase));
318 
319 	external_memory_enable(*m_spaces[AS_PROGRAM], !m_exm_in);
320 }
321 
device_stop()322 void dsp16_device_base::device_stop()
323 {
324 	m_recompiler.reset();
325 }
326 
device_reset()327 void dsp16_device_base::device_reset()
328 {
329 	cpu_device::device_reset();
330 
331 	m_cache_mode = cache::NONE;
332 	m_phase = phase::PURGE;
333 	std::fill(std::begin(m_int_enable), std::end(m_int_enable), 0U);
334 	m_flags = FLAGS_NONE;
335 	m_cache_ptr = 0U;
336 	m_core->xaau_pc = 0U;
337 	m_core->yaau_rb = 0U;
338 	m_core->yaau_re = 0U;
339 	m_sio_sioc = 0U;
340 	m_sio_ofsr = 0U;
341 	m_sio_clk = 1U;
342 	m_sio_clk_div = 0U;
343 	m_sio_clk_res = 0U;
344 	m_pio_pioc = 0x0008U;
345 	m_pio_pids_cnt = 0U;
346 	m_pio_pods_cnt = 0U;
347 	m_st_pcbase = 0U;
348 
349 	// interrupt reset outputs
350 	if (!m_iack_out)
351 	{
352 		LOGINT("DSP16: de-asserting IACK for reset\n");
353 		m_iack_cb(m_iack_out = 1U);
354 	}
355 
356 	// SIO reset outputs
357 	m_ick_cb(1); // actually high-impedance
358 	m_ild_cb(1); // actually high-impedance
359 	m_do_cb(m_do_out = 1U); // actually high-impedance
360 	m_ock_cb(1); // actually high-impedance
361 	m_old_cb(1); // actually high-impedance
362 	if (!m_ose_out)
363 		m_ose_cb(m_ose_out = 1U);
364 
365 	// PIO reset outputs
366 	m_pdb_w_cb(m_psel_out, 0xffffU, 0x0000U);
367 	if (!m_pids_out)
368 	{
369 		LOGPIO("DSP16: de-asserting PIDS for reset\n");
370 		m_pids_cb(m_pids_out = 1U); // actually high-impedance
371 	}
372 	if (!m_pods_out)
373 	{
374 		LOGPIO("DSP16: de-asserting PODS for reset\n");
375 		m_pods_cb(m_pods_out = 1U); // actually high-impedance
376 	}
377 }
378 
379 /***********************************************************************
380     device_execute_interface implementation
381 ***********************************************************************/
382 
execute_run()383 void dsp16_device_base::execute_run()
384 {
385 	if (debugger_enabled())
386 	{
387 		while (m_core->icount_remaining())
388 		{
389 			switch (m_cache_mode)
390 			{
391 			case cache::NONE:
392 				execute_some_rom<true, false>();
393 				break;
394 			case cache::LOAD:
395 				execute_some_rom<true, true>();
396 				break;
397 			case cache::EXECUTE:
398 				execute_some_cache<true>();
399 				break;
400 			}
401 		}
402 	}
403 	else
404 	{
405 		while (m_core->icount_remaining())
406 		{
407 			switch (m_cache_mode)
408 			{
409 			case cache::NONE:
410 				execute_some_rom<false, false>();
411 				break;
412 			case cache::LOAD:
413 				execute_some_rom<false, true>();
414 				break;
415 			case cache::EXECUTE:
416 				execute_some_cache<false>();
417 				break;
418 			}
419 		}
420 	}
421 }
422 
execute_set_input(int inputnum,int state)423 void dsp16_device_base::execute_set_input(int inputnum, int state)
424 {
425 	switch (inputnum)
426 	{
427 	case DSP16_INT_LINE:
428 		m_int_in = state;
429 		break;
430 	case DSP16_ICK_LINE:
431 		if (((CLEAR_LINE == state) ? 0U : 1U) != m_ick_in)
432 		{
433 			if (!sio_ick_active())
434 			{
435 				if (CLEAR_LINE != state)
436 					sio_ick_active_edge();
437 			}
438 			else
439 			{
440 				logerror("DSP16: warning: ignoring ICK input in active mode (PC = %04X)\n", m_st_pcbase);
441 			}
442 			m_ick_in = (ASSERT_LINE == state) ? 1U : 0U;
443 		}
444 		if (CLEAR_LINE != state)
445 			standard_irq_callback(DSP16_ICK_LINE);
446 		break;
447 	case DSP16_ILD_LINE:
448 		if (sio_ild_active())
449 			logerror("DSP16: warning: ignoring ILD input in active mode (PC = %04X)\n", m_st_pcbase);
450 		m_ild_in = state;
451 		break;
452 	case DSP16_OCK_LINE:
453 		if (((CLEAR_LINE == state) ? 0U : 1U) != m_ock_in)
454 		{
455 			if (!sio_ock_active())
456 			{
457 				if (CLEAR_LINE != state)
458 					sio_ock_active_edge();
459 			}
460 			else
461 			{
462 				logerror("DSP16: warning: ignoring OCK input in active mode (PC = %04X)\n", m_st_pcbase);
463 			}
464 			m_ock_in = (ASSERT_LINE == state) ? 1U : 0U;
465 		}
466 		if (CLEAR_LINE != state)
467 			standard_irq_callback(DSP16_OCK_LINE);
468 		break;
469 	case DSP16_OLD_LINE:
470 		if (sio_old_active())
471 			logerror("DSP16: warning: ignoring OLD input in active mode (PC = %04X)\n", m_st_pcbase);
472 		m_old_in = state;
473 		break;
474 	}
475 }
476 
477 /***********************************************************************
478     device_memory_interface implementation
479 ***********************************************************************/
480 
memory_space_config() const481 device_memory_interface::space_config_vector dsp16_device_base::memory_space_config() const
482 {
483 	return space_config_vector{
484 			std::make_pair(AS_PROGRAM, &m_space_config[AS_PROGRAM]),
485 			std::make_pair(AS_DATA, &m_space_config[AS_DATA]),
486 			std::make_pair(AS_IO, &m_space_config[AS_IO]) };
487 }
488 
489 /***********************************************************************
490     device_state_interface implementation
491 ***********************************************************************/
492 
state_import(device_state_entry const & entry)493 void dsp16_device_base::state_import(device_state_entry const &entry)
494 {
495 	switch (entry.index())
496 	{
497 	// extend signed registers that aren't a power-of-two size
498 	case DSP16_I: m_core->xaau_extend_i(); break;
499 	case DSP16_J: m_core->yaau_extend_j(); break;
500 	case DSP16_K: m_core->yaau_extend_k(); break;
501 	case DSP16_A0: m_core->dau_extend_a<0>(); break;
502 	case DSP16_A1: m_core->dau_extend_a<1>(); break;
503 
504 	// guard bits of accumulators are accessible via status word
505 	case DSP16_PSW: m_core->dau_import_psw(); break;
506 
507 	// put partial registers in the appropriate places
508 	case DSP16_YH:
509 		m_core->dau_y = (s32(m_st_yh) << 16) | (m_core->dau_y & ((s32(1) << 16) - 1));
510 		break;
511 	case DSP16_A0H:
512 		m_core->dau_a[0] = (s32(m_st_ah[0]) << 16) | s32(m_core->dau_a[0] & ((s32(1) << 16) - 1));
513 		break;
514 	case DSP16_A1H:
515 		m_core->dau_a[1] = (s32(m_st_ah[1]) << 16) | s32(m_core->dau_a[1] & ((s32(1) << 16) - 1));
516 		break;
517 	case DSP16_YL:
518 		m_core->dau_y = (m_core->dau_y & ~((s32(1) << 16) - 1)) | u32(m_st_yl);
519 		break;
520 	case DSP16_A0L:
521 		m_core->dau_a[0] = (m_core->dau_a[0] & ~((s64(1) << 16) - 1)) | u64(m_st_al[0]);
522 		break;
523 	case DSP16_A1L:
524 		m_core->dau_a[1] = (m_core->dau_a[1] & ~((s64(1) << 16) - 1)) | u64(m_st_al[1]);
525 		break;
526 	}
527 }
528 
state_export(device_state_entry const & entry)529 void dsp16_device_base::state_export(device_state_entry const &entry)
530 {
531 	switch (entry.index())
532 	{
533 	// guard bits of accumulators are accessible via status word
534 	case DSP16_PSW: m_core->dau_export_psw(); break;
535 
536 	// put partial registers in the appropriate places
537 	case DSP16_YH:
538 		m_st_yh = m_core->dau_y >> 16;
539 		break;
540 	case DSP16_A0H:
541 		m_st_ah[0] = u16(u64(m_core->dau_a[0]) >> 16);
542 		break;
543 	case DSP16_A1H:
544 		m_st_ah[1] = u16(u64(m_core->dau_a[1]) >> 16);
545 		break;
546 	case DSP16_YL:
547 		m_st_yl = u16(u32(m_core->dau_y));
548 		break;
549 	case DSP16_A0L:
550 		m_st_al[0] = u16(u64(m_core->dau_a[0]));
551 		break;
552 	case DSP16_A1L:
553 		m_st_al[1] = u16(u64(m_core->dau_a[1]));
554 		break;
555 	}
556 }
557 
state_string_export(device_state_entry const & entry,std::string & str) const558 void dsp16_device_base::state_string_export(device_state_entry const &entry, std::string &str) const
559 {
560 	switch (entry.index())
561 	{
562 	// show DAU flags
563 	case STATE_GENFLAGS:
564 		str = util::string_format(
565 				"%s%s%s%s",
566 				m_core->dau_psw_lmi() ? "LMI " : "",
567 				m_core->dau_psw_leq() ? "LEQ " : "",
568 				m_core->dau_psw_llv() ? "LLV " : "",
569 				m_core->dau_psw_lmv() ? "LMV " : "");
570 		break;
571 	}
572 }
573 
574 /***********************************************************************
575     device_disasm_interface implementation
576 ***********************************************************************/
577 
create_disassembler()578 std::unique_ptr<util::disasm_interface> dsp16_device_base::create_disassembler()
579 {
580 	return std::make_unique<dsp16_disassembler>(static_cast<dsp16_disassembler::cpu const &>(*this));
581 }
582 
583 /***********************************************************************
584     dsp16_disassembler::cpu implementation
585 ***********************************************************************/
586 
check_con(offs_t pc,u16 op) const587 dsp16_disassembler::cpu::predicate dsp16_device_base::check_con(offs_t pc, u16 op) const
588 {
589 	if (pc != m_st_pcbase)
590 	{
591 		return predicate::INDETERMINATE;
592 	}
593 	else
594 	{
595 		bool result;
596 		u16 const con(op_con(op));
597 		switch (con >> 1)
598 		{
599 		case 0x0: // mi/pl
600 			result = m_core->dau_psw_lmi();
601 			break;
602 		case 0x1: // eq/ne
603 			result = m_core->dau_psw_leq();
604 			break;
605 		case 0x2: // lvs/lvc
606 			result = m_core->dau_psw_llv();
607 			break;
608 		case 0x3: // mvs/mvc
609 			result = m_core->dau_psw_lmv();
610 			break;
611 		case 0x4: // heads/tails
612 			return predicate::INDETERMINATE; // FIXME: implement PRNG
613 		case 0x5: // c0ge/c0lt
614 		case 0x6: // c1ge/c1lt
615 			result = 0 <= m_core->dau_c[(con >> 1) - 0x05];
616 			break;
617 		case 0x7: // true/false
618 			result = true;
619 			break;
620 		case 0x8: // gt/le
621 			result = !m_core->dau_psw_lmi() && !m_core->dau_psw_leq();
622 			break;
623 		default: // Reserved
624 			return predicate::INDETERMINATE;
625 		}
626 		return (bool(BIT(con, 0)) == result) ? predicate::SKIPPED : predicate::TAKEN;
627 	}
628 }
629 
check_branch(offs_t pc) const630 dsp16_disassembler::cpu::predicate dsp16_device_base::check_branch(offs_t pc) const
631 {
632 	if (pc != m_st_pcbase)
633 		return predicate::INDETERMINATE;
634 	else if (FLAGS_PRED_TRUE == (m_flags & FLAGS_PRED_MASK))
635 		return predicate::TAKEN;
636 	else if (FLAGS_PRED_FALSE == (m_flags & FLAGS_PRED_MASK))
637 		return predicate::SKIPPED;
638 	else
639 		return predicate::INDETERMINATE;
640 }
641 
external_memory_r(offs_t offset,u16 mem_mask)642 template <offs_t Base> u16 dsp16_device_base::external_memory_r(offs_t offset, u16 mem_mask)
643 {
644 	return m_spaces[AS_IO]->read_word(Base + offset, mem_mask);
645 }
646 
647 /***********************************************************************
648     internal address maps
649 ***********************************************************************/
650 
program_map(address_map & map)651 void dsp16_device_base::program_map(address_map &map)
652 {
653 	map.global_mask(0xffff);
654 	map.unmap_value_high();
655 }
656 
657 /***********************************************************************
658     instruction execution
659 ***********************************************************************/
660 
execute_some_rom()661 template <bool Debugger, bool Caching> inline void dsp16_device_base::execute_some_rom()
662 {
663 	assert(bool(machine().debug_flags & DEBUG_FLAG_ENABLED) == Debugger);
664 	for (bool mode_change = false; !mode_change && m_core->icount_remaining(); m_core->decrement_icount())
665 	{
666 		assert((cache::LOAD == m_cache_mode) == Caching);
667 
668 		u16 const op(m_cache[m_cache_ptr]);
669 		bool const last_cache_load(Caching && (m_cache_ptr == m_cache_limit));
670 		u16 const cache_next((m_cache_ptr + (Caching ? 1 : 0)) & 0x0fU);
671 		u16 *fetch_target(&m_cache[cache_next]);
672 		u16 fetch_addr(0U);
673 		flags predicate(FLAGS_PRED_NONE);
674 
675 		switch (m_phase)
676 		{
677 		case phase::PURGE:
678 			fetch_addr = m_core->xaau_pc;
679 			m_phase = phase::OP1;
680 			break;
681 
682 		case phase::OP1:
683 			if (Debugger)
684 			{
685 				if (FLAGS_PRED_NONE == (m_flags & FLAGS_PRED_MASK))
686 				{
687 					debugger_instruction_hook(m_st_pcbase);
688 				}
689 				else
690 				{
691 					switch (op >> 11)
692 					{
693 					case 0x00: // goto JA
694 					case 0x01:
695 					case 0x10: // call JA
696 					case 0x11:
697 						break;
698 					case 0x18: // goto B
699 						switch (op_b(op))
700 						{
701 						case 0x0: // return
702 						case 0x2: // goto pt
703 						case 0x3: // call pt
704 							break;
705 						default:
706 							debugger_instruction_hook(m_st_pcbase);
707 						}
708 						break;
709 					default:
710 						debugger_instruction_hook(m_st_pcbase);
711 					}
712 				}
713 			}
714 
715 			// IACK is updated for the next instruction
716 			switch (m_flags & FLAGS_IACK_MASK)
717 			{
718 			case FLAGS_IACK_SET:
719 				if (m_iack_out)
720 				{
721 					LOGINT("DSP16: asserting IACK (PC = %04X)\n", m_st_pcbase);
722 					m_iack_cb(m_iack_out = 0U);
723 					standard_irq_callback(DSP16_INT_LINE);
724 				}
725 				break;
726 			case FLAGS_IACK_CLEAR:
727 				if (!m_iack_out)
728 				{
729 					LOGINT("DSP16: de-asserting IACK (PC = %04X)\n", m_st_pcbase);
730 					m_iack_cb(m_iack_out = 1U);
731 					m_pio_pioc &= 0xfffeU;
732 				}
733 				break;
734 			default:
735 				break;
736 			}
737 			set_iack(FLAGS_IACK_NONE);
738 
739 			// if we're not servicing an interrupt or caching
740 			if (m_iack_out && !Caching)
741 			{
742 				// TODO: is INT sampled on any instruction or only interruptible instructions?
743 				// if an unmasked interrupt is pending
744 				if ((m_pio_pioc & m_int_enable[0] & 0x001eU) || (BIT(m_int_enable[0], 0) && (CLEAR_LINE != m_int_in)))
745 				{
746 					// if the current instruction is interruptible
747 					if (op_interruptible(op))
748 					{
749 						if (pio_int_enable() && (CLEAR_LINE != m_int_in))
750 						{
751 							if (ASSERT_LINE != m_int_in)
752 								m_int_in = CLEAR_LINE;
753 							m_pio_pioc |= 0x0001U;
754 						}
755 						LOGINT(
756 								"DSP16: servicing interrupts%s%s%s%s%s (PC = %04X)\n",
757 								(pio_ibf_enable() && pio_ibf_status()) ? " IBF" : "",
758 								(pio_obe_enable() && pio_obe_status()) ? " OBE" : "",
759 								(pio_pids_enable() && pio_pids_status()) ? " PIDS" : "",
760 								(pio_pods_enable() && pio_pods_status()) ? " PODS" : "",
761 								(pio_int_enable() && pio_int_status()) ? " INT" : "",
762 								m_st_pcbase);
763 						set_iack(FLAGS_IACK_SET);
764 						fetch_addr = m_core->xaau_next_pc();
765 						m_int_enable[0] = m_int_enable[1];
766 						m_core->xaau_pc = 0x0001U;
767 						m_phase = phase::PURGE;
768 						break;
769 					}
770 				}
771 			}
772 
773 			// normal opcode execution
774 			fetch_addr = set_xaau_pc_offset(m_core->xaau_pc + 1);
775 			m_int_enable[0] = m_int_enable[1];
776 			switch (op >> 11)
777 			{
778 			case 0x00: // goto JA
779 			case 0x01:
780 			case 0x10: // call JA
781 			case 0x11:
782 				if (check_predicate())
783 				{
784 					if (BIT(op, 15))
785 						m_core->xaau_pr = m_core->xaau_pc;
786 					set_xaau_pc_offset(op_ja(op));
787 				}
788 				m_phase = phase::PURGE;
789 				break;
790 
791 			case 0x02: // R = M
792 			case 0x03:
793 				yaau_short_immediate_load(op);
794 				break;
795 
796 			case 0x04: // F1 ; Y = a1[l]
797 			case 0x1c: // F1 ; Y = a0[l]
798 				fetch_target = nullptr;
799 				m_phase = phase::OP2;
800 				break;
801 
802 			case 0x05: // F1 ; Z : aT[l]
803 				{
804 					fetch_target = nullptr;
805 					s64 const d(m_core->dau_f1(op));
806 					m_core->dau_temp = u16(u64(dau_saturate(op_d(~op))) >> (op_x(op) ? 16 : 0));
807 					m_core->op_dau_ad(op) = d;
808 					m_core->dau_set_atx(op, yaau_read<Debugger>(op));
809 					m_phase = phase::OP2;
810 				}
811 				break;
812 
813 			case 0x06: // F1 ; Y
814 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
815 				yaau_read<Debugger>(op);
816 				break;
817 
818 			case 0x07: // F1 ; aT[l] = Y
819 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
820 				m_core->dau_set_atx(op, yaau_read<Debugger>(op));
821 				break;
822 
823 			case 0x08: // aT = R
824 				assert(!(op & 0x000fU)); // reserved field?
825 				fetch_target = nullptr;
826 				m_core->dau_set_at(op, get_r(op));
827 				m_phase = phase::OP2;
828 				break;
829 
830 			case 0x09: // R = a0
831 			case 0x0b: // R = a1
832 				assert(!(op & 0x040fU)); // reserved fields?
833 				fetch_target = nullptr;
834 				set_r(op, u16(u64(dau_saturate(BIT(op, 12))) >> 16));
835 				m_phase = phase::OP2;
836 				break;
837 
838 			case 0x0a: // R = N
839 				assert(!(op & 0x040fU)); // reserved fields?
840 				m_phase = phase::OP2;
841 				fetch_target = &m_rom_data;
842 				break;
843 
844 			case 0x0c: // Y = R
845 				assert(!(op & 0x0400U)); // reserved field?
846 				fetch_target = nullptr;
847 				m_phase = phase::OP2;
848 				break;
849 
850 			case 0x0d: // Z : R
851 				fetch_target = nullptr;
852 				m_core->dau_temp = get_r(op);
853 				set_r(op, yaau_read<Debugger>(op));
854 				m_phase = phase::OP2;
855 				break;
856 
857 			case 0x0e: // do K { instr1...instrNI } # redo K
858 				{
859 					u16 const ni(op_ni(op));
860 					if (ni)
861 					{
862 						mode_change = true;
863 						fetch_target = &m_cache[m_cache_ptr = 1U];
864 						m_cache_mode = cache::LOAD;
865 						m_cache_limit = ni;
866 						m_cache_pcbase = m_st_pcbase;
867 					}
868 					else
869 					{
870 						mode_change = true;
871 						fetch_target = nullptr;
872 						m_cache_mode = cache::EXECUTE;
873 						m_phase = phase::PREFETCH;
874 						m_cache_ptr = 1U;
875 					}
876 					m_cache_iterations = op_k(op);
877 					assert(m_cache_iterations >= 2U); // p3-25: "The iteration count can be between 2 and 127, inclusive"
878 				}
879 				break;
880 
881 			case 0x0f: // R = Y
882 				assert(!(op & 0x0400U)); // reserved field?
883 				fetch_target = nullptr;
884 				set_r(op, yaau_read<Debugger>(op));
885 				m_phase = phase::OP2;
886 				break;
887 
888 			case 0x12: // ifc CON F2
889 				{
890 					bool const con(op_dau_con(op, false));
891 					++m_core->dau_c[1];
892 					if (con)
893 					{
894 						m_core->dau_f2(op);
895 						m_core->dau_c[2] = m_core->dau_c[1];
896 					}
897 				}
898 				break;
899 
900 			case 0x13: // if CON F2
901 				if (op_dau_con(op, true))
902 					m_core->dau_f2(op);
903 				break;
904 
905 			case 0x14: // F1 ; Y = y[l]
906 				fetch_target = nullptr;
907 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
908 				m_phase = phase::OP2;
909 				break;
910 
911 			case 0x15: // F1 ; Z : y[l]
912 				fetch_target = nullptr;
913 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
914 				m_core->dau_temp = m_core->dau_get_y(op);
915 				m_core->dau_set_y(op, yaau_read<Debugger>(op));
916 				m_phase = phase::OP2;
917 				break;
918 
919 			case 0x16: // F1 ; x = Y
920 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
921 				m_core->dau_x = yaau_read<Debugger>(op);
922 				break;
923 
924 			case 0x17: // F1 ; y[l] = Y
925 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
926 				m_core->dau_set_y(op, yaau_read<Debugger>(op));
927 				break;
928 
929 			case 0x18: // goto B
930 				assert(!(op & 0x00ffU)); // reserved field?
931 				switch (op_b(op))
932 				{
933 				case 0x0: // return
934 					if (check_predicate())
935 						m_core->xaau_pc = m_core->xaau_pr;
936 					break;
937 				case 0x1: // ireturn
938 					if (m_iack_out)
939 						logerror("DSP16: ireturn when not servicing interrupt (PC = %04X)\n", m_st_pcbase);
940 					LOGINT("DSP16: return from interrupt (PC = %04X)\n", m_st_pcbase);
941 					set_iack(FLAGS_IACK_CLEAR);
942 					m_core->xaau_pc = m_core->xaau_pi;
943 					break;
944 				case 0x2: // goto pt
945 					if (check_predicate())
946 						m_core->xaau_pc = m_core->xaau_pt;
947 					break;
948 				case 0x3: // call pt
949 					if (check_predicate())
950 					{
951 						m_core->xaau_pr = m_core->xaau_pc;
952 						m_core->xaau_pc = m_core->xaau_pt;
953 					}
954 					break;
955 				case 0x4: // Reserved
956 				case 0x5:
957 				case 0x6:
958 				case 0x7:
959 					throw emu_fatalerror("DSP16: reserved B value %01X (PC = %04X)\n", op_b(op), m_st_pcbase);
960 				}
961 				if (m_iack_out)
962 					m_core->xaau_pi = m_core->xaau_pc;
963 				m_phase = phase::PURGE;
964 				break;
965 
966 			case 0x19: // F1 ; y = a0 ; x = *pt++[i]
967 			case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
968 				{
969 					assert(!(op & 0x000fU)); // reserved field?
970 					s64 const d(m_core->dau_f1(op));
971 					s64 a(m_core->dau_a[BIT(op, 12)]);
972 					// FIXME: is saturation applied when transferring a to y?
973 					m_core->dau_y = u32(u64(a));
974 					m_core->op_dau_ad(op) = d;
975 					fetch_target = nullptr;
976 					m_rom_data = m_spaces[AS_PROGRAM]->read_word(m_core->xaau_pt);
977 					m_phase = phase::OP2;
978 				}
979 				break;
980 
981 			case 0x1a: // if CON # icall
982 				assert(!(op & 0x03e0U)); // reserved field?
983 				predicate = op_dau_con(op, true) ? FLAGS_PRED_TRUE : FLAGS_PRED_FALSE;
984 				if (BIT(op, 10))
985 				{
986 					fetch_target = nullptr;
987 					assert(0x000eU == op_con(op)); // CON must be true for icall?
988 					m_phase = phase::OP2;
989 				}
990 				break;
991 
992 			case 0x1d: // F1 ; Z : y ; x = *pt++[i]
993 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
994 				m_core->dau_temp = s16(m_core->dau_y >> 16);
995 				m_core->dau_set_y(yaau_read<Debugger>(op));
996 				fetch_target = nullptr;
997 				m_rom_data = m_spaces[AS_PROGRAM]->read_word(m_core->xaau_pt);
998 				m_phase = phase::OP2;
999 				break;
1000 
1001 			case 0x1e: // Reserved
1002 				throw emu_fatalerror("DSP16: reserved op %u (PC = %04X)\n", op >> 11, m_st_pcbase);
1003 				break;
1004 
1005 			case 0x1f: // F1 ; y = Y ; x = *pt++[i]
1006 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1007 				m_core->dau_set_y(yaau_read<Debugger>(op));
1008 				fetch_target = nullptr;
1009 				m_rom_data = m_spaces[AS_PROGRAM]->read_word(m_core->xaau_pt);
1010 				m_phase = phase::OP2;
1011 				break;
1012 
1013 			default:
1014 				throw emu_fatalerror("DSP16: unimplemented op %u (PC = %04X)\n", op >> 11, m_st_pcbase);
1015 			}
1016 
1017 			if (Caching && (phase::OP1 == m_phase))
1018 			{
1019 				// if the last instruction loaded to the cache completes in a single cycle, there's an extra cycle for a data fetch
1020 				if (last_cache_load)
1021 				{
1022 					mode_change = true;
1023 					fetch_target = nullptr;
1024 					m_cache_mode = cache::EXECUTE;
1025 					m_phase = phase::PREFETCH;
1026 					m_cache_ptr = 1U;
1027 					--m_cache_iterations;
1028 				}
1029 				else
1030 				{
1031 					m_cache_ptr = cache_next;
1032 				}
1033 			}
1034 			break;
1035 
1036 		case phase::OP2:
1037 			m_phase = phase::OP1;
1038 			switch (op >> 11)
1039 			{
1040 			case 0x04: // F1 ; Y = a1[l]
1041 			case 0x1c: // F1 ; Y = a0[l]
1042 				yaau_write<Debugger>(op, u16(u64(dau_saturate(BIT(~op, 14))) >> (op_x(op) ? 16 : 0)));
1043 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1044 				break;
1045 
1046 			case 0x05: // F1 ; Z : aT[l]
1047 			case 0x0d: // Z : R
1048 			case 0x15: // F1 ; Z : y[l]
1049 				yaau_write_z<Debugger>(op);
1050 				break;
1051 
1052 			case 0x08: // aT = R
1053 			case 0x09: // R = a0
1054 			case 0x0b: // R = a1
1055 				break;
1056 
1057 			case 0x0a: // R = N
1058 				set_xaau_pc_offset(m_core->xaau_pc + 1);
1059 				set_r(op, m_rom_data);
1060 				break;
1061 
1062 			case 0x0c: // Y = R
1063 				yaau_write<Debugger>(op, get_r(op));
1064 				break;
1065 
1066 			case 0x0f: // R = Y
1067 				break;
1068 
1069 			case 0x14: // F1 ; Y = y[l]
1070 				yaau_write<Debugger>(op, m_core->dau_get_y(op));
1071 				break;
1072 
1073 			case 0x19: // F1 ; y = a0 ; x = *pt++[i]
1074 			case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
1075 			case 0x1f: // F1 ; y = Y ; x = *pt++[i]
1076 				m_core->xaau_increment_pt(op);
1077 				m_core->dau_x = m_rom_data;
1078 				break;
1079 
1080 			case 0x1a: // icall
1081 				// TODO: does INT get sampled or could an external interrupt be lost here?
1082 				assert(BIT(op, 10));
1083 				assert(FLAGS_PRED_TRUE == (m_flags & FLAGS_PRED_MASK));
1084 				if (check_predicate())
1085 				{
1086 					LOGINT(
1087 							"DSP16: servicing software interrupt%s%s%s%s%s (PC = %04X)\n",
1088 							(pio_ibf_enable() && pio_ibf_status()) ? " IBF" : "",
1089 							(pio_obe_enable() && pio_obe_status()) ? " OBE" : "",
1090 							(pio_pids_enable() && pio_pids_status()) ? " PIDS" : "",
1091 							(pio_pods_enable() && pio_pods_status()) ? " PODS" : "",
1092 							(pio_int_enable() && pio_int_status()) ? " INT" : "",
1093 							m_st_pcbase);
1094 					set_iack(FLAGS_IACK_SET);
1095 					m_core->xaau_pc = 0x0002U;
1096 				}
1097 				m_phase = phase::PURGE;
1098 				break;
1099 
1100 			case 0x1d: // F1 ; Z : y ; x = *pt++[i]
1101 				m_core->xaau_increment_pt(op);
1102 				m_core->dau_x = m_rom_data;
1103 				yaau_write_z<Debugger>(op);
1104 				break;
1105 
1106 			default:
1107 				throw emu_fatalerror("DSP16: op %u doesn't take two cycles to run from ROM\n", op >> 11);
1108 			}
1109 
1110 			if (last_cache_load)
1111 			{
1112 				mode_change = true;
1113 				fetch_target = nullptr;
1114 				m_cache_mode = cache::EXECUTE;
1115 				m_cache_ptr = 1U;
1116 				--m_cache_iterations;
1117 				overlap_rom_data_read();
1118 			}
1119 			else
1120 			{
1121 				fetch_addr = m_core->xaau_pc;
1122 				if (Caching)
1123 					m_cache_ptr = cache_next;
1124 			}
1125 			break;
1126 
1127 		default:
1128 			throw emu_fatalerror("DSP16: inappropriate phase for ROM execution\n");
1129 		}
1130 
1131 		if (FLAGS_PRED_NONE != (m_flags & FLAGS_PRED_MASK))
1132 			throw emu_fatalerror("DSP16: predicate applied to ineligible op %u (PC = %04X)\n", op >> 11, m_st_pcbase);
1133 		set_predicate(predicate);
1134 
1135 		if (fetch_target)
1136 			*fetch_target = m_pcache.read_word(fetch_addr);
1137 
1138 		if (phase::OP1 == m_phase)
1139 		{
1140 			if (cache::EXECUTE != m_cache_mode)
1141 				m_st_pcbase = m_core->xaau_pc;
1142 			else
1143 				m_st_pcbase = (m_cache_pcbase & 0xf000U) | ((m_cache_pcbase + m_cache_ptr) & 0x0fffU);
1144 		}
1145 
1146 		sio_step();
1147 		pio_step();
1148 	}
1149 }
1150 
execute_some_cache()1151 template <bool Debugger> inline void dsp16_device_base::execute_some_cache()
1152 {
1153 	assert(bool(machine().debug_flags & DEBUG_FLAG_ENABLED) == Debugger);
1154 	for (bool mode_change = false; !mode_change && m_core->icount_remaining(); m_core->decrement_icount())
1155 	{
1156 		u16 const op(m_cache[m_cache_ptr]);
1157 		bool const at_limit(m_cache_ptr == m_cache_limit);
1158 		bool const last_instruction(at_limit && (1U == m_cache_iterations));
1159 		switch (m_phase)
1160 		{
1161 		case phase::OP1:
1162 			if (Debugger)
1163 				debugger_instruction_hook(m_st_pcbase);
1164 			m_int_enable[0] = m_int_enable[1];
1165 			switch (op >> 11)
1166 			{
1167 			case 0x02: // R = M
1168 			case 0x03:
1169 				yaau_short_immediate_load(op);
1170 				break;
1171 
1172 			case 0x04: // F1 ; Y = a1[l]
1173 			case 0x1c: // F1 ; Y = a0[l]
1174 				m_phase = phase::OP2;
1175 				break;
1176 
1177 			case 0x05: // F1 ; Z : aT[l]
1178 				{
1179 					s64 const d(m_core->dau_f1(op));
1180 					m_core->dau_temp = u16(u64(dau_saturate(op_d(~op))) >> (op_x(op) ? 16 : 0));
1181 					m_core->op_dau_ad(op) = d;
1182 					m_core->dau_set_atx(op, yaau_read<Debugger>(op));
1183 					m_phase = phase::OP2;
1184 				}
1185 				break;
1186 
1187 			case 0x06: // F1 ; Y
1188 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1189 				yaau_read<Debugger>(op);
1190 				break;
1191 
1192 			case 0x07: // F1 ; aT[l] = Y
1193 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1194 				m_core->dau_set_atx(op, yaau_read<Debugger>(op));
1195 				break;
1196 
1197 			case 0x08: // aT = R
1198 				assert(!(op & 0x000fU)); // reserved field?
1199 				m_core->dau_set_at(op, get_r(op));
1200 				m_phase = phase::OP2;
1201 				break;
1202 
1203 			case 0x09: // R = a0
1204 			case 0x0b: // R = a1
1205 				assert(!(op & 0x040fU)); // reserved fields?
1206 				set_r(op, u16(u64(dau_saturate(BIT(op, 12))) >> 16));
1207 				m_phase = phase::OP2;
1208 				break;
1209 
1210 			case 0x0c: // Y = R
1211 				assert(!(op & 0x0400U)); // reserved field?
1212 				m_phase = phase::OP2;
1213 				break;
1214 
1215 			case 0x0d: // Z : R
1216 				m_core->dau_temp = get_r(op);
1217 				set_r(op, yaau_read<Debugger>(op));
1218 				m_phase = phase::OP2;
1219 				break;
1220 
1221 			case 0x0f: // R = Y
1222 				assert(!(op & 0x0400U)); // reserved field?
1223 				set_r(op, yaau_read<Debugger>(op));
1224 				m_phase = phase::OP2;
1225 				break;
1226 
1227 			case 0x12: // ifc CON F2
1228 				{
1229 					bool const con(op_dau_con(op, false));
1230 					++m_core->dau_c[1];
1231 					if (con)
1232 					{
1233 						m_core->dau_f2(op);
1234 						m_core->dau_c[2] = m_core->dau_c[1];
1235 					}
1236 				}
1237 				break;
1238 
1239 			case 0x13: // if CON F2
1240 				if (op_dau_con(op, true))
1241 					m_core->dau_f2(op);
1242 				break;
1243 
1244 			case 0x14: // F1 ; Y = y[l]
1245 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1246 				m_phase = phase::OP2;
1247 				break;
1248 
1249 			case 0x15: // F1 ; Z : y[l]
1250 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1251 				m_core->dau_temp = m_core->dau_get_y(op);
1252 				m_core->dau_set_y(op, yaau_read<Debugger>(op));
1253 				m_phase = phase::OP2;
1254 				break;
1255 
1256 			case 0x16: // F1 ; x = Y
1257 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1258 				m_core->dau_x = yaau_read<Debugger>(op);
1259 				break;
1260 
1261 			case 0x17: // F1 ; y[l] = Y
1262 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1263 				m_core->dau_set_y(op, yaau_read<Debugger>(op));
1264 				break;
1265 
1266 			case 0x19: // F1 ; y = a0 ; x = *pt++[i]
1267 			case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
1268 				{
1269 					assert(!(op & 0x000fU)); // reserved field?
1270 					s64 const d(m_core->dau_f1(op));
1271 					s64 a(m_core->dau_a[BIT(op, 12)]);
1272 					// FIXME: is saturation applied when transferring a to y?
1273 					m_core->dau_y = u32(u64(a));
1274 					m_core->op_dau_ad(op) = d;
1275 					if (last_instruction)
1276 					{
1277 						m_rom_data = m_pcache.read_word(m_core->xaau_pt);
1278 						m_phase = phase::OP2;
1279 					}
1280 					else
1281 					{
1282 						m_core->xaau_increment_pt(op);
1283 						m_core->dau_x = m_rom_data;
1284 					}
1285 				}
1286 				break;
1287 
1288 			case 0x1d: // F1 ; Z : y ; x = *pt++[i]
1289 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1290 				m_core->dau_temp = s16(m_core->dau_y >> 16);
1291 				m_core->dau_set_y(yaau_read<Debugger>(op));
1292 				m_rom_data = m_pcache.read_word(m_core->xaau_pt);
1293 				m_phase = phase::OP2;
1294 				break;
1295 
1296 			case 0x1f: // F1 ; y = Y ; x = *pt++[i]
1297 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1298 				m_core->dau_set_y(yaau_read<Debugger>(op));
1299 				if (last_instruction)
1300 				{
1301 					m_rom_data = m_pcache.read_word(m_core->xaau_pt);
1302 					m_phase = phase::OP2;
1303 				}
1304 				else
1305 				{
1306 					m_core->xaau_increment_pt(op);
1307 					m_core->dau_x = m_rom_data;
1308 				}
1309 				break;
1310 
1311 			default:
1312 				throw emu_fatalerror("DSP16: inelligible op %u in cache (PC = %04X)\n", op >> 11, m_st_pcbase);
1313 			}
1314 			break;
1315 
1316 		case phase::OP2:
1317 			m_phase = phase::OP1;
1318 			switch (op >> 11)
1319 			{
1320 			case 0x04: // F1 ; Y = a1[l]
1321 			case 0x1c: // F1 ; Y = a0[l]
1322 				yaau_write<Debugger>(op, u16(u64(dau_saturate(BIT(~op, 14))) >> (op_x(op) ? 16 : 0)));
1323 				m_core->op_dau_ad(op) = m_core->dau_f1(op);
1324 				break;
1325 
1326 			case 0x05: // F1 ; Z : aT[l]
1327 			case 0x0d: // Z : R
1328 			case 0x15: // F1 ; Z : y[l]
1329 				yaau_write_z<Debugger>(op);
1330 				break;
1331 
1332 			case 0x08: // aT = R
1333 			case 0x09: // R = a0
1334 			case 0x0b: // R = a1
1335 				break;
1336 
1337 			case 0x0c: // Y = R
1338 				yaau_write<Debugger>(op, get_r(op));
1339 				break;
1340 
1341 			case 0x0f: // R = Y
1342 				break;
1343 
1344 			case 0x14: // F1 ; Y = y[l]
1345 				yaau_write<Debugger>(op, m_core->dau_get_y(op));
1346 				break;
1347 
1348 			case 0x19: // F1 ; y = a0 ; x = *pt++[i]
1349 			case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
1350 			case 0x1f: // F1 ; y = Y ; x = *pt++[i]
1351 				assert(last_instruction);
1352 				m_core->xaau_increment_pt(op);
1353 				m_core->dau_x = m_rom_data;
1354 				break;
1355 
1356 			case 0x1d: // F1 ; Z : y ; x = *pt++[i]
1357 				m_core->xaau_increment_pt(op);
1358 				m_core->dau_x = m_rom_data;
1359 				yaau_write_z<Debugger>(op);
1360 				break;
1361 
1362 			default:
1363 				throw emu_fatalerror("DSP16: op %u doesn't take two cycles to run from cache\n", op >> 11);
1364 			}
1365 			break;
1366 
1367 		case phase::PREFETCH:
1368 			break;
1369 
1370 		default:
1371 			throw emu_fatalerror("DSP16: inappropriate phase for cache execution\n");
1372 		}
1373 
1374 		if (phase::PREFETCH == m_phase)
1375 		{
1376 			m_phase = phase::OP1;
1377 			overlap_rom_data_read();
1378 			m_st_pcbase = (m_cache_pcbase & 0xf000U) | ((m_cache_pcbase + m_cache_ptr) & 0x0fffU);
1379 		}
1380 		else if (phase::OP1 == m_phase)
1381 		{
1382 			if (last_instruction)
1383 			{
1384 				// overlapped fetch of next instruction from ROM
1385 				mode_change = true;
1386 				m_cache_mode = cache::NONE;
1387 				m_cache[m_cache_ptr = 0] = m_pcache.read_word(m_core->xaau_pc);
1388 				m_st_pcbase = m_core->xaau_pc;
1389 			}
1390 			else
1391 			{
1392 				if (at_limit)
1393 				{
1394 					// loop to first cached instruction
1395 					m_cache_ptr = 1U;
1396 					--m_cache_iterations;
1397 				}
1398 				else
1399 				{
1400 					// move to next cached instruction
1401 					m_cache_ptr = (m_cache_ptr + 1) & 0x0fU;
1402 				}
1403 				overlap_rom_data_read();
1404 				m_st_pcbase = (m_cache_pcbase & 0xf000U) | ((m_cache_pcbase + m_cache_ptr) & 0x0fffU);
1405 			}
1406 		}
1407 
1408 		sio_step();
1409 		pio_step();
1410 	}
1411 }
1412 
overlap_rom_data_read()1413 inline void dsp16_device_base::overlap_rom_data_read()
1414 {
1415 	assert(cache::EXECUTE == m_cache_mode);
1416 	assert(phase::OP1 == m_phase);
1417 	u16 const op(m_cache[m_cache_ptr]);
1418 	switch (op >> 11)
1419 	{
1420 	case 0x19: // F1 ; y = a0 ; x = *pt++[i]
1421 	case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
1422 	case 0x1f: // F1 ; y = Y ; x = *pt++[i]
1423 		m_rom_data = m_pcache.read_word(m_core->xaau_pt);
1424 		break;
1425 	}
1426 }
1427 
yaau_short_immediate_load(u16 op)1428 inline void dsp16_device_base::yaau_short_immediate_load(u16 op)
1429 {
1430 	u16 const r((op >> 9) & 0x0007U);
1431 	u16 const m(op & 0x01ff);
1432 	switch (r)
1433 	{
1434 	case 0x0: // j
1435 		m_core->yaau_j = m | ((m & m_core->yaau_sign) ? ~m_core->yaau_mask : 0);
1436 		break;
1437 	case 0x1: // k
1438 		m_core->yaau_k = m | ((m & m_core->yaau_sign) ? ~m_core->yaau_mask : 0);
1439 		break;
1440 	case 0x2: // rb
1441 		m_core->yaau_rb = m;
1442 		break;
1443 	case 0x3: // re
1444 		m_core->yaau_re = m;
1445 		break;
1446 	case 0x4: // r0
1447 	case 0x5: // r1
1448 	case 0x6: // r2
1449 	case 0x7: // r3
1450 		m_core->yaau_r[r & 0x0003U] = m;
1451 		break;
1452 	}
1453 }
1454 
yaau_read(u16 op)1455 template <bool Debugger> inline s16 dsp16_device_base::yaau_read(u16 op)
1456 {
1457 	u16 const &r(m_core->op_yaau_r(op));
1458 	s16 const result(Debugger ? m_spaces[AS_DATA]->read_word(r) : m_workram[r & m_workram_mask]);
1459 	m_core->yaau_postmodify_r(op);
1460 	return result;
1461 }
1462 
yaau_write(u16 op,s16 value)1463 template <bool Debugger> inline void dsp16_device_base::yaau_write(u16 op, s16 value)
1464 {
1465 	u16 const &r(m_core->op_yaau_r(op));
1466 	if (Debugger)
1467 		m_spaces[AS_DATA]->write_word(r, value);
1468 	else
1469 		m_workram[r & m_workram_mask] = value;
1470 	m_core->yaau_postmodify_r(op);
1471 }
1472 
yaau_write_z(u16 op)1473 template <bool Debugger> void dsp16_device_base::yaau_write_z(u16 op)
1474 {
1475 	u16 &r(m_core->op_yaau_r(op));
1476 	if (Debugger)
1477 		m_spaces[AS_DATA]->write_word(r, m_core->dau_temp);
1478 	else
1479 		m_workram[r & m_workram_mask] = m_core->dau_temp;
1480 	switch (op & 0x0003U)
1481 	{
1482 	case 0x0: // *rNzp
1483 		if (m_core->yaau_re && (m_core->yaau_re == r))
1484 			r = m_core->yaau_rb;
1485 		else
1486 			++r;
1487 		break;
1488 	case 0x1: // *rNpz
1489 		break;
1490 	case 0x2: // *rNm2
1491 		r += 2;
1492 		break;
1493 	case 0x3: // *rNjk;
1494 		r += m_core->yaau_k;
1495 		break;
1496 	}
1497 	r &= m_core->yaau_mask;
1498 }
1499 
1500 /***********************************************************************
1501     built-in peripherals
1502 ***********************************************************************/
1503 
sio_step()1504 inline void dsp16_device_base::sio_step()
1505 {
1506 	// step the serial I/O clock divider
1507 	if (m_sio_clk_div)
1508 	{
1509 		--m_sio_clk_div;
1510 	}
1511 	else
1512 	{
1513 		bool const active(!m_sio_clk);
1514 		m_sio_clk = active ? 1U : 0U;
1515 		if (sio_ick_active())
1516 		{
1517 			if (active)
1518 				sio_ick_active_edge();
1519 			m_ick_cb(m_sio_clk);
1520 		}
1521 		if (sio_ock_active())
1522 		{
1523 			m_ock_cb(m_sio_clk);
1524 			if (active)
1525 				sio_ock_active_edge();
1526 		}
1527 		m_sio_clk_div = m_sio_clk_res;
1528 	}
1529 }
1530 
pio_step()1531 inline void dsp16_device_base::pio_step()
1532 {
1533 	// udpate parallel input strobe
1534 	if (m_pio_pids_cnt)
1535 	{
1536 		assert(!m_pids_out);
1537 		if (!--m_pio_pids_cnt)
1538 		{
1539 			if (!m_pio_r_cb.isnull())
1540 				m_pio_pdx_in = m_pio_r_cb(m_psel_out, 0xffffU);
1541 			m_pids_cb(m_pids_out = 1U);
1542 			LOGPIO("DSP16: PIO read active edge PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, m_pio_pdx_in, m_st_pcbase);
1543 		}
1544 	}
1545 	else
1546 	{
1547 		assert(m_pids_out);
1548 	}
1549 
1550 	// udpate parallel output strobe
1551 	if (m_pio_pods_cnt)
1552 	{
1553 		assert(!m_pods_out);
1554 		if (!--m_pio_pods_cnt)
1555 		{
1556 			LOGPIO("DSP16: PIO write active edge PSEL = %u, PDX = %04X (PC = %04X)\n", m_psel_out, m_pio_pdx_out, m_st_pcbase);
1557 			m_pods_cb(1U);
1558 			m_pio_w_cb(m_psel_out, m_pio_pdx_out, 0xffffU);
1559 			m_pods_out = 1U;
1560 			m_pdb_w_cb(m_psel_out, 0xffffU, 0x0000U);
1561 		}
1562 	}
1563 	else
1564 	{
1565 		assert(m_pods_out);
1566 	}
1567 }
1568 
1569 /***********************************************************************
1570     inline helpers
1571 ***********************************************************************/
1572 
op_interruptible(u16 op)1573 inline bool dsp16_device_base::op_interruptible(u16 op)
1574 {
1575 	switch (op >> 11)
1576 	{
1577 	case 0x02: // R = M
1578 	case 0x03:
1579 	case 0x04: // F1 ; Y = a1[l]
1580 	case 0x05: // F1 ; Z : aT[l]
1581 	case 0x06: // F1 ; Y
1582 	case 0x07: // F1 ; aT[l] = Y
1583 	case 0x08: // aT = R
1584 	case 0x09: // R = a0
1585 	case 0x0a: // R = N
1586 	case 0x0b: // R = a1
1587 	case 0x0c: // Y = R
1588 	case 0x0d: // Z : R
1589 	case 0x0f: // R = Y
1590 	case 0x12: // ifc CON F2
1591 	case 0x13: // if CON F2
1592 	case 0x14: // F1 ; Y = y[l]
1593 	case 0x15: // F1 ; Z : y[l]
1594 	case 0x16: // F1 ; x = Y
1595 	case 0x17: // F1 ; y[l] = Y
1596 	case 0x19: // F1 ; y = a0 ; x = *pt++[i]
1597 	case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
1598 	case 0x1c: // F1 ; Y = a0[l]
1599 	case 0x1d: // F1 ; Z : y ; x = *pt++[i]
1600 	case 0x1f: // F1 ; y = Y ; x = *pt++[i]
1601 		return true;
1602 	case 0x00: // goto JA
1603 	case 0x01:
1604 	case 0x0e: // do K { instr1...instrNI } # redo K
1605 	case 0x10: // call JA
1606 	case 0x11:
1607 	case 0x18: // goto B
1608 	case 0x1a: // if CON # icall
1609 	case 0x1e: // Reserved
1610 	default:
1611 		return false;
1612 	};
1613 }
1614 
check_predicate()1615 inline bool dsp16_device_base::check_predicate()
1616 {
1617 	bool const result(FLAGS_PRED_FALSE != (m_flags & FLAGS_PRED_MASK));
1618 	set_predicate(FLAGS_PRED_NONE);
1619 	return result;
1620 }
1621 
set_xaau_pc_offset(u16 offset)1622 inline u16 &dsp16_device_base::set_xaau_pc_offset(u16 offset)
1623 {
1624 	m_core->xaau_pc = (m_core->xaau_pc & XAAU_I_EXT) | (offset & XAAU_I_MASK);
1625 	if (m_iack_out)
1626 		m_core->xaau_pi = m_core->xaau_pc;
1627 	return m_core->xaau_pc;
1628 }
1629 
get_r(u16 op)1630 inline s16 dsp16_device_base::get_r(u16 op)
1631 {
1632 	switch (op_r(op))
1633 	{
1634 	case 0x00: // r0 (u)
1635 	case 0x01: // r1 (u)
1636 	case 0x02: // r2 (u)
1637 	case 0x03: // r3 (u)
1638 		return m_core->yaau_r[op_r(op)];
1639 	case 0x04: // j (s)
1640 		return m_core->yaau_j;
1641 	case 0x05: // k (s)
1642 		return m_core->yaau_k;
1643 	case 0x06: // rb (u)
1644 		return m_core->yaau_rb;
1645 	case 0x07: // re (u)
1646 		return m_core->yaau_re;
1647 	case 0x08: // pt
1648 		return m_core->xaau_pt;
1649 	case 0x09: // pr
1650 		return m_core->xaau_pr;
1651 	case 0x0a: // pi
1652 		return m_core->xaau_pi;
1653 	case 0x0b: // i (s)
1654 		return m_core->xaau_i;
1655 	case 0x10: // x
1656 		return m_core->dau_x;
1657 	case 0x11: // y
1658 		return u16(u32(m_core->dau_y >> 16));
1659 	case 0x12: // yl
1660 		return u16(u32(m_core->dau_y));
1661 		break;
1662 	case 0x13: // auc (u)
1663 		return m_core->dau_auc;
1664 	case 0x14: // psw
1665 		return m_core->dau_export_psw();
1666 	case 0x15: // c0 (s)
1667 	case 0x16: // c1 (s)
1668 	case 0x17: // c2 (s)
1669 		return m_core->dau_c[op_r(op) - 0x15];
1670 	case 0x18: // sioc
1671 		return m_sio_sioc;
1672 	case 0x19: // srta
1673 		logerror("DSP16: unimplemented get SRTA\n");
1674 		return 0;
1675 	case 0x1a: // sdx
1676 		logerror("DSP16: unimplemented get SDX\n");
1677 		return 0;
1678 	case 0x1b: // tdms
1679 		logerror("DSP16: unimplemented get TDMS\n");
1680 		return 0;
1681 	case 0x1c: // pioc
1682 		return m_pio_pioc;
1683 	case 0x1d: // pdx0
1684 	case 0x1e: // pdx1
1685 		return pio_pdx_read(BIT(op_r(op), 1));
1686 	default:
1687 		throw emu_fatalerror("DSP16: invalid R value %02X (PC = %04X)\n", op_r(op), m_st_pcbase);
1688 	}
1689 }
1690 
set_r(u16 op,s16 value)1691 inline void dsp16_device_base::set_r(u16 op, s16 value)
1692 {
1693 	switch (op_r(op))
1694 	{
1695 	case 0x00: // r0 (u)
1696 	case 0x01: // r1 (u)
1697 	case 0x02: // r2 (u)
1698 	case 0x03: // r3 (u)
1699 		m_core->yaau_r[op_r(op)] = value & m_core->yaau_mask;
1700 		break;
1701 	case 0x04: // j (s)
1702 		m_core->yaau_set_j(value);
1703 		break;
1704 	case 0x05: // k (s)
1705 		m_core->yaau_set_k(value);
1706 		break;
1707 	case 0x06: // rb (u)
1708 		m_core->yaau_set_rb(value);
1709 		break;
1710 	case 0x07: // re (u)
1711 		m_core->yaau_set_re(value);
1712 		break;
1713 	case 0x08: // pt
1714 		m_core->xaau_pt = value;
1715 		break;
1716 	case 0x09: // pr
1717 		m_core->xaau_pr = value;
1718 		break;
1719 	case 0x0a: // pi
1720 		// FIXME: reset PRNG
1721 		if (!m_iack_out)
1722 			m_core->xaau_pi = value;
1723 		break;
1724 	case 0x0b: // i (s)
1725 		m_core->xaau_i = (value & XAAU_I_MASK) | ((value & XAAU_I_SIGN) ? XAAU_I_EXT : 0);
1726 		break;
1727 	case 0x10: // x
1728 		m_core->dau_x = value;
1729 		break;
1730 	case 0x11: // y
1731 		m_core->dau_set_y(value);
1732 		break;
1733 	case 0x12: // yl
1734 		m_core->dau_set_yl(value);
1735 		break;
1736 	case 0x13: // auc (u)
1737 		m_core->dau_auc = u8(value & 0x007f);
1738 		break;
1739 	case 0x14: // psw
1740 		m_core->dau_psw = value;
1741 		m_core->dau_import_psw();
1742 		break;
1743 	case 0x15: // c0 (s)
1744 	case 0x16: // c1 (s)
1745 	case 0x17: // c2 (s)
1746 		m_core->dau_c[op_r(op) - 0x15] = u8(u16(value));
1747 		break;
1748 	case 0x18: // sioc
1749 		sio_sioc_write(value);
1750 		break;
1751 	case 0x19: // srta
1752 		logerror("DSP16: unimplemented SRTA = %04X\n", value);
1753 		break;
1754 	case 0x1a: // sdx
1755 		LOGSIO("DSP16: write SDX = %04X%s (PC = %04X)\n", value, pio_obe_status() ? "" : " - overrun", m_st_pcbase);
1756 		if (pio_obe_status())
1757 			LOGINT("DSP16 clear OBE flag (PC = %04X)\n", m_st_pcbase);
1758 		m_sio_obuf = value;
1759 		m_pio_pioc &= ~(u16(1) << 3);
1760 		break;
1761 	case 0x1b: // tdms
1762 		logerror("DSP16: unimplemented TDMS = %04X\n", value);
1763 		break;
1764 	case 0x1c: // pioc
1765 		pio_pioc_write(value);
1766 		break;
1767 	case 0x1d: // pdx0
1768 	case 0x1e: // pdx1
1769 		pio_pdx_write(BIT(op_r(op), 1), value);
1770 		break;
1771 	default:
1772 		throw emu_fatalerror("DSP16: invalid R value %02X (PC = %04X)\n", op_r(op), m_st_pcbase);
1773 	}
1774 }
1775 
dau_saturate(u16 a) const1776 s64 dsp16_device_base::dau_saturate(u16 a) const
1777 {
1778 	if (m_core->dau_auc_sat(a))
1779 		return m_core->dau_a[a];
1780 	else
1781 		return std::min<s64>(std::max<s64>(m_core->dau_a[a], std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
1782 }
1783 
op_dau_con(u16 op,bool inc)1784 inline bool dsp16_device_base::op_dau_con(u16 op, bool inc)
1785 {
1786 	bool result;
1787 	u16 const con(op_con(op));
1788 	switch (con >> 1)
1789 	{
1790 	case 0x0: // mi/pl
1791 		result = m_core->dau_psw_lmi();
1792 		break;
1793 	case 0x1: // eq/ne
1794 		result = m_core->dau_psw_leq();
1795 		break;
1796 	case 0x2: // lvs/lvc
1797 		result = m_core->dau_psw_llv();
1798 		break;
1799 	case 0x3: // mvs/mvc
1800 		result = m_core->dau_psw_lmv();
1801 		break;
1802 	case 0x4: // heads/tails
1803 		throw emu_fatalerror("DSP16: unimplemented CON value %02X (PC = %04X)\n", con, m_st_pcbase);
1804 	case 0x5: // c0ge/c0lt
1805 	case 0x6: // c1ge/c1lt
1806 		{
1807 			s8 &c(m_core->dau_c[(con >> 1) - 0x05]);
1808 			result = 0 <= c;
1809 			if (inc)
1810 				++c;
1811 		}
1812 		break;
1813 	case 0x7: // true/false
1814 		result = true;
1815 		break;
1816 	case 0x8: // gt/le
1817 		result = !m_core->dau_psw_lmi() && !m_core->dau_psw_leq();
1818 		break;
1819 	default: // Reserved
1820 		throw emu_fatalerror("DSP16: reserved CON value %02X (PC = %04X)\n", con, m_st_pcbase);
1821 	}
1822 	return BIT(con, 0) ? !result : result;
1823 }
1824 
1825 /***********************************************************************
1826     serial I/O
1827 ***********************************************************************/
1828 
sio_sioc_write(u16 value)1829 void dsp16_device_base::sio_sioc_write(u16 value)
1830 {
1831 	static constexpr unsigned DIVIDERS[4] = { 4U, 12U, 16U, 20U };
1832 	value &= 0x03ffU;
1833 	LOGSIO(
1834 			"DSP16: write SIOC = %03X: "
1835 			"LD %cCK/n->%cCK/n, CLK CKI/%u->CKI/%u, %cSB->%cSB first, "
1836 			"OLD %s->%s, ILD %s->%s, OCK %s->%s, ICK %s->%s, OLEN %u->%u, ILEN %u->%u "
1837 			"(PC = %04X)\n",
1838 			value,
1839 			sio_ld_ock() ? 'O' : 'I', BIT(value, 9) ? 'O' : 'I',
1840 			DIVIDERS[(m_sio_sioc >> 7) & 0x0003U], DIVIDERS[(value >> 7) & 0x0003U],
1841 			sio_msb_first() ? 'M' : 'L', BIT(value, 6) ? 'M' : 'L',
1842 			sio_old_active() ? "active" : "passive", BIT(value, 5) ? "active" : "passive",
1843 			sio_ild_active() ? "active" : "passive", BIT(value, 4) ? "active" : "passive",
1844 			sio_ock_active() ? "active" : "passive", BIT(value, 3) ? "active" : "passive",
1845 			sio_ick_active() ? "active" : "passive", BIT(value, 2) ? "active" : "passive",
1846 			sio_olen(), BIT(value, 1) ? 8U : 16U,
1847 			sio_ilen(), BIT(value, 0) ? 8U : 16U,
1848 			m_st_pcbase);
1849 
1850 	bool const old_change(BIT(value ^ m_sio_sioc, 5));
1851 	bool const ild_change(BIT(value ^ m_sio_sioc, 4));
1852 	bool const ock_change(BIT(value ^ m_sio_sioc, 3));
1853 	bool const ick_change(BIT(value ^ m_sio_sioc, 2));
1854 	m_sio_sioc = value;
1855 
1856 	// we're using treating high-impedance and high as the same thing
1857 	if (!m_sio_ld)
1858 	{
1859 		if (ild_change)
1860 			m_ild_cb(sio_ild_active() ? 0 : 1);
1861 		if (old_change)
1862 			m_old_cb(sio_old_active() ? 0 : 1);
1863 	}
1864 	if (!m_sio_clk)
1865 	{
1866 		if (ick_change)
1867 			m_ick_cb(sio_ick_active() ? 0 : 1);
1868 		if (ock_change)
1869 			m_ock_cb(sio_ock_active() ? 0 : 1);
1870 	}
1871 
1872 	// precalculate divider preload
1873 	switch ((value >> 7) & 0x0003U)
1874 	{
1875 	case 0x0: m_sio_clk_res = (4 / 4) - 1; break; // CKI÷4
1876 	case 0x1: m_sio_clk_res = (12 / 4) - 1; break; // CKI÷12
1877 	case 0x2: m_sio_clk_res = (16 / 4) - 1; break; // CKI÷16
1878 	case 0x3: m_sio_clk_res = (20 / 4) - 1; break; // CKI÷20
1879 	}
1880 }
1881 
sio_ick_active_edge()1882 inline void dsp16_device_base::sio_ick_active_edge()
1883 {
1884 	// check for start of transaction
1885 	bool const ild(sio_ild_active() ? !m_sio_ld : (CLEAR_LINE != m_ild_in));
1886 	if (ASSERT_LINE != m_ild_in)
1887 		m_ild_in = CLEAR_LINE;
1888 	if (ild)
1889 	{
1890 		// FIXME: implement enough to put something here
1891 		m_sio_flags |= SIO_FLAGS_ILD;
1892 	}
1893 	else
1894 	{
1895 		m_sio_flags &= ~SIO_FLAGS_ILD;
1896 	}
1897 
1898 	// update internal LD divider if it's being driven by ICK
1899 	if (sio_ld_ick())
1900 		sio_step_ld_div();
1901 }
1902 
sio_ock_active_edge()1903 inline void dsp16_device_base::sio_ock_active_edge()
1904 {
1905 	// check for load opportunity
1906 	bool const old(sio_old_active() ? !m_sio_ld : (CLEAR_LINE != m_old_in));
1907 	if (ASSERT_LINE != m_old_in)
1908 		m_old_in = CLEAR_LINE;
1909 	if (old)
1910 	{
1911 		if ((SIO_FLAGS_NONE == (m_sio_flags & SIO_FLAGS_OLD)) && !m_sio_ofsr && !pio_obe_status())
1912 		{
1913 			bool const eight_bit(8U == sio_olen());
1914 			LOGSIO(
1915 					"DSP16: load OSR = %04X & %04X %cSB first (PC = %04X)\n",
1916 					m_sio_obuf, !eight_bit ? 0xffffU : sio_msb_first() ? 0xff00U : 0x00ffU, sio_msb_first() ? 'M' : 'L', m_st_pcbase);
1917 			LOGINT("DSP16: set OBE flag (PC = %04X)\n", m_st_pcbase);
1918 
1919 			m_sio_osr = sio_msb_first() ? bitswap<16>(m_sio_obuf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) : m_sio_obuf;
1920 			m_sio_ofsr = 0xffffU;
1921 			if (eight_bit)
1922 			{
1923 				m_sio_osr |= 0xff00U;
1924 				m_sio_ofsr >>= 8;
1925 			}
1926 
1927 			m_pio_pioc |= u16(1) << 3;
1928 		}
1929 		m_sio_flags |= SIO_FLAGS_OLD;
1930 	}
1931 	else
1932 	{
1933 		m_sio_flags &= ~SIO_FLAGS_OLD;
1934 	}
1935 
1936 	// shift out serial data
1937 	if (BIT(m_sio_osr, 0) != m_do_out)
1938 		m_do_cb(m_do_out = BIT(m_sio_osr, 0));
1939 	if (BIT(~m_sio_ofsr, 0) != m_ose_out)
1940 	{
1941 		LOGSIO("DSP16: OSE %u->%u (PC = %04X)\n", m_ose_out, BIT(~m_sio_ofsr, 0), m_st_pcbase);
1942 		m_ose_cb(m_ose_out = BIT(~m_sio_ofsr, 0));
1943 	}
1944 	m_sio_osr = (m_sio_osr >> 1) | 0x8000U;
1945 	m_sio_ofsr >>= 1;
1946 
1947 	// update internal LD divider if it's being driven by OCK
1948 	if (sio_ld_ock())
1949 		sio_step_ld_div();
1950 }
1951 
sio_step_ld_div()1952 inline void dsp16_device_base::sio_step_ld_div()
1953 {
1954 	if (m_sio_ld_div)
1955 	{
1956 		--m_sio_ld_div;
1957 	}
1958 	else
1959 	{
1960 		m_sio_ld = m_sio_ld ? 0U : 1U;
1961 		m_sio_ld_div = (16 / 2) - 1;
1962 		if (sio_ild_active())
1963 			m_ild_cb(m_sio_ld);
1964 		if (sio_old_active())
1965 			m_old_cb(m_sio_ld);
1966 	}
1967 }
1968 
1969 /***********************************************************************
1970     parallel I/O
1971 ***********************************************************************/
1972 
pio_pioc_write(u16 value)1973 void dsp16_device_base::pio_pioc_write(u16 value)
1974 {
1975 	LOGPIO(
1976 			"DSP16: write PIOC = %04X: "
1977 			"STROBE %uT->%uT, PODS %s->%s, PIDS %s->%s, S/C %u->%u, "
1978 			"IBF %s->%s, OBE %s->%s, PIDS %s->%s, PODS %s->%s, INT %s->%s "
1979 			"(PC = %04X)\n",
1980 			value,
1981 			pio_strobe(), ((value >> 13) & 0x0003U) + 1,
1982 			pio_pods_active() ? "active" : "passive", BIT(value, 12) ? "active" : "passive",
1983 			pio_pids_active() ? "active" : "passive", BIT(value, 11) ? "active" : "passive",
1984 			BIT(m_pio_pioc, 10), BIT(value, 10),
1985 			pio_ibf_enable() ? "en" : "dis", BIT(value, 9) ? "en" : "dis",
1986 			pio_obe_enable() ? "en" : "dis", BIT(value, 8) ? "en" : "dis",
1987 			pio_pids_enable() ? "en" : "dis", BIT(value, 7) ? "en" : "dis",
1988 			pio_pods_enable() ? "en" : "dis", BIT(value, 6) ? "en" : "dis",
1989 			pio_int_enable() ? "en" : "dis", BIT(value, 5) ? "en" : "dis",
1990 			m_st_pcbase);
1991 
1992 	m_pio_pioc = (m_pio_pioc & 0x801fU) | (value & 0x7fe0U);
1993 	m_int_enable[1] = (value >> 5) & 0x001fU;
1994 	if (!pio_pids_active())
1995 	{
1996 		m_pio_pids_cnt = 0U;
1997 		if (!m_pids_out)
1998 			m_pids_cb(m_pids_out = 1U); // actually high-impedance
1999 	}
2000 	if (!pio_pods_active())
2001 	{
2002 		m_pio_pods_cnt = 0U;
2003 		if (!m_pods_out)
2004 		{
2005 			m_pods_cb(m_pods_out = 1U); // actually high-impedance
2006 			m_pdb_w_cb(m_psel_out, 0xffffU, 0x0000U);
2007 		}
2008 	}
2009 }
2010 
pio_pdx_read(u16 sel)2011 u16 dsp16_device_base::pio_pdx_read(u16 sel)
2012 {
2013 	bool const active(pio_pids_active());
2014 	LOGPIO("DSP16: read PDX%u = %04X %s (PC = %04X)\n", sel, m_pio_pdx_in, active ? "active" : "passive", m_st_pcbase);
2015 	if (pio_pids_status())
2016 		LOGINT("DSP16: clear PIDS flag (PC = %04X)\n", m_st_pcbase);
2017 	m_pio_pioc &= ~(u16(1) << 2);
2018 
2019 	if (sel != m_psel_out)
2020 	{
2021 		LOGPIO("DSP16: PSEL %u->%u (PC = %04X)\n", m_psel_out, sel, m_st_pcbase);
2022 		m_psel_cb(m_psel_out = sel);
2023 	}
2024 
2025 	if (active)
2026 	{
2027 		if (m_pio_pids_cnt)
2028 		{
2029 			assert(!m_pids_out);
2030 			logerror("DSP16: PDX%u active read while PIDS still asserted (PC = %04X)\n", sel, m_st_pcbase);
2031 		}
2032 		else
2033 		{
2034 			assert(m_pids_out);
2035 			m_pids_cb(m_pids_out = 0U);
2036 		}
2037 		m_pio_pids_cnt = pio_strobe() + 1; // decremented this cycle
2038 	}
2039 
2040 	return m_pio_pdx_in;
2041 }
2042 
pio_pdx_write(u16 sel,u16 value)2043 void dsp16_device_base::pio_pdx_write(u16 sel, u16 value)
2044 {
2045 	bool const active(pio_pods_active());
2046 	LOGPIO("DSP16: write PDX%u = %04X %s (PC = %04X)\n", sel, value, active ? "active" : "passive", m_st_pcbase);
2047 	if (pio_pods_status())
2048 		LOGINT("DSP16: clear PODS flag (PC = %04X)\n", m_st_pcbase);
2049 	m_pio_pioc &= ~(u16(1) << 1);
2050 	m_pio_pdx_out = value;
2051 
2052 	if (sel != m_psel_out)
2053 	{
2054 		LOGPIO("DSP16: PSEL %u->%u (PC = %04X)\n", m_psel_out, sel, m_st_pcbase);
2055 		m_psel_cb(m_psel_out = sel);
2056 	}
2057 
2058 	if (active)
2059 	{
2060 		if (m_pio_pods_cnt)
2061 		{
2062 			assert(!m_pods_out);
2063 			logerror("DSP16: PDX%u active write while PODS still asserted (PC = %04X)\n", sel, m_st_pcbase);
2064 		}
2065 		else
2066 		{
2067 			assert(m_pods_out);
2068 			m_pods_cb(m_pods_out = 0U);
2069 			m_pdb_w_cb(sel, value, 0xffffU);
2070 		}
2071 		m_pio_pods_cnt = pio_strobe() + 1; // decremented this cycle
2072 	}
2073 }
2074 
2075 
2076 /***************************************************************************
2077     DSP16 SPECIALISATION
2078 ***************************************************************************/
2079 
dsp16_device(machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)2080 dsp16_device::dsp16_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
2081 	: dsp16_device_base(
2082 			mconfig, DSP16, tag, owner, clock,
2083 			9,
2084 			address_map_constructor(FUNC(dsp16_device::data_map), this))
2085 	, m_rom(*this, DEVICE_SELF, 0x0800)
2086 {
2087 }
2088 
external_memory_enable(address_space & space,bool enable)2089 void dsp16_device::external_memory_enable(address_space &space, bool enable)
2090 {
2091 	// manual implies the DSP16 doesn't support enabling both internal and external ROM at the same time (page 2-2)
2092 	// this assumes internal ROM is mirrored above 2KiB, but actual hardware behaviour is unknown
2093 	space.unmap_read(0x0000, 0xffff);
2094 	if (enable)
2095 		space.install_read_handler(0x0000, 0xffff, read16s_delegate(*this, FUNC(dsp16_device::external_memory_r<0x0000>)));
2096 	else
2097 		space.install_rom(0x0000, 0x07ff, 0xf800, &m_rom[0]);
2098 }
2099 
data_map(address_map & map)2100 void dsp16_device::data_map(address_map &map)
2101 {
2102 	map.global_mask(0x01ff);
2103 	map.unmap_value_high();
2104 	map(0x0000, 0x01ff).ram().share("workram");
2105 }
2106 
2107 
2108 /***************************************************************************
2109     DSP16A SPECIALISATION
2110 ***************************************************************************/
2111 
dsp16a_device(machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)2112 dsp16a_device::dsp16a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
2113 	: dsp16_device_base(
2114 			mconfig, DSP16A, tag, owner, clock,
2115 			16,
2116 			address_map_constructor(FUNC(dsp16a_device::data_map), this))
2117 	, m_rom(*this, DEVICE_SELF, 0x1000)
2118 {
2119 }
2120 
external_memory_enable(address_space & space,bool enable)2121 void dsp16a_device::external_memory_enable(address_space &space, bool enable)
2122 {
2123 	space.unmap_read(0x0000, 0xffff);
2124 	if (enable)
2125 	{
2126 		space.install_read_handler(0x0000, 0xffff, read16s_delegate(*this, FUNC(dsp16a_device::external_memory_r<0x0000>)));
2127 	}
2128 	else
2129 	{
2130 		space.install_rom(0x0000, 0x0fff, &m_rom[0]);
2131 		space.install_read_handler(0x1000, 0xffff, read16s_delegate(*this, FUNC(dsp16a_device::external_memory_r<0x1000>)));
2132 	}
2133 }
2134 
data_map(address_map & map)2135 void dsp16a_device::data_map(address_map &map)
2136 {
2137 	map.global_mask(0x07ff);
2138 	map.unmap_value_high();
2139 	map(0x0000, 0x07ff).ram().share("workram");
2140 }
2141