2 * Simulator of microcontrollers (xa.cc)
4 * Copyright (C) 1999,2002 Drotos Daniel, Talker Bt.
6 * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
7 * Other contributors include:
8 * Karl Bongers karl@turbobit.com,
12 /* This file is part of microcontroller simulator: ucsim.
14 UCSIM is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 UCSIM is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with UCSIM; see the file COPYING. If not, write to the Free
26 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
50 * Base type of xa controllers
53 cl_xa::cl_xa(class cl_sim *asim):
62 cl_uc::init(); /* Memories now exist */
66 wmem_direct = (TYPE_UWORD *) &mem_direct[0];
68 /* set SCR to osc/4, native XA mode, flat 24 */
70 /* initialize SP to 100H */
72 /* set PSW from reset vector */
74 /* set PC from reset vector */
77 printf("The XA Simulator is in development, UNSTABLE, DEVELOPERS ONLY!\n");
83 cl_xa::id_string(void)
85 return("unspecified XA");
90 * Making elements of the controller
94 cl_xa::get_mem_size(enum mem_class type)
98 case MEM_ROM: return(0x10000);
99 case MEM_XRAM: return(0x10000);
102 return(cl_uc::get_mem_size(type));
106 cl_xa::mk_hw_elements(void)
109 /* t_uc::mk_hw() does nothing */
114 * Help command interpreter
120 // this should be unused, we need to make main prog code
121 // independent of any array thing.
122 printf("ERROR - Using disass[] table in XA sim code!\n");
123 return(glob_disass_xa);
126 struct name_entry *cl_xa::sfr_tbl(void)
131 struct name_entry *cl_xa::bit_tbl(void)
137 cl_xa::inst_length(t_addr addr)
141 get_disasm_info(addr, &len, NULL, NULL, NULL, NULL);
147 cl_xa::inst_branch(t_addr addr)
151 get_disasm_info(addr, NULL, &b, NULL, NULL, NULL);
157 cl_xa::longest_inst(void)
162 static char dir_name[64];
163 char *cl_xa::get_dir_name(short addr) {
164 if (!get_name(addr, sfr_tbl(), dir_name)) {
165 sprintf (dir_name, "0x%03x", addr);
170 static char bit_name[64];
171 char *cl_xa::get_bit_name(short addr) {
172 if (!get_name(addr, bit_tbl(), bit_name)) {
173 sprintf (bit_name, "0x%03x", addr);
178 /*--------------------------------------------------------------------
179 get_disasm_info - Given an address, return information about the opcode
181 addr - address of opcode we want information on.
182 ret_len - return length of opcode.
183 ret_branch - return a character which indicates if we are
184 a branching opcode. Used by main app to implement "Next"
185 function which steps over functions.
186 immed_offset - return a number which represents the number of bytes
187 offset to where any immediate data is(tail end of opcode). Used
188 for printing disassembly.
189 operands - return a key indicating the form of the operands,
190 used for printing the disassembly.
191 mnemonic - return a key indicating the mnemonic of the instruction.
193 Return value: Return the operand code formed by either the single
194 byte opcode or 2 bytes of the opcode for multi-byte opcodes.
196 Note: Any of the return pointer parameters can be set to NULL to
197 indicate the caller does not want the information.
198 |--------------------------------------------------------------------*/
200 cl_xa::get_disasm_info(t_addr addr,
211 int start_addr = addr;
213 code= get_mem(MEM_ROM, addr++);
216 while (disass_xa[i].mnemonic != NOP)
220 code = (code << 8) | get_mem(MEM_ROM, addr++);
222 while ((code & disass_xa[i].mask) != disass_xa[i].code &&
223 disass_xa[i].mnemonic != BAD_OPCODE)
228 *ret_len = disass_xa[i].length;
230 *ret_branch = disass_xa[i].branch;
233 *immed_offset = immed_n;
234 else *immed_offset = (addr - start_addr);
237 *parms = disass_xa[i].operands;
240 *mnemonic = disass_xa[i].mnemonic;
246 static char *w_reg_strs[] = {
256 static char *b_reg_strs[] = {
266 /*--------------------------------------------------------------------
267 disass - Disassemble an opcode.
268 addr - address of opcode to disassemble/print.
269 sep - optionally points to string(tab) to use as separator.
270 |--------------------------------------------------------------------*/
272 cl_xa::disass(t_addr addr, char *sep)
274 char work[256], parm_str[40];
278 int immed_offset = 0;
285 code = get_disasm_info(addr, &len, NULL, &immed_offset, &operands, &mnemonic);
287 if (mnemonic == BAD_OPCODE) {
288 buf= (char*)malloc(30);
289 strcpy(buf, "UNKNOWN/INVALID");
294 reg_strs = w_reg_strs;
296 reg_strs = b_reg_strs;
299 // the repeating common parameter encoding for ADD, ADDC, SUB, AND...
301 sprintf(parm_str, "%s,%s",
302 reg_strs[((code >> 4) & 0xf)],
303 reg_strs[(code & 0xf)]);
306 sprintf(parm_str, "%s,[%s]",
307 reg_strs[((code >> 4) & 0xf)],
308 w_reg_strs[(code & 0xf)]);
311 sprintf(parm_str, "[%s],%s",
312 w_reg_strs[(code & 0x7)],
313 reg_strs[((code >> 4) & 0xf)] );
316 sprintf(parm_str, "%s,[%s+%02d]",
317 reg_strs[((code >> 4) & 0xf)],
318 w_reg_strs[(code & 0x7)],
319 get_mem(MEM_ROM, addr+immed_offset));
323 sprintf(parm_str, "[%s+%02d],%s",
324 w_reg_strs[(code & 0x7)],
325 get_mem(MEM_ROM, addr+immed_offset),
326 reg_strs[((code >> 4) & 0xf)] );
330 sprintf(parm_str, "%s,[%s+%04d]",
331 reg_strs[((code >> 4) & 0xf)],
332 w_reg_strs[(code & 0x7)],
333 (short)((get_mem(MEM_ROM, addr+immed_offset+1)) |
334 (get_mem(MEM_ROM, addr+immed_offset)<<8)) );
339 sprintf(parm_str, "[%s+%04d],%s",
340 w_reg_strs[(code & 0x7)],
341 (short)((get_mem(MEM_ROM, addr+immed_offset+1)) |
342 (get_mem(MEM_ROM, addr+immed_offset)<<8)),
343 reg_strs[((code >> 4) & 0xf)] );
348 sprintf(parm_str, "%s,[%s+]",
349 reg_strs[((code >> 4) & 0xf)],
350 w_reg_strs[(code & 0xf)]);
353 sprintf(parm_str, "[%s+],%s",
354 w_reg_strs[(code & 0x7)],
355 reg_strs[((code >> 4) & 0xf)] );
358 sprintf(parm_str, "%s,%s",
359 get_dir_name(((code & 0x7) << 8) |
360 get_mem(MEM_ROM, addr+immed_offset)),
361 reg_strs[((code >> 4) & 0xf)] );
365 sprintf(parm_str, "%s,%s",
366 reg_strs[((code >> 4) & 0xf)],
367 get_dir_name(((code & 0x7) << 8) |
368 get_mem(MEM_ROM, addr+immed_offset)));
372 sprintf(parm_str, "%s,#0x%02x",
373 b_reg_strs[((code >> 4) & 0xf)],
374 get_mem(MEM_ROM, addr+immed_offset) );
378 sprintf(parm_str, "%s,#0x%04x",
379 reg_strs[((code >> 4) & 0xf)],
380 (short)((get_mem(MEM_ROM, addr+immed_offset+1)) |
381 (get_mem(MEM_ROM, addr+immed_offset)<<8)) );
386 sprintf(parm_str, "[%s], 0x%02x",
387 w_reg_strs[((code >> 4) & 0x7)],
388 get_mem(MEM_ROM, addr+immed_offset) );
392 sprintf(parm_str, "[%s], 0x%04x",
393 w_reg_strs[((code >> 4) & 0x7)],
394 (short)((get_mem(MEM_ROM, addr+immed_offset+1)) |
395 (get_mem(MEM_ROM, addr+immed_offset)<<8)) );
400 sprintf(parm_str, "[%s+], 0x%02x",
401 w_reg_strs[((code >> 4) & 0x7)],
402 get_mem(MEM_ROM, addr+immed_offset) );
405 case IREGINC_DATA16 :
406 sprintf(parm_str, "[%s+], 0x%04x",
407 w_reg_strs[((code >> 4) & 0x7)],
408 (short)((get_mem(MEM_ROM, addr+immed_offset+1)) |
409 (get_mem(MEM_ROM, addr+immed_offset)<<8)) );
413 case IREGOFF8_DATA8 :
414 sprintf(parm_str, "[%s+%02d], 0x%02x",
415 w_reg_strs[((code >> 4) & 0x7)],
416 get_mem(MEM_ROM, addr+immed_offset),
417 get_mem(MEM_ROM, addr+immed_offset+1) );
420 case IREGOFF8_DATA16 :
421 sprintf(parm_str, "[%s+%02d], 0x%04x",
422 w_reg_strs[((code >> 4) & 0x7)],
423 get_mem(MEM_ROM, addr+immed_offset),
424 (short)((get_mem(MEM_ROM, addr+immed_offset+2)) |
425 (get_mem(MEM_ROM, addr+immed_offset+1)<<8)) );
428 case IREGOFF16_DATA8 :
429 sprintf(parm_str, "[%s+%04d], 0x%02x",
430 w_reg_strs[((code >> 4) & 0x7)],
431 (short)((get_mem(MEM_ROM, addr+immed_offset+1)) |
432 (get_mem(MEM_ROM, addr+immed_offset+0)<<8)),
433 get_mem(MEM_ROM, addr+immed_offset+2) );
436 case IREGOFF16_DATA16 :
437 sprintf(parm_str, "[%s+%04d], 0x%04x",
438 w_reg_strs[((code >> 4) & 0x7)],
439 (short)((get_mem(MEM_ROM, addr+immed_offset+1)) |
440 (get_mem(MEM_ROM, addr+immed_offset+0)<<8)),
441 (short)((get_mem(MEM_ROM, addr+immed_offset+3)) |
442 (get_mem(MEM_ROM, addr+immed_offset+2)<<8)) );
446 sprintf(parm_str, "%s,#0x%02x",
447 get_dir_name(((code & 0x0070) << 4) |
448 get_mem(MEM_ROM, addr+immed_offset)),
449 get_mem(MEM_ROM, addr+immed_offset+1));
453 sprintf(parm_str, "%s,#0x%04x",
454 get_dir_name(((code & 0x0070) << 4) |
455 get_mem(MEM_ROM, addr+immed_offset)),
456 get_mem(MEM_ROM, addr+immed_offset+2) +
457 (get_mem(MEM_ROM, addr+immed_offset+1)<<8));
462 case NO_OPERANDS : // for NOP
463 strcpy(parm_str, "");
466 strcpy(parm_str, "C_BIT");
469 strcpy(parm_str, "REG_DATA4");
472 strcpy(parm_str, "IREG_DATA4");
475 strcpy(parm_str, "IREGINC_DATA4");
477 case IREGOFF8_DATA4 :
478 strcpy(parm_str, "IREGOFF8_DATA4");
480 case IREGOFF16_DATA4 :
481 strcpy(parm_str, "IREGOFF16_DATA4");
484 sprintf(parm_str, "%s,#0x%x",
485 get_dir_name(((code & 0x70)<<4) |
486 get_mem(MEM_ROM, addr+2)),
490 sprintf(parm_str, "%s",
491 get_dir_name(((code & 0x007) << 4) +
492 get_mem(MEM_ROM, addr+2)));
495 sprintf(parm_str, "%s",
496 reg_strs[((code >> 4) & 0xf)] );
499 sprintf(parm_str, "[%s]",
500 reg_strs[((code >> 4) & 0xf)] );
503 sprintf(parm_str, "%s",
504 get_bit_name(((code&0x0003)<<8) + get_mem(MEM_ROM, addr+2)));
507 sprintf(parm_str, "%s,0x%04x",
508 get_bit_name((code&0x0003)<<8) + get_mem(MEM_ROM, addr+2),
509 ((signed char)get_mem(MEM_ROM, addr+3)*2+addr+len)&0xfffe);
512 strcpy(parm_str, "ADDR24");
515 sprintf(parm_str, "%s,0x%04x",
516 reg_strs[(code>>4) & 0xf],
517 ((signed char)get_mem(MEM_ROM, addr+2)*2+addr+len)&0xfffe);
520 sprintf(parm_str, "%s,0x%04x",
521 get_dir_name(((code&0x07)<<8) +
522 get_mem(MEM_ROM, addr+2)),
523 ((signed char)get_mem(MEM_ROM, addr+2)*2+addr+len)&0xfffe);
527 sprintf(parm_str, "0x%04x",
528 ((signed char)get_mem(MEM_ROM, addr+1)*2+addr+len)&0xfffe);
531 sprintf(parm_str, "0x%04x",
532 ((signed short)((get_mem(MEM_ROM, addr+1)<<8) + get_mem(MEM_ROM, addr+2))*2+addr+len)&0xfffe);
536 strcpy(parm_str, "RLIST");
539 case REG_DIRECT_REL8 :
540 sprintf(parm_str, "%s,%s,0x%02x",
541 reg_strs[((code >> 4) & 0xf)],
542 get_dir_name(((code & 0x7) << 8) +
543 get_mem(MEM_ROM, addr+immed_offset)),
544 ((signed char) get_mem(MEM_ROM, addr+immed_offset+1) * 2) & 0xfffe );
546 case REG_DATA8_REL8 :
547 sprintf(parm_str, "%s,#0x%04x,0x%02x",
548 reg_strs[((code >> 4) & 0xf)],
549 get_mem(MEM_ROM, addr+immed_offset),
550 ((signed char)get_mem(MEM_ROM, addr+immed_offset+1) * 2) & 0xfffe );
552 case REG_DATA16_REL8 :
553 sprintf(parm_str, "%s,#0x%02x,0x%02x",
554 w_reg_strs[((code >> 4) & 0x7)*2],
555 get_mem(MEM_ROM, addr+immed_offset+1) +
556 (get_mem(MEM_ROM, addr+immed_offset+0)<<8),
557 ((signed char)get_mem(MEM_ROM, addr+immed_offset+2) * 2) & 0xfffe );
559 case IREG_DATA8_REL8 :
560 sprintf(parm_str, "[%s],#0x%04x,0x%02x",
561 reg_strs[((code >> 4) & 0x7)],
562 get_mem(MEM_ROM, addr+immed_offset),
563 ((signed char)get_mem(MEM_ROM, addr+immed_offset+1) * 2) & 0xfffe );
565 case IREG_DATA16_REL8 :
566 sprintf(parm_str, "[%s],#0x%02x,0x%02x",
567 w_reg_strs[((code >> 4) & 0x7)*2],
568 get_mem(MEM_ROM, addr+immed_offset+1) +
569 (get_mem(MEM_ROM, addr+immed_offset+0)<<8),
570 ((signed char)get_mem(MEM_ROM, addr+immed_offset+2) * 2) & 0xfffe );
574 strcpy(parm_str, "???");
578 sprintf(work, "%s %s",
579 op_mnemonic_str[ mnemonic ],
582 p= strchr(work, ' ');
589 buf= (char *)malloc(6+strlen(p)+1);
591 buf= (char *)malloc((p-work)+strlen(sep)+strlen(p)+1);
592 for (p= work, b= buf; *p != ' '; p++, b++)
598 while (strlen(buf) < 6)
607 /*--------------------------------------------------------------------
608 print_regs - Print the registers, flags and other useful information.
609 Used to print a status line while stepping through the code.
610 |--------------------------------------------------------------------*/
612 cl_xa::print_regs(class cl_console *con)
617 con->dd_printf("CA---VNZ Flags: %02x ", flags);
618 con->dd_printf("R0:%04x R1:%04x R2:%04x R3:%04x\n",
619 reg2(0), reg2(1), reg2(2), reg2(3));
621 con->dd_printf("%c%c---%c%c%c ",
622 (flags & BIT_C)?'1':'0',
623 (flags & BIT_AC)?'1':'0',
624 (flags & BIT_V)?'1':'0',
625 (flags & BIT_N)?'1':'0',
626 (flags & BIT_Z)?'1':'0');
628 con->dd_printf("R4:%04x R5:%04x R6:%04x R7(SP):%04x ES:%04x DS:%04x\n",
629 reg2(4), reg2(5), reg2(6), reg2(7), 0, 0);
631 print_disass(PC, con);
635 /*--------------------------------------------------------------------
636 exec_inst - Called to implement simulator execution of 1 instruction
637 at the current PC(program counter) address.
638 |--------------------------------------------------------------------*/
639 int cl_xa::exec_inst(void)
647 return(resBREAKPOINT);
650 /* the following lookups make for a slow simulation, we will
651 figure out how to make it fast later... */
653 /* scan to see if its a 1 byte-opcode */
656 while ( ((code & disass_xa[i].mask) != disass_xa[i].code ||
657 ((disass_xa[i].mask & 0x00ff) != 0)) /* one byte op code */
659 disass_xa[i].mnemonic != BAD_OPCODE)
662 if (disass_xa[i].mnemonic == BAD_OPCODE) {
663 /* hit the end of the list, must be a 2 or more byte opcode */
664 /* fetch another code byte and search the list again */
665 //if (fetch(&code2)) ?not sure if break allowed in middle of opcode?
666 // return(resBREAKPOINT);
667 code |= fetch(); /* add 2nd opcode */
670 while ((code & disass_xa[i].mask) != disass_xa[i].code &&
671 disass_xa[i].mnemonic != BAD_OPCODE)
673 /* we should have found the opcode by now, if not invalid entry at eol */
676 operands = (int)(disass_xa[i].operands);
677 switch (disass_xa[i].mnemonic)
680 return inst_ADD(code, operands);
682 return inst_ADDC(code, operands);
684 return inst_ADDS(code, operands);
686 return inst_AND(code, operands);
688 return inst_ANL(code, operands);
690 return inst_ASL(code, operands);
692 return inst_ASR(code, operands);
694 return inst_BCC(code, operands);
696 return inst_BCS(code, operands);
698 return inst_BEQ(code, operands);
700 return inst_BG(code, operands);
702 return inst_BGE(code, operands);
704 return inst_BGT(code, operands);
706 return inst_BKPT(code, operands);
708 return inst_BL(code, operands);
710 return inst_BLE(code, operands);
712 return inst_BLT(code, operands);
714 return inst_BMI(code, operands);
716 return inst_BNE(code, operands);
718 return inst_BNV(code, operands);
720 return inst_BOV(code, operands);
722 return inst_BPL(code, operands);
724 return inst_BR(code, operands);
726 return inst_CALL(code, operands);
728 return inst_CJNE(code, operands);
730 return inst_CLR(code, operands);
732 return inst_CMP(code, operands);
734 return inst_CPL(code, operands);
736 return inst_DA(code, operands);
742 return inst_DIV(code, operands);
744 return inst_DJNZ(code, operands);
746 return inst_FCALL(code, operands);
748 return inst_FJMP(code, operands);
750 return inst_JB(code, operands);
752 return inst_JBC(code, operands);
754 return inst_JMP(code, operands);
756 return inst_JNB(code, operands);
758 return inst_JNZ(code, operands);
760 return inst_JZ(code, operands);
762 return inst_LEA(code, operands);
764 return inst_LSR(code, operands);
766 return inst_MOV(code, operands);
768 return inst_MOVC(code, operands);
770 return inst_MOVS(code, operands);
772 return inst_MOVX(code, operands);
776 return inst_MUL(code, operands);
778 return inst_NEG(code, operands);
780 return inst_NOP(code, operands);
782 return inst_NORM(code, operands);
784 return inst_OR(code, operands);
786 return inst_ORL(code, operands);
789 return inst_POP(code, operands);
792 return inst_PUSH(code, operands);
794 return inst_RESET(code, operands);
796 return inst_RET(code, operands);
798 return inst_RETI(code, operands);
800 return inst_RL(code, operands);
802 return inst_RLC(code, operands);
804 return inst_RR(code, operands);
806 return inst_RRC(code, operands);
808 return inst_SETB(code, operands);
810 return inst_SEXT(code, operands);
812 return inst_SUB(code, operands);
814 return inst_SUBB(code, operands);
816 return inst_TRAP(code, operands);
818 return inst_XCH(code, operands);
820 return inst_XOR(code, operands);
830 PC= get_mem_size(MEM_ROM)-1;
831 //tick(-clock_per_cycle());
832 sim->stop(resINV_INST);
837 /* End of xa.src/xa.cc */