1043 lines
36 KiB
Markdown
1043 lines
36 KiB
Markdown
# CBE Platform — Полное руководство по созданию плагинов и систем
|
||
|
||
## Содержание
|
||
|
||
1. [Введение](#1-введение)
|
||
2. [Архитектура CBE](#2-архитектура-cbe)
|
||
3. [Формат плагина (.cbeplugin)](#3-формат-плагина-cbeplugin)
|
||
4. [Создание модуля CPU](#4-создание-модуля-cpu)
|
||
5. [Создание модуля RAM](#5-создание-модуля-ram)
|
||
6. [Создание модуля GPU](#6-создание-модуля-gpu)
|
||
7. [Создание модуля KBD (клавиатура)](#7-создание-модуля-kbd)
|
||
8. [Создание модуля SND (звук)](#8-создание-модуля-snd)
|
||
9. [Создание модуля BIOS](#9-создание-модуля-bios)
|
||
10. [Создание модуля DISK](#10-создание-модуля-disk)
|
||
11. [Семантические операции инструкций](#11-семантические-операции)
|
||
12. [Написание программ на ассемблере](#12-написание-программ-на-ассемблере)
|
||
13. [Написание программ на C/C++](#13-написание-программ-на-cc)
|
||
14. [Написание программ на Python](#14-написание-программ-на-python)
|
||
15. [Hex-машинный код](#15-hex-машинный-код)
|
||
16. [Сборка плагинов (cbecc)](#16-сборка-плагинов-cbecc)
|
||
17. [Тулчейн: компиляция из разных языков](#17-тулчейн-компиляция-из-разных-языков)
|
||
18. [Система POST-диагностики](#18-система-post-диагностики)
|
||
19. [Memory-mapped I/O](#19-memory-mapped-io)
|
||
20. [Бесконечные шаги и детектор циклов](#20-бесконечные-шаги-и-детектор-циклов)
|
||
21. [Тёмная тема GUI](#21-тёмная-тема-gui)
|
||
22. [Примеры](#22-примеры)
|
||
23. [Устранение неполадок](#23-устранение-неполадок)
|
||
24. [Справочник команд](#24-справочник-команд)
|
||
|
||
---
|
||
|
||
## 1. Введение
|
||
|
||
**CBE (Create. Build. Execute.)** — платформа для эмуляции и создания собственных компьютерных компонентов: процессоров, оперативной памяти, видеокарт, дисков, BIOS, клавиатур и звуковых карт. Всё это собирается в единую архитектуру и запускается через эмулятор с графическим интерфейсом.
|
||
|
||
Основная идея: вы описываете поведение компонента через JSON-конфигурацию и/или бинарные данные, а платформа предоставляет среду выполнения с:
|
||
|
||
- Эмулятором на Java с GUI (Swing)
|
||
- Компилятором .cbeplugin
|
||
- Тулчейном для ассемблера, C/C++, Python, hex
|
||
- Системой POST-диагностики
|
||
- Детектором бесконечных циклов
|
||
- Тёмной темой
|
||
|
||
### Ключевые концепции
|
||
|
||
- **Plugin** — модуль в формате `.cbeplugin`, содержащий метаданные, инструкции, микрокод и данные
|
||
- **ModuleInstance** — экземпляр загруженного модуля в эмуляторе
|
||
- **Engine** — оркестратор, управляющий всеми модулями и циклом выполнения CPU
|
||
- **Bus** — системная шина, связывающая модули
|
||
- **Registers** — регистры CPU
|
||
- **POST** — Power-On Self-Test, система самодиагностики при старте
|
||
- **Memory-mapped I/O** — регистры ввода-вывода, отображённые на адресное пространство
|
||
|
||
---
|
||
|
||
## 2. Архитектура CBE
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ CBE Emulator │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ ┌───────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
|
||
│ │ CPU │ │ RAM │ │ GPU │ │ KBD │ │
|
||
│ │ (плагин) │ │ (плагин) │ │ (плагин) │ │ (плагин) │ │
|
||
│ └─────┬─────┘ └────┬─────┘ └────┬─────┘ └─────┬─────┘ │
|
||
│ │ │ │ │ │
|
||
│ ┌─────┴──────────────┴─────────────┴───────────────┴─────┐ │
|
||
│ │ System Bus (шина) │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │ │ │ │ │
|
||
│ ┌─────┴─────┐ ┌────┴────┐ ┌─────┴─────┐ ┌──────┴─────┐ │
|
||
│ │ SND/Sound│ │ BIOS │ │ DISK │ │ POST │ │
|
||
│ │ (плагин) │ │ (плагин)│ │ (плагин) │ │ (встроено) │ │
|
||
│ └───────────┘ └─────────┘ └───────────┘ └────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Модули (ModuleType)
|
||
|
||
| Тип | ID | Описание |
|
||
|---------|----|--------------------------------------------------------------|
|
||
| CPU | 0 | Процессор. Определяет регистры, набор инструкций, микрокод |
|
||
| RAM | 1 | Оперативная память с банками данных |
|
||
| DISK | 2 | Диск с секторной адресацией (512 байт/сектор) |
|
||
| GPU | 3 | Видеокарта. 80x25 текстовый режим, VRAM, курсор |
|
||
| BIOS | 4 | BIOS с информацией о системе |
|
||
| KBD | 5 | Клавиатура с буфером клавиш, handshake-протокол |
|
||
| SND | 6 | Звуковая карта (PC Speaker beep) |
|
||
| DATA_ONLY | 7 | Только данные, без логики |
|
||
|
||
### CompileMode
|
||
|
||
| Режим | ID | Описание |
|
||
|------------|----|------------------------------------|
|
||
| FULL | 0 | Только логика (инструкции + микрокод) |
|
||
| HYBRID | 1 | Логика + данные |
|
||
| PACK_ONLY | 2 | Только данные |
|
||
|
||
---
|
||
|
||
## 3. Формат плагина (.cbeplugin)
|
||
|
||
### Структура файла
|
||
|
||
Бинарный формат с little-endian числами:
|
||
|
||
```
|
||
Смещение Размер Поле
|
||
-------- ------ ------------------------------------
|
||
0 8 Магическая строка: "CBE_PLUG\0"
|
||
8 4 Версия (int32 LE)
|
||
12 4 Размер заголовка (int32 LE, всегда 62)
|
||
16 1 ModuleType (byte)
|
||
17 1 CompileMode (byte)
|
||
18 4 Смещение секции метаданных (int32 LE)
|
||
22 4 Длина секции метаданных
|
||
26 4 Смещение таблицы опкодов
|
||
30 4 Длина таблицы опкодов
|
||
34 4 Смещение таблицы микрокода
|
||
38 4 Длина таблицы микрокода
|
||
42 4 Смещение байткода обработчика
|
||
46 4 Длина байткода обработчика
|
||
50 4 Смещение секции данных
|
||
54 4 Длина секции данных
|
||
58 4 CRC32 (покрывает байты 0..57)
|
||
```
|
||
|
||
### Секции после заголовка
|
||
|
||
- **Метаданные:** JSON-строка с name, arch, module_type, version, tdp, frequency
|
||
- **Таблица опкодов:** JSON-массив объектов инструкций
|
||
- **Микрокод:** JSON-объект { command: [byte, ...] }
|
||
- **Байткод обработчика:** зарезервировано (raw bytecode)
|
||
- **Секция данных:** [bank_count:4][bank0_size:4][bank0_data...][bank1_size:4]...
|
||
|
||
---
|
||
|
||
## 4. Создание модуля CPU
|
||
|
||
### Структура директории
|
||
|
||
```
|
||
my-cpu.cpu/
|
||
├── module.json # Метаданные модуля
|
||
├── registers.json # Определения регистров
|
||
├── instructions/ # Определения инструкций
|
||
│ ├── 0x00.json # NOP
|
||
│ ├── 0x01.json # MOV
|
||
│ └── ...
|
||
├── microcode/
|
||
│ └── bus.json # Сигналы шины
|
||
├── roms/
|
||
│ └── boot.bin # Boot ROM (исполняемый код)
|
||
├── banks/ # Банки данных (опционально)
|
||
│ └── bank_0.bin
|
||
├── program.asm # Исходник программы (альтернатива boot.bin)
|
||
├── program.c # Исходник на C
|
||
├── program.py # Исходник на Python
|
||
└── program.hex # Hex-машинный код
|
||
```
|
||
|
||
### module.json
|
||
|
||
```json
|
||
{
|
||
"name": "MyCPU",
|
||
"arch": "my-8bit",
|
||
"module_type": "cpu",
|
||
"version": 1,
|
||
"tdp": 5.0,
|
||
"memory_size": 65536,
|
||
"frequency": 1000000
|
||
}
|
||
```
|
||
|
||
Поля:
|
||
- `name` — название процессора
|
||
- `arch` — архитектура (строка)
|
||
- `module_type` — "cpu"
|
||
- `tdp` — тепловыделение (W)
|
||
- `memory_size` — размер адресного пространства (байт)
|
||
- `frequency` — частота в Hz
|
||
|
||
### registers.json
|
||
|
||
```json
|
||
{
|
||
"a": 0,
|
||
"b": 0,
|
||
"c": 0,
|
||
"d": 0,
|
||
"pc": 0,
|
||
"sp": 0,
|
||
"carry": 0,
|
||
"zero": 0
|
||
}
|
||
```
|
||
|
||
Каждый регистр — ключ с начальным значением. `pc` (program counter) и `sp` (stack pointer) обязательны.
|
||
|
||
### Определение инструкции
|
||
|
||
Файл `instructions/0x00.json`:
|
||
|
||
```json
|
||
{
|
||
"opcode": 0,
|
||
"mnemonic": "NOP",
|
||
"args": [],
|
||
"cycles": 1,
|
||
"semantics": [
|
||
{"op": "nop"}
|
||
]
|
||
}
|
||
```
|
||
|
||
Инструкция с аргументами:
|
||
|
||
```json
|
||
{
|
||
"opcode": 2,
|
||
"mnemonic": "MOV_IMM_A",
|
||
"args": [
|
||
{"name": "value", "type": "imm"}
|
||
],
|
||
"cycles": 2,
|
||
"semantics": [
|
||
{"op": "load_imm", "to": "a", "value": "$next"}
|
||
]
|
||
}
|
||
```
|
||
|
||
- `opcode` — числовой код операции (0-255)
|
||
- `mnemonic` — мнемоника для ассемблера
|
||
- `args` — список аргументов (name + type: "reg", "imm", "address")
|
||
- `cycles` — тактов на выполнение
|
||
- `semantics` — список семантических операций (см. раздел 11)
|
||
|
||
### Микрокод (bus.json)
|
||
|
||
```json
|
||
{
|
||
"memory_read": [0x01, 0x00],
|
||
"memory_write": [0x02, 0x00],
|
||
"io_read": [0x03],
|
||
"io_write": [0x04]
|
||
}
|
||
```
|
||
|
||
Каждый сигнал — имя и массив байт.
|
||
|
||
### Boot ROM
|
||
|
||
Файл `roms/boot.bin` содержит исполняемый код, который загружается в начало адресного пространства CPU при старте. Максимальный размер — 64KB. Можно создать:
|
||
- через ассемблер (program.asm)
|
||
- через компилятор C (program.c)
|
||
- через Python-транслятор (program.py)
|
||
- как hex-дамп (program.hex)
|
||
|
||
---
|
||
|
||
## 5. Создание модуля RAM
|
||
|
||
```
|
||
my-ram.ram/
|
||
├── module.json
|
||
├── banks/
|
||
│ └── bank_0.bin # Начальные данные RAM
|
||
└── controller/ # Опциональный контроллер
|
||
└── microcode/
|
||
└── bus.json
|
||
```
|
||
|
||
### module.json
|
||
|
||
```json
|
||
{
|
||
"name": "MyRAM",
|
||
"arch": "generic-ram",
|
||
"module_type": "ram",
|
||
"version": 1,
|
||
"tdp": 2.0,
|
||
"bank_size": 256,
|
||
"bank_count": 1
|
||
}
|
||
```
|
||
|
||
Поля:
|
||
- `bank_size` — размер банка в байтах
|
||
- `bank_count` — количество банков
|
||
|
||
---
|
||
|
||
## 6. Создание модуля GPU
|
||
|
||
```
|
||
my-gpu.gpu/
|
||
├── module.json
|
||
├── banks/
|
||
│ └── bank_0.bin # VRAM (2000 байт для 80x25)
|
||
└── microcode/
|
||
└── bus.json
|
||
```
|
||
|
||
### module.json
|
||
|
||
```json
|
||
{
|
||
"name": "MyGPU",
|
||
"arch": "vga-text-80x25",
|
||
"module_type": "gpu",
|
||
"version": 1,
|
||
"tdp": 10.0,
|
||
"vram_size": 2000,
|
||
"rows": 25,
|
||
"cols": 80
|
||
}
|
||
```
|
||
|
||
Поля:
|
||
- `vram_size` — размер видеопамяти (80x25 = 2000)
|
||
- `rows` — количество строк
|
||
- `cols` — количество колонок
|
||
|
||
GPU отображается как 80x25 текстовый терминал (а-ля QEMU). Вывод символов осуществляется записью в порт 0xC0.
|
||
|
||
---
|
||
|
||
## 7. Создание модуля KBD
|
||
|
||
```
|
||
my-kbd.kbd/
|
||
└── module.json
|
||
```
|
||
|
||
### module.json
|
||
|
||
```json
|
||
{
|
||
"name": "MyKeyboard",
|
||
"arch": "ps2-like",
|
||
"module_type": "kbd",
|
||
"version": 1,
|
||
"tdp": 0.5,
|
||
"buffer_size": 32
|
||
}
|
||
```
|
||
|
||
Поля:
|
||
- `buffer_size` — размер буфера клавиш
|
||
|
||
Клавиатура работает через memory-mapped I/O:
|
||
- Чтение `0xFB` — данные клавиши (peek, не удаляет)
|
||
- Чтение `0xFA` — статус (0 = нет клавиши, 1 = есть)
|
||
- Запись `0xFA = 0` — acknowledge (удаляет клавишу из буфера)
|
||
|
||
---
|
||
|
||
## 8. Создание модуля SND
|
||
|
||
```
|
||
my-snd.snd/
|
||
└── module.json
|
||
```
|
||
|
||
### module.json
|
||
|
||
```json
|
||
{
|
||
"name": "MySound",
|
||
"arch": "pc-speaker",
|
||
"module_type": "snd",
|
||
"version": 1,
|
||
"tdp": 1.0
|
||
}
|
||
```
|
||
|
||
Любая запись в порт `0xF9` вызывает системный звуковой сигнал (beep). Частота ограничена 10 beep/сек.
|
||
|
||
---
|
||
|
||
## 9. Создание модуля BIOS
|
||
|
||
```
|
||
my-bios.bios/
|
||
└── module.json
|
||
```
|
||
|
||
### module.json
|
||
|
||
```json
|
||
{
|
||
"name": "MyBIOS",
|
||
"arch": "generic-bios",
|
||
"module_type": "bios",
|
||
"version": 1,
|
||
"tdp": 1.0
|
||
}
|
||
```
|
||
|
||
BIOS хранит строку информации о системе, доступную через `engine.getSystemInfo()`. Триггер перезапуска диагностики — запись в порт `0xF7`.
|
||
|
||
---
|
||
|
||
## 10. Создание модуля DISK
|
||
|
||
```
|
||
my-disk.disk/
|
||
├── module.json
|
||
└── banks/
|
||
└── bank_0.bin # Данные диска
|
||
```
|
||
|
||
### module.json
|
||
|
||
```json
|
||
{
|
||
"name": "MyDisk",
|
||
"arch": "ata-like",
|
||
"module_type": "disk",
|
||
"version": 1,
|
||
"tdp": 5.0,
|
||
"sector_size": 512
|
||
}
|
||
```
|
||
|
||
Диск работает через порты:
|
||
- `0xB0` — запись LBA сектора (инициирует чтение)
|
||
- `0xB1` — статус готовности (1 = готов)
|
||
- `0xB2+` — данные сектора (512 байт)
|
||
|
||
Если последние 2 байта сектора 0 равны `0x55 0xAA`, диск считается загрузочным.
|
||
|
||
### Загрузка с диска (Boot flow)
|
||
|
||
При старте эмулятор выполняет POST-диагностику, которая:
|
||
1. Пишет BIOS-программу в память CPU (адреса `0x00..0x15`)
|
||
2. Строит POST-текст и размещает его в буфере display (`0x16+`)
|
||
3. Если диск загрузочный (сектор 0 содержит `0x55 0xAA`):
|
||
- Копирует сектор 0 в память CPU по адресу `0x80`
|
||
- Заменяет idle-цикл BIOS (`0x14..0x15`) на `JMP_IMM 0x80`
|
||
4. CPU начинает выполнение с `PC=0`:
|
||
- Исполняет BIOS-программу, которая выводит POST-текст на GPU
|
||
- После вывода POST-текста переходит к `0x14` → прыжок на `0x80`
|
||
- CPU выполняет загрузочный код из сектора 0
|
||
|
||
Пример создания загрузочного диска (Python):
|
||
```python
|
||
# TinyCPU bytecode for boot sector at address 0x80
|
||
# Prints "BOOT OK!" to GPU via port 0xC0, then halts
|
||
program = bytes([
|
||
0x02, 0x42, # MOV_IMM_A 'B'
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0x02, 0x4F, # MOV_IMM_A 'O'
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0x02, 0x4F, # MOV_IMM_A 'O'
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0x02, 0x54, # MOV_IMM_A 'T'
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0x02, 0x20, # MOV_IMM_A ' '
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0x02, 0x4F, # MOV_IMM_A 'O'
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0x02, 0x4B, # MOV_IMM_A 'K'
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0x02, 0x21, # MOV_IMM_A '!'
|
||
0x0A, 0xC0, # STORE_A 0xC0
|
||
0xFF, # HLT
|
||
])
|
||
sector = program + b'\x00' * (510 - len(program)) + b'\x55\xAA'
|
||
```
|
||
|
||
Готовый пример: `examples/system-disk/disk.img/`.
|
||
|
||
---
|
||
|
||
## 11. Семантические операции
|
||
|
||
| Операция | Описание |
|
||
|-------------|--------------------------------------------------------------|
|
||
| `copy` | Копирует значение из `from` в `to` |
|
||
| `load_imm` | Загружает непосредственное значение (literal или `$next`) |
|
||
| `add` | Складывает `from` + `to`, сохраняет в `result`, обновляет флаги carry/zero |
|
||
| `sub` | Вычитает `to` из `from`, обновляет флаги borrow/zero |
|
||
| `cmp` | Сравнивает `from` - `to`, обновляет флаги |
|
||
| `store` | Записывает значение в память `mem[address]` |
|
||
| `load` | Читает из памяти `mem[address]` в регистр |
|
||
| `jmp` | Безусловный переход на адрес в `to` |
|
||
| `jcc` | Условный переход, если флаг равен ожидаемому |
|
||
| `jmp_imm` | Переход на байт, следующий за опкодом |
|
||
| `jcc_imm` | Условный переход на байт за опкодом |
|
||
| `call` | Push адреса возврата в стек, прыжок |
|
||
| `ret` | Pop адреса из стека, прыжок |
|
||
| `push` | Push значения в стек |
|
||
| `pop` | Pop значения из стека |
|
||
| `inc` | Инкремент значения |
|
||
| `nop` | Нет операции |
|
||
|
||
### Специальные значения
|
||
|
||
- `$next` — следующий байт в памяти (используется для immediate значений)
|
||
- `arg.X` — ссылка на аргумент инструкции по имени
|
||
- `mem[N]` — прямая ссылка на память по адресу N
|
||
- `mem[arg.X]` — косвенная адресация через аргумент
|
||
|
||
### Условные переходы
|
||
|
||
```json
|
||
{
|
||
"op": "jcc_imm",
|
||
"condition": "zero,1",
|
||
"to": "$next"
|
||
}
|
||
```
|
||
|
||
Формат условия: `"имя_флага,ожидаемое_значение"`. Например `"zero,1"`, `"carry,0"`.
|
||
|
||
---
|
||
|
||
## 12. Написание программ на ассемблере
|
||
|
||
Ассемблер CBE поддерживает мнемоники, определённые в инструкциях CPU.
|
||
|
||
### Синтаксис
|
||
|
||
```asm
|
||
; комментарий
|
||
|
||
label: ; определение метки
|
||
MNEMONIC ; инструкция без аргументов
|
||
MNEMONIC arg1, arg2 ; инструкция с аргументами
|
||
|
||
.org 0x100 ; установка адреса
|
||
.byte 0xAB ; эмит байта
|
||
.db "hello", 0 ; эмит строки с нулевым терминатором
|
||
```
|
||
|
||
### Адресация
|
||
|
||
- Числа: `0x10` (hex), `10` (dec), `0b1010` (bin), `$10` (hex)
|
||
- Метки: `loop_start`, `loop_start+5`
|
||
- Символы: `'A'` (ASCII код)
|
||
|
||
### Пример
|
||
|
||
```asm
|
||
; Программа Hello World
|
||
.org 0x00
|
||
|
||
start:
|
||
MOV_IMM_A 0x48 ; 'H'
|
||
STORE_A 0xC0 ; вывод на GPU
|
||
MOV_IMM_A 0x65 ; 'e'
|
||
STORE_A 0xC0
|
||
MOV_IMM_A 0x6C ; 'l'
|
||
STORE_A 0xC0
|
||
MOV_IMM_A 0x6C ; 'l'
|
||
STORE_A 0xC0
|
||
MOV_IMM_A 0x6F ; 'o'
|
||
STORE_A 0xC0
|
||
HLT
|
||
```
|
||
|
||
### Сборка
|
||
|
||
```bash
|
||
# Собрать .asm в .bin с архитектурой TinyCPU
|
||
cbecc asm program.asm -o roms/boot.bin --arch examples/tiny-cpu.cpu
|
||
|
||
# Или собрать весь плагин (авто-детекция program.asm)
|
||
cbecc build my-cpu.cpu -o build/my-cpu.cbeplugin
|
||
```
|
||
|
||
---
|
||
|
||
## 13. Написание программ на C/C++
|
||
|
||
### Поддержка
|
||
|
||
Транслятор C → TinyCPU поддерживает:
|
||
|
||
- Объявление переменных: `int x = 5;`, `char c;`
|
||
- Присваивание: `x = expr;`
|
||
- Вывод на GPU: `write_gpu('A');`
|
||
- Вывод в порт: `outb(addr, value);`
|
||
- Циклы: `while`, `for` (ограниченно)
|
||
- Условные операторы: `if` (ограниченно)
|
||
- `return 0` → HLT
|
||
|
||
### Пример
|
||
|
||
```c
|
||
void write_gpu(char c) {
|
||
// Транслируется в MOV_IMM_A c; STORE_A 0xC0
|
||
}
|
||
|
||
int main() {
|
||
write_gpu('H');
|
||
write_gpu('e');
|
||
write_gpu('l');
|
||
write_gpu('l');
|
||
write_gpu('o');
|
||
write_gpu('\n');
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
### Компиляция
|
||
|
||
```bash
|
||
# Для TinyCPU (встроенный транслятор)
|
||
cbecc ccompile program.c -o roms/boot.bin --arch tinycpu
|
||
|
||
# Для нативной архитектуры (x86_64 через gcc)
|
||
cbecc ccompile program.c -o program.bin --arch x86_64
|
||
|
||
# C++
|
||
cbecc ccompile program.cpp -o roms/boot.bin --arch tinycpu
|
||
```
|
||
|
||
### Для реальных архитектур
|
||
|
||
Для не-tinycpu архитектур `cbecc ccompile` использует:
|
||
1. `gcc` для компиляции в объектный файл
|
||
2. `ld` или `objcopy` для извлечения flat binary
|
||
|
||
Убедитесь, что установлены `gcc`, `binutils`.
|
||
|
||
---
|
||
|
||
## 14. Написание программ на Python
|
||
|
||
### Поддержка
|
||
|
||
Транслятор Python → TinyCPU поддерживает упрощённый синтаксис:
|
||
|
||
- Присваивание: `x = 5`
|
||
- Вывод: `print(x)` → GPU (0xC0)
|
||
- Циклы: `for i in range(n):`, `while condition:`
|
||
- Условные операторы: `if x == 5:`
|
||
- Комментарии: `# comment`
|
||
|
||
### Пример
|
||
|
||
```python
|
||
# Hello World для TinyCPU
|
||
print("Hello from Python!")
|
||
|
||
# Счётчик
|
||
count = 0
|
||
while count < 5:
|
||
print(count)
|
||
count = count + 1
|
||
```
|
||
|
||
### Трансляция
|
||
|
||
```bash
|
||
cbecc py program.py -o roms/boot.bin
|
||
# Или в составе сборки плагина (auto-detect)
|
||
cbecc build my-cpu.cpu -o build/my-cpu.cbeplugin
|
||
```
|
||
|
||
---
|
||
|
||
## 15. Hex-машинный код
|
||
|
||
Hex-загрузчик поддерживает форматы:
|
||
- Простые hex-байты: `02 48 0A C0 FF`
|
||
- C-стиль: `{0x02, 0x48, 0x0A, 0xC0, 0xFF}`
|
||
- Intel HEX (.hex): `:1000000002480AC0FF...`
|
||
- Один байт на строку
|
||
- Разделители: пробелы, запятые, новые строки
|
||
|
||
### Пример
|
||
|
||
```
|
||
; boot.bin в hex-формате
|
||
; MOV_IMM_A 'H' ; STORE_A 0xC0 ; HLT
|
||
02 48 0A C0 FF
|
||
```
|
||
|
||
### Конвертация
|
||
|
||
```bash
|
||
cbecc hex program.hex -o roms/boot.bin
|
||
```
|
||
|
||
---
|
||
|
||
## 16. Сборка плагинов (cbecc)
|
||
|
||
### Основные команды
|
||
|
||
```bash
|
||
# Сборка из source-директории (авто-детекция program.*)
|
||
cbecc build my-plugin.cpu -o build/my-plugin.cbeplugin
|
||
|
||
# Сборка с указанием бинарника программы
|
||
cbecc plugin my-plugin.cpu --program build/program.bin -o build/my-plugin.cbeplugin
|
||
|
||
# Сборка стандартная (без авто-детекции)
|
||
java -cp modules/cbecc/build/libs/cbecc-0.1.0.jar:modules/loader/build/libs/loader-0.1.0.jar:modules/core/build/libs/core-0.1.0.jar com.cbe.cbecc.Main build my-plugin.cpu -o build/my-plugin.cbeplugin
|
||
```
|
||
|
||
### Процесс сборки
|
||
|
||
1. Чтение `module.json`
|
||
2. Определение ModuleType
|
||
3. Парсинг метаданных
|
||
4. Если есть `program.asm/py/c/cpp/hex` — компиляция в `roms/boot.bin`
|
||
5. Построение секции метаданных (JSON)
|
||
6. Построение таблицы опкодов (JSON-массив из инструкций)
|
||
7. Построение таблицы микрокода (JSON)
|
||
8. Построение секции данных (банки + ROMs)
|
||
9. Вычисление CRC32
|
||
10. Запись .cbeplugin файла
|
||
|
||
---
|
||
|
||
## 17. Тулчейн: компиляция из разных языков
|
||
|
||
### Общая схема
|
||
|
||
```
|
||
program.asm ──→ Assembler ──→ boot.bin
|
||
program.c ──→ CCompiler ──→ boot.bin (gcc + objcopy или встроенный транслятор)
|
||
program.py ──→ PythonTranslator ──→ boot.bin
|
||
program.hex ──→ HexLoader ──→ boot.bin
|
||
│
|
||
▼
|
||
module.json + registers.json + instructions/ + microcode/
|
||
│
|
||
▼
|
||
Compiler (.cbeplugin)
|
||
│
|
||
▼
|
||
my-plugin.cbeplugin ←── run.sh/gradle
|
||
```
|
||
|
||
### Авто-детекция
|
||
|
||
При запуске `cbecc build <dir>`, тулчейн проверяет файлы в порядке приоритета:
|
||
|
||
1. `program.asm` → Assembler
|
||
2. `program.py` → PythonTranslator
|
||
3. `program.c` → CCompiler
|
||
4. `program.cpp` → CCompiler
|
||
5. `program.hex` → HexLoader
|
||
|
||
Если ни один не найден, ищет `roms/boot.bin`.
|
||
|
||
---
|
||
|
||
## 18. Система POST-диагностики
|
||
|
||
POST (Power-On Self-Test) автоматически выполняется при первом шаге CPU.
|
||
|
||
### Коды POST
|
||
|
||
| Код | Описание |
|
||
|-----|---------------------------------------|
|
||
| 0x12| CPU не обнаружен |
|
||
| 0x61| Диск обнаружен |
|
||
| 0x73| CPU обнаружен |
|
||
| 0x74| RAM обнаружена |
|
||
| 0x75| GPU обнаружен |
|
||
| 0x76| KBD обнаружена |
|
||
| 0x77| SND обнаружена |
|
||
| 0x78| Все устройства проверены |
|
||
| 0x00| BOOT_OK — система готова |
|
||
| 0xFF| WARNING — не все компоненты найдены |
|
||
|
||
### LED индикаторы
|
||
|
||
- PWR — питание
|
||
- CPU — процессор
|
||
- MEM — память
|
||
- VID — видео
|
||
- KBD — клавиатура
|
||
- SND — звук
|
||
- DSK — диск
|
||
- CLK — тактовый генератор
|
||
|
||
Адреса memory-mapped I/O для POST:
|
||
- `0xFE` — POST code
|
||
- `0xFD` — Error code
|
||
- `0xFC` — LED status
|
||
|
||
---
|
||
|
||
## 19. Memory-mapped I/O
|
||
|
||
| Адрес | Размер | Назначение |
|
||
|-------|--------|-------------------------------------|
|
||
| 0xB0 | 1 | DISK_SECTOR_ADDR (LBA сектора) |
|
||
| 0xB1 | 1 | DISK_READY_ADDR (1 = готов) |
|
||
| 0xB2 | 512 | DISK_DATA_BASE (данные сектора) |
|
||
| 0xC0 | 1 | GPU_OUT_CHAR (вывод символа) |
|
||
| 0xD0 | 16 | DEVICE_TABLE_BASE (таблица устройств)|
|
||
| 0xE0 | 16 | BIOS_INFO_BASE (информация BIOS) |
|
||
| 0xF7 | 1 | BIOS_TRIGGER (перезапуск диагностики)|
|
||
| 0xF9 | 1 | SND_BEEP_ADDR (звуковой сигнал) |
|
||
| 0xFA | 1 | KBD_STATUS_ADDR (0 = нет, 1 = есть) |
|
||
| 0xFB | 1 | KBD_DATA_ADDR (код клавиши) |
|
||
| 0xFC | 1 | LED_STATUS_ADDR (LED индикаторы) |
|
||
| 0xFD | 1 | ERROR_CODE_ADDR (код ошибки) |
|
||
| 0xFE | 1 | POST_CODE_ADDR (POST код) |
|
||
|
||
---
|
||
|
||
## 20. Бесконечные шаги и детектор циклов
|
||
|
||
### Бесконечное выполнение
|
||
|
||
В CBE нет максимального лимита шагов. CPU выполняется:
|
||
|
||
- **В GUI:** пока не нажата кнопка Stop или CPU не выполнит HLT (0xFF)
|
||
- **В консоли:** пока CPU не выполнит HLT или процесс не будет прерван
|
||
|
||
### Детектор бесконечных циклов
|
||
|
||
В Engine встроен `LoopDetector`, который:
|
||
|
||
1. Записывает последние 64 значения PC
|
||
2. Анализирует повторяющиеся паттерны (длиной 1-8)
|
||
3. При обнаружении цикла выводит сообщение в консоль
|
||
4. **НЕ останавливает выполнение** — циклы не прерываются
|
||
|
||
Пример сообщения:
|
||
```
|
||
[LoopDetector] Infinite loop detected: jump pattern [0x14, 0x06] repeats indefinitely. Execution continues.
|
||
```
|
||
|
||
---
|
||
|
||
## 21. Тёмная тема GUI
|
||
|
||
Эмулятор CBE использует тёмную тему по умолчанию.
|
||
|
||
### Цветовая схема
|
||
|
||
| Элемент | Цвет |
|
||
|------------------|------------------------|
|
||
| Фон | #1E1E24 |
|
||
| Панели | #26262E |
|
||
| Границы | #32323C |
|
||
| Текст основной | #C8C8D2 |
|
||
| Текст яркий | #DCDCF0 |
|
||
| Акцент (синий) | #50A0FF |
|
||
| Зелёный (терминал)| #50DC78 |
|
||
| Оранжевый (7-seg) | #FF6414 |
|
||
|
||
### Компоненты
|
||
|
||
Все панели, текстовые поля, списки, скроллы, кнопки и рамки используют тёмную тему, настроенную через UIManager и явные цвета компонентов.
|
||
|
||
### Изменение темы
|
||
|
||
Для возврата к системной теме, закомментируйте `applyDarkUIManager()` в `EmulatorWindow.java` и раскомментируйте:
|
||
```java
|
||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||
```
|
||
|
||
---
|
||
|
||
## 22. Примеры
|
||
|
||
### Полный пример плагина
|
||
|
||
Структура:
|
||
```
|
||
examples/tiny-cpu.cpu/
|
||
├── module.json
|
||
├── registers.json
|
||
├── instructions/ (18 инструкций)
|
||
│ ├── 0x00.json NOP
|
||
│ ├── 0x01.json MOV_A_B
|
||
│ ├── 0x02.json MOV_IMM_A
|
||
│ ├── 0x03.json ADD
|
||
│ ├── 0x04.json SUB
|
||
│ ├── 0x05.json CMP_A_B
|
||
│ ├── 0x06.json JMP
|
||
│ ├── 0x07.json JC
|
||
│ ├── 0x08.json CMP_A_B (reuse)
|
||
│ ├── 0x09.json MOV_IMM_B
|
||
│ ├── 0x0A.json STORE_A
|
||
│ ├── 0x0B.json LOAD_A
|
||
│ ├── 0x0C.json JMP_IMM
|
||
│ ├── 0x0D.json JZ_IMM
|
||
│ ├── 0x0E.json RET
|
||
│ ├── 0x0F.json INC_A
|
||
│ ├── 0x10.json CALL
|
||
│ └── 0x11.json (stack ops)
|
||
├── microcode/
|
||
│ └── bus.json
|
||
└── roms/
|
||
└── boot.bin
|
||
```
|
||
|
||
### Запуск эмулятора
|
||
|
||
```bash
|
||
# Сборка + запуск с GUI
|
||
./run.sh
|
||
|
||
# Только сборка
|
||
./run.sh build
|
||
|
||
# Без GUI (консоль)
|
||
./run.sh nogui
|
||
|
||
# Прямой запуск с кастомными плагинами
|
||
java -cp modules/gui/build/libs/gui-0.1.0.jar:modules/loader/build/libs/loader-0.1.0.jar:modules/core/build/libs/core-0.1.0.jar com.cbe.gui.Main \
|
||
--cpu build/tiny-cpu.cbeplugin \
|
||
--ram build/basic-ram.cbeplugin \
|
||
--gpu build/vga-display.cbeplugin
|
||
|
||
# Собрать fat-jar
|
||
./run.sh jar
|
||
```
|
||
|
||
---
|
||
|
||
## 23. Устранение неполадок
|
||
|
||
### "Invalid magic: expected CBEPLUGIN"
|
||
|
||
Файл .cbeplugin повреждён или это не валидный плагин. Пересоберите:
|
||
```bash
|
||
./run.sh build
|
||
```
|
||
|
||
### "Missing module.json"
|
||
|
||
Убедитесь, что source-директория содержит `module.json`.
|
||
|
||
### "No CPU loaded"
|
||
|
||
Используйте флаг `--cpu`:
|
||
```bash
|
||
# По директории
|
||
--cpu examples/tiny-cpu.cpu
|
||
# По .cbeplugin
|
||
--cpu build/tiny-cpu.cbeplugin
|
||
```
|
||
|
||
### "Checksum mismatch"
|
||
|
||
Файл .cbeplugin повреждён. Пересоберите.
|
||
|
||
### "Unknown opcode: 0xNN"
|
||
|
||
Инструкция с данным опкодом не определена в вашем CPU. Проверьте `instructions/`.
|
||
|
||
### GPU не отображает ничего
|
||
|
||
1. Убедитесь, что GPU загружен (`--gpu examples/vga-display.gpu`)
|
||
2. CPU должен писать в порт `0xC0`
|
||
3. Проверьте, что boot ROM содержит валидный код
|
||
4. После HLT (0xFF) CPU останавливается — новые символы не выводятся
|
||
|
||
### Клавиатура не реагирует
|
||
|
||
1. Убедитесь, что KBD модуль загружен
|
||
2. CPU должен читать статус (`0xFA`) и данные (`0xFB`)
|
||
3. После чтения данных CPU должен записать `0` в статус (`0xFA`) для acknowledge
|
||
|
||
---
|
||
|
||
## 24. Справочник команд
|
||
|
||
### cbecc
|
||
|
||
```bash
|
||
# Сборка плагина из директории
|
||
cbecc build <source-dir> -o <output.cbeplugin>
|
||
|
||
# Ассемблирование .asm → .bin
|
||
cbecc asm <input.asm> -o <output.bin> --arch <cpu-dir>
|
||
|
||
# Конвертация hex → .bin
|
||
cbecc hex <input.hex> -o <output.bin>
|
||
|
||
# Компиляция C/C++ → .bin
|
||
cbecc ccompile <input.c> -o <output.bin> --arch <arch>
|
||
|
||
# Трансляция Python → .bin
|
||
cbecc py <input.py> -o <output.bin>
|
||
|
||
# Сборка плагина с готовой программой
|
||
cbecc plugin <source-dir> --program <binary> -o <output.cbeplugin>
|
||
```
|
||
|
||
### cbe-emu
|
||
|
||
```bash
|
||
# Запуск с GUI
|
||
./run.sh
|
||
|
||
# Запуск без GUI
|
||
./run.sh nogui
|
||
|
||
# Прямой запуск Java
|
||
java -cp <classpath> com.cbe.gui.Main \
|
||
--cpu <path> --ram <path> --gpu <path> \
|
||
[--kbd <path>] [--snd <path>] [--bios <path>] [--disk <path>] \
|
||
[--program <text>] [--nogui]
|
||
|
||
# Параметры RAM
|
||
--ram <path> --ram-base <addr> --ram-size <bytes>
|
||
```
|
||
|
||
### Gradle
|
||
|
||
```bash
|
||
# Полная сборка всех модулей
|
||
./gradlew build
|
||
|
||
# Сборка fat-jar
|
||
./gradlew :modules:gui:stage
|
||
|
||
# Сборка native-образа (jpackage)
|
||
./gradlew :modules:gui:packageImage
|
||
|
||
# Сборка Windows portable
|
||
./gradlew :modules:gui:portableWindowsZip
|
||
```
|
||
|
||
### run.sh
|
||
|
||
```bash
|
||
./run.sh build # пересобрать все jar
|
||
./run.sh compile # скомпилировать example-плагины
|
||
./run.sh nogui # запуск без GUI
|
||
./run.sh disk # загрузка с диска (nogui)
|
||
./run.sh # запуск с GUI
|
||
./run.sh jar # fat-jar
|
||
./run.sh image # native-образ
|
||
./run.sh windows # Windows portable
|
||
```
|