Шум в заводской столовой стоял сплошной, густой, замешанный на звоне алюминиевых вилок, грохоте жестяных подносов по трубчатым направляющим раздачи и запахе пережаренного лука. Воздух казался влажным и тяжелым от пара, поднимавшегося над огромными алюминиевыми кастрюлями с супом. Свободных мест не было. Люди ели быстро, сосредоточенно, изредка перекидываясь короткими фразами.
Морозов сидел за угловым столиком у окна, методично разрезая ребром вилки плотную, щедро обвалянную в сухарях столовскую котлету. Напротив него Евгений Громов совершал сложные акробатические маневры: левой рукой он удерживал на весу тетрадный листок в клеточку, защищая его от брызг подливки, а правой пытался зацепить скользкое картофельное пюре.
Между тарелками, прямо на влажной клеенке, лежала причина их спора.
— Относись к этому как к схеме, Женя, — Морозов указал вилкой на листок.
На бумаге убористым почерком Морозова была выведена всего одна длинная строка кода на языке Си. Короткая функция, вычисляющая день недели по заданной дате. Никаких громоздких условных переходов, никаких многоэтажных проверок. Только базовая арифметика, пара побитовых сдвигов вправо, заменявших деление на степени двойки, и в конце — тернарный оператор, изящно сводящий финальный выбор между двумя значениями в конструкцию с вопросительным знаком и двоеточием.
int get_day(int d, int m, int y) { return ((y -= (14 — m) / 12) || 1)? (d = (d + y + (y 2) — y / 100 + (y / 100 2) + 31 * (m + 12 * ((14 — m) / 12) — 2) / 12) % 7)? d: 7: 0; }
Громов наконец сдался, отложил вилку и пододвинул листок ближе, брезгливо огибая мокрый след от чьего-то чужого стакана.
— Это прекрасно и ужасно, — проворчал программист, всматриваясь в плотную вязь латинских символов. Он поднял взгляд на коллегу. — Нет, Алексей Николаевич, ты послушай. Это абсолютно прекрасно. Но это совершенно ужасно.
Он постучал тупым концом карандаша по сдвоенным угловым скобкам побитового сдвига.
— Да, компактно. Да, ты упаковал три экрана на ассемблере в одну строчку. Машинное время экономится, транслятор проглотит это вмиг. Но это же шифровка! За такое в приличном проекте по рукам бьют.
Морозов отпил компот из граненого стакана. Компот отдавал сухофруктами и хлоркой.
— Это выразительность, — возразил он, чувствуя давно забытый азарт чистого программистского спора, далекого от режимов, планов и нормоконтроля. — Язык позволяет тебе сжать мысль до формулы. Я ведь даже оператор «запятая» использовать не стал, чтобы не плодить банальные последовательные команды. Видишь эти две вертикальные черты? Чистая магия короткого замыкания через логическое «ИЛИ». Мощнейший трюк: этот костыль с единицей заставляет компилятор жестко споткнуться, зафиксировать точку останова и гарантированно обновить год прямо в полете, до начала основного расчета. Никакого неопределенного поведения, всё строго по стандарту! Ты просто говоришь машине: пересчитай год, проваливайся по условию в формулу, сдвинь биты в регистре, а в конце проверь — если истина, бери левое, если ложь — правое. Всё.
— Отлично, — Громов саркастично усмехнулся, прищурив уставшие глаза. — А теперь представь, что этот код через год откроет какой-нибудь вчерашний выпускник. И у него на входе окажется кривая дата. Например, тридцать второе мартобря. Знаешь, что сделает твоя гениальная формула с двойным «ИЛИ»? Она радостно зафиксирует твою точку останова, сдвинет биты, проглотит мусор, выплюнет тебе какой-нибудь «минус третий день недели» и пойдет дальше. А этот уставший выпускник будет три дня сидеть над распечаткой, пытаясь понять, в каком именно месте этой изящной строчки потерялся смысл.
Морозов кивнул, соглашаясь. Плотность кода радовала автора, но убивала того, кто приходил следом.
— Для производственного кода, — примирительно сказал Морозов, — один такой фокус хуже десяти скучных, но понятных процедур с комментариями. Согласен. Но я показываю тебе принцип. Если мы тащим Си на «Сферу», мы должны понимать, какую гибкость он дает…
— Вы не возражаете?
Голос прозвучал сверху, сухо и уверенно.
Морозов поднял голову. Рядом со столиком стоял человек лет тридцати. Худощавый, в очках с массивной роговой оправой и потертой фланелевой рубашке в крупную сине-белую клетку. В руках он держал стандартный жестяной поднос, на котором сиротливо жались тарелка с такой же котлетой, два куска серого хлеба и стакан чая.
Морозов оглядел столовую. Действительно, ни одного свободного стула. Он молча кивнул и сдвинул свою тарелку, освобождая край стола.
Незнакомец сел, аккуратно сгрузил посуду с подноса, сам поднос прислонил к ножке стола. Взял вилку и начал есть. Ел он быстро, механически, глядя прямо перед собой.
Громов, недовольный тем, что их прервали, снова пододвинул к себе листок.
— Гибкость он дает, — продолжил программист вполголоса, игнорируя соседа. — Только эта гибкость нам боком выйдет. Мы еще МикроДОС до конца не вычистили от мусора, а ты уже предлагаешь людям писать иероглифами.
Незнакомец в клетчатой рубашке замер с занесенной над тарелкой вилкой. Он медленно перевел взгляд на листок. Несколько секунд он просто разглядывал строчку вверх ногами, слегка наклонив голову — словно мысленно накладывал только что услышанные из их спора термины на чужие закорючки. Наконец, его взгляд зацепился за самый конец выражения.
— Я в этом языке не силен, — спокойно произнес он, не отрывая глаз от бумаги. — Но календарный остаток по модулю семь узнаю в любом гриме, даже перевернутым. Дело здесь не в иероглифах.
Громов медленно повернул голову. Во взгляде программиста читалось откровенное возмущение: мало того, что подсел, так еще и лезет в чужой код.
— Простите? — язвительно уточнил Громов.
Незнакомец отложил вилку на край тарелки и поправил очки на переносице.
— Вы сейчас полминуты спорили о том, как компактнее упаковать вычисление, и упадет ли компилятор на вашем «коротком замыкании». Но вы смотрите не туда.
Незнакомец ответил не сразу. Он методично доел картофельное пюре, собрал остатки подливки мякишем серого хлеба и отправил в рот. Затем не спеша вытер пальцы тонкой бумажной салфеткой.
Громов уже открыл рот для отповеди, когда сосед придвинул к себе чистую салфетку из пластикового стаканчика на столе.
— Запись изящная, спору нет, — спокойно произнес он. Из нагрудного кармана клетчатой рубашки появился цанговый карандаш. Тонкий грифель легко коснулся рыхлой бумаги, набросав три небольших блока. — Ожидание, прием, расчет. В лабораторных условиях сработает отлично.
Он провел дугообразную отводную стрелку вниз от среднего квадрата.
— На практике данные приходят грязными. Напряжение в кабеле просело, прошла наводка от цехового оборудования, пропал бит в кадре. Ваша короткая формула попытается честно прожевать этот мусор. В промышленной системе всегда закладывают запасной маршрут. Устройство должно четко понимать, куда уходить при получении битого формата, как очищать буфер и каким путем возвращаться к исходному ожиданию. Без страховки алгоритм просто зависнет до аппаратного сброса.
Громов нахмурился, разглядывая нарисованную схему. Откровенное раздражение сменилось профессиональной настороженностью. Морозов молчал. Ему определенно нравилась эта сухая логика практика, привыкшего не доверять физической среде.
— Вы из заводской АСУ? — спросил Морозов, внимательно разглядывая собеседника.
— Из нее, — незнакомец спрятал карандаш обратно в карман рубашки и снова взялся за вилку. — Точнее, был там до вчерашнего дня. Занимался сопряжением. Станки с ЧПУ, длинные линии, телетайпы. Там, знаете ли, линия может молчать секунду, может прислать половину кадра, а может повторить вчерашний ответ, потому что реле залипло. Если вы заранее не нарисуете, как машина выходит из ступора, потом весь цех будет бегать и искать крайнего.
Он отрезал кусок котлеты, отправил в рот. Прожевал.
— Меня, собственно, вчера перевели в ваш институт, в КБ. Сказали, собирают локальную сеть, а обмена толком нет, одни провода. Я после обеда собирался искать Алексея Николаевича Морозова. Говорят, он у вас там за главного.
Громов поперхнулся компотом. Закашлялся, прикрывая рот рукой, и сквозь кашель выдавил короткий смешок.
Морозов аккуратно промокнул губы салфеткой, не той, на которой были нарисованы состояния, а чистой. Отодвинул пустую тарелку.
— Нашли, — спокойно сказал он.
Незнакомец перестал жевать. Он перевел взгляд с откровенно ухмылявшегося Громова на Морозова, проглотил еду, взял стакан и кивнул.
— Вадим Сергеевич Кравец, — представился он. И добавил, указывая подбородком на тетрадный листок: — Я спорил не с должностью. Я спорил с кодом.
— И поспорили по делу, — ответил Морозов, не скрывая удовлетворения. Именно такой человек ему сейчас был нужен. — Допивайте чай, Вадим Сергеевич. Сказок не обещаю, но автомат состояний вам рисовать придется много.
Они вышли из столовой в гулкий, выкрашенный до половины зеленой масляной краской коридор первого этажа. Кравец нес свой пустой поднос к окну приема грязной посуды, машинально выверяя шаг, чтобы не столкнуться со встречными инженерами.
— Значит, так, Вадим Сергеевич, — Морозов шел рядом, заложив руки в карманы брюк. — В декабре мы собрали на столе сеть-кольцо. Три машины. Одна передает маркер, вторая принимает, третья слушает. Написали простенькую программу на ассемблере, пакеты пошли. Для лабораторного отчета этого хватило.
Кравец сгрузил поднос в окно, где грузная женщина в белом фартуке с грохотом сортировала тарелки. Вытирая руки о штанины, он повернулся к Морозову.
— На столе всё всегда работает, — сухо заметил он. — Какая длина кабеля была?
— Три метра, — подал голос Громов, шагавший с другой стороны. — Идеальные условия.
— Понятно, — Кравец чуть скривил губы. — А теперь вы хотите вытянуть это в реальный цех или соседнее здание. И вдруг выяснится, что провод ловит наводки от сварочного аппарата, земля у машин разная, а половина данных бьется в пути.
— Именно, — кивнул Морозов. — У нас физику линии тянет опытный аналоговик старой школы, а пакеты перебрасывает молодой программист. И между ними зияет дыра. Железо отдельно, код отдельно, а как машина реагирует на сбой связи — толком не описано, а у нас на всё рук не хватает.
Они подошли к широкой лестнице, ведущей на верхние этажи.
— Нам нужен нормальный профиль сопряжения, — сформулировал Морозов, поднимаясь по ступеням. — Чтобы при потере пакета ЭВМ не висла, а писала ошибку, ждала и запрашивала повтор. Буфер, кадр, контрольная сумма. Проект СФ-ЛИНК-81. Возьметесь?
Кравец не задавал лишних вопросов о зарплате или рабочем месте. Его мозг уже переключился в режим проектирования.
— Что считается потерей сообщения? — спросил он на ходу, глядя на ступени под ногами. — Отсутствие несущей или несовпадение контрольной суммы?
— И то, и другое, — ответил Громов.
— Кто имеет право держать маркер при старте системы? Как разрешаются коллизии, если две машины одновременно решат, что сеть пуста?
— Вот об этом вы и будете спорить с Птицыным и Петром Ивановичем, — Морозов остановился на площадке третьего этажа.
Коридор здесь выглядел иначе. Зеленую краску сменили светлые панели, на полу лежал свежий линолеум, но главное — путь преграждала массивная деревянная стойка с прозрачным стеклом наверху. Внутренний пост ВОХР. Физическая граница режима.
За новым столом сидел дежурный. Тот самый молодой, скуластый парень в безупречно застегнутой форме, который охранял этот периметр с января. Перед ним лежала пухлая, прошитая суровой ниткой амбарная книга. Обычный НИИ остался позади. Здесь начиналась рабочая зона КБ «Сфера».
Морозов достал из кармана пропуск — красную книжечку со спецотметкой. Громов молча положил свою рядом.
— Добрый день, — Морозов кивнул охраннику. — К нам пополнение. Направление из отдела кадров должно быть у вас в списках. Кравец Вадим Сергеевич.
Дежурный бросил сухой, цепкий взгляд на подошедшего и начал водить пальцем по списку, пришпиленному к деревянной столешнице.
— Есть такой. Предписание номер сорок два, — коротко отчеканил он. — Ваш паспорт.
Кравец достал из заднего кармана брюк документ. Охранник въедливо сверил фотографию с оригиналом, затем аккуратно переписал данные в журнал.
— Распишитесь, — дежурный развернул книгу к Кравцу. — И напоминаю: вынос любых бумаг, носителей, чертежей или радиодеталей за периметр — строго по сопроводительной ведомости.
— Понял, — Кравец быстро поставил размашистую подпись.
Металлический язычок турникета с лязгом освободил проход, впуская их внутрь.
В лаборатории КБ-3 стоял привычный рабочий гул. На центральных столах громоздились осциллографы, мотки проводов и серые корпуса будущих серийных машин.
Саша Птицын сидел у окна, сгорбившись над разобранным блоком питания. Он аккуратно выпаивал подозрительный конденсатор, но, заметив Морозова, отложил паяльник и вытер лоб тыльной стороной ладони.
— Алексей Николаевич, я тут по питанию посмотрел… — начал он.
— Питание потом вместе с Любой проверите, — спокойно ответил Морозов. — Подойди сюда, Саш. У нас к тебе сетевой вопрос.
Птицын вытер руки куском ветоши и подошел.
— Знакомься. Это Вадим Сергеевич Кравец, — Морозов указал на нового инженера. — Он из заводской АСУ. Поможет довести наш кольцевой обмен до нормального рабочего вида.
Кравец окинул Птицына оценивающим, чуть скептическим взглядом. Молодой парень, очки набекрень, пальцы в следах от канифоли. Классический паяльщик-энтузиаст.
— Это вы написали тестовую программу для декабрьского прогона? — спросил Кравец без предисловий.
— Нет, основу писал Евгений Александрович, а я сейчас перевожу её на прерывания и кольцевой буфер, — Птицын слегка выпрямился, почувствовав вызов.
— Как программа обрабатывает ситуацию, когда пакет ушел, а подтверждение о приеме не вернулось?
Вопрос прозвучал сухо. Это была классическая проверка на «синдром кустарной самоделки», когда машина намертво зависает, ожидая потерянный байт. Птицын даже не моргнул.
— Аппаратный таймер отсчитывает сто миллисекунд, — спокойно ответил Саша. — Если к этому моменту подтверждения нет, программа сама сбрасывает регистр приемника, пишет код ошибки в кольцевую таблицу состояний и инициирует повторный запрос. Никаких глухих зависаний.
Кравец чуть приподнял брови, обдумывая ответ. Он явно ожидал услышать про ручной сброс и перезагрузку.
— Аппаратный таймер и сброс регистра? — Кравец посмотрел на Птицына с появившимся уважением. — Для лабораторного стенда весьма недурно. Кто подсказал?
Громов, стоявший чуть позади, довольно усмехнулся.
— Старшие товарищи подсказали, — честно признался Птицын. — Заставили развязать логику и посадить обрыв на таймер. Но код я сам переписал.
— Значит, мы сработаемся, Александр, — кивнул Кравец, окончательно сменив тон. — Раз вы понимаете, что такое время ожидания линии, мне не придется объяснять вам азы. Осталось только привести ваш журнал к нормальному промышленному виду.
Птицын серьезно кивнул.
— Если скажете, как правильно формировать этот журнал для цеха — сделаю. Мне главное, чтобы железо из-за помех не простаивало.
Морозов удовлетворенно наблюдал. Кравец не стал давить авторитетом, а Птицын — защищать недоработку.
— Обустраивайтесь, Вадим, — Морозов указал на свободный стол у стены. — Птицын выдаст вам распечатки кода и введёт в курс дела по «Сфере» и каталогу рабочих дискет. И Петра Ивановича отыщите, он где-то в соседней комнате макет собирает. А у нас с Женей еще одно дело.
Коридор заканчивался массивной деревянной дверью. У маленького столика дежурный подвинул Морозову прошнурованный журнал с красной диагональной полосой. Алексей Николаевич вписал время, расписался и передал ручку Громову. Замок сухо щелкнул.
За порогом пахло мастикой, старой бумагой и металлом. Воздух казался пересушенным. Под потолком ровно гудели люминесцентные лампы. Центр комнаты занимали четыре массивных стола, сдвинутые в прямоугольник и застеленные зеленым сукном. У стены темнел серый сейф, перетянутый шпагатом с пухлой пластилиновой печатью, рядом на тумбочке стоял аппарат прямой связи. Вычислительную машину для группы обещали выделить из новой малой партии после сборки в лаборатории. Сейчас на сукне лежали папки, мотки многожильных кабелей, разъемы и стопки номерных бланков.
Горелов поднялся навстречу, кивком указывая на свободные стулья.
— Проходите. Павел Андреевич вас уже заждался.
Ширяев стоял у окна, держа двумя руками плотный запечатанный пакет. Тамара Николаевна Егорова у стола аккуратно перекладывала листы через синюю копирку.
— Осторожнее с бланками, — тихо попросила она, сдвигая стопку на край. — Свежая копирка, легко смазать.
Ширяев подошел к столу, удерживая пакет на весу.
— Уральский промышленный узел, Алексей Николаевич, — тихо произнес он. — Транспортная задача. Маршрутизация грузов, комплектование партий, тоннаж, устранение встречных порожних пробегов. Ваши ребята после Олимпиады придумали отличные эвристики для отсечения тупиковых вариантов расчёта. Для учебных задач алгоритмы работают блестяще. Здесь же цена ошибки измеряется реальными вагонами, забитыми путями и сорванными сроками.
Морозов отодвинул стул и сел.
— Алексей Николаевич, на крупном узле картина меняется постоянно, — Ширяев положил запечатанный пакет на край стола. — Заявки, свободные вагоны, подача платформ, путевые ограничения сыплются весь день. Как одна машина справится с этим потоком?
— Зависит от архитектуры, — ответил Морозов. — Диспетчерская система реального времени работает по своим законам. Проверяемый расчетный цикл требует иного подхода.
— Мне нужен плановый расчет и возможность пересчитать маршруты при сбое, — Ширяев говорил как прагматик, привыкший к работе на земле. — Диспетчер обязан видеть свежую сводку. При этом ему предстоит подписывать конкретный результат на конкретный час.
Морозов обдумал сказанное, выстраивая архитектуру будущего рабочего места.
— Значит, создание живой информационной системы оставим на следующие этапы. Иначе зароемся. Первую версию научим считать утвержденные срезы данных циклами: утренний план, внеплановый пересчет, вечерняя сверка. Обязательно заложим механизм для спорного прогона.
— Тогда какие параметры пойдут в ведомость учета? — спросила Егорова, выравнивая край стопки бланков с синей копиркой. — Допустим, мы берем утренний срез данных и получаем ответ. Чтобы при спорном прогоне выйти на те же цифры, нам нужно зафиксировать точное состояние машины на момент старта.
— Загрузку с гибких дискет оставим для лабораторной подготовки, — отозвался Громов. — Штатный запуск пойдет из аппаратного блока ПЗУ-82В. Внутри поместим урезанную МикроДОС и сам расчетный модуль. При включении питания машина проводит самотест оборудования, проверяет контрольную сумму зашитой программы на целостность и автоматически запускает приложение. Потребуется обновить математику — физически меняем ПЗУ, ставим свежую пломбу и вписываем номер версии в режимный журнал.
Ширяев посмотрел на ровную стопку бланков перед Егоровой.
— Алексей Николаевич, крупный транспортный узел содержит сотни станций, перегонов, ограничений по тоннажу. Заставлять оператора вбивать такие объемы с нуля ради каждого расчета гибельно. Смена закончится раньше первого ответа.
Морозов коротко обрисовал схему разделения данных:
— Сформируем базовый справочник узла: станции, типы платформ, постоянные лимиты. Его готовят заранее, утверждают, снабжают версией и контрольным числом. Этот блок загружают один раз. В каждом цикле человек вводит исключительно оперативный срез: свежие заявки, свободные вагоны, временные запреты на участках.
Громов потер подбородок.
— Питание можно держать включенным всю смену. При этом любой прогон программа оформляет как самостоятельный пакет. Высчитывает контрольную сумму введенного оперативного среза, прикрепляет к ней текущую версию базового справочника и номер зашитого модуля.
Горелов придвинул чистый лист, быстро делая пометки.
— Запишем этот порядок в основу технического задания. Оператор набивает срез. Контролер сверяет ввод по номерным листам. Диспетчер получает отпечатанный бумажный бланк как готовую команду.
Ширяев сделал согласный жест.
— Приемлемо. Раздельный учет справочника и среза дает воспроизводимость: тот же справочник, тот же срез и тот же модуль дают тот же ответ. Полноценную систему с диспетчерской сводкой на экране пока отодвигаем в перспективу.
Шрамов постучал карандашом по сукну.
— Штатная проверка ОЗУ остается первым шагом. После нее для 82В нужен расширенный пусковой контроль. Проверка самого блока ПЗУ-82В, подсчет контрольной суммы расчетного модуля, опрос узлов ввода-вывода и подтверждение готовности АЦПУ. При любом аппаратном отказе блокируем старт вычислений и выдаем код неисправного узла, чтобы техник сразу видел, где искать.
— Встроим эти процедуры в стартовый блок, — кивнул Громов. — Выполним их сразу после проверки памяти, до передачи управления расчетному модулю.
Сбоку раздался металлический стук. Чернов бросил на стол тяжелый многоконтактный штекер.
— Машину будут перевозить. Обычные разъемы потеряют контакт после третьего переподключения, а платы пострадают от дорожной тряски. Закладывайте штекеры с винтовой фиксацией.
— Учтем в требованиях, — ответил Морозов и обратился к координатору, — Андрей Витальевич, запишите это в ТЗ отдельными пунктами. Разведите первый этап и перспективу. По срокам предлагаю двигаться так. К концу недели собираем бумажную схему рабочего места и формы бланков. Через две недели демонстрируем макет ввода и печати на общей «Сфере», когда ее освободят от дневных задач. К моменту получения первой машины из опытной партии у нас должен лежать черновой блок ПЗУ-82В с расширенным пусковым контролем, проверкой сумм и автоматическим запуском модуля.
Ширяев опустил тяжелый палец на правый нижний угол будущего документа, который Горелов начал расчерчивать.
— Вот здесь оставьте место. Дата расчета, контрольная сумма среза. И пустая строка — «Ответственный исполнитель». Диспетчер принимает лист как финальную команду к действию, цифры внутри машины аппаратно блокируются от оперативных корректировок.
Горелов молча приложил деревянную линейку, отчеркнул внизу широкую полосу и пододвинул штемпельную подушку поближе к пакету с уральскими маршрутами.