YACASL2
monitor.c
Go to the documentation of this file.
1 #include "monitor.h"
2 
7 
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 = NULL;
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 = NULL;
40  unsigned h = 0;
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 = NULL;
60  BPSLIST *q = NULL;
61  unsigned h = 0;
62  bool res = false;
63 
64  p = bps[h = adrhash(adr)];
65  if(p != NULL) {
66  if(p->adr == adr) {
67  if(p->next == NULL) {
68  FREE(bps[h]);
69  } else {
70  bps[h] = p->next;
71  FREE(p);
72  }
73  res = true;
74  } else {
75  for(; p->next != NULL; p = p->next) {
76  q = p->next;
77  if(q->adr == adr) {
78  p->next = q->next;
79  FREE(q);
80  res = true;
81  break;
82  }
83  }
84  }
85  }
86  return res;
87 }
88 
89 void listbps()
90 {
91  int cnt = 0;
92  BPSLIST *p = NULL;
93 
94  fprintf(stdout, "List of breakpoints\n");
95  for(int i = 0; i < BPSTABSIZE; i++) {
96  for(p = bps[i]; p != NULL; p = p->next) {
97  fprintf(stdout, "#%04X\n", p->adr);
98  cnt++;
99  }
100  }
101  if(cnt == 0) {
102  fprintf(stdout, "(No breakpoints.)\n");
103  }
104 }
105 
106 void freebpslist(BPSLIST *head)
107 {
108  BPSLIST *p = NULL;
109  BPSLIST *q = NULL;
110  for(p = head; p != NULL; p = q) {
111  q = p->next;
112  FREE(p);
113  }
114 }
115 
116 void freebps()
117 {
118  for(int i = 0; i < BPSTABSIZE; i++) {
119  freebpslist(bps[i]);
120  bps[i] = NULL;
121  }
122 }
123 
124 MONARGS *monargstok(const char *str)
125 {
126  MONARGS *args = malloc_chk(sizeof(MONARGS), "args");
127  char *tok = NULL;
128  char *p = NULL;
129  char sepc = ' ';
130 
131  args->argc = 0;
132  if(!str || !str[0]) {
133  return args;
134  }
135  tok = p = strdup_chk(str, "argstok.p");
136  do {
137  int i = strcspn(p, " ");
138  sepc = p[i];
139  args->argv[(args->argc)++] = strndup_chk(p, i, "args->argv[]");
140  p += i + 1;
141  } while(sepc == ' ');
142  FREE(tok);
143  return args;
144 }
145 
146 MONCMDLINE *monlinetok(const char *line)
147 {
148  char *tokens = NULL;
149  char *p = NULL;
150  int i = 0;
151  MONCMDLINE *moncmdl = NULL;
152 
153  if(!line[0] || line[0] == '\n') {
154  return NULL;
155  }
156  p = tokens = strdup_chk(line, "tokens");
157  /* コメントを削除 */
159  /* 文字列末尾の改行と空白を削除 */
160  strip_end(p);
161 
162  moncmdl = malloc_chk(sizeof(MONCMDLINE), "moncmdl");
163  /* コマンドの取得 */
164  i = strcspn(p, " \t\n");
165  moncmdl->cmd = strndup_chk(p, i, "moncmdl->cmd");
166  /* コマンドと引数の間の空白をスキップ */
167  p += i;
168  while(*p == ' ' || *p == '\t') {
169  p++;
170  }
171  /* 引数として、改行までの文字列を取得 */
172  if(strcspn(p, "\n") > 0) {
173  moncmdl->args = monargstok(p);
174  } else {
175  moncmdl->args = malloc_chk(sizeof(MONARGS), "moncmdl.args");
176  moncmdl->args->argc = 0;
177  }
178  FREE(tokens);
179  return moncmdl;
180 }
181 
182 bool stracmp(char *str1, int str2c, char *str2v[])
183 {
184  int i;
185  if(str1 == NULL) {
186  return false;
187  }
188  for(i = 0; i < str2c; i++) {
189  if(strcmp(str1, str2v[i]) == 0) {
190  return true;
191  }
192  }
193  return false;
194 }
195 
196 void warn_ignore_arg(int argc, char *argv[])
197 {
198  int i;
199  for(i = 0; i < argc; i++) {
200  if(i > 0) {
201  fprintf(stderr, " ");
202  }
203  fprintf(stderr, "%s", argv[i]);
204  }
205  fprintf(stderr, ": ignored.\n");
206 }
207 
208 void mon_break(int argc, char *argv[])
209 {
210  WORD w;
211  int i = 0;
212  if(stracmp(argv[0], 2, (char* []){"l", "list"})) {
213  i++;
214  listbps();
215  } else if(stracmp(argv[0], 2, (char* []){"r", "reset"})) {
216  i++;
217  freebps();
218  fprintf(stdout, "All breakpoints are deleted.\n");
219  } else {
220  if(argc > 1) {
221  if((w = nh2word(argv[1])) == 0x0) {
222  fprintf(stderr, "%s: address error\n", argv[1]);
223  }
224  }
225  if(stracmp(argv[0], 2, (char* []){"a", "add"})) {
226  i += 2;
227  if(addbps(w) == true) {
228  fprintf(stdout, "#%04X: breakpoint added\n", w);
229  } else {
230  fprintf(stdout, "No breakpoint added\n");
231  }
232  } else if(stracmp(argv[0], 2, (char* []){"d", "del"})) {
233  i += 2;
234  if(delbps(w) == true) {
235  fprintf(stdout, "#%04X: breakpoint deleted\n", w);
236  } else {
237  fprintf(stdout, "No breakpoint deleted\n");
238  }
239  } else if(stracmp(argv[0], 3, (char* []){"?", "h", "help"})) {
240  i++;
241  fprintf(stdout, "breakpoint manipulate:\n");
242  fprintf(stdout, " b[reak] a[dd] <address>\n");
243  fprintf(stdout, " b[reak] d[el] <address>\n");
244  fprintf(stdout, " b[reak] l[ist]\n");
245  fprintf(stdout, " b[reak] r[eset]\n");
246  } else {
247  fprintf(stderr, "%s: Not breakpoint manipulate command. see `b ?'.\n", argv[0]);
248  }
249  if(argc > i) {
250  warn_ignore_arg(argc - i, argv + i);
251  }
252  }
253 }
254 
255 void mon_dump(int argc, char *argv[])
256 {
257  int i = 0;
258  WORD dump_start = 0, dump_end = 0x40;
259  if(argc > 0 && stracmp(argv[0], 2, (char* []){"a", "auto"})) {
260  execmode.dump = true;
261  i++;
262  } else if(argc > 0 && stracmp(argv[0], 2, (char* []){"no", "noauto"})) {
263  execmode.dump = false;
264  i++;
265  }
266  if(argc > i) {
267  dump_start = nh2word(argv[i++]);
268  if(argc > i) {
269  if(argv[i][0] =='+') {
270  dump_end = dump_start + nh2word(argv[i] + 1);
271  } else {
272  dump_end = nh2word(argv[i]);
273  }
274  } else {
275  dump_end += dump_start;
276  }
277  i++;
278  }
279  if(argc > i) {
280  warn_ignore_arg(argc - i, argv + i);
281  }
282  dumpmemory(dump_start, dump_end);
283  execmode.dump_start = dump_start;
284  execmode.dump_end = dump_end;
285 }
286 
287 MONCMDTYPE monitorcmd(char *cmd, MONARGS *args)
288 {
289  MONCMDTYPE cmdtype = MONREPEAT;
290  if(stracmp(cmd, 2, (char* []){"a", "assemble"})) {
291  if(args->argc == 0) {
292  fprintf(stderr, "Error: Input file name.\n");
293  } else if(args->argc == 1) {
294  assemble(1, (char* []){args->argv[0]}, 0);
295  } else {
296  assemble(1, (char* []){args->argv[0]}, nh2word(args->argv[1]));
297  }
298  } else if(stracmp(cmd, 2, (char* []){"b", "break"})) {
299  mon_break(args->argc, args->argv);
300  } else if(stracmp(cmd, 2, (char* []){"c", "continue"})) {
301  execmode.step = false;
302  cmdtype = MONNEXT;
303  } else if(stracmp(cmd, 2, (char* []){"d", "dump"})) {
304  mon_dump(args->argc, args->argv);
305  } else if(stracmp(cmd, 2, (char* []){"l", "load"})) {
306  execptr->end = loadassemble(args->argv[0], nh2word(args->argv[1]));
307  } else if(stracmp(cmd, 2, (char* []){"n", "next"})) {
308  execmode.step = true;
309  cmdtype = MONNEXT;
310  } else if(stracmp(cmd, 2, (char* []){"q", "quit"})) {
311  fprintf(stdout, "Quit: COMET II monitor\n");
312  cmdtype = MONQUIT;
313  } else if(stracmp(cmd, 2, (char* []){"r", "reverse"})) {
314  if(args->argc == 2) {
315  disassemble_memory(nh2word(args->argv[0]), nh2word(args->argv[1]));
316  }
317  } else if(stracmp(cmd, 1, (char* []){"reset"})) {
318  fprintf(stdout, "Reset COMET II.\n");
319  reset(sys->memsize, sys->clocks); /* COMET II仮想マシンのリセット */
320  } else if(stracmp(cmd, 2, (char* []){"t", "trace"})) {
321  if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"a", "auto"})) {
322  execmode.logical = false;
323  execmode.trace = true;
324  } else if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"no", "noauto"})) {
325  execmode.trace = false;
326  } else {
327  fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
328  dspregister();
329  }
330  } else if(stracmp(cmd, 2, (char* []){"T", "tracelogical"})) {
331  if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"a", "auto"})) {
332  execmode.logical = true;
333  execmode.trace = true;
334  } else if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"no", "noauto"})) {
335  execmode.trace = false;
336  } else {
337  fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
338  dspregister();
339  }
340  } else if(stracmp(cmd, 3, (char* []){"?", "h", "help"})) {
341  fprintf(stdout, "b[reak] -- Manipulate Breakpoints. See details, `b ?'.\n");
342  fprintf(stdout, "c[ontinue] -- Continue running your program.\n");
343  fprintf(stdout, "d[ump] -- Display memory dump. `d[ump] a[uto]/n[oauto]' set auto/noauto display.\n");
344  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");
345  fprintf(stdout, "n[ext] -- Go next instruction.\n");
346  fprintf(stdout, "q[uit] -- Quit running your program.\n");
347  fprintf(stdout, "reset -- Reset the system.\n");
348  fprintf(stdout, "r[everse] -- Disassemble memory. `r[everse] <start address> <end address>.\n");
349  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");
350  fprintf(stdout, "t[race] -- Display CPU register. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
351  fprintf(stdout, "T[race] -- Display CPU register as logical value. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
352  fprintf(stdout, "?/h[elp] -- Display this help.\n");
353  }
354  return cmdtype;
355 }
356 
358 {
359  int i;
360  assert(moncmdl != NULL);
361  if(moncmdl->args != NULL) {
362  for(i = 0; i < moncmdl->args->argc; i++) {
363  FREE(moncmdl->args->argv[i]);
364  }
365  FREE(moncmdl->args);
366  }
367  if(moncmdl->cmd != NULL) {
368  FREE(moncmdl->cmd);
369  }
370  if(moncmdl != NULL) {
371  FREE(moncmdl);
372  }
373 }
374 
375 int monquit()
376 {
377  int stat = 0;
378  shutdown();
379  freebps();
382  if(cerr->num > 0) {
383  stat = 1;
384  }
385  freecerr();
386  return stat;
387 }
388 
389 void monitor()
390 {
391  char *buf = NULL;
392  MONCMDLINE *moncmdl = NULL;
393  MONCMDTYPE cmdtype = MONREPEAT;
394 
395  do {
396  fprintf(stdout, "%s ", monitor_prompt);
397  buf = malloc_chk(MONINSIZE + 1, "monitor.buf");
398  fgets(buf, MONINSIZE, stdin);
399  if(!buf[0]) {
400  cmdtype = MONQUIT;
401  }
402  strip_end(buf); /* 文字列末尾の改行と空白を削除 */
403  fprintf(stdout, "%s\n", buf);
404  if((moncmdl = monlinetok(buf)) != NULL) {
405  cmdtype = monitorcmd(moncmdl->cmd, moncmdl->args);
406  free_moncmdline(moncmdl);
407  }
408  FREE(buf);
409  if(cmdtype == MONQUIT) {
410  exit(monquit());
411  }
412  } while(cmdtype == MONREPEAT);
413 }
bool assemble(int filec, char *filev[], WORD adr)
指定された1つまたは複数のファイルを2回アセンブル
Definition: assemble.c:751
CERR * cerr
現在のエラー
Definition: cerr.c:9
void freecerr()
エラーリストと現在のエラーを解放する
Definition: cerr.c:72
char * strndup_chk(const char *s, size_t len, const char *tag)
malloc_chkを実行してメモリを確保し、コピーした文字列の指定した長さの部分を返す
Definition: cmem.c:33
#define FREE(ptr)
メモリを解放するマクロ
Definition: cmem.h:21
void strip_end(char *s)
文字列の末尾から、改行と空白とタブを削除する
Definition: cmem.c:48
char * strdup_chk(const char *s, const char *tag)
malloc_chkを実行してメモリを確保し、コピーした文字列を返す
Definition: cmem.c:25
void strip_casl2_comment(char *s)
文字列から「'」以降の文字列をCASL IIのコメントとして削除する。「''」の場合は除く
Definition: cmem.c:55
void * malloc_chk(size_t size, const char *tag)
mallocを実行し、0で初期化する
Definition: cmem.c:3
void disassemble_memory(WORD start, WORD end)
COMET IIのメモリーを逆アセンブルし、標準出力へ出力する
Definition: disassemble.c:238
void dumpmemory(WORD start, WORD end)
COMET IIのメモリを表示する
Definition: dump.c:4
void dspregister()
COMET IIのレジスタを表示する
Definition: dump.c:38
@ INT
Definition: hash.h:9
unsigned hash(int keyc, HKEY *keyv[], int tabsize)
ハッシュ値を取得する
Definition: hash.c:3
WORD loadassemble(const char *file, WORD start)
指定されたファイルからアセンブル結果を読み込む
Definition: load.c:27
void monitor()
COMET IIモニターを起動する
Definition: monitor.c:389
void free_moncmdline(MONCMDLINE *moncmdl)
Definition: monitor.c:357
static char * monitor_prompt
comet2monitorのプロンプト
Definition: monitor.c:11
MONCMDLINE * monlinetok(const char *line)
行から、モニターの命令と引数を取得する
Definition: monitor.c:146
MONCMDTYPE monitorcmd(char *cmd, MONARGS *args)
モニターの命令を実行する
Definition: monitor.c:287
static BPSLIST * bps[BPSTABSIZE]
ブレークポイント表
Definition: monitor.c:6
void warn_ignore_arg(int argc, char *argv[])
Definition: monitor.c:196
bool getbps(WORD adr)
ブレークポイント表にアドレスがある場合はtrue、ない場合はfalseを返す
Definition: monitor.c:25
void listbps()
Definition: monitor.c:89
void mon_break(int argc, char *argv[])
Definition: monitor.c:208
MONARGS * monargstok(const char *str)
文字列から、モニターの引数を取得する
Definition: monitor.c:124
unsigned adrhash(WORD adr)
アドレスのハッシュ値を返す
Definition: monitor.c:13
void freebpslist(BPSLIST *head)
Definition: monitor.c:106
bool stracmp(char *str1, int str2c, char *str2v[])
Definition: monitor.c:182
void freebps()
ブレークポイント表を解放する
Definition: monitor.c:116
bool delbps(WORD adr)
ブレークポイント表からアドレスを削除する
Definition: monitor.c:57
bool addbps(WORD adr)
ブレークポイント表にアドレスを追加する
Definition: monitor.c:37
int monquit()
Definition: monitor.c:375
void mon_dump(int argc, char *argv[])
Definition: monitor.c:255
@ BPSTABSIZE
Definition: monitor.h:46
@ MONINSIZE
Definition: monitor.h:50
MONCMDTYPE
Definition: monitor.h:53
@ MONNEXT
Definition: monitor.h:55
@ MONQUIT
Definition: monitor.h:56
@ MONREPEAT
Definition: monitor.h:54
@ HASH_CMDTYPE
Definition: struct.h:61
@ HASH_CODE
Definition: struct.h:62
void reset(int memsize, int clocks)
Definition: struct.c:253
EXECPTR * execptr
Definition: struct.c:12
void shutdown()
Definition: struct.c:278
void free_cmdtable(CMDTAB_HASH hash)
Definition: struct.c:135
SYSTEM * sys
COMET IIの仮想実行マシンシステム
Definition: struct.c:7
EXECMODE execmode
実行モード: trace, logical, dump, monitor, step
Definition: exec.c:91
ブレークポイント表を表すデータ型
Definition: monitor.h:37
struct _BPSLIST * next
Definition: monitor.h:38
WORD adr
Definition: monitor.h:39
int num
Definition: cerr.h:16
WORD pr
Definition: struct.h:38
bool step
Definition: struct.h:148
bool dump
Definition: struct.h:144
bool trace
Definition: struct.h:142
bool logical
Definition: struct.h:143
int dump_start
Definition: struct.h:145
int dump_end
Definition: struct.h:146
WORD end
Definition: struct.h:132
ハッシュ共用体のデータ型
Definition: hash.h:15
UTYPE type
Definition: hash.h:16
int i
Definition: hash.h:19
union HKEY::@3 val
モニター引数を表すデータ型
Definition: monitor.h:21
int argc
Definition: monitor.h:22
char * argv[MONARGSIZE]
Definition: monitor.h:23
モニター命令行を表すデータ型
Definition: monitor.h:29
MONARGS * args
Definition: monitor.h:31
char * cmd
Definition: monitor.h:30
int memsize
Definition: struct.h:48
clock_t clocks
Definition: struct.h:49
CPU * cpu
Definition: struct.h:46
unsigned short WORD
16ビットの数値を表すデータ型
Definition: word.h:9
WORD nh2word(const char *str)
10進数または16進数の文字列をWORD値に変換する
Definition: word.c:82