/* very simple and crude simulator for the 6811 some instructions aren't there yet (notably converning multiplication and interrupts) and the interface only allows stepping. this should be easily rectifiable, however, and the simple structure should make grafting on a graphical interface quite simple. to run the simulator, just provide the name of an object file on the command line. the object file must be in s19 format, and must include a reset vector in order to tell the simulator where to start execution. simulation proceeds one instruction at a time, with a register and page zero memory dump being performed at each step. several simple commands are supported, but additional commands to modify memory, cause interrupts and simulate the special registers would all be nice, and relatively easy to add. the current command set includes l [address [n]] - disassemble n instructions starting at address g [address [n]] - go starting at address for n steps. s [n] - step n times (n=1 default) b [address[cnt]] - set a breakpoint, which will stop cnt times t [address[cnt]] - set a temporary breakpoint. - step once $Log: main.c,v $ * Revision 1.11 1994/03/22 22:16:45 ted * added type declarations to get gcc -Wall to keep quiet * * Revision 1.10 1994/03/22 21:29:51 ted * added memory modification command * * Revision 1.9 1993/02/02 01:03:43 ted * added reset, and help commands, got ready to * add interrupts. * * Revision 1.8 1993/01/30 00:56:15 ted * fixed up small problems with help * * Revision 1.7 1993/01/30 00:00:35 ted * fixed some pointer bugs and added help and reset * commands * * Revision 1.6 1993/01/28 02:27:14 ted * and fixed it so INLINE needn't be used * * Revision 1.5 1993/01/28 02:25:40 ted * oops... fixed a simple screwup in the interrupt * catching logic * * Revision 1.4 1993/01/28 02:05:20 ted * simple speed ups based on better inlining, * and passing a pointer to the state instead of * passing the actual state. * * Revision 1.3 1993/01/27 23:22:34 ted * added some commands for multi-stepping and support for breakpoints * and disassembling * */ #ifndef INLINE #define INLINE #endif #include #include #include #include "sim.h" /* how to handle all other op codes */ void bad_op(m6811 state) { fprintf(stderr, "bad op at pc=%04lx\n", state.pc&0xffff); getchar(); } /* load memory from s records. each line of an s record file consists of S1 byte_count address data checksum where the byte_count counts the address, data and checksum the address is high byte first, the checksum doesn't usually matter. the last record of an s record file consists of S9 byte_count stuff we just ignore the content of this line. */ void load_code(FILE *f, byte *memory) { int key, byte_count, add, byte, csum; if (fscanf(f, "S%1x%2x%4x", &key, &byte_count, &add) != 3) { key = 9; } while (key == 1) { int i; for (i=0;it, get_d(state), get_x(state), get_y(state)); printf(" breakpoints -> "); for (i=0;i<65536;i++) { if (breaks[i]<0) { printf("%04x ", 0xffff&i); } else if (breaks[i]>0) { printf("%04x[%d] ", 0xffff&i, breaks[i]); } } printf("\n"); printf("SP %04lX PC %04lX ", get_s(state), get_pc(state)); /* and next insruction */ (void) disassemble(stdout, memory+get_pc(state)); /* followed by condition codes */ printf(" "); printf("%c %c %c %c %c %c %c %c\n", get_stop_disable(state)?'S':'.', get_x_interrupt(state)?'X':'.', get_half_carry(state)?'H':'.', get_idisable(state)?'I':'.', get_negative(state)?'N':'.', get_zero(state)?'Z':'.', get_overflow(state)?'V':'.', get_carry(state)?'C':'.'); /* and a quick memory dump */ printf("\n "); for (i=0;i<16;i++) { printf("%2x ", i); } printf("\n"); for (i=0;i<256;i+=16) { printf("%04x ", i); for (j=0;j<16;j++) { printf("%02x ", memory[i+j]); } for (j=0;j<16;j++) { if (isprint(memory[i+j])) putchar(memory[i+j]); else putchar('.'); } printf("\n"); } } int caught_signal = 0; void interrupt() { caught_signal++; (void) signal(SIGINT, interrupt); } /* return 1 if we should continue executing here, 0 if we should stop */ INLINE int check_break(m6811 *state, short breaks[]) { int pc; pc = get_pc( state); if (breaks[pc] > 0) { breaks[pc]--; return 0; } else return !breaks[pc]; } void multi_step(int n, m6811 *state, byte memory[], short breaks[]) { caught_signal = 0; if (n > 0) { single_step(state, memory); n--; while (n>0 && !caught_signal && check_break(state, breaks)) { single_step(state, memory); n--; } } else if (n < 0) { single_step(state, memory); while (!caught_signal && check_break(state, breaks)) { single_step(state, memory); } } } int file_count; char **files; void reset(m6811 *state, byte memory[], short breaks[]) { FILE *f; int i; for (i=0;i<65536;i++) { breaks[i] = 0; memory[i] = 0xff; } for (i=0;i<256;i++) { /* put distinctive stuff in page zero */ memory[i] = 0xaa; } for (i=1;it = 0; /* have to start time somewhere */ set_ccw(state, 0); /* initialize condition bits*/ set_pc(state, /* and get initial pc */ get_mem16(memory, 0xfffe)); } int do_command(int command, m6811 *state, byte memory[], short breaks[]) { static last_irq=13; /* default is serial transfer done */ long t; int n, add; char line[200]; switch (command) { case '\n': /* step one step */ multi_step(1, state, memory, breaks); break; case 's': /* step n steps */ (void) fgets(line, sizeof(line), stdin); n = 1; sscanf(line, "%d", &n); multi_step(n, state, memory, breaks); break; case 'b': /* set breakpoint */ (void) fgets(line, sizeof(line), stdin); add = get_pc(state); n = -1; sscanf(line, "%x %d", &add, &n); breaks[add] = n; break; case 'g': /* go somewhere */ (void) fgets(line, sizeof(line), stdin); n = -1; add = get_pc(state); sscanf(line, "%x %d", &add, &n); set_pc(state, add); multi_step(n, state, memory, breaks); break; case 'i': /* schedule an interrupt */ (void) fgets(line, sizeof(line), stdin); n = last_irq; /* default is last one used */ t = state->t; /* default is *now* */ sscanf(line, "%x %ld", &n, &t); /* schedule_interrupt(n, t);*/ break; case 'l': /* list some code */ (void) fgets(line, sizeof(line), stdin); add = get_pc(state); n = 20; sscanf(line, "%x %d", &add, &n); while (n--) { printf("%c %04x ", breaks[add]?'*':' ', add); add += disassemble(stdout, memory+add); } printf("hit return to continue"); fflush(stdout); fgets(line, sizeof(line), stdin); break; case 'm': /* modify memory */ (void) fgets(line, sizeof(line), stdin); if (sscanf(line, "%x %x", &add, &n) == 2) { set_mem8(memory, add, n); } break; case 'r': /* modify regs */ break; case 'R': /* reset */ reset(state, memory, breaks); fgets(line, sizeof(line), stdin); break; case 't': /* temporary breakpoint */ (void) fgets(line, sizeof(line), stdin); add = get_pc(state); n = 1; sscanf(line, "%x %d", &add, &n); breaks[add] = n; break; case '?': /* help */ (void) fgets(line, sizeof(line), stdin); printf("\n\n (empty line) step once\ns [n] step n times\nb [add [n]] set break at add which will survive n hits\ng [add [n]] set pc to add, step n times\nl [add [n]] list n lines of disassembly starting from pc\nm add n set specified memory location to n\nR Reset memory, regs and reload code\nt [add [n]] set temporary break at add which will survive n hits\nq or EOF exit simulator\n? print this list\n\n"); printf("hit return to continue"); fflush(stdout); fgets(line, sizeof(line), stdin); break; default: fgets(line, sizeof(line), stdin); fprintf(stderr, "bad command [%c]\n\n", command); printf("hit return to continue"); fflush(stdout); fgets(line, sizeof(line), stdin); break; case 'q': /* quit */ case EOF: return 0; } return 1; } int main(int argc, char *argv[]) { int command; m6811 state; byte memory[65536]; short breaks[65536]; /* break counts. 0 -> no break, -1 -> permanent breakpoint +n -> temporary breakpoint that will evaporate after being hit n times */ if (argc < 2) { fprintf(stderr, "usage: sim68 prog.s19\n"); exit(1); } (void) signal(SIGINT, interrupt); caught_signal = 0; file_count = argc; files = argv; reset(&state, memory, breaks); init_dis(); /* set up the disassembler */ show_state(&state, memory, breaks); fflush(stdout); command = getchar(); while (do_command(command, &state, memory, breaks)) { show_state(&state, memory, breaks); fflush(stdout); command = getchar(); } return 0; }