i2c tools better naming scheme
[cr816-sim.git] / isa.c
blobb71b201fc36fddb0c3edfa8c2d7900d94caf4ca8
1 #include <string.h>
2 #include <stdlib.h>
3 #include "disasm.h"
4 #include "log.h"
5 #include "access.h"
7 static u16 hw_stack[STACK_LEN];
8 static struct opcode_word mem_prog[MEM_PROG_LEN];
11 #define IXS_NAME_MAX 4
12 static const char ixs_to_name[4][IXS_NAME_MAX] = {
13 "i0", "i1", "i2", "i3",
16 #define REG_NAME_MAX 6
17 static const char regs_to_name[16][REG_NAME_MAX] = {
18 "i0l", "i0h", "i1l", "i1h",
19 "i2l", "i2h", "i3l", "i3h",
20 "ipl", "iph", "stat", "r3",
21 "r2", "r1", "r0", "a",
24 const char * get_ixs_name(enum alu_ixs ixs)
26 return ixs_to_name[ixs];
29 const char * get_regs_name(enum alu_regs regs)
31 return regs_to_name[regs];
34 void do_push(u16 val)
36 for (unsigned idx=STACK_LEN-1;idx>0;idx--) {
37 hw_stack[idx] = hw_stack[idx-1];
39 hw_stack[0] = val;
42 u16 do_pop(void)
44 u16 ret;
46 ret = hw_stack[0];
47 for (unsigned idx=0;idx<STACK_LEN-1;idx++) {
48 hw_stack[idx] = hw_stack[idx+1];
51 return ret;
55 static u16 do_alu_testb(u8 op, u8 val)
57 u8 acc;
58 struct cpuflags flags = read_flags(0);
60 #ifdef QUIRK_TESTB_IS_AND
61 //reality
62 acc = op & val;
63 #else
64 //specification
65 acc = op & (1 << (val & 7));
66 #endif
68 flags.z = (acc == 0)?1:0;
70 write_flags(flags, 1);
71 write_reg8(MAIN_REG_A, acc, 1);
73 return read_pc()+1;
76 //move to memory
77 static u16 do_move_mem(u16 dest, u8 src)
79 log_instr_name("move");
81 write_mem(dest, src, 1);
83 return read_pc()+1;
86 #define OP5_NAME_MAX 12
87 static const char op5_to_name[32][OP5_NAME_MAX] = {
88 //0 - 7
89 "cmpa", "cmp", "and", "subs", "subd", "subdc", "mula", "subsc",
90 //8 - 0xf
91 "xor", "unknown_09", "move", "or", "add", "addc", "mul", "unknown_0f",
92 //0x10 - 0x17
93 "shra", "inc", "cmvd", "cmvs", "shrc", "incc", "shr", "unknown_17",
94 //0x18 - 0x1f
95 "cpl1", "cpl2", "shl", "dec", "cpl2c", "unknown_1d","shlc", "decc"
99 //indexed alu with immediate
100 //ex: op1 - op2
101 static u16 do_alu_op5(
102 enum alu_op5 alu, enum alu_regs dest, u8 op1, enum alu_regs op2_enum)
104 s16 s16temp;
105 u16 u16temp;
106 u8 acc;
107 u8 op2;
108 struct cpuflags flags = read_flags(0);
109 //TODO log only where required (move into cases)
111 log_instr_name("%s", op5_to_name[alu]);
113 switch(alu) {
114 case OP5_CMPA:
115 //ex op1 = #0x62
116 op2 = read_reg8(op2_enum, 1);
117 acc = (u8)((s8)(op1) - (s8)(op2));
119 flags.c = (((s8)(op2)) > ((s8)(op1)))?0:1;
120 flags.z = (acc == 0)?1:0;
121 flags.v = flags.c && (!flags.z);
123 write_flags(flags, 1);
124 write_reg8(MAIN_REG_A, acc, 1);
125 break;
126 case OP5_CMP:
127 op2 = read_reg8(op2_enum, 1);
129 acc = op1 - op2;
131 flags.c = (op2 > op1)?0:1;
132 flags.z = (acc == 0)?1:0;
133 flags.v = flags.c && (!flags.z);
135 write_flags(flags, 1);
136 write_reg8(MAIN_REG_A, acc, 1);
137 break;
138 case OP5_AND:
139 op2 = read_reg8(op2_enum, 1);
141 acc = op1 & op2;
143 flags.z = (acc == 0)?1:0;
145 write_flags(flags, 1);
146 write_reg8(MAIN_REG_A, acc, 1);
147 //TODO global function?
148 if (dest != MAIN_REG_A)
149 write_reg8(dest, acc, 1);
150 break;
151 case OP5_SUBS:
152 op2 = read_reg8(op2_enum, 1);
154 acc = (u8)((s16)op2 - (s16)op1);
156 //TODO maybe better eval?
157 if ((((s16)((s8)(op2)) - (s16)((s8)(op1))) < -0x80) ||
158 (((s16)((s8)(op2)) - (s16)((s8)(op1))) > 0x7f)) {
159 flags.v = 1;
160 } else {
161 flags.v = 0;
163 flags.c = (op1 > op2)?0:1;
164 flags.z = (acc == 0)?1:0;
166 write_flags(flags, 1);
167 write_reg8(MAIN_REG_A, acc, 1);
168 if (dest != MAIN_REG_A)
169 write_reg8(dest, acc, 1);
170 break;
171 case OP5_SUBD:
172 op2 = read_reg8(op2_enum, 1);
174 acc = (u8)((s16)op1 - (s16)op2);
176 //TODO maybe better eval?
177 if ((((s16)((s8)(op1)) - (s16)((s8)(op2))) < -0x80) ||
178 (((s16)((s8)(op1)) - (s16)((s8)(op2))) > 0x7f)) {
179 flags.v = 1;
180 } else {
181 flags.v = 0;
183 flags.c = (op2 > op1)?0:1;
184 flags.z = (acc == 0)?1:0;
186 write_flags(flags, 1);
187 write_reg8(MAIN_REG_A, acc, 1);
188 if (dest != MAIN_REG_A)
189 write_reg8(dest, acc, 1);
190 break;
191 case OP5_SUBDC:
192 op2 = read_reg8(op2_enum, 1);
194 //TODO maybe better flag evaluation?
195 acc = (s16)op1 - (s16)op2 - (flags.c?0:1);
197 if ((((s16)((s8)(op1)) - (s16)((s8)(op2))) < -0x80) ||
198 (((s16)((s8)(op1)) - (s16)((s8)(op2))) > 0x7f)) {
199 flags.v = 1;
200 } else {
201 flags.v = 0;
204 flags.c = (op2 > op1)?0:1;
205 flags.z = (acc == 0)?1:0;
207 write_flags(flags, 1);
208 write_reg8(MAIN_REG_A, acc, 1);
209 if (dest != MAIN_REG_A)
210 write_reg8(dest, acc, 1);
211 break;
212 case OP5_MULA:
213 op2 = read_reg8(op2_enum, 1);
215 s16temp = ((s16)op1) * ((s16)op2);
216 acc = s16temp & 0xff;
218 write_reg8(MAIN_REG_A, acc, 1);
219 write_reg8(dest, s16temp >> 8, 1);
220 break;
221 case OP5_SUBSC:
222 op2 = read_reg8(op2_enum, 1);
224 acc = (s16)op2 - (s16)op1 - (flags.c?0:1);
226 //TODO maybe better eval?
227 if ((((s16)((s8)(op2)) - (s16)((s8)(op1))) < -0x80) ||
228 (((s16)((s8)(op2)) - (s16)((s8)(op1))) > 0x7f)) {
229 flags.v = 1;
230 } else {
231 flags.v = 0;
233 flags.c = (op1 > op2)?0:1;
234 flags.z = (acc == 0)?1:0;
236 write_flags(flags, 1);
237 write_reg8(MAIN_REG_A, acc, 1);
238 if (dest != MAIN_REG_A)
239 write_reg8(dest, acc, 1);
240 break;
241 case OP5_XOR:
242 op2 = read_reg8(op2_enum, 1);
244 acc = op1 ^ op2;
246 flags.z = (acc == 0)?1:0;
248 write_flags(flags, 1);
249 write_reg8(MAIN_REG_A, acc, 1);
250 if (dest != MAIN_REG_A)
251 write_reg8(dest, acc, 1);
252 break;
253 case OP5_MOVE:
254 acc = op1;
256 flags.z = (acc == 0)?1:0;
258 write_flags(flags, 1);
259 write_reg8(MAIN_REG_A, acc, 1);
260 if (dest != MAIN_REG_A)
261 write_reg8(dest, acc, 1);
262 break;
263 case OP5_OR:
264 op2 = read_reg8(op2_enum, 1);
266 acc = op1 | op2;
268 flags.z = (acc == 0)?1:0;
270 write_flags(flags, 1);
271 write_reg8(MAIN_REG_A, acc, 1);
272 if (dest != MAIN_REG_A)
273 write_reg8(dest, acc, 1);
274 break;
275 case OP5_ADD:
276 op2 = read_reg8(op2_enum, 1);
278 //TODO double reg read, read only once!!
279 u16temp = op1 + op2;
280 acc = u16temp & 0xff;
282 // fprintf(stderr, " \n||%02x %02x|| ", op1, op2);
284 if (((s8)op1 > 0) && ((s8)op2 > 0)) {
285 flags.v = ((s8)u16temp < 0)?1:0;
286 // fprintf(stderr, " >>>A %02x %02x<<<\n", u16temp, s16temp);
287 } else if (((s8)op1 < 0) && ((s8)op2 < 0)) {
288 flags.v = ((s8)u16temp > 0)?1:0;
289 // fprintf(stderr, " >>>B %02x %02x<<<\n", u16temp, s16temp);
290 } else {
291 flags.v = 0;
292 // fprintf(stderr, " >>>C %02x %02x<<<\n", u16temp, s16temp);
294 flags.c = (u16temp > 0xff)?1:0;
295 flags.z = (acc == 0)?1:0;
297 write_flags(flags, 1);
298 write_reg8(MAIN_REG_A, acc, 1);
299 if (dest != MAIN_REG_A)
300 write_reg8(dest, acc, 1);
301 break;
302 case OP5_ADDC:
303 op2 = read_reg8(op2_enum, 1);
305 //TODO testing carry
306 u16temp = op1 + op2 + (flags.c?1:0);
307 acc = u16temp & 0xff;
309 //TODO carry?
310 if (((s8)op1 > 0) && ((s8)op2 > 0)) {
311 flags.v = ((s8)u16temp < 0)?1:0;
312 // fprintf(stderr, " >>>A %02x %02x<<<\n", u16temp, s16temp);
313 } else if (((s8)op1 < 0) && ((s8)op2 < 0)) {
314 flags.v = ((s8)u16temp > 0)?1:0;
315 // fprintf(stderr, " >>>B %02x %02x<<<\n", u16temp, s16temp);
316 } else {
317 flags.v = 0;
318 // fprintf(stderr, " >>>C %02x %02x<<<\n", u16temp, s16temp);
320 // flags.v = (u16temp > 0x7f)?1:0;
321 flags.c = (u16temp > 0xff)?1:0;
322 flags.z = (acc == 0)?1:0;
324 write_flags(flags, 1);
325 write_reg8(MAIN_REG_A, acc, 1);
326 if (dest != MAIN_REG_A)
327 write_reg8(dest, acc, 1);
328 break;
329 case OP5_MUL:
330 op2 = read_reg8(op2_enum, 1);
332 u16temp = ((s16)op1) * ((s16)op2);
333 acc = u16temp & 0xff;
335 write_reg8(MAIN_REG_A, acc, 1);
336 write_reg8(dest, u16temp >> 8, 1);
337 break;
338 case OP5_SHRA:
339 acc = ((op1 >> 1) & 0x7f) | (op1 & 0x80);
341 flags.c = (op1 & 1)?1:0;
342 flags.v = 0;
343 flags.z = (acc == 0)?1:0;
345 write_flags(flags, 1);
346 write_reg8(MAIN_REG_A, acc, 1);
347 if (dest != MAIN_REG_A)
348 write_reg8(dest, acc, 1);
349 break;
350 case OP5_INC:
351 acc = op1 + 1;
353 flags.v = (op1 == 0x7f)?1:0;
354 flags.c = (acc == 0)?1:0;
355 flags.z = (acc == 0)?1:0;
357 write_flags(flags, 1);
358 write_reg8(MAIN_REG_A, acc, 1);
359 if (dest != MAIN_REG_A)
360 write_reg8(dest, acc, 1);
361 break;
362 case OP5_CMVD:
363 //TODO log if depends on flag state
364 flags.z = (op1 == 0)?1:0; //always modified
366 if (!flags.c) {
367 acc = op1;
369 write_reg8(MAIN_REG_A, acc, 1);
370 if (dest != MAIN_REG_A)
371 write_reg8(dest, acc, 1);
374 write_flags(flags, 1);
375 break;
376 case OP5_CMVS:
377 flags.z = (op1 == 0)?1:0; //always modified
379 if (flags.c) {
380 acc = op1;
382 write_reg8(MAIN_REG_A, acc, 1);
383 if (dest != MAIN_REG_A)
384 write_reg8(dest, acc, 1);
387 write_flags(flags, 1);
388 break;
389 case OP5_SHRC:
390 acc = ((op1 >> 1) & 0x7f) | (flags.c?0x80:0);
392 flags.c = (op1 & 1)?1:0;
393 flags.v = 0;
394 flags.z = (acc == 0)?1:0;
396 write_flags(flags, 1);
397 write_reg8(MAIN_REG_A, acc, 1);
398 if (dest != MAIN_REG_A)
399 write_reg8(dest, acc, 1);
400 break;
401 case OP5_INCC:
402 //TODO testing carry
403 acc = (op1) + (flags.c?1:0);
405 flags.v = ((op1 == 0x7f)&&(flags.c))?1:0;
406 flags.c = (acc == 0)?1:0;
407 flags.z = (acc == 0)?1:0;
409 write_flags(flags, 1);
410 write_reg8(MAIN_REG_A, acc, 1);
411 if (dest != MAIN_REG_A)
412 write_reg8(dest, acc, 1);
413 break;
414 case OP5_SHR:
415 acc = ((op1 >> 1) & 0x7f);
417 flags.v = 0;
418 flags.c = (op1 & 1)?1:0;
419 flags.z = (acc == 0)?1:0;
421 write_flags(flags, 1);
422 write_reg8(MAIN_REG_A, acc, 1);
423 if (dest != MAIN_REG_A)
424 write_reg8(dest, acc, 1);
425 break;
426 case OP5_CPL1:
427 acc = (~ op1);
429 flags.z = (acc == 0)?1:0;
431 write_flags(flags, 1);
432 write_reg8(MAIN_REG_A, acc, 1);
433 if (dest != MAIN_REG_A)
434 write_reg8(dest, acc, 1);
435 break;
436 case OP5_CPL2:
437 acc = (~ op1) + 1;
439 flags.v = (op1 == 0x80)?1:0;
440 flags.c = (op1 == 0)?1:0;
441 flags.z = (acc == 0)?1:0;
443 write_flags(flags, 1);
444 write_reg8(MAIN_REG_A, acc, 1);
445 if (dest != MAIN_REG_A)
446 write_reg8(dest, acc, 1);
447 break;
448 case OP5_SHL:
449 acc = ((op1 << 1) & 0xfe);
451 flags.v = (((op1 >> 7)&1)!=((op1 >> 6)&1))?1:0;
452 flags.c = (op1 & 0x80)?1:0;
453 flags.z = (acc == 0)?1:0;
455 write_flags(flags, 1);
456 write_reg8(MAIN_REG_A, acc, 1);
457 if (dest != MAIN_REG_A)
458 write_reg8(dest, acc, 1);
459 break;
460 case OP5_DEC:
461 acc = op1 - 1;
463 flags.v = (op1 == 0x80)?1:0;
464 flags.c = (acc == 0xff)?0:1;
465 flags.z = (acc == 0)?1:0;
467 write_flags(flags, 1);
468 write_reg8(MAIN_REG_A, acc, 1);
469 if (dest != MAIN_REG_A)
470 write_reg8(dest, acc, 1);
471 break;
472 case OP5_CPL2C:
473 acc = (~ op1) + (flags.c?1:0);
475 flags.v = ((op1 == 0x80)&&(flags.c))?1:0;
476 flags.c = ((op1 == 0)&&(flags.c))?1:0; //NOTICE causal
477 flags.z = (acc == 0)?1:0;
479 write_flags(flags, 1);
480 write_reg8(MAIN_REG_A, acc, 1);
481 if (dest != MAIN_REG_A)
482 write_reg8(dest, acc, 1);
483 break;
484 case OP5_SHLC:
485 acc = ((op1 << 1) & 0xfe) | (flags.c?1:0);
487 flags.v = (((op1 >> 7)&1)!=((op1 >> 6)&1))?1:0;
488 flags.c = (op1 & 0x80)?1:0;
489 flags.z = (acc == 0)?1:0;
491 write_flags(flags, 1);
492 write_reg8(MAIN_REG_A, acc, 1);
493 if (dest != MAIN_REG_A)
494 write_reg8(dest, acc, 1);
495 break;
496 case OP5_DECC:
497 //TODO testing carry
498 acc = op1 + (flags.c?1:0) - 1;
500 flags.v = (acc == 0x7f)?1:0;
501 flags.c = (acc == 0xff)?0:1;
502 flags.z = (acc == 0)?1:0;
504 write_flags(flags, 1);
505 write_reg8(MAIN_REG_A, acc, 1);
506 if (dest != MAIN_REG_A)
507 write_reg8(dest, acc, 1);
508 break;
509 default:
510 sim_breakpoint_set(SIM_BREAKPOINT_CODE);
511 break;
514 return read_pc()+1;
518 #define JMP_NAME_MAX 6
519 static const char jmp_type_name[8][JMP_NAME_MAX] = {
520 "jcc", "jvc", "jzc", "jmp",
521 "jcs", "jvs", "jzs", "jevt",
525 static unsigned do_jump(enum jmp_type cc) {
526 struct cpuflags f;
527 struct reg_stat stat;
529 switch(cc) {
530 case JMP_CC:
531 f = read_flags(1);
532 log_access_read_add("(> !c) ");
533 return (!f.c)?1:0;
534 case JMP_VC:
535 f = read_flags(1);
536 log_access_read_add("(>= !o) ");
537 return (!f.v)?1:0;
538 case JMP_ZC:
539 f = read_flags(1);
540 log_access_read_add("(!= !z) ");
541 return (!f.z)?1:0;
542 case JMP_UNCOND:
543 return 1;
544 case JMP_CS:
545 f = read_flags(1);
546 log_access_read_add("(<= C) ");
547 return (f.c)?1:0;
548 case JMP_VS:
549 f = read_flags(1);
550 log_access_read_add("(< O) ");
551 return (f.v)?1:0;
552 case JMP_ZS:
553 f = read_flags(1);
554 log_access_read_add("(== Z) ");
555 return (f.z)?1:0;
556 case JMP_EVT:
557 stat.raw = read_reg8(MAIN_REG_STAT, 1);
558 log_access_read_add("(event) ");
559 return (stat.ev0 || stat.ev1)?1:0;
561 return 0; //default error?
564 /** ******** opcodes *******/
566 static u16 opcode_jump_imm(struct opcode_word opcode)
568 u16 addr = (~opcode.jmp_imm.n_addr) & 0xffff;
569 enum jmp_type cc = opcode.jmp_imm.cc;
571 log_instr_name("%s", jmp_type_name[cc]);
572 log_instr_args("0x%04hx", addr);
574 if (do_jump(cc)) {
575 //TODO append?
576 // fprintf(stderr, "GO");
577 return addr;
578 } else {
579 // fprintf(stderr, "SKIP");
580 return read_pc()+1;
584 static u16 opcode_jump_ip(struct opcode_word opcode)
586 u16 addr = read_ip(1);
587 enum jmp_type cc = opcode.jmp_imm.cc; //borrowed?
589 log_instr_name("%s", jmp_type_name[cc]);
590 log_instr_args("ip");
592 if (do_jump(cc)) {
593 //TODO use vvv?
594 // log_comment_add("GO");
595 return addr;
596 } else {
597 // log_comment_add("SKIP");
598 return read_pc()+1;
602 static u16 opcode_nop(struct opcode_word opcode)
604 log_instr_name("nop");
605 return read_pc()+1;
608 static u16 opcode_ret(struct opcode_word opcode)
610 log_instr_name("ret");
611 return do_pop();
614 static u16 opcode_reti(struct opcode_word opcode)
616 log_instr_name("reti");
618 struct reg_stat stat;
619 stat.raw = read_reg8(MAIN_REG_STAT, 1);
620 stat.gie = 1;
621 write_reg8(MAIN_REG_STAT, stat.raw, 1);
623 return do_pop();
626 static u16 opcode_pop(struct opcode_word opcode)
628 log_instr_name("pop");
630 write_ip(do_pop(), 1);
632 return read_pc()+1;
635 static u16 opcode_push(struct opcode_word opcode)
637 log_instr_name("push");
639 do_push(read_ip(1));
641 return read_pc()+1;
644 static u16 opcode_call_imm(struct opcode_word opcode)
646 u16 addr = ~(opcode.call_imm.n_addr & 0xffff);
648 log_instr_name("call");
649 log_instr_args("0x%04hx", addr);
651 do_push(read_pc() + 1);
653 return addr;
656 static u16 opcode_call_ip(struct opcode_word opcode)
658 u16 addr = read_ip(1);
660 log_instr_name("call");
661 log_instr_args("ip");
663 do_push(read_pc() + 1);
665 return addr;
668 static u16 opcode_calls_imm(struct opcode_word opcode)
670 u16 addr = ~(opcode.calls_imm.n_addr & 0xffff);
672 log_instr_name("calls");
673 log_instr_args("0x%04hx", addr);
675 write_ip(read_pc() + 1, 1);
676 return addr;
679 static u16 opcode_calls_ip(struct opcode_word opcode)
681 u16 addr = read_ip(1);
683 log_instr_name("calls");
684 log_instr_args("ip");
686 write_ip(read_pc() + 1, 1);
687 return addr;
690 static u16 opcode_pmd(struct opcode_word opcode)
692 //TODO
693 log_instr_name("pmd");
695 if (opcode.pmd.on) {
696 log_instr_args("on");
697 } else {
698 log_instr_args("off");
701 return read_pc()+1;
704 static u16 opcode_halt(struct opcode_word opcode)
706 struct reg_stat stat;
707 stat.raw = read_reg8(MAIN_REG_STAT, 1);
709 log_instr_name("halt");
711 sim_breakpoint_set(SIM_BREAKPOINT_HALT);
713 if (stat.ev0 || stat.ev1) {
715 //experiment
716 // stat.ev0 = 0;
717 // stat.ev1 = 0;
718 // write_reg8(MAIN_REG_STAT, stat.raw, 1);
721 return read_pc()+1;
725 return read_pc();
728 static u16 opcode_freq(struct opcode_word opcode)
730 log_instr_name("freq");
732 switch(opcode.freq.div) {
733 case 0x0:
734 log_instr_args("clk");
735 break;
736 case 0x8:
737 log_instr_args("clk/2");
738 break;
739 case 0xc:
740 log_instr_args("clk/4");
741 break;
742 case 0xe:
743 log_instr_args("clk/8");
744 break;
745 case 0xf:
746 log_instr_args("clk/16");
747 break;
748 default:
749 log_instr_args("invalid div table = %01hhx",
750 opcode.freq.div);
751 break;
754 return read_pc()+1;
757 static u16 opcode_sflag(struct opcode_word opcode)
759 struct cpuflags f = read_flags(1);
761 log_instr_name("sflag");
763 u8 acc;
765 acc =
766 ((f.c&1) << 7) |
767 (((f.c ^ f.v)&1) << 6) |
768 ((f.sf&1) << 5) |
769 ((f.se&1) << 4);
770 //bit 3 = was halt (only 816l?)
772 if (acc == 0) {
773 //816l no Z modify
774 //rest bit, undefined -> can be "1" -> never
775 f.z = 1;
778 write_reg8(MAIN_REG_A, acc, 1);
780 return read_pc()+1;
784 //alu1 rx, (ix, 0x12)
785 static u16 opcode_alu1(struct opcode_word opcode)
787 enum alu_op5 alu = opcode.alu1.alu_op;
788 enum alu_ixs ixs = opcode.alu1.ix;
789 enum alu_regs dst = opcode.alu1.dst;
790 u8 offset = opcode.alu1.offset;
792 log_instr_args("%s, (%s, 0x%02hhx)",
793 get_regs_name(dst),
794 get_ixs_name(ixs),
795 offset
798 u16 addr = read_ix(ixs, 1) + offset;
800 return do_alu_op5(
801 alu,
802 dst, //destination
803 read_mem(addr, 1),
808 //alu2 rx, -(ix, 0x12)+
809 static u16 opcode_alu2(struct opcode_word opcode)
811 enum alu_op5 alu = opcode.alu2.alu_op;
812 enum alu_ixs ixs = opcode.alu2.ix;
813 enum alu_regs dst = opcode.alu2.dst;
814 unsigned sign = opcode.alu2.sign;
815 u8 cpl2_offset = opcode.alu2.cpl2_offset;
817 u16 addr, newix;
818 u16 ret;
820 if (sign) {
821 //pre, signed
822 log_instr_args("%s, -(%s, 0x%02hhx)",
823 get_regs_name(dst), get_ixs_name(ixs), cpl2_offset);
825 addr = read_ix(ixs, 1) + ((s16)(cpl2_offset) | 0xff80);
826 newix = addr;
827 } else {
828 //post, unsigned
829 log_instr_args("%s, (%s, 0x%02hhx)+",
830 get_regs_name(dst), get_ixs_name(ixs), cpl2_offset);
832 addr = read_ix(ixs, 1);
833 newix = addr + cpl2_offset;
836 ret = do_alu_op5(
837 alu,
838 dst,
839 read_mem(addr, 1),
843 //NOTICE problem with modification causality (opcode i0l, -(i0, 42)) ... everything is: stores new index value after the memory access is done
844 write_ix(ixs, newix, 1);
846 return ret;
849 #define OP4_NAME_MAX 12
850 static const char op4_to_name[16][OP4_NAME_MAX] = {
851 //0 - 7
852 "cmpa", "cmp", "and", "subs", "subd", "subdc", "mula", "subsc",
853 //8 - 0xf
854 "xor", "unknown_09", "move", "or", "add", "addc", "mul", "tstb",
857 //alu3 rx, #const
858 static u16 opcode_alu3(struct opcode_word opcode)
860 enum alu_op4 alu = opcode.alu3.alu_op;
861 enum alu_regs dst = opcode.alu3.dst;
862 u8 val = (~opcode.alu3.n_data) & 0xff;
864 log_instr_name("%s", op4_to_name[alu]);
866 log_instr_args("%s, #0x%02hhx", get_regs_name(dst), val);
868 if (alu == OP4_TESTB) {
869 return do_alu_testb(read_reg8(dst, 1), val);
870 } else {
871 return do_alu_op5(
872 (enum alu_op5)alu,
873 dst,
874 val,
880 //only register operands
881 static u16 opcode_alu4(struct opcode_word opcode)
883 enum alu_op5 alu = opcode.alu4.alu_op;
884 enum alu_regs reg_op2_k = opcode.alu4.op2;
885 enum alu_regs reg_op1_j = opcode.alu4.op1;
886 enum alu_regs reg_res_i = opcode.alu4.dst;
888 switch(alu) {
889 case OP5_CMPA:
890 case OP5_CMP:
891 //alu4 op1 vs op2
892 log_instr_args("%s, %s",
893 get_regs_name(reg_op1_j),
894 get_regs_name(reg_op2_k));
896 if (reg_res_i != 0xf) {
897 log_comment_add("bad reg field I/res %s",
898 get_regs_name(reg_res_i));
900 break;
901 case OP5_AND:
902 case OP5_SUBS:
903 case OP5_SUBD:
904 case OP5_SUBDC:
905 case OP5_MULA:
906 case OP5_SUBSC:
907 case OP5_OR:
908 case OP5_ADD:
909 case OP5_ADDC:
910 case OP5_MUL:
911 //alu4 regi, regj, regk
912 log_instr_args("%s, %s, %s",
913 get_regs_name(reg_res_i),
914 get_regs_name(reg_op1_j),
915 get_regs_name(reg_op2_k));
916 break;
917 case OP5_MOVE: //probably
918 case OP5_SHRA:
919 case OP5_INC:
920 case OP5_CMVD:
921 case OP5_CMVS:
922 case OP5_SHRC:
923 case OP5_INCC:
924 case OP5_SHR:
925 case OP5_CPL1:
926 case OP5_CPL2:
927 case OP5_SHL:
928 case OP5_DEC:
929 case OP5_CPL2C:
930 case OP5_SHLC:
931 case OP5_DECC:
932 //alu4 regi=f(regj)
933 log_instr_args("%s, %s",
934 get_regs_name(reg_res_i),
935 get_regs_name(reg_op1_j));
937 if (reg_op2_k != 0xf) {
938 log_comment_add("bad regk array %s",
939 get_regs_name(reg_op2_k));
941 break;
942 default:
943 //alu4 regi, regj, regk
944 log_instr_args("%s, %s, %s",
945 get_regs_name(reg_res_i),
946 get_regs_name(reg_op1_j),
947 get_regs_name(reg_op2_k));
948 log_comment_add("unknown reg use");
949 break;
952 return do_alu_op5(
953 alu,
954 reg_res_i,
955 read_reg8(reg_op1_j, 1),
956 reg_op2_k
960 //alu5 regi, (ix, r3)
961 static u16 opcode_alu5(struct opcode_word opcode)
963 enum alu_op5 alu = opcode.alu5.alu_op;
964 enum alu_ixs ixs = opcode.alu5.ix;
965 enum alu_regs dst = opcode.alu5.dst;
966 u16 addr = read_ix(ixs, 1) + read_reg8(MAIN_REG_R3, 1);
968 log_instr_args("%s, (%s, r3)",
969 get_regs_name(dst), get_ixs_name(ixs));
971 return do_alu_op5(
972 alu,
973 dst,
974 read_mem(addr, 1),
979 //alu6 regi, direct addr
980 static u16 opcode_alu6(struct opcode_word opcode)
982 enum alu_op5 alu = opcode.alu6.alu_op;
983 enum alu_regs dst = opcode.alu6.dst;
984 u16 addr = (~opcode.alu6.n_addr) & 0xff;
986 log_instr_args("%s, 0x%02hhx",
987 get_regs_name(dst), addr);
989 return do_alu_op5(
990 alu,
991 dst,
992 read_mem(addr, 1),
997 //move7 (ix, r3), reg
998 static u16 opcode_move7(struct opcode_word opcode)
1000 enum alu_ixs ixs = opcode.move7.ix;
1001 enum alu_regs src = opcode.move7.src;
1002 u16 addr = read_ix(ixs, 1) + read_reg8(MAIN_REG_R3, 1);
1004 log_instr_args("(%s, r3), %s",
1005 get_ixs_name(ixs), get_regs_name(src));
1007 return do_move_mem(
1008 addr,
1009 read_reg8(src, 1)
1013 static u16 opcode_move8(struct opcode_word opcode)
1015 enum alu_ixs ixs = opcode.move8.ix;
1016 enum alu_regs src = opcode.move8.src;
1017 u8 cpl2_offset = opcode.move8.cpl2_offset;
1018 u16 addr, newix;
1019 u16 ret;
1021 if (opcode.move8.sign) {
1022 //pre/signed: move8 -(ix, 0x12), reg
1023 log_instr_args("-(%s, 0x%02hhx), %s",
1024 get_ixs_name(ixs), cpl2_offset, get_regs_name(src));
1026 addr = read_ix(ixs, 1) + ((s16)(cpl2_offset) | 0xff80);
1028 newix = addr;
1029 } else {
1030 //post/unsigned: move8 (ix, 0x12)+, reg
1031 log_instr_args("(%s, 0x%02hhx)+, %s",
1032 get_ixs_name(ixs), cpl2_offset, get_regs_name(src));
1034 addr = read_ix(ixs, 1);
1036 newix = addr + cpl2_offset;
1039 ret = do_move_mem(
1040 addr,
1041 read_reg8(src, 1)
1044 //NOTICE problem with modification causality (opcode i0l, -(i0, 42)) ... everything is: stores new index value after the memory access is done
1045 write_ix(ixs, newix, 1);
1047 return ret;
1050 //move9 (ix, 0xff), reg
1051 static u16 opcode_move9(struct opcode_word opcode)
1053 enum alu_ixs ixs = opcode.move9.ix;
1054 enum alu_regs src = opcode.move9.src;
1055 u16 addr = read_ix(ixs, 1) + opcode.move9.offset;
1057 log_instr_args("(%s, 0x%02hhx), %s",
1058 get_ixs_name(ixs), opcode.move9.offset, get_regs_name(src));
1060 return do_move_mem(
1061 addr,
1062 read_reg8(src, 1)
1066 //move10 0xff, reg (direct address)
1067 static u16 opcode_move10(struct opcode_word opcode)
1069 enum alu_regs src = opcode.move10.src;
1070 u8 addr = (~opcode.move10.n_addr) & 0xff;
1072 log_instr_args("0x%02hhx, %s",
1073 addr, get_regs_name(src));
1075 return do_move_mem(
1076 addr,
1077 read_reg8(src, 1)
1081 //move11 0xff, #0x42
1082 static u16 opcode_move11(struct opcode_word opcode)
1084 u8 addr = (~opcode.move11.n_addr) & 0xff;
1085 u8 val = (~opcode.move11.n_data) & 0xff;
1087 log_instr_args("0x%02hhx, #0x%02hhx",
1088 addr, val);
1090 return do_move_mem(
1091 addr,
1096 //invalid opcode
1097 static u16 opcode_inval(struct opcode_word opcode)
1099 log_instr_name("!inval %06x", opcode.raw);
1100 return read_pc()+1; //??
1104 //83p coolrisc trm
1105 #define DECODER_ALL_BITS 0x3fffff
1106 static const struct opcode_decoder cr816[] = {
1107 {DECODER_ALL_BITS, DECODER_ALL_BITS, opcode_nop},
1108 {DECODER_ALL_BITS, 0x3f3fff, opcode_ret},
1109 {DECODER_ALL_BITS, 0x3f1fff, opcode_reti},
1110 {DECODER_ALL_BITS, 0x3ebfff, opcode_pop},
1111 {0x3f0000, 0x3a0000, opcode_calls_imm},
1112 {0x3f0000, 0x390000, opcode_call_imm},
1113 {0x380000, 0x300000, opcode_jump_imm},
1114 {DECODER_ALL_BITS, 0x2dffff, opcode_push},
1115 {DECODER_ALL_BITS, 0x2affff, opcode_calls_ip},
1116 {DECODER_ALL_BITS, 0x29ffff, opcode_call_ip},
1117 {0x38ffff, 0x20ffff, opcode_jump_ip},
1118 {0x380000, 0x180000, opcode_alu1},
1119 {0x380000, 0x100000, opcode_alu2},
1120 {0x3f0000, 0x0e0000, opcode_alu3},
1121 {0x3e0000, 0x0c0000, opcode_alu4},
1122 {0x3ffeff, 0x0beeff, opcode_pmd},
1123 {DECODER_ALL_BITS, 0x0bdfff, opcode_halt},
1124 {0x3ffff0, 0x0bbff0, opcode_freq},
1125 {DECODER_ALL_BITS, 0x0b7fff, opcode_sflag},
1126 {0x3e00fc, 0x0600fc, opcode_alu5},
1127 {0x3e0000, 0x040000, opcode_alu6},
1128 {0x3fc0ff, 0x0380ff, opcode_move7},
1129 {0x3fc000, 0x034000, opcode_move8},
1130 {0x3fc000, 0x02c000, opcode_move9},
1131 {0x3ff000, 0x01b000, opcode_move10},
1132 {0x3f0000, 0x000000, opcode_move11},
1133 {0, 0, opcode_inval}, //stopper last
1136 u16 opcode_decode(struct opcode_word opcode)
1138 unsigned i = 0;
1139 u16 curr_pc = 0; //reset if bug?
1141 while(1) {
1142 if ((opcode.raw & cr816[i].and_mask) == cr816[i].equal) {
1143 curr_pc = cr816[i].opcode_fcn(opcode);
1145 // if (cr816[i].and_mask == 0)
1146 //always breaks
1147 break;
1149 i++;
1152 return curr_pc;
1155 struct opcode_word read_code(u16 addr)
1157 struct opcode_word ret;
1159 ret = mem_prog[addr];
1161 return ret;
1164 void init_isa(char * filename)
1166 memset(hw_stack, 0, STACK_LEN*2);
1168 for (unsigned addr = 0; addr < MEM_PROG_LEN; addr++) {
1169 mem_prog[addr].raw = 0x3fffff; //NOP
1170 // mem_prog[addr].raw = 0x0bdfff; //halt
1173 if (filename) {
1174 FILE * fp;
1175 struct opcode_word word;
1176 unsigned addr = 0;
1177 fp = fopen(filename, "r");
1178 if (fp == NULL) {
1179 perror("code dump opening");
1180 exit(1);
1183 while (fread(&word.raw, 3, 1, fp) == 1) {
1184 mem_prog[addr] = word;
1185 addr++;
1187 fclose(fp);
1191 //just validations vvv
1192 #if 0
1193 //opcodes validation (ADD)
1194 unsigned addr=0;
1195 mem_prog[addr++].raw = 0x0ead00 | ((~0x0f)&0xff);
1196 mem_prog[addr++].raw = 0x0ecd00 | ((~0xf6)&0xff);
1198 mem_prog[addr++].raw = 0x0ead00 | ((~0x43)&0xff);
1199 mem_prog[addr++].raw = 0x0ecd00 | ((~0x42)&0xff);
1201 mem_prog[addr++].raw = 0x0ead00 | ((~0xff)&0xff);
1202 mem_prog[addr++].raw = 0x0ecd00 | ((~0x01)&0xff);
1203 mem_prog[addr++].raw = 0x0bdfff;
1204 #endif
1206 #if 0
1207 //opcodes validation (CMP)
1208 unsigned addr=0;
1209 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1210 mem_prog[addr++].raw = 0x0e1d00 | ((~0x62)&0xff);
1212 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1213 mem_prog[addr++].raw = 0x0e1d00 | ((~0x99)&0xff);
1215 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1216 mem_prog[addr++].raw = 0x0e1d00 | ((~0x50)&0xff);
1218 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1219 mem_prog[addr++].raw = 0x0e1d00 | ((~0x47)&0xff);
1221 mem_prog[addr++].raw = 0x0ead00 | ((~0xb6)&0xff);
1222 mem_prog[addr++].raw = 0x0e1d00 | ((~0xb4)&0xff);
1224 mem_prog[addr++].raw = 0x0ead00 | ((~0x7e)&0xff);
1225 mem_prog[addr++].raw = 0x0e1d00 | ((~0x80)&0xff);
1227 mem_prog[addr++].raw = 0x0bdfff;
1228 #endif
1230 #if 0
1231 //opcodes validation (CMPA)
1232 unsigned addr=0;
1233 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1234 mem_prog[addr++].raw = 0x0e0d00 | ((~0x62)&0xff);
1236 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1237 mem_prog[addr++].raw = 0x0e0d00 | ((~0x50)&0xff);
1239 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1240 mem_prog[addr++].raw = 0x0e0d00 | ((~0x47)&0xff);
1242 mem_prog[addr++].raw = 0x0ead00 | ((~0x50)&0xff);
1243 mem_prog[addr++].raw = 0x0e0d00 | ((~0x99)&0xff);
1245 mem_prog[addr++].raw = 0x0ead00 | ((~0x90)&0xff);
1246 mem_prog[addr++].raw = 0x0e0d00 | ((~0x82)&0xff);
1248 mem_prog[addr++].raw = 0x0ead00 | ((~0x90)&0xff);
1249 mem_prog[addr++].raw = 0x0e0d00 | ((~0x90)&0xff);
1251 mem_prog[addr++].raw = 0x0ead00 | ((~0x90)&0xff);
1252 mem_prog[addr++].raw = 0x0e0d00 | ((~0xa7)&0xff);
1254 mem_prog[addr++].raw = 0x0ead00 | ((~0x90)&0xff);
1255 mem_prog[addr++].raw = 0x0e0d00 | ((~0x05)&0xff);
1258 mem_prog[addr++].raw = 0x0bdfff;
1259 #endif
1261 #if 0
1262 //opcodes validation
1263 unsigned addr=0;
1266 // ============== subsc
1267 mem_prog[addr++].raw = 0x0eae00; //move r0,ff
1268 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1269 mem_prog[addr++].raw = 0x0ead00 | ((~0x77)&0xff);
1270 mem_prog[addr++].raw = 0x0e7d00 | ((~0x07)&0xff);
1271 mem_prog[addr++].raw = 0x3fffff; //nop
1273 mem_prog[addr++].raw = 0x0eaeff; //move r0,0
1274 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1275 mem_prog[addr++].raw = 0x0ead00 | ((~0x77)&0xff);
1276 mem_prog[addr++].raw = 0x0e7d00 | ((~0x07)&0xff);
1277 mem_prog[addr++].raw = 0x3fffff; //nop
1279 mem_prog[addr++].raw = 0x0eae00; //move r0,ff
1280 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1281 mem_prog[addr++].raw = 0x0ead00 | ((~0x07)&0xff);
1282 mem_prog[addr++].raw = 0x0e7d00 | ((~0x77)&0xff);
1283 mem_prog[addr++].raw = 0x3fffff; //nop
1285 mem_prog[addr++].raw = 0x0eaeff; //move r0,0
1286 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1287 mem_prog[addr++].raw = 0x0ead00 | ((~0x07)&0xff);
1288 mem_prog[addr++].raw = 0x0e7d00 | ((~0x77)&0xff);
1289 mem_prog[addr++].raw = 0x3fffff; //nop
1291 mem_prog[addr++].raw = 0x0eaeff; //move r0,0
1292 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1293 mem_prog[addr++].raw = 0x0ead00 | ((~0xc6)&0xff);
1294 mem_prog[addr++].raw = 0x0e7d00 | ((~0x5a)&0xff);
1295 mem_prog[addr++].raw = 0x3fffff; //nop
1297 mem_prog[addr++].raw = 0x0eae00; //move r0,ff
1298 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1299 mem_prog[addr++].raw = 0x0ead00 | ((~0x6c)&0xff);
1300 mem_prog[addr++].raw = 0x0e7d00 | ((~0xa5)&0xff);
1301 mem_prog[addr++].raw = 0x3fffff; //nop
1303 mem_prog[addr++].raw = 0x0bdfff; //halt
1305 // ============== subdc
1306 mem_prog[addr++].raw = 0x0eae00; //move r0,ff
1307 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1308 mem_prog[addr++].raw = 0x0ead00 | ((~0x77)&0xff);
1309 mem_prog[addr++].raw = 0x0e5d00 | ((~0x07)&0xff);
1310 mem_prog[addr++].raw = 0x3fffff; //nop
1312 mem_prog[addr++].raw = 0x0eaeff; //move r0,0
1313 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1314 mem_prog[addr++].raw = 0x0ead00 | ((~0x77)&0xff);
1315 mem_prog[addr++].raw = 0x0e5d00 | ((~0x07)&0xff);
1316 mem_prog[addr++].raw = 0x3fffff; //nop
1318 mem_prog[addr++].raw = 0x0eae00; //move r0,ff
1319 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1320 mem_prog[addr++].raw = 0x0ead00 | ((~0x07)&0xff);
1321 mem_prog[addr++].raw = 0x0e5d00 | ((~0x77)&0xff);
1322 mem_prog[addr++].raw = 0x3fffff; //nop
1324 mem_prog[addr++].raw = 0x0eaeff; //move r0,0
1325 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1326 mem_prog[addr++].raw = 0x0ead00 | ((~0x07)&0xff);
1327 mem_prog[addr++].raw = 0x0e5d00 | ((~0x77)&0xff);
1328 mem_prog[addr++].raw = 0x3fffff; //nop
1330 mem_prog[addr++].raw = 0x0eae00; //move r0,ff
1331 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1332 mem_prog[addr++].raw = 0x0ead00 | ((~0xa5)&0xff);
1333 mem_prog[addr++].raw = 0x0e5d00 | ((~0x6c)&0xff);
1334 mem_prog[addr++].raw = 0x3fffff; //nop
1336 mem_prog[addr++].raw = 0x0eae00; //move r0,ff
1337 mem_prog[addr++].raw = 0x0d9fee; //cpl2 r0
1338 mem_prog[addr++].raw = 0x0ead00 | ((~0x5a)&0xff);
1339 mem_prog[addr++].raw = 0x0e5d00 | ((~0xc6)&0xff);
1340 mem_prog[addr++].raw = 0x3fffff; //nop
1342 mem_prog[addr++].raw = 0x0bdfff; //halt
1344 // ============== subs
1345 mem_prog[addr++].raw = 0x0ead00 | ((~0x56)&0xff);
1346 mem_prog[addr++].raw = 0x0e3d00 | ((~0x12)&0xff);
1347 mem_prog[addr++].raw = 0x3fffff; //nop
1349 mem_prog[addr++].raw = 0x0ead00 | ((~0x56)&0xff);
1350 mem_prog[addr++].raw = 0x0e3d00 | ((~0x90)&0xff);
1351 mem_prog[addr++].raw = 0x3fffff; //nop
1353 mem_prog[addr++].raw = 0x0ead00 | ((~0x12)&0xff);
1354 mem_prog[addr++].raw = 0x0e3d00 | ((~0x56)&0xff);
1355 mem_prog[addr++].raw = 0x3fffff; //nop
1357 mem_prog[addr++].raw = 0x0ead00 | ((~0x90)&0xff);
1358 mem_prog[addr++].raw = 0x0e3d00 | ((~0x56)&0xff);
1359 mem_prog[addr++].raw = 0x3fffff; //nop
1361 mem_prog[addr++].raw = 0x0bdfff; //halt
1363 // ============== subd
1364 mem_prog[addr++].raw = 0x0ead00 | ((~0x56)&0xff);
1365 mem_prog[addr++].raw = 0x0e4d00 | ((~0x12)&0xff);
1366 mem_prog[addr++].raw = 0x3fffff; //nop
1368 mem_prog[addr++].raw = 0x0ead00 | ((~0x56)&0xff);
1369 mem_prog[addr++].raw = 0x0e4d00 | ((~0x90)&0xff);
1370 mem_prog[addr++].raw = 0x3fffff; //nop
1372 mem_prog[addr++].raw = 0x0ead00 | ((~0x12)&0xff);
1373 mem_prog[addr++].raw = 0x0e4d00 | ((~0x56)&0xff);
1374 mem_prog[addr++].raw = 0x3fffff; //nop
1376 mem_prog[addr++].raw = 0x0ead00 | ((~0x90)&0xff);
1377 mem_prog[addr++].raw = 0x0e4d00 | ((~0x56)&0xff);
1378 mem_prog[addr++].raw = 0x3fffff; //nop
1380 mem_prog[addr++].raw = 0x0bdfff;
1381 #endif