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