experiments
Today

Заводной абрикос

Помимо всем известной Apple, на свете существовала еще одна «фруктовая» компания, когда-то выпускавшая очень популярные компьютеры.

И сейчас мы цинично оживим и запустим эмулятор этих замечательных машин.

Когда-то умели делать туториалы.

Поскольку и сама компания и ее компьютеры и даже эмулятор (вместе с автором)  — с берегов «туманного альбиона», большая часть ссылок в статье ведет в никуда на ресурсы, заблокированные для доступа из РФ, родной РКН к этому никакого отношения не имеет.

Поэтому надеваем монокли, цилиндры и поднимаем тост «За обход блокировок».

Кто бы мне сказал еще лет десять назад, что попасть на фанатский сайт о старых британских компьютерах станет сложнее, чем на официальный сайт Северной Кореи.

Его звали "Apricot"

Изучая материалы из недавнего компьютерного прошлого, в который раз убеждаюсь:

за каждой успешной историей в ИТ есть натуральное кладбище всевозможных фейлов, обсеров и провалов.

А нынешние «лидеры ИТ-индустрии» были отнюдь не первыми и часто далеко не самыми инновационными.

Еще у людей короткая память:

вчерашний «лидер рынка» и «король продаж» может легко и просто, а главное — невероятно быстро пропасть из информационного поля.

Невзирая на всю шумиху в прессе, пиар, известность, публичность и народную любовь.

Сегодняшняя история как раз про такую компанию:

Apricot Computers Ltd., originally Applied Computer Techniques Ltd. (ACT), was a British electronic company active from 1965 to 2005.

Как вам такие факты:

  • Who owned up to 30% market share in the UK, extended its sales in the USA and was ahead of IBM in the mid-80s in Europe?
  • Who was the first to launch speech recognition system for PC… in 1984?
  • Who introduced the first 3.5’’ floppy drive? The infrared trackball ? The keyboard with programmable functions keys along with a built-in LCD screen?
  • Who decided to deliver stylish designs, high resolution screens (800×400 in 1983), through a fully integrated conception in Scotland, allowing to manufacture in the early 90s one of the world’s most secure x86-based PCs?

Как видите, история более чем интересная и удивительная.

Так выглядел один из «абрикосов», предназначенный для корпоративного рынка:

Тут в высоком разрешении.

Название аппарата к кириллице разумеется отношения не имеет — на экране отнюдь не буква «Ж», а стилизованное «Xi».

Процесс загрузки Windows 1.0 на настоящем Apricot Xi:

Поскольку был найден эмулятор этих машин, я решил попробовать все это дело собрать и оживить.

Однако все оказалось не так просто и процесс написания этой статьи (вместе со сроками) пошел по п#зде не по плану, затянувшись на три месяца экзотических изысканий.

Эмулятор

Эмулятор компьютеров Apricot называется QDAE:

QDAE is a Quick and Dirty Apricot Emulator for Linux, Windows and MacOS X. This version emulates the Apricot F1, Xi and Portable; it may support other F-series and PC-series Apricots as well.

Основная разработка была закончена в далеком 2012 м году, собственно у файла Changelog, в котором находится описание изменений между версиями, дата последней модификации — май 2012 года.

И с тех пор проект не развивается, можно сказать заброшен.

Эмулятор полностью оправдывает название «Quick & Dirty», поскольку был создан действительно «на коленке», на основе кодовой базы DOS-приложения а стабильность его работы — как у вздорной девы.

Плюс документация, которой нет, ROM-файлы, которых тоже нет и экзотические машины из далекого прошлого, физического доступа к которым нет и не предвидится.

Но разумеется и таких мы #бем все это меня не остановило.

Готовая сборка QDAE существует только для Windows, как оказалось в дальнейшем, автор эмулятора создавал эти сборки с помощью кросс-компиляции из-под Linux, причем невероятно старым компилятором.

Хотя все эти замечательные нюансы всплывут уже потом, скачивая первый раз сборку этого чуда, ни о чем подобном я и не подозревал.

