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

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

アセンブラ(6)

仕様の変更

前回の仕様に、グローバル変数を定義する方法を追加します。

グローバル変数

グローバル変数を定義する方法を追加します。

  • var.l 初期値
  • var.w 初期値
  • var.b 初期値
  • array.l 個数
  • array.w 個数
  • array.b 個数

デバッグ用疑似命令

デバッグ用疑似命令を追加します。

疑似関数

疑似関数を追加します。これらは関数を呼び出す手順で呼び出すものとします。

  • muls
  • mulu
  • divs
  • divu
  • sin
  • cos
  • sqrt
  • itof
  • itod

プログラムを実行する処理

コードの後半の部分は Visual Studio が自動的に補完したもので、まだ動かせるようにはなっていません。

void executeInstruction(const string& line, CPUState& cpu) {
    if (cpu.debug) cout << "Executing: " << line << endl;

    string label;
    string opcode;
    size_t spacePos = line.find(' ');
    std::vector<Operand> operands;
    if (spacePos != std::string::npos) {
        opcode = line.substr(0, spacePos);
        string operands_str = line.substr(spacePos);
        size_t commaPos = operands_str.find(',');
        // かっこで囲まれた部分をとばす
        size_t parenPos = operands_str.find('(');
        if (parenPos != std::string::npos) {
            size_t closePos = operands_str.substr(parenPos).find(')') + parenPos;
            commaPos = operands_str.substr(closePos).find(',') + closePos;
        }
        if (commaPos != std::string::npos) {
            operands.push_back(Operand(operands_str.substr(0, commaPos)));
            operands.push_back(Operand(operands_str.substr(commaPos)));
        }
        else {
            operands.push_back(Operand(operands_str));
        }
    }
    else {
        opcode = line; // オペコードのみの場合
    }

    Instruction instruction(label, opcode);

    if(instruction.is_move_instruction()) {
        // MOVE命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid MOVE instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t value = src.get_value(instruction.data_size());
        dst.set_value(value, instruction.data_size());
    }
    else if (instruction.is_movem_instruction()) {
        // MOVEM命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid MOVEM instruction: " << line << endl;
            return;
        }
        Operand& regs = operands[0];
        Operand& addr = operands[1];
        int32_t address = addr.get_address();
        for (char reg : regs.get_string()) {
            if (reg == 'd') continue; // dレジスタは無視
            int regIndex = reg - '0';
            cpu.stack.push_back(cpu.d[regIndex]);
            cpu.a[7] -= 4;
        }
    }
    else if (instruction.is_jump_instruction()) {
        // JMP命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid JMP instruction: " << line << endl;
            return;
        }
        string label = operands[0].get_string();
        if (cpu.labelTable.count(label)) {
            cpu.pc = cpu.labelTable[label];
            return; // skip increment
        }
        else {
            cerr << "Unknown label in JMP: " << label << endl;
        }
    }
	else if (instruction.is_conditional_jump_instruction()) {
        // 条件付きジャンプ命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid conditional jump instruction: " << line << endl;
            return;
        }
        string label = operands[0].get_string();
        if (cpu.labelTable.count(label)) {
            string condition = instruction.get_jump_condition();
            if ((condition == "E" && cpu.is_zero) ||
                (condition == "NE" && !cpu.is_zero) ||
                (condition == "G" && !cpu.is_zero && !cpu.is_sign) ||
                (condition == "GE" && !cpu.is_sign) ||
                (condition == "L" && cpu.is_sign) ||
                (condition == "LE" && (cpu.is_sign || cpu.is_zero)) ||
                (condition == "A" && !cpu.is_carry && !cpu.is_zero) ||
                (condition == "AE" && !cpu.is_carry) ||
                (condition == "B" && cpu.is_carry) ||
                (condition == "BE" && cpu.is_carry) ||
                (condition == "S" && cpu.is_sign) ||
                (condition == "NS" && !cpu.is_sign) ||
                (condition == "O" && cpu.is_overflow) ||
                (condition == "NO" && !cpu.is_overflow)) {
                cpu.pc = cpu.labelTable[label];
                return; // skip increment
            }
        }
        else {
            cerr << "Unknown label in conditional jump: " << label << endl;
        }
    }
    else if (instruction.is_jsr_instruction()) {
        // JSR命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid JSR instruction: " << line << endl;
            return;
        }
        string label = operands[0].get_string();
        if (cpu.labelTable.count(label)) {
            cpu.stack.push_back(cpu.pc + 1);
            cpu.a[7] -= 4;
            cpu.pc = cpu.labelTable[label];
            return; // skip increment
        }
        else {
            cerr << "Unknown label in JSR: " << label << endl;
        }
    }
    else if (instruction.is_rts_instruction()) {
        // RTS命令の処理
        if (!cpu.stack.empty()) {
            cpu.pc = cpu.stack.back();
            cpu.stack.pop_back();
            cpu.a[7] += 4;
            return; // skip increment
        }
        else {
            cerr << "Return stack empty!" << endl;
        }
    }
    else if (instruction.is_lea_instruction()) {
        // LEA命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid LEA instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(4); // .Lは4バイト
        if (dst.get_string()[0] == 'a') {
            cpu.a[dst.get_string()[1] - '0'] = val; // Aレジスタに設定
        }
    }
    else if (instruction.is_pea_instruction()) {
        // PEA命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid PEA instruction: " << line << endl;
            return;
        }
        Operand& operand = operands[0];
        int32_t addr = operand.get_address();
        cpu.stack.push_back(addr);
        cpu.a[7] -= 4; // スタックポインタを調整
    }
    else if (instruction.is_link_instruction()) {
        // LINK命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid LINK instruction: " << line << endl;
            return;
        }
        string reg = operands[0].get_string();
		int32_t offset = operands[1].get_value(4); // .Lは4バイト
        if (reg[0] == 'a') {
            int regIndex = reg[1] - '0';
            cpu.stack.push_back(cpu.a[regIndex]);
            cpu.a[regIndex] = cpu.a[7];
            cpu.a[7] -= offset; // スタックポインタを調整
        }
        else {
            cerr << "Invalid register in LINK: " << reg << endl;
        }
    }
    else if (instruction.is_unlk_instruction()) {
        // UNLK命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid UNLK instruction: " << line << endl;
            return;
        }
        string reg = operands[0].get_string();
        if (reg[0] == 'a') {
            int regIndex = reg[1] - '0';
            cpu.a[7] = cpu.a[regIndex];
            cpu.a[regIndex] = cpu.stack.back();
            cpu.stack.pop_back();
        }
        else {
            cerr << "Invalid register in UNLK: " << reg << endl;
        }
    }
    else if (instruction.is_add_instruction()) {
        // ADD命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid ADD instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(instruction.data_size());
        if (dst.get_string()[0] == 'a') {
            cpu.a[dst.get_string()[1] - '0'] += val; // Aレジスタに加算
        }
        else if (dst.get_string()[0] == 'd') {
            cpu.d[dst.get_string()[1] - '0'] += val; // Dレジスタに加算
        }
    }
    else if (instruction.is_sub_instruction()) {
        // SUB命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid SUB instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(instruction.data_size());
		if (dst.get_string()[0] == ' a') {
            cpu.a[dst.get_string()[1] - '0'] -= val; // Aレジスタから減算
        }
        else if (dst.get_string()[0] == 'd') {
            cpu.d[dst.get_string()[1] - '0'] -= val; // Dレジスタから減算
        }
    }
    else if (instruction.is_cmp_instruction()) {
        // CMP命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid CMP instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t s = src.get_value(instruction.data_size());
        int32_t d = dst.get_value(instruction.data_size());
        cpu.is_zero = (s == d);
		cpu.is_sign = (s < 0);
        cpu.is_carry = (s < d);
        cpu.is_overflow = ((s < 0 && d >= 0 && s > d) || (s >= 0 && d < 0 && s < d));
        if (cpu.debug) cout << "Compare " << s << " and " << d << endl;
    }
    else if (instruction.is_neg_instruction()) {
        // NEG命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid NEG instruction: " << line << endl;
            return;
        }
        Operand& dst = operands[0];
        int32_t val = dst.get_value(instruction.data_size());
        dst.set_value(-val, instruction.data_size());
    }
    else if (instruction.is_tst_instruction()) {
        // TST命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid TST instruction: " << line << endl;
            return;
        }
        Operand& dst = operands[0];
        int32_t val = dst.get_value(instruction.data_size());
		cpu.is_zero = (val == 0);

        cpu.is_sign = (val < 0);
        cpu.is_carry = (val < 0); // TSTは符号ビットをチェック
        cpu.is_overflow = false; // TSTではオーバーフローは考慮しない
        if (cpu.debug) cout << "Test " << val << endl;
    }
    else if (instruction.is_and_instruction()) {
        // AND命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid AND instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(instruction.data_size());
        int32_t dst_val = dst.get_value(instruction.data_size());
        dst.set_value(dst_val & val, instruction.data_size());
    }
    else if (instruction.is_or_instruction()) {
        // OR命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid OR instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(instruction.data_size());
        int32_t dst_val = dst.get_value(instruction.data_size());
        dst.set_value(dst_val | val, instruction.data_size());
    }
    else if (instruction.is_eor_instruction()) {
        // XOR命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid EOR instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(instruction.data_size());
        int32_t dst_val = dst.get_value(instruction.data_size());
        dst.set_value(dst_val ^ val, instruction.data_size());
    }
    else if (instruction.is_not_instruction()) {
        // NOT命令の処理
        if (operands.size() != 1) {
            cerr << "Invalid NOT instruction: " << line << endl;
            return;
        }
		Operand& dst = operands[0];
        int32_t val = dst.get_value(instruction.data_size());
        dst.set_value(~val, instruction.data_size());
    }
    else if (instruction.is_shift_instruction()) {
        // シフト命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid shift instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(4); // .Lは4バイト
        int32_t dst_val = dst.get_value(instruction.data_size());
        if (instruction.is_left_shift()) {
            dst.set_value(dst_val << val, instruction.data_size());
        }
        else {
            dst.set_value(dst_val >> val, instruction.data_size());
        }
    }
    else if (instruction.is_rotate_instruction()) {
        // ローテート命令の処理
        if (operands.size() != 2) {
            cerr << "Invalid rotate instruction: " << line << endl;
            return;
        }
        Operand& src = operands[0];
        Operand& dst = operands[1];
        int32_t val = src.get_value(4); // .Lは4バイト
        int32_t dst_val = dst.get_value(instruction.data_size());
        if (instruction.mnemonic_upper.find("ROL") == 0) {
            dst.set_value((dst_val << val) | (dst_val >> (32 - val)), instruction.data_size());
        }
        else if (instruction.mnemonic_upper.find("ROR") == 0) {
            dst.set_value((dst_val >> val) | (dst_val << (32 - val)), instruction.data_size());
        }
    }
    cpu.pc++;
}