SPC info '95

SPC info '95

Strogino Programming Company © winter 1995, Moscow, Russia
Так выглядел этот выпуск электронного журнала на компьютере БК-0010.

Мы рады приветствовать Вас на страницах памяти Вашей БК0011 или в непрерывном адресном пространстве БК0010. Тем не менее, нельзя сказать, что именно радость, равно как и любая другая положительная эмоция, побудила нас к написанию статей в первый номер SPCinfo. Дело вот в чем. Технологии программирования во всем мире делают гигантские шаги вперед год за годом. Достаточно сравнить прошлогодние и новые программы, представляемые на конкурсы типа 4K-intro и 16K-intro. Программки размером 4К наводят на экране такие головокружительные эффекты, что глазам своим не веришь, посмотрев на индикатор тактовой частоты - 25 MHz! На прошлом конкурсе intro были куда слабее, да еще притормаживали на DX-33! Главное то, что независимо от роста мощности персональных компьютеров, растет мастерство, совершенствуется технология, изобретаются новые методы программирования.

Почему подобных тенденций не заметно на БК, нельзя сказать объективно, каждый имеет свое мнение на этот счет. Тем не менее, БК - очень интересный компьютер с точки зрения настоящего программиста, и такие программисты на БК есть. Более того, многие настоящие хакеры на PC прошли школу БК.

В то же время, множество владельцев БК образует некое унылое сонное царство, безо всякого энтузиазма ожидающее появление чего-нибудь сказочно интересного, что смогло бы его расшевелить, или же поголовного и бесплатного перехода на PC'шки.

И все же возникает иногда желание поковыряться в сборнике новых программ или почитать последние размышления (новостями это не назовешь) БК-шечников в газетах. Само собой, возникают мысли, которыми хочется поделиться с программистами, способными оценить и взять на вооружение наши идеи, а еще лучше - способными на собственные разработки в том же направлении, обладающие лучшими характеристиками. Поэтому все предлагаемые статьи рассчитаны на серьезных читателей.


MATH

Alexander Matchugovsky

На страницах (экранах?) многих газет авторы делятся с читателями полезными идеями и подпрограммами, что само по себе, конечно, интересно, но на практике зачастую неприменимо. Встречаются и более досадные моменты. Так, в одной из газет автор обещал в следующем номере поместить тексты программ умножения и деления, придуманные "крутыми мужиками из DEC'а"...

При всем уважении к Digital (и, возможно, к автору, если я все-таки вспомню, что это была за газета) такое заявление может вызвать праведный гнев программистов: "А когда будут опубликованы исходные тексты подпрограмм сложения и вычитания?!!". Такие поначалу у меня были мысли... Потом, где-то год спустя, решил я заняться векторной графикой на БК и понадобилась программа деления для вычисления тангенсов... Я, похоже, не такой крутой, как DEC'овские мужики, поэтому провозился над этой подпрограммой около часа. И тогда возникла мысль: а ведь есть наверное люди, которые программируют еще хуже меня, но (в отличии от меня) горят желанием сделать что-нибудь интересное. Может быть именно подпрограммки деления им и не хватает для осуществления своих замыслов? Следующего номера той самой газеты я так и не увидел, поэтому решил все-таки опубликовать свое решение (хотя, очень может быть, что оно совпадает с DEC'овским с точностью до имен регистров). Поскольку пишу я только в OS91 и даже не умею обращаться со всякими TURBO'ми, приводимая программа будет мало напоминать так называемые "исходники".

Вход: R1 - делимое, R2 - делитель. Выход: R0 - частное. Регистры R2 и R5 не портятся. Можете рассчитывать на скорость 2299 вызовов процедуры в секунду.

В ассемблере DEC порядок операндов обратный, по сравнению с ассемблером Intel.

Это, так сказать, программа минимум, т.е. R1 делится на R2 нацело и без остатка.

Есть более интересный и полезный вариант: R1 делится на R2, целая часть ответа помещается в R0, дробная - в R3. Заметьте, "дробная часть", а не "остаток"!. Таким образом Вы можете свободно делить меньшее число на большее и получать реальный ответ.

Что представляет из себя дробная часть?

Предположим, нам надо сложить два числа с дробной частью, представленных в предлагаемом формате:

R1 - целая часть первого слагаемого, R2 - дробная часть первого слагаемого, R3 - целая часть второго слагаемого, R4 - дробная часть второго слагаемого.

Прибавляем первое число ко второму:

Результат сложения в R3 (целая часть) и в R4 (дробная часть).

Просто, не правда ли? Зачем нужно такое представление чисел? Меньшее число делим на большее, берем дробную часть... Так рассчитывается скорость проигрывания оцифрованных инструментов для разных частот, так определяется тангенс угла наклона прямой при рисовании линии (об этом дальше) и многое другое.

А где же сама программа такого деления? Здесь:

Вход: R1 - делимое, R2 - делитель. Выход: R0 - частное (его целая часть), R3 - частное (дробная часть).

Втрое медленнее обычного деления, быстродействие - 699 вызовов в секунду.

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

Для начала замечу, что любую прямую в декартовой системе координат можно отнести к одному из двух условных классов: "почти горизонтальные" и "почти вертикальные". К первому классу отнесем прямые, у которых модуль разности Y-координат начальной и конечной точек меньше модуля разности X-координат этих двух точек. Остальные прямые отнесем ко второму классу. Что касается алгоритма рисования прямых, то он свой для каждого типа (т.е. по сути у алгоритма 2 частных случая).

Теперь тексты подпрограмм для обоих случаев: слева "почти вертикальные" линии, справа - "почти горизонтальные".

R0 - адрес экрана начальной точки, R1 - битовая маска начальной точки.

