非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

関数電卓コマンド版(3)

乗算・除算をインラインアセンブラで記述したものを作成しました。『独習アセンブラ 新版』に GCCインラインアセンブラの書き方が説明されています。

#define USE_X68000

X68000 版を作ることができます。最初は起動できなかったのですが、実行ファイルのサイズを削減するためのコンパイルのオプションを取り除くと起動できました。実行ファイルのサイズは 958 KB あります。これは今後調査の必要があります。

乗算・除算をインラインアセンブラで記述するサンプル

を切り替えることができます。Visual Studio ではインラインアセンブラを使うことが難しいようなのでインラインアセンブラは使っていません。

使い方

16 ビットの符号なし整数の乗算・除算を行います。

  • 「数値 * 数値」で乗算
  • 「数値 / 数値」で除算

を行います。間違った入力をすると終了します。

#include <iostream>
#include <string>

#define BITRANGE 16
//#define USE_WINGCC
//#define USE_X68000

//int multiply2(int x, int y, int bitsize)
#ifdef USE_X68000
asm(
    "shift_multiply_a:\n\t"
    "move.l 8(%sp), %d1\n\t"
    "move.w #16, %a0\n\t"
    "moveq  #0, %d0\n\t"
    "smulL3:\n\t"
    "add.l  %d1, %d1\n\t"
    "add.l  %d0, %d0\n\t"
    "btst   #16, %d1\n\t"
    "jeq    smulL2\n\t"
    "add.l  4(%sp), %d0\n\t"
    "smulL2:\n\t"
    "subq.l #1, %a0\n\t"
    "cmp.w  #0, %a0\n\t"
    "jne    smulL3\n\t"
    "rts\n\t"
);
int shift_multiply(int x, int y) {
    int result = 0;
    asm(
        "move.l %1, -(%%sp)\n\t"
        "move.l %2, -(%%sp)\n\t"
        "jsr shift_multiply_a\n\t"
        "add.l  #8, %%sp\n\t"
        "move.l %%d0, %0\n\t"
        : "=r"(result)
        : "r"(x), "r"(y)
		: "d0", "d0", "a0", "a1"
    );
    return result;
}
#else
#ifdef USE_WINGCC
    asm(
        "shift_multiply_a:\n\t"
        "movl $16, %r8d\n\t"
        "xorl %eax, %eax\n\t"
        "smulL3:\n\t"
        "addl %edx, %edx\n\t"
        "addl %eax, %eax\n\t"
        "btl  $16, %edx\n\t"
        "jnc  smulL2\n\t"
        "addl %ecx, %eax\n\t"
        "smulL2:\n\t"
        "decl %r8d\n\t"
        "jne  smulL3\n\t"
        "ret\n\t"
    );
int shift_multiply(int x, int y) {
    int result = 0;
    asm(
        "call shift_multiply_a\n\t"
		: "=a"(result)
		: "c"(x), "d"(y)
		: "r8"
    );
	return result;
}
#else
int shift_multiply(int x, int y) {
    int c = 1 << BITRANGE;
    int result = 0;
    for (int i = 0; i < BITRANGE; i++) {
        y <<= 1;
        result <<= 1;
        if (y & c) {
            result += x;
        }
    }
    return result;
}
#endif
#endif

int test_multiply(int x, int y) {
	return shift_multiply(x, y);
}

//int divide1(int x, int y, int bitsize)
#ifdef USE_X68000
asm(
    "shift_divide_a:\n\t"
    "move.l 4(%sp), %a1\n\t"
    "move.l 8(%sp), %d1\n\t"
    "swap   %d1\n\t"
    "clr.w  %d1\n\t"
    "move.w #16, %a0\n\t"
    "moveq  #0, %d0\n\t"
    "sdivL10:\n\t"
    "asr.l  #1, %d1\n\t"
    "add.l  %d0, %d0\n\t"
    "cmp.l  %d1, %a1\n\t"
    "jlt    sdivL9\n\t"
    "addq.l #1, %d0\n\t"
    "sub.l  %d1, % a1\n\t"
    "sdivL9:\n\t"
    "subq.l #1, %a0\n\t"
    "cmp.w  #0, %a0\n\t"
    "jne    sdivL10\n\t"
    "rts\n\t"
);
int shift_divide(int x, int y) {
    int result = 0;
    asm(
        "move.l %1, -(%%sp)\n\t"
        "move.l %2, -(%%sp)\n\t"
        "jsr shift_divide_a\n\t"
        "add.l  #8, %%sp\n\t"
        "move.l %%d0, %0\n\t"
        : "=r"(result)
        : "r"(x), "r"(y)
        : "d0", "d0", "a0", "a1"
    );
    return result;
}
#else
#ifdef USE_WINGCC
asm(
    "shift_divide_a:\n\t"
    "movl $16, %r8d\n\t"
    "xorl %eax, %eax\n\t"
    "sall $16, %edx\n\t"
    "sdivL12:\n\t"
    "sarl %edx\n\t"
    "addl %eax, %eax\n\t"
    "cmpl %ecx, %edx\n\t"
    "jg sdivL11\n\t"
    "incl %eax\n\t"
    "subl %edx, %ecx\n\t"
    "sdivL11:\n\t"
    "decl %r8d\n\t"
    "jne sdivL12\n\t"
    "ret\n\t"
);
int shift_divide(int x, int y) {
    int result = 0;
    asm(
        "call shift_divide_a\n\t"
        : "=a"(result)
        : "c"(x), "d"(y)
        : "r8"
    );
    return result;
}
#else
int shift_divide(int x, int y) {
    int result = 0;
    y <<= BITRANGE;
    for (int i = 0; i < BITRANGE; i++) {
        y >>= 1;
        result <<= 1;
        if (x >= y) {
            result++;
            x -= y;
        }
    }
    return result;
}
#endif
#endif

int test_divide(int x, int y) {
	return shift_divide(x, y);
}

int main()
{
    std::cout << "Start" << std::endl;
    for (;;) {
        std::cout << "input exp> ";
        int x, y;
        std::string op;
        std::cin >> x >> op >> y;
        if (op == "*") {
            int result_multiply = test_multiply(x, y);
            std::cout << "Multiply: " << result_multiply << std::endl;
        }
        else if (op == "/") {
            int result_divide = test_divide(x, y);
            std::cout << "Divide: " << result_divide << std::endl;
        }
        else {
            std::cout << "Invalid operation" << std::endl;
            return 1;
        }
    }
	return 0;
}