1 // license:BSD-3-Clause
2 // copyright-holders:Patrick Mackinlay
3
4 /*
5 * IBM Research and Office Products Division Microprocessor (ROMP).
6 *
7 * Sources:
8 * - http://bitsavers.org/pdf/ibm/pc/rt/6489893_RT_PC_Technical_Reference_Volume_1_Nov85.pdf
9 *
10 * TODO:
11 * - mmu/iocc exceptions
12 * - unimplemented instructions (multiply, divide, wait)
13 * - timer/counter
14 */
15
16 #include "emu.h"
17 #include "romp.h"
18 #include "rompdasm.h"
19 #include "debugger.h"
20
21 #define LOG_GENERAL (1U << 0)
22 #define LOG_INTERRUPT (1U << 1)
23
24 //#define VERBOSE (LOG_INTERRUPT)
25 #include "logmacro.h"
26
27 // instruction decode helpers
28 #define R2 ((op >> 4) & 15)
29 #define R3 (op & 15)
30
31 DEFINE_DEVICE_TYPE(ROMP, romp_device, "romp", "IBM ROMP")
32
33 ALLOW_SAVE_TYPE(romp_device::branch_state);
34
romp_device(machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)35 romp_device::romp_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
36 : cpu_device(mconfig, ROMP, tag, owner, clock)
37 , m_mem_config("memory", ENDIANNESS_BIG, 32, 32)
38 , m_io_config("io", ENDIANNESS_BIG, 32, 24, -2)
39 , m_out_tm(*this)
40 , m_icount(0)
41 {
42 }
43
device_start()44 void romp_device::device_start()
45 {
46 m_out_tm.resolve_safe();
47
48 // set instruction counter
49 set_icountptr(m_icount);
50
51 // register state for the debugger
52 state_add(STATE_GENPC, "GENPC", m_scr[IAR]).noshow();
53 state_add(STATE_GENPCBASE, "CURPC", m_scr[IAR]).noshow();
54 state_add(STATE_GENFLAGS, "GENFLAGS", m_scr[CS]).formatstr("%6s").noshow();
55
56 state_add(ROMP_SCR + IAR, "IAR", m_scr[IAR]);
57 state_add(ROMP_SCR + COUS, "COUS", m_scr[COUS]);
58 state_add(ROMP_SCR + COU, "COU", m_scr[COU]);
59 state_add(ROMP_SCR + TS, "TS", m_scr[TS]);
60 state_add(ROMP_SCR + MQ, "MQ", m_scr[MQ]);
61 state_add(ROMP_SCR + MPCS, "MPCS", m_scr[MPCS]);
62 state_add(ROMP_SCR + IRB, "IRB", m_scr[IRB]);
63 state_add(ROMP_SCR + ICS, "ICS", m_scr[ICS]);
64 state_add(ROMP_SCR + CS, "CS", m_scr[CS]);
65
66 for (unsigned i = 0; i < ARRAY_LENGTH(m_gpr); i++)
67 state_add(ROMP_GPR + i, util::string_format("R%d", i).c_str(), m_gpr[i]);
68
69 // register state for saving
70 save_item(NAME(m_scr));
71 save_item(NAME(m_gpr));
72 save_item(NAME(m_branch_state));
73 save_item(NAME(m_branch_target));
74 }
75
state_string_export(device_state_entry const & entry,std::string & str) const76 void romp_device::state_string_export(device_state_entry const &entry, std::string &str) const
77 {
78 switch (entry.index())
79 {
80 case STATE_GENFLAGS:
81 str = string_format("%c%c%c%c%c%c",
82 (m_scr[CS] & CS_L) ? 'L' : '.',
83 (m_scr[CS] & CS_E) ? 'E' : '.',
84 (m_scr[CS] & CS_G) ? 'G' : '.',
85 (m_scr[CS] & CS_C) ? 'C' : '.',
86 (m_scr[CS] & CS_O) ? 'O' : '.',
87 (m_scr[CS] & CS_T) ? 'T' : '.');
88 break;
89 }
90 }
91
device_reset()92 void romp_device::device_reset()
93 {
94 // TODO: assumed
95 for (u32 &scr : m_scr)
96 scr = 0;
97 m_out_tm(0);
98
99 // TODO: assumed
100 for (u32 &gpr : m_gpr)
101 gpr = 0;
102
103 // initialize the state
104 m_scr[IAR] = space(AS_PROGRAM).read_dword(0);
105 m_branch_state = DEFAULT;
106 }
107
execute_run()108 void romp_device::execute_run()
109 {
110 // core execution loop
111 while (m_icount-- > 0)
112 {
113 // debugging
114 debugger_instruction_hook(m_scr[IAR]);
115
116 if (m_branch_state == DEFAULT)
117 interrupt_check();
118
119 // fetch instruction
120 u16 const op = space(AS_PROGRAM).read_word(m_scr[IAR]);
121 u32 updated_iar = m_scr[IAR] + 2;
122
123 switch (op >> 12)
124 {
125 case 0x0: // jb/jnb: jump on [not] condition bit
126 if (m_branch_state == BRANCH)
127 program_check(PCS_PCK | PCS_IOC);
128 else if (BIT(m_scr[CS], ((op >> 8) & 7) ^ 7) == BIT(op, 11))
129 {
130 m_branch_target = m_scr[IAR] + ji(op);
131 m_branch_state = BRANCH;
132 m_icount -= 4;
133 }
134 break;
135 case 0x1: // stcs: store character short
136 space(AS_PROGRAM).write_byte(r3_0(R3) + ((op >> 8) & 15), m_gpr[R2]);
137 m_icount -= 4;
138 break;
139 case 0x2: // sths: store half short
140 space(AS_PROGRAM).write_word(r3_0(R3) + ((op >> 7) & 30), m_gpr[R2]);
141 m_icount -= 4;
142 break;
143 case 0x3: // sts: store short
144 space(AS_PROGRAM).write_dword(r3_0(R3) + ((op >> 6) & 60), m_gpr[R2]);
145 m_icount -= 4;
146 break;
147 case 0x4: // lcs: load character short
148 m_gpr[R2] = space(AS_PROGRAM).read_byte(r3_0(R3) + ((op >> 8) & 15));
149 m_icount -= 4;
150 break;
151 case 0x5: // lhas: load half algebraic short
152 m_gpr[R2] = s32(s16(space(AS_PROGRAM).read_word(r3_0(R3) + ((op >> 7) & 30))));
153 m_icount -= 4;
154 break;
155 case 0x6: // cas: compute address short
156 m_gpr[(op >> 8) & 15] = m_gpr[R2] + r3_0(R3);
157 break;
158 case 0x7: // ls: load short
159 m_gpr[R2] = space(AS_PROGRAM).read_dword(r3_0(R3) + ((op >> 6) & 60));
160 m_icount -= 4;
161 break;
162 case 0x8: // BI, BA format
163 {
164 u16 const b = space(AS_PROGRAM).read_word(updated_iar);
165 updated_iar += 2;
166
167 if (m_branch_state == BRANCH)
168 {
169 program_check(PCS_PCK | PCS_IOC);
170 break;
171 }
172
173 switch (op >> 8)
174 {
175 case 0x88: // bnb: branch on not condition bit immediate
176 if (!BIT(m_scr[CS], R2 ^ 15))
177 {
178 m_branch_target = m_scr[IAR] + bi(op, b);
179 m_branch_state = BRANCH;
180 m_icount -= 4;
181 }
182 break;
183 case 0x89: // bnbx: branch on not condition bit immediate with execute
184 if (!BIT(m_scr[CS], R2 ^ 15))
185 {
186 m_branch_target = m_scr[IAR] + bi(op, b);
187 m_branch_state = DELAY;
188 m_icount -= 4;
189 }
190 break;
191 case 0x8a: // bala: branch and link absolute
192 m_gpr[15] = updated_iar;
193 m_branch_target = ba(op, b);
194 m_branch_state = BRANCH;
195 m_icount -= 4;
196 break;
197 case 0x8b: // balax: branch and link absolute with execute
198 m_gpr[15] = updated_iar + 4;
199 m_branch_target = ba(op, b);
200 m_branch_state = DELAY;
201 m_icount -= 4;
202 break;
203 case 0x8c: // bali: branch and link immediate
204 m_gpr[R2] = updated_iar;
205 m_branch_target = m_scr[IAR] + bi(op, b);
206 m_branch_state = BRANCH;
207 m_icount -= 4;
208 break;
209 case 0x8d: // balix: branch and link immediate with execute
210 m_gpr[R2] = updated_iar + 4;
211 m_branch_target = m_scr[IAR] + bi(op, b);
212 m_branch_state = DELAY;
213 m_icount -= 4;
214 break;
215 case 0x8e: // bb: branch on condition bit immediate
216 if (BIT(m_scr[CS], R2 ^ 15))
217 {
218 m_branch_target = m_scr[IAR] + bi(op, b);
219 m_branch_state = BRANCH;
220 m_icount -= 4;
221 }
222 break;
223 case 0x8f: // bbx: branch on condition bit immediate with execute
224 if (BIT(m_scr[CS], R2 ^ 15))
225 {
226 m_branch_target = m_scr[IAR] + bi(op, b);
227 m_branch_state = DELAY;
228 m_icount -= 4;
229 }
230 break;
231
232 default:
233 program_check(PCS_PCK | PCS_IOC);
234 break;
235 }
236 }
237 break;
238
239 case 0xc:
240 case 0xd: // D format
241 {
242 u16 const i = space(AS_PROGRAM).read_word(updated_iar);
243 updated_iar += 2;
244
245 u32 const r3 = R3 ? m_gpr[R3] : 0;
246
247 switch (op >> 8)
248 {
249 case 0xc0: // svc: supervisor call
250 if (m_branch_state != BRANCH)
251 {
252 interrupt_enter(9, r3 + i);
253 m_branch_state = EXCEPTION;
254
255 m_icount -= 15;
256 }
257 else
258 program_check(PCS_PCK | PCS_IOC);
259 break;
260 case 0xc1: // ai: add immediate
261 flags_add(m_gpr[R3], s32(s16(i)));
262 m_gpr[R2] = m_gpr[R3] + s32(s16(i));
263 break;
264 case 0xc2: // cal16: compute address lower half 16-bit
265 m_gpr[R2] = (r3 & 0xffff'0000U) | u16(r3 + i);
266 break;
267 case 0xc3: // oiu: or immediate upper half
268 m_gpr[R2] = (u32(i) << 16) | m_gpr[R3];
269 flags(m_gpr[R2]);
270 break;
271 case 0xc4: // oil: or immediate lower half
272 m_gpr[R2] = u32(i) | m_gpr[R3];
273 flags(m_gpr[R2]);
274 break;
275 case 0xc5: // nilz: and immediate lower half extended zeroes
276 m_gpr[R2] = u32(i) & m_gpr[R3];
277 flags(m_gpr[R2]);
278 break;
279 case 0xc6: // nilo: and immediate lower half extended ones
280 m_gpr[R2] = (i | 0xffff'0000U) & m_gpr[R3];
281 flags(m_gpr[R2]);
282 break;
283 case 0xc7: // xil: exclusive or immediate lower half
284 m_gpr[R2] = u32(i) ^ m_gpr[R3];
285 flags(m_gpr[R2]);
286 break;
287 case 0xc8: // cal: compute address lower half
288 m_gpr[R2] = r3 + s16(i);
289 break;
290 case 0xc9: // lm: load multiple
291 for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4)
292 {
293 m_gpr[reg] = space(AS_PROGRAM).read_dword(offset);
294 m_icount -= 2;
295 }
296 m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 1;
297 break;
298 case 0xca: // lha: load half algebraic
299 m_gpr[R2] = s32(s16(space(AS_PROGRAM).read_word(r3 + s16(i))));
300 m_icount -= 4;
301 break;
302 case 0xcb: // ior: input/output read
303 if (r3 + i < 0x0100'0000U)
304 m_gpr[R2] = space(AS_IO).read_dword(r3 + i);
305 else
306 program_check(PCS_PCK | PCS_IOC);
307 break;
308 case 0xcc: // ti: trap on condition immediate
309 if (m_branch_state == BRANCH)
310 program_check(PCS_PCK | PCS_IOC);
311 else if ((BIT(op, 6) && (m_gpr[R3] < u32(s32(s16(i)))))
312 || (BIT(op, 5) && (m_gpr[R3] == u32(s32(s16(i)))))
313 || (BIT(op, 4) && (m_gpr[R3] > u32(s32(s16(i))))))
314 program_check(PCS_PCK | PCS_PT);
315 break;
316 case 0xcd: // l: load
317 m_gpr[R2] = space(AS_PROGRAM).read_dword(r3 + s16(i));
318 m_icount -= 4;
319 break;
320 case 0xce: // lc: load character
321 m_gpr[R2] = space(AS_PROGRAM).read_byte(r3 + s16(i));
322 m_icount -= 4;
323 break;
324 case 0xcf: // tsh: test and set half
325 m_gpr[R2] = space(AS_PROGRAM).read_word(r3 + s16(i));
326 space(AS_PROGRAM).write_byte(r3 + s16(i), 0xff);
327 m_icount -= 4;
328 break;
329
330 case 0xd0: // lps: load program status
331 if (m_branch_state != BRANCH)
332 {
333 m_branch_target = space(AS_PROGRAM).read_dword(r3 + s16(i) + 0);
334 m_branch_state = BRANCH;
335 m_scr[ICS] = space(AS_PROGRAM).read_word(r3 + s16(i) + 4);
336 m_scr[CS] = space(AS_PROGRAM).read_word(r3 + s16(i) + 6);
337 m_scr[MPCS] &= ~0xffff;
338 // TODO: defer interrupt enable
339
340 m_icount -= 15;
341 }
342 else
343 program_check(PCS_PCK | PCS_IOC);
344 break;
345 case 0xd1: // aei: add extended immediate
346 flags_add(m_gpr[R3], s32(s16(i)) + bool(m_scr[CS] & CS_C));
347 m_gpr[R2] = m_gpr[R3] + s32(s16(i)) + bool(m_scr[CS] & CS_C);
348 break;
349 case 0xd2: // sfi: subtract from immediate
350 flags_sub(s32(s16(i)), m_gpr[R3]);
351 m_gpr[R2] = s32(s16(i)) - m_gpr[R3];
352 break;
353 case 0xd3: // cli: compare logical immediate
354 flags(m_gpr[R3] - u32(s32(s16(i))));
355 break;
356 case 0xd4: // ci: compare immediate
357 flags(s32(m_gpr[R3]) - s32(s16(i)));
358 break;
359 case 0xd5: // niuz: and immediate upper half extended zeroes
360 m_gpr[R2] = (u32(i) << 16) & m_gpr[R3];
361 flags(m_gpr[R2]);
362 break;
363 case 0xd6: // niuo: and immediate upper half extended ones
364 m_gpr[R2] = ((u32(i) << 16) | 0x0000'ffffU) & m_gpr[R3];
365 flags(m_gpr[R2]);
366 break;
367 case 0xd7: // xiu: exclusive or immediate upper half
368 m_gpr[R2] = (u32(i) << 16) ^ m_gpr[R3];
369 flags(m_gpr[R2]);
370 break;
371 case 0xd8: // cau: compute address upper half
372 m_gpr[R2] = r3 + (u32(i) << 16);
373 break;
374 case 0xd9: // stm: store multiple
375 for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4)
376 {
377 space(AS_PROGRAM).write_dword(offset, m_gpr[reg]);
378 m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 2;
379 }
380 m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 2;
381 break;
382 case 0xda: // lh: load half
383 m_gpr[R2] = space(AS_PROGRAM).read_word(r3 + s16(i));
384 m_icount -= 4;
385 break;
386 case 0xdb: // iow: input/output write
387 if (r3 + i < 0x0100'0000U)
388 space(AS_IO).write_dword(r3 + i, m_gpr[R2]);
389 else
390 program_check(PCS_PCK | PCS_IOC);
391 m_icount--;
392 break;
393 case 0xdc: // sth: store half
394 space(AS_PROGRAM).write_word(r3 + s16(i), m_gpr[R2]);
395 m_icount -= 4;
396 break;
397 case 0xdd: // st: store
398 space(AS_PROGRAM).write_dword(r3 + s16(i), m_gpr[R2]);
399 m_icount -= 4;
400 break;
401 case 0xde: // stc: store character
402 space(AS_PROGRAM).write_byte(r3 + s16(i), m_gpr[R2]);
403 m_icount -= 4;
404 break;
405
406 default:
407 program_check(PCS_PCK | PCS_IOC);
408 break;
409 }
410 }
411 break;
412
413 case 0x9:
414 case 0xa:
415 case 0xb:
416 case 0xe:
417 case 0xf: // R format
418 switch (op >> 8)
419 {
420 case 0x90: // ais: add immediate short
421 flags_add(m_gpr[R2], R3);
422 m_gpr[R2] += R3;
423 break;
424 case 0x91: // inc: increment
425 m_gpr[R2] += R3;
426 break;
427 case 0x92: // sis: subtract immediate short
428 flags_sub(m_gpr[R2], R3);
429 m_gpr[R2] -= R3;
430 break;
431 case 0x93: // dec: decrement
432 m_gpr[R2] -= R3;
433 break;
434 case 0x94: // cis: compare immediate short
435 flags(m_gpr[R2] - R3);
436 break;
437 case 0x95: // clrsb: clear scr bit
438 set_scr(R2, m_scr[R2] & ~(0x0000'8000U >> R3));
439 m_icount -= 3;
440 break;
441 case 0x96: // mfs: move from scr
442 if (R2 == IAR)
443 m_gpr[R3] = updated_iar;
444 else
445 m_gpr[R3] = m_scr[R2];
446 m_icount--;
447 break;
448 case 0x97: // setsb: set scr bit
449 set_scr(R2, m_scr[R2] | (0x0000'8000U >> R3));
450 m_icount -= 3;
451 break;
452 case 0x98: // clrbu: clear bit upper half
453 m_gpr[R2] &= ~(0x8000'0000U >> R3);
454 flags(m_gpr[R2]);
455 break;
456 case 0x99: // clrbl: clear bit lower half
457 m_gpr[R2] &= ~(0x0000'8000U >> R3);
458 flags(m_gpr[R2]);
459 break;
460 case 0x9a: // setbu: set bit upper half
461 m_gpr[R2] |= (0x8000'0000U >> R3);
462 flags(m_gpr[R2]);
463 break;
464 case 0x9b: // setbl: set bit lower half
465 m_gpr[R2] |= (0x0000'8000U >> R3);
466 flags(m_gpr[R2]);
467 break;
468 case 0x9c: // mftbiu: move from test bit immediate upper half
469 if (m_scr[CS] & CS_T)
470 m_gpr[R2] |= (0x8000'0000U >> R3);
471 else
472 m_gpr[R2] &= ~(0x8000'0000U >> R3);
473 break;
474 case 0x9d: // mftbil: move from test bit immediate lower half
475 if (m_scr[CS] & CS_T)
476 m_gpr[R2] |= (0x0000'8000U >> R3);
477 else
478 m_gpr[R2] &= ~(0x0000'8000U >> R3);
479 break;
480 case 0x9e: // mttbiu: move to test bit immediate upper half
481 if (m_gpr[R2] & (0x8000'0000U >> R3))
482 m_scr[CS] |= CS_T;
483 else
484 m_scr[CS] &= ~CS_T;
485 break;
486 case 0x9f: // mttbil: move to test bit immediate lower half
487 if (m_gpr[R2] & (0x0000'8000U >> R3))
488 m_scr[CS] |= CS_T;
489 else
490 m_scr[CS] &= ~CS_T;
491 break;
492
493 case 0xa0: // sari: shift algebraic right immediate
494 m_gpr[R2] = s32(m_gpr[R2]) >> R3;
495 flags(m_gpr[R2]);
496 break;
497 case 0xa1: // sari16: shift algebraic right immediate plus sixteen
498 m_gpr[R2] = s32(m_gpr[R2]) >> (R3 + 16);
499 flags(m_gpr[R2]);
500 break;
501
502 case 0xa4: // lis: load immediate short
503 m_gpr[R2] = R3;
504 break;
505
506 case 0xa8: // sri: shift right immediate
507 m_gpr[R2] >>= R3;
508 flags(m_gpr[R2]);
509 break;
510 case 0xa9: // sri16: shift right immediate plus sixteen
511 m_gpr[R2] >>= (R3 + 16);
512 flags(m_gpr[R2]);
513 break;
514 case 0xaa: // sli: shift left immediate
515 m_gpr[R2] <<= R3;
516 flags(m_gpr[R2]);
517 break;
518 case 0xab: // sli16: shift left immediate plus sixteen
519 m_gpr[R2] <<= (R3 + 16);
520 flags(m_gpr[R2]);
521 break;
522 case 0xac: // srpi: shift right paired immediate
523 m_gpr[R2 ^ 1] = m_gpr[R2] >> R3;
524 flags(m_gpr[R2 ^ 1]);
525 break;
526 case 0xad: // srpi16: shift right paired immediate plus sixteen
527 m_gpr[R2 ^ 1] = m_gpr[R2] >> (R3 + 16);
528 flags(m_gpr[R2 ^ 1]);
529 break;
530 case 0xae: // slpi: shift left paired immediate
531 m_gpr[R2 ^ 1] = m_gpr[R2] << R3;
532 flags(m_gpr[R2 ^ 1]);
533 break;
534 case 0xaf: // slpi16: shift left paired immediate plus sixteen
535 m_gpr[R2 ^ 1] = m_gpr[R2] << (R3 + 16);
536 flags(m_gpr[R2 ^ 1]);
537 break;
538
539 case 0xb0: // sar: shift algebraic right
540 m_gpr[R2] = s32(m_gpr[R2]) >> (m_gpr[R3] & 63);
541 flags(m_gpr[R2]);
542 break;
543 case 0xb1: // exts: extend sign
544 m_gpr[R2] = s16(m_gpr[R3]);
545 flags(m_gpr[R2]);
546 break;
547 case 0xb2: // sf: subtract from
548 flags_sub(m_gpr[R3], m_gpr[R2]);
549 m_gpr[R2] = m_gpr[R3] - m_gpr[R2];
550 break;
551 case 0xb3: // cl: compare logical
552 flags(m_gpr[R2] - m_gpr[R3]);
553 break;
554 case 0xb4: // c: compare
555 flags(s32(m_gpr[R2]) - s32(m_gpr[R3]));
556 break;
557 case 0xb5: // mts: move to scr
558 set_scr(R2, m_gpr[R3]);
559 m_icount -= 2;
560 break;
561 //case 0xb6: // d: divide step
562 // m_icount -= 2;
563 case 0xb8: // sr: shift right
564 m_gpr[R2] >>= (m_gpr[R3] & 63);
565 flags(m_gpr[R2]);
566 break;
567 case 0xb9: // srp: shift right paired
568 m_gpr[R2 ^ 1] = m_gpr[R2] >> (m_gpr[R3] & 63);
569 flags(m_gpr[R2 ^ 1]);
570 break;
571 case 0xba: // sl: shift left
572 m_gpr[R2] <<= (m_gpr[R3] & 63);
573 flags(m_gpr[R2]);
574 break;
575 case 0xbb: // slp: shift left paired
576 m_gpr[R2 ^ 1] = m_gpr[R2] << (m_gpr[R3] & 63);
577 flags(m_gpr[R2 ^ 1]);
578 break;
579 case 0xbc: // mftb: move from test bit
580 if (m_scr[CS] & CS_T)
581 m_gpr[R2] |= (0x8000'0000U >> (m_gpr[R3] & 31));
582 else
583 m_gpr[R2] &= ~(0x8000'0000U >> (m_gpr[R3] & 31));
584 break;
585 case 0xbd: // tgte: trap if register greater than or equal
586 if (m_branch_state == BRANCH)
587 program_check(PCS_PCK | PCS_IOC);
588 else if (m_gpr[R2] >= m_gpr[R3])
589 {
590 program_check(PCS_PCK | PCS_PT);
591 m_icount -= 14;
592 }
593 m_icount--;
594 break;
595 case 0xbe: // tlt: trap if register less than
596 if (m_branch_state == BRANCH)
597 program_check(PCS_PCK | PCS_IOC);
598 else if (m_gpr[R2] < m_gpr[R3])
599 {
600 program_check(PCS_PCK | PCS_PT);
601 m_icount -= 14;
602 }
603 m_icount--;
604 break;
605 case 0xbf: // mttb: move to test bit
606 if (m_gpr[R2] & (0x8000'0000U >> (m_gpr[R3] & 31)))
607 m_scr[CS] |= CS_T;
608 else
609 m_scr[CS] &= ~CS_T;
610 break;
611
612 case 0xe0: // abs: absolute
613 if (s32(m_gpr[R3]) < 0)
614 m_gpr[R2] = -s32(m_gpr[R3]);
615 else
616 m_gpr[R2] = m_gpr[R3];
617 m_icount--;
618 // TODO: test for maximum negative
619 // TODO: LT, EQ, GT, C0, OV
620 break;
621 case 0xe1: // a: add
622 flags_add(m_gpr[R2], m_gpr[R3]);
623 m_gpr[R2] += m_gpr[R3];
624 break;
625 case 0xe2: // s: subtract
626 flags_sub(m_gpr[R2], m_gpr[R3]);
627 m_gpr[R2] -= m_gpr[R3];
628 break;
629 case 0xe3: // o: or
630 m_gpr[R2] |= m_gpr[R3];
631 flags(m_gpr[R2]);
632 break;
633 case 0xe4: // twoc: twos complement
634 flags_sub(0, m_gpr[R3]);
635 m_gpr[R2] = -m_gpr[R3];
636 break;
637 case 0xe5: // n: and
638 m_gpr[R2] &= m_gpr[R3];
639 flags(m_gpr[R2]);
640 break;
641 //case 0xe6: // m: multiply step
642 // m_icount -= 3;
643 case 0xe7: // x: exclusive or
644 m_gpr[R2] ^= m_gpr[R3];
645 flags(m_gpr[R2]);
646 break;
647 case 0xe8: // bnbr: branch on not condition bit
648 if (m_branch_state == BRANCH)
649 program_check(PCS_PCK | PCS_IOC);
650 else if (!BIT(m_scr[CS], R2 ^ 15))
651 {
652 m_branch_target = m_gpr[R3] & ~1;
653 m_branch_state = BRANCH;
654 }
655 break;
656 case 0xe9: // bnbrx: branch on not condition bit with execute
657 if (m_branch_state == BRANCH)
658 program_check(PCS_PCK | PCS_IOC);
659 else if (!BIT(m_scr[CS], R2 ^ 15))
660 {
661 m_branch_target = m_gpr[R3] & ~1;
662 m_branch_state = DELAY;
663 }
664 break;
665
666 case 0xeb: // lhs: load half short
667 m_gpr[R2] = space(AS_PROGRAM).read_word(m_gpr[R3]);
668 m_icount -= 4;
669 break;
670 case 0xec: // balr: branch and link
671 if (m_branch_state != BRANCH)
672 {
673 m_gpr[R2] = updated_iar;
674 m_branch_target = m_gpr[R3] & ~1;
675 m_branch_state = BRANCH;
676 m_icount -= 4;
677 }
678 else
679 program_check(PCS_PCK | PCS_IOC);
680 break;
681 case 0xed: // balrx: branch and link with execute
682 if (m_branch_state != BRANCH)
683 {
684 m_gpr[R2] = updated_iar + 4;
685 m_branch_target = m_gpr[R3] & ~1;
686 m_branch_state = DELAY;
687 m_icount -= 4;
688 }
689 else
690 program_check(PCS_PCK | PCS_IOC);
691 break;
692 case 0xee: // bbr: branch on condition bit
693 if (m_branch_state == BRANCH)
694 program_check(PCS_PCK | PCS_IOC);
695 else if (BIT(m_scr[CS], R2 ^ 15))
696 {
697 m_branch_target = m_gpr[R3] & ~1;
698 m_branch_state = BRANCH;
699 m_icount -= 4;
700 }
701 break;
702 case 0xef: // bbrx: branch on condition bit with execute
703 if (m_branch_state == BRANCH)
704 program_check(PCS_PCK | PCS_IOC);
705 else if (BIT(m_scr[CS], R2 ^ 15))
706 {
707 m_branch_target = m_gpr[R3] & ~1;
708 m_branch_state = DELAY;
709 m_icount -= 4;
710 }
711 break;
712
713 //case 0xf0: // wait: wait
714 // if (m_branch_state == BRANCH)
715 // program_check(PCS_PCK | PCS_IOC);
716 case 0xf1: // ae: add extended
717 flags_add(m_gpr[R2], m_gpr[R3] + bool(m_scr[CS] & CS_C));
718 m_gpr[R2] += m_gpr[R3] + bool(m_scr[CS] & CS_C);
719 break;
720 case 0xf2: // se: subtract extended
721 flags_sub(m_gpr[R2], m_gpr[R3] + bool(m_scr[CS] & CS_C));
722 m_gpr[R2] -= m_gpr[R3] + bool(m_scr[CS] & CS_C);
723 break;
724 case 0xf3: // ca16: compute address 16-bit
725 m_gpr[R2] = (m_gpr[R3] & 0xffff'0000U) | (u16(m_gpr[R2]) + u16(m_gpr[R3]));
726 break;
727 case 0xf4: // onec: ones complement
728 m_gpr[R2] = ~m_gpr[R3];
729 flags(m_gpr[R2]);
730 break;
731 case 0xf5: // clz: count leading zeros
732 m_gpr[R2] = count_leading_zeros(u16(m_gpr[R3])) - 16;
733 break;
734
735 case 0xf9: // mc03: move character zero from three
736 m_gpr[R2] = (m_gpr[R2] & 0x00ff'ffffU) | ((m_gpr[R3] & 0x0000'000ffU) << 24);
737 break;
738 case 0xfa: // mc13: move character one from three
739 m_gpr[R2] = (m_gpr[R2] & 0xff00'ffffU) | ((m_gpr[R3] & 0x0000'000ffU) << 16);
740 break;
741 case 0xfb: // mc23: move character two from three
742 m_gpr[R2] = (m_gpr[R2] & 0xffff'00ffU) | ((m_gpr[R3] & 0x0000'000ffU) << 8);
743 break;
744 case 0xfc: // mc33: move character three from three
745 m_gpr[R2] = (m_gpr[R2] & 0xffff'ff00U) | ((m_gpr[R3] & 0x0000'000ffU) << 0);
746 break;
747 case 0xfd: // mc30: move character three from zero
748 m_gpr[R2] = (m_gpr[R2] & 0xffff'ff00U) | u8(m_gpr[R3] >> 24);
749 break;
750 case 0xfe: // mc31: move character three from one
751 m_gpr[R2] = (m_gpr[R2] & 0xffff'ff00U) | u8(m_gpr[R3] >> 16);
752 break;
753 case 0xff: // mc32: move character three from two
754 m_gpr[R2] = (m_gpr[R2] & 0xffff'ff00U) | u8(m_gpr[R3] >> 8);
755 break;
756
757 default:
758 program_check(PCS_PCK | PCS_IOC);
759 break;
760 }
761 break;
762 }
763
764 // update iar and branch state
765 switch (m_branch_state)
766 {
767 case DEFAULT:
768 m_scr[IAR] = updated_iar;
769 break;
770
771 case BRANCH:
772 m_scr[IAR] = m_branch_target;
773 m_branch_state = DEFAULT;
774 break;
775
776 case DELAY:
777 m_scr[IAR] = updated_iar;
778 m_branch_state = BRANCH;
779 break;
780
781 case EXCEPTION:
782 m_branch_state = DEFAULT;
783 break;
784 }
785 }
786 }
787
set_scr(unsigned scr,u32 data)788 void romp_device::set_scr(unsigned scr, u32 data)
789 {
790 static char const *const scr_names[16] =
791 {
792 "scr0", "scr1", "scr2", "scr3", "scr4", "scr5", "cous", "cou",
793 "ts", "scr9", "mq", "mpcs", "irb", "iar", "ics", "cs",
794 };
795
796 LOG("set_scr %s data 0x%08x (%s)\n", scr_names[scr], data, machine().describe_context());
797
798 switch (scr)
799 {
800 case ICS:
801 m_out_tm(bool(data & ICS_TM));
802 break;
803
804 default:
805 break;
806 }
807
808 m_scr[scr] = data;
809 }
810
execute_set_input(int irqline,int state)811 void romp_device::execute_set_input(int irqline, int state)
812 {
813 // interrupt lines are active low
814 if (!state)
815 {
816 m_scr[IRB] |= (IRB_L0 >> irqline);
817
818 // enable debugger interrupt breakpoints
819 standard_irq_callback(irqline);
820 }
821 else
822 m_scr[IRB] &= ~(IRB_L0 >> irqline);
823 }
824
memory_space_config() const825 device_memory_interface::space_config_vector romp_device::memory_space_config() const
826 {
827 return space_config_vector {
828 std::make_pair(AS_PROGRAM, &m_mem_config),
829 std::make_pair(AS_IO, &m_io_config)
830 };
831 }
832
memory_translate(int spacenum,int intention,offs_t & address)833 bool romp_device::memory_translate(int spacenum, int intention, offs_t &address)
834 {
835 return true;
836 }
837
create_disassembler()838 std::unique_ptr<util::disasm_interface> romp_device::create_disassembler()
839 {
840 return std::make_unique<romp_disassembler>();
841 }
842
flags(u32 const data)843 void romp_device::flags(u32 const data)
844 {
845 m_scr[CS] &= ~(CS_L | CS_E | CS_G);
846
847 if (data == 0)
848 m_scr[CS] |= CS_E;
849 else
850 if (BIT(data, 31))
851 m_scr[CS] |= CS_L;
852 else
853 m_scr[CS] |= CS_G;
854 }
855
flags_add(u32 const op1,u32 const op2)856 void romp_device::flags_add(u32 const op1, u32 const op2)
857 {
858 u32 const result = op1 + op2;
859
860 m_scr[CS] &= ~(CS_L | CS_E | CS_G | CS_C | CS_O);
861
862 if (result == 0)
863 m_scr[CS] |= CS_E;
864 else
865 if (BIT(result, 31))
866 m_scr[CS] |= CS_L;
867 else
868 m_scr[CS] |= CS_G;
869
870 // carry
871 if ((BIT(op2, 31) && BIT(op1, 31)) || (!BIT(result, 31) && (BIT(op2, 31) || BIT(op1, 31))))
872 m_scr[CS] |= CS_C;
873
874 // overflow
875 if ((BIT(op2, 31) == BIT(op1, 31)) && (BIT(result, 31) != BIT(op2, 31)))
876 m_scr[CS] |= CS_O;
877 }
878
flags_sub(u32 const op1,u32 const op2)879 void romp_device::flags_sub(u32 const op1, u32 const op2)
880 {
881 u32 const result = op1 - op2;
882
883 m_scr[CS] &= ~(CS_L | CS_E | CS_G | CS_C | CS_O);
884
885 if (result == 0)
886 m_scr[CS] |= CS_E;
887 else
888 if (BIT(result, 31))
889 m_scr[CS] |= CS_L;
890 else
891 m_scr[CS] |= CS_G;
892
893 // carry
894 if ((!BIT(op2, 31) && BIT(op1, 31)) || (BIT(result, 31) && (!BIT(op2, 31) || BIT(op1, 31))))
895 m_scr[CS] |= CS_C;
896
897 // overflow
898 if ((BIT(op2, 31) != BIT(op1, 31)) && (BIT(result, 31) != BIT(op2, 31)))
899 m_scr[CS] |= CS_O;
900 }
901
interrupt_check()902 void romp_device::interrupt_check()
903 {
904 // interrupts masked or no interrupts
905 if ((m_scr[ICS] & ICS_IM) || !(m_scr[IRB] & IRB_ALL))
906 return;
907
908 unsigned const priority = m_scr[ICS] & ICS_PP;
909 for (unsigned irl = 0; irl < priority; irl++)
910 {
911 if (BIT(m_scr[IRB], 15 - irl))
912 {
913 LOGMASKED(LOG_INTERRUPT, "interrupt_check taking interrupt request level %d\n", irl);
914 interrupt_enter(irl);
915
916 break;
917 }
918 }
919 }
920
machine_check(u32 mcs)921 void romp_device::machine_check(u32 mcs)
922 {
923 debugger_exception_hook(7);
924
925 LOGMASKED(LOG_INTERRUPT, "machine_check mcs 0x%08x\n", mcs);
926
927 m_scr[MPCS] &= ~MCS_ALL;
928 m_scr[MPCS] |= (mcs & MCS_ALL);
929
930 interrupt_enter(7);
931
932 m_branch_state = EXCEPTION;
933 }
934
program_check(u32 pcs)935 void romp_device::program_check(u32 pcs)
936 {
937 debugger_exception_hook(8);
938
939 LOGMASKED(LOG_INTERRUPT, "program_check pcs 0x%08x\n", pcs);
940
941 m_scr[MPCS] &= ~PCS_ALL;
942 m_scr[MPCS] |= (pcs & PCS_ALL);
943
944 interrupt_enter(8);
945
946 m_branch_state = EXCEPTION;
947 }
948
interrupt_enter(unsigned vector,u16 svc)949 void romp_device::interrupt_enter(unsigned vector, u16 svc)
950 {
951 // take interrupt
952 offs_t const address = 0x100 + vector * 16;
953
954 // disable address translation
955 m_out_tm(0);
956
957 // save old program status
958 space(AS_PROGRAM).write_dword(address + 0, m_scr[IAR]);
959 space(AS_PROGRAM).write_word(address + 4, u16(m_scr[ICS]));
960 space(AS_PROGRAM).write_word(address + 6, u16(m_scr[CS]));
961 if (vector == 9)
962 space(AS_PROGRAM).write_word(address + 14, svc);
963
964 // load new program status
965 m_scr[IAR] = space(AS_PROGRAM).read_dword(address + 8);
966 m_scr[ICS] = space(AS_PROGRAM).read_word(address + 12);
967 if (vector < 7)
968 m_scr[CS] = space(AS_PROGRAM).read_word(address + 14);
969
970 m_out_tm(bool(m_scr[ICS] & ICS_TM));
971 }
972