comet2monitorのダンプで引数のない場合は0から#40までダンプ
[YACASL2.git] / src / monitor.c
1 #include "monitor.h"
2
3 /**
4  * @brief ブレークポイント表
5  */
6 static BPSLIST *bps[BPSTABSIZE];
7
8 /**
9  * @brief comet2monitorのプロンプト
10  */
11 static char *monitor_prompt = "(comet2 monitor)";
12
13 unsigned adrhash(WORD adr)
14 {
15     HKEY *key[1];
16     unsigned h;
17     key[0] = malloc_chk(sizeof(HKEY), "adrhash.key");
18     key[0]->type = INT;
19     key[0]->val.i = adr;
20     h = hash(1, key, BPSTABSIZE);
21     FREE(key[0]);
22     return h;
23 }
24
25 bool getbps(WORD adr)
26 {
27     BPSLIST *p;
28
29     for(p = bps[adrhash(adr)]; p != NULL; p = p->next) {
30         if(p->adr == adr) {
31             return true;
32         }
33     }
34     return false;
35 }
36
37 bool addbps(WORD adr)
38 {
39     BPSLIST *p;
40     unsigned h;
41
42     /* 登録されたラベルを検索。すでに登録されている場合は終了 */
43     if(getbps(adr) == true) {
44         fprintf(stderr, "%04X: Breakpoint is already defined.\n", adr);
45         return false;
46     }
47     /* メモリを確保 */
48     p = malloc_chk(sizeof(BPSLIST), "bps.next");
49     /* アドレスを設定 */
50     p->adr = adr;
51     /* ハッシュ表へ追加 */
52     p->next = bps[h = adrhash(adr)];
53     bps[h] = p;
54     return true;
55 }
56
57 bool delbps(WORD adr)
58 {
59     BPSLIST *p, *q;
60     unsigned h;
61     bool res = false;
62
63     p = bps[h = adrhash(adr)];
64     if(p != NULL) {
65         if(p->adr == adr) {
66             if(p->next == NULL) {
67                 FREE(bps[h]);
68             } else {
69                 bps[h] = p->next;
70                 FREE(p);
71             }
72             res = true;
73         } else {
74             for(; p->next != NULL; p = p->next) {
75                 q = p->next;
76                 if(q->adr == adr) {
77                     p->next = q->next;
78                     FREE(q);
79                     res = true;
80                     break;
81                 }
82             }
83         }
84     }
85     return res;
86 }
87
88 void listbps()
89 {
90     int i, cnt = 0;
91     BPSLIST *p;
92
93     fprintf(stdout, "List of breakpoints\n");
94     for(i = 0; i < BPSTABSIZE; i++) {
95         for(p = bps[i]; p != NULL; p = p->next) {
96             fprintf(stdout, "#%04X\n", p->adr);
97             cnt++;
98         }
99     }
100     if(cnt == 0) {
101         fprintf(stdout, "(No breakpoints.)\n");
102     }
103 }
104
105 void freebpslist(BPSLIST *head)
106 {
107     BPSLIST *p, *q;
108     for(p = head; p != NULL; p = q) {
109         q = p->next;
110         FREE(p);
111     }
112 }
113
114 void freebps()
115 {
116     int i;
117     for(i = 0; i < BPSTABSIZE; i++) {
118         freebpslist(bps[i]);
119         bps[i] = NULL;
120     }
121 }
122
123 MONARGS *monargstok(const char *str)
124 {
125     MONARGS *args = malloc_chk(sizeof(MONARGS), "args");
126     char *tok, *p, sepc = ' ';
127     int i = 0;
128
129     args->argc = 0;
130     if(!str || !str[0]) {
131         return args;
132     }
133     tok = p = strdup_chk(str, "argstok.p");
134     do {
135         i = strcspn(p, " ");
136         sepc = p[i];
137         args->argv[(args->argc)++] = strndup_chk(p, i, "args->argv[]");
138         p += i + 1;
139         i = 0;
140     } while(sepc == ' ');
141     FREE(tok);
142     return args;
143 }
144
145 MONCMDLINE *monlinetok(const char *line)
146 {
147     char *tokens, *p;
148     long l;
149     MONCMDLINE *moncmdl = NULL;
150
151     if(!line[0] || line[0] == '\n') {
152         return NULL;
153     }
154     p = tokens = strdup_chk(line, "tokens");
155     moncmdl = malloc_chk(sizeof(MONCMDLINE), "moncmdl");
156     /* コマンドの取得 */
157     moncmdl->cmd = malloc_chk((l = strcspn(p, " \t\n")) + 1, "moncmdl.cmd");
158     strncpy(moncmdl->cmd, p, l);
159     /* コマンドと引数の間の空白をスキップ */
160     p += l;
161     while(*p == ' ' || *p == '\t') {
162         p++;
163     }
164     /* 引数として、改行までの文字列を取得 */
165     if((l = strcspn(p, "\n")) > 0) {
166         moncmdl->args = monargstok(p);
167     } else {
168         moncmdl->args = malloc_chk(sizeof(MONARGS), "moncmdl.args");
169         moncmdl->args->argc = 0;
170     }
171     FREE(tokens);
172     return moncmdl;
173 }
174
175 bool stracmp(char *str1, int str2c, char *str2v[])
176 {
177     int i;
178     if(str1 == NULL) {
179         return false;
180     }
181     for(i = 0; i < str2c; i++) {
182         if(strcmp(str1, str2v[i]) == 0) {
183             return true;
184         }
185     }
186     return false;
187 }
188
189 void mon_break(int argc, char *argv[])
190 {
191     WORD w;
192     if(stracmp(argv[0], 2, (char* []){"l", "list"})) {
193         listbps();
194     } else if(stracmp(argv[0], 2, (char* []){"r", "reset"})) {
195         freebps();
196         fprintf(stdout, "All breakpoints are deleted.\n");
197     } else {
198         if(argc > 1) {
199             if((w = nh2word(argv[1])) == 0x0) {
200                 fprintf(stderr, "%s: address error\n", argv[1]);
201             }
202         }
203         if(stracmp(argv[0], 2, (char* []){"a", "add"})) {
204             if(addbps(w) == true) {
205                 fprintf(stdout, "#%04X: breakpoint added\n", w);
206             } else {
207                 fprintf(stdout, "No breakpoint added\n");
208             }
209         } else if(stracmp(argv[0], 2, (char* []){"d", "del"})) {
210             if(delbps(w) == true) {
211                 fprintf(stdout, "#%04X: breakpoint deleted\n", w);
212             } else {
213                 fprintf(stdout, "No breakpoint deleted\n");
214             }
215         } else if(stracmp(argv[0], 3, (char* []){"?", "h", "help"})) {
216             fprintf(stdout, "breakpoint manipulate:\n");
217             fprintf(stdout, "    b[reak] a[dd] <address>\n");
218             fprintf(stdout, "    b[reak] d[el] <address>\n");
219             fprintf(stdout, "    b[reak] l[ist]\n");
220             fprintf(stdout, "    b[reak] r[eset]\n");
221         } else {
222             fprintf(stderr, "%s: Not breakpoint manipulate command. see `b ?'.\n", argv[0]);
223         }
224     }
225 }
226
227 void mon_dump(int argc, char *argv[])
228 {
229     int i = 0, j;
230     WORD dump_start = 0, dump_end = 0x40;
231     if(argc > 0 && stracmp(argv[0], 2, (char* []){"a", "auto"})) {
232         execmode.dump = true;
233         i++;
234     } else if(argc > 0 && stracmp(argv[0], 2, (char* []){"no", "noauto"})) {
235         execmode.dump = false;
236         i++;
237     }
238     if(argc > i) {
239         dump_start = execmode.dump_start = nh2word(argv[i++]);
240         if(argc > i) {
241             dump_end = execmode.dump_end = nh2word(argv[i++]);
242         }
243         if(argc > i) {
244             for(j = i; j < argc; j++) {
245                 if(j > i) {
246                     fprintf(stderr, " ");
247                 }
248                 fprintf(stderr, "%s", argv[j]);
249             }
250             fprintf(stderr, ": ignored.\n");
251         }
252     }
253     dumpmemory(dump_start, dump_end);
254 }
255
256 MONCMDTYPE monitorcmd(char *cmd, MONARGS *args)
257 {
258     MONCMDTYPE cmdtype = MONREPEAT;
259     if(stracmp(cmd, 2, (char* []){"a", "assemble"})) {
260         if(args->argc == 0) {
261             fprintf(stderr, "Error: Input file name.\n");
262         } else if(args->argc == 1) {
263             assemble(1, (char* []){args->argv[0]}, 0);
264         } else {
265             assemble(1, (char* []){args->argv[0]}, nh2word(args->argv[1]));
266         }
267     } else if(stracmp(cmd, 2, (char* []){"b", "break"})) {
268         mon_break(args->argc, args->argv);
269     } else if(stracmp(cmd, 2, (char* []){"c", "continue"})) {
270         execmode.step = false;
271         cmdtype = MONNEXT;
272     } else if(stracmp(cmd, 2, (char* []){"d", "dump"})) {
273         mon_dump(args->argc, args->argv);
274     } else if(stracmp(cmd, 2, (char* []){"l", "load"})) {
275         execptr->end = loadassemble(args->argv[0], nh2word(args->argv[1]));
276     } else if(stracmp(cmd, 2, (char* []){"n", "next"})) {
277         execmode.step = true;
278         cmdtype = MONNEXT;
279     } else if(stracmp(cmd, 2, (char* []){"q", "quit"})) {
280         fprintf(stdout, "Quit: COMET II monitor\n");
281         cmdtype = MONQUIT;
282     } else if(stracmp(cmd, 2, (char* []){"r", "reverse"})) {
283         if(args->argc == 2) {
284             disassemble_memory(nh2word(args->argv[0]), nh2word(args->argv[1]));
285         }
286     } else if(stracmp(cmd, 1, (char* []){"reset"})) {
287         fprintf(stdout, "Reset COMET II.\n");
288         reset(sys->memsize, sys->clocks);     /* COMET II仮想マシンのリセット */
289     } else if(stracmp(cmd, 2, (char* []){"t", "trace"})) {
290         if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"a", "auto"})) {
291             execmode.logical = false;
292             execmode.trace = true;
293         } else if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"no", "noauto"})) {
294             execmode.trace = false;
295         } else {
296             fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
297             dspregister();
298         }
299     } else if(stracmp(cmd, 2, (char* []){"T", "tracelogical"})) {
300         if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"a", "auto"})) {
301             execmode.logical = true;
302             execmode.trace = true;
303         } else if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"no", "noauto"})) {
304             execmode.trace = false;
305         } else {
306             fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
307             dspregister();
308         }
309     } else if(stracmp(cmd, 3, (char* []){"?", "h", "help"})) {
310         fprintf(stdout, "b[reak] -- Manipulate Breakpoints. See details, `b ?'.\n");
311         fprintf(stdout, "c[ontinue] -- Continue running your program.\n");
312         fprintf(stdout, "d[ump] -- Display memory dump. `d[ump] a[uto]/n[oauto]' set auto/noauto display.\n");
313         fprintf(stdout, "l[oad] -- Load object from a file to the memory. `l[oad] <filepath> <address>' if address is omitted, load to address 0.\n");
314         fprintf(stdout, "n[ext] -- Go next instruction.\n");
315         fprintf(stdout, "q[uit] -- Quit running your program.\n");
316         fprintf(stdout, "reset -- Reset the system.\n");
317         fprintf(stdout, "r[everse] -- Disassemble memory. `r[everse] <start address> <end address>.\n");
318         fprintf(stdout, "s[ave] -- Save object from the memory to a file. `s[ave] <filepath> [<start address1> [<end address>]]' if <start address> and <end address> is omitted, save the whole memory. if <end address> is omitted, save the memory after <start address>.\n");
319         fprintf(stdout, "t[race] -- Display CPU register. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
320         fprintf(stdout, "T[race] -- Display CPU register as logical value. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
321         fprintf(stdout, "?/h[elp] -- Display this help.\n");
322     }
323     return cmdtype;
324 }
325
326 void free_moncmdline(MONCMDLINE *moncmdl)
327 {
328     int i;
329     assert(moncmdl != NULL);
330     if(moncmdl->args != NULL) {
331         for(i = 0;  i < moncmdl->args->argc; i++) {
332             FREE(moncmdl->args->argv[i]);
333         }
334         FREE(moncmdl->args);
335     }
336     if(moncmdl->cmd != NULL) {
337         FREE(moncmdl->cmd);
338     }
339     if(moncmdl != NULL) {
340         FREE(moncmdl);
341     }
342 }
343
344 void monitor()
345 {
346     char *buf = NULL;
347     int i;
348     MONCMDLINE *moncmdl;
349     MONCMDTYPE cmdtype = MONREPEAT;
350
351     do {
352         fprintf(stdout, "%s ", monitor_prompt);
353         buf = malloc_chk(MONINSIZE + 1, "monitor.buf");
354         fgets(buf, MONINSIZE, stdin);
355         fprintf(stdout, "%s", buf);
356         if(!buf[0]) {
357             cmdtype = MONQUIT;
358         }
359         if((i = strcspn(buf, "\n")) > 0 || buf[0] == '\n') {
360             buf[i] = '\0';
361         }
362         if((moncmdl = monlinetok(buf)) != NULL) {
363             cmdtype = monitorcmd(moncmdl->cmd, moncmdl->args);
364             free_moncmdline(moncmdl);
365         }
366         FREE(buf);
367         if(cmdtype == MONQUIT) {
368             shutdown();
369             freebps();
370             free_cmdtable(HASH_CODE);
371             freecerr();
372             exit(0);
373         }
374     } while(cmdtype == MONREPEAT);
375 }