乗算・除算をインラインアセンブラで記述した shiftasm.x を以下のように修正しました。
- iostream と string を使わないように変更しました。実行ファイルのサイズは 98KB になりました。
- 実行方法を選択することができるようにしました。
乗算・除算をインラインアセンブラで記述するサンプル
を切り替えることができます。
使い方
16 ビットの符号なし整数の乗算・除算を行います。
- 「数値 * 数値」で乗算
- 「数値 / 数値」で除算
を行います。「exit」と入力をすると終了します。
処理の方法を切り替えることができます。
//#define USE_WINGCC //#define USE_X68000 //#define USE_IOSTREAM #ifdef USE_IOSTREAM #include <iostream> #define USE_STDSTRING #ifdef USE_X68000 #include <limits> #endif #else #include <cstring> #endif #include <string> #define BITRANGE 16 #define C_OP_SIZE 1000 //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 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 #ifdef USE_IOSTREAM void print_line(const std::string& str) { std::cout << str << std::endl; } void print_string(const std::string& str) { std::cout << str; } void print_int(const std::string& str, int val) { std::cout << str << val << std::endl; } #else void print_line(const char* str) { printf("%s\n", str); } void print_string(const char* str) { printf("%s", str); } void print_int(const char* str, int val) { printf("%s%d\n", str, val); } #endif #ifdef USE_STDSTRING bool str_eq(std::string str1, std::string str2) { return str1 == str2; } #else bool str_eq(char* str1, const char* str2) { return strcmp(str1, str2) == 0; } #endif void clear_input_buffer() { #ifdef USE_X68000 scanf("%*[^\n]"); // Clear the rest of the line #else scanf_s("%*[^\n]"); // Clear the rest of the line #endif } int read_expression(int* x, char* op, int* y) { #ifdef USE_X68000 int field_count = scanf("%d %s %d", x, op, y); #else int field_count = scanf_s("%d %s %d", x, op, C_OP_SIZE - 1, y); #endif return field_count; } int read_string(char* str) { #ifdef USE_X68000 int field_count = scanf("%s", str); #else int field_count = scanf_s("%s", str, C_OP_SIZE - 1); #endif return field_count; } void string_copy(char* dst, char* src) { #ifdef USE_X68000 strncpy(dst, src, C_OP_SIZE - 1); dst[C_OP_SIZE - 1] = '\0'; // Ensure null termination #else strcpy_s(dst, C_OP_SIZE - 1, src); #endif } enum ClacMethod { Asm, // Assembler CPP, // C++ SysLong, // System Long }; enum ClacMethod clac_method = Asm; #ifdef USE_STDSTRING bool change_clac_method(std::string method) { if (method == "asm") { clac_method = Asm; return true; } else if (method == "cpp") { clac_method = CPP; return true; } else if (method == "sys") { clac_method = SysLong; return true; } return false; } std::string get_clac_method() { switch (clac_method) { case Asm: return "asm"; case CPP: return "cpp"; case SysLong: return "sys"; default: return "unknown"; } } #else bool change_clac_method(const char* method) { if (strcmp(method, "asm") == 0) { clac_method = Asm; return true; } else if (strcmp(method, "cpp") == 0) { clac_method = CPP; return true; } else if (strcmp(method, "sys") == 0) { clac_method = SysLong; return true; } return false; } const char* get_clac_method() { switch (clac_method) { case Asm: return "asm"; case CPP: return "cpp"; case SysLong: return "sys"; default: return "unknown"; } } #endif int test_multiply(int x, int y) { switch (clac_method) { case Asm: return shift_multiply(x, y); case CPP: return x * y; // Simple C++ multiplication case SysLong: { int result = 0; #ifdef USE_X68000 asm( "move.l %1, %%d0\n\t" "move.l %2, %%d1\n\t" "dc.w 0xfe00\n\t" // __LMUL "move.l %%d0, %0\n\t" : "=r"(result) // Output operand : "r"(x), "r"(y) // Input operand : "d0", "d1" // Clobbered register ); #endif return result; // Return the result of the multiplication } default: return 0; // Default case to avoid warnings } } int test_divide(int x, int y) { switch (clac_method) { case Asm: return shift_divide(x, y); case CPP: return x / y; // Simple C++ division case SysLong: { int result = 0; #ifdef USE_X68000 asm( "move.l %1, %%d0\n\t" "move.l %2, %%d1\n\t" "dc.w 0xfe01\n\t" // __LDIV "move.l %%d0, %0\n\t" : "=r"(result) // Output operand : "r"(x), "r"(y) // Input operand : "d0", "d1" // Clobbered register ); #endif return result; // Return the result of the multiplication } default: return 0; // Default case to avoid warnings } } int main() { print_line("Start"); for (;;) { print_string(get_clac_method()); print_string(" exp> "); int x, y; #ifdef USE_STDSTRING std::string op; #else char op[C_OP_SIZE] = { 0 }; #endif #ifdef USE_IOSTREAM if (!(std::cin >> x >> op >> y)) { std::cin.clear(); std::string command; std::cin >> command; if (command == "exit") { std::cout << "Exiting..." << std::endl; break; } if(change_clac_method(command)) { continue; } std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cout << "Invalid command" << std::endl; continue; } #else char c_op[C_OP_SIZE] = { 0 }; int field_count = read_expression(&x, c_op, &y); if (field_count != 3) { read_string(c_op); if (strcmp(c_op, "exit") == 0) { printf("Exiting...\n"); break; } if (change_clac_method(c_op)) { continue; } clear_input_buffer(); printf("Invalid command\n"); continue; } string_copy(op, c_op); #endif int result; if (str_eq(op, "*")) { result = test_multiply(x, y); print_int("Multiply: ", result); } else if (str_eq(op, "/")) { result = test_divide(x, y); print_int("Divide: ", result); } else { print_line("Invalid operation"); } } return 0; }


