/* * dlxsim.c * $Id: dlxsim.c,v 1.22 2005/01/28 16:12:45 obi Exp $ * Christoph Berg * * 010729 */ // TODO check disassemble commands (address translation?) #include #include #include #include #include #include #include "dlx.h" #include "help.h" #include "hex.h" #include "memory.h" #include "terminal.h" #define VERSION "v4.0alpha" // ^C handling -------- int sigint; void sigint_handler() { sigint = 1; } // -------------------- void check_machine() { /* * If any of these checks fail: this program was written for the x86 * architecture (little endian, 4 bytes integers). If you are going to * run it on a different architecture, you probably have to change (at * least) the memory referencing code (that is, (int *) casts). * You will also have to look at the include files and the endian * conversion in hex.c */ char p[] = "1234"; assert(*(int *)p == 0x34333231); // check for little endian assert(sizeof(int) == 4); // check for integer size 32 bit } void set_option(char *option) { if(option == NULL) { printf("set: no option given\n"); return; } if(!strcmp(option, "intflip")) { intflip = 1; return; } if(!strcmp(option, "nointflip")) { intflip = 0; return; } if(!strcmp(option, "trace")){ state.trace = 1; return; } if(!strcmp(option, "notrace")){ state.trace = 0; return; } if(!strcmp(option, "notracetrap")){ state.tracetrap = 0; return; } if(!strcmp(option, "tracetrap")){ state.tracetrap = 1; return; } if(!strcmp(option, "stop_never")){ state.stopmask = 0; return; } if(!strcmp(option, "stop_all")){ state.stopmask = -1; return; } if(!strcmp(option, "stop_trap")){ state.stopmask |= (STOP_TRAP_EXIT|STOP_TRAP_OPEN|STOP_TRAP_CLOSE|STOP_TRAP_READ|STOP_TRAP_WRITE|STOP_TRAP_INTERRUPT); return; } if(!strcmp(option, "no_stop_trap")){ state.stopmask &= ~(STOP_TRAP_EXIT|STOP_TRAP_OPEN|STOP_TRAP_CLOSE|STOP_TRAP_READ|STOP_TRAP_WRITE|STOP_TRAP_INTERRUPT); return; } if(!strcmp(option, "stop_trap_exit")){ state.stopmask |= STOP_TRAP_EXIT; return; } if(!strcmp(option, "no_stop_trap_exit")){ state.stopmask &= ~STOP_TRAP_EXIT; return; } if(!strcmp(option, "stop_trap_open")){ state.stopmask |= STOP_TRAP_OPEN; return; } if(!strcmp(option, "no_stop_trap_open")){ state.stopmask &= ~STOP_TRAP_OPEN; return; } if(!strcmp(option, "stop_trap_close")){ state.stopmask |= STOP_TRAP_CLOSE; return; } if(!strcmp(option, "no_stop_trap_close")){ state.stopmask &= ~STOP_TRAP_CLOSE; return; } if(!strcmp(option, "stop_trap_read")){ state.stopmask |= STOP_TRAP_READ; return; } if(!strcmp(option, "no_stop_trap_read")){ state.stopmask &= ~STOP_TRAP_READ; return; } if(!strcmp(option, "stop_trap_write")){ state.stopmask |= STOP_TRAP_WRITE; return; } if(!strcmp(option, "no_stop_trap_write")){ state.stopmask &= ~STOP_TRAP_WRITE; return; } if(!strcmp(option, "stop_trap_irq")){ state.stopmask |= STOP_TRAP_INTERRUPT; return; } if(!strcmp(option, "no_stop_trap_irq")){ state.stopmask &= ~STOP_TRAP_INTERRUPT; return; } if(!strcmp(option, "stop_jisr")){ state.stopmask |= STOP_JISR; return; } if(!strcmp(option, "no_stop_jisr")){ state.stopmask &= ~STOP_JISR; return; } if(!strcmp(option, "stop_rfe")){ state.stopmask |= STOP_RFE; return; } if(!strcmp(option, "no_stop_rfe")){ state.stopmask &= ~STOP_RFE; return; } if(!strcmp(option, "stop_warning")){ state.stopmask |= STOP_WARNING; return; } if(!strcmp(option, "no_stop_warning")){ state.stopmask &= ~STOP_WARNING; return; } if(!strcmp(option, "stop_chmod")){ state.stopmask |= STOP_CHMOD; return; } if(!strcmp(option, "no_stop_chmod")){ state.stopmask &= ~STOP_CHMOD; return; } if(!strcmp(option, "stop_bbend")){ state.stopmask |= STOP_BBEND; return; } if(!strcmp(option, "no_stop_bbend")){ state.stopmask &= ~STOP_BBEND; return; } if(!strcmp(option,"stop_jal")){ state.stopmask |= STOP_JAL; return; } if(!strcmp(option,"no_stop_jal")){ state.stopmask &= ~STOP_JAL; return; } if (!strcmp(option,"stop_jr31")){ state.stopmask |= STOP_JR31; return; } if (!strcmp(option,"no_stop_jr31")){ state.stopmask &= ~STOP_JR31; return; } printf("set: unknown option `%s'\n", option); } void parse_input(char *line) { char *token; int oldmask; token = strtok(line, TOK_SEP); if(token == NULL || !strcmp(token, "step")) { // return pressed // always trace single steps int oldtrace = state.trace; state.trace = 1; step(); state.trace = oldtrace; return; } if(!strcmp(token, "fdump")){ int start = str2int(strtok(NULL, TOK_SEP)); int length = str2int(strtok(NULL, TOK_SEP)); length = length == 0 ? 0x100 : length; fdump(state.memory, start, length); return; } if(!strcmp(token, "bindump")) { int start = str2int(strtok(NULL, TOK_SEP)); int length = str2int(strtok(NULL, TOK_SEP)); length = length == 0 ? 0x40 : length; bindump(state.memory, start, length); return; } if(!strcmp(token, "disassemble")) { int start = str2int(strtok(NULL, TOK_SEP)); int length = str2int(strtok(NULL, TOK_SEP)); length = length == 0 ? 0x40 : length; disassemble_memory(state.memory, start, length); return; } if(!strcmp(token, "dump") || !strcmp(token, "hexdump")) { int start = str2int(strtok(NULL, TOK_SEP)); int length = str2int(strtok(NULL, TOK_SEP)); length = length == 0 ? 0x100 : length; hexdump(state.memory, start, length); return; } if(!strcmp(token, "exit") || !strcmp(token, "quit")) exit(0); if(!strcmp(token, "explain")) { int start = str2int(strtok(NULL, TOK_SEP)); explain(state.memory, start); return; } if(!strcmp(token, "exrequest")) { int index = str2int(strtok(NULL, TOK_SEP)); if( index < 0 || index > 19 ) { printf("must specify index between 1 and 19 (corresponding to exception cause 13 to 31)\n"); return; } exrequest(index); return; } if(!strcmp(token, "exservice")) { int index = str2int(strtok(NULL, TOK_SEP)); if( index < 0 || index > 19 ) { printf("must specify index between 1 and 19 (corresponding to exception cause 13 to 31)\n"); return; } exservice(index); return; } if(!strcmp(token, "fill")) { int start = str2int(strtok(NULL, TOK_SEP)); int length = str2int(strtok(NULL, TOK_SEP)); int c = 0; length = length == 0 ? 1 : length; token = strtok(NULL, TOK_SEP); if(token != NULL) { c = token[0]; } fill_memory(state.memory, start, length, c); return; } if(!strcmp(token, "fillcount")) { int start = str2int(strtok(NULL, TOK_SEP)); int length = str2int(strtok(NULL, TOK_SEP)); length = length == 0 ? 0x100 : length; count_memory(state.memory, start, length); return; } if(!strcmp(token, "fpr")) { print_fpr(3); return; } if(!strcmp(token, "fpr.s")) { char *p; int reg; if( (p=strtok(NULL, TOK_SEP)) ) { // dirty... if( (*p == 'f' || *p == 'F') ) p++; if( (*p == 'r' || *p == 'R') ) p++; reg = str2int(p); if( reg >= 0 && reg < GPR_SIZE ) *((float*)(state.fpr + reg)) = (float) atof(strtok(NULL, TOK_SEP)); } else print_fpr(1); return; } if(!strcmp(token, "fpr.d")) { char *p; int reg; if( (p=strtok(NULL, TOK_SEP)) ) { // dirty... if( (*p == 'f' || *p == 'F') ) p++; if( (*p == 'r' || *p == 'R') ) p++; reg = str2int(p); if( reg >= 0 && reg < GPR_SIZE && !(reg&0x1) ) *((double*)(state.fpr + reg)) = atof(strtok(NULL, TOK_SEP)); } else print_fpr(2); return; } if(!strcmp(token, "gpr")) { char *p; int reg; if( (p=strtok(NULL, TOK_SEP)) ) { if( *p == 'r' || *p == 'R' ) p++; reg = str2int(p); if( reg > 0 && reg < GPR_SIZE ) state.gpr[reg] = str2int(strtok(NULL, TOK_SEP)); } else print_gpr(); return; } if(!strcmp(token, "spr")) { char *p; int reg; if( (p=strtok(NULL, TOK_SEP)) ) { for( reg = 0; reg < SPR_SIZE; reg++ ) if( !strcasecmp(spr_name[reg],p) ) break; if( reg==SPR_SIZE ) { if( *p == 's' || *p == 'S' ) p++; reg = str2int(p); } if( reg >= 0 && reg < SPR_SIZE ) state.spr[reg] = str2int(strtok(NULL, TOK_SEP)); } else print_spr(); return; } if(!strcmp(token, "help")) { help(); return; } if(!strcmp(token, "jump")) { int dpc = str2int(strtok(NULL, TOK_SEP)); state.dpc = dpc; state.pc = dpc + 4; return; } if(!strcmp(token, "load")) { if((token = strtok(NULL, TOK_SEP)) == NULL) { printf("no filename given\n"); return; } init_state(); init_prof(); load_file(token); return; } if(!strcmp(token, "number")) { int number = str2int(strtok(NULL, TOK_SEP)); printf("0x%x %d 0%o %s\n", number, number, number, byte2bin(number)); return; } if(!strcmp(token, "poke")) { int pos = str2int(strtok(NULL, TOK_SEP)); int data = str2int(strtok(NULL, TOK_SEP)); poke(state.memory, pos, data); return; } if(!strcmp(token, "prof")) { print_prof(); return; } if(!strcmp(token, "reset")) { init_state(); init_memory(state.memorysize); return; } if(!strcmp(token, "run")) { int i; int steps = str2int(strtok(NULL, TOK_SEP)); sigint = 0; for(i = 0; i < steps && !sigint && !state.stopflag; i++) { step(); } printf("%d out of %d instructions done\n", i, steps); return; } if(!strcmp(token, "runto")) { int breakpoint = str2int(strtok(NULL, TOK_SEP)); int i = 0; sigint = 0; do { step(); i++; } while(state.dpc != breakpoint && !sigint && !state.stopflag); if( state.dpc != breakpoint ) printf("stopping prematurely at dpc=0x%08x\n", state.dpc); else printf("stopping at dpc=0x%08x\n", state.dpc); return; } if(!strcmp(token, "state")) { print_state(); return; } if(!strcmp(token, "set")) { set_option(strtok(NULL, TOK_SEP)); return; } if(!strcmp(token, "stepbb")) { sigint = 0; oldmask = state.stopmask; do { step(); } while(!sigint && !state.stopflag); state.stopmask = oldmask; return; } printf("unknown command `%s'\n", token); } int main(int argc, char **argv) { printf("dlxsim " VERSION " (" __DATE__ ")\n"); //printf("TODO: frame pointer, main return address?\n"); check_machine(); init_state(); init_memory(INIT_MEMORY_SIZE); init_readline(); init_prof(); signal(SIGINT, sigint_handler); // TODO getopt! argv++; argc--; // skip command name if(argc==0) { fprintf(stderr,"\nUsage: dlxsim [-vm] [-t INSTRUCTIONS] object.o\n"); exit(1); } while( argc > 1 ) { if( !strcmp("-vm",argv[0]) | !strcmp("--vm",argv[0]) ) { init_arch( ARCH_VM ); argv++; argc--; } else if( !strcmp("-t",argv[0]) | !strcmp("--t",argv[0]) ) { argv++; argc--; if(argc>1) { init_timer(atoi(argv[0])); argv++; argc--; } else { fprintf(stderr,"?Must specify timer frequency (currently: instruction count) with -t option.\n"); exit(1); } } } if(argc==0) { fprintf(stderr,"?Must specify object file to load as last argument.\n"); exit(1); } load_file(argv[0]); for(;;) { int *cp = (int *)(state.memory+physicaladdress(state.dpc)); char *line, prompt[60]; sprintf(prompt, "0x%08x [0x%08x]: %-17s $ ", state.dpc, physicaladdress(state.dpc), disassemble(*cp)); // TODO avoid segfault due to wrong translation, very ugly line = get_str(prompt); assert(line != NULL); parse_input(line); } return 0; }