Мир в 1982 году
Общие даты, по категориям, наука, спорт, музыка, кино, театр, литература, живопись, игры (англ.), авиация, метро, железные дороги.
Положение на игровом и компьютерно-железных рынках
По моим впечатлениям, этот год не был чем-то примечателен - выходили новые игры и системы (компьютеры, приставки, портативные устройства) и ничто не предвещало бурь в следующем году.
Из выпущенных систем стоит отметить:
11.1981 - PC-88. Несмотря на выпуск в прошлом году, игры начали выходить только с 1982 года (во всяком сл��чае достоверной информации о играх за 1981 год нет, на mobygames с высокой долей вероятности может быть ошибка с платформой).
23.04.1982 - ZX Spectrum. Только в Британии, выпуск в США будет только в ноябре 1983 года. 06.1982 - MPC 1600 (Columbia Data Products). Первый IBM PC совместимый клон.
08.1982 - Commodore 64. Легенда и важный гвоздь кризиса игровой индустрии США в 1983 году. 10.1982 - PC-98. Самый известный японский компьютер. В последние годы, за счет основы на процессорах Intel, возможна эмуляция в DosBox-X.
11.1982 - Sharp X1. Самый продвинутый из основной тройки японцев на момент выхода (PC-88, X1, FM-7).
11.1982 - FM-7.
Для обычного человека все тоже шло своим чередом - потребности покупать еще один компьютер нет, в отличие от приобретения софта и потенциального расширения памяти. Последнее можно было приобрести у IBM или же купить у Microsoft подобие-аналог RamCard (помимо опции расширения памяти её можно было использовать и как RAM-диск, что могло быть полезным). Другое направление - программирование. BASIC показался привлекательным по своей простоте и интересно посмотреть еще какой-нибудь язык. Таковым становится ассемблер, благо IBM и Microsoft продают компиляторы под него (но с нюансом).
Эмуляционный конфиг

RamCard выпускался с начала 1982 года (пример раннего экземпляра - у некоторых чипов стоит дата 8204 (четвертая неделя 1982 года), а на самой плате указан 1981 год) и был доступным решением (125 долларов за вариант на 64КБ при покупке напрямую у Microsoft согласно официальной брошюре, у реселлеров цена могла быть до двух с небольшим раз выше). Память же нужна для работы компилятора из .ASM в .OBJ - нужно минимум 128КБ, на 64КБ работать не будет.
Софт
Насколько понимаю, новая версия BASICA поставлялась с новыми партиями IBM PC, потому на текущем этапе будут использоваться изначальные PC-DOS и BASICA версий 1.00. BASIC-86 5.22 также не стал смотреть из-за наличия знакомства с BASIC и несовместимости (исполняемый файл в формате CMD, работающий под CP\M).
Однако, как раз с этого года доступны компиляторы под ассемблер - IBM Macro Assembler и Microsoft Macro Assembler. По факту это один и тот же компилятор, просто у IBM самая ранняя версия за декабрь 1981 года. Вариант Microsoft вышел в феврале-марте 1982 года, но обновленная версия указано только у линковщика (LINK.EXE, 1.08) - у компилятора 1.00 и 1981 год. Нюанс в том, что у IBM на дискете только компилятор, а LINK.EXE изначально вложен в состав PC-DOS 1.00. Я об этом подумал уже в ходе компиляции кода под вариант Microsoft, но я решил этим пренебречь ввиду не сильно большой разницы во времени выхода.
Так как писать под ассемблер придется много, я позволил себе допустить послабление и использовать текстовый редактор для IBM PC, который стал доступен на этой платформе немного позже 1982 года. Настолько сильно погружаться в эпоху интереса у меня не было, а встроенный в PC-DOS 1.00 EDLIN меня ужаснул за 10 секунд. После просмотра ряда самых маленьких текстовых редакторов на old-dos.ru выбор пал на WordStar 3.20 (остальное не заработало) - исполняемый файл датируется маем 1983 года, хотя в самой программе указан 1982 год. Несмотря на неказистый дизайн у него есть базовый набор нужных функций по набору текста. Вкупе с моноширинным шрифтом я, не побоюсь сказать, кайфанул от процесса печати кода - просто и минималистично, но в то же время приятно и комфортно. Есть, однако, нюанс с размером файлов - максимальный размер при сохранении составляет, примерно, около 14КБ (хотя при этом WordStar может открывать файлы большего размера). Дополнительная причина писать код модульно (в идеале - каждая функция в своем файле, а в условном MAIN.ASM только ссылки на эти файлы), а не в один файл.