Исходники находятся на личном сайте автора, никаких копий на GitHub обнаружено не было.

Так что забирать придется оттуда:

wget https://www.seasip.info/Unix/QDAE/qdae-0.0.10.tar.gz

Также архив с исходниками присутствует в Windows-версии эмулятора — будет лежать в каталоге установленного приложения.

На всякий случай оставлю еще пару линков на сборки, поскольку непонятно как долго еще будет существовать личный сайт автора.

Образы ROM

Первой проблемой с этим эмулятором оказалось полное отсутствие ROM-файлов, необходимых для работы.

Сам автор с истинно британским юмором советует «снять дамп с работающей машины»:

For copyright reasons, QDAE is not supplied with any BIOS ROMs or
disk images. Accordingly, when you launch QDAE for the first
time, it will abort with the message: "Could not open f1.rom".
You will need a dump of the F1 ROM (the F10 ROM is not suitable;
the F2 ROM may work but has not been tested).

Если у вас есть возможность сгонять на выходные в Лондон, найти там одну из примерно таких сохранившихся машин:

И затем уломать владельца на проведение жестоких экспериментов с его музейным экспонатом — проблемы разумеется нет.

Но я был не в настроении путешествовать и подумал, будет разумнее поискать эти самые ROM в сети.

И нашел прекрасное:

Только вдумайтесь:

народ в UK за#бан копирайтерами до такой степени, что там ссутся выложить загрузочный образ для компьютера из 1980х, произведенного компанией, которой давно не существует.

Представляете как надо было запугать людей?

Зато обнаружился легкий намек на то, как эти самые образы можно получить:

Дальнейшие изыскания показали, что образы вообщем-то в сети есть, причем их довольно много.

Но есть нюанс:

Файлов ROM оказалось два.

А эмулятору нужен один.

Что это вообще такое и как быть?

Не буду утруждать читателя всей историей изысканий, но мои поиски в итоге привели к этому gist:

Use this script to merge a pair of even+odd / low+high roms into a single file. You'll need to do this for games which have 16-bit CPUs which use 8-bit ROMs. Then, once you've merged each high/low pair, concatenate all the merged pairs into one single file to use in your disassembler.

Приведу код скрипта целиком:

#!/usr/bin/perl
#
# Merge a pair of hi/low byte roms into a single file
# 
# Usage: merger.pl <low_or_even_byte_rom> <high_or_odd_byte_rom> >outputfile.bin
open LO, $ARGV[0] || die $!;
open HI, $ARGV[1] || die $!;

$i=0;
while(!(eof(LO) | eof(HI)))
{
   $a=getc(LO);
   print $a;
  
   $a=getc(HI);
   print $a;
}

Тут происходит чтение LO и HI-файлов, переданных в качестве аргументов а затем их побайтовая перекодировка в символы:

getc returns the next character from the input file attached to FILEHANDLE

В этом и была главная хитрость, выносившая мне мозг пару недель — надо не просто слить два ROM-файла в один, а еще и перекодировать.

Образы дисков

С дисками все оказалось сильно проще, они неплохо каталогизированы и доступны для скачивания:

Еще на известном Archive.org выложена огромная коллекция образов (~90Гб!), среди которых присутствуют интересные образы дисков и для машин Apricot. Часть из которых покажу в действии ниже.

Запуск и работа

При попытке запуска версии для Windows, эмулятор откажется работать, выдав сообщение о том что ROM-файлы не найдены:

ROM-файлы читаются из каталога ~/.qdae/Roms, либо из %USERPROFILE%/Documents/QDAE в Windows.

Однако имена самих файлов зашиты в коде, например для машины «Apricot F1» файл называется f1.rom.

Соответственно для того чтобы ROM-файл был найден эмулятором — недостаточно просто положить его в нужный каталог, нужно еще и соблюсти именование.

Напоминаю:

Без ROM-файлов эмулятор не заработает, совсем.

