typo, missing semicolon
[dcpu16] / dcpu16.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <assert.h>
8 #include <sysexits.h>
9
10 #include "dcpu16.h"
11
12 /*
13 * emulates the DCPU16 system from http://0x10c.com/doc/dcpu-16.txt
14 * currently emulates '1.7' spec from http://pastebin.com/Q4JvQvnM
15 *
16 * I couldn't remember ever implementing an emulator before, so this
17 * happened. As such, consider this a toy in progress.
18 * There are likely many improvable aspects.
19 *
20 * Justin Wind <justin.wind@gmail.com>
21 * 2012 04 05 - implementation started
22 * 2012 05 05 - start of v1.7 revisions
23 * 2012 05 08 - v1.7 revisions mostly complete
24 *
25 * TODO
26 * !! v1.7 bit-shift and signed opcodes need to be reviewed/finished
27 * !! v1.7 hardware interface needs to be finished
28 * !! v1.7 interrupts need to be finished
29 * change api to print into buffers rather than stdio
30 * let callbacks determine whether to override events, or just observe
31 * sort init callbacks by base addr, to call in-order
32 * make all callbacks register addr range of interest
33 */
34
35 static const char * const src_id_ = "$Id$";
36
37 #define OPCODE_BASIC_BITS 5
38 #define OPCODE_OPERAND_B_BITS 5
39 #define OPCODE_OPERAND_A_BITS 6
40
41 const char * const dcpu16_reg_names[] = {
42 "A",
43 "B",
44 "C",
45 "X",
46 "Y",
47 "Z",
48 "I",
49 "J",
50 "PC",
51 "SP",
52 "EX",
53 "IA",
54 NULL
55 };
56
57 static void printf_null_(char *fmt, ...) { (void)fmt; }
58
59 /* some default warning and debug reporting functions, which can be overridden by clients */
60 #define WARN(...) do { if (warn_cb_) warn_cb_(__VA_ARGS__); } while (0)
61 static inline void warn_(char *fmt, ...) __attribute__((format(printf, 1, 2)));
62 static inline
63 void warn_(char *fmt, ...) {
64 va_list ap;
65
66 fprintf(stderr, "[warning] ");
67 va_start(ap, fmt);
68 vfprintf(stderr, fmt, ap);
69 va_end(ap);
70 fprintf(stderr, "\n");
71 fflush(stderr);
72 }
73 static void (*warn_cb_)(char *fmt, ...) = warn_;
74 void dcpu16_warn_cb_set(void (*fn)(char *fmt, ...)) {
75 if (fn)
76 warn_cb_ = fn;
77 else
78 warn_cb_ = printf_null_;
79 }
80
81 #ifdef DEBUG
82 #define TRACE(...) do { if (trace_cb_) trace_cb_(__VA_ARGS__); } while (0)
83 static inline void trace_(char *fmt, ...) __attribute__((format(printf, 1, 2)));
84 static inline
85 void trace_(char *fmt, ...) {
86 va_list ap;
87
88 fprintf(stdout, "[debug] ");
89 va_start(ap, fmt);
90 vfprintf(stdout, fmt, ap);
91 va_end(ap);
92 fprintf(stdout, "\n");
93 fflush(stdout);
94 }
95 #else /* DEBUG */
96 #define TRACE(...) do {} while(0)
97 #endif /* DEBUG */
98 static void (*trace_cb_)(char *fmt, ...) =
99 #ifdef DEBUG
100 trace_
101 #else /* DEBUG */
102 NULL
103 #endif
104 ;
105 void dcpu16_trace_cb_set(void (*fn)(char *fmt, ...)) {
106 if (fn)
107 trace_cb_ = fn;
108 else
109 trace_cb_ = printf_null_;
110 }
111
112
113 /* acct_event_
114 * invokes callbacks for specified event
115 */
116 static inline
117 void acct_event_(struct dcpu16 *vm, dcpu16_acct_event ev, DCPU16_WORD addr) {
118 struct dcpu16_acct_cb *cb = vm->cb_table_;
119 size_t i;
120
121 for (i = 0; i < vm->cb_table_entries_; i++) {
122 if ( (cb[i].mask & ev) )
123 if (addr >= cb[i].addr_l && addr <= cb[i].addr_h)
124 cb[i].fn(vm, ev, addr, cb[i].data);
125 }
126 }
127
128
129 /* add an entry to the interrupt queue */
130 static
131 int interrupt_enqueue_(struct dcpu16 *vm, DCPU16_WORD message) {
132 vm->interrupts_[vm->interrupts_tail_] = message;
133 vm->interrupts_tail_ += 1;
134 vm->interrupts_tail_ %= DCPU16_INTERRUPT_QUEUE_SIZE;
135
136 if (vm->interrupts_tail_ == vm->interrupts_head_) {
137 vm->on_fire_ = 1;
138 WARN("interrupt queue overflow (system is now on fire)");
139 return -1;
140 }
141
142 return 0;
143 }
144
145 static
146 DCPU16_WORD interrupt_dequeue_(struct dcpu16 *vm) {
147 DCPU16_WORD message;
148
149 if (vm->interrupts_tail_ == vm->interrupts_head_) {
150 WARN("interrupt underflow");
151 return 0;
152 }
153
154 message = vm->interrupts_[vm->interrupts_head_];
155 vm->interrupts_head_ += 1;
156 vm->interrupts_head_ %= DCPU16_INTERRUPT_QUEUE_SIZE;
157
158 return message;
159 }
160
161 inline
162 void dcpu16_cycle_inc(struct dcpu16 *vm, unsigned int n) {
163 size_t i;
164
165 while (n--) {
166 /* new cycle */
167 vm->cycle_ += 1;
168 TRACE("%s>> starting cycle %llu", vm->cycle_);
169
170 /* signal interested cycle hooks */
171 acct_event_(vm, DCPU16_ACCT_EV_CYCLE, vm->reg[DCPU16_REG_PC]);
172
173 /* signal attached hardware */
174 for (i = 0; i < vm->hw_table_entries_; i++) {
175 TRACE("%s>> notifying %s", __func__, vm->hw_table_[i].mod->name_);
176 if (vm->hw_table_[i].mod->cycle)
177 vm->hw_table_[i].mod->cycle(vm, &vm->hw_table_[i]);
178 }
179 }
180 }
181
182 /* value_decode_
183 * sets *v to be the address of the represented value
184 * value_is_a is 0 for b, 1 for a, alters behavior of some operands
185 * value_data is 'nextword' for this operand, ignored if unused
186 * workv is buffer to use to accumulate literal value into, before use. one exists for either potential instruction operand
187 * e_addr is set to a referenced address, for accounting callback
188 * pc_adjust is set to how to change the program counter
189 * stack_adjust is set to how to change the stack pointer
190 * cycle_adjust is set to number of cycles spent looking up operand
191 *
192 * zero all adjustables before decoding first operand, and pass in these values when
193 * decoding next operand..
194 *
195 */
196 #define EWHAT_NONE (0)
197 #define EWHAT_REG (1<<1)
198 #define EWHAT_RAM (1<<2)
199 static inline
200 void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a, DCPU16_WORD value_data,
201 DCPU16_WORD *work_v, DCPU16_WORD **v, DCPU16_WORD *e_addr, enum dcpu16_register_indexes *e_reg, unsigned int *e_what,
202 short *pc_adjust, short *sp_adjust, unsigned int *cycle_adjust) {
203 assert(value <= 0x3f);
204
205 DCPU16_WORD pc = (DCPU16_WORD)(vm->reg[DCPU16_REG_PC] + *pc_adjust),
206 sp = (DCPU16_WORD)(vm->reg[DCPU16_REG_SP] + *sp_adjust);
207
208 (void)pc;
209 TRACE("%s>> is_a:%u pc:0x%04x sp:0x%04x value_data:0x%04x\n",
210 __func__,
211 value_is_a,
212 pc,
213 sp,
214 value_data);
215
216 if (value <= 0x07) { /* register */
217 *e_what = EWHAT_REG;
218 *e_reg = value & 0x07;
219 *v = vm->reg + *e_reg;
220 TRACE("%s>> %s (0x%04x)",
221 __func__,
222 dcpu16_reg_names[value],
223 **v);
224 return;
225 }
226
227 if (value <= 0x0f) { /* [register] */
228 *e_what = EWHAT_RAM;
229 *e_addr = vm->reg[value & 0x07];
230 *v = &(vm->ram[ *e_addr ]);
231 acct_event_(vm, DCPU16_ACCT_EV_REG_READ, value & 0x07);
232 TRACE("%s>> [%s] [0x%04x] (0x%04x)",
233 __func__,
234 dcpu16_reg_names[value & 0x07],
235 vm->reg[value & 0x07],
236 **v);
237 return;
238 }
239
240 if (value <= 0x17) { /* [next word + register] */
241 acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_PC);
242 *pc_adjust += 1; /* consume next word */
243 *cycle_adjust += 1;
244 *e_what = EWHAT_RAM;
245 *e_addr = value_data + vm->reg[value & 0x07];
246 acct_event_(vm, DCPU16_ACCT_EV_REG_READ, value & 0x07);
247 *v = vm->ram + *e_addr;
248 TRACE("%s>> [nextword + %s] [0x%04x + 0x%04x] (0x%04x)",
249 __func__,
250 dcpu16_reg_names[value & 0x07],
251 value_data,
252 vm->reg[value & 0x07],
253 **v);
254 return;
255 }
256
257 switch (value) {
258 case 0x18: /* PUSH/[--SP] or POP/[SP++] */
259 *e_what = EWHAT_RAM;
260 acct_event_(vm, DCPU16_ACCT_EV_REG_READ, DCPU16_REG_SP);
261 acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_SP);
262 if (value_is_a == 0) { /* b */
263 *v = &(vm->ram[sp - 1]);
264 *sp_adjust -= 1;
265 *e_addr = sp - 1;
266 TRACE("%s>> PUSH [0x%04x] (0x%04x)", __func__, sp - 1, **v);
267 } else { /* a */
268 *v = &(vm->ram[sp]);
269 *sp_adjust += 1;
270 *e_addr = sp;
271 TRACE("%s>> POP [0x%04x] (0x%04x)", __func__, sp, **v);
272 }
273 break;
274
275 case 0x19: /* PEEK/[SP] */
276 acct_event_(vm, DCPU16_ACCT_EV_REG_READ, DCPU16_REG_SP);
277 *e_what = EWHAT_RAM;
278 *v = &(vm->ram[sp]);
279 *e_addr = sp;
280 TRACE("%s>> PEEK [0x%04x] (0x%04x)",
281 __func__,
282 sp,
283 **v);
284 break;
285
286 case 0x1a: /* PICK n */
287 acct_event_(vm, DCPU16_ACCT_EV_REG_READ, DCPU16_REG_SP);
288 *e_what = EWHAT_RAM;
289 *pc_adjust += 1;
290 *cycle_adjust += 1;
291 *e_addr = sp + value_data;
292 *v = vm->ram + *e_addr;
293 TRACE("%s>> PICK 0x%04x [0x%04x] (0x%04x)",
294 __func__,
295 value_data,
296 sp + value_data,
297 **v);
298 break;
299
300 case 0x1b: /* SP */
301 *e_reg = DCPU16_REG_SP;
302 *e_what = EWHAT_REG;
303 *v = &(vm->reg[DCPU16_REG_SP]);
304 TRACE("%s>> %s (0x%04x)",
305 __func__,
306 dcpu16_reg_names[DCPU16_REG_SP],
307 **v);
308 break;
309
310 case 0x1c: /* PC */
311 *e_reg = DCPU16_REG_PC;
312 *e_what = EWHAT_REG;
313 *v = &(vm->reg[DCPU16_REG_PC]);
314 TRACE("%s>> %s (0x%04x)",
315 __func__,
316 dcpu16_reg_names[DCPU16_REG_PC],
317 **v);
318 break;
319
320 case 0x1d: /* EX */
321 *e_reg = DCPU16_REG_EX;
322 *e_what = EWHAT_REG;
323 *v = &(vm->reg[DCPU16_REG_EX]);
324 TRACE("%s>> %s (0x%04x)",
325 __func__,
326 dcpu16_reg_names[DCPU16_REG_EX],
327 **v);
328 break;
329
330 case 0x1e: /* [next word] / [[pc++]] */
331 *e_what = EWHAT_RAM;
332 acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_PC);
333 *pc_adjust += 1;
334 *cycle_adjust += 1;
335 *e_addr = value_data;
336 *v = vm->ram + *e_addr;
337 TRACE("%s>> [nextword] [0x%04x] (0x%04x)",
338 __func__,
339 value_data,
340 **v);
341 break;
342
343 case 0x1f: /* next word (literal) / [pc++] */
344 *e_what = EWHAT_NONE;
345 acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_PC);
346 *pc_adjust += 1;
347 *cycle_adjust += 1;
348 *work_v = value_data;
349 *v = work_v;
350 TRACE("%s>> nextword (0x%04x)",
351 __func__,
352 **v);
353 break;
354
355 default: /* 0x20-0x3f: literal values 0xffff-0x1e */
356 *e_what = EWHAT_NONE;
357 *work_v = (value & 0x1f) - 1;
358 *v = work_v;
359 TRACE("%s>> literal (0x%04x)",
360 __func__,
361 **v);
362 }
363 }
364
365
366 #define OPCODE_NAME_LEN 16
367 struct opcode_entry {
368 unsigned short value;
369 char name[OPCODE_NAME_LEN];
370 void (*impl)(struct dcpu16 *, DCPU16_WORD, DCPU16_WORD, DCPU16_WORD, DCPU16_WORD);
371 };
372
373 /* messy boilerplate for opcode handlers */
374
375 /* opcode doesn't adjust its own PC, the step function which invoked it handles that */
376 /* opcode does adjust stack and cycle count */
377
378 #define OP_IMPL(x) static void op_##x(struct dcpu16 *vm, DCPU16_WORD val_b, DCPU16_WORD val_b_data, DCPU16_WORD val_a, DCPU16_WORD val_a_data)
379
380 #define OP_TYPE(op_type) DCPU16_WORD *a, *b;\
381 DCPU16_WORD ev_a_addr = 0, ev_b_addr = 0;\
382 enum dcpu16_register_indexes ev_a_reg = DCPU16_REG__NUM, ev_b_reg = DCPU16_REG__NUM;\
383 unsigned int ev_a_what = 0, ev_b_what = 0;\
384 short pc_adjust = 0, sp_adjust = 0;\
385 unsigned int cycle_adjust = 0;\
386 do {\
387 op_type;\
388 value_decode_(vm, val_a, 1, val_a_data,\
389 &vm->reg_work_[1], &a, &ev_a_addr, &ev_a_reg, &ev_a_what,\
390 &pc_adjust, &sp_adjust, &cycle_adjust);\
391 vm->reg[DCPU16_REG_SP] += sp_adjust;\
392 dcpu16_cycle_inc(vm, cycle_adjust);\
393 } while (0)
394 #define OP_NBI_ (void)val_b, (void)b, (void)ev_b_addr, (void)val_b_data, (void)ev_b_reg, (void)ev_b_what
395 #define OP_BASIC_ value_decode_(vm, val_b, 0, val_b_data,\
396 &vm->reg_work_[0], &b, &ev_b_addr, &ev_b_reg, &ev_b_what,\
397 &pc_adjust, &sp_adjust, &cycle_adjust)
398 #define OP_BASIC(x) OP_TYPE(OP_BASIC_)
399 #define OP_NBI(x) OP_TYPE(OP_NBI_)
400
401 /* after invoking one of these header macros, the instruction and operands will have been decoded, and the control registers have been adjusted to the next instruction et cetera */
402
403 /*
404 accounting helpers, these fire off the related callbacks for memory reads,
405 memory writes, and execution of reserved instructions
406 */
407 #define ACCT_ILL(addr) do { acct_event_(vm, DCPU16_ACCT_EV_NOP, addr); } while (0)
408 #define ACCT_RAM_R(addr) do { acct_event_(vm, DCPU16_ACCT_EV_READ, addr); } while (0)
409 #define ACCT_RAM_W(addr) do { acct_event_(vm, DCPU16_ACCT_EV_WRITE, addr); } while (0)
410 #define ACCT_REG_R(reg) do { acct_event_(vm, DCPU16_ACCT_EV_REG_READ, reg); } while (0)
411 #define ACCT_REG_W(reg) do { acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, reg); } while (0)
412
413 #define ACCT_R(__x__) do {\
414 if (ev_##__x__##_what & EWHAT_REG) ACCT_REG_R(ev_##__x__##_reg);\
415 if (ev_##__x__##_what & EWHAT_RAM) ACCT_RAM_R(ev_##__x__##_addr);\
416 } while (0)
417 #define ACCT_W(__x__) do {\
418 if (ev_##__x__##_what & EWHAT_REG) ACCT_REG_W(ev_##__x__##_reg);\
419 if (ev_##__x__##_what & EWHAT_RAM) ACCT_RAM_W(ev_##__x__##_addr);\
420 } while (0)
421
422 /* extended opcodes */
423
424 /*
425 N.B. this next function currently decodes values -- id est, it is
426 an opcode processing terminus; however, if 'future instruction set
427 expansion' happens, this will probably need to behave more like
428 the OP_IMPL(_nbi_) function which invoked it, if those instructions
429 have zero or differently styled operands.
430 */
431 OP_IMPL(nbi__reserved_) {
432 OP_NBI(nbi__reserved_);
433 /* reserved for future expansion */
434
435 /* fire an illegal instruction event for current instruction */
436 DCPU16_WORD future_opcode = (vm->ram[vm->reg[DCPU16_REG_PC] - pc_adjust] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_B_BITS));
437
438 WARN("reserved future opcode 0x%04x invoked", future_opcode);
439
440 ACCT_ILL(vm->reg[DCPU16_REG_PC] - pc_adjust);
441
442 dcpu16_cycle_inc(vm, 1);
443 }
444
445 OP_IMPL(nbi_jsr) {
446 OP_NBI(nbi_jsr);
447 /* pushes the address of the next instruction to the stack, then sets PC to a */
448
449 ACCT_R(a);
450
451 ACCT_REG_R(DCPU16_REG_PC);
452 ACCT_REG_R(DCPU16_REG_SP);
453 vm->ram[ --vm->reg[DCPU16_REG_SP] ] = vm->reg[DCPU16_REG_PC];
454 ACCT_REG_W(DCPU16_REG_SP);
455 ACCT_RAM_W(vm->reg[DCPU16_REG_SP] + 1);
456
457 vm->reg[DCPU16_REG_PC] = *a;
458 ACCT_REG_W(DCPU16_REG_PC);
459
460
461 dcpu16_cycle_inc(vm, 2);
462 }
463
464 OP_IMPL(nbi__reserved2_) {
465 OP_NBI(nbi__reserved2_);
466 /* reserved */
467
468 WARN("reserved nbi opcode invoked");
469
470 ACCT_ILL(vm->reg[DCPU16_REG_PC] - pc_adjust);
471
472 dcpu16_cycle_inc(vm, 1);
473 }
474
475 OP_IMPL(nbi_int) {
476 OP_NBI(nbi_int);
477
478 ACCT_R(a);
479
480 ACCT_REG_R(DCPU16_REG_IA);
481 if (vm->reg[DCPU16_REG_IA]) {
482 if ( interrupt_enqueue_(vm, *a) ) {
483 WARN("failed to queue interrupt");
484 return;
485 }
486
487 if (vm->interrupts_deferred_)
488 return;
489
490 vm->interrupts_deferred_ = 1;
491
492 ACCT_REG_R(DCPU16_REG_PC);
493 ACCT_REG_R(DCPU16_REG_SP);
494 vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_PC];
495 ACCT_RAM_W(vm->reg[DCPU16_REG_SP] + 1);
496 ACCT_REG_W(DCPU16_REG_SP);
497
498 ACCT_REG_R(DCPU16_REG_A);
499 ACCT_REG_R(DCPU16_REG_SP);
500 vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_A];
501 ACCT_RAM_W(vm->reg[DCPU16_REG_SP] + 1);
502 ACCT_REG_W(DCPU16_REG_SP);
503
504 ACCT_REG_R(DCPU16_REG_IA);
505 vm->reg[DCPU16_REG_PC] = vm->reg[DCPU16_REG_IA];
506 ACCT_REG_W(DCPU16_REG_PC);
507
508 vm->reg[DCPU16_REG_A] = *a;
509 ACCT_REG_W(DCPU16_REG_A);
510 }
511
512 dcpu16_cycle_inc(vm, 4);
513 }
514
515 OP_IMPL(nbi_iag) {
516 OP_NBI(nbi_iag);
517
518 ACCT_REG_R(DCPU16_REG_IA);
519 *a = vm->reg[DCPU16_REG_IA];
520
521 ACCT_W(a);
522
523 dcpu16_cycle_inc(vm, 1);
524 }
525
526 OP_IMPL(nbi_ias) {
527 OP_NBI(nbi_ias);
528
529 ACCT_R(a);
530
531 vm->reg[DCPU16_REG_IA] = *a;
532 ACCT_REG_W(DCPU16_REG_IA);
533
534 dcpu16_cycle_inc(vm, 1);
535 }
536
537 /* does this just ignore its operand? */
538 OP_IMPL(nbi_rfi) {
539 OP_NBI(nbi_rfi);
540
541 /* well, it consumes the argument, currently, so I guess pretend like we care */
542 ACCT_R(a);
543
544 vm->interrupts_deferred_ = 0;
545
546 ACCT_REG_R(DCPU16_REG_SP);
547 ACCT_RAM_R(vm->reg[DCPU16_REG_SP]);
548 vm->reg[DCPU16_REG_A] = vm->ram[vm->reg[DCPU16_REG_SP]++];
549 ACCT_REG_W(DCPU16_REG_A);
550 ACCT_REG_W(DCPU16_REG_SP);
551
552 ACCT_REG_R(DCPU16_REG_SP);
553 ACCT_RAM_R(vm->reg[DCPU16_REG_SP]);
554 vm->reg[DCPU16_REG_PC] = vm->ram[vm->reg[DCPU16_REG_SP]++];
555 ACCT_REG_W(DCPU16_REG_PC);
556 ACCT_REG_W(DCPU16_REG_SP);
557
558 dcpu16_cycle_inc(vm, 3);
559 }
560
561 OP_IMPL(nbi_iaq) {
562 OP_NBI(nbi_iaq);
563
564 ACCT_R(a);
565
566 if (*a) {
567 vm->interrupts_deferred_ = 1;
568 } else {
569 vm->interrupts_deferred_ = 0;
570 }
571
572 dcpu16_cycle_inc(vm, 2);
573 }
574
575 OP_IMPL(nbi_hwn) {
576 OP_NBI(nbi_hwn);
577
578 *a = vm->hw_table_entries_;
579 ACCT_W(a);
580
581 dcpu16_cycle_inc(vm, 2);
582 }
583
584 OP_IMPL(nbi_hwq) {
585 OP_NBI(nbi_hwq);
586
587 ACCT_R(a);
588
589 if (*a >= vm->hw_table_entries_) {
590 WARN("hardware query for non-extant device 0x%04x", *a);
591 vm->reg[DCPU16_REG_A] = 0;
592 vm->reg[DCPU16_REG_B] = 0;
593 vm->reg[DCPU16_REG_C] = 0;
594 vm->reg[DCPU16_REG_X] = 0;
595 vm->reg[DCPU16_REG_Y] = 0;
596 } else {
597 vm->reg[DCPU16_REG_A] = vm->hw_table_[*a].mod->id_l;
598 vm->reg[DCPU16_REG_B] = vm->hw_table_[*a].mod->id_h;
599 vm->reg[DCPU16_REG_C] = vm->hw_table_[*a].mod->ver;
600 vm->reg[DCPU16_REG_X] = vm->hw_table_[*a].mod->mfg_l;
601 vm->reg[DCPU16_REG_Y] = vm->hw_table_[*a].mod->mfg_h;
602 }
603
604 ACCT_REG_W(DCPU16_REG_A);
605 ACCT_REG_W(DCPU16_REG_B);
606 ACCT_REG_W(DCPU16_REG_C);
607 ACCT_REG_W(DCPU16_REG_X);
608 ACCT_REG_W(DCPU16_REG_Y);
609
610 dcpu16_cycle_inc(vm, 4);
611 }
612
613 OP_IMPL(nbi_hwi) {
614 OP_NBI(nbi_hwi);
615
616 ACCT_R(a);
617
618 if (*a > vm->hw_table_entries_) {
619 WARN("interrupt for non-extant device 0x%04x", *a);
620 return;
621 }
622
623 if (vm->hw_table_[*a].mod->hwi)
624 vm->hw_table_[*a].mod->hwi(vm, &vm->hw_table_[*a]);
625 else
626 WARN("hardware 0x%04x has no interrupt handler", *a);
627
628 dcpu16_cycle_inc(vm, 4);
629 }
630
631 OP_IMPL(nbi_hcf) {
632 OP_NBI(nbi_hcf);
633
634 ACCT_R(a);
635
636 vm->on_fire_ = 1;
637 WARN("system on fire");
638
639 dcpu16_cycle_inc(vm, 9);
640 }
641
642 static const struct opcode_entry opcode_nbi_entries[] = {
643 {0x00, "(reserved)", op_nbi__reserved_},
644 {0x01, "JSR", op_nbi_jsr},
645 {0x02, "(reserved)", op_nbi__reserved2_},
646 {0x03, "(reserved)", op_nbi__reserved2_},
647 {0x04, "(reserved)", op_nbi__reserved2_},
648 {0x05, "(reserved)", op_nbi__reserved2_},
649 {0x06, "(reserved)", op_nbi__reserved2_},
650 {0x07, "HCF", op_nbi_hcf}, /* undocumented */
651 {0x08, "INT", op_nbi_int},
652 {0x09, "IAG", op_nbi_iag},
653 {0x0a, "IAS", op_nbi_ias},
654 {0x0b, "RFI", op_nbi_rfi},
655 {0x0c, "IAQ", op_nbi_iaq},
656 {0x0d, "(reserved)", op_nbi__reserved2_},
657 {0x0e, "(reserved)", op_nbi__reserved2_},
658 {0x0f, "(reserved)", op_nbi__reserved2_},
659 {0x10, "HWN", op_nbi_hwn},
660 {0x11, "HWQ", op_nbi_hwq},
661 {0x12, "HWI", op_nbi_hwi},
662 {0x13, "(reserved)", op_nbi__reserved2_},
663 {0x00, "", NULL}
664 };
665 #define OPCODE_NBI_MAX (((sizeof(opcode_nbi_entries)) / (sizeof(struct opcode_entry))) - 1)
666
667
668 /* basic opcodes */
669
670 /*
671 N.B. the following function does not decode values.
672 Decoding is handled by the secondary opcode functions it calls.
673 */
674 OP_IMPL(_nbi_) {
675 /* non-basic instruction */
676
677 /* don't do normal value decoding here */
678
679 DCPU16_WORD nbi_opcode = val_b;
680 const struct opcode_entry *e = opcode_nbi_entries;
681
682 (void)val_b_data;
683
684 e = opcode_nbi_entries + ( (nbi_opcode < OPCODE_NBI_MAX) ? nbi_opcode : (OPCODE_NBI_MAX - 1) );
685
686 assert(e->impl != NULL);
687
688 TRACE(">> %s 0x%04x", e->name, val_b);
689 e->impl(vm, 0, 0, val_a, val_a_data);
690 }
691
692 OP_IMPL(set) {
693 OP_BASIC(set);
694 /* sets b to a */
695
696 ACCT_R(a);
697
698 /*
699 if b is a literal, it's aimed at a scratch register,
700 so it's fine to update, as it won't have any effect.
701 */
702 *b = *a;
703
704 ACCT_W(b);
705
706 dcpu16_cycle_inc(vm, 1);
707 }
708
709 OP_IMPL(add) {
710 OP_BASIC(add);
711 /* sets b to b+a, sets EX to 0x0001 if there's an overflow, 0x0 otherwise */
712 unsigned int acc = *b + *a;
713
714 ACCT_R(b);
715 ACCT_R(a);
716
717 *b = acc;
718 vm->reg[DCPU16_REG_EX] = (acc > 0xffff);
719
720 ACCT_REG_W(DCPU16_REG_EX);
721
722 ACCT_W(b);
723
724 dcpu16_cycle_inc(vm, 2);
725 }
726
727 OP_IMPL(sub) {
728 OP_BASIC(sub);
729 /* sets b to b-a, sets EX to 0xffff if there's an underflow, 0x0 otherwise */
730 unsigned int acc = *b - *a;
731
732 ACCT_R(b);
733 ACCT_R(a);
734
735 *b = acc;
736 vm->reg[DCPU16_REG_EX] = (acc > 0xffff);
737
738 ACCT_REG_W(DCPU16_REG_EX);
739
740 ACCT_W(b);
741
742 dcpu16_cycle_inc(vm, 2);
743 }
744
745 OP_IMPL(mul) {
746 OP_BASIC(mul);
747 /* sets b to b*a, unsigned, sets EX to ((b*a)>>16)&0xffff */
748 unsigned int acc = *b * *a;
749
750 ACCT_R(b);
751 ACCT_R(a);
752
753 *b = acc;
754 vm->reg[DCPU16_REG_EX] = acc >> 16;
755
756 ACCT_REG_W(DCPU16_REG_EX);
757
758 ACCT_W(b);
759
760 dcpu16_cycle_inc(vm, 2);
761 }
762
763 OP_IMPL(mli) {
764 OP_BASIC(mli);
765 /* sets b to b*a, signed */
766 int acc = (short)*b * (short)*a;
767
768 ACCT_R(b);
769 ACCT_R(a);
770
771 *b = acc;
772 vm->reg[DCPU16_REG_EX] = acc >> 16;
773
774 ACCT_REG_W(DCPU16_REG_EX);
775
776 ACCT_W(b);
777
778 dcpu16_cycle_inc(vm, 2);
779 }
780
781 OP_IMPL(div) {
782 OP_BASIC(div);
783 /* sets b to b/a, sets EX to ((b<<16)/a)&0xffff. if a==0, sets a and EX to 0 instead. */
784
785 ACCT_R(b);
786 ACCT_R(a);
787
788 if (*a == 0) {
789 *b = 0;
790 vm->reg[DCPU16_REG_EX] = 0;
791 } else {
792 *b = *b / *a;
793 vm->reg[DCPU16_REG_EX] = (*b << 16) / *a;
794 }
795
796 ACCT_REG_W(DCPU16_REG_EX);
797
798 ACCT_W(b);
799
800 dcpu16_cycle_inc(vm, 3);
801 }
802
803 OP_IMPL(dvi) {
804 OP_BASIC(dvi);
805 /* sets b to b/a, signed, round towards 0 */
806
807 ACCT_R(b);
808 ACCT_R(a);
809
810 if (*a == 0) {
811 *b = 0;
812 vm->reg[DCPU16_REG_EX] = 0;
813 } else {
814 *b = (short)*b / (short)*a;
815 vm->reg[DCPU16_REG_EX] = (short)(*b << 16) / (short)*a;
816 }
817
818 ACCT_REG_W(DCPU16_REG_EX);
819 ACCT_W(b);
820
821 dcpu16_cycle_inc(vm, 3);
822 }
823
824 OP_IMPL(mod) {
825 OP_BASIC(mod);
826 /* sets b to b%a. if a==0, sets b to 0 instead. */
827
828 ACCT_R(b);
829 ACCT_R(a);
830
831 if (*a == 0) {
832 *b = 0;
833 } else {
834 *b = *b % *a;
835 }
836
837 ACCT_W(a);
838
839 dcpu16_cycle_inc(vm, 3);
840 }
841
842 OP_IMPL(mdi) {
843 OP_BASIC(mdi);
844 /* sets b to b%a, signed */
845
846 ACCT_R(b);
847 ACCT_R(a);
848
849 if (*a == 0) {
850 *b = 0;
851 } else {
852 *b = (short)*b % (short)*a;
853 }
854
855 ACCT_W(b);
856
857 dcpu16_cycle_inc(vm, 3);
858 }
859
860 OP_IMPL(and) {
861 OP_BASIC(and);
862 /* sets b to b&a */
863
864 ACCT_R(b);
865 ACCT_R(a);
866
867 *b = *b & *a;
868
869 ACCT_W(b);
870
871 dcpu16_cycle_inc(vm, 1);
872 }
873
874 OP_IMPL(bor) {
875 OP_BASIC(bor);
876 /* sets b to b|a */
877
878 ACCT_R(b);
879 ACCT_R(a);
880
881 *b = *b | *a;
882
883 ACCT_W(b);
884
885 dcpu16_cycle_inc(vm, 1);
886 }
887
888 OP_IMPL(xor) {
889 OP_BASIC(xor);
890 /* sets b to b^a */
891
892 ACCT_R(b);
893 ACCT_R(a);
894
895 *b = *b ^ *a;
896
897 dcpu16_cycle_inc(vm, 1);
898
899 ACCT_W(b);
900 }
901
902 OP_IMPL(shr) {
903 OP_BASIC(shr);
904 /* sets b to b>>>a, sets EX to ((b<<16)>>a)&0xffff */
905 unsigned int acc = *b >> *a;
906
907 ACCT_R(b);
908 ACCT_R(a);
909
910 *b = acc & 0xffff;
911 vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a;
912
913 WARN("IMPLEMENT");
914
915 ACCT_REG_W(DCPU16_REG_EX);
916 ACCT_W(b);
917
918 dcpu16_cycle_inc(vm, 2);
919 }
920
921 OP_IMPL(asr) {
922 OP_BASIC(asr);
923 /* sets b to b>>a, sets EX to ((b<<16)>>>a)&0xffff (arithmetic shift) (treats b as signed) */
924 unsigned int acc = *b << *a;
925
926 ACCT_R(b);
927 ACCT_R(a);
928
929 *b = acc & 0xffff;
930 vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a;
931
932 WARN("IMPLEMENT");
933
934 ACCT_REG_W(DCPU16_REG_EX);
935 ACCT_W(b);
936
937 dcpu16_cycle_inc(vm, 2);
938 }
939
940 OP_IMPL(shl) {
941 OP_BASIC(shl);
942 /* sets b to b<<a, sets EX to ((b<<a)>>16)&0xffff */
943 unsigned int acc = *b << *a;
944
945 ACCT_R(b);
946 ACCT_R(a);
947
948 *b = acc;
949
950 vm->reg[DCPU16_REG_EX] = acc >> 16;
951
952 ACCT_REG_W(DCPU16_REG_EX);
953 ACCT_W(b);
954
955 dcpu16_cycle_inc(vm, 2);
956 }
957
958 OP_IMPL(ifb) {
959 OP_BASIC(ifb);
960 /* performs next instruction only if (b&a)!=0 */
961
962 ACCT_R(b);
963 ACCT_R(a);
964
965 if ((*b & *a) != 0) {
966 /* */
967 } else {
968 vm->skip_ = 1;
969 dcpu16_cycle_inc(vm, 1);
970 }
971
972 dcpu16_cycle_inc(vm, 2);
973 }
974
975 OP_IMPL(ifc) {
976 OP_BASIC(ifc);
977 /* performs next instruction only if (b&a)==0 */
978
979 ACCT_R(b);
980 ACCT_R(a);
981
982 if ((*b & *a) == 0) {
983 /* */
984 } else {
985 vm->skip_ = 1;
986 dcpu16_cycle_inc(vm, 1);
987 }
988
989 dcpu16_cycle_inc(vm, 2);
990 }
991
992 OP_IMPL(ife) {
993 OP_BASIC(ife);
994 /* performs next instruction only if b==a */
995
996 ACCT_R(b);
997 ACCT_R(a);
998
999 if (*b == *a) {
1000 /* */
1001 } else {
1002 vm->skip_ = 1;
1003 dcpu16_cycle_inc(vm, 1);
1004 }
1005
1006 dcpu16_cycle_inc(vm, 2);
1007 }
1008
1009 OP_IMPL(ifn) {
1010 OP_BASIC(ifn);
1011 /* performs next instruction only if b!=a */
1012
1013 ACCT_R(b);
1014 ACCT_R(a);
1015
1016 if (*b != *a) {
1017 /* */
1018 } else {
1019 vm->skip_ = 1;
1020 dcpu16_cycle_inc(vm, 1);
1021 }
1022
1023 dcpu16_cycle_inc(vm, 2);
1024 }
1025
1026 OP_IMPL(ifg) {
1027 OP_BASIC(ifg);
1028 /* performs next instruction only if b>a */
1029
1030 ACCT_R(b);
1031 ACCT_R(a);
1032
1033 if (*b > *a) {
1034 /* */
1035 } else {
1036 vm->skip_ = 1;
1037 dcpu16_cycle_inc(vm, 1);
1038 }
1039
1040 dcpu16_cycle_inc(vm, 2);
1041 }
1042
1043 OP_IMPL(ifa) {
1044 OP_BASIC(ifa);
1045 /* performs next instruction only if b>a (signed) */
1046
1047 ACCT_R(b);
1048 ACCT_R(a);
1049
1050 if (*b > *a) {
1051 /* */
1052 } else {
1053 vm->skip_ = 1;
1054 dcpu16_cycle_inc(vm, 1);
1055 }
1056
1057 dcpu16_cycle_inc(vm, 2);
1058 }
1059
1060 OP_IMPL(ifl) {
1061 OP_BASIC(ifl);
1062 /* performs next instruction only if b<a */
1063
1064 ACCT_R(b);
1065 ACCT_R(a);
1066
1067 if (*b < *a) {
1068 /* */
1069 } else {
1070 vm->skip_ = 1;
1071 dcpu16_cycle_inc(vm, 1);
1072 }
1073
1074 dcpu16_cycle_inc(vm, 2);
1075 }
1076
1077 OP_IMPL(ifu) {
1078 OP_BASIC(ifu);
1079 /* performs next instruction only if b<a (signed) */
1080
1081 ACCT_R(b);
1082 ACCT_R(a);
1083
1084 if (*b < *a) {
1085 /* */
1086 } else {
1087 vm->skip_ = 1;
1088 dcpu16_cycle_inc(vm, 1);
1089 }
1090
1091 dcpu16_cycle_inc(vm, 2);
1092 }
1093
1094 OP_IMPL(adx) {
1095 OP_BASIC(adx);
1096 /* sets b to b+a+EX, sets EX to 0x0001 if overflow, 0x0 otherwise */
1097 unsigned int acc;
1098
1099 ACCT_R(b);
1100 ACCT_R(a);
1101
1102 ACCT_REG_R(DCPU16_REG_EX);
1103
1104 acc = *b + *a + vm->reg[DCPU16_REG_EX];
1105 *b = acc & 0xffff;
1106 if (acc > 0xffff)
1107 vm->reg[DCPU16_REG_EX] = 0x0001;
1108 else
1109 vm->reg[DCPU16_REG_EX] = 0x0000;
1110
1111 ACCT_REG_W(DCPU16_REG_EX);
1112 ACCT_W(b);
1113
1114 dcpu16_cycle_inc(vm, 3);
1115 }
1116
1117 OP_IMPL(sbx) {
1118 OP_BASIC(sbx);
1119 /* sets b to b-a+EX, sets EX to 0xffff if underflow, 0x0 otherwise */
1120 unsigned int acc;
1121
1122 ACCT_R(b);
1123 ACCT_R(a);
1124
1125 ACCT_REG_R(DCPU16_REG_EX);
1126
1127 acc = *b - *a + vm->reg[DCPU16_REG_EX];
1128 *b = acc & 0xffff;
1129 if (acc > 0xffff)
1130 vm->reg[DCPU16_REG_EX] = 0xffff;
1131 else
1132 vm->reg[DCPU16_REG_EX] = 0;
1133
1134 ACCT_REG_W(DCPU16_REG_EX);
1135
1136 ACCT_W(b);
1137
1138 dcpu16_cycle_inc(vm, 3);
1139 }
1140
1141 OP_IMPL(sti) {
1142 OP_BASIC(sti);
1143 /* sets b to a, then increases I and J by 1 */
1144
1145 ACCT_R(b);
1146 ACCT_R(a);
1147
1148 *b = *a;
1149 vm->reg[DCPU16_REG_I] += 1;
1150 vm->reg[DCPU16_REG_J] += 1;
1151
1152 ACCT_REG_W(DCPU16_REG_I);
1153 ACCT_REG_W(DCPU16_REG_J);
1154
1155 ACCT_W(b);
1156
1157 dcpu16_cycle_inc(vm, 2);
1158 }
1159
1160 OP_IMPL(std) {
1161 OP_BASIC(std);
1162 /* sets b to a, then decreases I and J by 1 */
1163
1164 ACCT_R(b);
1165 ACCT_R(a);
1166
1167 *b = *a;
1168 vm->reg[DCPU16_REG_I] -= 1;
1169 vm->reg[DCPU16_REG_J] -= 1;
1170
1171 ACCT_REG_W(DCPU16_REG_I);
1172 ACCT_REG_W(DCPU16_REG_J);
1173
1174 ACCT_W(b);
1175
1176 dcpu16_cycle_inc(vm, 2);
1177 }
1178
1179 OP_IMPL(_reserved_) {
1180 OP_BASIC(_reserved_);
1181
1182 WARN("reserved opcode invoked");
1183
1184 ACCT_ILL(vm->reg[DCPU16_REG_PC] - pc_adjust);
1185 }
1186
1187 static const struct opcode_entry opcode_basic_entries[] = {
1188 {0x00, "(nbi)", op__nbi_},
1189 {0x01, "SET", op_set },
1190 {0x02, "ADD", op_add },
1191 {0x03, "SUB", op_sub },
1192 {0x04, "MUL", op_mul },
1193 {0x05, "MLI", op_mli },
1194 {0x06, "DIV", op_div },
1195 {0x07, "DVI", op_dvi },
1196 {0x08, "MOD", op_mod },
1197 {0x09, "MDI", op_mdi },
1198 {0x0a, "AND", op_and },
1199 {0x0b, "BOR", op_bor },
1200 {0x0c, "XOR", op_xor },
1201 {0x0d, "SHR", op_shr },
1202 {0x0e, "ASR", op_asr },
1203 {0x0f, "SHL", op_shl },
1204 {0x10, "IFB", op_ifb },
1205 {0x11, "IFC", op_ifc },
1206 {0x12, "IFE", op_ife },
1207 {0x13, "IFN", op_ifn },
1208 {0x14, "IFG", op_ifg },
1209 {0x15, "IFA", op_ifa },
1210 {0x16, "IFL", op_ifl },
1211 {0x17, "IFU", op_ifu },
1212 {0x18, "(reserved)", op__reserved_ },
1213 {0x19, "(reserved)", op__reserved_ },
1214 {0x1a, "ADX", op_adx },
1215 {0x1b, "SBX", op_sbx },
1216 {0x1c, "(reserved)", op__reserved_ },
1217 {0x1d, "(reserved)", op__reserved_ },
1218 {0x1e, "STI", op_sti },
1219 {0x1f, "STD", op_std },
1220 {0x00, "", NULL }
1221 };
1222
1223 static inline
1224 void dump_operand_value_(DCPU16_WORD value, DCPU16_WORD nextword, unsigned int value_position) {
1225 if (value <= 0x07) {
1226 printf(" %s", dcpu16_reg_names[value]);
1227 } else if (value <= 0x0f) {
1228 printf(" [%s]", dcpu16_reg_names[value & 0x07]);
1229 } else if (value <= 0x17) {
1230 printf(" [0x%04x + %s]", nextword, dcpu16_reg_names[value & 0x07]);
1231 } else switch (value) {
1232 case 0x18:
1233 if (value_position == 0) { /* b */
1234 printf(" PUSH");
1235 } else {
1236 printf(" POP");
1237 }
1238 break;
1239 case 0x19: printf(" PEEK"); break;
1240 case 0x1a: printf(" PICK 0x%04x", nextword); break;
1241 case 0x1b: printf(" SP"); break;
1242 case 0x1c: printf(" PC"); break;
1243 case 0x1d: printf(" EX"); break;
1244 case 0x1e: printf(" [0x%04x]", nextword); break;
1245 case 0x1f: printf(" 0x%04x", nextword); break;
1246 default: printf(" 0x%02x", value - 0x21);
1247 }
1248 }
1249
1250
1251 /* split a sequence of (one to three) words into the components of an instruction */
1252 static inline
1253 void instruction_decode_(DCPU16_WORD *mem, DCPU16_WORD addr,
1254 DCPU16_WORD *opcode, DCPU16_WORD *b, DCPU16_WORD **b_data, DCPU16_WORD *a, DCPU16_WORD **a_data,
1255 DCPU16_WORD *instr_len) {
1256 *opcode = *a = *b = mem[addr];
1257 *opcode = mem[addr] & ((1 << OPCODE_BASIC_BITS) - 1);
1258 *b = (mem[addr] >> OPCODE_BASIC_BITS) & ((1 << OPCODE_OPERAND_B_BITS) - 1);
1259 *a = (mem[addr] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_B_BITS)) & ((1 << OPCODE_OPERAND_A_BITS) - 1);
1260 *instr_len = 1;
1261
1262 if ((*opcode != 0x0000) &&
1263 ( (*b >= 0x10 && *b <= 0x17) || *b == 0x1e || *b == 0x1f ) ) {
1264 *b_data = mem + (DCPU16_WORD)(addr + *instr_len);
1265 *instr_len += 1;
1266 } else {
1267 *b_data = NULL;
1268 }
1269
1270 if ( (*opcode != 0x0000 || (*opcode == 0 && *b != 0x0000) )
1271 && ( (*a >= 0x10 && *a <= 0x17) || *a == 0x1e || *a == 0x1f) ) {
1272 *a_data = mem + (DCPU16_WORD)(addr + *instr_len);
1273 *instr_len += 1;
1274 } else {
1275 *a_data = NULL;
1276 }
1277
1278 TRACE("\n%s: [0x%04x]:0x%04x op:0x%02x b:0x%02x (b_data:0x%04x) a:0x%02x (a_data:0x%04x) len:0x%02x\n",
1279 __func__,
1280 addr,
1281 mem[addr],
1282 *opcode,
1283 *b,
1284 *b_data ? **b_data : 0,
1285 *a,
1286 *a_data ? **a_data : 0,
1287 *instr_len);
1288 }
1289
1290 /* dcpu16_mnemonify_buf
1291 print words as words
1292 */
1293 DCPU16_WORD dcpu16_mnemonify_buf(DCPU16_WORD *buf) {
1294 DCPU16_WORD opcode, b, a, instr_len, *b_data, *a_data;
1295 const struct opcode_entry *e;
1296
1297 instruction_decode_(buf, 0, &opcode, &b, &b_data, &a, &a_data, &instr_len);
1298
1299 if (opcode == 0x0000)
1300 e = opcode_nbi_entries +
1301 ( (b < OPCODE_NBI_MAX) ? b : (OPCODE_NBI_MAX - 1) );
1302 else
1303 e = opcode_basic_entries + opcode;
1304 printf("%s", e->name);
1305
1306 if (opcode) {
1307 dump_operand_value_(b, b_data ? *b_data : 0, 0);
1308 printf(",");
1309 }
1310
1311 if (opcode || b) {
1312 dump_operand_value_(a, a_data ? *a_data : 0, 1);
1313 }
1314
1315 return instr_len;
1316 }
1317
1318 /* dcpu16_disassemble_print
1319 print the words of the instruction at addr, followed by its assembly representation
1320 returns the length of the instruction in words
1321 */
1322 DCPU16_WORD dcpu16_disassemble_print(struct dcpu16 *vm, DCPU16_WORD addr) {
1323 DCPU16_WORD opcode, b, a, instr_len, i, *b_data, *a_data;
1324 DCPU16_WORD buf[3] = { vm->ram[addr], vm->ram[(DCPU16_WORD)(addr + 1)], vm->ram[(DCPU16_WORD)(addr + 2)] };
1325 unsigned int indent = 0;
1326 unsigned int partial = 0;
1327
1328 if (!vm) return 0;
1329
1330 #if 0
1331 /*
1332 Check the previous instruction, to see if this one should be
1333 indented. This check isn't foolproof, as preceeding addresses
1334 could be data which happen to match instructions..
1335 */
1336 for (i = 3; i; i--) {
1337 instruction_decode_(vm->ram, (DCPU16_WORD)(addr - i), &opcode, &b, &b_data, &a, &a_data, &instr_len);
1338 if (instr_len > i)
1339 partial++;
1340 if (instr_len == i
1341 && (opcode >= 0x10 && opcode <= 0x17) ) {
1342 indent++;
1343 break;
1344 }
1345 }
1346 #endif
1347
1348 /* just need instr_len */
1349 instruction_decode_(vm->ram, addr, &opcode, &b, &b_data, &a, &a_data, &instr_len);
1350
1351 /* show the raw words */
1352 printf("%04x", vm->ram[addr]);
1353 for (i = 1; i < instr_len; i++) {
1354 printf(" %04x", vm->ram[addr + i]);
1355 }
1356
1357 /* align things neatly, show the instruction */
1358 printf("%s%s ;%s%s",
1359 instr_len < 3 ? " " : "",
1360 instr_len < 2 ? " " : "",
1361 partial ? "*" : " ",
1362 indent ? " " : "");
1363
1364 dcpu16_mnemonify_buf(buf);
1365
1366 return instr_len;
1367 }
1368
1369 int dcpu16_interrupt(struct dcpu16 *vm, DCPU16_WORD message) {
1370 TRACE("%s>> message:0x%04x", __func__, message);
1371 return interrupt_enqueue_(vm, message);
1372 }
1373
1374 /* execute the next instruction */
1375 void dcpu16_step(struct dcpu16 *vm) {
1376 DCPU16_WORD opcode, b, a, instr_len, *b_data, *a_data;
1377 const struct opcode_entry *e;
1378
1379 if (!vm)
1380 return;
1381
1382 instruction_decode_(vm->ram, vm->reg[DCPU16_REG_PC], &opcode, &b, &b_data, &a, &a_data, &instr_len);
1383
1384 /* consume what we decoded */
1385 /* this happens immediately as PC might be re-set as an operation */
1386 vm->reg[DCPU16_REG_PC] += instr_len;
1387
1388 /* run the operation */
1389 for (e = opcode_basic_entries; e->impl; e++) {
1390 if (e->value == opcode) {
1391 TRACE("%s>> %s 0x%04x, 0x%04x", __func__, e->name, b, a);
1392 e->impl(vm, b, b_data ? *b_data : 0, a, a_data ? *a_data : 0);
1393 break;
1394 }
1395 }
1396
1397 /* and jump over next instr(s) if needed */
1398 while (vm->skip_) {
1399 instruction_decode_(vm->ram, vm->reg[DCPU16_REG_PC], &opcode, &b, &b_data, &a, &a_data, &instr_len);
1400 vm->reg[DCPU16_REG_PC] += instr_len;
1401 TRACE("++ SKIPPED %x words", instr_len);
1402 if (opcode >= 0x10 && opcode <= 0x17) {
1403 /* skipping a branch instruction? skip branch's skippable instruction as well */
1404 dcpu16_cycle_inc(vm, 1);
1405 } else {
1406 vm->skip_ = 0;
1407 }
1408 }
1409
1410 /* if we're currently servicing interrupts */
1411 if (vm->interrupts_deferred_ == 0) {
1412 /* and there are interrupts to be serviced */
1413 if (vm->interrupts_head_ != vm->interrupts_tail_) {
1414 DCPU16_WORD message;
1415 message = interrupt_dequeue_(vm);
1416
1417 TRACE("%s>> %s interrupt IA:0x%04x message:0x%04x",
1418 __func__,
1419 vm->reg[DCPU16_REG_IA] ? "servicing" : "ignoring",
1420 vm->reg[DCPU16_REG_IA],
1421 message);
1422 if (vm->reg[DCPU16_REG_IA]) {
1423 /* then service the next interrupt */
1424 vm->interrupts_deferred_ = 1;
1425 vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_PC];
1426 vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_A];
1427 vm->reg[DCPU16_REG_PC] = vm->reg[DCPU16_REG_IA];
1428 vm->reg[DCPU16_REG_A] = message;
1429 }
1430 }
1431 }
1432 }
1433
1434
1435 /* instantiate a new 'hardware' device */
1436 struct dcpu16_hw *dcpu16_hw_new(struct dcpu16 *vm, struct dcpu16_hw_module *mod, void *data) {
1437 struct dcpu16_hw *hw;
1438
1439 hw = malloc(sizeof *hw);
1440 if (hw == NULL) {
1441 vm->warn_cb_("%s():%s", "malloc", strerror(errno));
1442 return NULL;
1443 }
1444 hw->vm = vm;
1445 hw->mod = mod;
1446
1447 if (mod->data_init) {
1448 if (mod->data_init(hw, data)) {
1449 vm->warn_cb_("failed to init hw module data");
1450 free(hw);
1451 return NULL;
1452 }
1453 } else {
1454 hw->data = NULL;
1455 }
1456
1457 return hw;
1458 }
1459
1460 /* destroy a 'hardware' device */
1461 void dcpu16_hw_del(struct dcpu16_hw **hw) {
1462 if (hw) {
1463 if (*hw) {
1464 if ((*hw)->mod->data_free) {
1465 (*hw)->mod->data_free(*hw);
1466 }
1467 free(*hw);
1468 *hw = NULL;
1469 }
1470 }
1471 }
1472
1473 /* dcpu16_hw_ctl
1474 * invokes per-module controls for hw device
1475 */
1476 int dcpu16_hw_ctl(struct dcpu16_hw *hw, const char *cmd, void *data_in, void *data_out) {
1477 if (hw) {
1478 if (hw->mod) {
1479 if (hw->mod->ctl) {
1480 if (cmd) {
1481 return hw->mod->ctl(hw, cmd, data_in, data_out);
1482 }
1483 }
1484 }
1485 }
1486 return 0;
1487 }
1488
1489
1490 /* dcpu16_hw_attach
1491 * registers new 'hardware' device with system
1492 */
1493 int dcpu16_hw_attach(struct dcpu16 *vm, struct dcpu16_hw *hw) {
1494 if (!vm || !hw)
1495 return -1;
1496
1497 TRACE("%s>> name:%s ID:0x%04x%04x MFG:0x%04x%04x VER:0x%04x",
1498 __func__,
1499 hw->mod->name_,
1500 hw->mod->id_h, hw->mod->id_l,
1501 hw->mod->mfg_l, hw->mod->mfg_h,
1502 hw->mod->ver);
1503
1504 if (vm->hw_table_entries_ == 0xffff) {
1505 WARN("maximum hardware entries reached");
1506 return -1;
1507 }
1508
1509 if (vm->hw_table_entries_ == vm->hw_table_allocated_) {
1510 size_t new_entries = vm->hw_table_allocated_ + 32;
1511 void *tmp_ptr = realloc(vm->hw_table_, new_entries * sizeof * (vm->hw_table_));
1512 if (tmp_ptr == NULL) {
1513 fprintf(stderr, "%s():%s", "realloc", strerror(errno));
1514 return -1;
1515 }
1516 vm->hw_table_ = tmp_ptr;
1517 vm->hw_table_allocated_ += 32;
1518 }
1519
1520 memcpy(vm->hw_table_ + vm->hw_table_entries_, hw, sizeof *hw);
1521 vm->hw_table_entries_++;
1522
1523 TRACE("%s>> added hw entry %zu", __func__, vm->hw_table_entries_);
1524
1525 return 0;
1526 }
1527
1528 /* dcpu16_acct_add
1529 * Register callback fn to be triggered whenever event matching any events
1530 * in bitwise mask occur.
1531 */
1532 int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event mask, dcpu16_ev_cb_t *fn, DCPU16_WORD addr_l, DCPU16_WORD addr_h, void *data) {
1533 struct dcpu16_acct_cb cb = {
1534 .mask = mask,
1535 .addr_l = addr_l,
1536 .addr_h = addr_h,
1537 .fn = fn,
1538 .data = data,
1539 };
1540
1541 if (!vm)
1542 return -1;
1543
1544 cb.mask = mask;
1545 cb.addr_l = addr_l;
1546 cb.addr_h = addr_h;
1547 cb.fn = fn;
1548 cb.data = data;
1549
1550 if (vm->cb_table_entries_ == vm->cb_table_allocated_) {
1551 size_t new_entries = vm->cb_table_allocated_ + 32;
1552 void *tmp_ptr = realloc(vm->cb_table_, new_entries * sizeof *(vm->cb_table_));
1553 if (tmp_ptr == NULL) {
1554 fprintf(stderr, "%s():%s", "realloc", strerror(errno));
1555 return -1;
1556 }
1557 vm->cb_table_ = tmp_ptr;
1558 vm->cb_table_allocated_ += 32;
1559 }
1560
1561 memcpy(vm->cb_table_ + vm->cb_table_entries_, &cb, sizeof cb);
1562 vm->cb_table_entries_++;
1563
1564 TRACE("%s>> attached event callback %zu", __func__, vm->cb_table_entries_);
1565
1566 return 0;
1567 }
1568
1569 /* dcpu16_reset
1570 * signals cpu to reset, clearing runstate and ram, then reload any init callbacks
1571 */
1572 void dcpu16_reset(struct dcpu16 *vm) {
1573 size_t i;
1574
1575 if (!vm)
1576 return;
1577
1578 TRACE("%s>> reset", __func__);
1579
1580 vm->skip_ = 0;
1581 vm->interrupts_deferred_ = 0;
1582 vm->on_fire_ = 0;
1583 memset(vm->interrupts_, 0, sizeof vm->interrupts_);
1584 vm->interrupts_head_ = 0;
1585 vm->interrupts_tail_ = 0;
1586
1587 /* signal attached hardware */
1588 for (i = 0; i < vm->hw_table_entries_; i++) {
1589 if (vm->hw_table_[i].mod->reset)
1590 vm->hw_table_[i].mod->reset(vm, &vm->hw_table_[i]);
1591 }
1592
1593 memset(vm->reg, 0, sizeof vm->reg);
1594 memset(vm->ram, 0, sizeof vm->ram);
1595 vm->cycle_ = 0;
1596
1597 acct_event_(vm, DCPU16_ACCT_EV_RESET, 0);
1598 }
1599
1600 /* dcpu16_new
1601 * allocate a new dcpu16 instance
1602 */
1603 struct dcpu16 *dcpu16_new(void) {
1604 struct dcpu16 *vm;
1605
1606 vm = calloc(1, sizeof *vm);
1607 if (vm == NULL)
1608 WARN("%s: %s(%zu): %s", __func__, "calloc", strerror(errno));
1609
1610 vm->warn_cb_ = warn_cb_;
1611 vm->trace_cb_ = trace_cb_;
1612
1613 return vm;
1614 }
1615
1616 /* dcpu16_delete
1617 * release a dcpu16 instance
1618 */
1619 void dcpu16_delete(struct dcpu16 **vm) {
1620 if (!vm || !*vm)
1621 return;
1622
1623 free(*vm);
1624 *vm = NULL;
1625 }