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

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

アセンブラ(5)

前回のオペランドに「-(レジスタ)」と「+(レジスタ)」が必要だったので追加します。

オペランド

オペランドがアドレスを表す場合
オペランドが値を表す場合のデータのサイズ

命令の後に

  • .B が付く → 1 バイト
  • .W が付く → 2 バイト
  • .L が付く → 4 バイト
オペランドが値を表す場合(取得)
オペランドが値を表す場合(設定)

まだ動かすことはできていないのですが、オペランドの処理は以下のようになります。

class CPUState {
public:
    int32_t d[8] = { 0 };
    int32_t a[8] = { 0 }; // A7 は SP
    vector<int32_t> memory;
    int pc = 0; // プログラムカウンタ
    bool debug = false;
    bool is_zero = false; // ゼロフラグ
    bool is_carry = false; // キャリーフラグ
    bool is_sign = false; // サインフラグ
    bool is_overflow = false; // オーバーフローフラグ
    bool is_parity = false; // パリティフラグ
    map<string, int> labelTable;
    set<int> breakpoints;
    set<int> outputpoints;
    bool stepMode = false;
    int32_t getRegisterValue(const string& reg) const {
        if (reg == "SP" || reg == "sp") return a[7];
        if (reg == "FP" || reg == "fp") return a[6];
        if (reg.size() > 1 && reg[0] == '%') {
            int index = stoi(reg.substr(2));
            if (index >= 0 && index < 8) return a[index];
        }
        throw runtime_error("Invalid register name: " + reg);
    }
    void setRegisterValue(const string& reg, int32_t value) {
        if (reg == "SP" || reg == "sp") a[7] = value;
        else if (reg == "FP" || reg == "fp") a[6] = value;
        else if (reg.size() > 1 && reg[0] == '%') {
            int index = stoi(reg.substr(2));
            if (index >= 0 && index < 8) a[index] = value;
            else throw runtime_error("Invalid register index: " + reg);
        } else {
            throw runtime_error("Invalid register name: " + reg);
        }
    }
    int32_t getDataValue(int address, int byte_size) const {
        // メモリから指定されたアドレスのデータを取得
        if (address < 0 || address + byte_size > memory.size()) {
            throw runtime_error("Memory access out of bounds");
        }
        int32_t value = 0;
        for (int i = 0; i < byte_size; ++i) {
            value |= (memory[address + i] & 0xFF) << (i * 8);
        }
        return value;
    }
    void setDataValue(int address, int32_t value, int byte_size) {
        // メモリに指定されたアドレスにデータを書き込む
        if (address < 0 || address + byte_size > memory.size()) {
            throw runtime_error("Memory access out of bounds");
        }
        for (int i = 0; i < byte_size; ++i) {
            memory[address + i] = (value >> (i * 8)) & 0xFF;
        }
    }
    void printState() {
        int sp = a[7];
        cout << "PC=" << pc + 1 << " SP=" << sp << " STACK=[";
        for (int i = sp; i < memory.size(); ++i)
            cout << hex << memory[i] << (i + 1 < memory.size() ? ", " : "");
        cout << "]" << endl;
    }
    void printDebugLine(const vector<string>& program) {
        std::string bp_marker = breakpoints.contains(pc + 1) ? " *" : "";
        std::string op_marker = outputpoints.contains(pc + 1) ? " !" : "";
        cout << pc + 1 << ": " << bp_marker << op_marker << program[pc] << endl;
    }
    void debugPrint(const vector<string>& program) {
        printDebugLine(program);
        printState();
    }
    void setBreakpoint(int line) {
        breakpoints.insert(line);
    }
    void removeBreakpoint(int line) {
        breakpoints.erase(line);
    }
    void setOutputPoint(int line) {
        outputpoints.insert(line);
    }
    void removeOutputPoint(int line) {
        outputpoints.erase(line);
    }
    bool isBreakpoint() const {
        return breakpoints.contains(pc + 1);
    }
    bool isOutputPoint() const {
        return outputpoints.contains(pc + 1);
    }
};

