Этим летом я занимался созданием нового приложения для машины, продажи которой закончились в 1980 году, и которая не была рассчитана на поддержку графики, сети и даже букв в нижнем регистре. Её продавала компания, обанкротившаяся десяток лет назад. Приложение было специально разработано под единственного пользователя — моего отца, которому в позапрошлую пятницу исполнилось семьдесят лет. Представляю вашему вниманию MTS-70:
Программа MTS-70 была разработана для Radio Shack
TRS-80 Model 1 (примерно 1979 год). У неё есть шесть уникальных и очень забавных функций, неинтересных никому, кроме меня и (в идеале) моего отца (инициалы которого, разумеется, MTS):
- Чат с Dadbot — инстансом gpt-3.5 с fine-tuning на основе текстовых переписок между мной и отцом на протяжении пятнадцати лет.
- Воспроизведение «Happy birthday» (через 500-бодный кассетный вывод данных; этот хак был необходим из-за отсутствия нативной поддержки звука в TRS-80).
- Морской прогноз на сегодня, в том числе прогнозы прилива и течений.
- Поиск ближайших концертов и мероприятий в Ист-Энде Лонг-Айленда (где живёт мой старик).
- Текстовая адвенчурная игра на основе LLM о выживании летом в Ист-Энде, дополненная забавными семейными байками.
- Игра в го (на доске 9×9 против достаточно сильного локального игрового движка).
▍ Почему TRS-80?
В моём детстве отец всегда говорил о своём TRS-80 с благоговением. Это был первый купленный им компьютер, когда он открывал
свою юридическую фирму. Отец предавался тёплым воспоминаниям об этой машине: однажды зимой прямо над компьютером начало течь с потолка, отец просто отключил компьютер, положил на бок, дождался, пока тот высохнет, а потом снова включил его. (И следующей зимой инцидент повторился!)
Моим первым компьютером был SE/30, так что у меня нет непосредственной ностальгии по TRS-80, который отец примерно при моём рождении поменял на Mac 512k. Тёплые чувства я позаимствовал из этих коротких чужих воспоминаний; а ещё я понимал, как старик любит эту машину, истинного первопроходца эпохи зарождения персональных компьютеров.
Поэтому этой весной, придумав проект по превращению деталей старых электрических пишущих машинок в USB-клавиатуры (у меня было
много запчастей), я купил на eBay для экспериментов TRS-80. (Всё оборудование TRS-80 отец хранил в чулане, но я решил, что разумней будет ломать какую-нибудь другую машину!) Я выбрал идеальный момент — RetroStack выложил на GitHub
репозиторий именно для этой цели — применения Arduino, соединённого с адресными шинами клавиатуры TRS-80. Я достаточно быстро собрал устройство, хоть и пришлось немного поработать над кодом, чтобы решить проблему дребезга контактов.
▍ Возвращаемся в 1979 год
Создание матрицы клавиатуры было интересным занятием, но мне этого не хватило. Вся Model 1 находится внутри клавиатуры, поэтому у меня осталась на выброс целая машина в отличном состоянии. А я слышал так много хорошего о TRS-80, но пока ни разу не работал с ней. Единственная проблема заключалась в том, что купленный мной компьютер был недоукомплектован, его продавали без аксессуаров и проводов питания. Погуглив, я узнал, что в Model 1 использовался комически сложный нестандартный кабель питания, подававший сочетание переменного и постоянного токов через разъём DIN-5.
Я собрал собственный блок питания, а позже изготовил специальную печатную плату,
спроектированную @maboytim. (Также мне удалось многое узнать о цепи из
схемы блока питания, реверс-инжининг которой выполнил Shock Risk.) Для этого потребовалось множество проб и ошибок. Я
по-прежнему не до конца понимаю, как работают двухобмоточные трансформаторы с выведенной средней точкой. Где-то внутри я надеюсь, что мне и не придётся это понимать. Но у меня получился отлично работающий самодельный блок питания.
Благодаря
переходнику с TRS-80 на композитный видеокабель с 8-Bit Classics и адаптеру вывода видео с RCA на HDMI я смог использовать в качестве дисплея свой MacBook. Я задержал дыхание и включил машину. Узрите: она запустилась!
Однако дальше запуска дело не пошло. TRS-80 загружал данные с кассет (хотя и поддерживал 5,25-дюймовые гибкие диски через отдельный интерфейс расширения). Я узнал, что существует широкая поддержка архивирования данных с кассет и их воспроизведения; обычно это делается при помощи Windows-приложения
PlayCAS. Благодаря
инструкциям по управлению TRS-80 мне стало известно, что загрузка команд на BASIC с кассет начинается с простой команды
CLOAD.
Однако проблема заключалась в том, что у меня не работала клавиша «A». Поэтому я вернулся на eBay, где и купил
запасной переключатель для клавиатуры TRS-80, после чего установил его.
Вот теперь можно и начинать. Я запустил PlayCAS в эмуляторе Windows XP при помощи UTM на M1 MacBook Air и отправил кассетные данные через компьютерный разъём для наушников на
кабель звукового входа TRS-80. Отлично, теперь можно загружать практически любые программы, созданные для TRS-80.
(Кстати, позже я узнал, что можно просто преобразовывать файлы BASIC в аудиофайлы WAV и загружать из напрямую с Mac, а не использовать специальный инструмент. Это возможно благодаря чудесному приложению командной строки
trs80-tool.)
▍ Возвращаемся в 2024
Загрузка программ заставила меня задуматься о том, можно ли вывести компьютер онлайн. Возможно, кто-то уже создал последовательный интерфейс или связь TCP/IP? Оказалось, уже есть множество таких проектов! На форумах любителей @GK2001 выложил
подробное описание разработанной им карты RS-232. Позже я нашёл на компьютере отца интерфейс расширения, к которому была подключена карта RS-232, хоть мне так и не удалось заставить правильно работать двусторонний последовательный интерфейс (даже после замены большинства интегральных схем карты!).
Но самым важным было обнаружение
TRS-IO пользователя @apuder. TRS-IO — это карта, подключаемая к 40-контактному слоту расширения TRS-80 и эмулирующая большую часть функциональности исходного интерфейса расширения. Она добавляет 32 КБ эмулируемой ОЗУ, часы реального времени и рудиментарное подключение к Интернету через карту на ESP32. В более новых версиях даже появился вывод HDMI через FPGA-карту. Мне понадобились
месяцы, чтобы заставить правильно работать TRS-IO. Самые новые версии карты предназначены для поверхностного монтажа, поэтому я неделями сидел, скрючившись за своей рабочей станцией, глядя через лупу и припаивая крошечные соединения. Благодаря этому я сильно прокачал навыки пайки SMD, но в конечном итоге мне удалось собрать только более раннюю и простую версию платы. Также мне пришлось учиться компилировать и прошивать код ESP32, а также изучать Verilog, который применялся для создания FPGA-карты Tang Nano 9k (но потом я всё же сдался). Это был безумно сложный процесс обучения. Лучший совет, который я могу дать: подружитесь с @apuder и @maboytim на Discord-сервере Tandy и тщательно изучите все закрытые issue в репозитории TRS-IO на GitHub.
Чего я только ни пробовал делать, чтобы TRS-IO заработала. Я экспериментировал с удалением аддонов, например, официальной модификации Radio Shack, добавлявшей буквы в нижнем регистре. Выполнял сложные инструкции по прошивке современных чипов EEPROM самыми новыми версиями TRS-80 ROM просто на случай, если причиной проблем с TRS-IO были более ранние версии. (Это практически точно не так). Для этого понадобилась ещё одна печатная плата, которую я заказал из Китая (спасибо @maboytim и
модулю адаптера @dannybloe); я собрал её вручную, прошил двоичным файлом TRS-80 ROM при помощи
программатора EEPROM и установил её в компьютер. Настоящее безумие.
И, разумеется, в процессе всего этого машина полностью перестала работать. Я потратил несколько недель на
восстановление платы и систематическую замену всех DIP-переключателей и интегральных схем, чтобы вывод видео снова заработал. Это был настоящий парадокс корабля Тесея в действии. Я купил ручной осциллограф, но пока не разобрался с ним. Думаю, мне повезло. Мне не удалось бы ничего сделать без
Sams Computerfacts (примерно 1985 год) и
руководства по устранению неполадок.
Ещё кучу времени я потратил на то, чтобы починить видеодисплей отцовского TRS-80. Трубка нагревалась и работала ручка настройки яркости, но я не мог получить никакого сигнала с TRS-80. Благодаря руководству по обслуживанию и
постам на любительских форумах я попробовал почти всё, от восстановления видеоплаты до замены разных редких и уже не изготавливаемых транзисторов. В конце концов, я выяснил, что у меня не одна, а несколько проблем: после того, как я заменил транзистор 2n3906 видеоплаты и присоединил ВЧ-дроссель на L2 основной платы, всё заработало; однако мне всё равно приходится использовать хак для инъецирования композитного сигнала, потому что я так и не разобрался, почему не работает собственный вход TRS-80. Мне повезло, что меня не поджарило при работе с этим ЭЛТ-дисплеем, не повторяйте этого дома.
Когда же всё, наконец, заработало, я ввёл с клавиатуры TRS-80
?MEM, увидел, что вместо 16 КБ ОЗУ доступно 48 КБ, и едва не расплакался. После этого работа пошла гораздо быстрее.
Получив наконец IP-адрес благодаря TRS-IO, я, разумеется, первым делом подумал о том, как подключить GPT-4. Оказалось, меня обогнал в этом @druid77, выпустив прошлой осенью
TRS-GPT. Его код, созданный на основе примера WHOIS из репозитория TRS-IO, очень мне помог.
После этого я один за другим начал собирать маленькие модули. Вдохновлённый примером TRS-GPT, я запустил на своём Mac скрипт на Python, выполнивший всю сложную работу, и воспользовался помощью ChatGPT для создания и совершенствования программы на BASIC, которая позволила бы мне создать демо всех важных для отца функций. ChatGPT пригождалась мне множество раз, например, когда я не мог разобраться, как переключиться с порта 43 на порт 5050, потому что он передавался через аппаратный интерфейс в каком-то формате старших и младших битов, который для меня был совершенно непонятен.
Так я всё, наконец, доделал. Ниже я чуть подробнее расскажу о каждой из функций, которые можно выполнять на MTS-70.
▍ Воспроизведение «Happy birthday»
У TRS-80 Model 1 отсутствует возможность воспроизведения звука. Похоже, кто-то придумал, как использовать способность сохранения данных на кассеты, чтобы издавать простой писк (а из-за создаваемых машиной невероятно сильных радиопомех, вероятно, можно просто поставить рядом с ней AM-радиоприёмник и перехватывать вывод). Я не смог найти подробной документации и не разобрался в найденном исходном коде, основная часть которого была написана на ассемблере, а не на BASIC. Впрочем, со временем я обнаружил
руководство по «взрослым» играм для TRS-80 из начала 80-х, которое начиналось с чёткого набора инструкций и даже звукового драйвера, резервирующего часть ОЗУ и определяющего функции для преобразования битов в звуки.
Запустив на телефоне приложение для определения тона, я смог при помощи примеров звуков из книги преобразовать звуки данных в конкретные ноты, а добавив маленький динамик с внешним питанием, получил Happy birthday.
▍ Игра в го
Это тоже была интересная задача. Мой отец любит играть в го и может часами заворожённо продумывать ходы. Сначала я подумал, что можно просто заставить играть в го GPT-4, но она справлялась ужасно. (Думаю, для этого нужно создать или выполнить fine-tuning определённой модели наподобие AlphaGo.)
Немного поискав, я обнаружил
gnugo — работающий в командной строке движок го, имеющий ASCII-интерфейс и представляющий собой достойного противника. Мой скрипт на Python открывает подпроцесс и отправляет команды gnugo в терминал, а затем генерирует доску в ASCII, передаваемую TRS-80. Игра происходит на доске размером 9×9, в основном потому, что экрана не хватает даже для 19×19! Движок оказался достаточно хорош, чтобы увлечь моего отца и вызвать бормотание «хмм...», «любопытно...» и «ха!». (Было бы ОЧЕНЬ здорово подключить эту систему к API наподобие
предоставляемого online-go.com, тогда стала бы возможна игра с другими игроками и в полном формате!)
▍ Владение домом как ролевая игра
Мои родители живут в милом доме в заливе Лонг-Айленда. Отцу всегда нравилось называть его «Лесом у моря», и это стало основой для небольшой текстовой адвенчуры под управлением GPT-4. Я ввёл в GPT-4 промт системы, в которой назначил себе роль хранителя подземелья, добавив несколько сюжетных моментов из жизни моих родителей, а также цветастый лор, накопленный за десятилетия жизни в доме, чтобы это казалось очень реалистичным. В промте говорилось о таких опасностях, как приезжающие летом из Хэмптона туристы, стрижка лужайки и чистка бассейна, а также о борьбе с береговой эрозией. (Любопытный факт: да, однажды родители
схлестнулись со вдовой Джона Стейнбека Элейн: они спорили по поводу поддержания удобства проезда через их собственность на принадлежащий им небольшой кусочек берега.)
В каком-то смысле это было самое простое из мини-приложений, но при демонстрации проекта оно поразило мою семью больше всего. Мне пришлось напомнить им, что в игру невозможно выиграть, и что они просто играют в RPG, пока им не надоест. Наверно, то же самое можно сказать и о домовладении?
▍ Общение с Dadbot
После создания
Joshbot я, разумеется, должен был попробовать свои силы в Dadbot. С ним добиться хороших результатов оказалось на удивление трудно, я всё ещё продолжаю его отлаживать. Исходный материал здесь
очень разнится: это всего лишь моё текстовое общение с отцом (использованное для этой цели с его согласия), которое часто было кратким и деловым; иногда его очень сложно разбить на пары «вопрос-ответ», потому что, разумеется, некоторые тексты оставались без ответа и накапливались. Я создал в Google Sheets макрос для GPT-4 для генерации дополнительных сообщений, чтобы получить пары «вопрос-ответ» для fine-tuning GPT-3.5. (Я также попробовал использовать GPT-4o, но с 3.5 результаты оказались гораздо более правдоподобными!)
Но всё равно мне очень весело общаться с моим поддельным робопапой через этот интерфейс. Крайне рекомендую.
▍ Мероприятия и погода
Я решил добавить функции получения морского прогноза и местных концертов, потому что отец всегда любил прогулки на лодке и ночную жизнь Ист-Энда. Для этого мой серверный скрипт на Python просто подтягивает локальные данные. Данные о погоде берутся из источников NOAA и NWS от выбранных местных метеостанций; они конкатенируются и передаются через сокет TCP/IP. Мероприятия берутся из календаря событий Ист-Энда, парсинг которого я выполняю при помощи своей Python-библиотеки icalendar. Меня не перестаёт удивлять просмотр свежей и актуальной информации через древний интерфейс компьютера.
▍ Наша жизнь с Tandy
Итак, если вас интересует, как была воспринята MTS-70, то могу сказать, что в день рождения она стала громким хитом. Учитывая то, что этот проект возник из чужой ностальгии по TRS-80, мне было удивительно наблюдать за благоговением отца перед этой древней технологией.
Что касается меня, то моя ностальгия состояла из смешанных чувств. Этот проект сражался со мной
на каждом из этапов. Серьёзно, для его реализации мне понадобилось три месяца, чего я совершенно не ожидал. Иногда чипы ROM ломались просто потому, что я косо на них посмотрел. В то же время было видно, что это очень надёжная машина. И мне было очень приятно работать со столь знаковой технологией, ставшей предком всего того, что мы знаем и любим сегодня в мире компьютеров. Удивительно мне было и иметь дело с машиной, которая после запуска в буквальном смысле загружает интерфейс программирования BASIC. Работа с TRS-80 действительно
неотличима от программирования!
Приятно было и увидеть, насколько велико сообщество любителей TRS-80. Спустя пятьдесят лет я нахожу огромное множество плат расширения, эмуляторов, клонов и утилит, предназначенных для поддержания жизни этого компьютера. Это живая и вдохновляющая область, и мне было интересно побыть малой её частью.
На этом опыт моего взаимодействия с TRS-80 не закончится. Я продолжаю работать над проектом, который, если всё пойдёт по плану, позволит TRS-80 и SE/30 общаться друг с другом.
P.S. Любопытный факт! Чип Z80, лежащий в основе TRS-80,
прекратили производить только в этом году, спустя более чем пятьдесят лет. Какое же огромное наследие он оставил.
Результат можно увидеть на видео здесь
Проект MTS-70 можно изучить на
Github.
Telegram-канал со скидками, розыгрышами призов и новостями IT 💻