Как уже было отмечено выше, ROM-файл еще нужно собрать из двух частей, поскольку все доступные в интернете образы разделены на HI и LO части.

В качестве примера, покажу весь процесс на ROM-файле для Apricot F1.

Скачиваем архив, например отсюда или отсюда.

Как нетрудно догадаться по адресам сайтов, эти ROM были созданы для более известного и популярного эмулятора Mame, но мы ведь не ищем легких путей, правда?

В архиве будет два файла, которые необходимо соединить в один:

Вот так это выглядит:

perl merger.pl lo_f1_1.6.8f hi_f1_1.6.10f > f1.rom

Копируем полученный ROM в домашний каталог с эмулятора:

cp f1.rom ~/.qdae/Roms/

Дальше можно пробовать запускать c использованием образа диска apr00007.dsk:

/opt/own/qdae/bin/qdae ~/Downloads/apr00007.dsk 

Будет загружен MS-DOS 2.11 прямиком из 1984 года, так это выглядит:

Сборка

Если вы считаете себя нормальным или хотя-бы психически стабильным — просто скачайте готовую Windows-версию, благо она отлично устанавливается и затем запускается с помощью Wine.

Автор заморачивался со сборкой и кровавым патчингом этого страхоп#здилища только ради того чтобы повесить отрубленную башку чудовища над камином в качестве демонстрации собственной мощи и интеллекта.

Ради принципа и высоких достижений, короч.

Если вы простой обыватель — вам такое точно не надо.

А теперь рассказываю как это было.

Скачав и распаковав архив с исходниками:

wget https://www.seasip.info/Unix/QDAE/qdae-0.0.10.tar.gz
tar xvf ~/Downloads/qdae-0.0.10.tar.gz

получим каталог с набором трешевых исходников на C и C++ и скриптами сборки:

cd qdae-0.0.10
./configure --prefix=/opt/own/qdae

Сборка происходила на Linux Manjaro, поэтому ниже будут детали и особенности только по этому дистрибутиву.

Эмулятор использует известную библиотеку SDL, причем ее 1.х версию, убедитесь что она установлена:

Как видите, я использовал даже не саму 1.х версию а слой совместимости для более современного SDL2

Запускаем сборку командой make.

Первая ошибка, которая появляется при сборке на Linux выглядит так:

compress.c: In function ‘comp_open’:
compress.c:137:37: error: implicit declaration of function ‘major’ [-Wimplicit-function-declaration]
  137 |         if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == 2)) return DSK_ERR_NOTME;

Связана она с тем что функции major и minor объявлены устаревшими в заголовках текущей версии ядра Linux:

/* BSD defines `major', `minor', and `makedev' in this header.
   However, these symbols are likely to collide with user code, so we are
   going to stop defining them here in an upcoming release.  Code that needs
   these macros should include <sys/sysmacros.h> directly.  Code that does
   not need these macros should #undef them after including this header.  */
# define __SYSMACROS_DEPRECATED_INCLUSION
# include <sys/sysmacros.h>
# undef __SYSMACROS_DEPRECATED_INCLUSION

Для исправления, необходимо добавить использование заголовка sys/sysmacros.h в начало файла LibDsk/lib/compress.c и перезапустить сборку.

Следующая ошибка, также связанная с этой проблемой выглядит так:

drvlinux.c: In function ‘linux_open’:
drvlinux.c:182:13: error: implicit declaration of function ‘major’ [-Wimplicit-function-declaration]
  182 |         if (major(st.st_rdev) != 2) return DSK_ERR_NOTME;

Исправление аналогично предыдущей ошибке — просто добавляем:

#include <sys/sysmacros.h>

в начало файла LibDsk/lib/drvlinux.c.

После перезапуска сборки, появится куча ошибок вида:

f1_keyboard.cxx:57:32: error: invalid use of incomplete type ‘struct tm’
   57 |         pkt[ 3] = 0x403 | ((ptm->tm_hour % 10) << 4);
      |                                ^~