Пара нюансов по Macro Assembler - расширение файла не имеет значения (можно не только .ASM, но и любое другое, главное чтобы внутри был код ассемблера), внутри файла должен быть особый символ для определения конца файла (в моем случае это был знак с hex-кодом 1A: стрелка).
Также - dosbox-x с некоторых пор поддерживает монтирование дискет форматированных под DOS 1.x, потому его можно использовать для копирования файлов туда-сюда.
Программы
Из-за размера .ASM файлов, полные листинги приводится не будут.
Скачать - github.
Memory Check (MEM.EXE)
Классика поздних версий MS-DOS в реализации для ранних.
Запросы: Qwen (ранняя версия запроса), Grok (ранняя версия запроса).

Также - рабочий пример работы с файлами через FCB (File Control Block): в ходе работы данные записываются в файл MEM.TXT объемом 64 байта, который можно посмотреть через команду TYPE. Интересно, что размер показывается честно - BASIC, WordStar и, возможно, Macro Assembler округляют размер файла до кратного 128 байтам (насколько понимаю, следствие наследия\совместимости CP\M). FCB является единственным способом работы с файлами в DOS 1.x, handle-метод появился только в DOS 2.x.
Ниже - отрывок из кода (плюс код с разными процедурами выхода из программы в зависимости от версии DOS - 1.x не знает про 4Ch; выход из программы работает через RET, а перед этим нужно в самой первой процедуре кода набирать команды PUSH DS ; SUB AX, AX ; PUSH AX для обозначения PSP-сегмента, от которого выход и происходит):
; Set up FCB to MEM.TXT LEA DX, FILE_FCB MOV AH, 0Fh ; Open file INT 21h CMP AL, 0FFh ; FFh="not found/error" JNE SHORT FILE_OPENED ; If not found, create it LEA DX, FILE_FCB MOV AH, 16h ; Create file INT 21h CMP AL, 0FFh ; Error? JE SHORT SKIP_SAVE ; Skip if create failed FILE_OPENED: ; Set record size to 1 byte (for seq write) MOV WORD PTR [FILE_FCB+0Eh], 64 ; Record size = 64 ; Set DTA to output buffer (for write) MOV DX, OFFSET OUTPUT_BUFFER MOV AH, 1Ah ; Set DTA INT 21h ; Write to file (AH=15, number of records=OUTPUT_LEN) MOV CX, OUTPUT_LEN LEA DX, FILE_FCB MOV AH, 15h ; Seq write INT 21h CMP AL, 0 ; AL=0 success JNE SHORT SKIP_SAVE ; Skip close if write failed ; Close file LEA DX, FILE_FCB MOV AH, 10h ; Close file INT 21h SKIP_SAVE: ; Exit based on DOS version CMP DOS_MAJOR, 2 JAE SHORT EXIT_DOS2 RET EXIT_DOS2: MOV AH, 4Ch INT 21h START ENDP
Draw Tool (Draw160)
Рисовалка в нестандартном режиме 160x100x16 RGBI (технически обозначается как 160x200, но чем это обусловлено я не выяснял, специалисты смогут лучше пояснить). По факту - модификация текстового режима 80x25 с поддержкой цвета.
Под DOS 1.x глючит (курсор появляется в любой точке экрана и в том числе за его пределами) и работает только один из Shift'ов клавиатуры, такое поведение происходит и в MartyPC. Под DOS 2.x+ работает корректно. Также - запускается и на конфиге с 48КБ памяти.
Запросы: Qwen (1, 2, 3), Google Gemini, Grok (1, 2, 3).


