rotoの日記: GMC-4 Assembler 1
日記 by
roto
大人の科学のヤツ、4ビットマイコンと思っていたら、4ビットマイコン風インタプリタ(?)だった。
とりあえず使える程度のアセンブラ(?)を作ってみた。
/* GMC4ASM */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#define CODE_SIZE (0x50)
typedef struct
{
const char* mnemonic;
int operand;
char code;
} mnemonic_t;
typedef struct
{
const char* exMnemonic;
char code;
} exMnemonic_t;
typedef struct
{
const mnemonic_t *mnemonic;
const exMnemonic_t *exMnemonic;
char immediate;
char *label;
} code_t;
typedef struct
{
char* name;
int addr;
} label_t;
#define IMM_LABEL (-2)
#define IMM_EXMNE (-1)
static const mnemonic_t mnemonicList[] =
{
{"KA", 0, '0'},
{"AO", 0, '1'},
{"CH", 0, '2'},
{"CY", 0, '3'},
{"AM", 0, '4'},
{"MA", 0, '5'},
{"M+", 0, '6'},
{"M-", 0, '7'},
{"TIA", 1, '8'},
{"AIA", 1, '9'},
{"TIY", 1, 'A'},
{"AIY", 1, 'B'},
{"CIA", 1, 'C'},
{"CIY", 1, 'D'},
{"CAL", IMM_EXMNE, 'E'},
{"JUMP", IMM_LABEL, 'F'},
};
static const exMnemonic_t extenedMnemonicList[] =
{
{"RSTO", '0'}, // E0
{"SETR", '1'}, // E1
{"RSTR", '2'}, // E2
// {"INPT", '3'}, // E3
{"CMPL", '4'}, // E4
{"CHNG", '5'}, // E5
{"SIFT", '6'}, // E6
{"ENDS", '7'}, // E7
{"ERRS", '8'}, // E8
{"SHTS", '9'}, // E9
{"LONS", 'A'}, // EA
{"SUND", 'B'}, // EB
{"TIMR", 'C'}, // EC
{"DSPR", 'D'}, // ED
{"DEM-", 'E'}, // EE
{"DEM+", 'F'}, // EF
};
typedef enum
{
ERROR_SUCCESS,
ERROR_SYNTAX,
ERROR_LABELDUP,
ERROR_CODESIZE,
ERROR_LABELLISTSIZE
} errorCode_t;
static const struct
{
errorCode_t code;
const char* message;
} ErrorList[] =
{
{ERROR_SYNTAX, "Syntax error"},
{ERROR_LABELDUP, "Label duplicated"},
{ERROR_CODESIZE, "Too much Codes"},
{ERROR_LABELLISTSIZE, "Too much Labels"},
};
static const char* wordDelim = " \t";
static int codeCounter = 0;
static code_t codeList[CODE_SIZE];
static int codeListCount = 0;
static label_t labelList[CODE_SIZE];
static int labelListCounter = 0;
static const exMnemonic_t* GetExtendedInstruction(const char *exMnemonicStr)
{
int i;
for(i = 0; i < ARRAYSIZE(extenedMnemonicList); i++)
{
if(strcmp(extenedMnemonicList[i].exMnemonic, exMnemonicStr) == 0)
{
return &extenedMnemonicList[i];
}
}
return NULL;
}
static int GetLabelAddress(const char *name)
{
int i;
for(i = 0; i < labelListCounter; i++)
{
if(strcmp(name, labelList[i].name) == 0)
{
return labelList[i].addr;
}
}
return -1;
}
static errorCode_t SetInstruction(const mnemonic_t *mnemonic, char *p)
{
int operand = mnemonic->operand;
codeList[codeListCount].mnemonic = mnemonic;
codeList[codeListCount].exMnemonic = NULL;
codeList[codeListCount].immediate = '\0';
codeList[codeListCount].label = NULL;
codeCounter++;
if(operand != 0)
{
p = strtok(NULL, wordDelim);
if(p == NULL) return ERROR_SYNTAX;
if(*p == ';') return ERROR_SYNTAX;
if(operand == 1)
{
if(strlen(p) != 1) return ERROR_SYNTAX;
if(!('0' <= *p && *p <= '9') && !('A' <= *p && *p <= 'F'))
{
return ERROR_SYNTAX;
}
codeList[codeListCount].immediate = *p;
codeCounter++;
}
else if(operand == IMM_LABEL)
{
codeList[codeListCount].label = _strdup(p);
codeCounter += 2;
}
else if(operand == IMM_EXMNE)
{
const exMnemonic_t* exMnemonic = GetExtendedInstruction(p);
if(!exMnemonic) return ERROR_SYNTAX;
codeList[codeListCount].exMnemonic = exMnemonic;
codeCounter++;
}
}
if(codeCounter > CODE_SIZE) return ERROR_CODESIZE;
p = strtok(NULL, wordDelim);
if(p != NULL && *p != ';') return ERROR_SYNTAX;
codeListCount++;
return ERROR_SUCCESS;
}
static errorCode_t lineTrans(char* line)
{
char *p = strtok(_strupr(line), wordDelim);
int i;
int len;
if(p == NULL) return ERROR_SUCCESS;
if(*p == ';') return ERROR_SUCCESS;
len = strlen(p);
if(p[len - 1] == ':')
{
if(labelListCounter >= ARRAYSIZE(labelList))
{
return ERROR_LABELLISTSIZE;
}
if(len < 2) return ERROR_SYNTAX;
p[len - 1] = '\0';
if(GetLabelAddress(p) >= 0) return ERROR_LABELDUP;
labelList[labelListCounter].name = _strdup(p);
labelList[labelListCounter].addr = codeCounter;
labelListCounter++;
line = strtok(NULL, "");
if(line == NULL) return ERROR_SUCCESS;
return lineTrans(strtok(NULL, ""));
}
for(i = 0; i < ARRAYSIZE(mnemonicList); i++)
{
if(strcmp(p, mnemonicList[i].mnemonic) == 0)
{
if(codeListCount >= ARRAYSIZE(codeList))
{
return ERROR_CODESIZE;
}
return SetInstruction(&mnemonicList[i], p);
}
}
return ERROR_SUCCESS;
}
static void OutputInstSet(FILE* fp)
{
int i;
int address = 0;
fprintf(fp, "ADDR\tINST\tCODE\n");
for(i = 0; i < codeListCount; i++)
{
fprintf(fp, "%02X\t%s\t%c\n", address++, codeList[i].mnemonic->mnemonic, codeList[i].mnemonic->code);
if(codeList[i].immediate != '\0')
{
fprintf(fp, "%02X\t<%c>\t%c\n", address++, codeList[i].immediate, codeList[i].immediate);
}
else if(codeList[i].exMnemonic != NULL)
{
fprintf(fp, "%02X\t_%s\t%c\n", address++, codeList[i].exMnemonic->exMnemonic, codeList[i].exMnemonic->code);
}
else if(codeList[i].label != NULL)
{
int lbl = GetLabelAddress(codeList[i].label);
if(lbl < 0)
{
fprintf(stderr, "Label %s not found\n", codeList[i].label);
return;
}
fprintf(fp, "%02X\t<%X>\t%X\n", address++, lbl >> 4, lbl >> 4);
fprintf(fp, "%02X\t<%X>\t%X\n", address++, lbl & 0xF, lbl & 0xF);
}
}
}
void PutErrorMessage(errorCode_t err, int lineCount, char* buf)
{
int i;
for(i = 0; i < ARRAYSIZE(ErrorList); i++)
{
if(ErrorList[i].code == err)
{
fprintf(stderr, ErrorList[i].message);
break;
}
}
fprintf(stderr, "(%d): %s\n", lineCount, buf);
}
int main(int argc, char**argv)
{
FILE *fp;
char buf[256];
int lineCount;
if(argc < 2)
{
fprintf(stderr, "USAGE: GMC4ASM <asm file> [<out file>]\n");
return 1;
}
fp = fopen(argv[1], "r");
if(fp == NULL)
{
fprintf(stderr, "ERR: oepn %s\n", argv[1]);
return 2;
}
lineCount = 0;
while(fgets(buf, sizeof(buf) - 1, fp) != NULL)
{
char *p;
errorCode_t err;
buf[sizeof(buf) - 1] = '\0';
strtok(buf, "\r\n");
p = _strdup(buf);
err = lineTrans(p);
if(err != ERROR_SUCCESS)
{
PutErrorMessage(err, lineCount, buf);
free(p);
fclose(fp);
return 3;
}
free(p);
}
fclose(fp);
if(argc > 2)
{
fp = fopen(argv[2], "w");
if(fp == NULL)
{
fprintf(stderr, "ERR: oepn %s\n", argv[2]);
return 4;
}
}
else
{
fp = stdout;
}
OutputInstSet(fp);
if(fp != stdout)
{
fclose(fp);
}
return 0;
}
とりあえず使える程度のアセンブラ(?)を作ってみた。
/* GMC4ASM */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#define CODE_SIZE (0x50)
typedef struct
{
const char* mnemonic;
int operand;
char code;
} mnemonic_t;
typedef struct
{
const char* exMnemonic;
char code;
} exMnemonic_t;
typedef struct
{
const mnemonic_t *mnemonic;
const exMnemonic_t *exMnemonic;
char immediate;
char *label;
} code_t;
typedef struct
{
char* name;
int addr;
} label_t;
#define IMM_LABEL (-2)
#define IMM_EXMNE (-1)
static const mnemonic_t mnemonicList[] =
{
{"KA", 0, '0'},
{"AO", 0, '1'},
{"CH", 0, '2'},
{"CY", 0, '3'},
{"AM", 0, '4'},
{"MA", 0, '5'},
{"M+", 0, '6'},
{"M-", 0, '7'},
{"TIA", 1, '8'},
{"AIA", 1, '9'},
{"TIY", 1, 'A'},
{"AIY", 1, 'B'},
{"CIA", 1, 'C'},
{"CIY", 1, 'D'},
{"CAL", IMM_EXMNE, 'E'},
{"JUMP", IMM_LABEL, 'F'},
};
static const exMnemonic_t extenedMnemonicList[] =
{
{"RSTO", '0'}, // E0
{"SETR", '1'}, // E1
{"RSTR", '2'}, // E2
// {"INPT", '3'}, // E3
{"CMPL", '4'}, // E4
{"CHNG", '5'}, // E5
{"SIFT", '6'}, // E6
{"ENDS", '7'}, // E7
{"ERRS", '8'}, // E8
{"SHTS", '9'}, // E9
{"LONS", 'A'}, // EA
{"SUND", 'B'}, // EB
{"TIMR", 'C'}, // EC
{"DSPR", 'D'}, // ED
{"DEM-", 'E'}, // EE
{"DEM+", 'F'}, // EF
};
typedef enum
{
ERROR_SUCCESS,
ERROR_SYNTAX,
ERROR_LABELDUP,
ERROR_CODESIZE,
ERROR_LABELLISTSIZE
} errorCode_t;
static const struct
{
errorCode_t code;
const char* message;
} ErrorList[] =
{
{ERROR_SYNTAX, "Syntax error"},
{ERROR_LABELDUP, "Label duplicated"},
{ERROR_CODESIZE, "Too much Codes"},
{ERROR_LABELLISTSIZE, "Too much Labels"},
};
static const char* wordDelim = " \t";
static int codeCounter = 0;
static code_t codeList[CODE_SIZE];
static int codeListCount = 0;
static label_t labelList[CODE_SIZE];
static int labelListCounter = 0;
static const exMnemonic_t* GetExtendedInstruction(const char *exMnemonicStr)
{
int i;
for(i = 0; i < ARRAYSIZE(extenedMnemonicList); i++)
{
if(strcmp(extenedMnemonicList[i].exMnemonic, exMnemonicStr) == 0)
{
return &extenedMnemonicList[i];
}
}
return NULL;
}
static int GetLabelAddress(const char *name)
{
int i;
for(i = 0; i < labelListCounter; i++)
{
if(strcmp(name, labelList[i].name) == 0)
{
return labelList[i].addr;
}
}
return -1;
}
static errorCode_t SetInstruction(const mnemonic_t *mnemonic, char *p)
{
int operand = mnemonic->operand;
codeList[codeListCount].mnemonic = mnemonic;
codeList[codeListCount].exMnemonic = NULL;
codeList[codeListCount].immediate = '\0';
codeList[codeListCount].label = NULL;
codeCounter++;
if(operand != 0)
{
p = strtok(NULL, wordDelim);
if(p == NULL) return ERROR_SYNTAX;
if(*p == ';') return ERROR_SYNTAX;
if(operand == 1)
{
if(strlen(p) != 1) return ERROR_SYNTAX;
if(!('0' <= *p && *p <= '9') && !('A' <= *p && *p <= 'F'))
{
return ERROR_SYNTAX;
}
codeList[codeListCount].immediate = *p;
codeCounter++;
}
else if(operand == IMM_LABEL)
{
codeList[codeListCount].label = _strdup(p);
codeCounter += 2;
}
else if(operand == IMM_EXMNE)
{
const exMnemonic_t* exMnemonic = GetExtendedInstruction(p);
if(!exMnemonic) return ERROR_SYNTAX;
codeList[codeListCount].exMnemonic = exMnemonic;
codeCounter++;
}
}
if(codeCounter > CODE_SIZE) return ERROR_CODESIZE;
p = strtok(NULL, wordDelim);
if(p != NULL && *p != ';') return ERROR_SYNTAX;
codeListCount++;
return ERROR_SUCCESS;
}
static errorCode_t lineTrans(char* line)
{
char *p = strtok(_strupr(line), wordDelim);
int i;
int len;
if(p == NULL) return ERROR_SUCCESS;
if(*p == ';') return ERROR_SUCCESS;
len = strlen(p);
if(p[len - 1] == ':')
{
if(labelListCounter >= ARRAYSIZE(labelList))
{
return ERROR_LABELLISTSIZE;
}
if(len < 2) return ERROR_SYNTAX;
p[len - 1] = '\0';
if(GetLabelAddress(p) >= 0) return ERROR_LABELDUP;
labelList[labelListCounter].name = _strdup(p);
labelList[labelListCounter].addr = codeCounter;
labelListCounter++;
line = strtok(NULL, "");
if(line == NULL) return ERROR_SUCCESS;
return lineTrans(strtok(NULL, ""));
}
for(i = 0; i < ARRAYSIZE(mnemonicList); i++)
{
if(strcmp(p, mnemonicList[i].mnemonic) == 0)
{
if(codeListCount >= ARRAYSIZE(codeList))
{
return ERROR_CODESIZE;
}
return SetInstruction(&mnemonicList[i], p);
}
}
return ERROR_SUCCESS;
}
static void OutputInstSet(FILE* fp)
{
int i;
int address = 0;
fprintf(fp, "ADDR\tINST\tCODE\n");
for(i = 0; i < codeListCount; i++)
{
fprintf(fp, "%02X\t%s\t%c\n", address++, codeList[i].mnemonic->mnemonic, codeList[i].mnemonic->code);
if(codeList[i].immediate != '\0')
{
fprintf(fp, "%02X\t<%c>\t%c\n", address++, codeList[i].immediate, codeList[i].immediate);
}
else if(codeList[i].exMnemonic != NULL)
{
fprintf(fp, "%02X\t_%s\t%c\n", address++, codeList[i].exMnemonic->exMnemonic, codeList[i].exMnemonic->code);
}
else if(codeList[i].label != NULL)
{
int lbl = GetLabelAddress(codeList[i].label);
if(lbl < 0)
{
fprintf(stderr, "Label %s not found\n", codeList[i].label);
return;
}
fprintf(fp, "%02X\t<%X>\t%X\n", address++, lbl >> 4, lbl >> 4);
fprintf(fp, "%02X\t<%X>\t%X\n", address++, lbl & 0xF, lbl & 0xF);
}
}
}
void PutErrorMessage(errorCode_t err, int lineCount, char* buf)
{
int i;
for(i = 0; i < ARRAYSIZE(ErrorList); i++)
{
if(ErrorList[i].code == err)
{
fprintf(stderr, ErrorList[i].message);
break;
}
}
fprintf(stderr, "(%d): %s\n", lineCount, buf);
}
int main(int argc, char**argv)
{
FILE *fp;
char buf[256];
int lineCount;
if(argc < 2)
{
fprintf(stderr, "USAGE: GMC4ASM <asm file> [<out file>]\n");
return 1;
}
fp = fopen(argv[1], "r");
if(fp == NULL)
{
fprintf(stderr, "ERR: oepn %s\n", argv[1]);
return 2;
}
lineCount = 0;
while(fgets(buf, sizeof(buf) - 1, fp) != NULL)
{
char *p;
errorCode_t err;
buf[sizeof(buf) - 1] = '\0';
strtok(buf, "\r\n");
p = _strdup(buf);
err = lineTrans(p);
if(err != ERROR_SUCCESS)
{
PutErrorMessage(err, lineCount, buf);
free(p);
fclose(fp);
return 3;
}
free(p);
}
fclose(fp);
if(argc > 2)
{
fp = fopen(argv[2], "w");
if(fp == NULL)
{
fprintf(stderr, "ERR: oepn %s\n", argv[2]);
return 4;
}
}
else
{
fp = stdout;
}
OutputInstSet(fp);
if(fp != stdout)
{
fclose(fp);
}
return 0;
}
MacOSX 10.4(PowerPC)でコンパイルしてみました (スコア:1)
多分ニーモニックは大文字しか通りません。
$ diff gmc4asm.cpp gmc4asm.original.cpp
163c163
< codeList[codeListCount].label = strdup(p);
---
> codeList[codeListCount].label = _strdup(p);
183c183
< char *p = strtok(line, wordDelim); // char *p = strtok(_strupr(line), wordDelim);
---
> char *p = strtok(_strupr(line), wordDelim);
199c199
< labelList[labelListCounter].name = strdup(p);
---
> labelList[labelListCounter].name = _strdup(p);
291c291
< p = strdup(buf);
---
> p = _strdup(buf);
$ g++ -v
Using built-in specs.
Target: powerpc-apple-darwin8
Configured with: /var/tmp/gcc/gcc-5370~2/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=powerpc-apple-darwin8 --host=powerpc-apple-darwin8 --target=powerpc-apple-darwin8
Thread model: posix
gcc version 4.0.1 (Apple Computer, Inc. build 5370)
$ g++ gmc4asm.cpp
*アセンブルの例:p.60 program2 電子サイコロのソース
TIY 1
DISP:
CY
AO
CY
AIY 1
CIY 7
JUMP KEYSUB
TIY 1
KEYSUB:
KA
JUMP DISP
JUMP KEYSUB
アセンブル例:
$ ./gmc4asm a.asm
ADDR INST CODE
00 TIY A
01 <1> 1
02 CY 3
03 AO 1
04 CY 3
05 AIY B
06 <1> 1
07 CIY D
08 <7> 7
09 JUMP F
0A <0> 0
0B <E> E
0C TIY A
0D <1> 1
0E KA 0
0F JUMP F
10 <0> 0
11 <2> 2
12 JUMP F
13 <0> 0
14 <E> E