ремонт регистров р9 - р11
This commit is contained in:
parent
50d9a5b7be
commit
ce1800f236
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
.gigacode
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
|
@ -186,44 +186,92 @@ def encode_mov_mem_reg_absolute(reg_info, mem_info, current_pos, vaddr_text):
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
|
||||||
def encode_mov_reg_mem_indirect(reg_info, base_reg):
|
def encode_mov_reg_mem_indirect(reg_info: dict, base_reg: str) -> bytearray:
|
||||||
"""
|
"""
|
||||||
Кодирует MOV reg, [base_reg] — косвенная адресация.
|
Кодирует MOV reg, [base_reg] — косвенная адресация через регистр.
|
||||||
Пример: mov rax, [rbx] → 48 8B 03
|
|
||||||
|
|
||||||
Аргументы:
|
|
||||||
- reg_info: словарь от get_reg_info() с ключами 'index' (int) и 'size' (int)
|
|
||||||
- base_reg: строка с именем регистра, например 'рбикс'
|
|
||||||
|
|
||||||
REGISTERS[base_reg] возвращает число-индекс (int), НЕ словарь.
|
|
||||||
"""
|
"""
|
||||||
code = bytearray()
|
code = bytearray()
|
||||||
reg = reg_info['index']
|
|
||||||
base = REGISTERS[base_reg] # REGISTERS возвращает int (индекс регистра)
|
|
||||||
|
|
||||||
rex = 0x48 if reg_info['size'] == 64 else 0x40
|
# === 1. Получаем индексы регистров ===
|
||||||
if reg >= 8:
|
reg_index = reg_info['index']
|
||||||
rex |= 0x04 # REX.R
|
reg_size = reg_info['size']
|
||||||
if base >= 8:
|
|
||||||
rex |= 0x01 # REX.B
|
|
||||||
code.append(rex)
|
|
||||||
code.append(0x8B) # MOV r64, r/m64
|
|
||||||
|
|
||||||
# Особый случай: [rbp] или [r13] требует disp8=0 при mod=00
|
if base_reg not in REGISTERS:
|
||||||
# (mod=00 с r/m=101 означает RIP-relative, а не [rbp])
|
raise ValueError(f"Неизвестный базовый регистр: {base_reg}")
|
||||||
if (base & 7) == 5:
|
base_index = REGISTERS[base_reg]
|
||||||
# mod=01 (disp8), reg, r/m=5
|
|
||||||
modrm = 0x40 | ((reg & 7) << 3) | 5
|
# === 2. Выбираем opcode и префиксы ===
|
||||||
code.append(modrm)
|
#
|
||||||
code.append(0x00) # disp8 = 0
|
# В x86-64 для MOV существуют разные opcodes:
|
||||||
|
# - 8A /r — MOV r8, r/m8 (только 8-бит!)
|
||||||
|
# - 8B /r — MOV r16/r32/r64, r/m16/r/m32/r/m64
|
||||||
|
#
|
||||||
|
# Для 16-бит нужен префикс 0x66
|
||||||
|
# Для 64-бит нужен REX.W (бит 3 в REX)
|
||||||
|
#
|
||||||
|
if reg_size == 8:
|
||||||
|
opcode = 0x8A # MOV r8, r/m8
|
||||||
|
rex_base = 0x40 # Без REX.W
|
||||||
|
need_prefix_66 = False
|
||||||
|
elif reg_size == 16:
|
||||||
|
opcode = 0x8B # MOV r16, r/m16
|
||||||
|
rex_base = 0x40 # Без REX.W
|
||||||
|
need_prefix_66 = True # ← ВАЖНО: префикс 0x66 для 16-бит!
|
||||||
|
elif reg_size == 32:
|
||||||
|
opcode = 0x8B # MOV r32, r/m32
|
||||||
|
rex_base = 0x40 # Без REX.W
|
||||||
|
need_prefix_66 = False
|
||||||
|
elif reg_size == 64:
|
||||||
|
opcode = 0x8B # MOV r64, r/m64
|
||||||
|
rex_base = 0x48 # С REX.W (бит 3 = 1)
|
||||||
|
need_prefix_66 = False
|
||||||
else:
|
else:
|
||||||
# mod=00, reg, r/m=base
|
raise ValueError(f"Неподдерживаемый размер регистра: {reg_size} бит")
|
||||||
modrm = ((reg & 7) << 3) | (base & 7)
|
|
||||||
code.append(modrm)
|
# === 3. Формируем REX-префикс ===
|
||||||
|
rex = rex_base
|
||||||
|
|
||||||
|
# REX.R: для регистра-источника (reg) — нужен если индекс >= 8
|
||||||
|
if reg_index >= 8:
|
||||||
|
rex |= 0x04 # REX.R = 1
|
||||||
|
|
||||||
|
# REX.B: для базового регистра (base) — нужен если индекс >= 8
|
||||||
|
if base_index >= 8:
|
||||||
|
rex |= 0x01 # REX.B = 1
|
||||||
|
|
||||||
|
# === 4. Формируем ModR/M байт ===
|
||||||
|
if (base_index & 7) == 5:
|
||||||
|
# [rbp] или [r13] требуют disp8=0
|
||||||
|
modrm = 0x40 | ((reg_index & 7) << 3) | 5
|
||||||
|
modrm_byte = modrm
|
||||||
|
disp8 = 0x00
|
||||||
|
else:
|
||||||
|
modrm = ((reg_index & 7) << 3) | (base_index & 7)
|
||||||
|
modrm_byte = modrm
|
||||||
|
disp8 = None
|
||||||
|
|
||||||
|
# === 5. Собираем инструкцию ===
|
||||||
|
|
||||||
|
# 5a. Префикс 0x66 для 16-битных операндов (ДО REX!)
|
||||||
|
if need_prefix_66:
|
||||||
|
code.append(0x66)
|
||||||
|
|
||||||
|
# 5b. REX-префикс (если не равен 0x40)
|
||||||
|
if rex != 0x40:
|
||||||
|
code.append(rex)
|
||||||
|
|
||||||
|
# 5c. Opcode
|
||||||
|
code.append(opcode)
|
||||||
|
|
||||||
|
# 5d. ModR/M байт
|
||||||
|
code.append(modrm_byte)
|
||||||
|
|
||||||
|
# 5e. Disp8 (если есть)
|
||||||
|
if disp8 is not None:
|
||||||
|
code.append(disp8)
|
||||||
|
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
|
||||||
def encode_mov_mem_reg_indirect(base_reg, reg_info):
|
def encode_mov_mem_reg_indirect(base_reg, reg_info):
|
||||||
"""
|
"""
|
||||||
Кодирует MOV [base_reg], reg — косвенная адресация.
|
Кодирует MOV [base_reg], reg — косвенная адресация.
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,7 @@
|
||||||
1;тест_бнд_3;Проверка BSS: смешанная адресация (абсолютная запись + косвенное чтение)
|
1;тест_бнд_3;Проверка BSS: смешанная адресация (абсолютная запись + косвенное чтение)
|
||||||
1;сложение;Тест сложения 40+2=42 (проверка через код возврата)
|
1;сложение;Тест сложения 40+2=42 (проверка через код возврата)
|
||||||
0;сложение+;Тест сложения 40+2=42 (проверка через код возврата+)
|
0;сложение+;Тест сложения 40+2=42 (проверка через код возврата+)
|
||||||
1;вычитание;Тест вычитания 50-8=42
|
1;вычитание;Тест вычитания 50-8=42
|
||||||
|
1;тест_адресации_р9;Проверка косвенной адресации через R9 (ASCII код первого символа аргумента)
|
||||||
|
1;тест_адресации_р10;Проверка косвенной адресации через R10 (ASCII код первого символа аргумента)
|
||||||
|
1;тест_адресации_р11;Проверка косвенной адресации через R11 (ASCII код первого символа аргумента)
|
||||||
|
Can't render this file because it contains an unexpected character in line 2 and column 46.
|
|
|
@ -5,7 +5,7 @@ import csv
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Диспетчер лежит в тесты/kvs_full_test.py
|
# Диспетчер лежит в тесты/прогон_тестов.py
|
||||||
# Значит, корень с табличкой — та же папка (тесты/)
|
# Значит, корень с табличкой — та же папка (тесты/)
|
||||||
tests_dir = Path(__file__).parent
|
tests_dir = Path(__file__).parent
|
||||||
csv_file = tests_dir / "kvs_full_test.csv"
|
csv_file = tests_dir / "kvs_full_test.csv"
|
||||||
|
|
|
||||||
140
тесты/тест_адресации_р10/тест_адресации_р10.py
Normal file
140
тесты/тест_адресации_р10/тест_адресации_р10.py
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Тест для проверки косвенной адресации через регистр R10
|
||||||
|
Запускает скомпилированную программу с различными аргументами
|
||||||
|
и проверяет код возврата (должен быть равен ASCII коду первого символа)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Определяем пути
|
||||||
|
SCRIPT_DIR = Path(__file__).parent.absolute()
|
||||||
|
PROJECT_ROOT = SCRIPT_DIR.parent.parent
|
||||||
|
SOURCE_REL = SCRIPT_DIR / "тест_адресации_р10.квс"
|
||||||
|
|
||||||
|
def clean():
|
||||||
|
"""Очищает артефакты сборки"""
|
||||||
|
files = [
|
||||||
|
"тест_адресации_р10.elf",
|
||||||
|
"тест_адресации_р10.csv",
|
||||||
|
"тест_адресации_р10.аст",
|
||||||
|
"тест_адресации_р10.токены",
|
||||||
|
"тест_адресации_р10.константа",
|
||||||
|
"тест_адресации_р10_pass4.log"
|
||||||
|
]
|
||||||
|
for f in files:
|
||||||
|
f_path = SCRIPT_DIR / f
|
||||||
|
if f_path.exists():
|
||||||
|
f_path.unlink()
|
||||||
|
print(f"DEBUG: Удалён {f}", file=sys.stderr)
|
||||||
|
|
||||||
|
def build() -> bool:
|
||||||
|
"""
|
||||||
|
Собирает тестовую программу с помощью КВС
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True если сборка успешна, иначе False
|
||||||
|
"""
|
||||||
|
print(f"DEBUG: Сборка {SOURCE_REL}", file=sys.stderr)
|
||||||
|
os.chdir(PROJECT_ROOT)
|
||||||
|
|
||||||
|
build = subprocess.run(
|
||||||
|
["python3", "квс_сборка.py", str(SOURCE_REL)],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if build.returncode != 0:
|
||||||
|
print(f"❌ Ошибка сборки: {build.returncode}", file=sys.stderr)
|
||||||
|
print(build.stderr, file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("DEBUG: Сборка успешна", file=sys.stderr)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_with_char(char: str, expected_code: int) -> bool:
|
||||||
|
"""
|
||||||
|
Запускает скомпилированную программу с одним символом в качестве аргумента
|
||||||
|
и проверяет код возврата
|
||||||
|
|
||||||
|
Args:
|
||||||
|
char: символ для передачи в программу
|
||||||
|
expected_code: ожидаемый ASCII код символа
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True если код возврата совпадает с ожидаемым, иначе False
|
||||||
|
"""
|
||||||
|
print(f"DEBUG: Тест с символом '{char}' (ожидается код {expected_code})", file=sys.stderr)
|
||||||
|
os.chdir(SCRIPT_DIR)
|
||||||
|
|
||||||
|
elf_path = SCRIPT_DIR / "тест_адресации_р10.elf"
|
||||||
|
if not elf_path.exists():
|
||||||
|
print("❌ ELF файл не найден", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Запускаем программу с аргументом
|
||||||
|
run = subprocess.run(
|
||||||
|
[str(elf_path), char],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Проверяем код возврата (должен быть ASCII код символа)
|
||||||
|
if run.returncode != expected_code:
|
||||||
|
print(f"❌ Код возврата: ожидался {expected_code}, получен {run.returncode}", file=sys.stderr)
|
||||||
|
if run.stderr:
|
||||||
|
print(f" stderr: {run.stderr}", file=sys.stderr)
|
||||||
|
if run.stdout:
|
||||||
|
print(f" stdout: {run.stdout}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"DEBUG: Тест с символом '{char}' пройден (код {run.returncode})", file=sys.stderr)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Главная функция теста"""
|
||||||
|
print("DEBUG: Начало теста тест_адресации_р10", file=sys.stderr)
|
||||||
|
|
||||||
|
# Собираем программу
|
||||||
|
if not build():
|
||||||
|
clean()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Тестируем разные символы
|
||||||
|
tests = [
|
||||||
|
('A', 65), # Латинская A
|
||||||
|
('B', 66), # Латинская B
|
||||||
|
('0', 48), # Цифра 0
|
||||||
|
('z', 122), # Латинская z
|
||||||
|
('!', 33), # Восклицательный знак
|
||||||
|
('x', 120), # Латинская x
|
||||||
|
('5', 53), # Цифра 5
|
||||||
|
('_', 95), # Подчёркивание
|
||||||
|
('$', 36), # Знак доллара
|
||||||
|
('@', 64), # Собака
|
||||||
|
]
|
||||||
|
|
||||||
|
all_passed = True
|
||||||
|
|
||||||
|
for char, expected_code in tests:
|
||||||
|
if not test_with_char(char, expected_code):
|
||||||
|
all_passed = False
|
||||||
|
break
|
||||||
|
|
||||||
|
# Очищаем артефакты
|
||||||
|
clean()
|
||||||
|
|
||||||
|
if all_passed:
|
||||||
|
print("✅ Все тесты пройдены!", file=sys.stderr)
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("❌ Тест провален", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
29
тесты/тест_адресации_р10/тест_адресации_р10.квс
Normal file
29
тесты/тест_адресации_р10/тест_адресации_р10.квс
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
;./тесты/тест_адресации_р10.elf "A"
|
||||||
|
;echo $? # должен быть 65
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; тест_адресации_r10.квс - тест косвенной адресации через R10
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
.текст
|
||||||
|
.глобал _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
; Получаем argv[1]
|
||||||
|
вытолкнуть рсикс ; argc
|
||||||
|
вытолкнуть рсиай ; argv[0]
|
||||||
|
вытолкнуть р10 ; argv[1] в R10
|
||||||
|
|
||||||
|
; Загружаем первый байт из argv[1] через R10
|
||||||
|
загрузить ал, [р10]
|
||||||
|
|
||||||
|
; Сохраняем в переменную (не обязательно, но для проверки)
|
||||||
|
сохранить [байт], ал
|
||||||
|
|
||||||
|
; Выход с кодом = загруженный байт
|
||||||
|
переместить_имм раикс, 60
|
||||||
|
загрузить рдиай, [байт]
|
||||||
|
вызов_системы
|
||||||
|
|
||||||
|
.данные
|
||||||
|
байт: .байт 0
|
||||||
142
тесты/тест_адресации_р11/тест_адресации_р11.py
Normal file
142
тесты/тест_адресации_р11/тест_адресации_р11.py
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Тест для проверки косвенной адресации через регистр R11
|
||||||
|
Запускает скомпилированную программу с различными аргументами
|
||||||
|
и проверяет код возврата (должен быть равен ASCII коду первого символа)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Определяем пути
|
||||||
|
SCRIPT_DIR = Path(__file__).parent.absolute()
|
||||||
|
PROJECT_ROOT = SCRIPT_DIR.parent.parent
|
||||||
|
SOURCE_REL = SCRIPT_DIR / "тест_адресации_р11.квс"
|
||||||
|
|
||||||
|
def clean():
|
||||||
|
"""Очищает артефакты сборки"""
|
||||||
|
files = [
|
||||||
|
"тест_адресации_р11.elf",
|
||||||
|
"тест_адресации_р11.csv",
|
||||||
|
"тест_адресации_р11.аст",
|
||||||
|
"тест_адресации_р11.токены",
|
||||||
|
"тест_адресации_р11.константа",
|
||||||
|
"тест_адресации_р11_pass4.log"
|
||||||
|
]
|
||||||
|
for f in files:
|
||||||
|
f_path = SCRIPT_DIR / f
|
||||||
|
if f_path.exists():
|
||||||
|
f_path.unlink()
|
||||||
|
print(f"DEBUG: Удалён {f}", file=sys.stderr)
|
||||||
|
|
||||||
|
def build() -> bool:
|
||||||
|
"""
|
||||||
|
Собирает тестовую программу с помощью КВС
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True если сборка успешна, иначе False
|
||||||
|
"""
|
||||||
|
print(f"DEBUG: Сборка {SOURCE_REL}", file=sys.stderr)
|
||||||
|
os.chdir(PROJECT_ROOT)
|
||||||
|
|
||||||
|
build = subprocess.run(
|
||||||
|
["python3", "квс_сборка.py", str(SOURCE_REL)],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if build.returncode != 0:
|
||||||
|
print(f"❌ Ошибка сборки: {build.returncode}", file=sys.stderr)
|
||||||
|
print(build.stderr, file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("DEBUG: Сборка успешна", file=sys.stderr)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_with_char(char: str, expected_code: int) -> bool:
|
||||||
|
"""
|
||||||
|
Запускает скомпилированную программу с одним символом в качестве аргумента
|
||||||
|
и проверяет код возврата
|
||||||
|
|
||||||
|
Args:
|
||||||
|
char: символ для передачи в программу
|
||||||
|
expected_code: ожидаемый ASCII код символа
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True если код возврата совпадает с ожидаемым, иначе False
|
||||||
|
"""
|
||||||
|
print(f"DEBUG: Тест с символом '{char}' (ожидается код {expected_code})", file=sys.stderr)
|
||||||
|
os.chdir(SCRIPT_DIR)
|
||||||
|
|
||||||
|
elf_path = SCRIPT_DIR / "тест_адресации_р11.elf"
|
||||||
|
if not elf_path.exists():
|
||||||
|
print("❌ ELF файл не найден", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Запускаем программу с аргументом
|
||||||
|
run = subprocess.run(
|
||||||
|
[str(elf_path), char],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Проверяем код возврата (должен быть ASCII код символа)
|
||||||
|
if run.returncode != expected_code:
|
||||||
|
print(f"❌ Код возврата: ожидался {expected_code}, получен {run.returncode}", file=sys.stderr)
|
||||||
|
if run.stderr:
|
||||||
|
print(f" stderr: {run.stderr}", file=sys.stderr)
|
||||||
|
if run.stdout:
|
||||||
|
print(f" stdout: {run.stdout}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"DEBUG: Тест с символом '{char}' пройден (код {run.returncode})", file=sys.stderr)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Главная функция теста"""
|
||||||
|
print("DEBUG: Начало теста тест_адресации_р11", file=sys.stderr)
|
||||||
|
|
||||||
|
# Собираем программу
|
||||||
|
if not build():
|
||||||
|
clean()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Тестируем разные символы
|
||||||
|
tests = [
|
||||||
|
('A', 65), # Латинская A
|
||||||
|
('B', 66), # Латинская B
|
||||||
|
('0', 48), # Цифра 0
|
||||||
|
('z', 122), # Латинская z
|
||||||
|
('!', 33), # Восклицательный знак
|
||||||
|
('x', 120), # Латинская x
|
||||||
|
('5', 53), # Цифра 5
|
||||||
|
('_', 95), # Подчёркивание
|
||||||
|
('$', 36), # Знак доллара
|
||||||
|
('@', 64), # Собака
|
||||||
|
('#', 35), # Решётка
|
||||||
|
('*', 42), # Звёздочка
|
||||||
|
]
|
||||||
|
|
||||||
|
all_passed = True
|
||||||
|
|
||||||
|
for char, expected_code in tests:
|
||||||
|
if not test_with_char(char, expected_code):
|
||||||
|
all_passed = False
|
||||||
|
break
|
||||||
|
|
||||||
|
# Очищаем артефакты
|
||||||
|
clean()
|
||||||
|
|
||||||
|
if all_passed:
|
||||||
|
print("✅ Все тесты пройдены!", file=sys.stderr)
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("❌ Тест провален", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
29
тесты/тест_адресации_р11/тест_адресации_р11.квс
Normal file
29
тесты/тест_адресации_р11/тест_адресации_р11.квс
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
;./тесты/тест_адресации_р11.elf "A"
|
||||||
|
;echo $? # должен быть 65
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; тест_адресации_r11.квс - тест косвенной адресации через R11
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
.текст
|
||||||
|
.глобал _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
; Получаем argv[1]
|
||||||
|
вытолкнуть рсикс ; argc
|
||||||
|
вытолкнуть рсиай ; argv[0]
|
||||||
|
вытолкнуть р11 ; argv[1] в R11
|
||||||
|
|
||||||
|
; Загружаем первый байт из argv[1] через R11
|
||||||
|
загрузить ал, [р11]
|
||||||
|
|
||||||
|
; Сохраняем в переменную (не обязательно, но для проверки)
|
||||||
|
сохранить [байт], ал
|
||||||
|
|
||||||
|
; Выход с кодом = загруженный байт
|
||||||
|
переместить_имм раикс, 60
|
||||||
|
загрузить рдиай, [байт]
|
||||||
|
вызов_системы
|
||||||
|
|
||||||
|
.данные
|
||||||
|
байт: .байт 0
|
||||||
138
тесты/тест_адресации_р9/тест_адресации_р9.py
Normal file
138
тесты/тест_адресации_р9/тест_адресации_р9.py
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Тест для проверки косвенной адресации через регистр R9
|
||||||
|
Запускает скомпилированную программу с различными аргументами
|
||||||
|
и проверяет код возврата (должен быть равен ASCII коду первого символа)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Определяем пути
|
||||||
|
SCRIPT_DIR = Path(__file__).parent.absolute()
|
||||||
|
PROJECT_ROOT = SCRIPT_DIR.parent.parent
|
||||||
|
SOURCE_REL = SCRIPT_DIR / "тест_адресации_р9.квс"
|
||||||
|
|
||||||
|
def clean():
|
||||||
|
"""Очищает артефакты сборки"""
|
||||||
|
files = [
|
||||||
|
"тест_адресации_р9.elf",
|
||||||
|
"тест_адресации_р9.csv",
|
||||||
|
"тест_адресации_р9.аст",
|
||||||
|
"тест_адресации_р9.токены",
|
||||||
|
"тест_адресации_р9.константа",
|
||||||
|
"тест_адресации_р9_pass4.log"
|
||||||
|
]
|
||||||
|
for f in files:
|
||||||
|
f_path = SCRIPT_DIR / f
|
||||||
|
if f_path.exists():
|
||||||
|
f_path.unlink()
|
||||||
|
print(f"DEBUG: Удалён {f}", file=sys.stderr)
|
||||||
|
|
||||||
|
def build() -> bool:
|
||||||
|
"""
|
||||||
|
Собирает тестовую программу с помощью КВС
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True если сборка успешна, иначе False
|
||||||
|
"""
|
||||||
|
print(f"DEBUG: Сборка {SOURCE_REL}", file=sys.stderr)
|
||||||
|
os.chdir(PROJECT_ROOT)
|
||||||
|
|
||||||
|
build = subprocess.run(
|
||||||
|
["python3", "квс_сборка.py", str(SOURCE_REL)],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if build.returncode != 0:
|
||||||
|
print(f"❌ Ошибка сборки: {build.returncode}", file=sys.stderr)
|
||||||
|
print(build.stderr, file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("DEBUG: Сборка успешна", file=sys.stderr)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def test_with_char(char: str, expected_code: int) -> bool:
|
||||||
|
"""
|
||||||
|
Запускает скомпилированную программу с одним символом в качестве аргумента
|
||||||
|
и проверяет код возврата
|
||||||
|
|
||||||
|
Args:
|
||||||
|
char: символ для передачи в программу
|
||||||
|
expected_code: ожидаемый ASCII код символа
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True если код возврата совпадает с ожидаемым, иначе False
|
||||||
|
"""
|
||||||
|
print(f"DEBUG: Тест с символом '{char}' (ожидается код {expected_code})", file=sys.stderr)
|
||||||
|
os.chdir(SCRIPT_DIR)
|
||||||
|
|
||||||
|
elf_path = SCRIPT_DIR / "тест_адресации_р9.elf"
|
||||||
|
if not elf_path.exists():
|
||||||
|
print("❌ ELF файл не найден", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Запускаем программу с аргументом
|
||||||
|
run = subprocess.run(
|
||||||
|
[str(elf_path), char],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Проверяем код возврата (должен быть ASCII код символа)
|
||||||
|
if run.returncode != expected_code:
|
||||||
|
print(f"❌ Код возврата: ожидался {expected_code}, получен {run.returncode}", file=sys.stderr)
|
||||||
|
if run.stderr:
|
||||||
|
print(f" stderr: {run.stderr}", file=sys.stderr)
|
||||||
|
if run.stdout:
|
||||||
|
print(f" stdout: {run.stdout}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"DEBUG: Тест с символом '{char}' пройден (код {run.returncode})", file=sys.stderr)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Главная функция теста"""
|
||||||
|
print("DEBUG: Начало теста тест_адресации_р9", file=sys.stderr)
|
||||||
|
|
||||||
|
# Собираем программу
|
||||||
|
if not build():
|
||||||
|
clean()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Тестируем разные символы
|
||||||
|
tests = [
|
||||||
|
('A', 65), # Латинская A
|
||||||
|
('B', 66), # Латинская B
|
||||||
|
('0', 48), # Цифра 0
|
||||||
|
('z', 122), # Латинская z
|
||||||
|
('!', 33), # Восклицательный знак
|
||||||
|
('x', 120), # Латинская x
|
||||||
|
('5', 53), # Цифра 5
|
||||||
|
('_', 95), # Подчёркивание
|
||||||
|
]
|
||||||
|
|
||||||
|
all_passed = True
|
||||||
|
|
||||||
|
for char, expected_code in tests:
|
||||||
|
if not test_with_char(char, expected_code):
|
||||||
|
all_passed = False
|
||||||
|
break
|
||||||
|
|
||||||
|
# Очищаем артефакты
|
||||||
|
clean()
|
||||||
|
|
||||||
|
if all_passed:
|
||||||
|
print("✅ Все тесты пройдены!", file=sys.stderr)
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("❌ Тест провален", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
29
тесты/тест_адресации_р9/тест_адресации_р9.квс
Normal file
29
тесты/тест_адресации_р9/тест_адресации_р9.квс
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
;./тесты/тест_адресации_р9.elf "A"
|
||||||
|
;echo $? # должен быть 65
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; тест_адресации_r9.квс - тест косвенной адресации через R8
|
||||||
|
; ============================================================
|
||||||
|
|
||||||
|
.текст
|
||||||
|
.глобал _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
; Получаем argv[1]
|
||||||
|
вытолкнуть рсикс ; argc
|
||||||
|
вытолкнуть рсиай ; argv[0]
|
||||||
|
вытолкнуть р9 ; argv[1] в R9
|
||||||
|
|
||||||
|
; Загружаем первый байт из argv[1] через R9
|
||||||
|
загрузить ал, [р9]
|
||||||
|
|
||||||
|
; Сохраняем в переменную (не обязательно, но для проверки)
|
||||||
|
сохранить [байт], ал
|
||||||
|
|
||||||
|
; Выход с кодом = загруженный байт
|
||||||
|
переместить_имм раикс, 60
|
||||||
|
загрузить рдиай, [байт]
|
||||||
|
вызов_системы
|
||||||
|
|
||||||
|
.данные
|
||||||
|
байт: .байт 0
|
||||||
Loading…
Reference in a new issue