Запись в DosBox Pure (RetroArch) с шейдером crt-royale-ntsc-320px-composite.glslp (сделать скриншот не удалось - портится изображение).
Ниже два отрывка кода - в первом набор значений для перепрограммирования CRTC, а во втором сама процедура перенастройки режима:
; --- CRTC Register Data for 160x100 Mode --- crtcvals DB 71h, 50h, 5Ah, 0Ah ; R0-R3 (Horizontal) DB 7Fh ; R4: Vertical Total (127) DB 06h ; R5: Vertical Adjust DB 64h ; R6: Vertical Displayed (100 rows) DB 70h ; R7: Vertical Sync DB 02h ; R8 Interlace (Mode 2) DB 01h ; R9 Max Scan Line (1=2 lines high) DB 20h, 00h ; R10-11 (Cursor - hidden)
; =============================================== ; SET_MODE_160X100 ; =============================================== SET_MODE_160X100 PROC NEAR ; 1. Set standard 80x25 text mode first (Mode 3) MOV AX, 0003h INT 10h ; 2. Disable Blink (Port 03D8h) MOV DX, 03D8h MOV AL, 09h OUT DX, AL ; 3. Reprogram CRTC (6845) MOV SI, OFFSET DGROUP:crtcvals MOV CX, 12 ; Update registers 0 to 11 MOV DX, 03D4h ; CRTC Index Register XOR AH, AH ; Start at Register 0 CRTC_LOOP: MOV AL, AH ; Select Register Index OUT DX, AL INC DX ; Select Data Register (3D5h) MOV AL, CS:[SI] ; Get Value (CS override needed) OUT DX, AL DEC DX ; Back to Index INC SI INC AH LOOP CRTC_LOOP RET SET_MODE_160X100 ENDP
Основной функционал и выход из программы под DOS 1.x работает. Единственное что не удалось сделать рабочим - сохранение\загрузка файла через FCB. Найти или подобрать рабочие процедуры мне не удалось, информации про это в документации к Macro Assembler нет. Обидненько.
Обновление (16.02.2026): используя документацию по самому DOS (IBM PC-DOS 1.0 (Aug. 1981), доступен минимум на WinWorld) удалось сделать рабочими FCB и функции сохранения\загрузки файла (запросы - Qwen, DeepSeek, Grok):
; --- FCB for IMG.PIC (Standard 37 bytes) --- fcb DB 0 ; Drive=0 (default) DB 'IMG', 5 DUP(' ') ; Filename (8 chars, space-padded) DB 'PIC' ; Extension (3 chars, space-padded) DW 0 ; Current block (DW 0) DW 80h ; Record size=128 bytes DB 16 DUP(0) ; File size + reserved fields (16 bytes) DB 0 ; Current record within block DD 0 ; Relative record number (4 bytes)
; =============================================== ; SAVE_IMAGE ; =============================================== SAVE_IMAGE PROC NEAR PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH DS PUSH ES ; Set DTA to our buffer MOV DX, OFFSET dta MOV AH, 1Ah INT 21h ; First try to delete existing file (FCB delete) LEA DX, fcb MOV AH, 13h ; Delete file via FCB INT 21h ; Ignore errors (file may not exist) ; Create file IMG.PIC LEA DX, fcb MOV AH, 16h ; Create file via FCB INT 21h OR AL, AL ; AL=0, success JNZ SAVE_ERROR ; FCB block record XOR AX, AX MOV WORD PTR fcb+12, AX ; current block = 0 MOV BYTE PTR fcb+32, AL ; current record = 0 ; Prepare to write 125 records (128 bytes each, total 16000 bytes) MOV BX, 125 ; Number of records MOV AX, 0B800h MOV ES, AX ; ES = VRAM segment XOR SI, SI ; Source offset in VRAM SAVE_LOOP: PUSH BX ; Copy 128 bytes from VRAM to DTA MOV DI, OFFSET dta ; Reset DI to start of DTA MOV CX, 128 ; 128 bytes CLD COPY_BYTE: MOV AL, ES:[SI] ; Byte from VRAM MOV [DI], AL ; Store in DTA INC SI INC DI LOOP COPY_BYTE ; Write one record via FCB LEA DX, fcb MOV AH, 15h ; Write seq record INT 21h OR AL, AL ; AL=0, success JNZ SAVE_ERROR_POP POP BX DEC BX JNZ SAVE_LOOP ; Close file LEA DX, fcb MOV AH, 10h ; Close file via FCB INT 21h ; Restore segment registers ; MOV AX, DGROUP ; MOV DS, AX ; MOV ES, AX POP ES POP DS POP DI POP SI POP DX POP CX POP BX POP AX CLC ; Success RET SAVE_ERROR_POP: POP BX SAVE_ERROR: ; Close file if open LEA DX, fcb MOV AH, 10h ; Close file via FCB INT 21h MOV DL, 07h ; Beep on error MOV AH, 02h INT 21h POP ES POP DS POP DI POP SI POP DX POP CX POP BX POP AX STC ; Failure RET SAVE_IMAGE ENDP ; =============================================== ; LOAD_IMAGE ; =============================================== LOAD_IMAGE PROC NEAR PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH DS PUSH ES ; Set DTA to our buffer MOV DX, OFFSET dta MOV AH, 1Ah INT 21h ; Open file using FCB LEA DX, fcb MOV AH, 0Fh ; Open file via FCB INT 21h OR AL, AL ; AL=0, success JNZ LOAD_ERROR ; FCB block record XOR AX, AX MOV WORD PTR fcb+12, AX ; current block = 0 MOV BYTE PTR fcb+32, AL ; current record = 0 ; Read 125 records (128 bytes each) MOV BX, 125 ; Number of records MOV AX, DGROUP PUSH AX POP DS ; DS=Data segment MOV AX, 0B800h PUSH AX POP ES ; ES=VRAM segment MOV DI, 0 ; Start offset in VRAM LOAD_LOOP: PUSH BX ; Read one record into DTA LEA DX, fcb MOV AH, 14h ; Read seq record INT 21h OR AL, AL ; AL=:0 - success, 1 - EOF, 3 - error JNZ LOAD_ERROR_POP ; Copy 128 bytes from DTA to VRAM MOV SI, OFFSET dta ; Reset SI to start of DTA MOV CX, 64 ; 64 words = 128 bytes CLD REP MOVSW ; Copy, DI advances by 128 bytes POP BX DEC BX JNZ LOAD_LOOP ; Close file LEA DX, fcb MOV AH, 10h ; Close file via FCB INT 21h ; Restore segment registers ; MOV AX, DGROUP ; MOV DS, AX ; MOV ES, AX POP ES POP DS POP DI POP SI POP DX POP CX POP BX POP AX CLC ; Success RET LOAD_ERROR_POP: POP BX LOAD_ERROR: ; Close file if open LEA DX, fcb MOV AH, 10h ; Close file via FCB INT 21h MOV DL, 07h ; Beep on error MOV AH, 02h INT 21h POP ES POP DS POP DI POP SI POP DX POP CX POP BX POP AX STC ; Failure RET LOAD_IMAGE ENDP
К сожалению, возникла другая проблема - после сохранения\загрузки перестает работать курсор. Выявить проблему пока не удалось. Впрочем, исправление этого момента не является принципиально важным - есть возможности компенсировать.
Текущая альтернатива это dosbox-x из-за поддержки сэйв-стейтов (и DosBox Pure в Retroarch).









