前回のオペランドに「-(レジスタ)」と「+(レジスタ)」が必要だったので追加します。
オペランド
オペランドが値を表す場合(取得)
オペランドが値を表す場合(設定)
- ラベル → ラベルが表すアドレスから指定したサイズに値を設定
- レジスタ → レジスタの値(指定したサイズ)を設定
- (レジスタ) → レジスタが表すアドレスから指定したサイズに値を設定
- -(レジスタ) → レジスタの値を指定したサイズ減らした後、レジスタが表すアドレスから指定したサイズに値を設定
- (レジスタ)+ → レジスタが表すアドレスから指定したサイズに値を設定後、レジスタの値を指定したサイズ増やす
- 数値(レジスタ) → レジスタの値 + 数値が表すアドレスから指定したサイズに値を設定
まだ動かすことはできていないのですが、オペランドの処理は以下のようになります。
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); // 計算したアドレスに指定したサイズの値を設定 } } };