Связаны эти ошибки с изменением структуры заголовков, конкретно — с переносом описания структуры времени из sys/time.h в просто time.h.

Для исправления ситуации, необходимо добавить включение этого заголовка в файле bin/sysdep.h:

#include <time.h>

После исправлений, сборка наконец завершается успешно.

Однако собранный эмулятор откажется запускаться из каталога сборки:

Поэтому необходимо выполнить установку:

make install

В каталоге /opt/own/qdae появится сборка эмулятора, бинарник будет находиться в каталоге /opt/own/qdae/bin.

И уже отсюда собранный эмулятор можно наконец запустить.

Так выглядит успешный запуск эмулятора с правильным ROM-файлом, но без загрузочных дисков:

Мигающие индикаторы фиска и флоппи - легкий намек на отсутствующий загрузочный диск.

Казалось бы все и вот она — победа, достойный результат многомесячного превозмогания, гугления и #бли с ROM-файлами.

Увы, но нет — дела с этим эмулятором обстояли куда сложнее, чем казалось.

Внимание на экран:

На этом интересном месте происходит зависание и эмулятора и отладчика и эмулируемой ОС — проще говоря:

наступает полный п#здец.

Полный Пэ

Перед вами баг в эмуляторе компьютеров из 1980х от компании, которой больше не существует.

Доживших до наших дней, действующих компьютеров Apricot осталось крайне мало, ближайший находится где-то в Лондоне. И как-либо с ним поработать вам дадут только после кунилингуса лично королеве, с соответствующими шансами на успех мероприятия.

Сам эмулятор написан 20 лет назад, с использованием ископаемых технологий тех лет, активная разработка давно прекращена, сайт заброшен а сам автор не отвечает.

Чтобы просто запустить эту йобу, пришлось потратить месяц на поиск и сборку ROM-файлов.

Более-менее работает лишь Windows-версия, собранная последний раз в 2012м году.

Для Windows 7.

Мануалов фактически нет, исходный код внутри такой, что одним своим видом может напугать неподготовленного человека.

Даже без знания C/C++.

Ну что, взялись бы за работу по исправлению при таких-то вводных?

Письмо автору

На всякий случай сообщаю, что я не окончательно #бнутый, поэтому первым делом попытался написать автору эмулятора:

Greetings Mr. Elliott.
I'm trying to resurrect the QDAE emulator and found a problem that I cannot solve myself.
I was able to fix the build process on Linux, found and successfully merged ROM files, found working disk images. But when emulator loads any graphical environment (ex. Activity) — emulated OS crashes or reboots.
Same problem persist with all types of emulated machines: right after it goes into graphics mode — emulated OS reboots or crashes.
I’ve tried to use this «server version» of MS DOS, found some disk images without automatic start for graphics. That worked and was more-less stable. But without graphics. Not fun.
Then tried to reduce speed ticks (in source code) — down to 1000, 500 or even 100 — emulation has became much slower, but issue not gone.
Tried to use fake year (1985) instead of calculated from the current timestamp — also didn’t help.
I’m not asking for exact solution, just point to right direction, because issues like that always come from something small or stupid.
There were some minor fixes I did, related to missing headers (due to changes in Linux kernel sources) with date-time functions, but don't think that it could be responsible for described issue.

Как видите, прежде чем писать автору, было перепробовано много разных вариантов исправления ситуации, но ни один увы не сработал.

Хотя ответа я так и не получил, выяснил что почтовый адрес, мелькающий в исходниках более не существует.

Дорога приключений

Собственно при таких раскладах оставалось только два пути — закладки и ИТ потратить пару лет на ковыряние кривых исходников, либо попытаться восстановить сборку Windows-версии, поскольку та по какой-то причине продолжала работать.

Для этой статьи я выбрал второй путь.

Так выглядит установка Windows-версии QDAE в Wine:

Инсталлятор NSIS - проект на века ;)

