From 3ce19efae691787f6108af5978bebbd37524d846 Mon Sep 17 00:00:00 2001 From: mzhoot Date: Sun, 17 May 2026 22:37:32 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=82=D0=BE=D1=82=D0=B8?= =?UTF-8?q?=D0=BF=20=D1=81=D1=82=D0=B0=D0=BD=D0=B4=D0=B0=D1=80=D1=82=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5?= =?UTF-8?q?=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kvs_build.py | 7 +- kvs_builder.py | 15 +- kvs_data.py | 77 +++++--- kvs_pass1.py | 78 ++++---- kvs_pass2_encoder_mutsize.py | 20 +- kvs_verify.py | 247 ++++++++++++++++++++++++ todo.txt | 5 +- тесты/itoa0.квс | 67 +++++++ тесты/itoa1.квс | 80 ++++++++ тесты/itoa2.квс | 94 +++++++++ тесты/itoa3.квс | 94 +++++++++ тесты/длина_числа.квс | 73 +++++++ тесты/циклы.квс | 27 +++ тесты/циклы2.квс | 40 ++++ тесты/циклы3.квс | 40 ++++ тесты/циклы4.квс | 45 +++++ тесты/циклы5.квс | 86 +++++++++ тесты/циклы6.квс | 81 ++++++++ тесты/циклы7.квс | 138 +++++++++++++ тесты/циклы8.квс | 180 +++++++++++++++++ тесты/циклы9.квс | 77 ++++++++ 21 files changed, 1502 insertions(+), 69 deletions(-) create mode 100644 kvs_verify.py create mode 100644 тесты/itoa0.квс create mode 100644 тесты/itoa1.квс create mode 100644 тесты/itoa2.квс create mode 100644 тесты/itoa3.квс create mode 100644 тесты/длина_числа.квс create mode 100644 тесты/циклы.квс create mode 100644 тесты/циклы2.квс create mode 100644 тесты/циклы3.квс create mode 100644 тесты/циклы4.квс create mode 100644 тесты/циклы5.квс create mode 100644 тесты/циклы6.квс create mode 100644 тесты/циклы7.квс create mode 100644 тесты/циклы8.квс create mode 100644 тесты/циклы9.квс diff --git a/kvs_build.py b/kvs_build.py index 688408a..46c8931 100644 --- a/kvs_build.py +++ b/kvs_build.py @@ -32,6 +32,7 @@ if __name__ == "__main__": ("kvs_parser.py", [tokens_file, ast_file], "Парсинг"), ("kvs_pass1.py", [ast_file, pass1_file], "Первый проход"), ("kvs_pass2.py", [ast_file, pass1_file, csv_file], "Второй проход и генерация CSV"), + ("kvs_verify.py", [pass1_file, csv_file], "Проверка размеров инструкций"), ("kvs_builder.py", [csv_file, pass1_file, elf_file], "Сборка ELF"), ] @@ -43,9 +44,13 @@ if __name__ == "__main__": if result.returncode != 0: print(f"ОШИБКА на этапе '{description}':") print(result.stderr) + if result.stdout: + print(result.stdout) sys.exit(1) - print(result.stdout) + # Для верификатора показываем stdout (там детали проверки) + if result.stdout: + print(result.stdout) print(f"\n=== Компиляция успешно завершена ===") print(f"Исполняемый файл: {elf_file}") diff --git a/kvs_builder.py b/kvs_builder.py index 13e9163..274562f 100644 --- a/kvs_builder.py +++ b/kvs_builder.py @@ -17,7 +17,7 @@ def read_csv(input_file, vaddr_text, vaddr_data, text_size, data_size): data_bytes = bytearray(data_size) with open(input_file, 'r', encoding='utf-8') as f: - next(f) # Пропускаем заголовок + next(f) for line in f: line = line.strip() if not line: @@ -34,7 +34,6 @@ def read_csv(input_file, vaddr_text, vaddr_data, text_size, data_size): except ValueError: continue - # Определяем секцию по адресу if addr >= vaddr_data: offset = addr - vaddr_data if 0 <= offset < data_size: @@ -44,6 +43,18 @@ def read_csv(input_file, vaddr_text, vaddr_data, text_size, data_size): if 0 <= offset < text_size: text_bytes[offset] = byte_val + # Заменяем хвостовые нули на NOP'ы (0x90) + # Находим последний ненулевой байт + last_nonzero = -1 + for i in range(len(text_bytes) - 1, -1, -1): + if text_bytes[i] != 0: + last_nonzero = i + break + + if last_nonzero >= 0 and last_nonzero < len(text_bytes) - 1: + for i in range(last_nonzero + 1, len(text_bytes)): + text_bytes[i] = 0x90 + return text_bytes, data_bytes def read_pass1(input_file): diff --git a/kvs_data.py b/kvs_data.py index 6b72074..6a4eedf 100644 --- a/kvs_data.py +++ b/kvs_data.py @@ -238,11 +238,31 @@ INSTRUCTIONS = { } -# Размеры инструкций в байтах (для первого прохода) -INSTRUCTION_SIZES = { - "переместить_имм": 10, - "сравнить_с": 7, +# ========== РАЗМЕРЫ ИНСТРУКЦИЙ ДЛЯ ПЕРВОГО ПРОХОДА ========== + +# Инструкции с ФИКСИРОВАННЫМ размером (не зависят от операндов) +FIXED_SIZE_INSTRUCTIONS = { + "переместить": 3, + "сравнить": 3, + "сравнить_байт": 3, + "проверить": 3, + "прибавить": 3, + "прибавить_байт": 3, + "вычесть": 3, + "вычесть_байт": 3, + "увеличить": 3, + "уменьшить": 3, + "умножить": 3, + "умножить_знаковое": 3, + "разделить": 3, + "разделить_знаковое": 3, + "и": 3, + "или": 3, + "исключающее_или": 3, + "инвертировать": 3, + "отрицать": 3, "переход": 5, + "короткий_переход": 2, "переход_если_равно": 6, "переход_если_неравно": 6, "переход_если_ноль": 6, @@ -253,9 +273,6 @@ INSTRUCTION_SIZES = { "переход_если_больше_или_равно": 6, "переход_если_перенос": 6, "переход_если_нет_переноса": 6, - "вызов_системы": 2, - "нет_операции": 1, - "короткий_переход": 2, "короткий_переход_если_равно": 2, "короткий_переход_если_неравно": 2, "короткий_переход_если_меньше": 2, @@ -266,31 +283,19 @@ INSTRUCTION_SIZES = { "короткий_переход_если_нет_переноса": 2, "короткий_переход_если_ноль": 2, "короткий_переход_если_не_ноль": 2, - "сравнить": 3, - "проверить": 3, - "вычесть": 3, - "прибавить": 3, - "увеличить": 3, - "уменьшить": 3, - "и": 3, - "или": 3, - "исключающее_или": 3, - "инвертировать": 3, - "отрицать": 3, - "втолкнуть": 2, - "вытолкнуть": 2, - "втолкнуть_непосредственно": 5, - "умножить": 3, - "умножить_знаковое": 3, - "разделить": 3, - "разделить_знаковое": 3, + "вызвать": 5, + "вернуться": 1, + "вызов_системы": 2, + "нет_операции": 1, + "остановить": 1, + "отладка": 1, + "цикл": 2, + "обменять": 4, "сдвиг_влево": 4, "сдвиг_вправо": 4, "сдвиг_арифметический_вправо": 4, "вращать_влево": 4, "вращать_вправо": 4, - "цикл": 2, - "обменять": 4, "прервать": 2, "ввод_байта": 2, "вывод_байта": 2, @@ -308,6 +313,24 @@ INSTRUCTION_SIZES = { "прочитать_счётчик": 2, } +# Инструкции с ПЕРЕМЕННЫМ размером (зависят от операндов) +# Для них pass1 должен анализировать операнды +VARIABLE_SIZE_INSTRUCTIONS = { + "переместить_имм", # зависит от размера регистра (5/10) + "загрузить_байт", # зависит от регистра (1/2) + "сравнить_с", # зависит от размера регистра (4/7) + "прибавить_непосредственно", # зависит от размера регистра и imm (4/7) + "вычесть_непосредственно", # зависит от размера регистра и imm (4/7) + "загрузить", # зависит от режима адресации (3/7) + "сохранить", # зависит от режима адресации (3/7) + "загрузить_адрес", # зависит от режима адресации (3/7) + "втолкнуть", # зависит от регистра (1/2) + "вытолкнуть", # зависит от регистра (1/2) + "втолкнуть_непосредственно", # зависит от imm (2/5) + "переместить_с_нулями", # зависит от размера регистра + "переместить_со_знаком", # зависит от размера регистра +} + # === ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ === diff --git a/kvs_pass1.py b/kvs_pass1.py index 255cea4..8530bd8 100644 --- a/kvs_pass1.py +++ b/kvs_pass1.py @@ -8,7 +8,13 @@ import sys sys.path.insert(0, '.') -from kvs_data import PAGE_SIZE, text_vaddr_base, align_up, INSTRUCTIONS, INSTRUCTION_SIZES +from kvs_data import PAGE_SIZE, text_vaddr_base, align_up, INSTRUCTIONS +from kvs_data import FIXED_SIZE_INSTRUCTIONS, VARIABLE_SIZE_INSTRUCTIONS + +# ========== РЕЖИМ ОЦЕНКИ РАЗМЕРОВ ========== +# True — пессимистичный: все неизвестные инструкции = 10 байт (максимум) +# False — оптимистичный: использовать точный анализ операндов +PESSIMISTIC_SIZE_ESTIMATE = False def unescape_string(s): """Преобразует escape-последовательности в реальные символы""" @@ -91,15 +97,7 @@ def split_by_operators(content): def parse_memory_operand(operand_str): """ Анализирует операнд памяти вида [reg + reg*scale + disp] - Возвращает словарь с информацией: - - has_base: bool - - base_reg: str or None - - has_index: bool - - index_reg: str or None - - scale: int (1,2,4,8) - - has_disp: bool - - disp_value: int (если есть) - - disp_size: 1 или 4 + Возвращает словарь с информацией. """ if not operand_str.startswith('[') or not operand_str.endswith(']'): return None @@ -119,7 +117,6 @@ def parse_memory_operand(operand_str): 'disp_size': 0 } - # Проверяем, не является ли содержимое просто числом (абсолютный адрес) if is_dec_number(content) or is_hex_number(content): result['has_disp'] = True if content.startswith('0x') or content.startswith('0X'): @@ -129,13 +126,11 @@ def parse_memory_operand(operand_str): result['disp_size'] = 4 return result - # Простой регистр без смещения if is_register(content): result['has_base'] = True result['base_reg'] = content return result - # Разбираем выражение: регистр [+- регистр[*масштаб] [+- смещение]] parts = split_by_operators(content) for part in parts: @@ -235,26 +230,20 @@ class Pass1: elif directive == '.байт': sec = parts[2] if len(parts) > 3 and parts[3]: - # Считаем количество значений, разделённых запятыми num_bytes = 1 for ch in parts[3]: if ch == ',': num_bytes += 1 self.position[sec] += num_bytes - - # Директивы резервирования в .бнд elif directive == '.резб': count = int(parts[3]) self.position['.бнд'] += count * 1 - elif directive == '.резс': count = int(parts[3]) self.position['.бнд'] += count * 2 - elif directive == '.рездс': count = int(parts[3]) self.position['.бнд'] += count * 4 - elif directive == '.резкс': count = int(parts[3]) self.position['.бнд'] += count * 8 @@ -271,7 +260,6 @@ class Pass1: operands_str = parts[3] if len(parts) > 3 else "" operands = [] if operands_str: - # Разбиваем по запятым current = '' for ch in operands_str: if ch == ',': @@ -287,20 +275,44 @@ class Pass1: def estimate_size(self, mnemonic, operands): """Динамический расчёт размера инструкции""" - # Инструкции с памятью (загрузить, сохранить, загрузить_адрес) + # Инструкции с фиксированным размером + if mnemonic in FIXED_SIZE_INSTRUCTIONS: + return FIXED_SIZE_INSTRUCTIONS[mnemonic] + + # Инструкции с переменным размером — анализируем операнды if mnemonic in ("загрузить", "сохранить", "загрузить_адрес"): - # RIP-relative: REX (1) + opcode (1) + ModR/M (1) + disp32 (4) = 7 - return 7 + for op in operands: + if op.startswith('MEM:reg_indirect:'): + return 3 # косвенная: REX + opcode + ModR/M + return 7 # абсолютная: REX + opcode + ModR/M + disp32 - # Инструкции без операндов — размер из INSTRUCTIONS - if mnemonic in ("вызов_системы", "нет_операции", "вернуться", "остановить", "отладка"): - instr = INSTRUCTIONS.get(mnemonic) - if instr and "opcode" in instr: - return len(instr["opcode"]) - return 2 + if mnemonic in ("втолкнуть", "вытолкнуть"): + if operands: + reg = operands[0] + if reg in ('р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'): + return 2 # нужен REX-префикс + return 1 # без REX - # Фиксированные размеры из общей таблицы - return INSTRUCTION_SIZES.get(mnemonic, 3) + if mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно", "сравнить_с"): + return 7 # пессимистично: REX + opcode + ModR/M + imm32 + + if mnemonic == "переместить_имм": + return 10 # пессимистично: mov reg64, imm64 + + if mnemonic in ("переместить_с_нулями", "переместить_со_знаком"): + return 8 # REX + 3-байтный opcode + ModR/M + disp32 + + if mnemonic == "загрузить_байт": + return 2 # opcode + imm8 + + if mnemonic == "втолкнуть_непосредственно": + return 5 # пессимистично: opcode + imm32 + + # Неизвестная инструкция + if PESSIMISTIC_SIZE_ESTIMATE: + return 10 + else: + return 3 def calculate_layout(self): text_size = self.position[".text"] @@ -316,13 +328,11 @@ class Pass1: offset_data = align_up(offset_text + text_size, PAGE_SIZE) vaddr_text = text_vaddr_base vaddr_data = align_up(vaddr_text + text_size, PAGE_SIZE) - # .бнд всегда на следующей странице после .data vaddr_bnd = vaddr_data + PAGE_SIZE comment_size = len("Сборщик КВС".encode('utf-8')) + 1 offset_comment = align_up(offset_data + data_size, 1) - # shstrtab теперь включает ".bss" if bnd_size > 0: shstrtab_content = b"\x00.text\x00.data\x00.bss\x00.comment\x00.shstrtab\x00" else: @@ -371,7 +381,7 @@ if __name__ == "__main__": layout = pass1.calculate_layout() write_pass1(layout, pass1.labels, pass1.label_sections, pass1.symbols, sys.argv[2]) - print(f"Проход 1:") + print(f"Проход 1 (режим: {'пессимистичный' if PESSIMISTIC_SIZE_ESTIMATE else 'оптимистичный'}):") print(f" .text: размер={layout['text_size']} байт, смещение_в_файле=0x{layout['offset_text']:x}, виртуальный_адрес=0x{layout['vaddr_text']:x}") print(f" .data: размер={layout['data_size']} байт, смещение_в_файле=0x{layout['offset_data']:x}, виртуальный_адрес=0x{layout['vaddr_data']:x}") print(f" .бнд: размер={layout['bnd_size']} байт, виртуальный_адрес=0x{layout['vaddr_bnd']:x}") diff --git a/kvs_pass2_encoder_mutsize.py b/kvs_pass2_encoder_mutsize.py index 91ebf79..db4ea6f 100644 --- a/kvs_pass2_encoder_mutsize.py +++ b/kvs_pass2_encoder_mutsize.py @@ -734,14 +734,26 @@ def encode_add_sub_reg_reg(mnemonic, operands): # ДУБЛИКАТ return code -def encode_muldiv(mnemonic): # ДУБЛИКАТ +def encode_muldiv(mnemonic, operands): # ДУБЛИКАТ """MUL/IMUL/DIV/IDIV""" code = bytearray() instr = INSTRUCTIONS[mnemonic] subop = instr["subop"] - code.append(0x48) + + # Получаем индекс регистра-операнда + if operands: + reg_info = get_reg_info(operands[0]) + reg = reg_info["index"] + else: + reg = 0 # по умолчанию rax + + rex = 0x48 + if reg >= 8: + rex |= 0x01 # REX.B + + code.append(rex) code.extend(instr["opcode"]) - modrm = 0xC0 | (subop << 3) | 0 + modrm = 0xC0 | (subop << 3) | (reg & 7) code.append(modrm) return code @@ -1073,7 +1085,7 @@ def encode_instruction(mnemonic, operands, labels, label_sections, symbols, vadd # ----- MUL/DIV ----- elif mnemonic in ("умножить", "умножить_знаковое", "разделить", "разделить_знаковое"): - return encode_muldiv(mnemonic) + return encode_muldiv(mnemonic, operands) # ----- AND/OR/XOR ----- elif mnemonic in ("и", "или", "исключающее_или"): diff --git a/kvs_verify.py b/kvs_verify.py new file mode 100644 index 0000000..0bbc28b --- /dev/null +++ b/kvs_verify.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Верификатор КВС +Сравнивает размеры инструкций из pass1 с реальными размерами из CSV. +Выводит расхождения и останавливает сборку при ошибках. +""" + +import sys + +# Если True — разрешает сборку, когда единственная ошибка это общий размер .text +# (расхождение до 16 байт считается допустимым) +ALLOW_TEXT_SIZE_MISMATCH = True +MAX_TEXT_SIZE_MISMATCH = 25 + + +def read_pass1(input_file): + """Читает pass1-файл: PARAM и LABEL""" + params = {} + labels = {} + label_sections = {} + + with open(input_file, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line: + continue + parts = line.split(':') + if parts[0] == "PARAM": + key = parts[1] + value = parts[2] + if value.isdigit() or (value.startswith('-') and value[1:].isdigit()): + value = int(value) + params[key] = value + elif parts[0] == "LABEL": + label = parts[1] + sec = parts[2] + pos = int(parts[3]) + labels[label] = pos + label_sections[label] = sec + + return params, labels, label_sections + + +def read_csv(input_file): + """ + Читает CSV-файл. + Возвращает: + - instr_list: список инструкций с адресами и размерами + """ + instr_list = [] + current_cmd = None + current_start = None + current_size = 0 + + with open(input_file, 'r', encoding='utf-8') as f: + header = f.readline() + for line in f: + line = line.strip() + if not line: + continue + parts = line.split(';') + if len(parts) < 2: + continue + + addr_str = parts[0] + byte_str = parts[1] + cmd_str = parts[3] if len(parts) > 3 else "" + + try: + addr = int(addr_str, 16) + except ValueError: + continue + + if addr >= 0x402000: + break + + if cmd_str: + if current_cmd is not None: + instr_list.append({ + 'cmd': current_cmd, + 'start': current_start, + 'size': current_size + }) + current_cmd = cmd_str + current_start = addr + current_size = 1 + else: + current_size += 1 + + if current_cmd is not None: + instr_list.append({ + 'cmd': current_cmd, + 'start': current_start, + 'size': current_size + }) + + return instr_list + + +def verify(pass1_file, csv_file): + """Сравнивает pass1 и pass2, возвращает список ошибок""" + from kvs_data import FIXED_SIZE_INSTRUCTIONS, INSTRUCTIONS + + params, labels, label_sections = read_pass1(pass1_file) + instr_list = read_csv(csv_file) + + vaddr_text = params.get("vaddr_text", 0x401000) + text_size_pass1 = params.get("text_size", 0) + text_size_pass2 = sum(instr['size'] for instr in instr_list) + + errors = [] + warnings = [] + + print(f"Pass1 .text: {text_size_pass1} байт") + print(f"Pass2 .text: {text_size_pass2} байт") + print() + + # Проверка общего размера + text_size_error = None + if text_size_pass1 != text_size_pass2: + diff = text_size_pass2 - text_size_pass1 + text_size_error = f"Общий размер .text: pass1={text_size_pass1}, pass2={text_size_pass2} (разница {diff:+d} байт)" + if ALLOW_TEXT_SIZE_MISMATCH and abs(diff) <= MAX_TEXT_SIZE_MISMATCH: + warnings.append(text_size_error + " — допустимо, сборка продолжена") + else: + errors.append(text_size_error) + + # Проверка позиций меток + print("Проверка позиций меток (.text):") + for label, pass1_offset in labels.items(): + if label_sections.get(label) != ".text": + continue + + pass1_addr = vaddr_text + pass1_offset + + found = False + for instr in instr_list: + if instr['start'] == pass1_addr: + found = True + break + + if found: + print(f" [✓] {label} — 0x{pass1_addr:x}") + else: + closest = None + for instr in instr_list: + if instr['start'] <= pass1_addr: + closest = instr + + if closest: + real_addr = closest['start'] + shift = real_addr - pass1_addr + if shift != 0: + errors.append(f"Метка '{label}': pass1=0x{pass1_addr:x}, pass2=0x{real_addr:x} (сдвиг {shift:+d} байт)") + print(f" [✗] {label} — pass1: 0x{pass1_addr:x}, pass2: 0x{real_addr:x} (сдвиг {shift:+d})") + else: + print(f" [✓] {label} — 0x{pass1_addr:x}") + else: + warnings.append(f"Метка '{label}' не найдена в CSV") + print(f" [?] {label} — не найдена в CSV") + + print() + + # Сравнение размеров инструкций + print("Проверка размеров инструкций:") + + for instr in instr_list: + cmd = instr['cmd'] + real_size = instr['size'] + real_addr = instr['start'] + + mnemonic = cmd.split()[0] if cmd else "" + + if mnemonic in FIXED_SIZE_INSTRUCTIONS: + pass1_size = FIXED_SIZE_INSTRUCTIONS[mnemonic] + elif mnemonic in ("загрузить", "сохранить", "загрузить_адрес"): + if 'MEM:reg_indirect:' in cmd: + pass1_size = 3 + else: + pass1_size = 7 + elif mnemonic in ("втолкнуть", "вытолкнуть"): + parts = cmd.split() + if len(parts) >= 2: + reg = parts[1] + if reg in ('р8', 'р9', 'р10', 'р11', 'р12', 'р13', 'р14', 'р15'): + pass1_size = 2 + else: + pass1_size = 1 + else: + pass1_size = 1 + elif mnemonic in ("прибавить_непосредственно", "вычесть_непосредственно", "сравнить_с"): + pass1_size = 7 + elif mnemonic == "переместить_имм": + pass1_size = 10 + elif mnemonic in ("переместить_с_нулями", "переместить_со_знаком"): + pass1_size = 8 + elif mnemonic == "загрузить_байт": + pass1_size = 2 + elif mnemonic == "втолкнуть_непосредственно": + pass1_size = 5 + else: + instr_info = INSTRUCTIONS.get(mnemonic) + if instr_info and "opcode" in instr_info and instr_info["opcode"] is not None: + pass1_size = len(instr_info["opcode"]) + else: + pass1_size = 3 + + status = "✓" if pass1_size == real_size else "✗" + if pass1_size != real_size: + diff = real_size - pass1_size + errors.append(f"Инструкция '{cmd}' на 0x{real_addr:x}: pass1={pass1_size}, pass2={real_size} (ошибка {diff:+d})") + + print(f" [{status}] 0x{real_addr:x} {cmd} — pass1: {pass1_size}, pass2: {real_size}" + + (f" (ошибка {real_size - pass1_size:+d})" if pass1_size != real_size else "")) + + print() + + return errors, warnings + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Использование: python kvs_verify.py <вход.проход1> <вход.csv>") + sys.exit(1) + + pass1_file = sys.argv[1] + csv_file = sys.argv[2] + + errors, warnings = verify(pass1_file, csv_file) + + if warnings: + print(f"Предупреждений: {len(warnings)}") + for w in warnings: + print(f" ⚠ {w}") + print() + + if errors: + print(f"ОШИБОК: {len(errors)}") + for e in errors: + print(f" ❌ {e}") + print("\nСборка остановлена. Исправьте расхождения в размерах инструкций.") + sys.exit(1) + else: + print("Все размеры инструкций совпадают. Можно собирать.") + sys.exit(0) \ No newline at end of file diff --git a/todo.txt b/todo.txt index e5a69f3..c732fca 100644 --- a/todo.txt +++ b/todo.txt @@ -247,4 +247,7 @@ Pass2 (шаг 5): тестировать все директивы бнд -изучить работу с кучей \ No newline at end of file +изучить работу с кучей + + +сохранить_байт и загрузить_байт_из_памяти есть в INSTRUCTIONS, но не реализованы в диспетчере encode_instruction \ No newline at end of file diff --git a/тесты/itoa0.квс b/тесты/itoa0.квс new file mode 100644 index 0000000..1cf1b8b --- /dev/null +++ b/тесты/itoa0.квс @@ -0,0 +1,67 @@ +.текст +.глобал _start + +_start: + ; Число для преобразования + переместить_имм раикс, 73 + + ; Сохраняем число в .бнд + сохранить [число], раикс + + ; Загружаем обратно + загрузить раикс, [число] + + ; Делим на 10 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс ; rax = 7 (частное), rdx = 3 (остаток) + + ; Сохраняем остаток в .бнд + сохранить [остаток], рдикс + + ; Частное (rax) — в цифру и выводим + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Загружаем остаток из .бнд + загрузить раикс, [остаток] + + ; Остаток — в цифру и выводим + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A + +.бнд +число: + .резб 8 +остаток: + .резб 8 \ No newline at end of file diff --git a/тесты/itoa1.квс b/тесты/itoa1.квс new file mode 100644 index 0000000..3852ef0 --- /dev/null +++ b/тесты/itoa1.квс @@ -0,0 +1,80 @@ +.текст +.глобал _start + +_start: + ; Конвертируем 1034 + переместить_имм раикс, 1034 + + ; 1234 / 10 = 123, остаток 4 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра3], рдикс + + ; 123 / 10 = 12, остаток 3 + переместить_имм рдикс, 0 + разделить рсикс + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра2], рдикс + + ; 12 / 10 = 1, остаток 2 + переместить_имм рдикс, 0 + разделить рсикс + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра1], рдикс + + ; Частное 1 → последняя цифра + прибавить_непосредственно раикс, 0x30 + сохранить [цифра0], раикс + + ; Выводим 4 цифры по одной + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра0 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра1 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра2 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра3 + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +nl: + .байт 0x0A + +.бнд +цифра0: + .резб 8 +цифра1: + .резб 8 +цифра2: + .резб 8 +цифра3: + .резб 8 \ No newline at end of file diff --git a/тесты/itoa2.квс b/тесты/itoa2.квс new file mode 100644 index 0000000..4e98aba --- /dev/null +++ b/тесты/itoa2.квс @@ -0,0 +1,94 @@ +.текст +.глобал _start + +_start: + ; МЕНЯЙ ЧИСЛО: + переместить_имм раикс, 57321 + + ; 1-й разряд (единицы): число / 10 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс ; rax = 5432, rdx = 1 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра4], рдикс + + ; 2-й разряд (десятки): частное / 10 + переместить_имм рдикс, 0 + разделить рсикс ; rax = 543, rdx = 2 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра3], рдикс + + ; 3-й разряд (сотни) + переместить_имм рдикс, 0 + разделить рсикс ; rax = 54, rdx = 3 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра2], рдикс + + ; 4-й разряд (тысячи) + переместить_имм рдикс, 0 + разделить рсикс ; rax = 5, rdx = 4 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра1], рдикс + + ; 5-й разряд (десятки тысяч) + прибавить_непосредственно раикс, 0x30 + сохранить [цифра0], раикс + + ; Выводим 5 цифр по одной + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра0 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра1 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра2 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра3 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра4 + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +nl: + .байт 0x0A + +.бнд +цифра0: + .резб 8 +цифра1: + .резб 8 +цифра2: + .резб 8 +цифра3: + .резб 8 +цифра4: + .резб 8 \ No newline at end of file diff --git a/тесты/itoa3.квс b/тесты/itoa3.квс new file mode 100644 index 0000000..af76610 --- /dev/null +++ b/тесты/itoa3.квс @@ -0,0 +1,94 @@ +.текст +.глобал _start + +_start: + ; МЕНЯЙ ЧИСЛО: + переместить_имм раикс, 59321 + + ; 1-й разряд (единицы): число / 10 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс ; rax = 5432, rdx = 1 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра4], рдикс + + ; 2-й разряд (десятки): частное / 10 + переместить_имм рдикс, 0 + разделить рсикс ; rax = 543, rdx = 2 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра3], рдикс + + ; 3-й разряд (сотни) + переместить_имм рдикс, 0 + разделить рсикс ; rax = 54, rdx = 3 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра2], рдикс + + ; 4-й разряд (тысячи) + переместить_имм рдикс, 0 + разделить рсикс ; rax = 5, rdx = 4 + прибавить_непосредственно рдикс, 0x30 + сохранить [цифра1], рдикс + + ; 5-й разряд (десятки тысяч) + прибавить_непосредственно раикс, 0x30 + сохранить [цифра0], раикс + + ; Выводим 5 цифр по одной + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра0 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра1 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра2 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра3 + переместить_имм рдикс, 1 + вызов_системы + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, цифра4 + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +nl: + .байт 0x0A + +.бнд +цифра0: + .резб 8 +цифра1: + .резб 8 +цифра2: + .резб 8 +цифра3: + .резб 8 +цифра4: + .резб 8 \ No newline at end of file diff --git a/тесты/длина_числа.квс b/тесты/длина_числа.квс new file mode 100644 index 0000000..4a19126 --- /dev/null +++ b/тесты/длина_числа.квс @@ -0,0 +1,73 @@ +.текст +.глобал _start + +_start: + ; Тест: длина числа 1234 + переместить_имм раикс, 1234 + вызвать длина_числа ; rax = количество цифр + + ; Выводим результат как цифру + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +; ============================================= +; длина_числа: количество десятичных цифр в rax +; Вход: rax = число +; Выход: rax = количество цифр (1..20) +; ============================================= +длина_числа: + втолкнуть р8 + втолкнуть р9 + + переместить р8, раикс ; р8 = число + переместить_имм р9, 0 ; счётчик = 0 + + ; Проверка на 0 + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + переместить_имм раикс, 1 ; 0 — это 1 цифра + вытолкнуть р9 + вытолкнуть р8 + вернуться + +длина_цикл: + увеличить р9 ; счётчик++ + + ; Делим на 10 + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс + переместить р8, раикс ; частное + + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + + переместить раикс, р9 ; результат + вытолкнуть р9 + вытолкнуть р8 + вернуться + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A \ No newline at end of file diff --git a/тесты/циклы.квс b/тесты/циклы.квс new file mode 100644 index 0000000..5c08285 --- /dev/null +++ b/тесты/циклы.квс @@ -0,0 +1,27 @@ +.текст +.глобал _start + +_start: + ; Счётчик циклов = 5 + переместить_имм р8, 5 + +цикл: + ; Выводим сообщение + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, msg + переместить_имм рдикс, 21 + вызов_системы + + ; Счётчик-- + уменьшить р8 + сравнить_с р8, 0 + короткий_переход_если_неравно цикл + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +msg: .строка "Привет мир!\n" \ No newline at end of file diff --git a/тесты/циклы2.квс b/тесты/циклы2.квс new file mode 100644 index 0000000..d701bb4 --- /dev/null +++ b/тесты/циклы2.квс @@ -0,0 +1,40 @@ +.текст +.глобал _start + +_start: + переместить_имм р9, 1 ; счётчик = 1 + +цикл: + ; Выводим счётчик как цифру + переместить раикс, р9 + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; Счётчик++ + увеличить р9 + сравнить_с р9, 7 ; до 7 (1..6) + короткий_переход_если_неравно цикл + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A \ No newline at end of file diff --git a/тесты/циклы3.квс b/тесты/циклы3.квс new file mode 100644 index 0000000..cdb9d2a --- /dev/null +++ b/тесты/циклы3.квс @@ -0,0 +1,40 @@ +.текст +.глобал _start + +_start: + переместить_имм р9, 6 ; счётчик = 6 + +цикл: + ; Выводим счётчик как цифру + переместить раикс, р9 + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; Счётчик-- + уменьшить р9 + сравнить_с р9, 0 ; до 0 + короткий_переход_если_неравно цикл + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A \ No newline at end of file diff --git a/тесты/циклы4.квс b/тесты/циклы4.квс new file mode 100644 index 0000000..05ad7bd --- /dev/null +++ b/тесты/циклы4.квс @@ -0,0 +1,45 @@ +.текст +.глобал _start + +_start: + переместить_имм р8, 1 ; число = 1 + +цикл: + ; Выводим число + переместить раикс, р8 + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; Умножаем на 2 + переместить раикс, р8 + переместить_имм р9, 2 + умножить р9 + переместить р8, раикс + + ; Продолжаем пока < 10 + сравнить_с р8, 10 + переход_если_меньше цикл ; длинный переход вместо короткого + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A \ No newline at end of file diff --git a/тесты/циклы5.квс b/тесты/циклы5.квс new file mode 100644 index 0000000..2f914eb --- /dev/null +++ b/тесты/циклы5.квс @@ -0,0 +1,86 @@ +.текст +.глобал _start + +_start: + переместить_имм р8, 2 ; число = 2 + +цикл: + ; Если число < 10 — выводим как есть + сравнить_с р8, 10 + переход_если_больше_или_равно двузначное + + ; Однозначное: просто цифра + переместить раикс, р8 + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + переход продолжение + +двузначное: + ; Делим на 10 + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс ; rax = десятки, rdx = единицы + + ; Сохраняем единицы в .бнд (пока не испортились) + сохранить [остаток], рдикс + + ; Выводим десятки + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Загружаем единицы обратно + загрузить рдикс, [остаток] + + ; Выводим единицы + прибавить_непосредственно рдикс, 0x30 + сохранить [буфер], рдикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + +продолжение: + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; Прибавляем 2 + прибавить_непосредственно р8, 2 + + ; Продолжаем пока <= 99 + сравнить_с р8, 99 + переход_если_меньше цикл + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A + +.бнд +остаток: + .резб 8 \ No newline at end of file diff --git a/тесты/циклы6.квс b/тесты/циклы6.квс new file mode 100644 index 0000000..37c16ab --- /dev/null +++ b/тесты/циклы6.квс @@ -0,0 +1,81 @@ +.текст +.глобал _start + +_start: + ; Тест: выводим длины чисел от 0 до 20 + переместить_имм р8, 0 ; число = 0 + +цикл: + ; Считаем длину числа + переместить раикс, р8 + вызвать длина_числа + + ; Выводим длину как цифру + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; Число++ + увеличить р8 + сравнить_с р8, 21 ; 0..20 + переход_если_меньше цикл + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +; ============================================= +; длина_числа: количество десятичных цифр в rax +; Вход: rax = число +; Выход: rax = количество цифр +; ============================================= +длина_числа: + втолкнуть р8 + втолкнуть р9 + + переместить р8, раикс ; р8 = число + переместить_имм р9, 0 ; счётчик = 0 + + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + + переместить_имм раикс, 1 ; 0 = 1 цифра + вытолкнуть р9 + вытолкнуть р8 + вернуться + +длина_цикл: + увеличить р9 + + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс + переместить р8, раикс + + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + + переместить раикс, р9 + вытолкнуть р9 + вытолкнуть р8 + вернуться + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A \ No newline at end of file diff --git a/тесты/циклы7.квс b/тесты/циклы7.квс new file mode 100644 index 0000000..e3a5294 --- /dev/null +++ b/тесты/циклы7.квс @@ -0,0 +1,138 @@ +.текст +.глобал _start + +_start: + переместить_имм р8, 0 ; число = 0 + +цикл: + ; Выводим число (костыльно: до 99) + сравнить_с р8, 10 + переход_если_больше_или_равно двузначное + + ; Однозначное + переместить раикс, р8 + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + переход показать_длину + +двузначное: + ; Делим на 10 + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс + + сохранить [остаток], рдикс + + ; Десятки + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Единицы + загрузить рдикс, [остаток] + прибавить_непосредственно рдикс, 0x30 + сохранить [буфер], рдикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + +показать_длину: + ; Разделитель: " -> " + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, стрелка + переместить_имм рдикс, 4 + вызов_системы + + ; Длина числа + переместить раикс, р8 + вызвать длина_числа + + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; Число++ + увеличить р8 + сравнить_с р8, 9199 + переход_если_меньше цикл + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +; ============================================= +; длина_числа +; ============================================= +длина_числа: + втолкнуть р8 + втолкнуть р9 + + переместить р8, раикс + переместить_имм р9, 0 + + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + + переместить_имм раикс, 1 + вытолкнуть р9 + вытолкнуть р8 + вернуться + +длина_цикл: + увеличить р9 + + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс + переместить р8, раикс + + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + + переместить раикс, р9 + вытолкнуть р9 + вытолкнуть р8 + вернуться + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +стрелка: + .строка " -> " +nl: + .байт 0x0A + +.бнд +остаток: + .резб 8 \ No newline at end of file diff --git a/тесты/циклы8.квс b/тесты/циклы8.квс new file mode 100644 index 0000000..ff1b420 --- /dev/null +++ b/тесты/циклы8.квс @@ -0,0 +1,180 @@ +.текст +.глобал _start + +_start: + ; МЕНЯЙ ЧИСЛО ЗДЕСЬ: + переместить_имм р8, 456777 + + ; Выводим число через itoa3 (до 999!) + переместить раикс, р8 + переместить_имм рдиай, буфер + вызвать itoa3 + + загрузить рсиай, [указатель] + загрузить рдикс, [длина] + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + + ; " -> " + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, стрелка + переместить_имм рдикс, 4 + вызов_системы + + ; Длина числа + переместить раикс, р8 + вызвать длина_числа + + ; Выводим длину + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +; ============================================= +; itoa3 — работает для чисел до 999 +; ============================================= +itoa3: + втолкнуть рбикс + втолкнуть р8 + втолкнуть р9 + + переместить рбикс, рдиай + переместить р8, раикс + + сравнить_с р8, 10 + переход_если_меньше одна_цифра + сравнить_с р8, 100 + переход_если_меньше две_цифры + + ; Три цифры + прибавить_непосредственно рбикс, 3 + + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм р9, 10 + разделить р9 + прибавить_непосредственно рдикс, 0x30 + уменьшить рбикс + сохранить [рбикс], рдикс + + переместить р8, раикс + переместить раикс, р8 + переместить_имм рдикс, 0 + разделить р9 + прибавить_непосредственно рдикс, 0x30 + уменьшить рбикс + сохранить [рбикс], рдикс + + прибавить_непосредственно раикс, 0x30 + уменьшить рбикс + сохранить [рбикс], раикс + + сохранить [указатель], рбикс + переместить_имм раикс, 3 + сохранить [длина], раикс + вытолкнуть р9 + вытолкнуть р8 + вытолкнуть рбикс + вернуться + +две_цифры: + прибавить_непосредственно рбикс, 2 + + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм р9, 10 + разделить р9 + прибавить_непосредственно рдикс, 0x30 + уменьшить рбикс + сохранить [рбикс], рдикс + + прибавить_непосредственно раикс, 0x30 + уменьшить рбикс + сохранить [рбикс], раикс + + сохранить [указатель], рбикс + переместить_имм раикс, 2 + сохранить [длина], раикс + вытолкнуть р9 + вытолкнуть р8 + вытолкнуть рбикс + вернуться + +одна_цифра: + прибавить_непосредственно раикс, 0x30 + сохранить [рбикс], раикс + сохранить [указатель], рбикс + переместить_имм раикс, 1 + сохранить [длина], раикс + вытолкнуть р9 + вытолкнуть р8 + вытолкнуть рбикс + вернуться + +; ============================================= +; длина_числа +; ============================================= +длина_числа: + втолкнуть р8 + втолкнуть р9 + + переместить р8, раикс + переместить_имм р9, 0 + + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + + переместить_имм раикс, 1 + вытолкнуть р9 + вытолкнуть р8 + вернуться + +длина_цикл: + увеличить р9 + + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс + переместить р8, раикс + + сравнить_с р8, 0 + короткий_переход_если_неравно длина_цикл + + переместить раикс, р9 + вытолкнуть р9 + вытолкнуть р8 + вернуться + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +стрелка: + .строка " -> " +nl: + .байт 0x0A + +.бнд +указатель: + .резб 8 +длина: + .резб 8 \ No newline at end of file diff --git a/тесты/циклы9.квс b/тесты/циклы9.квс new file mode 100644 index 0000000..3659e32 --- /dev/null +++ b/тесты/циклы9.квс @@ -0,0 +1,77 @@ +.текст +.глобал _start + +_start: + ; МЕНЯЙ ЧИСЛО: + переместить_имм р8, 750 + + ; Выводим число (костыльно: делим на 100, потом на 10) + сравнить_с р8, 100 + переход_если_меньше меньше_100 + + ; >= 100: делим на 100 + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 100 + разделить рсикс ; rax = сотни, rdx = остаток + + ; Выводим сотни + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Остаток — продолжаем + переместить р8, рдикс + +меньше_100: + ; Делим на 10 + сравнить_с р8, 10 + переход_если_меньше меньше_10 + + переместить раикс, р8 + переместить_имм рдикс, 0 + переместить_имм рсикс, 10 + разделить рсикс + + ; Выводим десятки + прибавить_непосредственно раикс, 0x30 + сохранить [буфер], раикс + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + переместить р8, рдикс + +меньше_10: + ; Выводим единицы + прибавить_непосредственно р8, 0x30 + сохранить [буфер], р8 + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, буфер + переместить_имм рдикс, 1 + вызов_системы + + ; Перевод строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, nl + переместить_имм рдикс, 1 + вызов_системы + + ; exit(0) + переместить_имм раикс, 60 + переместить_имм рдиай, 0 + вызов_системы + +.данные +буфер: + .байт 0, 0, 0, 0, 0, 0, 0, 0 +nl: + .байт 0x0A \ No newline at end of file