パスワードを忘れた? アカウント作成
118172 journal

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;
}
この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • _struprと_strdupがなかったので、_struprは消して_strdupはstrdupに変えました。
    多分ニーモニックは大文字しか通りません。

    $ 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
typodupeerror

目玉の数さえ十分あれば、どんなバグも深刻ではない -- Eric Raymond

読み込み中...