separated vm-dcpu16.c cli driver wrapper from vm emulator core
[dcpu16] / vm-dcpu16.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <assert.h>
7 #include <sysexits.h>
8
9 #include <readline/readline.h>
10 #include <readline/history.h>
11
12 #include "dcpu16.h"
13
14 /*
15 * cli driver for dcpu16 core
16 *
17 * Justin Wind <justin.wind@gmail.com>
18 * 2012 04 10 - implementation started
19 *
20 */
21
22 static const char * const src_id_ = "$Id$";
23
24 /* global invocation options */
25 struct options {
26 unsigned int verbose;
27 } opt_ = {
28 .verbose = 0,
29 };
30
31 #define VERBOSE_PRINTF(...) do { if (opt_.verbose) printf(__VA_ARGS__); } while (0)
32
33 static void usage_(char *prog, unsigned int full) {
34 FILE *f = full ? stdout : stderr;
35 char *x = strrchr(prog, '/');
36
37 if (x && *(x + 1))
38 prog = x + 1;
39
40 if (full)
41 fprintf(f, "%s -- \n\n",
42 prog);
43
44 fprintf(f, "Usage: %s [file]\n",
45 prog);
46
47 if (full) {
48 fprintf(f, "\nOptions:\n"
49 "\t [file] -- ram image to load initially\n"
50 "\t -h -- this screen\n"
51 "\t -v -- verbose execution tracing\n");
52
53 fprintf(f, "\n%78s\n", src_id_);
54 }
55 }
56
57 static
58 int file_load_(struct dcpu16 *vm, char *filename) {
59 FILE *f;
60 size_t r;
61
62 f = fopen(filename, "rb");
63 if (f == NULL) {
64 fprintf(stderr, "%s('%s'):%s\n", "fopen", filename, strerror(errno));
65 return -1;
66 }
67
68 r = fread(vm->ram, sizeof(DCPU16_WORD), DCPU16_RAM, f);
69 VERBOSE_PRINTF("read %zu words", r);
70
71 if (ferror(f))
72 fprintf(stderr, "%s('%s'):%s\n", "fread", filename, strerror(errno));
73
74 fclose(f);
75 return 0;
76 }
77
78 int main(int argc, char **argv) {
79 int c;
80 char *command;
81 char *prompt = "dcpu16> ";
82 struct dcpu16 *vm;
83
84 while ( (c = getopt(argc, argv, "hv")) != EOF) {
85 switch (c) {
86 case 'v':
87 opt_.verbose++;
88 break;
89
90 case 'h':
91 usage_(argv[0], 1);
92 exit(EX_OK);
93
94 default:
95 usage_(argv[0], 0);
96 exit(EX_USAGE);
97 }
98 }
99 if (opt_.verbose < 1) {
100 dcpu16_warn_cb_set(NULL);
101 dcpu16_trace_cb_set(NULL);
102 } else if (opt_.verbose < 2) {
103 dcpu16_trace_cb_set(NULL);
104 }
105 argc -= optind;
106 argv += optind;
107
108 if ((vm = dcpu16_new()) == NULL) {
109 fprintf(stderr, "could not allocate new dcpu instance\n");
110 exit(EX_UNAVAILABLE);
111 }
112
113 if (argc) {
114 file_load_(vm, *argv);
115 }
116
117 dcpu16_state_print(vm);
118 dcpu16_disassemble_print(vm, vm->pc);
119 while ( (command = readline(prompt)) ) {
120 if (strcasecmp(command, "quit") == 0)
121 break;
122
123 dcpu16_step(vm);
124 dcpu16_state_print(vm);
125 dcpu16_disassemble_print(vm, vm->pc);
126 }
127
128 printf("finished\n");
129
130 dcpu16_delete(&vm);
131
132 exit(EX_OK);
133 }