Достаточно короткие и быстрые подпрограммки, но для черно-белого режима 512*256 точек.

Теперь то же самое, но для цветного режима и с пояснениями:

Вход: R0 - адрес экрана начальной точки, R1 - битовая маска начальной точки в слове по адресу R0, R2 - длина прямой в точках, R3 - тангенс угла наклона прямой, R4 - дробная часть начальной точки (обычно 0), R5 - длина строки экрана в байтах (обычно 100).

Выход: R0 - адрес экрана конечной точки, R1 - битовая маска конечной точки в слове по адресу R0, R4 - дробная часть конечной точки. Регистр R5 не портится.

Теперь на каждую точку приходится по две команды сдвига ASL.

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

Кстати, откуда такие числа типа "129" и "699"?

Естественно, точно замерить быстродействие нельзя т.к. кроме всего прочего, каждая из приведенных программ выполняется по-разному в зависимости от входных данных. Поэтому отклонения от приведенных коэффициентов быстродействия могут колебаться в пределах плюс/минус 10 или даже больше. Окончание на "9" всего лишь подчеркивает, что значение приведено в десятичной системе счисления.

Вернемся к разбору подпрограммы рисования прямых.

1. Для начала вам надо определиться, какую прямую вы решили нарисовать: "почти горизонтальную" или "почти вертикальную", и в зависимости от этого после подготовки всех данных обращаться к той или иной подпрограмме. Пусть Вам известны координаты двух точек (X1,Y1,X2,Y2). Вычислите dX=│X2-X1│ и dY=│Y2-Y1│. Если dX>dY, то линия "почти горизонтальная".

2. Далее - длина прямой (помещается в R2). Если линия "почти горизонтальная", то R2=dX, иначе R2=dY.

3. Тангенс угла наклона (R3). Если линия "почти горизонтальная", то R3=dY/dX, иначе R3=dX/dY (меньшее делиться на большее). Рекомендуется поместить делимое в R1, делитель в R2 и вызвать вышеописанную процедуру деления (вторую). Тогда в R3 - готовый результат.

4. Экранный адрес начальной точки (R0). Известно, что в одном слове 16 бит, а поскольку экран БК кодируется по правилу 2 бита на точку, в одно слово помещается 8 цветных точек. Нетрудно определить, какому слову на экране принадлежит любая точка.

5. Какая же из восьми адресуемых регистром R0 точек является начальной для нашей прямой? Эту информацию несет регистр R1. Перечислим значения в восьмеричной системе счисления. R1=3, если точка самая левая в слове, R1=14, если точка чуть правей, R1=30, если точка третья слева в данном слове, далее R1=140, 300, 1400, 3000, 14000, 30000, R1=140000 - самая правая точка в слове, адресуемом R0.

6. R5=100, если линия рисуется сверху вниз, и R5=177700, если линия рисуется снизу вверх.

7. Плавная подстройка (R4). Тонкий и не всегда ощутимый момент. Попробуйте нарисовать прямую под углом 45 градусов. При R4=0 будет заметна лишняя ступенька, при R4=100000 - все гладко. Вообще, рекомендуемое значение - 100000, но если Вы собрались рисовать следующую линию из конечной точки предыдущей, то R4 лучше как раз не изменять (как, впрочем, и R0 с R1).

Немного о вычислении тангенса. Я порекомендовал для этого обращаться к подпрограмме деления с дробной частью... В общем случае без нее не обойтись, но в частном (для цветного режима, когда длина линии всегда <= 256 точек и помещается в 1 байт) возможна оптимизация. Используйте процедуру целочисленного деления, но добавьте в нее самой первой команду "SWAB R1", а самой последней - "SWAB R0". Теперь, правда, ответ будет не в R3, а в R0, но это поправимо.

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


HACK

Arseny Vinnikov

При всем уважении к Александру не могу не отметить, что не стоит возиться целый час там, где можно повозиться 15 минут.

Подпрограмма деления (входные данные те же):

Арсений сразу пишет в машинных кодах и не признает ассемблер.


STUDY

Ilya Udin

Хочу сегодня поговорить с вами о том, что нельзя сделать на 8-разрядных машинах. Это ни в коей мере не умаляет тех достоинств, которыми эти компьютеры обладают (и тот, кто считает, что у них одни недостатки, сильно заблуждается), а лишь помогает лучше понять возможности 16-разрядных машин.

Хочу сразу сказать, что если бы ячейки нумеровались 0, 1, 2, 3 и т.д. то адресуемая память - говорю тем, кто это понимает - увеличилась бы вдвое и составила бы 128 Кб.

Итак, думаю лучше всего будет начать с того, что всем (или по крайней мере большинству) знакомо. С Бейсика.

Basic!

Эта маленькая подпрограмма переведена с ассемблера, но сохранила свои возможности и, как можно заметить, благодаря этому пригодится даже тем, кто не знает ассемблера, но знает Бейсик. В чем же ее предназначение? Многие мои знакомые, обладающие опытом, знающие несколько языков программирования, в том числе и ассемблер (тот или иной), надолго задумывались. Особенно когда вместо трех точек стояли какие-либо операторы.

Вопрос, который я им задавал, звучал так: "Что делает эта подпрограмма?" Последний человек, отвечавший на него, думал около 5 минут, потом даже нарисовал стек на бумаге... Надеюсь, этот участок текста дал Вам возможность найти решение самостоятельно. Ответ же таков: участок, обозначенный тремя точками выполняется ровно два раза. При этом нет никаких счетчиков цикла, признаков и другой цикловой атрибутики. Хотите выполнить один раз - обращаетесь к подпрограмме командой "GOSUB 1010", два раза - "GOSUB 1000".


Продолжение: Часть 2