Кстати на ролике выше используется новый 10й Wine, с режимом WOW64 — т.е одна и та же версия может запускать как 32 так и 64-битные приложения, без всяких отдельных префиксов:

Так выглядит запуск Windows-версии эмулятора в Wine:

ROM-файлы необходимо положить в каталог .wine/drive_c/Program\ Files\ \(x86\)/QDAE/Lib/Roms/ :

Изучение

Я решил применить свои «особые навыки» и залезть внутрь Windows-версии эмулятора, использовав PE Explorer, который весьма неплохо работает под Wine:

Ковыряем один эмулятор с помощью инструментов, запущенных в другом эмуляторе.

Конечно я догадывался, что шансов встретить серьезную защиту в таком ПО не очень много, поэтому не заняло много времени выяснить несколько важных деталей:

  1. Сборка Windows-версии осуществлялась кросс-компиляцией из Linux, с помощью MinGW окружения.
  2. Использовалась 32-битная версия компилятора и соответственно получился 32-битный бинарник.
  3. Использовалась отдельная библиотека ministl (набор заголовков), вместо обычного STL — см. ниже.

Версия MinGW, используемого автором для сборки эмулятора оказалась невероятно древней:

Чтобы вы оценили винтажность этой штуки, нашел информацию о релизе:

GCC-2.95.2 for Mingw (i386-mingw32) -- Release information
===================================================================

Release date: Nov 7, 1999.

I'm pleased to announce prebuilt gcc-2.95.2 packages for GNU Mingw
(i386-mingw32). 

1999 мать его год!

И вот этой ископаемой штукой, автор QDAE делал сборки своего эмулятора аж до 2012 года, причем из-под Linux.

Но это еще не все.

История с ministl

В каждой профессии обязательно есть вещи, о которых не принято говорить в приличном обществе.

Обычно это знание спрятано за семью замками и железной дверью, в самом темном углу, дорогу к которому вам не расскажут.

В случае программирования на C++ такой вещью является кастомный STL — «левая» реализация (от Васяна) стандартной библиотеки шаблонов «в переводе Гоблина».

Это самый темный угол C++, кладезь бесконечных и самых феерических багов, король дичи и программного треша, которые только можно сотворить в этом замечательном языке.

О самой возможности замены STL вам не расскажут вменяемые программисты, поэтому пишу отдельную статью по этой замечательной теме.

Думаю вы уже догадались, что автор QDAE как раз из таких использовал кастомный ministl при создании сборок своего эмулятора:

Тут должно быть драматическое молчание и МХАТовская пауза.

Чиним сборку с ministl

Если мы идем по пути восстановления сборки — придется пытаться собрать эмулятор с этим недоразумением вместо нормального, штатного STL.

Для этого необходимо запустить скрипт configure с указанием специального параметра:

./configure --with-ministl

И заново запустить сборку:

make clean
make

Разумеется сборка немедленно упадет:

Вы правда думали, что код на C++ из 1996 года соберется в современном окружении?

Хотя конкретно эта ошибка исправляется легко и просто — достаточно заменить устаревший заголовок <iostream.h> на просто <iostream>:

#include <iostream>

Сохраняем изменения в файле ministl/bstring.h и перезапускаем сборку.

Но вот дальше начинается ад:

За исправление такого треша мне и платят "кровавые шекели".

Вас ожидает простыня ошибок из самых разных интересных мест, общий смысл которых:

иди своей дорогой сталкер, тебе тут не рады

Как понять, что вас ждут п#здец, ад и погибель удивительные приключения и сутки тяжелой отладки?

Копирайт с датами начала 90х в заголовке исходника на C++:

Copyright (c) 1994-1995 Modena Software Inc.,

Стоит рассказать, откуда вообще взялся этот bstring.h, вот так выглядит его оргинал из 1996 года.

Дело в том что на свете есть одна известная и очень старая книжка по C++:

STL Tutorial and Reference Guide:
C++ Programming with the Standard Template Library

