/comet2
/dumpword
/casl2rev
+/comet2monitor
*.o
*.o.casl
!as/sample/hello.o
test/system/comet2_opt/opt_v/0.txt \
test/system/dumpword/opt_v/0.txt
-CMDFILES := casl2 comet2 dumpword casl2rev
+CMDFILES := casl2 comet2 dumpword casl2rev comet2monitor
all: build INSTALL gtags
build:
$(MAKE) -C src all
- @(for f in $(CMDFILES); do if test src/$$f -nt $$f; then $(CP) src/$$f $$f; fi; done)
+ @(for f in $(CMDFILES); do if test ! -e $$f -o src/$$f -nt $$f; then $(CP) src/$$f $$f; fi; done)
gtags:
$(if $(strip $(shell $(WHICH) $(GTAGS))),$(GTAGS),@$(ECHO) '$(GTAGS): not found')
また、本パッケージ中にCASL IIのサンプルプログラムが多数収録されています。
YACASL2は、「ふつうの処理系」として動作します。
-ほかの多くのCASL IIエミュレータと違い、デバッガとして動作したり、
-コンピュータ内部の模式図を表示したりすることはありません。
-そのかわり、YACASL2は、次のような動作内容をすべてテキストで出力します。
+YACASL2の操作は、端末上のコマンドラインインターフェイス(CLI)で操作します。
+YACASL2は、次のような動作内容をすべてテキストで出力します。
@itemize @bullet
実行時のメモリの内容
@end itemize
-出力された動作内容は、GNU/Linuxのさまざまなコマンド、
+YACASL2では、機械コードモニターを使い、動作中のCPUやメモリーを調べたりデバッグしたりすることもできます。
+
+また、出力された動作内容は、GNU/Linuxのさまざまなコマンド、
たとえば、@command{cat}、@command{less}、@command{grep}、@command{wc}などを使って解析できます。
-YACASL2の操作は、端末上のコマンドラインインターフェイスで行います。
+
@node Sample usage, casl2 invocation, Overview, Top
@chapter YACASL2の使用例
#0048: 72 = #0048 = 0000000001001000 = 'H'
@end example
-@unnumberedsubsec オプション
+@unnumberedsec オプション
@command{dumpword}は、次のオプションを指定できます。
$(CD) $(DOXYSRCDIR) && $(DOXYGEN)
$(DOXYSRCDIR)/Doxyfile: Doxyfile
- $(CP) -f Doxyfile $(DOXYSRCDIR)/
+ @$(CP) -vf Doxyfile $(DOXYSRCDIR)/
# htagsのHTMLドキュメント作成先は、
# 引数DIRで指定されたディレクトリーの下のHTMLディレクトリー
#include <errno.h>
#include "cerr.h"
#include "cmem.h"
+#include "exec.h"
#include "hash.h"
#include "struct.h"
#include "word.h"
*/
bool assemblefile(const char *file, PASS pass);
+/**
+ * @brief 指定された1つまたは複数のファイルを2回アセンブル
+ *
+ * @return なし
+ *
+ * @param filec アセンブルするファイルの数
+ * @param filev アセンブルするファイル名の配列
+ * @param adr アセンブル結果を格納するアドレス
+ */
+void assemble(int filec, char *filev[], WORD adr);
+
/**
* @brief ファイルにアセンブル結果を書き込む
*
#ifndef DISASSEMBLE_INCLUDE
#define DISASSEMBLE_INCLUDE
-#include "exec.h"
+#include "struct.h"
/**
* @brief CASL IIのオブジェクトファイルを逆アセンブルし、標準出力へ出力する
bool trace; /**<レジストリの内容をステップごとに表示する場合はtrue */
bool logical; /**<レジストリの内容を論理値(0から65535)で表示する場合はtrue */
bool dump; /**<メモリの内容をステップごとに表示する場合はtrue */
- bool step; /**<ステップ実行の場合はtrue */
+ bool monitor; /**<モニターモードの場合はtrue */
+ bool step; /**<ステップ実行の場合はtrue */
} EXECMODE;
/**
- * @brief 実行モード: trace, logical, dump, step
+ * @brief 実行モード: trace, logical, dump, monitor, step
*/
extern EXECMODE execmode;
/**
* @brief 指定されたファイルからアセンブル結果を読み込む
- */
-bool loadassemble(const char *file);
-
-/**
- * @brief 汎用レジスタの番号からレジスタを表す文字列を返す
*
- * @return 汎用レジスタを表す文字列。「GR0」「GR1」・・・「GR7」のいずれか
+ * @return 読み込み終了アドレス。読み込めなかった場合は、0
*
- * @param word レジスタ番号[0-7]を表すWORD値
+ * @param file 読み込むファイル名
+ * @param start 読み込み開始アドレス
*/
-char *grstr(WORD word);
+WORD loadassemble(const char *file, WORD start);
/**
* @class Exec
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#include "assemble.h"
#include "hash.h"
#include "cmem.h"
#include "cerr.h"
extern EXECPTR *execptr;
+/**
+ * @brief 汎用レジスタの番号からレジスタを表す文字列を返す
+ *
+ * @return 汎用レジスタを表す文字列。「GR0」「GR1」・・・「GR7」のいずれか
+ *
+ * @param word レジスタ番号[0-7]を表すWORD値
+ */
+char *grstr(WORD word);
+
/**
* COMET II仮想マシンのリセット
*/
casl2
comet2
dumpword
-casl2rev
\ No newline at end of file
+casl2rev
+comet2monitor
# ソースファイル。グループに分類
-CMDOBJ := casl2 comet2 dumpword casl2rev
+CMDOBJ := casl2 comet2 dumpword casl2rev comet2monitor
COMMONOBJ := word cmem cerr
-CASL2OBJ := struct hash
+STRUCTOBJ := struct hash
ASOBJ := assemble token label
-EXECOBJ := exec dump disassemble monitor
+EXECOBJ := exec dump monitor disassemble
# ヘッダファイル
INCLUDEDIR := ../include
all: build tag
-# casl2、comet2、dumpwordのビルド
+# casl2ã\80\81comet2ã\80\81dumpwordã\80\81casl2revã\80\81comet2monitorã\81®ã\83\93ã\83«ã\83\89
build: $(CMDOBJ)
-casl2: $(addsuffix .o,casl2 $(COMMONOBJ) $(CASL2OBJ) $(ASOBJ) $(EXECOBJ))
+casl2: $(addsuffix .o,casl2 $(COMMONOBJ) $(STRUCTOBJ) $(ASOBJ) $(EXECOBJ))
-comet2: $(addsuffix .o,comet2 $(COMMONOBJ) $(CASL2OBJ) $(EXECOBJ))
+comet2: $(addsuffix .o,comet2 $(COMMONOBJ) $(STRUCTOBJ) $(ASOBJ) $(EXECOBJ))
dumpword: $(addsuffix .o,dumpword $(COMMONOBJ))
-casl2rev:$(addsuffix .o,casl2rev $(COMMONOBJ) $(CASL2OBJ) $(EXECOBJ))
+casl2rev:$(addsuffix .o,casl2rev $(COMMONOBJ) $(STRUCTOBJ) $(ASOBJ) $(EXECOBJ))
+
+comet2monitor:$(addsuffix .o,comet2monitor $(COMMONOBJ) $(STRUCTOBJ) $(ASOBJ) $(EXECOBJ))
# .dファイルからヘッダファイルの依存関係を取得する
# tags、check、clean、.d で終わるターゲットの場合は除く
NODEP := %tags %check %clean %.d
ifeq ($(filter $(NODEP),$(MAKECMDGOALS)),)
- -include $(addsuffix .d,$(CMDOBJ) $(COMMONOBJ) $(CASL2OBJ) $(ASOBJ) $(EXECOBJ))
+ -include $(addsuffix .d,$(CMDOBJ) $(COMMONOBJ) $(STRUCTOBJ) $(ASOBJ) $(EXECOBJ))
endif
# tagファイル作成 - ctags & etags
return (cerr->num == 0) ? true : false;
}
+void assemble(int filec, char *filev[], WORD adr)
+{
+ int i;
+ PASS pass;
+ WORD bp[filec];
+
+ create_cmdtype_code(); /* 命令の名前とタイプがキーのハッシュ表を作成 */
+ asptr = malloc_chk(sizeof(ASPTR), "asptr"); /* アセンブル時のプロパティ用の領域確保 */
+ asptr->prog = malloc_chk(LABELSIZE + 1, "asptr.prog");
+ asptr->ptr = adr;
+ /* アセンブル。ラベル表作成のため、2回行う */
+ for(pass = FIRST; pass <= SECOND; pass++) {
+ for(i = 0; i < filec; i++) {
+ /* データの格納開始位置 */
+ if(pass == FIRST) {
+ bp[i] = asptr->ptr;
+ } else if(pass == SECOND) {
+ asptr->ptr = bp[i];
+ }
+ if(execmode.trace == true || execmode.dump == true ||
+ asmode.src == true || asmode.label == true || asmode.asdetail == true)
+ {
+ fprintf(stdout, "\nAssemble %s (%d)\n", filev[i], pass);
+ }
+ /* ファイルをアセンブル */
+ if(assemblefile(filev[i], pass) == false) {
+ goto asfin;
+ }
+ }
+ if(pass == FIRST && asmode.label == true) {
+ fprintf(stdout, "\nLabel::::\n");
+ printlabel();
+ if(asmode.onlylabel == true) {
+ break;
+ }
+ }
+ }
+asfin:
+ freelabel(); /* ラベルハッシュ表を解放 */
+ free_cmdtype_code(); /* 命令の名前とタイプがキーのハッシュ表を解放 */
+ FREE(asptr->prog); /* アセンブル時のプロパティを解放 */
+ FREE(asptr);
+}
+
/* assemble.hで定義された関数群 */
void addcerrlist_assemble()
{
#include "package.h"
#include "assemble.h"
-#include "exec.h"
/**
* @brief CASL IIのエラーをエラーリストに追加
*/
const char *objfile_name(const char *str);
-/**
- * @brief 指定された1つまたは複数のファイルを2回アセンブル
- *
- * @return なし
- *
- * @param filec アセンブルするファイルの数
- * @param filev アセンブルするファイル名の配列
- */
-void assemble(int filec, char *filev[]);
-
/**
* @brief casl2コマンドのオプション
*/
return (str == NULL) ? default_name : str;
}
-void assemble(int filec, char *filev[])
-{
- int i;
- PASS pass;
- WORD bp[filec];
-
- create_cmdtype_code(); /* 命令の名前とタイプがキーのハッシュ表を作成 */
- asptr = malloc_chk(sizeof(ASPTR), "asptr"); /* アセンブル時のプロパティ用の領域確保 */
- asptr->prog = malloc_chk(LABELSIZE + 1, "asptr.prog");
- asptr->ptr = 0;
- /* アセンブル。ラベル表作成のため、2回行う */
- for(pass = FIRST; pass <= SECOND; pass++) {
- for(i = 0; i < filec; i++) {
- /* データの格納開始位置 */
- if(pass == FIRST) {
- bp[i] = asptr->ptr;
- } else if(pass == SECOND) {
- asptr->ptr = bp[i];
- }
- if(execmode.trace == true || execmode.dump == true ||
- asmode.src == true || asmode.label == true || asmode.asdetail == true)
- {
- fprintf(stdout, "\nAssemble %s (%d)\n", filev[i], pass);
- }
- /* ファイルをアセンブル */
- if(assemblefile(filev[i], pass) == false) {
- goto asfin;
- }
- }
- if(pass == FIRST && asmode.label == true) {
- fprintf(stdout, "\nLabel::::\n");
- printlabel();
- if(asmode.onlylabel == true) {
- break;
- }
- }
- }
-asfin:
- freelabel(); /* ラベルハッシュ表を解放 */
- free_cmdtype_code(); /* 命令の名前とタイプがキーのハッシュ表を解放 */
- FREE(asptr->prog); /* アセンブル時のプロパティを解放 */
- FREE(asptr);
-}
-
/**
* @brief casl2コマンドのメイン
*
for(i = 0; i < argc - optind; i++) { /* 引数からファイル名配列を取得 */
af[i] = argv[optind + i];
}
- assemble(i, af); /* アセンブル */
+ assemble(i, af, 0); /* アセンブル */
if(asmode.onlylabel == true || cerr->num > 0) {
goto casl2fin;
}
execmode.dump = true;
break;
case 'm':
- execmode.step = true;
+ execmode.monitor = true;
break;
case 'M':
memsize = atoi(optarg);
if(argv[optind] == NULL) {
setcerr(211, ""); /* object file not specified */
fprintf(stderr, "comet2 error - %d: %s\n", cerr->num, cerr->msg);
- freecerr(); /* エラーの解放 */
- exit(1);
+ goto fin;
}
-
- /* COMET II仮想マシンのリセット */
- reset(memsize, clocks);
+ reset(memsize, clocks); /* COMET II仮想マシンのリセット */
execptr->start = 0;
- if(loadassemble(argv[optind]) == true) {
- exec(); /* プログラム実行 */
+ if((execptr->end = loadassemble(argv[optind], execptr->start)) > 0 && cerr->num == 0) {
+ exec(); /* プログラム実行 */
}
- /* COMET II仮想マシンのシャットダウン */
- shutdown();
+ shutdown(); /* COMET II仮想マシンのシャットダウン */
+fin:
stat = (cerr->num == 0) ? 0 : 1;
freecerr(); /* エラーの解放 */
return stat;
{
int memsize = DEFAULT_MEMSIZE, clocks = DEFAULT_CLOCKS;
int opt, stat = 0;
- const char *version = PACKAGE_VERSION, *cmdversion = "comet2 of YACASL2 version %s\n";
+ const char *version = PACKAGE_VERSION, *cmdversion = "comet2monitor: COMET II machine code monitor of YACASL2 version %s\n";
const char *usage = "Usage: %s [-vh] [-M <MEMORYSIZE>] [-C <CLOCKS>]\n";
/* オプションの処理 */
/* COMET II仮想マシンのリセット */
reset(memsize, clocks);
execptr->start = 0;
- execmode.step = true;
- exec(); /* プログラム実行 */
+ execmode.monitor = true;
+ exec(); /* プログラム実行 */
shutdown();
stat = (cerr->num == 0) ? 0 : 1;
freecerr(); /* エラーの解放 */
*
* @return なし
*
- * @param cmdtype コマンドの種類
- * @param *cmdname コマンドの名前
* @param word ワード値
- * @param adr アドレス値
* @param pradr 次に実行すべき命令語の先頭アドレス
*/
void disassemble_dc(WORD word, WORD pradr);
};
/**
- * @brief 実行モード: trace, logical, dump, step
+ * @brief 実行モード: trace, logical, dump, monitor, step
*/
-EXECMODE execmode = {false, false, false, false};
+EXECMODE execmode = {false, false, false, false, false};
char *pr2str(WORD pr)
{
addcerrlist(ARRAYSIZE(cerr_exec), cerr_exec);
}
-bool loadassemble(const char *file)
+WORD loadassemble(const char *file, WORD start)
{
FILE *fp;
- bool stat = true;
+ WORD end;
assert(file != NULL);
if((fp = fopen(file, "rb")) == NULL) {
perror(file);
- return false;
+ return 0;
}
- execptr->end = execptr->start +
- fread(sys->memory, sizeof(WORD), sys->memsize - execptr->start, fp);
- if(execptr->end == sys->memsize) {
+ end = start + fread(sys->memory + start, sizeof(WORD), sys->memsize - start, fp);
+ if(end == sys->memsize) {
setcerr(210, file); /* load - memory overflow */
fprintf(stderr, "Load error - %d: %s\n", cerr->num, cerr->msg);
- stat = false;
}
fclose(fp);
- return stat;
+ return end;
}
void nop()
sys->cpu->pr += 2;
}
-char *grstr(WORD word)
-{
- assert(word <= 7);
- char *str = malloc_chk(3 + 1, "grstr.str");
- sprintf(str, "GR%d", word);
- return str;
-}
-
void exec()
{
clock_t clock_begin, clock_end;
void (*cmdptr)();
char *s;
+ const char *monmsg = "COMET II machine code monitor. Type ? for help.\n";
create_code_cmdtype(); /* 命令のコードとタイプがキーのハッシュ表を作成 */
if(execmode.trace == true) {
}
fprintf(stdout, "\n");
}
- /* デバッガーモードの場合、デバッガーを起動 */
- if(execmode.step == true || getbps(sys->cpu->pr) == true) {
+ /* ステップモードまたはブレークポイントの場合、モニターを起動 */
+ if(
+ (execmode.monitor == true && sys->cpu->pr == execptr->start) ||
+ execmode.step == true || getbps(sys->cpu->pr) == true)
+ {
+ if(sys->cpu->pr == execptr->start) {
+ fprintf(stdout, "%s", monmsg);
+ }
monitor();
}
/* プログラムレジスタをチェック */
if(cerr->num > 0) {
goto execfin;
}
- /* 終了フラグがtrueの場合は、正常終了 */
+ /* 終了フラグがtrueの場合は、モニターまたは正常終了 */
if(execptr->stop == true) {
- break;
+ if(execmode.monitor == true) {
+ fprintf(stdout, "Return to top.\n");
+ monitor();
+ } else {
+ break;
+ }
}
/* クロック周波数の設定 */
do {
MONCMDTYPE monitorcmd(char *cmd, MONARGS *args)
{
MONCMDTYPE cmdtype = MONREPEAT;
- if(stracmp(cmd, 2, (char* []){"b", "break"})) {
+ if(stracmp(cmd, 2, (char* []){"a", "assemble"})) {
+ if(args->argc == 0) {
+ fprintf(stderr, "Error: Input file name.\n");
+ } else if(args->argc == 1) {
+ assemble(1, (char* []){args->argv[0]}, 0);
+ } else {
+ assemble(1, (char* []){args->argv[0]}, nh2word(args->argv[1]));
+ }
+ } else if(stracmp(cmd, 2, (char* []){"b", "break"})) {
mon_break(args->argc, args->argv);
} else if(stracmp(cmd, 2, (char* []){"c", "continue"})) {
execmode.step = false;
cmdtype = MONNEXT;
} else if(stracmp(cmd, 2, (char* []){"d", "dump"})) {
mon_dump(args->argc, args->argv);
+ } else if(stracmp(cmd, 2, (char* []){"l", "load"})) {
+ loadassemble(args->argv[0], nh2word(args->argv[1]));
+ } else if(stracmp(cmd, 2, (char* []){"n", "next"})) {
+ execmode.step = true;
+ cmdtype = MONNEXT;
} else if(stracmp(cmd, 2, (char* []){"q", "quit"})) {
fprintf(stdout, "Quit: COMET II monitor\n");
cmdtype = MONQUIT;
if(args->argc == 2) {
disassemble_memory(nh2word(args->argv[0]), nh2word(args->argv[1]));
}
- } else if(stracmp(cmd, 2, (char* []){"s", "step"})) {
- execmode.step = true;
- cmdtype = MONNEXT;
+ } else if(stracmp(cmd, 1, (char* []){"reset"})) {
+ fprintf(stdout, "Reset COMET II.\n");
+ reset(sys->memsize, sys->clocks); /* COMET II仮想マシンのリセット */
} else if(stracmp(cmd, 2, (char* []){"t", "trace"})) {
if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"a", "auto"})) {
execmode.logical = false;
fprintf(stdout, "b[reak] -- Manipulate Breakpoints. See details, `b ?'.\n");
fprintf(stdout, "c[ontinue] -- Continue running your program.\n");
fprintf(stdout, "d[ump] -- Display memory dump. `d[ump] a[uto]/n[oauto]' set auto/noauto display.\n");
+ 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");
+ fprintf(stdout, "n[ext] -- Go next instruction.\n");
fprintf(stdout, "q[uit] -- Quit running your program.\n");
+ fprintf(stdout, "reset -- Reset the system.\n");
fprintf(stdout, "r[everse] -- Disassemble memory. `r[everse] <start address> <end address>.\n");
- fprintf(stdout, "s[tep] -- Step by step running your program until next interaction.\n");
+ 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");
fprintf(stdout, "t[race] -- Display CPU register. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
fprintf(stdout, "T[race] -- Display CPU register as logical value. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
fprintf(stdout, "?/h[elp] -- Display this help.\n");
char *buf, *p;
MONCMDLINE *moncmdl;
MONCMDTYPE cmdtype = MONREPEAT;
+
do {
- fprintf(stdout, "COMET II (Type ? for help) > ");
+ fprintf(stdout, "- ");
buf = malloc_chk(MONINSIZE + 1, "monitor.buf");
fgets(buf, MONINSIZE, stdin);
if((p = strchr(buf, '\n')) != NULL) {
return cmd;
}
+/**
+ * 汎用レジスタの番号からレジスタを表す文字列を返す
+ */
+
+char *grstr(WORD word)
+{
+ assert(word <= 7);
+ char *str = malloc_chk(3 + 1, "grstr.str");
+ sprintf(str, "GR%d", word);
+ return str;
+}
+
/**
* コードがキーの命令ハッシュ表を解放する
*/