#include <iostream>
#include <vector>
#include <chrono>
#include <array>
#include <iomanip>
#include <algorithm>
#include <bitset>
#include <string>
#include <sstream>
static constexpr uint16_t USER_PROGRAM_BASE = 0x2000;
// Набор машинных инструкций виртуального компьютера
enum Opcode {
MOV_IMM = 0x1, // Загрузка константы в регистр: MOV_IMM rX, <imm>
ADD = 0x2, // Сложение: ADD r_dst, r_src1, r_src2
OUT = 0x3, // Вывод значения регистра (в десятичном виде)
MOV_REG = 0x4, // Перемещение данных между регистрами: MOV_REG r_dst, r_src
JMP = 0x5, // Безусловный переход: JMP <offset> (относительно базового адреса программы)
SLEEP = 0x6, // Задержка: SLEEP <кол-во циклов>
IN = 0x7, // Чтение символа с консоли: IN rX
PRINT = 0x8, // Вывод символа (нижние 8 бит регистра интерпретируются как char)
HALT = 0x9 // Завершение исполнения программы
};
class CPU {
private:
static constexpr size_t MEMORY_SIZE = 65536;
std::array<std::bitset<256>, 4> registers;
uint16_t ip = 0;
uint16_t program_base = 0;
std::vector<uint16_t> memory;
uint64_t sleep_cycles = 0;
uint64_t clock_freq;
std::chrono::time_point<std::chrono::high_resolution_clock> last_tick;
std::string bitsToDec(const std::bitset<256>& bits) {
std::string dec = "0";
for (int i = 255; i >= 0; --i) {
int carry = 0;
for (int j = dec.size() - 1; j >= 0; --j) {
int digit = (dec[j] - '0') * 2 + carry;
carry = digit / 10;
dec[j] = (digit % 10) + '0';
}
if (carry > 0)
dec.insert(dec.begin(), carry + '0');
if (bits[i]) {
carry = 1;
for (int j = dec.size() - 1; j >= 0; --j) {
int digit = (dec[j] - '0') + carry;
carry = digit / 10;
dec[j] = (digit % 10) + '0';
if (carry == 0)
break;
}
if (carry > 0)
dec.insert(dec.begin(), carry + '0');
}
}
return dec.empty() ? "0" : dec;
}
uint8_t getDestReg(uint16_t instr) { return (instr >> 10) & 0x03; }
uint8_t getSrcReg1(uint16_t instr) { return (instr >> 8) & 0x03; }
uint8_t getSrcReg2(uint16_t instr) { return (instr >> 6) & 0x03; }
uint8_t getImmediateValue(uint16_t instr) { return instr & 0xFF; }
uint16_t getJumpOffset(uint16_t instr) { return instr & 0x0FFF; }
void syncClock() {
auto now = std::chrono::high_resolution_clock::now();
std::chrono::nanoseconds target_duration(1000000000 / clock_freq);
auto elapsed = now - last_tick;
if (elapsed < target_duration) {
while (std::chrono::high_resolution_clock::now() - last_tick < target_duration) {}
}
last_tick = std::chrono::high_resolution_clock::now();
}
public:
CPU(uint64_t freq) : clock_freq(freq), memory(MEMORY_SIZE, 0) {
last_tick = std::chrono::high_resolution_clock::now();
}
void load_program(uint16_t address, const std::vector<uint16_t>& program) {
if (address + program.size() >= MEMORY_SIZE) {
throw std::out_of_range("Программа требует слишком много памяти");
}
std::copy(program.begin(), program.end(), memory.begin() + address);
}
void start_program(uint16_t entry_point) {
ip = entry_point;
program_base = entry_point;
registers.fill(std::bitset<256>(0));
sleep_cycles = 0;
}
void execute() {
while (ip < MEMORY_SIZE) {
syncClock();
if (sleep_cycles > 0) {
sleep_cycles--;
continue;
}
uint16_t instr = memory[ip++];
uint8_t opcode = (instr >> 12) & 0x0F;
switch (opcode) {
case MOV_IMM: {
uint8_t reg = getDestReg(instr);
uint8_t imm = getImmediateValue(instr);
registers[reg] = std::bitset<256>(imm);
break;
}
case ADD: {
uint8_t dst = getDestReg(instr);
uint8_t src1 = getSrcReg1(instr);
uint8_t src2 = getSrcReg2(instr);
bool carry = false;
std::bitset<256> result;
for (int i = 0; i < 256; ++i) {
bool b1 = registers[src1][i];
bool b2 = registers[src2][i];
uint8_t sum = b1 + b2 + carry;
result[i] = sum % 2;
carry = sum >= 2;
}
if (carry && program_base == USER_PROGRAM_BASE) {
printf("Прерывание: обнаружено переполнение 256-битного значения. Завершение программы.\n");
return;
}
registers[dst] = result;
break;
}
case OUT: {
uint8_t reg = getDestReg(instr);
printf("OUT: %s\n", bitsToDec(registers[reg]).c_str());
break;
}
case MOV_REG: {
uint8_t dst = getDestReg(instr);
uint8_t src = getSrcReg1(instr);
registers[dst] = registers[src];
break;
}
case JMP: {
uint16_t offset = getJumpOffset(instr);
ip = program_base + offset;
break;
}
case SLEEP: {
sleep_cycles = instr & 0x0FFF;
break;
}
case IN: {
uint8_t reg = getDestReg(instr);
char ch;
std::cin.get(ch);
registers[reg] = std::bitset<256>(static_cast<uint16_t>(ch));
break;
}
case PRINT: {
uint8_t reg = getDestReg(instr);
char ch = static_cast<char>(registers[reg].to_ulong() & 0xFF);
printf("%c", ch);
break;
}
case HALT: {
return;
}
default:
printf("Неизвестная инструкция: 0x%X\n", instr);
return;
}
}
}
};
void runLoader(CPU& cpu) {
printf("Добро пожаловать в эмулятор ОС\n\n");
printf("Доступные команды:\n");
printf(" run <машинный код> - загрузить и выполнить программу. Машинный код задаётся шестнадцатеричными числами через пробел.\n");
printf(" help - вывести справку по командам.\n");
printf(" programs - показать доступные для запуска программы\n");
printf(" exit - завершить работу ОС.\n\n");
const uint16_t PROGRAM_LOAD_ADDRESS = USER_PROGRAM_BASE;
while (true) {
printf("OS> ");
std::string line;
std::getline(std::cin, line);
if (line.empty())
std::getline(std::cin, line);
std::istringstream iss(line);
std::string command;
iss >> command;
if (command == "exit") {
printf("Завершение работы ОС.\n");
break;
}
else if (command == "help") {
printf("\nДоступные команды:\n");
printf(" run <машинный код> - загрузить и выполнить программу. Пример:\n");
printf(" run 0x1001 0x1401 0x3000 ... 0x9000\n");
printf(" programs - показать доступные для запуска программы\n");
printf(" exit - выйти из ОС.\n\n");
}
else if (command == "run") {
std::vector<uint16_t> program;
std::string token;
while (iss >> token) {
try {
if (token.find("0x") == 0 || token.find("0X") == 0)
token = token.substr(2);
uint16_t instr = static_cast<uint16_t>(std::stoul(token, nullptr, 16));
program.push_back(instr);
}
catch (std::exception& e) {
fprintf(stderr, "Ошибка преобразования токена '%s': %s\n", token.c_str(), e.what());
}
}
if (program.empty()) {
fprintf(stderr, "Не указан машинный код для загрузки.\n");
continue;
}
try {
cpu.load_program(PROGRAM_LOAD_ADDRESS, program);
cpu.start_program(PROGRAM_LOAD_ADDRESS);
printf("Запуск программы...\n");
cpu.execute();
printf("\nПрограмма завершила работу.\n");
}
catch (std::exception& e) {
fprintf(stderr, "Ошибка при загрузке/исполнении программы: %s\n", e.what());
}
}
else if (command == "programs") {
printf("\nДоступные программы (Вы можете скопировать их и вставить в команду run):\n");
printf("\nВычисление чисел Фибоначчи: 0x1001 0x1401 0x3000 0x63E8 0x3400 0x63E8 0x2840 0x3800 0x63E8 0x4100 0x4600 0x5006\n");
}
else {
fprintf(stderr, "Неизвестная команда. Введите 'help' для справки.\n");
}
}
}
int main() {
setlocale(LC_ALL, "ru");
int fr;
printf("Введите скорость работы виртуального компьютера (Рекомендуется 1000): ");
std::cin >> fr;
printf("\n\n");
CPU cpu(fr);
runLoader(cpu);
return 0;
}
class CPU {
private:
static constexpr size_t MEMORY_SIZE = 65536;
std::array<std::bitset<256>, 4> registers;
uint16_t ip = 0;
uint16_t program_base = 0;
std::vector<uint16_t> memory;
uint64_t sleep_cycles = 0;
uint64_t clock_freq;
std::chrono::time_point<std::chrono::high_resolution_clock> last_tick;
std::string bitsToDec(const std::bitset<256>& bits) {
std::string dec = "0";
for (int i = 255; i >= 0; --i) {
int carry = 0;
for (int j = dec.size() - 1; j >= 0; --j) {
int digit = (dec[j] - '0') * 2 + carry;
carry = digit / 10;
dec[j] = (digit % 10) + '0';
}
if (carry > 0)
dec.insert(dec.begin(), carry + '0');
if (bits[i]) {
carry = 1;
for (int j = dec.size() - 1; j >= 0; --j) {
int digit = (dec[j] - '0') + carry;
carry = digit / 10;
dec[j] = (digit % 10) + '0';
if (carry == 0)
break;
}
if (carry > 0)
dec.insert(dec.begin(), carry + '0');
}
}
return dec.empty() ? "0" : dec;
}
void runLoader() {
printf("Добро пожаловать в эмулятор ОС\n\n");
printf("Доступные команды:\n");
printf(" run <машинный код> - загрузить и выполнить программу. Машинный код задаётся шестнадцатеричными числами через пробел.\n");
printf(" help - вывести справку по командам.\n");
printf(" programs - показать доступные для запуска программы\n");
printf(" exit - завершить работу ОС.\n\n");
const uint16_t PROGRAM_LOAD_ADDRESS = USER_PROGRAM_BASE;
while (true) {
printf("OS> ");
std::string line;
std::getline(std::cin, line);
if (line.empty())
std::getline(std::cin, line);
std::istringstream iss(line);
std::string command;
iss >> command;
if (command == "exit") {
printf("Завершение работы ОС.\n");
break;
}
else if (command == "help") {
printf("\nДоступные команды:\n");
printf(" run <машинный код> - загрузить и выполнить программу. Пример:\n");
printf(" run 0x1001 0x1401 0x3000 ... 0x9000\n");
printf(" programs - показать доступные для запуска программы\n");
printf(" exit - выйти из ОС.\n\n");
}
else if (command == "run") {
std::vector<uint16_t> program;
std::string token;
while (iss >> token) {
try {
if (token.find("0x") == 0 || token.find("0X") == 0)
token = token.substr(2);
uint16_t instr = static_cast<uint16_t>(std::stoul(token, nullptr, 16));
program.push_back(instr);
}
catch (std::exception& e) {
fprintf(stderr, "Ошибка преобразования токена '%s': %s\n", token.c_str(), e.what());
}
}
if (program.empty()) {
fprintf(stderr, "Не указан машинный код для загрузки.\n");
continue;
}
try {
load_program(PROGRAM_LOAD_ADDRESS, program);
start_program(PROGRAM_LOAD_ADDRESS);
printf("Запуск программы...\n");
execute();
printf("\nПрограмма завершила работу.\n");
}
catch (std::exception& e) {
fprintf(stderr, "Ошибка при загрузке/исполнении программы: %s\n", e.what());
}
}
else if (command == "programs") {
printf("\nДоступные программы (Вы можете скопировать их и вставить в команду run):\n");
printf("\nВычисление чисел Фибоначчи: 0x1001 0x1401 0x3000 0x63E8 0x3400 0x63E8 0x2840 0x3800 0x63E8 0x4100 0x4600 0x5006\n");
}
else {
fprintf(stderr, "Неизвестная команда. Введите 'help' для справки.\n");
}
}
}
uint8_t getDestReg(uint16_t instr) { return (instr >> 10) & 0x03; }
uint8_t getSrcReg1(uint16_t instr) { return (instr >> 8) & 0x03; }
uint8_t getSrcReg2(uint16_t instr) { return (instr >> 6) & 0x03; }
uint8_t getImmediateValue(uint16_t instr) { return instr & 0xFF; }
uint16_t getJumpOffset(uint16_t instr) { return instr & 0x0FFF; }
void syncClock() {
auto now = std::chrono::high_resolution_clock::now();
std::chrono::nanoseconds target_duration(1000000000 / clock_freq);
auto elapsed = now - last_tick;
if (elapsed < target_duration) {
while (std::chrono::high_resolution_clock::now() - last_tick < target_duration) {}
}
last_tick = std::chrono::high_resolution_clock::now();
}
public:
CPU(uint64_t freq) : clock_freq(freq), memory(MEMORY_SIZE, 0) {
last_tick = std::chrono::high_resolution_clock::now();
runLoader();
}
void load_program(uint16_t address, const std::vector<uint16_t>& program) {
if (address + program.size() >= MEMORY_SIZE) {
throw std::out_of_range("Программа требует слишком много памяти");
}
std::copy(program.begin(), program.end(), memory.begin() + address);
}
void start_program(uint16_t entry_point) {
ip = entry_point;
program_base = entry_point;
registers.fill(std::bitset<256>(0));
sleep_cycles = 0;
}
void execute() {
while (ip < MEMORY_SIZE) {
syncClock();
if (sleep_cycles > 0) {
sleep_cycles--;
continue;
}
uint16_t instr = memory[ip++];
uint8_t opcode = (instr >> 12) & 0x0F;
switch (opcode) {
case MOV_IMM: {
uint8_t reg = getDestReg(instr);
uint8_t imm = getImmediateValue(instr);
registers[reg] = std::bitset<256>(imm);
break;
}
case ADD: {
uint8_t dst = getDestReg(instr);
uint8_t src1 = getSrcReg1(instr);
uint8_t src2 = getSrcReg2(instr);
bool carry = false;
std::bitset<256> result;
for (int i = 0; i < 256; ++i) {
bool b1 = registers[src1][i];
bool b2 = registers[src2][i];
uint8_t sum = b1 + b2 + carry;
result[i] = sum % 2;
carry = sum >= 2;
}
if (carry && program_base == USER_PROGRAM_BASE) {
printf("Прерывание: обнаружено переполнение 256-битного значения. Завершение программы.\n");
return;
}
registers[dst] = result;
break;
}
case OUT: {
uint8_t reg = getDestReg(instr);
printf("OUT: %s\n", bitsToDec(registers[reg]).c_str());
break;
}
case MOV_REG: {
uint8_t dst = getDestReg(instr);
uint8_t src = getSrcReg1(instr);
registers[dst] = registers[src];
break;
}
case JMP: {
uint16_t offset = getJumpOffset(instr);
ip = program_base + offset;
break;
}
case SLEEP: {
sleep_cycles = instr & 0x0FFF;
break;
}
case IN: {
uint8_t reg = getDestReg(instr);
char ch;
std::cin.get(ch);
registers[reg] = std::bitset<256>(static_cast<uint16_t>(ch));
break;
}
case PRINT: {
uint8_t reg = getDestReg(instr);
char ch = static_cast<char>(registers[reg].to_ulong() & 0xFF);
printf("%c", ch);
break;
}
case HALT: {
return;
}
default:
printf("Неизвестная инструкция: 0x%X\n", instr);
return;
}
}
}
};
int main() {
setlocale(LC_ALL, "ru");
int fr;
printf("Введите скорость работы виртуального компьютера (Рекомендуется 1000): ");
std::cin >> fr;
printf("\n\n");
CPU cpu(fr);
//runLoader(cpu);
return 0;
}