1 // license:BSD-3-Clause
2 // copyright-holders:F. Ulivi
3 
4 // I found 2 undocumented instructions in 5061-3001. First I noticed that PPU processor in
5 // hp9845b emulator executed 2 unknown instructions at each keyboard interrupt whose opcodes
6 // were 0x7026 & 0x7027.
7 // I searched for a while for any kind of documentation about them but found nothing at all.
8 // Some time later I found the mnemonics in the binary dump of assembly development option ROM:
9 // CIM & SIM, respectively. From the mnemonic I deduced their function: Clear & Set Interrupt Mode.
10 // After a few experiments, crashes, etc. here's my opinion on their purpose.
11 // When the CPU receives an interrupt, its AEC registers can be in any state so it could
12 // be impossible to properly save state, fetch the interrupt vector and start executing the ISR.
13 // The solution is having an hidden "interrupt mode" flag that gets set when an interrupt (either
14 // low or high priority) is acknowledged and is cleared when the "ret 0,p" instruction that ends
15 // the ISR is executed. The effects of having the interrupt mode set are:
16 // * No interrupts are recognized
17 // * A few essential AEC registers are overridden to establish a "safe" environment to save state
18 // and execute ISR (see hp_5061_3001_cpu_device::add_mae).
19 // Inside the ISR, CIM & SIM instructions can be used to change the interrupt mode and switch
20 // between normal & overridden settings of AEC.
21 // As an example of CIM&SIM usage, we can have a look at the keyboard ISR in 9845B PPU processor:
22 // * A key is pressed and IRQ 0 is set
23 // * Interrupt 0 is recognized, IM is set
24 // * R register is used to save program counter in block = 1 (overriding any R36 value)
25 // * Vector is fetched and execution begins in block 5 (overriding R33 value)
26 // * Registers are saved to RAM (again in overridden block 1)
27 // * AEC registers are set to correct value for ISR execution
28 // * CIM is used to exit the special behaviour of AEC and to allow high-priority interrupts
29 // * Useful ISR processing is done
30 // * SIM is used to re-enter special behaviour of AEC and to block any interrupt
31 // * State is restored (including all AEC registers)
32 // * RET 0,P is executed to end ISR: return program counter is popped off the stack and IM is cleared
33 
34 #include "emu.h"
35 #include "hphybrid.h"
36 #include "hphybrid_dasm.h"
37 #include "debugger.h"
38 
39 #include "hphybrid_defs.h"
40 
41 
42 enum {
43 	HPHYBRID_A,
44 	HPHYBRID_B,
45 	HPHYBRID_C,
46 	HPHYBRID_D,
47 	HPHYBRID_P,
48 	HPHYBRID_R,
49 	HPHYBRID_IV,
50 	HPHYBRID_PA,
51 	HPHYBRID_DMAPA,
52 	HPHYBRID_DMAMA,
53 	HPHYBRID_DMAC,
54 	HPHYBRID_I,
55 	HPHYBRID_W,
56 	HPHYBRID_AR2,
57 	HPHYBRID_AR2_2,
58 	HPHYBRID_AR2_3,
59 	HPHYBRID_AR2_4,
60 	HPHYBRID_SE,
61 	HPHYBRID_R25,
62 	HPHYBRID_R26,
63 	HPHYBRID_R27,
64 	HPHYBRID_R32,
65 	HPHYBRID_R33,
66 	HPHYBRID_R34,
67 	HPHYBRID_R35,
68 	HPHYBRID_R36,
69 	HPHYBRID_R37
70 };
71 
72 // Bit manipulation
73 namespace {
BIT_MASK(unsigned n)74 	template<typename T> constexpr T BIT_MASK(unsigned n)
75 	{
76 		return (T)1U << n;
77 	}
78 
BIT_CLR(T & w,unsigned n)79 	template<typename T> void BIT_CLR(T& w , unsigned n)
80 	{
81 		w &= ~BIT_MASK<T>(n);
82 	}
83 
BIT_SET(T & w,unsigned n)84 	template<typename T> void BIT_SET(T& w , unsigned n)
85 	{
86 		w |= BIT_MASK<T>(n);
87 	}
88 }
89 
90 // Bits in m_flags
91 enum : unsigned {
92 	HPHYBRID_C_BIT       = 0,   // Carry/extend
93 	HPHYBRID_O_BIT       = 1,   // Overflow
94 	HPHYBRID_CB_BIT      = 2,   // Cb
95 	HPHYBRID_DB_BIT      = 3,   // Db
96 	HPHYBRID_INTEN_BIT   = 4,   // Interrupt enable
97 	HPHYBRID_DMAEN_BIT   = 5,   // DMA enable
98 	HPHYBRID_DMADIR_BIT  = 6,   // DMA direction (1 = OUT)
99 	HPHYBRID_HALT_BIT    = 7,   // Halt flag
100 	HPHYBRID_IRH_BIT     = 8,   // IRH requested
101 	HPHYBRID_IRL_BIT     = 9,   // IRL requested
102 	HPHYBRID_IRH_SVC_BIT = 10,  // IRH in service
103 	HPHYBRID_IRL_SVC_BIT = 11,  // IRL in service
104 	HPHYBRID_DMAR_BIT    = 12,  // DMA request
105 	HPHYBRID_STS_BIT     = 13,  // Status flag
106 	HPHYBRID_FLG_BIT     = 14,  // "Flag" flag
107 	HPHYBRID_DC_BIT      = 15,  // Decimal carry
108 	HPHYBRID_IM_BIT      = 16   // Interrupt mode
109 };
110 
111 constexpr uint16_t HP_REG_IV_MASK = 0xfff0; // IV mask
112 constexpr uint16_t HP_REG_PA_MASK = 0x000f; // PA mask
113 constexpr uint16_t HP_REG_SE_MASK = 0x000f; // SE mask
114 
115 #define CURRENT_PA      (m_reg_PA[ 0 ])
116 
117 constexpr uint16_t HP_RESET_ADDR    = 0x0020;
118 
119 // Part of r32-r37 that is actually output as address extension (6 bits of "BSC": block select code)
120 constexpr uint16_t BSC_REG_MASK = 0x3f;
121 
122 // Address mask of 15-bit processor
123 constexpr uint16_t ADDR_MASK_15BIT = 0x7fff;
124 
125 // Mask of MSB of registers
126 constexpr uint16_t REG_MSB_MASK = BIT_MASK<uint16_t>(15);
127 
128 // Memory, I/O & register access timings
129 constexpr unsigned DEF_MEM_R_CYCLES = 4;    // Default memory read cycles
130 constexpr unsigned DEF_MEM_W_CYCLES = 4;    // Default memory write cycles
131 constexpr unsigned REGISTER_RW_CYCLES = 5;  // Internal register R/W cycles
132 constexpr unsigned IO_RW_CYCLES = 7;        // I/O R/W cycles
133 
134 DEFINE_DEVICE_TYPE(HP_5061_3001, hp_5061_3001_cpu_device, "5061_3001", "Hewlett-Packard HP-5061-3001")
135 DEFINE_DEVICE_TYPE(HP_5061_3011, hp_5061_3011_cpu_device, "5061_3011", "Hewlett-Packard HP-5061-3011")
136 DEFINE_DEVICE_TYPE(HP_09825_67907, hp_09825_67907_cpu_device, "09825_67907", "Hewlett-Packard HP-09825-67907")
137 
WRITE_LINE_MEMBER(hp_hybrid_cpu_device::dmar_w)138 WRITE_LINE_MEMBER(hp_hybrid_cpu_device::dmar_w)
139 {
140 	if (state)
141 		BIT_SET(m_flags, HPHYBRID_DMAR_BIT);
142 	else
143 		BIT_CLR(m_flags, HPHYBRID_DMAR_BIT);
144 }
145 
WRITE_LINE_MEMBER(hp_hybrid_cpu_device::halt_w)146 WRITE_LINE_MEMBER(hp_hybrid_cpu_device::halt_w)
147 {
148 	if (state)
149 		BIT_SET(m_flags, HPHYBRID_HALT_BIT);
150 	else
151 		BIT_CLR(m_flags, HPHYBRID_HALT_BIT);
152 }
153 
WRITE_LINE_MEMBER(hp_hybrid_cpu_device::status_w)154 WRITE_LINE_MEMBER(hp_hybrid_cpu_device::status_w)
155 {
156 	if (state)
157 		BIT_SET(m_flags, HPHYBRID_STS_BIT);
158 	else
159 		BIT_CLR(m_flags, HPHYBRID_STS_BIT);
160 }
161 
WRITE_LINE_MEMBER(hp_hybrid_cpu_device::flag_w)162 WRITE_LINE_MEMBER(hp_hybrid_cpu_device::flag_w)
163 {
164 	if (state)
165 		BIT_SET(m_flags, HPHYBRID_FLG_BIT);
166 	else
167 		BIT_CLR(m_flags, HPHYBRID_FLG_BIT);
168 }
169 
pa_r() const170 uint8_t hp_hybrid_cpu_device::pa_r() const
171 {
172 	return CURRENT_PA;
173 }
174 
hp_hybrid_cpu_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,uint8_t addrwidth)175 hp_hybrid_cpu_device::hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t addrwidth)
176 	: cpu_device(mconfig, type, tag, owner, clock)
177 	, m_pa_changed_func(*this)
178 	, m_opcode_func(*this)
179 	, m_stm_func(*this)
180 	, m_int_func(*this)
181 	, m_addr_mask((1U << addrwidth) - 1)
182 	, m_relative_mode(true)
183 	, m_r_cycles(DEF_MEM_R_CYCLES)
184 	, m_w_cycles(DEF_MEM_W_CYCLES)
185 	, m_boot_mode(false)
186 	, m_program_config("program", ENDIANNESS_BIG, 16, addrwidth, -1)
187 	, m_io_config("io", ENDIANNESS_BIG, 16, 6, -1)
188 {
189 	m_addr_mask_low16 = uint16_t(m_addr_mask & 0xffff);
190 }
191 
memory_space_config() const192 device_memory_interface::space_config_vector hp_hybrid_cpu_device::memory_space_config() const
193 {
194 	return space_config_vector {
195 		std::make_pair(AS_PROGRAM, &m_program_config),
196 		std::make_pair(AS_IO,      &m_io_config)
197 	};
198 }
199 
device_start()200 void hp_hybrid_cpu_device::device_start()
201 {
202 	{
203 		state_add(HPHYBRID_A,      "A",        m_reg_A);
204 		state_add(HPHYBRID_B,      "B",        m_reg_B);
205 		state_add(HPHYBRID_C,      "C",        m_reg_C);
206 		state_add(HPHYBRID_D,      "D",        m_reg_D);
207 		state_add(HPHYBRID_P,      "P",        m_reg_P);
208 		state_add(STATE_GENPC,     "GENPC",    m_genpc).noshow();
209 		state_add(STATE_GENPCBASE, "CURPC",    m_genpc).noshow();
210 		state_add(HPHYBRID_R,      "R",        m_reg_R);
211 		state_add(STATE_GENSP,     "GENSP",    m_reg_R).noshow();
212 		state_add(HPHYBRID_IV,     "IV",       m_reg_IV);
213 		state_add(HPHYBRID_PA,     "PA",       m_reg_PA[ 0 ]);
214 		state_add(HPHYBRID_W,      "W",        m_reg_W).noshow();
215 		state_add(STATE_GENFLAGS,  "GENFLAGS", m_flags).noshow().formatstr("%12s");
216 		state_add(HPHYBRID_DMAPA,  "DMAPA",    m_dmapa).noshow();
217 		state_add(HPHYBRID_DMAMA,  "DMAMA",    m_dmama).noshow();
218 		state_add(HPHYBRID_DMAC,   "DMAC",     m_dmac).noshow();
219 		state_add(HPHYBRID_I,      "I",        m_reg_I).noshow();
220 	}
221 
222 	space(AS_PROGRAM).cache(m_cache);
223 	space(AS_PROGRAM).specific(m_program);
224 	space(AS_IO).specific(m_io);
225 
226 	save_item(NAME(m_reg_A));
227 	save_item(NAME(m_reg_B));
228 	save_item(NAME(m_reg_C));
229 	save_item(NAME(m_reg_D));
230 	save_item(NAME(m_reg_P));
231 	save_item(NAME(m_reg_R));
232 	save_item(NAME(m_reg_IV));
233 	save_item(NAME(m_reg_PA[0]));
234 	save_item(NAME(m_reg_PA[1]));
235 	save_item(NAME(m_reg_PA[2]));
236 	save_item(NAME(m_reg_W));
237 	save_item(NAME(m_flags));
238 	save_item(NAME(m_dmapa));
239 	save_item(NAME(m_dmama));
240 	save_item(NAME(m_dmac));
241 	save_item(NAME(m_reg_I));
242 	save_item(NAME(m_forced_bsc_25));
243 
244 	set_icountptr(m_icount);
245 
246 	m_pa_changed_func.resolve_safe();
247 	m_opcode_func.resolve_safe();
248 	m_stm_func.resolve();
249 	m_int_func.resolve_safe(0xff);
250 }
251 
device_reset()252 void hp_hybrid_cpu_device::device_reset()
253 {
254 	m_reg_A = 0;
255 	m_reg_B = 0;
256 	m_reg_P = HP_RESET_ADDR;
257 	m_reg_R = 0;
258 	m_reg_C = 0;
259 	m_reg_D = 0;
260 	m_reg_IV = 0;
261 	m_reg_PA[ 0 ] = 0;
262 	m_reg_PA[ 1 ] = 0;
263 	m_reg_PA[ 2 ] = 0;
264 	m_reg_W = 0;
265 	m_flags = 0;
266 	m_dmapa = 0;
267 	m_dmama = 0;
268 	m_dmac = 0;
269 	m_curr_cycle = 0;
270 	m_forced_bsc_25 = m_boot_mode;
271 
272 	m_last_pa = ~0;
273 	update_pa();
274 
275 	m_reg_I = fetch();
276 }
277 
execute_run()278 void hp_hybrid_cpu_device::execute_run()
279 {
280 	do {
281 		if (BIT(m_flags , HPHYBRID_DMAEN_BIT) && BIT(m_flags , HPHYBRID_DMAR_BIT)) {
282 			handle_dma();
283 		} else {
284 			debugger_instruction_hook(m_genpc);
285 
286 			m_reg_I = execute_one(m_reg_I);
287 
288 			// Check for interrupts
289 			check_for_interrupts();
290 		}
291 	} while (m_icount > 0);
292 }
293 
execute_set_input(int inputnum,int state)294 void hp_hybrid_cpu_device::execute_set_input(int inputnum, int state)
295 {
296 	if (inputnum < HPHYBRID_INT_LVLS) {
297 		if (state)
298 			BIT_SET(m_flags , HPHYBRID_IRH_BIT + inputnum);
299 		else
300 			BIT_CLR(m_flags , HPHYBRID_IRH_BIT + inputnum);
301 	}
302 }
303 
304 /**
305  * Execute 1 instruction
306  *
307  * @param opcode Opcode to be executed
308  *
309  * @return Next opcode to be executed
310  */
execute_one(uint16_t opcode)311 uint16_t hp_hybrid_cpu_device::execute_one(uint16_t opcode)
312 {
313 	if ((opcode & 0x7fe0) == 0x7000) {
314 		// EXE
315 		m_icount -= 2;
316 		uint16_t fetch_addr = opcode & 0x1f;
317 		if (BIT(opcode , 15)) {
318 			fetch_addr = get_indirect_target(fetch_addr);
319 		}
320 		// Indirect addressing in EXE instruction seems to use AEC case A instead of case C
321 		// (because it's an opcode fetch)
322 		return fetch_at(add_mae(AEC_CASE_A , fetch_addr));
323 	} else {
324 		uint16_t next_P;
325 		if (!execute_one_bpc(opcode , next_P) &&
326 			!execute_no_bpc(opcode , next_P)) {
327 			// Unrecognized instruction, make it a NOP
328 			logerror("hp_hybrid: unknown opcode %04x @ %06x\n" , opcode , m_genpc);
329 			next_P = m_reg_P + 1;
330 		}
331 		m_reg_P = next_P & m_addr_mask_low16;
332 		return fetch();
333 	}
334 }
335 
336 /**
337  * Execute 1 BPC instruction (except EXE)
338  *
339  * @param opcode Opcode to be executed (no EXE instructions)
340  * @param[out] next_pc new value of P register
341  *
342  * @return true iff instruction executed
343  */
execute_one_bpc(uint16_t opcode,uint16_t & next_pc)344 bool hp_hybrid_cpu_device::execute_one_bpc(uint16_t opcode , uint16_t& next_pc)
345 {
346 	uint32_t ea;
347 	uint16_t tmp;
348 
349 	switch (opcode & 0x7800) {
350 	case 0x0000:
351 		// LDA
352 		m_icount -= 1;
353 		m_reg_A = RM(get_ea(opcode));
354 		break;
355 
356 	case 0x0800:
357 		// LDB
358 		m_icount -= 1;
359 		m_reg_B = RM(get_ea(opcode));
360 		break;
361 
362 	case 0x1000:
363 		// CPA
364 		m_icount -= 4;
365 		if (m_reg_A != RM(get_ea(opcode))) {
366 			// Skip next instruction
367 			next_pc = m_reg_P + 2;
368 			return true;
369 		}
370 		break;
371 
372 	case 0x1800:
373 		// CPB
374 		m_icount -= 4;
375 		if (m_reg_B != RM(get_ea(opcode))) {
376 			// Skip next instruction
377 			next_pc = m_reg_P + 2;
378 			return true;
379 		}
380 		break;
381 
382 	case 0x2000:
383 		// ADA
384 		m_icount -= 1;
385 		do_add(m_reg_A , RM(get_ea(opcode)));
386 		break;
387 
388 	case 0x2800:
389 		// ADB
390 		m_icount -= 1;
391 		do_add(m_reg_B , RM(get_ea(opcode)));
392 		break;
393 
394 	case 0x3000:
395 		// STA
396 		m_icount -= 1;
397 		WM(get_ea(opcode) , m_reg_A);
398 		break;
399 
400 	case 0x3800:
401 		// STB
402 		m_icount -= 1;
403 		WM(get_ea(opcode) , m_reg_B);
404 		break;
405 
406 	case 0x4000:
407 		// JSM
408 		m_icount -= 5;
409 		next_pc = remove_mae(get_ea(opcode));
410 		m_reg_R = (m_reg_R + 1) & m_addr_mask_low16;
411 		WM(AEC_CASE_C , m_reg_R , m_reg_P);
412 		return true;
413 
414 	case 0x4800:
415 		// ISZ
416 		m_icount -= 1;
417 		ea = get_ea(opcode);
418 		tmp = RM(ea) + 1;
419 		WM(ea , tmp);
420 		if (tmp == 0) {
421 			// Skip next instruction
422 			next_pc = m_reg_P + 2;
423 			return true;
424 		}
425 		break;
426 
427 	case 0x5000:
428 		// AND
429 		m_icount -= 1;
430 		m_reg_A &= RM(get_ea(opcode));
431 		break;
432 
433 	case 0x5800:
434 		// DSZ
435 		m_icount -= 1;
436 		ea = get_ea(opcode);
437 		tmp = RM(ea) - 1;
438 		WM(ea , tmp);
439 		if (tmp == 0) {
440 			// Skip next instruction
441 			next_pc = m_reg_P + 2;
442 			return true;
443 		}
444 		break;
445 
446 	case 0x6000:
447 		// IOR
448 		m_icount -= 1;
449 		m_reg_A |= RM(get_ea(opcode));
450 		break;
451 
452 	case 0x6800:
453 		// JMP
454 		m_icount -= 2;
455 		next_pc = remove_mae(get_ea(opcode));
456 		return true;
457 
458 	default:
459 		switch (opcode & 0xfec0) {
460 		case 0x7400:
461 			// RZA
462 			// SZA
463 			m_icount -= 8;
464 			next_pc = get_skip_addr(opcode , m_reg_A == 0);
465 			return true;
466 
467 		case 0x7440:
468 			// RIA
469 			// SIA
470 			m_icount -= 8;
471 			next_pc = get_skip_addr(opcode , m_reg_A++ == 0);
472 			return true;
473 
474 		case 0x7480:
475 			// SFS
476 			// SFC
477 			m_icount -= 8;
478 			next_pc = get_skip_addr(opcode , !BIT(m_flags , HPHYBRID_FLG_BIT));
479 			return true;
480 
481 		case 0x74c0:
482 			// SDS
483 			// SDC
484 			m_icount -= 8;
485 			next_pc = get_skip_addr(opcode , !BIT(m_flags , HPHYBRID_DC_BIT));
486 			return true;
487 
488 		case 0x7C00:
489 			// RZB
490 			// SZB
491 			m_icount -= 8;
492 			next_pc = get_skip_addr(opcode , m_reg_B == 0);
493 			return true;
494 
495 		case 0x7C40:
496 			// RIB
497 			// SIB
498 			m_icount -= 8;
499 			next_pc = get_skip_addr(opcode , m_reg_B++ == 0);
500 			return true;
501 
502 		case 0x7c80:
503 			// SSS
504 			// SSC
505 			m_icount -= 8;
506 			next_pc = get_skip_addr(opcode , !BIT(m_flags , HPHYBRID_STS_BIT));
507 			return true;
508 
509 		case 0x7cc0:
510 			// SHS
511 			// SHC
512 			m_icount -= 8;
513 			next_pc = get_skip_addr(opcode , !BIT(m_flags , HPHYBRID_HALT_BIT));
514 			return true;
515 
516 		default:
517 			switch (opcode & 0xfe00) {
518 			case 0x7600:
519 				// SLA
520 				// RLA
521 				m_icount -= 8;
522 				next_pc = get_skip_addr_sc(opcode , m_reg_A , 0);
523 				return true;
524 
525 			case 0x7e00:
526 				// SLB
527 				// RLB
528 				m_icount -= 8;
529 				next_pc = get_skip_addr_sc(opcode , m_reg_B , 0);
530 				return true;
531 
532 			case 0xf400:
533 				// SAP
534 				// SAM
535 				m_icount -= 8;
536 				next_pc = get_skip_addr_sc(opcode , m_reg_A , 15);
537 				return true;
538 
539 			case 0xf600:
540 				// SOC
541 				// SOS
542 				m_icount -= 8;
543 				next_pc = get_skip_addr_sc(opcode , m_flags , HPHYBRID_O_BIT);
544 				return true;
545 
546 			case 0xfc00:
547 				// SBP
548 				// SBM
549 				m_icount -= 8;
550 				next_pc = get_skip_addr_sc(opcode , m_reg_B , 15);
551 				return true;
552 
553 			case 0xfe00:
554 				// SEC
555 				// SES
556 				m_icount -= 8;
557 				next_pc = get_skip_addr_sc(opcode , m_flags , HPHYBRID_C_BIT);
558 				return true;
559 
560 			default:
561 				switch (opcode & 0xfff0) {
562 				case 0xf100:
563 					// AAR
564 					tmp = (opcode & 0xf) + 1;
565 					m_icount -= (3 + tmp);
566 					// A shift by 16 positions is equivalent to a shift by 15
567 					tmp = tmp > 15 ? 15 : tmp;
568 					m_reg_A = ((m_reg_A ^ 0x8000) >> tmp) - (0x8000 >> tmp);
569 					break;
570 
571 				case 0xf900:
572 					// ABR
573 					tmp = (opcode & 0xf) + 1;
574 					m_icount -= (3 + tmp);
575 					tmp = tmp > 15 ? 15 : tmp;
576 					m_reg_B = ((m_reg_B ^ 0x8000) >> tmp) - (0x8000 >> tmp);
577 					break;
578 
579 				case 0xf140:
580 					// SAR
581 					tmp = (opcode & 0xf) + 1;
582 					m_icount -= (3 + tmp);
583 					m_reg_A >>= tmp;
584 					break;
585 
586 				case 0xf940:
587 					// SBR
588 					tmp = (opcode & 0xf) + 1;
589 					m_icount -= (3 + tmp);
590 					m_reg_B >>= tmp;
591 					break;
592 
593 				case 0xf180:
594 					// SAL
595 					tmp = (opcode & 0xf) + 1;
596 					m_icount -= (3 + tmp);
597 					m_reg_A <<= tmp;
598 					break;
599 
600 				case 0xf980:
601 					// SBL
602 					tmp = (opcode & 0xf) + 1;
603 					m_icount -= (3 + tmp);
604 					m_reg_B <<= tmp;
605 					break;
606 
607 				case 0xf1c0:
608 					// RAR
609 					tmp = (opcode & 0xf) + 1;
610 					m_icount -= (3 + tmp);
611 					m_reg_A = (m_reg_A >> tmp) | (m_reg_A << (16 - tmp));
612 					break;
613 
614 				case 0xf9c0:
615 					// RBR
616 					tmp = (opcode & 0xf) + 1;
617 					m_icount -= (3 + tmp);
618 					m_reg_B = (m_reg_B >> tmp) | (m_reg_B << (16 - tmp));
619 					break;
620 
621 				default:
622 					if ((opcode & 0xff80) == 0xf080) {
623 						// RET
624 						m_icount -= 4;
625 						if (BIT(opcode , 6)) {
626 							// Pop PA stack
627 							if (BIT(m_flags , HPHYBRID_IRH_SVC_BIT)) {
628 								BIT_CLR(m_flags , HPHYBRID_IRH_SVC_BIT);
629 								memmove(&m_reg_PA[ 0 ] , &m_reg_PA[ 1 ] , HPHYBRID_INT_LVLS);
630 								update_pa();
631 							} else if (BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
632 								BIT_CLR(m_flags , HPHYBRID_IRL_SVC_BIT);
633 								memmove(&m_reg_PA[ 0 ] , &m_reg_PA[ 1 ] , HPHYBRID_INT_LVLS);
634 								update_pa();
635 							}
636 						}
637 						tmp = RM(AEC_CASE_C , m_reg_R) + (opcode & 0x1f);
638 						m_reg_R = (m_reg_R - 1) & m_addr_mask_low16;
639 						if (BIT(opcode , 6)) {
640 							BIT_CLR(m_flags, HPHYBRID_IM_BIT);
641 						}
642 						next_pc = BIT(opcode , 5) ? tmp - 0x20 : tmp;
643 						return true;
644 					} else {
645 						switch (opcode) {
646 						case 0x7110:
647 							// EIR
648 							m_icount -= 6;
649 							BIT_SET(m_flags , HPHYBRID_INTEN_BIT);
650 							break;
651 
652 						case 0x7118:
653 							// DIR
654 							m_icount -= 6;
655 							BIT_CLR(m_flags , HPHYBRID_INTEN_BIT);
656 							break;
657 
658 						case 0x7120:
659 							// DMA
660 							m_icount -= 6;
661 							BIT_SET(m_flags , HPHYBRID_DMAEN_BIT);
662 							break;
663 
664 						case 0x7138:
665 							// DDR
666 							m_icount -= 6;
667 							BIT_CLR(m_flags , HPHYBRID_DMAEN_BIT);
668 							break;
669 
670 						case 0xf020:
671 							// TCA
672 							m_icount -= 3;
673 							m_reg_A = ~m_reg_A;
674 							do_add(m_reg_A , 1);
675 							break;
676 
677 						case 0xf060:
678 							// CMA
679 							m_icount -= 3;
680 							m_reg_A = ~m_reg_A;
681 							break;
682 
683 						case 0xf820:
684 							// TCB
685 							m_icount -= 3;
686 							m_reg_B = ~m_reg_B;
687 							do_add(m_reg_B , 1);
688 							break;
689 
690 						case 0xf860:
691 							// CMB
692 							m_icount -= 3;
693 							m_reg_B = ~m_reg_B;
694 							break;
695 
696 						default:
697 							// Unrecognized instruction: pass it on for further processing by other units
698 							return false;
699 						}
700 					}
701 				}
702 			}
703 		}
704 	}
705 
706 	next_pc = m_reg_P + 1;
707 	return true;
708 }
709 
emc_start()710 void hp_hybrid_cpu_device::emc_start()
711 {
712 	state_add(HPHYBRID_AR2, "Ar2" , m_reg_ar2[ 0 ]);
713 	state_add(HPHYBRID_AR2_2, "Ar2_2" , m_reg_ar2[ 1 ]);
714 	state_add(HPHYBRID_AR2_3, "Ar2_3" , m_reg_ar2[ 2 ]);
715 	state_add(HPHYBRID_AR2_4, "Ar2_4" , m_reg_ar2[ 3 ]);
716 	state_add(HPHYBRID_SE, "SE" , m_reg_se);
717 	state_add(HPHYBRID_R25, "R25" , m_reg_r25).noshow();
718 	state_add(HPHYBRID_R26, "R26" , m_reg_r26).noshow();
719 	state_add(HPHYBRID_R27, "R27" , m_reg_r27).noshow();
720 
721 	save_item(NAME(m_reg_ar2));
722 	save_item(NAME(m_reg_se));
723 	save_item(NAME(m_reg_r25));
724 	save_item(NAME(m_reg_r26));
725 	save_item(NAME(m_reg_r27));
726 }
727 
execute_emc(uint16_t opcode,uint16_t & next_pc)728 bool hp_hybrid_cpu_device::execute_emc(uint16_t opcode , uint16_t& next_pc)
729 {
730 	// EMC instructions
731 	uint8_t n;
732 	uint16_t tmp1;
733 	uint16_t tmp2;
734 	uint64_t tmp_ar;
735 	uint64_t tmp_ar2;
736 	bool carry;
737 
738 	switch (opcode & 0xfff0) {
739 	case 0x7300:
740 		// XFR
741 		tmp1 = m_reg_A;
742 		tmp2 = m_reg_B;
743 		n = (opcode & 0xf) + 1;
744 		m_icount -= 15;
745 		while (n--) {
746 			WM(AEC_CASE_C , tmp2 , RM(AEC_CASE_C , tmp1));
747 			tmp1++;
748 			tmp2++;
749 		}
750 		break;
751 
752 	case 0x7380:
753 		// CLR
754 		tmp1 = m_reg_A;
755 		n = (opcode & 0xf) + 1;
756 		m_icount -= 10;
757 		while (n--) {
758 			WM(AEC_CASE_C , tmp1 , 0);
759 			tmp1++;
760 		}
761 		break;
762 
763 	default:
764 		switch (opcode) {
765 		case 0x7200:
766 			// MWA
767 			m_icount -= 22;
768 			tmp_ar2 = get_ar2();
769 			carry = do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , m_reg_B);
770 			set_ar2(tmp_ar2);
771 			if (carry)
772 				BIT_SET(m_flags, HPHYBRID_DC_BIT);
773 			else
774 				BIT_CLR(m_flags, HPHYBRID_DC_BIT);
775 			break;
776 
777 		case 0x7220:
778 			// CMY
779 			m_icount -= 17;
780 			tmp_ar2 = get_ar2();
781 			tmp_ar2 = 0x999999999999ULL - tmp_ar2;
782 			do_dec_add(true , tmp_ar2 , 0);
783 			set_ar2(tmp_ar2);
784 			BIT_CLR(m_flags , HPHYBRID_DC_BIT);
785 			break;
786 
787 		case 0x7260:
788 			// CMX
789 			m_icount -= 17;
790 			tmp_ar = get_ar1();
791 			tmp_ar = 0x999999999999ULL - tmp_ar;
792 			do_dec_add(true , tmp_ar , 0);
793 			set_ar1(tmp_ar);
794 			BIT_CLR(m_flags , HPHYBRID_DC_BIT);
795 			break;
796 
797 		case 0x7280:
798 			// FXA
799 			m_icount -= 16;
800 			tmp_ar2 = get_ar2();
801 			carry = do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , get_ar1());
802 			set_ar2(tmp_ar2);
803 			if (carry)
804 				BIT_SET(m_flags, HPHYBRID_DC_BIT);
805 			else
806 				BIT_CLR(m_flags, HPHYBRID_DC_BIT);
807 			break;
808 
809 		case 0x7340:
810 			// NRM
811 			tmp_ar2 = get_ar2();
812 			m_icount -= 17;
813 			for (n = 0; n < 12 && (tmp_ar2 & 0xf00000000000ULL) == 0; n++) {
814 				do_dec_shift_l(0 , tmp_ar2);
815 				m_icount--;
816 			}
817 			m_reg_B = n;
818 			if (n < 12) {
819 				BIT_CLR(m_flags , HPHYBRID_DC_BIT);
820 				set_ar2(tmp_ar2);
821 			} else {
822 				BIT_SET(m_flags , HPHYBRID_DC_BIT);
823 				// When ar2 is 0, total time is 69 cycles
824 				// (salcazzo che cosa fa per altri 34 cicli)
825 				m_icount -= 34;
826 			}
827 			break;
828 
829 		case 0x73c0:
830 			// CDC
831 			m_icount -= 5;
832 			BIT_CLR(m_flags , HPHYBRID_DC_BIT);
833 			break;
834 
835 		case 0x7a00:
836 			// FMP
837 			m_icount -= 15;
838 			m_reg_A = 0;
839 			n = m_reg_B & 0xf;
840 			if (n == 0) {
841 				tmp_ar = 0;
842 			} else {
843 				m_icount -= 3;
844 				tmp_ar = get_ar1();
845 				n--;
846 			}
847 			tmp_ar2 = get_ar2();
848 			do {
849 				m_icount -= 13;
850 				if (do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , tmp_ar)) {
851 					m_reg_A++;
852 				}
853 				BIT_CLR(m_flags , HPHYBRID_DC_BIT);
854 			} while (n--);
855 			set_ar2(tmp_ar2);
856 			break;
857 
858 		case 0x7a21:
859 			// FDV
860 			// This instruction keeps adding AR1 to AR2 until an overflow occurs.
861 			// Register B will hold the number of iterations after the execution.
862 			// Note that if AR1 is 0 overflow never happens and the processor hangs.
863 			// Here we stop at 15 iterations (after all there are only 4 bits in the loop counter).
864 			m_icount -= 13;
865 			m_reg_B = 0;
866 			tmp_ar = get_ar1();
867 			tmp_ar2 = get_ar2();
868 			while (m_reg_B < 15 && !do_dec_add(BIT(m_flags , HPHYBRID_DC_BIT) , tmp_ar2 , tmp_ar)) {
869 				m_icount -= 13;
870 				BIT_CLR(m_flags , HPHYBRID_DC_BIT);
871 				m_reg_B++;
872 			}
873 			set_ar2(tmp_ar2);
874 			break;
875 
876 		case 0x7b00:
877 			// MRX
878 			// Cycle count is incorrect for the case where B=0, as AR1 doesn't get read or written in real hw
879 			set_ar1(do_mrxy(get_ar1()));
880 			m_icount -= 20;
881 			break;
882 
883 		case 0x7b21:
884 			// DRS
885 			tmp_ar = get_ar1();
886 			m_icount -= 14;
887 			m_reg_A = m_reg_se = do_dec_shift_r(0 , tmp_ar);
888 			set_ar1(tmp_ar);
889 			BIT_CLR(m_flags , HPHYBRID_DC_BIT);
890 			break;
891 
892 		case 0x7b40:
893 			// MRY
894 			set_ar2(do_mrxy(get_ar2()));
895 			m_icount -= 27;
896 			break;
897 
898 		case 0x7b61:
899 			// MLY
900 			tmp_ar2 = get_ar2();
901 			m_icount -= 26;
902 			m_reg_A = m_reg_se = do_dec_shift_l(m_reg_A & 0xf , tmp_ar2);
903 			set_ar2(tmp_ar2);
904 			BIT_CLR(m_flags , HPHYBRID_DC_BIT);
905 			break;
906 
907 		case 0x7b8f:
908 			// MPY
909 			do_mpy();
910 			break;
911 
912 		default:
913 			// Unrecognized instruction
914 			return false;
915 		}
916 	}
917 
918 	next_pc = m_reg_P + 1;
919 	return true;
920 }
921 
state_string_export(const device_state_entry & entry,std::string & str) const922 void hp_hybrid_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const
923 {
924 	if (entry.index() == STATE_GENFLAGS) {
925 		str = string_format("%s %s %s %c %c",
926 							BIT(m_flags , HPHYBRID_DB_BIT) ? "Db":"..",
927 							BIT(m_flags , HPHYBRID_CB_BIT) ? "Cb":"..",
928 							BIT(m_flags , HPHYBRID_DC_BIT) ? "DC":"..",
929 							BIT(m_flags , HPHYBRID_O_BIT) ? 'O':'.',
930 							BIT(m_flags , HPHYBRID_C_BIT) ? 'E':'.');
931 	}
932 }
933 
add_mae(aec_cases_t aec_case,uint16_t addr)934 uint32_t hp_hybrid_cpu_device::add_mae(aec_cases_t aec_case , uint16_t addr)
935 {
936 	// No MAE on 5061-3011 or 09825-67907
937 	return addr;
938 }
939 
remove_mae(uint32_t addr)940 uint16_t hp_hybrid_cpu_device::remove_mae(uint32_t addr)
941 {
942 	return uint16_t(addr & 0xffff);
943 }
944 
RM(aec_cases_t aec_case,uint16_t addr)945 uint16_t hp_hybrid_cpu_device::RM(aec_cases_t aec_case , uint16_t addr)
946 {
947 	return RM(add_mae(aec_case , addr));
948 }
949 
RM(uint32_t addr)950 uint16_t hp_hybrid_cpu_device::RM(uint32_t addr)
951 {
952 	addr &= m_addr_mask;
953 	uint16_t addr_wo_bsc = remove_mae(addr);
954 
955 	if (addr_wo_bsc <= HP_REG_LAST_ADDR) {
956 		// Any access to internal registers removes forcing of BSC 2x
957 		m_forced_bsc_25 = false;
958 
959 		if (m_stm_func) {
960 			m_stm_func(m_curr_cycle | CYCLE_RAL_MASK | CYCLE_RD_MASK);
961 			m_curr_cycle = 0;
962 		}
963 
964 		// Memory mapped BPC registers
965 		uint16_t tmp;
966 		switch (addr_wo_bsc) {
967 		case HP_REG_A_ADDR:
968 			tmp = m_reg_A;
969 			break;
970 
971 		case HP_REG_B_ADDR:
972 			tmp = m_reg_B;
973 			break;
974 
975 		case HP_REG_P_ADDR:
976 			tmp = m_reg_P;
977 			break;
978 
979 		case HP_REG_R_ADDR:
980 			tmp = m_reg_R;
981 			break;
982 
983 		case HP_REG_R4_ADDR:
984 		case HP_REG_R5_ADDR:
985 		case HP_REG_R6_ADDR:
986 		case HP_REG_R7_ADDR:
987 			return RIO(CURRENT_PA , addr_wo_bsc - HP_REG_R4_ADDR);
988 
989 		case HP_REG_IV_ADDR:
990 			tmp = m_reg_IV;
991 			break;
992 
993 		case HP_REG_PA_ADDR:
994 			tmp = CURRENT_PA;
995 			break;
996 
997 		case HP_REG_W_ADDR:
998 			tmp = m_reg_W;
999 			break;
1000 
1001 		case HP_REG_DMAMA_ADDR:
1002 			tmp = m_dmama;
1003 			break;
1004 
1005 		case HP_REG_DMAC_ADDR:
1006 			tmp = m_dmac;
1007 			break;
1008 
1009 		case HP_REG_C_ADDR:
1010 			tmp = m_reg_C;
1011 			break;
1012 
1013 		case HP_REG_D_ADDR:
1014 			tmp = m_reg_D;
1015 			break;
1016 
1017 		default:
1018 			if (!read_non_common_reg(addr_wo_bsc , tmp)) {
1019 				// Non-existing registers are returned as 0
1020 				tmp = 0;
1021 			}
1022 			break;
1023 		}
1024 		m_icount -= REGISTER_RW_CYCLES;
1025 		return tmp;
1026 	} else {
1027 		m_icount -= m_r_cycles;
1028 		if (m_stm_func) {
1029 			m_stm_func(m_curr_cycle | CYCLE_RD_MASK);
1030 			m_curr_cycle = 0;
1031 		}
1032 		return m_cache.read_word(addr);
1033 	}
1034 }
1035 
read_emc_reg(uint16_t addr,uint16_t & v)1036 bool hp_hybrid_cpu_device::read_emc_reg(uint16_t addr , uint16_t& v)
1037 {
1038 	switch (addr) {
1039 	case HP_REG_AR2_ADDR:
1040 	case HP_REG_AR2_ADDR + 1:
1041 	case HP_REG_AR2_ADDR + 2:
1042 	case HP_REG_AR2_ADDR + 3:
1043 		v = m_reg_ar2[ addr - HP_REG_AR2_ADDR ];
1044 		return true;
1045 
1046 	case HP_REG_SE_ADDR:
1047 		v = m_reg_se;
1048 		return true;
1049 
1050 	case HP_REG_R25_ADDR:
1051 		v = m_reg_r25;
1052 		return true;
1053 
1054 	case HP_REG_R26_ADDR:
1055 		v = m_reg_r26;
1056 		return true;
1057 
1058 	case HP_REG_R27_ADDR:
1059 		v = m_reg_r27;
1060 		return true;
1061 
1062 	default:
1063 		return false;
1064 	}
1065 }
1066 
WM(aec_cases_t aec_case,uint16_t addr,uint16_t v)1067 void hp_hybrid_cpu_device::WM(aec_cases_t aec_case , uint16_t addr , uint16_t v)
1068 {
1069 	WM(add_mae(aec_case , addr) , v);
1070 }
1071 
WM(uint32_t addr,uint16_t v)1072 void hp_hybrid_cpu_device::WM(uint32_t addr , uint16_t v)
1073 {
1074 	addr &= m_addr_mask;
1075 	uint16_t addr_wo_bsc = remove_mae(addr);
1076 
1077 	if (addr_wo_bsc <= HP_REG_LAST_ADDR) {
1078 		// Any access to internal registers removes forcing of BSC 2x
1079 		m_forced_bsc_25 = false;
1080 
1081 		if (m_stm_func) {
1082 			m_stm_func(m_curr_cycle | CYCLE_RAL_MASK | CYCLE_WR_MASK);
1083 			m_curr_cycle = 0;
1084 		}
1085 
1086 		// Memory mapped BPC registers
1087 		switch (addr_wo_bsc) {
1088 		case HP_REG_A_ADDR:
1089 			m_reg_A = v;
1090 			break;
1091 
1092 		case HP_REG_B_ADDR:
1093 			m_reg_B = v;
1094 			break;
1095 
1096 		case HP_REG_P_ADDR:
1097 			m_reg_P = v & m_addr_mask_low16;
1098 			break;
1099 
1100 		case HP_REG_R_ADDR:
1101 			m_reg_R = v & m_addr_mask_low16;
1102 			break;
1103 
1104 		case HP_REG_R4_ADDR:
1105 		case HP_REG_R5_ADDR:
1106 		case HP_REG_R6_ADDR:
1107 		case HP_REG_R7_ADDR:
1108 			WIO(CURRENT_PA , addr_wo_bsc - HP_REG_R4_ADDR , v);
1109 			return;
1110 
1111 		case HP_REG_IV_ADDR:
1112 			m_reg_IV = v & HP_REG_IV_MASK;
1113 			break;
1114 
1115 		case HP_REG_PA_ADDR:
1116 			CURRENT_PA = v & HP_REG_PA_MASK;
1117 			update_pa();
1118 			break;
1119 
1120 		case HP_REG_W_ADDR:
1121 			m_reg_W = v;
1122 			break;
1123 
1124 		case HP_REG_DMAPA_ADDR:
1125 			m_dmapa = v & HP_REG_PA_MASK;
1126 			break;
1127 
1128 		case HP_REG_DMAMA_ADDR:
1129 			m_dmama = v;
1130 			break;
1131 
1132 		case HP_REG_DMAC_ADDR:
1133 			m_dmac = v;
1134 			break;
1135 
1136 		case HP_REG_C_ADDR:
1137 			m_reg_C = v;
1138 			break;
1139 
1140 		case HP_REG_D_ADDR:
1141 			m_reg_D = v;
1142 			break;
1143 
1144 		default:
1145 			write_non_common_reg(addr_wo_bsc , v);
1146 			break;
1147 		}
1148 		m_icount -= REGISTER_RW_CYCLES;
1149 	} else {
1150 		m_icount -= m_w_cycles;
1151 		if (m_stm_func) {
1152 			m_stm_func(m_curr_cycle | CYCLE_WR_MASK);
1153 			m_curr_cycle = 0;
1154 		}
1155 		m_program.write_word(addr , v);
1156 	}
1157 }
1158 
write_emc_reg(uint16_t addr,uint16_t v)1159 bool hp_hybrid_cpu_device::write_emc_reg(uint16_t addr , uint16_t v)
1160 {
1161 	switch (addr) {
1162 	case HP_REG_AR2_ADDR:
1163 	case HP_REG_AR2_ADDR + 1:
1164 	case HP_REG_AR2_ADDR + 2:
1165 	case HP_REG_AR2_ADDR + 3:
1166 		m_reg_ar2[ addr - HP_REG_AR2_ADDR ] = v;
1167 		return true;
1168 
1169 	case HP_REG_SE_ADDR:
1170 		m_reg_se = v & HP_REG_SE_MASK;
1171 		return true;
1172 
1173 	case HP_REG_R25_ADDR:
1174 		m_reg_r25 = v;
1175 		return true;
1176 
1177 	case HP_REG_R26_ADDR:
1178 		m_reg_r26 = v;
1179 		return true;
1180 
1181 	case HP_REG_R27_ADDR:
1182 		m_reg_r27 = v;
1183 		return true;
1184 
1185 	default:
1186 		return false;
1187 	}
1188 }
1189 
fetch()1190 uint16_t hp_hybrid_cpu_device::fetch()
1191 {
1192 	m_genpc = add_mae(AEC_CASE_A , m_reg_P);
1193 	return fetch_at(m_genpc);
1194 }
1195 
fetch_at(uint32_t addr)1196 uint16_t hp_hybrid_cpu_device::fetch_at(uint32_t addr)
1197 {
1198 	m_curr_cycle |= CYCLE_IFETCH_MASK;
1199 	uint16_t opcode = RM(addr);
1200 	m_opcode_func(opcode);
1201 	return opcode;
1202 }
1203 
get_indirect_target(uint32_t addr)1204 uint16_t hp_hybrid_cpu_device::get_indirect_target(uint32_t addr)
1205 {
1206 	// Single-level indirect addressing on 5061-3011 or 5061-3001
1207 	return RM(addr);
1208 }
1209 
get_ea(uint16_t opcode)1210 uint32_t hp_hybrid_cpu_device::get_ea(uint16_t opcode)
1211 {
1212 	uint16_t base;
1213 	uint16_t off;
1214 	aec_cases_t aec;
1215 
1216 	if (BIT(opcode , 10)) {
1217 		if (m_relative_mode) {
1218 			// Current page relative addressing
1219 			base = m_reg_P;
1220 		} else {
1221 			// Current page absolute addressing
1222 			base = (m_reg_P & 0xfc00) | 0x0200;
1223 		}
1224 		aec = AEC_CASE_A;
1225 	} else {
1226 		// Base page
1227 		base = 0;
1228 		aec = AEC_CASE_B;
1229 	}
1230 
1231 	off = opcode & 0x3ff;
1232 	if (off & 0x200) {
1233 		off -= 0x400;
1234 	}
1235 
1236 	base += off;
1237 	uint32_t ea = add_mae(aec , base);
1238 
1239 	if (BIT(opcode , 15)) {
1240 		// Indirect addressing
1241 		return add_mae(AEC_CASE_C , get_indirect_target(ea));
1242 	} else {
1243 		// Direct addressing
1244 		return ea;
1245 	}
1246 }
1247 
do_add(uint16_t & addend1,uint16_t addend2)1248 void hp_hybrid_cpu_device::do_add(uint16_t& addend1 , uint16_t addend2)
1249 {
1250 	uint32_t tmp = addend1 + addend2;
1251 
1252 	if (BIT(tmp , 16)) {
1253 		// Carry
1254 		BIT_SET(m_flags , HPHYBRID_C_BIT);
1255 	}
1256 
1257 	if (BIT((tmp ^ addend1) & (tmp ^ addend2) , 15)) {
1258 		// Overflow
1259 		BIT_SET(m_flags , HPHYBRID_O_BIT);
1260 	}
1261 
1262 	addend1 = uint16_t(tmp);
1263 }
1264 
get_skip_addr(uint16_t opcode,bool condition) const1265 uint16_t hp_hybrid_cpu_device::get_skip_addr(uint16_t opcode , bool condition) const
1266 {
1267 	bool skip_val = BIT(opcode , 8) != 0;
1268 
1269 	if (condition == skip_val) {
1270 		uint16_t off = opcode & 0x1f;
1271 
1272 		if (BIT(opcode , 5)) {
1273 			off -= 0x20;
1274 		}
1275 		return m_reg_P + off;
1276 	} else {
1277 		return m_reg_P + 1;
1278 	}
1279 }
1280 
get_skip_addr_sc(uint16_t opcode,T & v,unsigned n)1281 template<typename T> uint16_t hp_hybrid_cpu_device::get_skip_addr_sc(uint16_t opcode , T& v , unsigned n)
1282 {
1283 	bool val = BIT(v , n);
1284 
1285 	if (BIT(opcode , 7)) {
1286 		if (BIT(opcode , 6)) {
1287 			BIT_SET(v , n);
1288 		} else {
1289 			BIT_CLR(v , n);
1290 		}
1291 	}
1292 
1293 	return get_skip_addr(opcode , val);
1294 }
1295 
update_pa()1296 void hp_hybrid_cpu_device::update_pa()
1297 {
1298 	if (CURRENT_PA != m_last_pa) {
1299 		m_last_pa = CURRENT_PA;
1300 		m_pa_changed_func(m_last_pa);
1301 	}
1302 }
1303 
check_for_interrupts()1304 void hp_hybrid_cpu_device::check_for_interrupts()
1305 {
1306 	if (!BIT(m_flags , HPHYBRID_INTEN_BIT) || BIT(m_flags , HPHYBRID_IRH_SVC_BIT) || BIT(m_flags , HPHYBRID_IM_BIT)) {
1307 		return;
1308 	}
1309 
1310 	int irqline;
1311 
1312 	if (BIT(m_flags , HPHYBRID_IRH_BIT)) {
1313 		// Service high-level interrupt
1314 		BIT_SET(m_flags , HPHYBRID_IRH_SVC_BIT);
1315 		irqline = HPHYBRID_IRH;
1316 		if (BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
1317 			logerror("H pre-empted L @ %06x\n" , m_genpc);
1318 		}
1319 	} else if (BIT(m_flags , HPHYBRID_IRL_BIT) && !BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
1320 		// Service low-level interrupt
1321 		BIT_SET(m_flags , HPHYBRID_IRL_SVC_BIT);
1322 		irqline = HPHYBRID_IRL;
1323 	} else {
1324 		return;
1325 	}
1326 
1327 	standard_irq_callback(irqline);
1328 
1329 	// Get interrupt vector in low byte (level is available on PA3)
1330 	uint8_t vector = m_int_func(BIT(m_flags , HPHYBRID_IRH_BIT) ? 1 : 0);
1331 	uint8_t new_PA;
1332 
1333 	// Get highest numbered 1
1334 	// Don't know what happens if vector is 0, here we assume bit 7 = 1
1335 	if (vector == 0) {
1336 		new_PA = 7;
1337 	} else {
1338 		for (new_PA = 7; new_PA && !BIT(vector , 7); new_PA--, vector <<= 1) {
1339 		}
1340 	}
1341 	if (irqline == HPHYBRID_IRH) {
1342 		BIT_SET(new_PA , 3);
1343 	}
1344 
1345 	// Push PA stack
1346 	memmove(&m_reg_PA[ 1 ] , &m_reg_PA[ 0 ] , HPHYBRID_INT_LVLS);
1347 
1348 	CURRENT_PA = new_PA;
1349 	update_pa();
1350 
1351 	// Total time for int. ack execution = 12 + WM + RM * (1 + IND) + RR
1352 	// WM = memory write cycles
1353 	// RM = memory read cycles
1354 	// IND = count of indirections (1 in 3001/3011)
1355 	// RR = register read cycles
1356 	m_icount -= (12 + REGISTER_RW_CYCLES);
1357 
1358 	// Allow special processing in 5061-3001
1359 	enter_isr();
1360 
1361 	// Do a double-indirect JSM IV,I instruction
1362 	// On 09825 there can be more than 2 levels of indirection
1363 	m_reg_R = (m_reg_R + 1) & m_addr_mask_low16;
1364 	WM(AEC_CASE_C , m_reg_R , m_reg_P);
1365 	uint32_t addr = add_mae(AEC_CASE_C , m_reg_IV + CURRENT_PA);
1366 	m_reg_P = get_indirect_target(addr);
1367 	m_reg_I = fetch();
1368 }
1369 
enter_isr()1370 void hp_hybrid_cpu_device::enter_isr()
1371 {
1372 	// Do nothing special
1373 }
1374 
RIO(uint8_t pa,uint8_t ic)1375 uint16_t hp_hybrid_cpu_device::RIO(uint8_t pa , uint8_t ic)
1376 {
1377 	m_icount -= IO_RW_CYCLES;
1378 	return m_io.read_word(HP_MAKE_IOADDR(pa, ic));
1379 }
1380 
WIO(uint8_t pa,uint8_t ic,uint16_t v)1381 void hp_hybrid_cpu_device::WIO(uint8_t pa , uint8_t ic , uint16_t v)
1382 {
1383 	m_icount -= IO_RW_CYCLES;
1384 	m_io.write_word(HP_MAKE_IOADDR(pa, ic) , v);
1385 }
1386 
do_dec_shift_r(uint8_t d1,uint64_t & mantissa)1387 uint8_t hp_hybrid_cpu_device::do_dec_shift_r(uint8_t d1 , uint64_t& mantissa)
1388 {
1389 	uint8_t d12 = uint8_t(mantissa & 0xf);
1390 
1391 	mantissa = (mantissa >> 4) | (uint64_t(d1) << 44);
1392 
1393 	return d12;
1394 }
1395 
do_dec_shift_l(uint8_t d12,uint64_t & mantissa)1396 uint8_t hp_hybrid_cpu_device::do_dec_shift_l(uint8_t d12 , uint64_t& mantissa)
1397 {
1398 	uint8_t d1 = uint8_t((mantissa >> 44) & 0xf);
1399 
1400 	mantissa = (mantissa << 4) | uint64_t(d12);
1401 	mantissa &= 0xffffffffffffULL;
1402 
1403 	return d1;
1404 }
1405 
get_ar1()1406 uint64_t hp_hybrid_cpu_device::get_ar1()
1407 {
1408 	uint32_t addr;
1409 	uint64_t tmp;
1410 
1411 	addr = add_mae(AEC_CASE_B , HP_REG_AR1_ADDR + 1);
1412 	tmp = uint64_t(RM(addr++));
1413 	tmp <<= 16;
1414 	tmp |= uint64_t(RM(addr++));
1415 	tmp <<= 16;
1416 	tmp |= uint64_t(RM(addr));
1417 
1418 	return tmp;
1419 }
1420 
set_ar1(uint64_t v)1421 void hp_hybrid_cpu_device::set_ar1(uint64_t v)
1422 {
1423 	uint32_t addr;
1424 
1425 	addr = add_mae(AEC_CASE_B , HP_REG_AR1_ADDR + 3);
1426 	WM(addr-- , uint16_t(v & 0xffff));
1427 	v >>= 16;
1428 	WM(addr-- , uint16_t(v & 0xffff));
1429 	v >>= 16;
1430 	WM(addr , uint16_t(v & 0xffff));
1431 }
1432 
get_ar2() const1433 uint64_t hp_hybrid_cpu_device::get_ar2() const
1434 {
1435 	uint64_t tmp;
1436 
1437 	tmp = uint64_t(m_reg_ar2[ 1 ]);
1438 	tmp <<= 16;
1439 	tmp |= uint64_t(m_reg_ar2[ 2 ]);
1440 	tmp <<= 16;
1441 	tmp |= uint64_t(m_reg_ar2[ 3 ]);
1442 
1443 	return tmp;
1444 }
1445 
set_ar2(uint64_t v)1446 void hp_hybrid_cpu_device::set_ar2(uint64_t v)
1447 {
1448 	m_reg_ar2[ 3 ] = uint16_t(v & 0xffff);
1449 	v >>= 16;
1450 	m_reg_ar2[ 2 ] = uint16_t(v & 0xffff);
1451 	v >>= 16;
1452 	m_reg_ar2[ 1 ] = uint16_t(v & 0xffff);
1453 }
1454 
do_mrxy(uint64_t ar)1455 uint64_t hp_hybrid_cpu_device::do_mrxy(uint64_t ar)
1456 {
1457 	uint8_t n;
1458 
1459 	n = m_reg_B & 0xf;
1460 	m_reg_A &= 0xf;
1461 	m_reg_se = m_reg_A;
1462 	while (n--) {
1463 		m_reg_se = do_dec_shift_r(m_reg_A , ar);
1464 		m_reg_A = 0;
1465 		m_icount -= 4;
1466 	}
1467 	m_reg_A = m_reg_se;
1468 	BIT_CLR(m_flags , HPHYBRID_DC_BIT);
1469 
1470 	return ar;
1471 }
1472 
do_dec_add(bool carry_in,uint64_t & a,uint64_t b)1473 bool hp_hybrid_cpu_device::do_dec_add(bool carry_in , uint64_t& a , uint64_t b)
1474 {
1475 	uint64_t tmp = 0;
1476 	unsigned i;
1477 	uint8_t digit_a , digit_b;
1478 
1479 	for (i = 0; i < 12; i++) {
1480 		digit_a = uint8_t(a & 0xf);
1481 		digit_b = uint8_t(b & 0xf);
1482 
1483 		if (carry_in) {
1484 			digit_a++;
1485 		}
1486 
1487 		digit_a += digit_b;
1488 
1489 		carry_in = digit_a >= 10;
1490 
1491 		if (carry_in) {
1492 			digit_a = (digit_a - 10) & 0xf;
1493 		}
1494 
1495 		tmp |= uint64_t(digit_a) << (4 * i);
1496 
1497 		a >>= 4;
1498 		b >>= 4;
1499 	}
1500 
1501 	a = tmp;
1502 
1503 	return carry_in;
1504 }
1505 
do_mpy()1506 void hp_hybrid_cpu_device::do_mpy()
1507 {
1508 	// Count 0->1 and 1->0 transitions in A register
1509 	// Correct timing needs this count as real hw uses Booth's algorithm for multiplication
1510 	uint16_t tmp = m_reg_A;
1511 	uint16_t mask = ~0;
1512 	for (unsigned i = 0; i < 16 && tmp; ++i) {
1513 		if (BIT(tmp , 0)) {
1514 			tmp ^= mask;
1515 			m_icount -= 2;
1516 		}
1517 		tmp >>= 1;
1518 		mask >>= 1;
1519 	}
1520 
1521 	int32_t a = int16_t(m_reg_A);
1522 	int32_t b = int16_t(m_reg_B);
1523 	int32_t p = a * b;
1524 
1525 	m_reg_A = uint16_t(p & 0xffff);
1526 	m_reg_B = uint16_t((p >> 16) & 0xffff);
1527 
1528 	m_icount -= 59;
1529 }
1530 
1531 // ********************************************************************************
1532 // hp_5061_3011_cpu_device
1533 // ********************************************************************************
hp_5061_3011_cpu_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1534 hp_5061_3011_cpu_device::hp_5061_3011_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1535 	: hp_hybrid_cpu_device(mconfig, HP_5061_3011, tag, owner, clock, 16)
1536 {
1537 }
1538 
hp_5061_3011_cpu_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,uint8_t addrwidth)1539 hp_5061_3011_cpu_device::hp_5061_3011_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t addrwidth)
1540 	: hp_hybrid_cpu_device(mconfig, type, tag, owner, clock, addrwidth)
1541 {
1542 }
1543 
execute_no_bpc(uint16_t opcode,uint16_t & next_pc)1544 bool hp_5061_3011_cpu_device::execute_no_bpc(uint16_t opcode , uint16_t& next_pc)
1545 {
1546 	// 16-bit IOC instructions
1547 	if ((opcode & 0xf760) == 0x7160) {
1548 		// Place/withdraw
1549 		uint16_t tmp;
1550 		uint16_t reg_addr = opcode & 7;
1551 		uint16_t *ptr_reg;
1552 		uint32_t b_mask;
1553 
1554 		if (BIT(opcode , 3)) {
1555 			ptr_reg = &m_reg_D;
1556 			b_mask = BIT_MASK<uint32_t>(HPHYBRID_DB_BIT);
1557 		} else {
1558 			ptr_reg = &m_reg_C;
1559 			b_mask = BIT_MASK<uint32_t>(HPHYBRID_CB_BIT);
1560 		}
1561 
1562 		if (BIT(opcode , 4)) {
1563 			// Withdraw
1564 			if (BIT(opcode , 11)) {
1565 				// Byte
1566 				uint32_t tmp_addr = uint32_t(*ptr_reg);
1567 				if (m_flags & b_mask) {
1568 					tmp_addr |= BIT_MASK<uint32_t>(16);
1569 				}
1570 				tmp = RM(AEC_CASE_C , uint16_t(tmp_addr >> 1));
1571 				if (BIT(tmp_addr , 0)) {
1572 					tmp &= 0xff;
1573 				} else {
1574 					tmp >>= 8;
1575 				}
1576 			} else {
1577 				// Word
1578 				tmp = RM(AEC_CASE_C , *ptr_reg);
1579 			}
1580 			WM(reg_addr , tmp);
1581 
1582 			if (BIT(opcode , 7)) {
1583 				// Post-decrement
1584 				if ((*ptr_reg)-- == 0) {
1585 					m_flags ^= b_mask;
1586 				}
1587 			} else {
1588 				// Post-increment
1589 				if (++(*ptr_reg) == 0) {
1590 					m_flags ^= b_mask;
1591 				}
1592 			}
1593 		} else {
1594 			// Place
1595 			if (BIT(opcode , 7)) {
1596 				// Pre-decrement
1597 				if ((*ptr_reg)-- == 0) {
1598 					m_flags ^= b_mask;
1599 				}
1600 			} else {
1601 				// Pre-increment
1602 				if (++(*ptr_reg) == 0) {
1603 					m_flags ^= b_mask;
1604 				}
1605 			}
1606 			tmp = RM(reg_addr);
1607 			if (BIT(opcode , 11)) {
1608 				// Byte
1609 				uint32_t tmp_addr = uint32_t(*ptr_reg);
1610 				if (m_flags & b_mask) {
1611 					tmp_addr |= BIT_MASK<uint32_t>(16);
1612 				}
1613 				tmp = BIT(tmp_addr , 0) ? (tmp & 0xff) : (tmp << 8);
1614 				if (tmp_addr <= (HP_REG_LAST_ADDR * 2 + 1)) {
1615 					// Single bytes can be written to registers.
1616 					// The addressed register gets the written byte in the proper position
1617 					// and a 0 in the other byte because access to registers is always done in
1618 					// 16 bits units.
1619 					WM(tmp_addr >> 1 , tmp);
1620 				} else {
1621 					if (m_stm_func) {
1622 						m_stm_func(m_curr_cycle | CYCLE_WR_MASK);
1623 						m_curr_cycle = 0;
1624 					}
1625 					// Extend address, form byte address
1626 					uint16_t mask = BIT(tmp_addr , 0) ? 0x00ff : 0xff00;
1627 					tmp_addr = add_mae(AEC_CASE_C , tmp_addr >> 1);
1628 					m_program.write_word(tmp_addr , tmp , mask);
1629 					m_icount -= m_w_cycles;
1630 				}
1631 			} else {
1632 				// Word
1633 				WM(AEC_CASE_C , *ptr_reg , tmp);
1634 			}
1635 		}
1636 		m_icount -= 6;
1637 	} else {
1638 		switch (opcode) {
1639 		case 0x7100:
1640 			// SDO
1641 			m_icount -= 6;
1642 			BIT_SET(m_flags , HPHYBRID_DMADIR_BIT);
1643 			break;
1644 
1645 		case 0x7108:
1646 			// SDI
1647 			m_icount -= 6;
1648 			BIT_CLR(m_flags , HPHYBRID_DMADIR_BIT);
1649 			break;
1650 
1651 		case 0x7140:
1652 			// DBL
1653 			m_icount -= 6;
1654 			BIT_CLR(m_flags , HPHYBRID_DB_BIT);
1655 			break;
1656 
1657 		case 0x7148:
1658 			// CBL
1659 			m_icount -= 6;
1660 			BIT_CLR(m_flags , HPHYBRID_CB_BIT);
1661 			break;
1662 
1663 		case 0x7150:
1664 			// DBU
1665 			m_icount -= 6;
1666 			BIT_SET(m_flags , HPHYBRID_DB_BIT);
1667 			break;
1668 
1669 		case 0x7158:
1670 			// CBU
1671 			m_icount -= 6;
1672 			BIT_SET(m_flags , HPHYBRID_CB_BIT);
1673 			break;
1674 
1675 		default:
1676 			// Unrecognized instruction
1677 			return false;
1678 		}
1679 	}
1680 	next_pc = m_reg_P + 1;
1681 	return true;
1682 }
1683 
read_non_common_reg(uint16_t addr,uint16_t & v)1684 bool hp_5061_3011_cpu_device::read_non_common_reg(uint16_t addr , uint16_t& v)
1685 {
1686 	switch (addr) {
1687 	case HP_REG_DMAPA_ADDR:
1688 		v = m_dmapa & HP_REG_PA_MASK;
1689 		if (BIT(m_flags , HPHYBRID_CB_BIT)) {
1690 			BIT_SET(v , 15);
1691 		}
1692 		if (BIT(m_flags , HPHYBRID_DB_BIT)) {
1693 			BIT_SET(v , 14);
1694 		}
1695 		return true;
1696 
1697 	default:
1698 		return false;
1699 	}
1700 }
1701 
write_non_common_reg(uint16_t addr,uint16_t v)1702 bool hp_5061_3011_cpu_device::write_non_common_reg(uint16_t addr , uint16_t v)
1703 {
1704 	return false;
1705 }
1706 
handle_dma()1707 void hp_5061_3011_cpu_device::handle_dma()
1708 {
1709 	// Patent hints at the fact that terminal count is detected by bit 15 of dmac being 1 after decrementing
1710 	bool tc = BIT(--m_dmac , 15) != 0;
1711 	uint16_t tmp;
1712 
1713 	m_curr_cycle |= CYCLE_DMA_MASK;
1714 	// Timing here assumes that DMA transfers are isolated and not done in bursts
1715 	if (BIT(m_flags , HPHYBRID_DMADIR_BIT)) {
1716 		// "Outward" DMA: memory -> peripheral
1717 		tmp = RM(AEC_CASE_D , m_dmama++);
1718 		WIO(m_dmapa , tc ? 2 : 0 , tmp);
1719 	} else {
1720 		// "Inward" DMA: peripheral -> memory
1721 		tmp = RIO(m_dmapa , tc ? 2 : 0);
1722 		WM(AEC_CASE_D , m_dmama++ , tmp);
1723 		m_icount += 1;
1724 	}
1725 
1726 	// Mystery solved: DMA is not automatically disabled at TC (test of 9845's graphic memory relies on this to work)
1727 }
1728 
create_disassembler()1729 std::unique_ptr<util::disasm_interface> hp_5061_3011_cpu_device::create_disassembler()
1730 {
1731 	return std::make_unique<hp_5061_3011_disassembler>(m_relative_mode);
1732 }
1733 
1734 // ********************************************************************************
1735 // hp_5061_3001_cpu_device
1736 // ********************************************************************************
hp_5061_3001_cpu_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1737 hp_5061_3001_cpu_device::hp_5061_3001_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1738 	: hp_5061_3011_cpu_device(mconfig, HP_5061_3001, tag, owner, clock, 22)
1739 {
1740 }
1741 
device_start()1742 void hp_5061_3001_cpu_device::device_start()
1743 {
1744 	hp_hybrid_cpu_device::device_start();
1745 	emc_start();
1746 
1747 	state_add(HPHYBRID_R32, "R32" , m_reg_aec[ 0 ]);
1748 	state_add(HPHYBRID_R33, "R33" , m_reg_aec[ 1 ]);
1749 	state_add(HPHYBRID_R34, "R34" , m_reg_aec[ 2 ]);
1750 	state_add(HPHYBRID_R35, "R35" , m_reg_aec[ 3 ]);
1751 	state_add(HPHYBRID_R36, "R36" , m_reg_aec[ 4 ]);
1752 	state_add(HPHYBRID_R37, "R37" , m_reg_aec[ 5 ]);
1753 	save_item(NAME(m_reg_aec));
1754 }
1755 
device_reset()1756 void hp_5061_3001_cpu_device::device_reset()
1757 {
1758 	// Initial state of AEC registers:
1759 	// R32  0
1760 	// R33  5
1761 	// R34  0
1762 	// R35  0
1763 	// R36  0
1764 	// R37  0
1765 	m_reg_aec[ 0 ] = 0;
1766 	m_reg_aec[ 1 ] = 5;
1767 	m_reg_aec[ 2 ] = 0;
1768 	m_reg_aec[ 3 ] = 0;
1769 	m_reg_aec[ 4 ] = 0;
1770 	m_reg_aec[ 5 ] = 0;
1771 
1772 	hp_hybrid_cpu_device::device_reset();
1773 }
1774 
execute_no_bpc(uint16_t opcode,uint16_t & next_pc)1775 bool hp_5061_3001_cpu_device::execute_no_bpc(uint16_t opcode , uint16_t& next_pc)
1776 {
1777 	// Try to execute opcode as an IOC-16 instruction first then as an EMC one
1778 	if (hp_5061_3011_cpu_device::execute_no_bpc(opcode , next_pc) ||
1779 		execute_emc(opcode , next_pc)) {
1780 		return true;
1781 	}
1782 
1783 	// AEC instructions
1784 	switch (opcode) {
1785 	case 0x7026:
1786 		// CIM
1787 		// Undocumented instruction, see beginning of this file
1788 		// Probably "Clear Interrupt Mode"
1789 		// No idea at all about exec. time: make it 9 cycles (6 are in opcode fetch)
1790 		m_icount -= 3;
1791 		BIT_CLR(m_flags, HPHYBRID_IM_BIT);
1792 		break;
1793 
1794 	case 0x7027:
1795 		// SIM
1796 		// Undocumented instruction, see beginning of this file
1797 		// Probably "Set Interrupt Mode"
1798 		// No idea at all about exec. time: make it 9 cycles (6 are in opcode fetch)
1799 		m_icount -= 3;
1800 		BIT_SET(m_flags, HPHYBRID_IM_BIT);
1801 		break;
1802 
1803 	default:
1804 		return false;
1805 	}
1806 
1807 	next_pc = m_reg_P + 1;
1808 	return true;
1809 }
1810 
add_mae(aec_cases_t aec_case,uint16_t addr)1811 uint32_t hp_5061_3001_cpu_device::add_mae(aec_cases_t aec_case , uint16_t addr)
1812 {
1813 	uint16_t bsc_reg;
1814 	bool top_half = BIT(addr , 15) != 0;
1815 
1816 	// Detect accesses to top half of base page
1817 	if (aec_case == AEC_CASE_C && (addr & 0xfe00) == 0xfe00) {
1818 		aec_case = AEC_CASE_B;
1819 	}
1820 
1821 	// **** IM == 0 ****
1822 	// Case | Top | Bottom
1823 	//   A  | R34 | R33
1824 	//   B  | R36 | R33
1825 	//   C  | R32 | R35
1826 	//   D  | R32 | R37
1827 	//
1828 	// **** IM == 1 ****
1829 	// Case | Top | Bottom
1830 	//   A  | R34 |   5
1831 	//   B  |   1 |   5
1832 	//   C  |   0 | R35
1833 	//   D  | R32 | R37
1834 	switch (aec_case) {
1835 	case AEC_CASE_A:
1836 		if (top_half) {
1837 			bsc_reg = m_reg_aec[ HP_REG_R34_ADDR - HP_REG_R32_ADDR ];
1838 		} else {
1839 			// Block 5 is used when IM bit overrides R33 value
1840 			bsc_reg = BIT(m_flags , HPHYBRID_IM_BIT) ? 5 : m_reg_aec[ HP_REG_R33_ADDR - HP_REG_R32_ADDR ];
1841 		}
1842 		break;
1843 
1844 	case AEC_CASE_B:
1845 		if (top_half) {
1846 			// Block 1 is used when IM bit overrides R36 value
1847 			bsc_reg = BIT(m_flags , HPHYBRID_IM_BIT) ? 1 : m_reg_aec[ HP_REG_R36_ADDR - HP_REG_R32_ADDR ];
1848 		} else {
1849 			// Block 5 is used when IM bit overrides R33 value
1850 			bsc_reg = BIT(m_flags , HPHYBRID_IM_BIT) ? 5 : m_reg_aec[ HP_REG_R33_ADDR - HP_REG_R32_ADDR ];
1851 		}
1852 		break;
1853 
1854 	case AEC_CASE_C:
1855 		if (top_half) {
1856 			// Block 0 is used when IM bit overrides R32 value
1857 			bsc_reg = BIT(m_flags , HPHYBRID_IM_BIT) ? 0 : m_reg_aec[ HP_REG_R32_ADDR - HP_REG_R32_ADDR ];
1858 		} else {
1859 			bsc_reg = m_reg_aec[ HP_REG_R35_ADDR - HP_REG_R32_ADDR ];
1860 		}
1861 		break;
1862 
1863 	case AEC_CASE_D:
1864 		bsc_reg = top_half ? m_reg_aec[ HP_REG_R32_ADDR - HP_REG_R32_ADDR ] : m_reg_aec[ HP_REG_R37_ADDR - HP_REG_R32_ADDR ];
1865 			break;
1866 
1867 	default:
1868 		logerror("hphybrid: aec_case=%d\n" , aec_case);
1869 		return 0;
1870 	}
1871 
1872 	uint16_t aec_reg = bsc_reg & BSC_REG_MASK;
1873 
1874 	if (m_forced_bsc_25) {
1875 		aec_reg = (aec_reg & 0xf) | 0x20;
1876 	}
1877 
1878 	return uint32_t(addr) | (uint32_t(aec_reg) << 16);
1879 }
1880 
read_non_common_reg(uint16_t addr,uint16_t & v)1881 bool hp_5061_3001_cpu_device::read_non_common_reg(uint16_t addr , uint16_t& v)
1882 {
1883 	switch (addr) {
1884 	case HP_REG_R32_ADDR:
1885 	case HP_REG_R33_ADDR:
1886 	case HP_REG_R34_ADDR:
1887 	case HP_REG_R35_ADDR:
1888 	case HP_REG_R36_ADDR:
1889 	case HP_REG_R37_ADDR:
1890 		v = m_reg_aec[ addr - HP_REG_R32_ADDR ];
1891 		return true;
1892 
1893 	default:
1894 		return hp_5061_3011_cpu_device::read_non_common_reg(addr , v) ||
1895 			read_emc_reg(addr , v);
1896 	}
1897 }
1898 
write_non_common_reg(uint16_t addr,uint16_t v)1899 bool hp_5061_3001_cpu_device::write_non_common_reg(uint16_t addr , uint16_t v)
1900 {
1901 	switch (addr) {
1902 	case HP_REG_R32_ADDR:
1903 	case HP_REG_R33_ADDR:
1904 	case HP_REG_R34_ADDR:
1905 	case HP_REG_R35_ADDR:
1906 	case HP_REG_R36_ADDR:
1907 	case HP_REG_R37_ADDR:
1908 		m_reg_aec[ addr - HP_REG_R32_ADDR ] = v;
1909 		return true;
1910 
1911 	default:
1912 		return hp_5061_3011_cpu_device::write_non_common_reg(addr , v) ||
1913 			write_emc_reg(addr , v);
1914 	}
1915 }
1916 
create_disassembler()1917 std::unique_ptr<util::disasm_interface> hp_5061_3001_cpu_device::create_disassembler()
1918 {
1919 	return std::make_unique<hp_5061_3001_disassembler>(m_relative_mode);
1920 }
1921 
enter_isr()1922 void hp_5061_3001_cpu_device::enter_isr()
1923 {
1924 	// Set interrupt mode when entering an ISR
1925 	BIT_SET(m_flags, HPHYBRID_IM_BIT);
1926 }
1927 
1928 // ********************************************************************************
1929 // hp_09825_67907_cpu_device
1930 // ********************************************************************************
hp_09825_67907_cpu_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1931 hp_09825_67907_cpu_device::hp_09825_67907_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1932 	: hp_hybrid_cpu_device(mconfig , HP_09825_67907 , tag , owner , clock , 15)
1933 {
1934 }
1935 
device_start()1936 void hp_09825_67907_cpu_device::device_start()
1937 {
1938 	hp_hybrid_cpu_device::device_start();
1939 	emc_start();
1940 }
1941 
execute_no_bpc(uint16_t opcode,uint16_t & next_pc)1942 bool hp_09825_67907_cpu_device::execute_no_bpc(uint16_t opcode , uint16_t& next_pc)
1943 {
1944 	// 15-bit IOC instructions
1945 	if ((opcode & 0xf760) == 0x7160) {
1946 		// Place/withdraw
1947 		uint16_t tmp;
1948 		uint16_t reg_addr = opcode & 7;
1949 		uint16_t *ptr_reg;
1950 
1951 		if (BIT(opcode , 3)) {
1952 			ptr_reg = &m_reg_D;
1953 		} else {
1954 			ptr_reg = &m_reg_C;
1955 		}
1956 
1957 		if (BIT(opcode , 4)) {
1958 			// Withdraw
1959 			tmp = RM(AEC_CASE_C , *ptr_reg);
1960 			if (BIT(opcode , 11)) {
1961 				// Byte
1962 				if (BIT(*ptr_reg , 15)) {
1963 					tmp >>= 8;
1964 				} else {
1965 					tmp &= 0xff;
1966 				}
1967 			}
1968 			WM(reg_addr , tmp);
1969 
1970 			// Post inc/dec
1971 			inc_dec_cd(*ptr_reg , !BIT(opcode , 7) , BIT(opcode , 11));
1972 		} else {
1973 			// Place
1974 
1975 			// Pre inc/dec
1976 			inc_dec_cd(*ptr_reg , !BIT(opcode , 7) , BIT(opcode , 11));
1977 
1978 			tmp = RM(reg_addr);
1979 			uint16_t tmp_addr = *ptr_reg & ADDR_MASK_15BIT;
1980 			if (BIT(opcode , 11)) {
1981 				// Byte
1982 				tmp = BIT(*ptr_reg , 15) ? (tmp << 8) : (tmp & 0xff);
1983 				if (tmp_addr <= HP_REG_LAST_ADDR) {
1984 					// Single bytes can be written to registers.
1985 					// The addressed register gets the written byte in the proper position
1986 					// and a 0 in the other byte because access to registers is always done in
1987 					// 16 bits units.
1988 					WM(tmp_addr , tmp);
1989 				} else {
1990 					if (m_stm_func) {
1991 						m_stm_func(m_curr_cycle | CYCLE_WR_MASK);
1992 						m_curr_cycle = 0;
1993 					}
1994 					uint16_t mask = BIT(*ptr_reg , 15) ? 0xff00 : 0x00ff;
1995 					m_program.write_word(tmp_addr , tmp , mask);
1996 					m_icount -= m_w_cycles;
1997 				}
1998 			} else {
1999 				// Word
2000 				WM(AEC_CASE_C , tmp_addr , tmp);
2001 			}
2002 		}
2003 		m_icount -= 6;
2004 		next_pc = m_reg_P + 1;
2005 		return true;
2006 	} else {
2007 		return execute_emc(opcode , next_pc);
2008 	}
2009 }
2010 
inc_dec_cd(uint16_t & cd_reg,bool increment,bool byte)2011 void hp_09825_67907_cpu_device::inc_dec_cd(uint16_t& cd_reg , bool increment , bool byte)
2012 {
2013 	bool propagate;
2014 	if (byte) {
2015 		// Byte
2016 		// Toggle bit 15
2017 		cd_reg ^= REG_MSB_MASK;
2018 		// When incrementing, propagate to 15 LSBs when bit 15 goes 0->1
2019 		propagate = (cd_reg & REG_MSB_MASK) != 0;
2020 		if (!increment) {
2021 			// When decrementing, propagate when bit 15 goes 1->0
2022 			propagate = !propagate;
2023 		}
2024 	} else {
2025 		// Word
2026 		propagate = true;
2027 	}
2028 	if (propagate) {
2029 		if (increment) {
2030 			cd_reg = (cd_reg & ~ADDR_MASK_15BIT) | ((cd_reg + 1) & ADDR_MASK_15BIT);
2031 		} else {
2032 			cd_reg = (cd_reg & ~ADDR_MASK_15BIT) | ((cd_reg - 1) & ADDR_MASK_15BIT);
2033 		}
2034 	}
2035 }
2036 
read_non_common_reg(uint16_t addr,uint16_t & v)2037 bool hp_09825_67907_cpu_device::read_non_common_reg(uint16_t addr , uint16_t& v)
2038 {
2039 	switch (addr) {
2040 	case HP_REG_DMAPA_ADDR:
2041 		v = m_dmapa;
2042 		return true;
2043 
2044 	default:
2045 		return read_emc_reg(addr , v);
2046 	}
2047 }
2048 
write_non_common_reg(uint16_t addr,uint16_t v)2049 bool hp_09825_67907_cpu_device::write_non_common_reg(uint16_t addr , uint16_t v)
2050 {
2051 	return write_emc_reg(addr , v);
2052 }
2053 
get_indirect_target(uint32_t addr)2054 uint16_t hp_09825_67907_cpu_device::get_indirect_target(uint32_t addr)
2055 {
2056 	uint16_t tmp;
2057 	bool ind;
2058 
2059 	// Multi-level indirect addressing
2060 	// TODO: It wouldn't hurt to have some limit on iterations
2061 	do {
2062 		tmp = RM(addr);
2063 		ind = BIT(tmp , 15);
2064 		addr = tmp & ADDR_MASK_15BIT;
2065 	} while (ind);
2066 
2067 	return tmp;
2068 }
2069 
handle_dma()2070 void hp_09825_67907_cpu_device::handle_dma()
2071 {
2072 	bool tc = BIT(--m_dmac , 15) != 0;
2073 	uint16_t tmp;
2074 
2075 	// Timing here assumes that DMA transfers are isolated and not done in bursts
2076 	m_curr_cycle |= CYCLE_DMA_MASK;
2077 	if (BIT(m_dmama , 15)) {
2078 		// "Outward" DMA: memory -> peripheral
2079 		tmp = RM(AEC_CASE_D , m_dmama);
2080 		WIO(m_dmapa , tc ? 2 : 0 , tmp);
2081 	} else {
2082 		// "Inward" DMA: peripheral -> memory
2083 		tmp = RIO(m_dmapa , tc ? 2 : 0);
2084 		WM(AEC_CASE_D , m_dmama , tmp);
2085 		m_icount += 1;
2086 	}
2087 	m_dmama = (m_dmama & ~ADDR_MASK_15BIT) | ((m_dmama + 1) & ADDR_MASK_15BIT);
2088 }
2089 
create_disassembler()2090 std::unique_ptr<util::disasm_interface> hp_09825_67907_cpu_device::create_disassembler()
2091 {
2092 	return std::make_unique<hp_09825_67907_disassembler>(m_relative_mode);
2093 }
2094