By David R. Musser and Atul Saini
Addison-Wesley Professional Computing Series
ISBN 0-201-63398-1 * Hardcover * 432 pages * 1996

Книга, повторюсь, известная (даже я о ней слышал), думаю кое-кто из читателей держал такую на полке в свое время:

В комплекте с книгой шли примеры исходного кода на C++, одним из которых как раз и был наш bstring.h

Но это все лирика, а реалии к сожалению таковы, что сил моих на исправление и переделку под современный C++17 этого древнего шаблона уже не хватило.

Точнее хватить-то хватило (наbstring.h), но обновленная версия ministl сломала весь остальной проект эмулятора, с концами.

Поэтому я его просто.. удалил.

Да, это еще одно тайное знание о заменяемом STL — возможность замещения системных шаблонов по частям.

На самом деле удалить нужно лишь файл string, из которого уже включается bstring.h:

rm ministl/string

Точно также я поступил и с vector.h, где вылезла следующая ошибка на тему новых стандартов и ограничений:

 error: ‘void* operator new(size_t, void*)’ may not be declared as static

Затем с list.h и ошибкой:

h6301.hxx:71:14: error: ‘list’ in namespace ‘std’ does not name a template type
   71 |         std::list<unsigned char> m_input;
      |              ^~~~

Наконец последняя ошибка, связанная с ministl:

Path.cxx:199:9: error: ‘sort’ was not declared in this scope; did you mean ‘short’?
  199 |         sort(v.begin(), v.end());
      |         ^~~~

«Исправил» ее я аналогичным образом — цинично удалив заголовок ministl/algorithm.

Разумеется так делать нельзя и в нормальном проекте за подобные выкрутасы вас скорее всего побьют, возможно даже ногами.

Но и использовать «васянские» STL вместо стандартных — экстрим еще тот.

Со всеми этими правками, костылями и патчами сборка эмулятора наконец успешно завершается.

(бурные аплодисменты)

Но только собранный эмулятор все также не работает, зависая ровно на том же самом месте.

Ну что ж, не фартануло.

З2 бита

Как мы уже успели выяснить выше, работающая сборка эмулятора под Windows — 32-битная и была создана 32-битным компилятором, поэтому следующий логичный шаг это попытка сборки 32-битной версии.

И скажу сразу:

в современной системе такая сборка — то еще скотство

Нужно будет установить gcc multilib и 32-битные версии библиотек: SDL и всех остальных используемых библиотек, например libxml2.

Так выглядит набор параметров, передаваемых скрипту configure для сборки и линковки 32-битного приложения в 64-битном окружении:

./configure --build=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32

Если скрипт и проследующая сборка пройдут без ошибок, в каталоге bin появится 32-битный бинарник:

Который наконец заработает как надо.

Результат

Показываю собственно результат:

эмулируемые системы Apricot в действии.

Full disk image: apr00230.dsk (635273 bytes)

apricot SOFTWARE
*** BETA TEST COPY ***
Date Issued:15/07/85  Return by:29/07/85
F1 (UK)
MSDOS 2.11 BIOS 1.6
Disk One - Activity, Tutor
Disk Two - Diary,Sketch,Async,GWBASIC
1F1U04B Disk 1 of 3

Как же хорошо что моя юность пришлась на годы, когда порно уже было цветным.

Full disk image: apr00256.dsk (307631 bytes)

APRICOT DEMONSTRATION
PICTURES
BIOS V1.4 JAN 1984

Так выглядел далекий предок Microsoft World

Full disk image: apr00076.dsk (324425 bytes)

24/4/84
PS
PSMATE
SUB-MASTER 211
NOT FOR RELEASE

Full disk image: apr00190.dsk (318828 bytes)

2.6 BOOT PC/XI
WITH LINKWORD
INC MSBASIC
MASTER 61

Full disk image: apr00264.dsk (729799 bytes)

BASIC GAMES, ENCHANTE,
MASON, QUEST MASTER 19

В качестве эпилога: