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