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