Помощь приветствуется: DOS 1.x, FCB (решено), DOS 2.x+, handle (github).
PC Speaker Music Tool (PCSMUS)
По замыслу - программа для написания музыки под PC Speaker с возможностью сохранять\загружать результат в файл для использов��ния\прослушивания.
Запросы: Qwen, DeepSeek, Grok (1, 2).
Сделать рабочий код не старался, так как не видел смысла тратить на это время из-за фиаско с FCB для предыдущей программы. Первый вариант после конверсии из MASM 5.0+ в MASM 1.0 компилится без ошибок, но не работает (а еще из .OBJ получается большой по размеру исполняемый файл - 68480 байт). Второй вариант тоже компилится без ошибок и запускается, но зависает (возможно, неправильная последовательность операнд в одной из функций\процедур).
Помощь\предложения по написанию приветствуются - тема на github.
Концепт подобия движка
Идея простая - используя Draw160 и PCSMUS с написанием игровой логики под ассемблер писать игры, которые можно запускать на самых ранних IBM PC как в эмуляции, так и на реальном железе. При этом они - работают в нестандартном графическом режиме (160x100x16 RGBI), с музыкой на PC Speaker (пример красивой реализации - System Beeps, статьи на тему от автора - 1, 2).
Вспомогательные средства
CP437CHK - скрипт на python, проверяющий текстовые файлы на соответствие кодовой странице 437. Полезно, если в коде от нейронки неправильные символы из-за которых он не запускается под эмуляцией.
Возможные выводы
В целом, работа с ассемблером - это интересно. Правда, для понимания кода без справочника по командам и операндам процессора разобраться затруднительно. Сложностей при этом хватает и без этого - программа может скомпилироваться без ошибок, но не работать (для дополнительных проверок и дебага предусмотрены NUL.LST и NUL.CRF, но для этого требуются дополнительные знания) или же глючить в какой-то среде (Draw160 подглючивает в DOS 1.x, но при этом корректно работает под DOS 2.x).
Структура кода и синтаксис мне отчасти напомнили python (в частности, проставление пробелов в строках, хотя это, возможно, было не обязательно делать). Понравился и формат его организации (сначала идут сегменты данных DATASEG, потом STACKSEG, а затем до конца CODESEG; все операции желательно выполнять внутри процедур и самая первая должна быть PROC FAR, последующие — PROC NEAR; START PROC FAR и END START обертывают код внутри CODESEG). Разобрать работу с файлами и можно было бы попробовать сделать графический текстовый редактор с поддержкой нескольких языков минуя ограничения ранних IBM PC за счет использования графики из файла. И игры попробовать поделать само собой.
