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