diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..31a243f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,218 @@ +# AGENTS.md — Estex DSS + +Документ для ИИ-агентов, работающих с этим репозиторием. Описывает устройство +проекта, сборку, соглашения и подводные камни. Всё нижесказанное проверено по +содержимому репозитория. + +## 1. Обзор проекта + +**Estex DSS** — доработка дисковой операционной системы **DSS (Disk SubSystem)** +для компьютера **Sprinter 2000 (SP2000)** — российского ZX +Spectrum-совместимого компьютера фирмы Peters Plus на процессоре **Z84C15** +(Z80-совместимый, со встроенным SIO/CTC). Исходный код унаследован от +оригинальной DSS от Peters Plus (автор DNS — Denis Parinov, 1998–2003) и +развивается дальше (правки BAO и др., актуальная версия — DSS 1.71.x). + +Весь код — Z80-ассемблер для **sjasmplus**. Комментарии и документация — на +русском языке. Загрузочная цепочка: BIOS (≥3.06) → boot-сектор +(`DSSloader.bin`) → ядро `SYSTEM.DOS` → командный интерпретатор `SYSTEM.EXE`. + +Проект собирает три системных файла: + +| Файл | Источник | Назначение | +|---|---|---| +| `SYSTEM.DOS` | `DSS/DSS-MAIN.ASM` | Ядро DSS (API, файловые системы, драйверы) | +| `SYSTEM.EXE` | `SHELL/SHELL.ASM` | Командный интерпретатор (шелл) | +| `SYS.EXE` | `BOOT/boot.asm` | Установщик boot-загрузчика и системных файлов на диск | +| `DSSloader.bin` | `BOOT/DSSBOOT.ASM` | Сам boot-загрузчик (секторный, `ORG #8000`) | + +## 2. Структура репозитория + +- `DSS/` — ядро системы: + - `DSS-MAIN.ASM` — точка входа сборки ядра: RST-векторы, таблица функций + `DSS_API_TABLE`, карта буферов `CORE_BUFFERS`, подключает все модули + через `INCLUDE`. + - `API.asm` — агрегатор, включает `API/*.asm` (~50 файлов — по одному + системному вызову на файл: `Open.asm`, `Read.asm`, `ChDir.asm` и т.д.). + - `DOS_FS.ASM` — файловые/каталожные процедуры DOS-уровня. + - `Procedures.asm` — общие помощники (`PUTCHAR`, `MK_TIME` и др.). + - `KEYINTER.ASM` — клавиатурный драйвер (PS/2-хост на SIO канала A Z84C15), + обрабатывается в прерывании `RST 38`. + - `DRV-MAIN.ASM` — страница драйверов (компилируется в отдельный блок через + `DISP/ENT` в конце `DSS-MAIN.ASM`), своя таблица RST по `#A0000+`. + - `FS/` — файловые системы: `FS.ASM` (диспетчер по сигнатуре `#AA55`), + `FAT.asm` (FAT12/16/32), `CDFS.ASM` (CD, в разработке — ветка `beta_cdfs`). + - `drivers/` — драйверы устройств: `media/` (ata_atapi-drv, fdd-drv, + ram_disk-drv, ATAPI/CDX), `Input/` (MOUSE.ASM). + - `first_init.asm` — код первой инициализации (затирается после старта). + - `defines.inc` — compile-time флаги ядра (мышь, клавиатура, память и т.п.). + - `VERSION.INC` — версия ядра + Lua-логика номера билда. + - `build.txt` — счётчик билда ядра (одно число, сейчас 6). + - `DSS_API.TXT` — полное описание системных вызовов (UTF-8). + - `DSS_MAP.TXT` — карта памяти ядра; `KNOWN.BUG`, `ToDo.txt`, + `CHANGES.LOG` — известные баги, планы, история изменений. +- `SHELL/` — командный интерпретатор: + - `SHELL.ASM` — точка входа, `EXEC.ASM` — разбор и выполнение команд, + `BATCH.ASM` — парсер .BAT (%VAR%, %0..%9, GOTO/IF), `EDLINE.ASM` — + редактор строки с историей. + - `Commands/` — по файлу на команду: CD/CHDIR, CLS, DATE, DEL, DIR, ECHO, + EXIT, GOTO, HELP, IF, INFO, MD/MKDIR, PATH, PAUSE, REM, REN, RD/RMDIR, + SET, VER, REBOOT, BREAK. + - `Procedures/` — print, parsers, math, shared. `Messages/main_txt.asm` — + тексты сообщений. + - `version.inc`, `build.txt` — версия и счётчик билда шелла. + - `README.txt` — описание команд и клавиш истории (CP866). +- `BOOT/` — `boot.asm` (установщик → `SYS.EXE`), `DSSBOOT.ASM` (boot-сектор → + `Build/DSSloader.bin`), `README.TXT` (CP866). +- `Shared_Includes/` — **git-подмодуль** (ветка `main`, относительный URL + `../Shared_Includes.git`, содержит собственный `.git`): + - `constants/` — `SP2000.inc` (порты/железо Sprinter), `BIOS_equ.inc`, + `dss_equ.inc` (номера функций DSS), `dss_errors.z80`, `EXE_Header.z80` + (512-байтный заголовок EXE), TRDOS/ZX-константы. + - `structures/` — `FileSystem.inc`, `ATA_ATAPI.INC`, `bmp.inc`. + - `macroses/` — `macros.z80`, `accelerator.z80`. + - `LUA/Functions.lua` — Lua-функции для sjasmplus (`increase_build`, + `get_build`, `Get_date_RU`, `Get_checksum` и др.). + - `Docs/` — справочники: `BIOS functions.asm`, `DSS_1.71_Functions.asm`, + `sp2000.pdf`, описание команд Z80. +- `Build/` — выходы сборки (**не отслеживается git**, `.gitignore` в проекте + нет): `DSS/{SYSTEM.DOS,SYSTEM.EXE,SYS.EXE}`, листинги `*.LST`, + `Variables.inc` (экспорт символов через `--exp`), `Original/` — оригинальные + бинарники Peters Plus для сравнения, `*_dasm.a80` — дизассемблирования. +- `Hidden/` — архивные/справочные исходники (ATAPI, CDX); исключены из поиска + VS Code (`.vscode/settings.json` → `search.exclude`). +- `TMP_CODE.ASM` — временный рабочий файл-черновик (не часть сборки). +- `keys.md` — детальный хендофф-документ по клавиатурной подсистеме + (`KEYINTER.ASM`) для ИИ-сессий; полезен как образец глубокого разбора. + +## 3. Сборка + +Ассемблер: **sjasmplus** (проверено: установлен в +`/c/tools/msys64/usr/local/bin/sjasmplus`). Makefile нет — сборка идёт через +задачи VS Code (`.vscode/tasks.json`) или вручную теми же командами. +Ключевые флаги: `--syntax=afw --fullpath -Wno-shortblock`. + +Ядро (задача «Build SYSTEM.DOS», проверено — собирается, 0 ошибок): + +``` +sjasmplus --nologo --syntax=afw --fullpath --color=on -Wno-shortblock \ + --lst=Build/DSS-MAIN.LST --raw=Build/DSS/SYSTEM.DOS \ + --exp=Build/Variables.inc dss/dss-main.asm +``` + +Задача «Build NEW VERSION of SYSTEM.DOS» добавляет `--define INCREASE_BUILD` +— при этом Lua-код в `DSS/VERSION.INC` инкрементирует `DSS/build.txt`. + +Шелл (задача «Build SYSTEM.EXE», проверено — собирается, 0 ошибок): +`sjasmplus ... --raw=Build/DSS/SYSTEM.EXE SHELL/SHELL.ASM`. Без +`--define INCREASE_BUILD` билд шелла не трогает `SHELL/build.txt`. + +Установщик (задача «Build SYS.EXE», проверено — собирается, 0 ошибок): +`sjasmplus ... --raw=Build/DSS/SYS.EXE boot/boot.asm`. + +Особенности сборки: + +- Версия ядра: `VERS=1, MODF=71` в `DSS/VERSION.INC`, билд из + `DSS/build.txt` → строка вида «DSS 1.71.6». +- sjasmplus исполняет встроенные Lua-блоки (`LUA PASS1`/`LUA ALLPASS` … + `ENDLUA`, `INCLUDELUA 'Shared_includes/lua/Functions.lua'`) — через них + подставляются дата сборки и номер билда. +- Пути в `INCLUDE` относительны **корню репозитория** — запускать сборку + нужно из корня (в задачах `cwd = workspaceFolder`). Регистр имён + (`dss/dss-main.asm` vs `DSS/DSS-MAIN.ASM`) в задачах смешанный — на Windows + это работает. +- Включение файлов — текстовое (`INCLUDE`): модули не компилируются + отдельно, всё собирается одним проходом из главного файла. Активно + используются `MODULE/ENDMODULE`, `STRUCT/ENDS`, `DISP/ENT`, `ASSERT`, + `DISPLAY` (смотрите вывод сборки — там карта адресов буферов). + +## 4. Архитектура рантайма + +- Ядро собирается с `ORG 0` и живёт на своей странице в слоте 0 + (`#0000–#3FFF`); карта — в `DSS/DSS_MAP.TXT`. Вызов функций DSS из + программ: номер функции в регистре `C`, `RST 10h`; ошибки возвращаются по + флагу `CF` (код в `A`). Пример — в начале `DSS/DSS_API.TXT`. +- RST-векторы ядра: `RST 00` — возврат из процесса (RETFAR), `RST 08` — + портал в BIOS, `RST 10` — DSS API, `RST 18` — портал на страницу + драйверов, `RST 20` — FS API, `RST 30` — мышиный API, `RST 38` — обработчик + IM1 (клавиатура `KEYSCAN` → мышь → курсор). +- Диспетчер `RST_10` индексирует `DSS_API_TABLE` (адреса функций хранятся + раздельными байтами: младшие и старшие — двумя блоками). +- Драйверы (`DRV-MAIN.ASM`) собираются в отдельный блок в конце образа ядра + (через `DISP 0 … ENT`) и работают на собственной странице; переход между + страницами — через порталы RST и `PORTAL.*`. +- Формат исполняемых файлов Estex — EXE с 512-байтным заголовком + (`Shared_Includes/constants/EXE_Header.z80`: сигнатура `'EXE'`, версия, + адреса загрузки/старта/стека). Шелл собирается с `DEFINE App_EXE_Version 1`. +- Многозадачность: процессы с IX-контекстом, номер таски в `(ix-1)`; + подробности — в `DSS_API.TXT` (функции 41h EXEC, 47h APPINFO и др.). +- Минимальная версия BIOS: 3.06 (`MINIMUM_BIOS_VERSION` в `defines.inc`), + проверяется в `first_init.asm`. + +## 5. Соглашения по коду + +- **Кодировка: CP866 (русская DOS), переводы строк CRLF** — у почти всех + `.asm/.inc/.txt`. Исключения в UTF-8: `DSS/DSS_API.TXT`, `keys.md`, этот + файл. При чтении/поиске из Unix-окружения используйте `iconv -f CP866 -t + UTF-8` и `grep -a` (grep может считать файлы бинарными). **Не + перекодируйте файлы** — правьте их, сохраняя CP866+CRLF; `git config + core.autocrlf=true`. +- Отступы — табуляция; колонки: `метка: ОПЕРАЦИЯ операнды ; комментарий`. + Локальные метки — через точку (`.loop`), модули — `MODULE/ENDMODULE`. +- В заголовках файлов — таблица изменений `Rev / Date / Name / Description` + (авторы: DNS, BAO и др.). При существенных правках добавляйте строку туда + же в том же формате. +- Маркеры задач в коде: `;!TODO`, `;!FIXIT`, `;!HARDCODE`, чек-листы + `[ ]` / `[x]` / `[!]` (легенда — в `DSS/ToDo.txt`). +- Compile-time конфигурация — только через `DEFINE` в `DSS/defines.inc` + (для ядра) и аналогичных `*.inc`; закомментированный define = выключено + (см. комментарий в начале `defines.inc`). +- Новый системный вызов: файл `DSS/API/.asm` + `include` в + `DSS/API.asm` + слот в `DSS_API_TABLE` + константа в + `Shared_Includes/constants/dss_equ.inc` + описание в `DSS/DSS_API.TXT`. +- Новая команда шелла: файл `SHELL/Commands/.ASM` + `include` в + `SHELL/SHELL.ASM` + регистрация в парсере (`EXEC.ASM`/`BATCH.ASM`). +- Коммит-сообщения — на русском, свободной формы; пометки вида `-bug`, + `-bugfix`, `!FIXIT`. Текущая ветка разработки — `beta_cdfs`. + +## 6. Тестирование и отладка + +Автоматических тестов в проекте **нет**. Проверка — ручная, на эмуляторе или +реальном железе: + +- Задача «Copy files to IMG» / «Copy THIS file to Test_2g.img»: `hdfmonkey + put` копирует собранные файлы в HDD-образ + `C:\tools\Progs\MAME\IMG\test_2g.img` (или `sp_disk2.img`). +- Задача «Run MAME» запускает эмулятор через внешний `.bat` + (`C:\tools\Progs\MAME\*.bat`, сами скрипты вне репозитория). +- Отладка: VS Code + **DeZog** (`.vscode/launch.json`, remoteType `zsim`), + использует `.sld`-файлы sjasmplus; задача «Build this file» собирает + текущий файл с `--sld` для отладчика. +- Дизассемблирование: задача «Disassemble binary» (`z80dasm`). +- Листинг `Build/DSS-MAIN.LST` (~1 МБ) и вывод `DISPLAY` при сборке — + основной способ контроля адресов/размеров. +- При сборке с `--define INCREASE_BUILD` меняются отслеживаемые git'ом файлы + `*/build.txt` — не коммитьте случайные инкременты. + +## 7. Безопасность и осторожность + +- Код напрямую программирует железо (`OUT` в системные порты, переключение + страниц памяти, прерывания) — ошибка может подвесить систему только на + целевой машине/эмуляторе, но не хост. +- `hdfmonkey put` **модифицирует файлы-образы дисков** — убедитесь, что + путь к образу верный, прежде чем запускать задачи копирования. +- `BOOT/boot.asm` (SYS.EXE) — программа записи boot-сектора на реальные + FDD/HDD; на реальном железе это потенциально деструктивная операция. + +## 8. Известные проблемы (на момент написания) + +- ~~Сборка `SYSTEM.EXE` сломана~~ — **исправлено 2026-07-18** (в рабочем + дереве, правка `SHELL/version.inc` ещё не закоммичена): задвоенные блоки + (`CONSOLE_VERS`/`CONSOLE_MODF`/`CONSOLE_BUILD`, лишний `LUA ALLPASS`) + убраны, `increase_build` вызывается только при `--define INCREASE_BUILD`. + Проверено: шелл собирается с 0 ошибок, `SHELL/build.txt` не меняется. + Исходная поломка была зафиксирована в коммите `32dca48`. +- Актуальные списки багов и планов: `DSS/KNOWN.BUG` (включая разбор багов + от ИИ), `DSS/ToDo.txt`, `DSS/CHANGES.LOG` (секции `!FIXIT`/`!TODO`). +- Ветка `beta_cdfs` — работа над CDFS/BigDir в процессе («Пока не работает, + надо доделывать BigDir» — коммит `41ff458`). diff --git a/AGENT_TODO.MD b/AGENT_TODO.MD new file mode 100644 index 0000000..2589253 --- /dev/null +++ b/AGENT_TODO.MD @@ -0,0 +1,55 @@ +# AGENT_TODO.MD — советы от ИИ-агента к рассмотрению + +Копилка предложений от ИИ-агентов. По команде «сохрани совет» агент добавляет +сюда новый раздел со сквозным номером. Нумерация не переиспользуется. + +--- + +## Совет #1. DIR_PATH_CHECK.gotoPath: заменить трюк с CHECK_SLASH на JP CHDIR + +**Статус:** на рассмотрении (2026-07-19 применён другой вариант фикса — см. ниже) + +**Контекст.** Баг: из `C:\PASCAL` после `Open("SUB\A.TXT")` любой следующий +вызов с относительным путём (`Create`, `Open`, `ChDir`) резолвил путь от +корня диска и падал с #04 PATH_NOT_FOUND. Причина: в `DIR_PATH_CHECK.checkDir` +при несовпадении, где `WorkDirectory` ⊋ `CurrentDirectory` (спуск в +подкаталог), HL входил в `.gotoPath` уже ЗА терминатором `CurrentDirectory`, +и `FINDDIR.CHECK_SLASH` дописывал `\` после терминатора, а не вместо него. +`SetPath_GetName(CurrentPath)` видел `C:\PASCAL` без завершающего `\`, +выполнял только reroot через CHDISK и не доходил до CWD, возвращая CF=0. + +**Применённый вариант** (в рабочем дереве): перенос `INC DE/INC HL` после +`JR NZ,.gotoPath` — HL остаётся на символе несовпадения (в случае-префиксе это +сам терминатор), CHECK_SLASH находит конец строки за одну итерацию CPIR. +Нулевая дельта по размеру и тактам, основной баг устраняет. + +**Предлагаемый альтернативный вариант:** весь блок `.gotoPath` +(`DSS/DOS_FS.ASM`) заменить на: + +```asm +.gotoPath: LD HL,CORE_BUFFERS.CurrentPath + JP CHDIR +``` + +`CHDIR` (`DSS/API/ChDir.asm`) уже реализует ровно нужную семантику «пройти +путь, включая последний компонент»: `SetPath_GetName` + `OPENDIR(TMPNAME)`. +Трюк «дописать `\` → пройти путь → стереть `\`» становится ненужен. + +**Плюсы относительно применённого варианта:** + +- ~20 байт → 6 байт (−14 байт); нет вызова `CHECK_SLASH`/`CPIR` вовсе — + экономия тактов на любом входе, а не только на баг-кейсе; +- уходит зависимость `.gotoPath` от входящих HL/BC/AF' (на входе со смены + диска BC собирается из неинициализированного AF'); +- уходит косяк с затиранием корня: в применённом варианте при + `CurrentDirectory="\"` и спуске в подкаталог epilogue `DEC HL`/`LD (HL),0` + превращает `CurrentDirectory` в `""` (косметика: API #1E CURRDIR_FN вернёт + пустую строку вместо `"\"`, самолечится следующим ChDir; в старом коде тот + же эффект был на входе со смены диска при CWD=корень). + +**Минусы/риски:** большее семантическое изменение — ошибки возвращают +`SetPath_GetName`/`OPENDIR` напрямую, отдельный `LD A,PATH_NOT_FOUND` после +`CHECK_SLASH` удаляется; требуется прогон на эмуляторе/железе. + +**Связанное:** удаление дублирующего сравнения диска в `.forceCheck` +(строки 262–266) — применено (`JR NZ,.gotoPath` сразу после `CALL .checkDrive`). diff --git a/DSS/DOS_FS.ASM b/DSS/DOS_FS.ASM index 0abdb3f..6134584 100644 --- a/DSS/DOS_FS.ASM +++ b/DSS/DOS_FS.ASM @@ -257,14 +257,14 @@ DIR_PATH_CHECK: LD A,(HL) .forceCheck: ;LD HL,CurrentDirectory+1 LD BC,CORE_BUFFERS.CurrentDirectory.DEPTH-1 CALL .checkDrive - JR Z,.checkDir - ; - LD HL,CORE_BUFFERS.CurrentPath - LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) - ADD 'A' - CP (HL) JR NZ,.gotoPath ; + ;LD HL,CORE_BUFFERS.CurrentPath + ;LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) + ;ADD 'A' + ;CP (HL) + ;JR NZ,.gotoPath + ; .checkDir: LD HL,CORE_BUFFERS.CurrentDirectory+1 LD DE,CORE_BUFFERS.WorkDirectory+1 ; 稪 @@ -276,9 +276,9 @@ DIR_PATH_CHECK: LD A,(HL) AND A JR Z,.end CP (HL) - INC HL - INC DE JR NZ,.gotoPath + INC DE + INC HL DJNZ .loop EX AF,AF' SUB 1 diff --git a/SHELL/Commands/DIR.ASM b/SHELL/Commands/DIR.ASM index d2b2366..237f95d 100644 --- a/SHELL/Commands/DIR.ASM +++ b/SHELL/Commands/DIR.ASM @@ -128,7 +128,7 @@ cmd_dir: push de ld de,Buffers.work.buffer1 ; 80 ld a,FAT_ATTR.NoVolID ; ਡ (, ஬ ⪨ ⮬) ;ld bc,Dss.F_First.FATname ; f_first (ଠ 11) - ld bc,Dss.F_First.All_FATname ; f_first (ଠ 11) ; [ ] bigdir + ld bc,Dss.F_First.All_FATname ; f_first (ଠ 11) ; [ ] big dir RST ToDSS JR C,.Dir_Empty ;R14 ; diff --git a/SHELL/version.inc b/SHELL/version.inc index 24e4b3d..d1b40cf 100644 --- a/SHELL/version.inc +++ b/SHELL/version.inc @@ -1,11 +1,4 @@ -;------------------[ ⥪ BUILD++ ]-----------------[] - LUA PASS1 - Console_build = increase_build("./SHELL/build.txt") - if Console_build > 999 then - Console_build = 999 - print("WARNING! Build > 999","WARNING! Build > 999","WARNING! Build > 999","WARNING! Build > 999","\aWARNING! Build > 999\a") - end - ENDLUA IFNDEF INCREASE_BUILD + IFNDEF INCREASE_BUILD DEFINE INCREASE_BUILD 0 ELSE DEFINE+ INCREASE_BUILD 1 @@ -28,20 +21,6 @@ ENDLUA ;---------------------------------------------------------------------[] -; -; Shell full version -; ᨨ (0..9) -CONSOLE_VERS EQU 1 -; 䨪樨 (0..99) -CONSOLE_MODF EQU 2 -; (0..999) -CONSOLE_BUILD EQU lua_BUILD -; - LUA ALLPASS - sj.insert_label("lua_BUILD", Console_build) - ENDLUA -;---------------------------------------------------------------------[] - ; ; Shell full version ; ᨨ (0..9)