1 /*
2 * ============================================================================
3 * CP_1600: CP-1600 Main Core
4 *
5 * Author: J. Zbiciak
6 *
7 *
8 * ============================================================================
9 * CP1600_INIT -- Initializes the CP-1600 structure to a basic setup
10 * CP1600_RUN -- Runs the CP1600 for some number of microcycles.
11 * CP1600_RD -- Perform a read from the CP1600 (macro in cp_1600.h)
12 * CP1600_WR -- Perform a write from the CP1600 (macro in cp_1600.h)
13 * ============================================================================
14 *
15 * Notes/To-do:
16 *
17 * -- The CP1600_RD_xxx, CP1600_WR_xxx functions must not be called
18 * directly. Rather, the CP1600_RD, CP1600_WR macros must be used
19 * to assure proper address decoding and dispatch.
20 *
21 * -- The CP1600 supports interrupts but doesn't currently have a method for
22 * receiving them. Peripherals wishing to interrupt the CP1600 need to
23 * somehow set cp1600->intrq to '1' to trigger an interrupt.
24 *
25 * -- The CP1600 supports external branch conditions. Peripherals need to
26 * set cp1600->ext to the appropriate state to trigger these.
27 *
28 * -- SIN, TCI, etc. don't do anything yet. What do they need to do?
29 *
30 * -- Functions should be provided for setting up RAM, ROM images, and
31 * registering peripherals.
32 *
33 * ============================================================================
34 */
35
36
37 #include "config.h"
38 #include "periph/periph.h"
39 #include "cp1600.h"
40 #include "op_decode.h"
41 #include "op_exec.h"
42 #include "emu_link.h"
43 #include <limits.h>
44
45
46 LOCAL void cp1600_dtor(periph_t *const p);
47 LOCAL void cp1600_rand_regs(cp1600_t *const cp1600);
48
49 /*
50 * ============================================================================
51 * CP1600_INIT -- Initializes a CP1600_T structure
52 *
53 * This function sets up a basic CP1600 structure. It allocates a local "flat
54 * memory" which corresponds to the CP-1600 memory map, and it sets up the
55 * initial state of the instruction decoder logic.
56 *
57 * When it's finished, the CP1600 structure is configured to *not* have any
58 * memory deviced enabled at all. Calls to "CP1600_ADD_xxx" should be issued
59 * to configure the memory map as appropriate.
60 * ============================================================================
61 */
62
cp1600_init(cp1600_t * const cp1600,uint16_t const rst_vec,uint16_t const int_vec,bool const rand_mem)63 int cp1600_init
64 (
65 cp1600_t *const cp1600,
66 uint16_t const rst_vec,
67 uint16_t const int_vec,
68 bool const rand_mem
69 )
70 {
71 /* -------------------------------------------------------------------- */
72 /* Avoid problems with a garbage cp1600 structure by setting it to */
73 /* all-bits-zero. Note: This could be a portability problem to */
74 /* machines which represent NULL pointers as something other than */
75 /* all-bits-zero, but what interesting modern machines do that? */
76 /* -------------------------------------------------------------------- */
77 memset((void*)cp1600, 0, sizeof(cp1600_t));
78
79 /* -------------------------------------------------------------------- */
80 /* Set up our interrupt and reset vectors. */
81 /* -------------------------------------------------------------------- */
82 cp1600->r[7] = rst_vec;
83 cp1600->int_vec = int_vec;
84
85 /* -------------------------------------------------------------------- */
86 /* Initially not single-stepping. */
87 /* -------------------------------------------------------------------- */
88 cp1600->step_count = 0;
89 cp1600->steps_remaining = 0;
90
91 /* -------------------------------------------------------------------- */
92 /* Nothing hooked to the request queue initially. */
93 /* -------------------------------------------------------------------- */
94 req_q_init(&cp1600->req_q);
95
96 /* -------------------------------------------------------------------- */
97 /* Set the entire memory map to not-cacheable. */
98 /* -------------------------------------------------------------------- */
99 /* TODO: */
100 /* Outside routines will need to configure the memory map to make the */
101 /* CP1600 useful. :-) It is especially important to set the */
102 /* cacheable bits for performance. */
103 /* -------------------------------------------------------------------- */
104 for (unsigned i = 0;
105 i < (1u << (CP1600_MEMSIZE - CP1600_DECODE_PAGE - 5)); i++)
106 {
107 cp1600->cacheable[i] = 0;
108 }
109
110 /* -------------------------------------------------------------------- */
111 /* Mark all instructions as needing decode. The fn_decode function */
112 /* will cache the decoded instruction if the "cacheable" bit is set */
113 /* for the page containing the instruction. */
114 /* -------------------------------------------------------------------- */
115 for (unsigned i = 0; i < (1u << CP1600_MEMSIZE); i++)
116 {
117 cp1600->execute[i] = fn_decode_1st;
118 }
119
120 /* -------------------------------------------------------------------- */
121 /* If randomizing, initialize the registers and flags to garbage. */
122 /* -------------------------------------------------------------------- */
123 cp1600->rand_mem = rand_mem;
124 if (rand_mem)
125 cp1600_rand_regs(cp1600);
126
127 /* -------------------------------------------------------------------- */
128 /* Start with a pending reset. */
129 /* -------------------------------------------------------------------- */
130 cp1600->pend_reset = true;
131
132 /* -------------------------------------------------------------------- */
133 /* Set up the CP-1600 as a peripheral. */
134 /* -------------------------------------------------------------------- */
135 cp1600->periph.read = NULL;
136 cp1600->periph.write = NULL;
137 cp1600->periph.peek = NULL;
138 cp1600->periph.poke = NULL;
139 cp1600->periph.reset = cp1600_reset;
140 cp1600->periph.tick = cp1600_run;
141 cp1600->periph.min_tick = 1;
142 cp1600->periph.max_tick = 4;
143 cp1600->periph.dtor = cp1600_dtor;
144
145 cp1600->snoop.read = NULL;
146 cp1600->snoop.write = cp1600_write; /* Bus snoop for cache inval. */
147 cp1600->snoop.peek = NULL;
148 cp1600->snoop.poke = cp1600_write; /* Bus snoop for cache inval. */
149 cp1600->snoop.addr_base = 0;
150 cp1600->snoop.addr_mask = 0xFFFF;
151 cp1600->snoop.tick = NULL;
152 cp1600->snoop.min_tick = 0;
153 cp1600->snoop.max_tick = ~0U;
154 cp1600->snoop.parent = (void*)cp1600;
155 cp1600->snoop.dtor = NULL;
156 return 0;
157 }
158
159 /*
160 * ============================================================================
161 * CP1600_RESET -- Reset the CP1060
162 * ============================================================================
163 */
cp1600_reset(periph_t * const p)164 void cp1600_reset(periph_t *const p)
165 {
166 cp1600_t *const cp1600 = PERIPH_AS(cp1600_t, p);
167 cp1600->pend_reset = true;
168 }
169
170 /*
171 * ============================================================================
172 * CP1600_RUN -- Runs the CP1600 for some number of microcycles
173 *
174 * This is the main CP1600 loop. It is responsible for fetching instructions,
175 * decoding them if necessary (or using predecoded instructions if possible)
176 * and calling the required execute functions.
177 *
178 * The cp1600_run function will run as many instructions as are necessary to
179 * just barely exceed the specified number of microcycles. eg. It will
180 * execute a new instruction if the specified total number of microcycles
181 * has not yet been exceeded. The new instruction may exceed the specified
182 * number of microcycles. The total number of microcycles exhausted is
183 * returned as an int.
184 * ============================================================================
185 */
cp1600_run(periph_t * const periph,uint32_t const microcycles)186 uint32_t cp1600_run
187 (
188 periph_t *const periph,
189 uint32_t const microcycles
190 )
191 {
192 cp1600_t *const RESTRICT cp1600 = PERIPH_AS(cp1600_t, periph);
193 periph_tick_t *const instr_tick = cp1600->instr_tick;
194 req_q_t *const RESTRICT req_q = &cp1600->req_q;
195 uint64_t const orig_now = cp1600->periph.now;
196 uint64_t now = cp1600->periph.now;
197 uint64_t const future =
198 now + microcycles > req_q->horizon ? req_q->horizon
199 : now + microcycles;
200 uint64_t actual_microcycles = 0;
201 //printf("cp1600_run %u\n", microcycles);
202 /* -------------------------------------------------------------------- */
203 /* Initially, we're not stopped at any sort of breakpoint. */
204 /* -------------------------------------------------------------------- */
205 cp1600->hit_breakpoint = BK_NONE;
206
207 /* -------------------------------------------------------------------- */
208 /* Iterate until we've run out of microcycles. We can slightly */
209 /* exceed our target. */
210 /* -------------------------------------------------------------------- */
211 while (now < future)
212 {
213 const req_t req = REQ_Q_FRONT(req_q);
214 const int req_valid = REQ_Q_SIZE(req_q) != 0 &&
215 req.state == REQ_PENDING;
216 const int in_req_span = req_valid && req.start <= now && now < req.end;
217 const int in_busrq_span = in_req_span && req.type == REQ_BUS;
218 const int in_intrq_span = in_req_span && req.type == REQ_INT;
219 const int before_req_span = req_valid && now < req.start;
220 const int after_req_span = req_valid && now >= req.end;
221 uint32_t pc = cp1600->r[7];
222 uint64_t near_future = future;
223 int cycles = 0;
224 int instrs = 0;
225
226 /* ---------------------------------------------------------------- */
227 /* If we have a pending reset, handle it now. */
228 /* ---------------------------------------------------------------- */
229 if (cp1600->pend_reset)
230 {
231 /* Registers don't get reset by ~MSYNC, but they can be random. */
232 if (cp1600->rand_mem)
233 cp1600_rand_regs(cp1600);
234
235 cp1600->r[7] = 0x1000;
236 cp1600->intr = 0;
237 cp1600->pend_reset = false;
238
239 /* 5 dead cycles after ~MSYNC deasserts. */
240 /* Ref: Microproc Users Manual, page 27. */
241 /* Do zero cycles on first reset. */
242 cycles = now ? 5 : 0;
243 now += cycles;
244
245 if (cp1600->steps_remaining > 0)
246 cp1600->steps_remaining--;
247
248 cp1600->tot_instr++; /* treat reset as a phony instruction */
249
250 goto do_instr_tick;
251 }
252
253 assert(!(before_req_span && in_req_span ));
254 assert(!(in_req_span && after_req_span));
255 assert(!(before_req_span && after_req_span));
256
257 /* ---------------------------------------------------------------- */
258 /* Update our INTRQ/BUSRQ flags, in case debugger is watching. */
259 /* ---------------------------------------------------------------- */
260 cp1600->req_ack_state = (in_busrq_span ? CP1600_BUSRQ : 0)
261 | (in_intrq_span ? CP1600_INTRQ : 0);
262
263 /* ---------------------------------------------------------------- */
264 /* Determine if we need to respond to a bus request. */
265 /* ---------------------------------------------------------------- */
266 if (in_busrq_span && CP1600_CAN_BUSAK(cp1600))
267 {
268 cp1600->req_ack_state |= CP1600_BUSAK;
269 cycles = (int)(req.end - now);
270 req_q->ack(req_q, now);
271 now = req.end;
272 REQ_Q_POP(req_q);
273 goto do_instr_tick;
274 }
275
276 /* ---------------------------------------------------------------- */
277 /* Determine if we need to respond to an interrupt request. */
278 /* ---------------------------------------------------------------- */
279 if (in_intrq_span && CP1600_CAN_INTAK(cp1600))
280 {
281 cp1600->req_ack_state |= CP1600_INTAK;
282
283 /* ------------------------------------------------------------ */
284 /* The CPU goes 'dead' for 2 cycles before INTAK. */
285 /* ------------------------------------------------------------ */
286 now += 2;
287 req_q->ack(req_q, now);
288 REQ_Q_POP(req_q);
289
290 /* ------------------------------------------------------------ */
291 /* Then the CPU writes out the current PC at the top of stack. */
292 /* ------------------------------------------------------------ */
293 cp1600->periph.now = now;
294 CP1600_WR(cp1600, cp1600->r[6], cp1600->r[7]);
295 cp1600->r[6]++;
296
297 /* ------------------------------------------------------------ */
298 /* 10 more cycles pass across INTAK, DW, DWS, IAB, until we */
299 /* finally get to the first BAR of associated with the ISR. */
300 /* ------------------------------------------------------------ */
301 now += 10;
302 cp1600->r[7] = pc = cp1600->int_vec;
303
304 cycles = 12;
305 goto do_instr_tick;
306 }
307
308 /* ---------------------------------------------------------------- */
309 /* If we make it to here, either we are not in a request span, or */
310 /* we could not acknowledge the request type presented to us. */
311 /* ---------------------------------------------------------------- */
312 assert(!in_req_span || !CP1600_CAN_INTAK(cp1600)
313 || !CP1600_CAN_BUSAK(cp1600));
314
315 /* ---------------------------------------------------------------- */
316 /* If we've gone past a request span, pop it off and loop. We */
317 /* may have blown through a BUSRQ or INTRQ. Ooopsie! :D */
318 /* ---------------------------------------------------------------- */
319 if (after_req_span)
320 {
321 req_q->drop(req_q, now);
322 REQ_Q_POP(req_q);
323 /* Go back to the top of the loop to look at next req, if any. */
324 continue;
325 }
326
327 /* ---------------------------------------------------------------- */
328 /* Handle step requests. */
329 /* ---------------------------------------------------------------- */
330 if (cp1600->steps_remaining == 0)
331 cp1600->steps_remaining = cp1600->step_count;
332
333 /* ---------------------------------------------------------------- */
334 /* Attempt to execute as many instructions as possible in a tight */
335 /* loop. We will only execute up until the next request boundary */
336 /* or instruction-step boundary. Also, if an instruction happens */
337 /* to be a breakpoint, we'll exit early. */
338 /* ---------------------------------------------------------------- */
339 /* If we're before a new request span, run up to the edge of it. */
340 if (before_req_span && near_future > req.start)
341 near_future = req.start;
342
343 /* If we're *in* a request span, run for 1 instruction. */
344 if (in_req_span)
345 near_future = now + 1;
346
347 while (now < near_future)
348 {
349 /* ------------------------------------------------------------ */
350 /* Grab our execute function and instruction pointer. */
351 /* ------------------------------------------------------------ */
352 cp1600_ins_t *const execute = cp1600->execute[pc];
353 instr_t *instr = cp1600->instr[pc];
354 cp1600->periph.now = now;
355 cp1600->oldpc = pc;
356
357 /* ------------------------------------------------------------ */
358 /* The flag cp1600->intr is our interruptibility state. It is */
359 /* set equal to our interrupt enable bit, and is cleared by */
360 /* non-interruptible instructions, thus making it a "logical- */
361 /* AND" of the two conditions. */
362 /* ------------------------------------------------------------ */
363 cp1600->intr = (cp1600->I ? CP1600_INT_ENABLE : 0)
364 | CP1600_INT_INSTR;
365
366 /* ------------------------------------------------------------ */
367 /* Execute the next instruction, and record its cycle count */
368 /* and new PC value. Count-down the DBD state. */
369 /* ------------------------------------------------------------ */
370 cycles = execute(instr, cp1600);
371 pc = cp1600->r[7];
372 cp1600->D >>= 1;
373
374 /* ------------------------------------------------------------ */
375 /* Tally up instruction count and microcycle count. */
376 /* ------------------------------------------------------------ */
377 if (cycles == CYC_MAX)
378 {
379 /* Re-fetch instr in case execute() changed it on us. */
380 instr = cp1600->instr[cp1600->oldpc];
381
382 /* Halt and in-the-weeds still advance clock and instr cnt. */
383 if (instr->opcode.breakpt.cycles)
384 {
385 instrs++;
386 now += instr->opcode.breakpt.cycles;
387 }
388 cycles = -1;
389 break;
390 }
391 now += cycles;
392 instrs++;
393
394 /* ------------------------------------------------------------ */
395 /* Handle instruction step counter. */
396 /* ------------------------------------------------------------ */
397 if (cp1600->steps_remaining > 0 && !--cp1600->steps_remaining)
398 break;
399 }
400
401 /* ---------------------------------------------------------------- */
402 /* Accumulate instructions. */
403 /* ---------------------------------------------------------------- */
404 cp1600->tot_instr += instrs;
405
406 /* ---------------------------------------------------------------- */
407 /* If we have an "instruction tick" function registered, */
408 /* go run it. This is usually the debugger. */
409 /* ---------------------------------------------------------------- */
410 do_instr_tick:
411 cp1600->periph.now = now;
412 if (instr_tick &&
413 instr_tick(cp1600->instr_tick_periph, cycles) == CYC_MAX)
414 return CYC_MAX;
415 }
416
417 /* -------------------------------------------------------------------- */
418 /* Back out our updates to periph.now and move them to tot_cycles. */
419 /* We back them out because periph_tick will add them back in. */
420 /* Crappy software architecture is crappy... */
421 /* -------------------------------------------------------------------- */
422 actual_microcycles = now - orig_now;
423 cp1600->tot_cycle += actual_microcycles;
424 cp1600->periph.now = orig_now;
425
426 /* -------------------------------------------------------------------- */
427 /* Update our max_tick to account for our ever-shifting sim horizon. */
428 /* -------------------------------------------------------------------- */
429 if (now >= req_q->horizon)
430 {
431 cp1600->periph.min_tick = 1;
432 cp1600->periph.max_tick = 1;
433 } else
434 {
435 cp1600->periph.min_tick = 1;
436 cp1600->periph.max_tick = req_q->horizon - now;
437 }
438 //printf("max_tick=%llu horizon=%llu now=%llu\n", (unsigned long long)cp1600->periph.max_tick, (unsigned long long)req_q->horizon, (unsigned long long)now);
439
440 /* -------------------------------------------------------------------- */
441 /* Return how long we ran for. */
442 /* -------------------------------------------------------------------- */
443 return actual_microcycles;
444 }
445
446 /*
447 * ============================================================================
448 * CP1600_CACHEABLE -- Marks a region of instruction space as
449 * cacheable in the decoder, so that we can cache
450 * the decoded instructions. It doesn't actually
451 * trigger the decode of the instructions though.
452 * ============================================================================
453 */
cp1600_cacheable(cp1600_t * const cp1600,uint32_t const addr_lo,uint32_t const addr_hi,int const need_snoop)454 void cp1600_cacheable
455 (
456 cp1600_t *const cp1600,
457 uint32_t const addr_lo,
458 uint32_t const addr_hi,
459 int const need_snoop
460 )
461 {
462 /* -------------------------------------------------------------------- */
463 /* First, pull in addresses at either end of range. If address range */
464 /* doesn't span full decode pages at the ends, then don't include the */
465 /* pages at the ends of the range. */
466 /* -------------------------------------------------------------------- */
467 const uint32_t page_mask = (1u << CP1600_DECODE_PAGE) - 1;
468 const uint32_t r_addr_lo = (addr_lo + page_mask) & ~page_mask;
469 const uint32_t r_addr_hi = ((addr_hi + page_mask + 1) & ~page_mask) - 1;
470
471 if (r_addr_hi < r_addr_lo)
472 return;
473
474 /* -------------------------------------------------------------------- */
475 /* Now, step through all of the addresses and mark the instructions */
476 /* cacheable. */
477 /* -------------------------------------------------------------------- */
478 for (uint32_t addr = r_addr_lo; addr <= r_addr_hi;
479 addr += 1u << CP1600_DECODE_PAGE)
480 {
481 cp1600->cacheable[addr >> (CP1600_DECODE_PAGE + 5)] |=
482 1u << ((addr >> CP1600_DECODE_PAGE) & 31);
483 }
484
485 /* -------------------------------------------------------------------- */
486 /* If this memory range needs snooping (eg. is writable), inform the */
487 /* peripheral subsystem that the CP-1610 is interested in seeing */
488 /* memory events in these regions, since it now considers these */
489 /* locations to be cacheable. */
490 /* -------------------------------------------------------------------- */
491 if (need_snoop)
492 periph_register(cp1600->periph.bus, &cp1600->snoop,
493 r_addr_lo, r_addr_hi, "CP-1610 Snoop");
494 }
495
496 /*
497 * ============================================================================
498 * CP1600_INVALIDATE -- Invalidates a region of cached instructions.
499 * ============================================================================
500 */
cp1600_invalidate(cp1600_t * const cp1600,uint32_t const addr_lo,uint32_t const addr_hi)501 void cp1600_invalidate
502 (
503 cp1600_t *const cp1600,
504 uint32_t const addr_lo,
505 uint32_t const addr_hi
506 )
507 {
508 /* -------------------------------------------------------------------- */
509 /* Step through all of the addresses and mark the instructions for */
510 /* decode. */
511 /* -------------------------------------------------------------------- */
512 for (uint32_t addr = addr_lo; addr <= addr_hi; addr ++)
513 {
514 if (cp1600->execute[addr] != fn_breakpt)
515 cp1600->execute[addr] = fn_decode;
516 cp1600->disasm[addr] = NULL;
517 }
518 }
519
520 /*
521 * ============================================================================
522 * CP1600_WRITE -- Snoops bus writes and invalidates its cache.
523 * ============================================================================
524 */
cp1600_write(periph_t * const per,periph_t * const req,uint32_t const addr,uint32_t const data)525 void cp1600_write
526 (
527 periph_t *const per, /* Peripheral being written to. */
528 periph_t *const req, /* Peripheral requesting the write. */
529 uint32_t const addr, /* Address being written. */
530 uint32_t const data /* Data being written. */
531 )
532 {
533 cp1600_t *const cp1600 = PERIPH_PARENT_AS(cp1600_t, per);
534 const uint32_t a0 = 0xFFFF & (addr - 2);
535 const uint32_t a1 = 0xFFFF & (addr - 1);
536 const uint32_t a2 = 0xFFFF & (addr - 0);
537 const uint32_t a3 = 0xFFFF & (addr + 1);
538
539 UNUSED(req);
540 UNUSED(data);
541
542 /* -------------------------------------------------------------------- */
543 /* Step through "addr - 2" to "addr + 1" to invalidate. */
544 /* -------------------------------------------------------------------- */
545 if (cp1600->execute[a0] != fn_breakpt) cp1600->execute[a0] = fn_decode;
546 if (cp1600->execute[a1] != fn_breakpt) cp1600->execute[a1] = fn_decode;
547 if (cp1600->execute[a2] != fn_breakpt) cp1600->execute[a2] = fn_decode;
548 if (cp1600->execute[a3] != fn_breakpt) cp1600->execute[a3] = fn_decode;
549
550 cp1600->disasm[a0] = NULL;
551 cp1600->disasm[a1] = NULL;
552 cp1600->disasm[a2] = NULL;
553 cp1600->disasm[a3] = NULL;
554 }
555
556 /*
557 * ============================================================================
558 * CP1600_INSTR_TICK -- Sets/unsets an per-instruction ticker
559 *
560 * Note: I may eventually split cp1600_run into two flavors that vary
561 * depending on whether or not I have an instr_tick function registered.
562 * ============================================================================
563 */
cp1600_instr_tick(cp1600_t * const cp1600,periph_tick_t * const instr_tick,periph_t * const instr_tick_periph)564 void cp1600_instr_tick
565 (
566 cp1600_t *const cp1600,
567 periph_tick_t *const instr_tick,
568 periph_t *const instr_tick_periph
569 )
570 {
571 cp1600->instr_tick = instr_tick;
572 cp1600->instr_tick_periph = instr_tick_periph;
573 }
574
575 /*
576 * ============================================================================
577 * CP1600_SET_BREAKPT -- Sets a breakpoint at a given address.
578 * CP1600_SET_TRACEPT -- Like a breakpoint, except it resets itself
579 *
580 * Note: Instructions which overlap a breakpoint address but don't start
581 * at the breakpoint address won't trigger the breakpoint.
582 * ============================================================================
583 */
cp1600_set_breakpt(cp1600_t * const cp1600,uint16_t const addr,uint16_t const flags)584 int cp1600_set_breakpt
585 (
586 cp1600_t *const cp1600,
587 uint16_t const addr,
588 uint16_t const flags
589 )
590 {
591 const int was_bkpt = (cp1600->execute[addr] == fn_decode_bkpt ||
592 cp1600->execute[addr] == fn_breakpt);
593
594 if (!cp1600->instr[addr])
595 cp1600->instr[addr] = get_instr();
596
597 cp1600->instr[addr]->opcode.breakpt.flags |= flags;
598
599 cp1600->execute[addr] = addr == cp1600->r[7] ? fn_decode_bkpt : fn_breakpt;
600
601 return was_bkpt;
602 }
603
604 /*
605 * ============================================================================
606 * CP1600_CLR_BREAKPT -- Clears a breakpoint at a given address.
607 * ============================================================================
608 */
cp1600_clr_breakpt(cp1600_t * const cp1600,uint16_t const addr,uint16_t const flags)609 void cp1600_clr_breakpt
610 (
611 cp1600_t *const cp1600,
612 uint16_t const addr,
613 uint16_t const flags
614 )
615 {
616 if (cp1600->execute[addr] != fn_breakpt &&
617 cp1600->execute[addr] != fn_decode_bkpt)
618 return;
619
620 if (!cp1600->instr[addr])
621 return;
622
623 cp1600->instr[addr]->opcode.breakpt.flags &= ~flags;
624
625 if (!cp1600->instr[addr]->opcode.breakpt.flags)
626 cp1600->execute[addr] = fn_decode;
627 }
628
629 /*
630 * ============================================================================
631 * CP1600_LIST_BREAKPTS -- Lists all matching breakpoints via callback.
632 * ============================================================================
633 */
cp1600_list_breakpts(const cp1600_t * const cp1600,uint16_t const flags,cp1600_addr_callback_fn * const callback,void * const opaque)634 void cp1600_list_breakpts
635 (
636 const cp1600_t *const cp1600,
637 uint16_t const flags,
638 cp1600_addr_callback_fn *const callback,
639 void *const opaque
640 )
641 {
642 uint32_t addr;
643
644 for (addr = 0; addr <= 0xFFFF; addr++)
645 {
646 if (!cp1600->instr[addr])
647 continue;
648
649 const uint32_t instr_flags = cp1600->instr[addr]->opcode.breakpt.flags;
650 if ((instr_flags & flags) == flags)
651 {
652 callback(opaque, addr);
653 }
654 }
655 }
656
657 /*
658 * ============================================================================
659 * CP1600_DTOR -- Destructor for a cp1600_t
660 * ============================================================================
661 */
cp1600_dtor(periph_t * const p)662 LOCAL void cp1600_dtor(periph_t *const p)
663 {
664 cp1600_t *const cp1600 = PERIPH_AS(cp1600_t, p);
665
666 for (uint32_t addr = 0; addr <= 0xFFFF; addr++)
667 {
668 if (cp1600->instr[addr])
669 {
670 put_instr(cp1600->instr[addr]);
671 cp1600->instr[addr] = NULL;
672 }
673 }
674
675 emu_link_dtor();
676 }
677
678 /*
679 * ============================================================================
680 * CP1600_RAND_REGS -- Randomize the register file.
681 * ============================================================================
682 */
cp1600_rand_regs(cp1600_t * const cp1600)683 LOCAL void cp1600_rand_regs(cp1600_t *const cp1600)
684 {
685 for (int i = 0; i < 7; i++)
686 cp1600->r[i] = rand_jz();
687
688 uint32_t flags = rand_jz();
689 cp1600->S = !!(flags & 1);
690 cp1600->C = !!(flags & 2);
691 cp1600->O = !!(flags & 4);
692 cp1600->Z = !!(flags & 8);
693 cp1600->I = !!(flags & 16);
694 cp1600->D = !!(flags & 32);
695 }
696
697 /* ======================================================================== */
698 /* This program is free software; you can redistribute it and/or modify */
699 /* it under the terms of the GNU General Public License as published by */
700 /* the Free Software Foundation; either version 2 of the License, or */
701 /* (at your option) any later version. */
702 /* */
703 /* This program is distributed in the hope that it will be useful, */
704 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
705 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
706 /* General Public License for more details. */
707 /* */
708 /* You should have received a copy of the GNU General Public License along */
709 /* with this program; if not, write to the Free Software Foundation, Inc., */
710 /* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
711 /* ======================================================================== */
712 /* Copyright (c) 1998-2018, Joseph Zbiciak */
713 /* ======================================================================== */
714