class Operand {
    std::string operand_string; // オペランドを表す文字列
	CPUState state; // CPUの状態を保持する
public:
    Operand(const std::string& str) : operand_string(str) {}
    std::string get_string() const {
        return operand_string;
    }
    int get_address() const {
        // オペランドがアドレスを表す場合
        // ラベル → ラベルが表すアドレスを取得
        // 数値 → その数値を取得
        // (レジスタ) → レジスタの値を取得
        // (数値,レジスタ) → レジスタの値 + 数値を取得
        std::string srnum("[-+]?[0-9]+");
        std::regex rnum(srnum);
        std::string srlabel("[.]?[A-Za-z]+");
        std::regex rlabel(srlabel);
        std::string srreg("[%]([ADad][0-7]|SP|sp|FP|fp)");
        std::regex rireg("\\((" + srreg + ")\\)");
        std::regex ridreg("(" + srnum + ")\\((" + srreg + ")\\)");
        std::regex rixreg("\\((" + srnum + ")\\s*[,]\\s*(" + srreg + ")\\)");
        std::smatch match;
        if (std::regex_match(operand_string, match, rlabel)) {
            std::string label = match.str();
            return state.labelTable.at(label); // ラベルの場合、ラベルテーブルからアドレスを取得
        }
        else if (std::regex_match(operand_string, match, rnum)) {
            return std::stoi(match.str()); // 数値リテラルの場合、その数値を返す
        }
        else if (std::regex_match(operand_string, match, rireg)) {
            std::string reg = match[1].str();
            return state.getRegisterValue(reg); // レジスタ名の場合、レジスタの値を返す
        }
        else if (std::regex_match(operand_string, match, rixreg)) {
            int num = std::stoi(match[1].str());
            std::string reg = match[2].str();
            int reg_value = state.getRegisterValue(reg); // レジスタの値を取得
            return reg_value + num; // レジスタの値 + 数値を返す
        }
    }
    int get_value(int byte_size) const {
        // オペランドが値を表す場合(取得)
        // ラベル → ラベルが表すアドレスから指定したサイズの値を取得
        // #数値 → その数値を取得
        // レジスタ → レジスタの値を(指定したサイズにして)取得
        // (レジスタ) → レジスタが表すアドレスから指定したサイズの値を取得
        // -(レジスタ) → レジスタの値を指定したサイズ減らした後、レジスタが表すアドレスから指定したサイズの値を取得
        // (レジスタ)+ → レジスタが表すアドレスから指定したサイズの値を取得後、レジスタの値を指定したサイズ増やす
        // 数値(レジスタ) → レジスタの値 + 数値が表すアドレスから指定したサイズの値を取得
        std::string srnum("[-+]?[0-9]+");
        std::regex rnum(srnum);
        std::regex rimnum("#" + srnum);
        std::string srlabel("[.]?[A-Za-z]+");
        std::regex rlabel(srlabel);
        std::string srreg("[%]([ADad][0-7]|SP|sp|FP|fp)");
        std::regex rreg(srreg);
        std::regex rireg("\\((" + srreg + ")\\)");
        std::regex ridreg("(" + srnum + ")\\((" + srreg + ")\\)");
        std::regex rixreg("\\((" + srnum + ")\\s*[,]\\s*(" + srreg + ")\\)");
        std::smatch match;
        if (std::regex_match(operand_string, match, rlabel)) {
            std::string label = match.str();
            int address = state.labelTable.at(label); // ラベルの場合、ラベルテーブルからアドレスを取得
            return state.getDataValue(address, byte_size); // ラベルが表すアドレスから指定したサイズの値を取得
        }
        else if (std::regex_match(operand_string, match, rimnum)) {
            return std::stoi(match.str()); // 数値リテラルの場合、その数値を返す
        }
        else if (std::regex_match(operand_string, match, rreg)) {
            std::string reg_name = match.str();
            return state.getRegisterValue(reg_name); // レジスタ名の場合、レジスタの値を取得
        }
        else if (std::regex_match(operand_string, match, rireg)) {
            std::string reg_name = match[1].str();
            int address = state.getRegisterValue(reg_name); // レジスタ名の場合、レジスタの値を取得
            return state.getDataValue(address, byte_size); // 計算したアドレスから指定したサイズの値を取得
        }
        else if (std::regex_match(operand_string, match, rixreg)) {
            int num = std::stoi(match[1].str());
            std::string reg_name = match[2].str();
            int reg_value = state.getRegisterValue(reg_name); // レジスタの値を取得
            int address = reg_value + num; // レジスタの値 + 数値を計算
            return state.getDataValue(address, byte_size); // 計算したアドレスから指定したサイズの値を取得
        }
    }
    void set_value(int32_t value, int byte_size) const {
        // オペランドが値を表す場合(設定)
        // ラベル → ラベルが表すアドレスから指定したサイズに値を設定
        // レジスタ → レジスタの値(指定したサイズ)を設定
        // (レジスタ) → レジスタが表すアドレスから指定したサイズに値を設定
        // -(レジスタ) → レジスタの値を指定したサイズ減らした後、レジスタが表すアドレスから指定したサイズに値を設定
        // (レジスタ)+ → レジスタが表すアドレスから指定したサイズに値を設定後、レジスタの値を指定したサイズ増やす
        // 数値(レジスタ) → レジスタの値 + 数値が表すアドレスから指定したサイズに値を設定
        std::string srnum("[-+]?[0-9]+");
        std::regex rnum(srnum);
        std::regex rimnum("#" + srnum);
        std::string srlabel("[.]?[A-Za-z]+");
        std::regex rlabel(srlabel);
        std::string srreg("[%]([ADad][0-7]|SP|sp|FP|fp)");
        std::regex rreg(srreg);
        std::regex rireg("\\((" + srreg + ")\\)");
        std::regex ridreg("(" + srnum + ")\\((" + srreg + ")\\)");
        std::regex rixreg("\\((" + srnum + ")\\s*[,]\\s*(" + srreg + ")\\)");
        std::smatch match;
        if (std::regex_match(operand_string, match, rlabel)) {
            std::string label = match.str();
            int address = state.labelTable.at(label); // ラベルの場合、ラベルテーブルからアドレスを取得
            const_cast<CPUState&>(state).setDataValue(address, value, byte_size); // ラベルが表すアドレスに指定したサイズの値を設定
        }
        else if (std::regex_match(operand_string, match, rimnum)) {
            // 数値リテラルの場合、その数値を設定
            throw runtime_error("Cannot set value to immediate operand: " + operand_string);
        }
        else if (std::regex_match(operand_string, match, rreg)) {
            std::string reg_name = match.str();
            const_cast<CPUState&>(state).setRegisterValue(reg_name, value); // レジスタ名の場合、レジスタの値を設定
        }
        else if (std::regex_match(operand_string, match, rireg)) {
            std::string reg_name = match[1].str();
            int address = state.getRegisterValue(reg_name); // レジスタ名の場合、レジスタの値を取得
            const_cast<CPUState&>(state).setDataValue(address, value, byte_size); // 計算したアドレスに指定したサイズの値を設定
        }
        else if (std::regex_match(operand_string, match, rixreg)) {
            int num = std::stoi(match[1].str());
            std::string reg_name = match[2].str();
            int reg_value = state.getRegisterValue(reg_name); // レジスタの値を取得
            int address = reg_value + num; // レジスタの値 + 数値を計算
            const_cast<CPUState&>(state).setDataValue(address, value, byte_size); // 計算したアドレスに指定したサイズの値を設定
        }
    }
};