1 // license:BSD-3-Clause
2 // copyright-holders:Andrew Gardner
3 /***************************************************************************
4 
5     dsp56156.cpp
6     Core implementation for the portable DSP56156 emulator.
7     Written by Andrew Gardner
8 
9 ****************************************************************************
10 
11     Note:
12     This CPU emulator is very much a work-in-progress.
13 
14     DONE:
15     1:  1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
16        11,  ,  ,  ,  ,  ,  ,18,  ,   ,
17 
18     TODO:
19     X 1-6 Explore CORE naming scheme.
20     - 1-9 paragraph 1 : memory access timings
21     - 1-9 Data ALU arithmetic operations generally use fractional two's complement arithmetic
22           (Unsigned numbers are only supported by the multiply and multiply-accumulate instruction)
23     - 1-9 For fractional arithmetic, the 31-bit product is added to the 40-bit contents of A or B.  No pipeline!
24     - 1-10 Two types of rounding: convergent rounding and two's complement rounding.  See status register bit R.
25     - 1-10 Logic unit is 16-bits wide and works on MSP portion of accum register
26     - 1-10 The AGU can implement three types of arithmetic: linear, modulo, and reverse carry.
27     - 1-12 "Two external interrupt pins!!!"
28     - 1-12 Take care of all interrupt priority (IPR) stuff!
29     - 1-19 Memory WAIT states
30     - 1-20 The timer's interesting!
31     - 1-21 Vectored exception requests on the Host Interface!
32 ***************************************************************************/
33 
34 #include "emu.h"
35 #include "dsp56156.h"
36 #include "dsp56dsm.h"
37 
38 #include "opcode.h"
39 
40 #include "debugger.h"
41 
42 #include "dsp56def.h"
43 
44 /***************************************************************************
45     COMPONENT FUNCTIONALITY
46 ***************************************************************************/
47 /* 1-9 ALU */
48 // #include "dsp56alu.h"
49 
50 /* 1-10 Address Generation Unit (AGU) */
51 // #include "dsp56agu.h"
52 
53 /* 1-11 Program Control Unit (PCU) */
54 #include "dsp56pcu.h"
55 
56 /* 5-1 Host Interface (HI) */
57 //#include "dsp56hi.h"
58 
59 /* 4-8 Memory handlers for on-chip peripheral memory. */
60 #include "dsp56mem.h"
61 
62 
63 DEFINE_DEVICE_TYPE_NS(DSP56156, DSP_56156, dsp56156_device, "dsp56156", "Motorola DSP56156")
64 
65 
66 namespace DSP_56156 {
67 
68 enum
69 {
70 	// PCU
71 	DSP56156_PC=1,
72 	DSP56156_SR,
73 	DSP56156_LC,
74 	DSP56156_LA,
75 	DSP56156_SP,
76 	DSP56156_OMR,
77 
78 	// ALU
79 	DSP56156_X, DSP56156_Y,
80 	DSP56156_A, DSP56156_B,
81 
82 	// AGU
83 	DSP56156_R0,DSP56156_R1,DSP56156_R2,DSP56156_R3,
84 	DSP56156_N0,DSP56156_N1,DSP56156_N2,DSP56156_N3,
85 	DSP56156_M0,DSP56156_M1,DSP56156_M2,DSP56156_M3,
86 	DSP56156_TEMP,
87 	DSP56156_STATUS,
88 
89 	// CPU STACK
90 	DSP56156_ST0,
91 	DSP56156_ST1,
92 	DSP56156_ST2,
93 	DSP56156_ST3,
94 	DSP56156_ST4,
95 	DSP56156_ST5,
96 	DSP56156_ST6,
97 	DSP56156_ST7,
98 	DSP56156_ST8,
99 	DSP56156_ST9,
100 	DSP56156_ST10,
101 	DSP56156_ST11,
102 	DSP56156_ST12,
103 	DSP56156_ST13,
104 	DSP56156_ST14,
105 	DSP56156_ST15
106 };
107 
108 
109 /****************************************************************************
110  *  Internal Memory Maps
111  ****************************************************************************/
dsp56156_program_map(address_map & map)112 void dsp56156_device::dsp56156_program_map(address_map &map)
113 {
114 	map(0x0000, 0x07ff).ram().share("dsk56156_program_ram");   /* 1-5 */
115 //  map(0x2f00, 0x2fff).rom();                              /* 1-5 PROM reserved memory.  Is this the right spot for it? */
116 }
117 
dsp56156_x_data_map(address_map & map)118 void dsp56156_device::dsp56156_x_data_map(address_map &map)
119 {
120 	map(0x0000, 0x07ff).ram();                              /* 1-5 */
121 	map(0xffc0, 0xffff).rw(FUNC(dsp56156_device::peripheral_register_r), FUNC(dsp56156_device::peripheral_register_w));   /* 1-5 On-chip peripheral registers memory mapped in data space */
122 }
123 
124 
dsp56156_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)125 dsp56156_device::dsp56156_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
126 	: cpu_device(mconfig, DSP56156, tag, owner, clock)
127 	, m_program_config("program", ENDIANNESS_LITTLE, 16, 16, -1, address_map_constructor(FUNC(dsp56156_device::dsp56156_program_map), this))
128 	, m_data_config("data", ENDIANNESS_LITTLE, 16, 16, -1, address_map_constructor(FUNC(dsp56156_device::dsp56156_x_data_map), this))
129 	, m_program_ram(*this, "dsk56156_program_ram")
130 {
131 }
132 
memory_space_config() const133 device_memory_interface::space_config_vector dsp56156_device::memory_space_config() const
134 {
135 	return space_config_vector {
136 		std::make_pair(AS_PROGRAM, &m_program_config),
137 		std::make_pair(AS_DATA,    &m_data_config)
138 	};
139 }
140 
141 /***************************************************************************
142     MEMORY ACCESSORS
143 ***************************************************************************/
144 #define ROPCODE(pc)   cpustate->cache.read_word(pc)
145 
146 
147 /***************************************************************************
148     IRQ HANDLING
149 ***************************************************************************/
execute_set_input(int irqline,int state)150 void dsp56156_device::execute_set_input(int irqline, int state)
151 {
152 	//logerror("DSP56156 set irq line %d %d\n", irqline, state);
153 
154 	switch(irqline)
155 	{
156 		case DSP56156_IRQ_MODA:
157 			// TODO: 1-12 Get this triggering right
158 			if (irqa_trigger(&m_core))
159 				logerror("DSP56156 IRQA is set to fire on the \"Negative Edge\".\n");
160 
161 			if (state != CLEAR_LINE)
162 				m_core.modA_state = true;
163 			else
164 				m_core.modA_state = false;
165 
166 			if (m_core.reset_state != true)
167 				dsp56156_add_pending_interrupt(&m_core, "IRQA");
168 			break;
169 
170 		case DSP56156_IRQ_MODB:
171 			// TODO: 1-12 Get this triggering right
172 			if (irqb_trigger(&m_core))
173 				logerror("DSP56156 IRQB is set to fire on the \"Negative Edge\".\n");
174 
175 			if (state != CLEAR_LINE)
176 				m_core.modB_state = true;
177 			else
178 				m_core.modB_state = false;
179 
180 			if (m_core.reset_state != true)
181 				dsp56156_add_pending_interrupt(&m_core, "IRQB");
182 			break;
183 
184 		case DSP56156_IRQ_MODC:
185 			if (state != CLEAR_LINE)
186 				m_core.modC_state = true;
187 			else
188 				m_core.modC_state = false;
189 
190 			// TODO : Set bus mode or whatever
191 			break;
192 
193 		case DSP56156_IRQ_RESET:
194 			if (state != CLEAR_LINE)
195 				m_core.reset_state = true;
196 			else
197 			{
198 				/* If it changes state from asserted to cleared.  Call the reset function. */
199 				if (m_core.reset_state == true)
200 					device_reset();
201 
202 				m_core.reset_state = false;
203 			}
204 
205 			// dsp56156_add_pending_interrupt("Hardware RESET");
206 			break;
207 
208 		default:
209 			logerror("DSP56156 setting some weird irq line : %d", irqline);
210 			break;
211 	}
212 
213 	/* If the reset line isn't asserted, service interrupts */
214 	// TODO: Is it right to immediately service interrupts?
215 	//if (cpustate->reset_state != true)
216 	//  pcu_service_interrupts();
217 }
218 
219 
220 /***************************************************************************
221     INITIALIZATION AND SHUTDOWN
222 ***************************************************************************/
agu_init()223 void dsp56156_device::agu_init()
224 {
225 	/* save states - dsp56156_agu members */
226 	save_item(NAME(m_core.AGU.r0));
227 	save_item(NAME(m_core.AGU.r1));
228 	save_item(NAME(m_core.AGU.r2));
229 	save_item(NAME(m_core.AGU.r3));
230 	save_item(NAME(m_core.AGU.n0));
231 	save_item(NAME(m_core.AGU.n1));
232 	save_item(NAME(m_core.AGU.n2));
233 	save_item(NAME(m_core.AGU.n3));
234 	save_item(NAME(m_core.AGU.m0));
235 	save_item(NAME(m_core.AGU.m1));
236 	save_item(NAME(m_core.AGU.m2));
237 	save_item(NAME(m_core.AGU.m3));
238 	save_item(NAME(m_core.AGU.temp));
239 }
240 
alu_init()241 void dsp56156_device::alu_init()
242 {
243 	/* save states - dsp56156_alu members */
244 	save_item(NAME(m_core.ALU.x));
245 	save_item(NAME(m_core.ALU.y));
246 	save_item(NAME(m_core.ALU.a));
247 	save_item(NAME(m_core.ALU.b));
248 }
249 
device_start()250 void dsp56156_device::device_start()
251 {
252 	memset(&m_core, 0, sizeof(m_core));
253 
254 	m_core.device = this;
255 	m_core.program_ram = m_program_ram;
256 
257 	/* Call specific module inits */
258 	pcu_init(&m_core, this);
259 	agu_init();
260 	alu_init();
261 
262 	/* HACK - You're not in bootstrap mode upon bootup */
263 	m_core.bootstrap_mode = BOOTSTRAP_OFF;
264 
265 	/* Clear the irq states */
266 	m_core.modA_state = false;
267 	m_core.modB_state = false;
268 	m_core.modC_state = false;
269 	m_core.reset_state = false;
270 
271 	/* save states - dsp56156_core members */
272 	save_item(NAME(m_core.modA_state));
273 	save_item(NAME(m_core.modB_state));
274 	save_item(NAME(m_core.modC_state));
275 	save_item(NAME(m_core.reset_state));
276 	save_item(NAME(m_core.bootstrap_mode));
277 	save_item(NAME(m_core.repFlag));
278 	save_item(NAME(m_core.repAddr));
279 	save_item(NAME(m_core.ppc));
280 	save_item(NAME(m_core.op));
281 	save_item(NAME(m_core.interrupt_cycles));
282 
283 	/* save states - dsp56156_host_interface members */
284 	save_item(NAME(m_core.HI.icr));
285 	save_item(NAME(m_core.HI.cvr));
286 	save_item(NAME(m_core.HI.isr));
287 	save_item(NAME(m_core.HI.ivr));
288 	save_item(NAME(m_core.HI.trxh));
289 	save_item(NAME(m_core.HI.trxl));
290 	save_item(NAME(m_core.HI.bootstrap_offset));
291 
292 	save_item(NAME(m_core.peripheral_ram));
293 
294 	space(AS_PROGRAM).cache(m_core.cache);
295 	space(AS_PROGRAM).specific(m_core.program);
296 	space(AS_DATA).specific(m_core.data);
297 
298 	state_add(DSP56156_PC,     "PC", m_core.PCU.pc).formatstr("%04X");
299 	state_add(DSP56156_SR,     "SR", m_core.PCU.sr).formatstr("%04X");
300 	state_add(DSP56156_LC,     "LC", m_core.PCU.lc).formatstr("%04X");
301 	state_add(DSP56156_LA,     "LA", m_core.PCU.la).formatstr("%04X");
302 	state_add(DSP56156_SP,     "SP", m_core.PCU.sp).formatstr("%02X");
303 	state_add(DSP56156_OMR,    "OMR", m_core.PCU.omr).formatstr("%02X");
304 
305 	state_add(DSP56156_X,      "X", m_core.ALU.x.d).mask(0xffffffff).formatstr("%9s");
306 	state_add(DSP56156_Y,      "Y", m_core.ALU.y.d).mask(0xffffffff).formatstr("%9s");
307 
308 	state_add(DSP56156_A,      "A", m_core.ALU.a.q).mask(u64(0xffffffffffffffffU)).formatstr("%12s"); /* could benefit from a better mask? */
309 	state_add(DSP56156_B,      "B", m_core.ALU.b.q).mask(u64(0xffffffffffffffffU)).formatstr("%12s"); /* could benefit from a better mask? */
310 
311 	state_add(DSP56156_R0,     "R0", m_core.AGU.r0).formatstr("%04X");
312 	state_add(DSP56156_R1,     "R1", m_core.AGU.r1).formatstr("%04X");
313 	state_add(DSP56156_R2,     "R2", m_core.AGU.r2).formatstr("%04X");
314 	state_add(DSP56156_R3,     "R3", m_core.AGU.r3).formatstr("%04X");
315 
316 	state_add(DSP56156_N0,     "N0", m_core.AGU.n0).formatstr("%04X");
317 	state_add(DSP56156_N1,     "N1", m_core.AGU.n1).formatstr("%04X");
318 	state_add(DSP56156_N2,     "N2", m_core.AGU.n2).formatstr("%04X");
319 	state_add(DSP56156_N3,     "N3", m_core.AGU.n3).formatstr("%04X");
320 
321 	state_add(DSP56156_M0,     "M0", m_core.AGU.m0).formatstr("%04X");
322 	state_add(DSP56156_M1,     "M1", m_core.AGU.m1).formatstr("%04X");
323 	state_add(DSP56156_M2,     "M2", m_core.AGU.m2).formatstr("%04X");
324 	state_add(DSP56156_M3,     "M3", m_core.AGU.m3).formatstr("%04X");
325 
326 	state_add(DSP56156_TEMP,   "TMP", m_core.AGU.temp).formatstr("%04X").noshow();
327 	//state_add(DSP56156_STATUS, "STS", STATUS).formatstr("%02X");
328 
329 	state_add(DSP56156_ST0,    "ST0", m_core.PCU.ss[0].d).formatstr("%08X");
330 	state_add(DSP56156_ST1,    "ST1", m_core.PCU.ss[1].d).formatstr("%08X");
331 	state_add(DSP56156_ST2,    "ST2", m_core.PCU.ss[2].d).formatstr("%08X");
332 	state_add(DSP56156_ST3,    "ST3", m_core.PCU.ss[3].d).formatstr("%08X");
333 	state_add(DSP56156_ST4,    "ST4", m_core.PCU.ss[4].d).formatstr("%08X");
334 	state_add(DSP56156_ST5,    "ST5", m_core.PCU.ss[5].d).formatstr("%08X");
335 	state_add(DSP56156_ST6,    "ST6", m_core.PCU.ss[6].d).formatstr("%08X");
336 	state_add(DSP56156_ST7,    "ST7", m_core.PCU.ss[7].d).formatstr("%08X");
337 	state_add(DSP56156_ST8,    "ST8", m_core.PCU.ss[8].d).formatstr("%08X");
338 	state_add(DSP56156_ST9,    "ST9", m_core.PCU.ss[9].d).formatstr("%08X");
339 	state_add(DSP56156_ST10,   "ST10", m_core.PCU.ss[10].d).formatstr("%08X");
340 	state_add(DSP56156_ST11,   "ST11", m_core.PCU.ss[11].d).formatstr("%08X");
341 	state_add(DSP56156_ST12,   "ST12", m_core.PCU.ss[12].d).formatstr("%08X");
342 	state_add(DSP56156_ST13,   "ST13", m_core.PCU.ss[13].d).formatstr("%08X");
343 	state_add(DSP56156_ST14,   "ST14", m_core.PCU.ss[14].d).formatstr("%08X");
344 	state_add(DSP56156_ST15,   "ST15", m_core.PCU.ss[15].d).formatstr("%08X");
345 
346 	state_add(STATE_GENPC, "GENPC", m_core.PCU.pc).noshow();
347 	state_add(STATE_GENPCBASE, "CURPC", m_core.ppc).noshow();
348 	state_add(STATE_GENSP, "GENSP", m_core.PCU.sp).noshow();
349 	state_add(STATE_GENFLAGS, "GENFLAGS", m_core.PCU.sr).formatstr("%14s").noshow();
350 
351 	set_icountptr(m_core.icount);
352 }
353 
354 
state_string_export(const device_state_entry & entry,std::string & str) const355 void dsp56156_device::state_string_export(const device_state_entry &entry, std::string &str) const
356 {
357 	const dsp56156_core *cpustate = &m_core;
358 
359 	switch (entry.index())
360 	{
361 		case STATE_GENFLAGS:
362 			str = string_format("%s%s %s%s%s%s%s%s%s%s %s%s",
363 				/* Status Register */
364 				LF_bit(cpustate) ? "L" : ".",
365 				FV_bit(cpustate) ? "F" : ".",
366 
367 				S_bit(cpustate) ? "S" : ".",
368 				L_bit(cpustate) ? "L" : ".",
369 				E_bit(cpustate) ? "E" : ".",
370 				U_bit(cpustate) ? "U" : ".",
371 				N_bit(cpustate) ? "N" : ".",
372 				Z_bit(cpustate) ? "Z" : ".",
373 				V_bit(cpustate) ? "V" : ".",
374 				C_bit(cpustate) ? "C" : ".",
375 
376 				/* Stack Pointer */
377 				UF_bit(cpustate) ? "U" : ".",
378 				SE_bit(cpustate) ? "S" : ".");
379 			break;
380 
381 		case DSP56156_X:
382 			str = string_format("%04x %04x", X1, X0);
383 			break;
384 
385 		case DSP56156_Y:
386 			str = string_format("%04x %04x", Y1, Y0);
387 			break;
388 
389 		case DSP56156_A:
390 			str = string_format("%02x %04x %04x", A2, A1, A0);
391 			break;
392 
393 		case DSP56156_B:
394 			str = string_format("%02x %04x %04x", B2, B1, B0);
395 			break;
396 	}
397 }
398 
399 /***************************************************************************
400     RESET BEHAVIOR
401 ***************************************************************************/
agu_reset(dsp56156_core * cpustate)402 static void agu_reset(dsp56156_core* cpustate)
403 {
404 	/* FM.4-3 */
405 	R0 = 0x0000;
406 	R1 = 0x0000;
407 	R2 = 0x0000;
408 	R3 = 0x0000;
409 
410 	N0 = 0x0000;
411 	N1 = 0x0000;
412 	N2 = 0x0000;
413 	N3 = 0x0000;
414 
415 	M0 = 0xffff;
416 	M1 = 0xffff;
417 	M2 = 0xffff;
418 	M3 = 0xffff;
419 
420 	TEMP = 0x0000;
421 }
422 
alu_reset(dsp56156_core * cpustate)423 static void alu_reset(dsp56156_core* cpustate)
424 {
425 	X = 0x00000000;
426 	Y = 0x00000000;
427 	A = 0x0000000000;
428 	B = 0x0000000000;
429 }
430 
device_reset()431 void dsp56156_device::device_reset()
432 {
433 	logerror("DSP56156 reset\n");
434 
435 	m_core.interrupt_cycles = 0;
436 
437 	m_core.repFlag = 0;
438 	m_core.repAddr = 0x0000;
439 
440 	pcu_reset(&m_core);
441 	mem_reset(&m_core);
442 	agu_reset(&m_core);
443 	alu_reset(&m_core);
444 
445 	m_core.ppc = m_core.PCU.pc;
446 
447 	/* HACK - Put a jump to 0x0000 at 0x0000 - this keeps the CPU locked to the instruction at address 0x0000 */
448 	m_core.program.write_word(0x0000, 0x0124);
449 }
450 
451 
452 
453 /***************************************************************************
454     CORE INCLUDE
455 ***************************************************************************/
456 #include "dsp56ops.hxx"
457 
458 
459 /***************************************************************************
460     CORE EXECUTION LOOP
461 ***************************************************************************/
462 // Execute a single opcode and return how many cycles it took.
execute_one_new(dsp56156_core * cpustate)463 static size_t execute_one_new(dsp56156_core* cpustate)
464 {
465 	// For MAME
466 	cpustate->ppc = PC;
467 	if (cpustate->device->machine().debug_flags & DEBUG_FLAG_CALL_HOOK) // FIXME: if this was a member, the helper would work
468 		cpustate->device->debug()->instruction_hook(PC);
469 
470 	cpustate->op = ROPCODE(PC);
471 	uint16_t w0 = ROPCODE(PC);
472 	uint16_t w1 = ROPCODE(PC + 1);
473 
474 	Opcode op(w0, w1);
475 	op.evaluate(cpustate);
476 	PC += op.evalSize();    // Special size function needed to handle jmps, etc.
477 
478 	// TODO: Currently all operations take up 4 cycles (inst->cycles()).
479 	return 4;
480 }
481 
execute_run()482 void dsp56156_device::execute_run()
483 {
484 	/* If reset line is asserted, do nothing */
485 	if (m_core.reset_state)
486 	{
487 		m_core.icount = 0;
488 		return;
489 	}
490 
491 	/* HACK - if you're in bootstrap mode, simply pretend you ate up all your cycles waiting for data. */
492 	if (m_core.bootstrap_mode != BOOTSTRAP_OFF)
493 	{
494 		m_core.icount = 0;
495 		return;
496 	}
497 
498 	//m_core.icount -= m_core.interrupt_cycles;
499 	//m_core.interrupt_cycles = 0;
500 
501 	while(m_core.icount > 0)
502 	{
503 		execute_one(&m_core);
504 		if (0) m_core.icount -= execute_one_new(&m_core);
505 		pcu_service_interrupts(&m_core);   // TODO: Is it incorrect to service after each instruction?
506 	}
507 }
508 
509 
create_disassembler()510 std::unique_ptr<util::disasm_interface> dsp56156_device::create_disassembler()
511 {
512 	return std::make_unique<dsp56156_disassembler>();
513 }
514 
515 } // namespace DSP_56156
516