ZX Forum
#04
19 ноября 1997 |
|
Новые 40 лучших процедур - скроллинг экрана, слияние двух картинок, инвертирование экрана, поворот символов, замена атрибутов, заливка замкнутого контура, вычисление адресов в экране, копирование части экрана и т.д.
(c) Колотов Сергей, г.Шадринск, SerzhSoft, июль, 1997. НОВЫЕ "40 ЛУЧШИХ ПРОЦЕДУР" В 1992 году на страницах ZX-РЕВЮ был опубликован сокра- щенный перевод книги Дж.Хардма- на и Э.Хьюзон "40 лучших проце- дур". Публикация вызвала самые восторженные отклики читателей, ведь многие начинающие синкле- ристы именно с ее помощью нако- нец-то смогли преодолеть труд- ности "барьера машинного кода". Но вот проходит ровно пять лет, и старожилы ZX РЕВЮ с удивлением замечают в первом номере за 1997 год до боли знакомое название. Все многочисленные доводы, так убедительно изложенные ИН- ФОРКОМОМ, конечно же, во многом правильны. Но на мой (да и не только на мой) взгляд, они так и не дают права издателям народно- го журнала тратить драгоценные страницы ZX-РЕВЮ на печать уже опубликованного в свое время ма- териала. Вместо рубрики "РЕТРО" гораз- до полезнее и актуальнее было бы ввести раздел "РЕМЕЙК". А в нем печатать не просто старые ма- териалы, а рассматривать их бо- лее глубоко, приводить примеры более эффективной реализации программ и отдельных процедур. Взять хотя бы те же "40 про- цедур". Да, данная работа очень полезна для начинающих. Но уже чуть более опытные знатоки ас- семблера сразу заметят, что чем больше по обьему приводимая ав- торами процедура, тем неизменно она имеет и больше недостатков, более неэффективно реализована, имеет большее количество "лиш- них" команд... Да, некоторые "лучшие процедуры" сокращаются более чем вдвое! И еще: коммен- тарии к программам расположены за самими листингами, что очень затрудняет понимание "а что именно происходит при выполне- нии процедуры на определенном этапе". Конечно, дано описание типа "регистр C копируется в ре- гистр B", но вот та смысловая нагрузка, которая за этим стоит, понятна далеко не всегда... Далее будет приведена библио- течка, в которую интегрированы графические процедуры, заново переписанные по принципу "соро- ка лучших". Объем занимаемой па- мяти уменьшился с 1444 байт до 861 байта! Каждая процедура де- тально прокомментирована в самом ее листинге, так сказать, - "не отходя от кассы". см. Листинг и шестнадцатерич- ный дамп. Многие процедуры в своей ра- боте требуют некоторые заранее определенные значения - констан- ты. Под эти значения выделе- на специальная область памяти, адресуемая меткой CONSTS. В дан- ном случае CONSTS указывает на адрес 23296, но, конечно же, этот адрес можно изменить на лю- бой другой. Длина области кон- стант 8 байт. При выполнении лю- бой из процедур ни одна из кон- стант не изменяется. А иначе пришлось бы их называть перемен- ными... В процедурах, манипулирующих с координатами точек на экране, остчет идет в отличие от бейси- ка не снизу-вверх, а наоборот - сверху-вниз. Такой отсчет коор- динат гораздо удобнее и исполь- зуется во многих других компью- терах. Теперь можно указывать координату Y от 0 до 191 (вместо 175), т.е. появляется возмож- ность указывать координаты тех точек на экране, которые находя- тся в двух нижних строчках, от- водимых под сообщения об ошиб- ках. При отсчете же снизу-вверх, максимальной Y-координатой явля- ется Y=175, а до нижних двух строк вообще не добраться. КРАТКОЕ ОПИСАНИЕ ПРОЦЕДУР 1. ASRL_LF - процедура сдви- гает весь экран атрибутов (цве- тов) влево. Правая колонка за- полняется атрибутом из ячейки по адресу CONSTS (23296). Длина процедуры 22 байта (было - 23 байта). Оттранслирована под ад- рес 62000 (HEX: #F230). 2. ASRL_RG - сдвиг всего экрана атрибутов вправо. Левая колонка заполняется атрибутом из CONSTS. Длина процедуры 21 байт (19 байт). Располагается по ад- ресу 62022 (#F246). 3. ASRL_UP - сдвиг всего экрана атрибутов вверх. Нижняя строка атрибутов заполняется из CONSTS. Длина процедуры 19 байт (21 байт). Адрес: 62043 (#F25B). 4. ASRL_DN - сдвиг всего экрана атрибутов вниз. Верхняя строка заполняется атрибутом из CONSTS. Длина: 20 байт (21 байт). Адрес: 62062 (#F26E). 5. SSRL_LF - сдвиг всего экрана влево на один символ (графика). Правая колонка знако- мест очищается. Длина 20 байт (21 байт). Адрес: 62082 (#F282). 6. SSRL_RG - сдвиг всего экрана вправо на один символ. Левая колонка знакомест очища- ется. Длина 19 байт (22 байта). Адрес: 62102 (#F296). 7. SSRL_UP - сдвиг всего экрана вверх на один символ. Нижняя строка знакомест очища- ется. Длина 55 байт (68 байт). Адрес: 62121 (#F2A9). 8. SSRL_DN - сдвиг всего экрана вниз на один символ. Верхняя строка знакомест очи- щается. Длина 55 байт (73 бай- та). Адрес: 62176 (#F2E0). 9. PSRL_LF - сдвиг всего экрана влево на один пиксел (графика). Правая колонка пиксе- лей очищается. Длина 16 байт (17 байт). Адрес: 62231 (#F317). 10. PSRL_RG - сдвиг всего экрана вправо на один пиксел. Левая колонка пикселей очища- ется. Длина 17 байт (17 байт). Адрес: 62247 (#F327). 11. PSRL_UP - сдвиг всего экрана вверх на одну линию пик- селей. Нижняя строка пикселей очищается. Длина 38 байт (91 байт). Адрес: 62264 (#F338). 12. PSRL_DN - сдвиг всего экрана вниз на одну линию пиксе- лей. Верхняя строка пикселей очищается. Длина 38 байт (90 байт). Адрес: 62302 (#F35E). 13. SCR_MRG - слияние двух картинок (графика, по принципу ИЛИ). Двухбайтная константа по адресу CONSTS должна содержать адрес размещения второй картин- ки в памяти (накладываемой). Ре- зультат помещается на экран. Длина процедуры 17 байт (раньше - 21 байт). Адрес размещения: 62340 (#F384). 14. SCR_INV - инвертирование экрана (графика, по принципу НЕ). Все пикселы меняют свое значение на противоположное. Длина процедуры 12 байт (было - 18 байт). Адрес: 62357 (#F395). 15. SINV_UD - инвертирова- ние символа вертикально. Стре- лка, направленная вверх, стано- вится направленной вниз, и нао- борот. В двухбайтной переменной по адресу CONSTS должен содер- жаться адрес изменяемого симво- ла. Длина процедуры 20 байт (так и было). Адрес размещения: 62369 (#F3A1). 16. SINV_LR - инвертирова- ние символа горизонтально. Стре- лка, направленная влево, стано- вится направленной вправо, и на- оборот. В двухбайтной переменной по адресу CONSTS должен содер- жаться адрес изменяемого симво- ла. Длина процедуры 17 байт (бы- ло - 19 байт). Адрес размещения: 62389 (#F3B5). 17. SROTATE - вращение сим- вола по часовой стрелке на 90 градусов. В двухбайтной перемен- ной по адресу CONSTS должен со- держаться адрес изменяемого сим- вола. Длина 26 байт (раньше - 42 байта). Адрес: 62406 (#F3C6). 18. ACHANGE - изменение зна- чения атрибутов всех символов экрана. Побитная операция. В ячейке по адресу CONSTS должна содержаться маска битов: те би- ты, которые установлены в маске, остаются в атрибутах прежними, а биты, которые в маске имеют ну- левое значение - будут иметь ну- левое значение и в атрибутах (о- перация И (не "Ы"!)). В ячейке по адресу CONSTS+1 должен нахо- диться байт, включенные биты ко- торого будут введены во все ат- рибуты экрана, т.е. если в этом байте какой-либо бит включен, то он будет установлен и во всех атрибутах (операция ИЛИ). Длина процедуры 16 байт (21 байт). Ад- рес: 62432 (#F3E0). 19. AREPLC - поиск атрибу- тов с определенным значением и замена каждого найденного тако- го атрибута новым значением. В ячейке по адресу CONSTS должно содержаться значение байта, под- лежащего замене (что искать). В ячейке по адресу CONSTS+1 дол- жно находиться значение замещаю- щего байта (чем заменять). Дли- на процедуры 18 байт (22 байта). Адрес: 62448 (#F3F0). 20. PAINT - закрашивание оп- ределенной области экрана, огра- ниченной линией пикселей (залив- ка). Стартовая точка задается помещением ее координаты X по адресу CONSTS, а координаты Y - по адресу CONSTS+1. Если коорди- ната Y больше 191 или точка в указанных координатах уже уста- новлена, то программа экстренно прерывается. Эта процедура не перемещаема из-за вызовов проце- дуры POINT. При закраске активно используется стек - на нем запо- минаются координаты линий залив- ки. Когда закрашивается большая область сложной формы, необходи- мо и большее свободное простран- ство в ОЗУ - между окончанием BASIC-программы и адресом, ус- тановленным оператором CLEAR (содержимое системной переменной RAMTOP). Если места в памяти не хватит, то может произойти сбой. Процедура занимает 88 байт, а вместе с процедурой POINT - 123 байта, что более чем в два раза меньше длины процедуры 1992 года (263 байта!) Адрес PAINT: 62466 (#F402). 21. POINT - вычисление адреса точки в экране по заданным коор- динатам и проверка состояния этой точки (ON/OFF). Внимание! Эта процедура может быть исполь- зована только из машинных кодов (запуск из бейсика ничего не даст). Перед вызовом необходимо установить в регистре E коор- динату X (0..255), а в регистре D - координату Y (0..191) прове- ряемой точки. На выходе процеду- ра установит в регистровой паре HL адрес байта на экране, в ко- тором находится точка, а в реги- стре C - маску точки в этом бай- те (один бит, установленный в единицу). В зависимости от того, включена точка или нет, устанав- ливается флаг нуля: Z - точка не включена, NZ - точка включена. Если точка установлена (видима), то регистр A (аккумулятор) сов- падает по своему значению с ре- гистром C, а если точка не уста- новлена, то A обнуляется. Ре- гистр B всегда на выходе из про- цедуры равен нулю. Длина проце- дуры 35 байт (в оригинале заняла бы около 70 байт). Адрес разме- щения: 62554 (#F45A). 22. PFIGURE - построение лю- бой ранее определенной фигуры (шаблона) на экране. Координа- ты начальной (стартовой) точ- ки задаются аналогично процедуре PAINT. Шаблон задается в строко- вой переменной BASIC'а A$ (можно изменить на любую другую, чуть скорректировав ассемблерный лис- тинг или дамп). Строка символов имеет следующий формат (немного отличается от оригинала): "5" - уменьшить X-координату "6" - увеличить Y-координату (отсчет идет сверху-вниз) "7" - уменьшить Y-координату "8" - увеличить X-координату "0" - поместить точку. Любые другие символы игнори- руются. Если строковая перемен- ная не существует или не содер- жит никакой информации, то про- грамма прерывает свою работу. Контроля на выход начальной Y- координаты нет, т.к. часть фигу- ры все же может быть видна. Поэтому проверка на выход за пределы экрана введена в сам цикл формирования шаблона. Воз- можность 'wrap-round' сохранена, т.е. по прежнему, при выходе X-координаты за левую часть эк- рана, шаблон появляется справа, и наоборот. Процедура не перемещаема. Длина PFIGURE: 98 байт, а вмес- те с используемой подпрограммой POINT - 133 байта, что все рав- но гораздо меньше оригинала (196 байт). Адрес: 62589 (#F47D). Если "раскрыть" вызов процедуры POINT, то PFIGURE станет переме- щаемой и будет занимать при- мерно 125 байт! 23. PSCALER - копирование ча- сти экрана в другую область это- го же экрана с возможным увели- чением копии по X и/или по Y. Используются константы: Адрес Имя Комментарий CONSTS X1_OLD одна из двух начальных X-координат прямоуг-ка CONSTS+1 Y1_OLD одна из двух начальных Y-координат прямоуг-ка CONSTS+2 X2_OLD одна из двух начальных X-координат прямоуг-ка CONSTS+3 Y2_OLD одна из двух начальных Y-координат прямоуг-ка CONSTS+4 XSCALE масштабность увеличения по X CONSTS+5 YSCALE масштабность увеличения по Y CONSTS+6 X_NEW координаты левого верхнего угла области экрана, CONSTS+7 Y_NEW в которую производится копирование. Координаты начального прямоу- гольника для копирования задают- ся в константах X1_OLD, Y1_OLD, X2_OLD, Y2_OLD, причем, могут располагаться в любой последова- тельности. Процедура сама опре- делит наименьшую и наибольшую координаты. Экстренный выход из процедуры происходит в следующих случаях: 1. XSCALE=0 - масштаб увеличения по X равен нулю 2. YSCALE=0 - масштаб увеличения по Y равен нулю 3. Y_NEW>191 - новая координата Y выходит за пределы экрана 4. Y1_OLD>191 - старая координа- та Y1 выходит за пределы эк- рана 5. Y2_OLD>191 - старая координа- та Y2 выходит за пределы эк- рана. Как и в оригинале, в програм- ме нет контроля, который про- верял бы возможность размещения новой картинки на экране. Если этого не получается, то может произойти сбой. При выполнении процедура вна- чале закидывает на стек битовый образ копируемого прямоугольника экрана и лишь затем прорисовыва- ет его в новом месте, увеличивая при необходимости. Поэтому, если на стеке недостаточно места, то, как и в процедуре PAINT, мо- жет произойти зависание, сброс, ошибка... Если Вы хотите, чтобы скопи- рованный кусок экрана имел тот же размер, что и данный, то необходимо установить масштаб 1:1 - занести в константы XSCALE и YSCALE по единичке. При двой- ном размере там должны быть дво- ечки, ну и так далее... Процедура не перемещаема из-за использования подпрограм- мы POINT. PSCALER занимает 174 байта, а вместе с POINT - 209 байт. В любом случае, это гораз- до меньше, чем оригинал - 335 байт! Адрес размещения: 62687 (#F4DF). Итак, вот Вы и ознакомились с новой реализацией "лучших проце- дур". Но советую не обольща- ться - некоторые процедуры на- верняка можно сократить еще... Правда, при этом неизбежно при- дется чем-то пожертвовать: ско- ростью выполнения, перемещаемо- стью или, наконец, просто потра- ченным временем. Надеюсь, что приведенные в этой статье прог- раммы будут Вам полезны, в край- нем случае, - может быть, они просто натолкнут Вас на какие- нибудь мысли... Начинающие мо- гут попробовать сравнить проце- дуры 1992 года с новыми, изучить принципы создания более эффек- тивных программ, приемы для ин- теграции множества различных процедур в одну большую библио- теку... Опытные же программисты, возможно, получат немало удо- вольствия, ехидно посмеиваясь над данной работой. Но это тоже плюс: повеселить народ - очень нужное дело! Так что желаю всем читателям ПРИЯТНОЙ РАБОТЫ С ЛЮ- БИМЫМ SPECCY! 140. ;--------------------------------------------------------------; ;3 40 New Best Routines (graphic) ; ;3 (c) SerzhSoft, Shadrinsk, may-june, 1997 ; ; old length: 1444 bytes new length: 861 bytes ; ;--------------------------------------------------------------; ORG 62000 ;адрес ассемблирования ;--------------------------------------------------------------; CONSTS EQU 23296 ;адрес буфера констант (8 байт) ;--------------------------------------------------------------; ;Сдвиг атрибутов влево (22<=23) ;--------------------------------------------------------------; ASRL_LF LD DE,#5800 ;DE=адрес первого байта атрибутов LP_ASLF LD H,D ;скопировали DE в HL LD L,E ; и увеличили HL на единицу: INC HL ; HL=адрес второго байта атрибутов LD BC,#001F ;<длина линии атрибутов> - 1 LDIR ;сдвиг линии атрибутов влево LD A,(CONSTS) ;цвет заполнения после сдвига LD (DE),A ;устанавливаем новый атрибут INC DE ;переход к следующей линии снизу LD A,D ;если атрибуты уже кончились, CP #5B ; и мы набрели на буфер принтера, JR C,LP_ASLF ; то STOP, иначе сдвигаем дальше RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг атрибутов вправо (21<=23) ;--------------------------------------------------------------; ASRL_RG LD DE,#5AFF ;адрес последнего байта атрибутов LP_ASRG LD H,D ;скопировали DE в HL - LD L,E ; последний байт линии атрибутов DEC HL ;предпоследний байт линии атрибутов LD BC,#001F ;<длина линии атрибутов> - 1 LDDR ;сдвиг линии атрибутов вправо LD A,(CONSTS) ;цвет заполнения после сдвига LD (DE),A ;устанавливаем новый атрибут DEC DE ;переход к следующей линии сверху BIT 3,D ;если мы все еще в атрибутах, JR NZ,LP_ASRG ; то повторяем цикл для сл. линии RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг атрибутов вверх (19<=21) ;--------------------------------------------------------------; ASRL_UP LD HL,#5820 ;адрес второй линии атрибутов LD DE,#5800 ;адрес первой линии атрибутов LD BC,#02E0 3;перемещать: 23 линии по 32 байта LDIR 3;сдвигаем 23 нижние линии вверх LD A,(CONSTS) ;цвет для заполнения нижней линии LP_ASUP LD (DE),A ;устанавливаем новый атрибут INC E ;если заполнили всю последнюю линию JR NZ,LP_ASUP ; (E=0), то прерываем цикл RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг атрибутов вниз (20<=21) ;--------------------------------------------------------------; ASRL_DN LD HL,#5ADF ;адрес конца второй линии снизу LD DE,#5AFF ;адрес конца самой нижней линии LD BC,#02E0 3;перемещать: 23 линии по 32 байта LDDR 3;сдвигаем 23 верхние линии вниз LD A,(CONSTS) ;цвет для заполнения верхней линии LP_ASDN LD (DE),A ;устанавливаем новый атрибут DEC E ;если дошли до самого первого байта JR NZ,LP_ASDN ; области атрибутов (E=0), то STOP LD (DE),A ; и устанавливаем этот байт RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг влево на один символ (20<=21) ;--------------------------------------------------------------; SSRL_LF LD DE,#4000 ;начало области графики LP_SSLF LD H,D ;адрес первого LD L,E ; байта линии INC HL ;адрес второго байта линии LD BC,#001F ;сколько байт сдвигать LDIR ;сдвиг линии влево на 1 байт XOR A ;обнулили аккумулятор и занесли LD (DE),A ; в последний (правый) байт линии INC DE ;переход к следующей линии (снизу) LD A,D ;если атрибуты CP #58 ; "еще не видать", JR C,LP_SSLF ; то повторяем цикл для сл. линии RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг вправо на один символ (19<=22) ;--------------------------------------------------------------; SSRL_RG LD DE,#57FF ;последний байт области графики LP_SSRG LD H,D ;адрес последнего байта LD L,E ; текущей линии DEC HL ;адрес предпоследнего байта LD BC,#001F 3;сдвигаем: 31 байт LDDR ;сдвиг линии графики вправо XOR A ;очищаем аккумулятор и затем LD (DE),A ; первый (левый) байт текущей линии DEC DE ;переход к следующей линии выше BIT 6,D ;если мы еще не "набрели" на ПЗУ, JR NZ,LP_SSRG ; то продолжаем крутить цикл RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг вверх на один символ (55<=68) ;--------------------------------------------------------------; SSRL_UP LD DE,#4000 ;начало экранной области LP_SSU1 PUSH DE ;сохраняем адрес линии на стеке LD BC,#0020 3;в линии - 32 байта LD A,E ;В регистре DE находится адрес ADD A,C ; верхней линии. В регистре LD L,A ; HL необходимо получить адрес LD A,D ; линии, лежащей ниже с шагом 8. JR NC,GO_SSUP ; Для этого к регистру E прибав- ADD A,#08 3; ляем 32 и заносим в L. Если про- GO_SSUP LD H,A ; изошло переполнение, то H=D+8 LDIR 3;перенос одной линии (32 байта) POP DE ;восстанавливаем адрес начала линии LD A,H ;проверяем: а не пора ли нам закру- CP #58 3; гляться? (перенесли все 23 ряда) JR NC,LP_SSU2 ;если да, то переход на очистку INC D ;---------------------------------; LD A,D ; DOWN_DE AND #07 ; стандартная последовательность JR NZ,LP_SSU1 ; команд для перехода на линию LD A,E ; вниз в экранной области ADD A,#20 ; (для регистра DE) LD E,A ; JR C,LP_SSU1 ; на входе: DE - адрес линии LD A,D ; на выходе: DE - адрес линии ниже SUB #08 ; используется аккумулятор LD D,A ; JR LP_SSU1 ;---------------------------------; LP_SSU2 XOR A ;очистка аккумулятора LP_SSU3 LD (DE),A ;и с его помощью - INC E ; очистка одной линии изображения JR NZ,LP_SSU3 3; всего: 32 байта LD E,#E0 ;переход к следующей INC D ; (нижней) линии изображения BIT 3,D ;заполнили весь последний ряд? JR Z,LP_SSU2 ;если нет, то продолжаем заполнять RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг вниз на один символ (55<=73) ;--------------------------------------------------------------; SSRL_DN LD DE,#57FF ;адрес последнего байта графики LP_SSD1 PUSH DE ;сохранили адрес конца линии LD BC,#0020 ;длина одной линии изображения LD A,E ;в регистре HL SUB C ; получаем адрес LD L,A ; конца линии, LD A,D ; лежащей выше JR NC,GO_SSDN ; исходной с шагом SUB #08 ; в 8 пикселей (линий): GO_SSDN LD H,A ; HL=откуда копировать; DE=куда LDDR ;перенос одной линии графики POP DE ;восстанавливаем адрес конца линии BIT 6,H ;если мы уже не в экране, JR Z,LP_SSD2 ; то переходим на очистку LD A,D ;---------------------------------; DEC D ; UP_DE AND #07 ; стандартная последовательность JR NZ,LP_SSD1 ; команд для перехода на линию LD A,E ; вверх в экранной области SUB #20 ; (для регистра DE) LD E,A ; JR C,LP_SSD1 ; на входе: DE - адрес линии LD A,D ; на выходе: DE - адрес линии выше ADD A,#08 ; используется аккумулятор LD D,A ; JR LP_SSD1 ;---------------------------------; LP_SSD2 XOR A ;очистка аккумулятора LP_SSD3 LD (DE),A ;очистка одной DEC E ; линии изображения: JR NZ,LP_SSD3 3; (31 байт) LD (DE),A ;очищаем самый первый байт линии LD E,#1F ;переход к следующей (верхней) DEC D ; линии ряда из восьми линий BIT 6,D ;мы еще не попали в ПЗУ? JR NZ,LP_SSD2 ;если нет, то очищаем дальше RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг влево на один пиксел (16<=17) ;--------------------------------------------------------------; PSRL_LF LD HL,#57FF ;адрес последнего байта графики LP_PSL1 OR A ;сбрасываем флаг переноса CF LD B,#20 3;в одной линии - 32 байта LP_PSL2 RL (HL) ;CF<-[сдвигаемый байт]<-CF (влево) DEC HL ;переход к предыдущему байту линии DJNZ LP_PSL2 ;цикл сдвига для одной линии BIT 6,H ;мы еще в экране? JR NZ,LP_PSL1 ;если да, то сдвигаем след. линию RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг вправо на один пиксел (17) ;--------------------------------------------------------------; PSRL_RG LD HL,#4000 ;адрес первого байта графики LD C,#C0 3;сдвигать - 192 линии LP_PSR1 OR A ;CF=0 для пустой колонки слева LD B,#20 ;число байт в одной линии LP_PSR2 RR (HL) ;сдвиг одного байта вправо INC HL ;следующий байт линии изображения DJNZ LP_PSR2 3;сдвигаем всю линию - 32 байта DEC C ;уменьшаем счетчик линий JR NZ,LP_PSR1 ;если сдвинули все линии, то STOP RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг вверх на один пиксел (38<=91) ;--------------------------------------------------------------; PSRL_UP LD DE,#4000 ;адрес начала графики (верх. линия) LP_PSU1 LD H,D ;скопировали адрес начала LD L,E ; линии графики в HL LD BC,#0020 ;размер одной линии INC H ;---------------------------------; LD A,H ; DOWN_HL AND #07 ; стандартная последовательность JR NZ,GO_PSUP ; команд для перехода на линию LD A,L ; вниз в экранной области ADD A,C ; (для регистра HL) LD L,A ; (здесь ADD A,C вместо ADD A,#08) JR C,GO_PSUP ; на входе: HL - адрес линии LD A,H ; на выходе: HL - адрес линии ниже SUB #08 ; используется аккумулятор LD H,A ;---------------------------------; GO_PSUP PUSH HL ;сохраняем адрес нижней линии LDIR ;переброска изображения снизу-вверх 140. POP DE ;DE - адрес нижней линии LD A,H ;мы еще находимся в области графики CP #58 ; или уже наткнулись на атрибуты? JR C,LP_PSU1 ;если все еще графика, то повтор XOR A ;обнуляем аккумулятор и с его LP_PSU2 LD (DE),A ; помощью очищаем самую INC E ; нижнюю линию изображения JR NZ,LP_PSU2 ; после сдвига экрана вверх RET ;выход из процедуры ;--------------------------------------------------------------; ;Сдвиг вниз на один пиксел (38<=90) ;--------------------------------------------------------------; PSRL_DN LD DE,#57FF ;адрес последнего байта графики LP_PSD1 LD H,D ;скопировали адрес последнего LD L,E ; байта линии в HL LD BC,#0020 ;ширина одной линии изображения LD A,H ;---------------------------------; DEC H ; UP_HL AND #07 ; стандартная последовательность JR NZ,GO_PSDN ; команд для перехода на линию LD A,L ; вверх в экранной области SUB C ; (для регистра HL) LD L,A ; (здесь SUB C вместо SUB #08) JR C,GO_PSDN ; на входе: HL - адрес линии LD A,H ; на выходе: HL - адрес линии выше ADD A,#08 ; используется аккумулятор LD H,A ;---------------------------------; GO_PSDN PUSH HL ;сохраняем адрес верхней линии LDDR ;переносим 1 линию сверху - вниз POP DE ;адрес верхней линии стал текущим BIT 6,H ;пока еще не попали в ПЗУ - JR NZ,LP_PSD1 ; продолжаем цикл по линиям XOR A ;очищаем аккумулятор и с его LP_PSD2 LD (DE),A ; помощью - самую верхнюю линию DEC E ; изображения после сдвига JR NZ,LP_PSD2 ; всего экрана вниз LD (DE),A ;очистка самого первого байта RET ;выход из процедуры ;--------------------------------------------------------------; ;Слияние картинок (17<=21) ;--------------------------------------------------------------; SCR_MRG LD HL,(CONSTS) ;взяли адрес картинки из ячейки LD DE,#4000 ;адрес экранной области LP_SCRM LD A,(DE) ;байт изображения с экрана OR (HL) ;"слили" с байтом картинки в памяти LD (DE),A ;и поместили назад в экран INC HL ;следующий байт картинки в памяти INC DE ;следующий байт экранной области LD A,D ;проверка на окончание CP #58 ; экранной области JR C,LP_SCRM ;если не кончилась, то повторяем RET ;выход из процедуры ;--------------------------------------------------------------; ;Инвертирование экрана (12<=18) ;--------------------------------------------------------------; SCR_INV LD HL,#57FF ;последний байт экранной области LP_SCRI LD A,(HL) ;взяли байт изображения с экрана CPL ;проинвертировали его LD (HL),A ;и поставили обратно DEC HL ;двигаемся к началу области BIT 6,H ;если "перевалили" через начало, JR NZ,LP_SCRI ; то STOP, иначе крутим цикл RET ;выход из процедуры ;--------------------------------------------------------------; ;Инвертирование символа вертикально (20) ;--------------------------------------------------------------; SINV_UD LD HL,(CONSTS) ;взяли из ячейки адрес символа LD D,H ;сохранили этот LD E,L ; адрес в DE LD B,#08 ;в символе - 8 байт LP_SIU1 LD A,(HL) ;берем один байт символа PUSH AF ;и заталкиваем на стек INC HL ;переход к следующему байту символа DJNZ LP_SIU1 ;повторяем цикл для восьми байт LD B,#08 ;сколько байт будем считывать LP_SIU2 POP AF ;извлекаем байт со стека и в обрат- LD (DE),A ; ном порядке записываем в символ INC DE ;следующий байт символа DJNZ LP_SIU2 ;крутим цикл восемь раз RET ;выход из процедуры ;--------------------------------------------------------------; ;Инвертирование символа горизонтально (17<=19) ;--------------------------------------------------------------; SINV_LR LD HL,(CONSTS) ;берем из ячейки адрес символа LD B,#08 ;модифицируем: 8 байт LP_SIL1 LD A,#01 ;устанавливаем нулевой бит A в 1 LP_SIL2 RR (HL) ;вращаем байт символа вправо RLA ;а аккумулятор - влево (через CF) JR NC,LP_SIL2 ;пока нулевой бит не окажется в CF LD (HL),A ;записываем измененный байт INC HL ;следующий байт символа DJNZ LP_SIL1 ;повторяем цикл 8 раз RET ;выход из процедуры ;--------------------------------------------------------------; ;Вращение символа по часовой стрелке (26<=42) ;--------------------------------------------------------------; SROTATE LD HL,(CONSTS) ;адрес вращаемого символа из ячейки LD B,#08 ;8 вертикальных колонок в символе LP_SRO1 PUSH HL ;сохранили адрес на стеке LD A,#80 ;включили 7-ой бит в аккумуляторе LP_SRO2 RR (HL) ;вращаем байты символа вправо RRA ; и по одному биту из каждого байта INC HL ; постепенно заполняем аккумулятор JR NC,LP_SRO2 ; пока 7 вкл. бит не попадет в CF POP HL ;восстанавливаем адрес символа PUSH AF ;вертик. колонку символа - на стек DJNZ LP_SRO1 ;крутим цикл по числу колонок LD B,#08 ;колонки стали линиями - байтами LP_SRO3 POP AF ;стаскиваем байт со стека LD (HL),A ;и это - уже новая линия символа INC HL ;следующий байт символа DJNZ LP_SRO3 ;повторяем по числу линий (8 байт) RET ;выход из процедуры ;--------------------------------------------------------------; ;Изменение атрибута (16<=21) ;--------------------------------------------------------------; ACHANGE LD HL,(CONSTS) ;L - маска (AND), H - добавка (OR) LD DE,#5AFF ;последний байт области атрибутов LP_ACHN LD A,(DE) ;взяли текущее значение атрибута AND L ;отбросили лишние биты OR H ;добавили необходимые LD (DE),A ;и записали на старое место DEC DE ;движемся к началу атрибутов BIT 3,D ;а не графика ли уже? JR NZ,LP_ACHN ;если нет, то крутим цикл RET ;выход из процедуры ;--------------------------------------------------------------; ;Смена атрибута (18<=22) ;--------------------------------------------------------------; AREPLC LD DE,(CONSTS) ;E - что искать, D - чем заменять LD HL,#5AFF ;последний байт области атрибутов LP_ARPL LD A,(HL) ;взяли байт из области атрибутов CP E ;не тот ли, что ищем? JR NZ,GO_ARPL ;нет, перепрыгиваем изменение LD (HL),D ;да, изменяем на новое значение GO_ARPL DEC HL ;движемся к началу обл-ти атрибутов BIT 3,H ;атрибуты еще не кончились? JR NZ,LP_ARPL ;если нет, то проверяем следующий RET ;выход из процедуры ;--------------------------------------------------------------; ;Закрашивание контура (123<=263) ; 123=88+35 - вместе с процедурой POINT ;--------------------------------------------------------------; PAINT LD HL,(CONSTS) ;координаты начальной точки LD A,H ;проверяем координату Y на выход CP #C0 ; за пределы экрана: RET NC ; если Y>=192, то экстренный выход SBC A,A ;т.к. CF=1, то SBC A,A дает A=#FF - PUSH AF ; это будет указатель конца стека PUSH HL ;запоминаем координаты первой точки LP_PNT1 POP DE ;берем со стека X,Y след. точки INC D ;если Y=#FF, то стек исчерпан, RET Z ; и тогда выходим из процедуры DEC D ;восстанавливаем исходн. значение Y CALL POINT ;проверяем точку с коорд-ми (E,D) JR NZ,LP_PNT1 ;если включена, то переход к след. EX AF,AF' ;A'=0, CF=0 - вспомогат. признаки LP_PNT2 LD A,E ;взяли координату X OR A ;если она равна нулю, JR Z,GO_PNT1 ; то прыжок через движение назад DEC E ;иначе - уменьшаем координату X CALL POINT ;и проверяем предыдущую точку JR Z,LP_PNT2 ;если "нет препятствия", повторяем LP_PNT3 INC E ;переход на точку вправо (X=X+1) JR Z,LP_PNT1 ;если X>255, то сл. точка со стека GO_PNT1 CALL POINT ;проверяем следующую правую точку JR NZ,LP_PNT1 ;если включена, то след. со стека LD A,(HL) ;если точка не установлена, OR C ; то берем байт с экрана, включаем LD (HL),A ; нужный бит и ставим назад LD A,D ;проверяем координату Y: OR A ;если она равна нулю, JR Z,GO_PNT4 ; то не проверяем лежащ. выше линию DEC D ;переход к линии выше (Y=Y-1) CALL POINT ;проверка вышележащей точки JR Z,GO_PNT2 ;если не включена, то переход EX AF,AF' ;взяли вспомогательные флаги LD A,B ;разрешили запоминать точку в стеке JR GO_PNT3 ;переход на продолжение GO_PNT2 EX AF,AF' ;взяли вспомогательные флаги INC A ;если A>0, то это означает запрет DEC A ; на сохранение координаты новой JR NZ,GO_PNT3 ; точки в стеке, -> перепрыгиваем LD A,C ;иначе - запрещаем сохранять коор- PUSH DE ; динаты, но одну пихаем на стек GO_PNT3 EX AF,AF' ;сохранили вспомогательные флаги INC D ;возвращаемся на нижнюю линию GO_PNT4 LD A,D ;проверяем координату Y: CP #BF ;если - последняя (ниже не бывает), JR NC,LP_PNT3 ; то переход к след. точке справа INC D ;иначе - спускаемся на линию ниже CALL POINT ;проверяем нижележащую точку JR Z,GO_PNT5 ;если не включена, то переход EX AF,AF' ;взяли вспомогательные флаги AND A ;разрешили запоминать точку в стеке JR GO_PNT6 ;переход на продолжение GO_PNT5 EX AF,AF' ;взяли вспомогательные флаги JR C,GO_PNT6 ;если нельзя сохранять, то переход SCF ;запрещаем сохранять точку на стеке PUSH DE ;но одну точку на стек запихиваем GO_PNT6 EX AF,AF' ;сохранили вспомогательные флаги DEC D ;возвращаемся на верхнюю линию JR LP_PNT3 ;переход к следующей точке справа ;--------------------------------------------------------------; ;Проверка состояния точки и вычисление адреса в экране (35<=70) ;--------------------------------------------------------------; POINT ;если точка выключена, то ZF=1 (Z), иначе ZF=0 (NZ) LD B,#07 ;часто используемая маска (#07) LD A,D ;взяли Y-координату RRA ;разделили ее на 8 SCF ; и начали формировать RRA ; старший байт RRA ; адреса пиксела AND #5F ; в экране (регистр H): LD H,A ; %010yyyyy XOR E ;далее формируем AND B ; младший байт XOR E ; адреса RRCA ; пиксела RRCA ; в экране RRCA ; (регистр L): LD L,A ; %yyyxxxxx LD A,D ;заканчиваем XOR H ; формирование AND B ; старшего байта XOR H ; адреса пиксела LD H,A ; в экране (регистр H) 140. LD A,E ;начинаем формировать AND B ; маску пиксела в байте LD B,A ; изображения (соответствующий LD A,#80 ; бит включен). Включаем 7-ой бит JR Z,GO_PNT ;если это как раз то что надо, LP_PNT RRCA ; то перепрыгиваем через сдвиг DJNZ LP_PNT ; включенного бита вправо GO_PNT LD C,A ;сохраняем маску вкл. бита в рег. C AND (HL) ;проверяем пиксел в экране RET ;выход из процедуры ;--------------------------------------------------------------; ;Построение шаблонов (98<=196) ; 98+35=133 - вместе с процедурой POINT ;--------------------------------------------------------------; PFIGURE LD DE,(CONSTS) ;координаты начальной точки LD HL,(23627) ;адрес начала переменных бейсика LP_PFG1 LD A,(HL) ;первый байт какой-то переменной INC HL ;переход к следующему байту LD BC,#0012 ;размер переменной цикла FOR...NEXT CP #E0 ;нашли переменную цикла FOR...NEXT? JR NC,GO_PFG2 ;если да, то переход к след. перем. CP #80 ;переменные бейсика закончились? RET Z ;если да, то выходим из процедуры LD C,#05 ;длина числ. перем. с одним симв. JR NC,GO_PFG3 ;массив или числ. пер. с неск. сим. CP #60 ;числ перем. с одним симв. в имени? JR NC,GO_PFG2 ;да, переход к следующей переменной CP "A" ;имя символьной переменной (A$) JR Z,GO_PFG4 ;ура, все-таки нашли-и-и-и-и!!! GO_PFG1 LD C,(HL) ;получаем INC HL ; размер исследуемой LD B,(HL) ; переменной INC HL ; в байтах и, GO_PFG2 ADD HL,BC ; прибавив к адресу, JR LP_PFG1 ; переходим к следующей переменной GO_PFG3 BIT 5,A ;переменная массива? JR Z,GO_PFG1 ;да, перепрыгиваем ее LP_PFG2 BIT 7,(HL) ;проверка на конец имени числ. пер. INC HL ;следующий байт имени JR NZ,GO_PFG1 ;имя закончилось, переход JR LP_PFG2 ;продолжаем просматривать имя GO_PFG4 LD C,(HL) ;взяли длину найденной INC HL ; строковой переменной LD B,(HL) ; с данными по шаблону LP_PFG3 INC HL ;следующий символ данных шаблона LD A,B ;проверяем: а не исчерпали ли OR C ; мы все данные по шаблону? RET Z ;если да (длина=0), то выход DEC BC ;уменьшили длину LD A,(HL) ;взяли символ данных шаблона CP "0" ;а не "поставить ли точку"? JR NZ,GO_PFG6 ;если нет, переход на продолжение LD A,D ;y-координата текущей точки CP #C0 ;если выходит за нижнюю кромку JR NC,LP_PFG3 ; экрана, то точку не изображаем PUSH HL ;иначе - сохраняем некоторые PUSH BC ; регистры, чтоб не портились CALL POINT ;вызываем процедуру проверки точки LD A,(HL) ;по вычисленным значениям OR C ; изображаем точку на экране LD (HL),A ; пользуясь тем, что HL=адрес, POP BC ; а регистр C содержит маску точки POP HL ;восстанавливаем сохр-ные регистры JR LP_PFG3 ;обработка след. символа шаблона GO_PFG6 SUB "5" ;сместить перо влево? JR NZ,GO_PFG7 ;если нет, то оставить все как есть DEC E ;иначе - уменьшить x-координату GO_PFG7 DEC A ;двигаемся вниз? JR NZ,GO_PFG8 ;нет, переход INC D ;да, увеличиваем y-координату GO_PFG8 DEC A ;направление "вверх"? JR NZ,GO_PFG9 ;нет, перепрыгиваем DEC D ;да, уменьшаем y-координату GO_PFG9 DEC A ;может надо сдвинуться вправо? JR NZ,LP_PFG3 ;нет, переход к след. символу шабл. INC E ;да, увеличиваем x-координату JR LP_PFG3 ; и переходим к след. символу шабл. ;--------------------------------------------------------------; ;Увеличение экрана и копирование (174<=335) ; 174+35=209 - вместе с процедурой POINT ;--------------------------------------------------------------; PSCALER LD HL,(CONSTS+4);масштабность увеличения по x и y INC L ;проверка x-координаты DEC L ; на нулевое значение RET Z ;если равна 0, то ошибка (выход) INC H ;проверка y-координаты DEC H ; на нулевое значение RET Z ;если равна 0, то ошибка (выход) LD HL,(CONSTS+6);новые x-,y-координаты ("куда") LD A,#BF ;максимально возможная y-координата CP H ;проверяем новую y-координату RET C ;если не в экране - выход LD HL,(CONSTS) ;x1-,y1-координаты ("откуда") CP H ;проверяем y1 на вхождение в экран RET C ;если за экраном, то выходим LD DE,(CONSTS+2);x2-,y2-координаты ("откуда") CP D ;y2 находится в экране? RET C ;если нет, то выход из процедуры LD A,E ;координата x2 CP L ;сравнили с координатой x1 JR NC,GO_PSC1 ;если L0, то флаг CF включится RR B ;"вкручиваем" этот бит в регистр B DEC C ;уменьшаем счетчик количества битов JR NZ,GO_PSC3 ;если не ноль, то перепрыгиваем PUSH BC ;иначе - забрасываем на стек INC SP ; регистр B (только 1 байт) LD C,#08 ; и устанавливаем счетчик битов GO_PSC3 LD A,E ;текущая x-координата DEC E ;движемся по линии влево CP L ;проверка на окончание линии JR NZ,LP_PSC2 ;крутим цикл по линии EX AF,AF' ;восстанавливаем значение LD E,A ; x-координаты из альтернативного A LD A,D ;текущая y-координата DEC D ;движемся по строчкам вверх CP H ;это была последняя линия? JR NZ,LP_PSC1 ;если нет, то крутим цикл по линиям LD A,#08 ;число битов в байте SUB C ;A=число заполненных битов в рег. B JR NZ,GO_PSC4 ;если не ноль, то перепрыгиваем LD A,C ;A=C=8 - число бит в байте DEC SP ;снимаем со стека последний POP BC ; заброшенный туда байт GO_PSC4 LD C,A ;сколько битов данных в посл. байте LD DE,(CONSTS+6);новые x-,y-координаты ("куда") LP_PSC3 LD A,E ;сохраняем x-координату начала EX AF,AF' ; линии изображения в A' EXX ;переход к альтернативным регистрам LD E,C ;это будет счетчик точек по x LP_PSC4 EXX ;вернулись к осн. набору регистров EX AF,AF' ;переход к альтерн. флаг. регистру RLC B ;флаг CF - выводить/не_выв. точку EX AF,AF' ;вернулись к нормальным флагам PUSH BC ;сохраняем байт данных и сч. битов LD HL,(CONSTS+4);масштабность увеличения по x и y LD B,H ;сохранили масштабы увеличения LD C,L ; в регистрах C и B (x и y) PUSH DE ;сохраняем коор-ты (цикл по линиям) LP_PSC5 PUSH DE ;сохраняем коор-ты (цикл по точкам) LP_PSC6 PUSH HL ;сохраняем регистры HL и BC PUSH BC ; перед вызовом процедуры POINT CALL POINT ;расчет адреса в экране и маски LD A,C ;маска точки (бит включен) POP BC ;восстановили BC со стека EX AF,AF' ;проверяем альтернативный флаг CF JR C,GO_PSC5 ;если он включен, то перепрыгиваем EX AF,AF' ;сохраняем этот флаг CF CPL ;инвертируем маску бита точки AND (HL) ; и с ее помощью сбрасываем пиксел JR GO_PSC6 ;переход на продолжение GO_PSC5 EX AF,AF' ;флаг CF делаем снова альтерн-ным OR (HL) ;включаем пиксел GO_PSC6 LD (HL),A ;запись измененного байта в экран POP HL ;восстанавливаем HL (сч. масштаба) INC E ;переход к сл. точке в линии экрана DEC L ;уменьшаем счетчик масштаба по x JR NZ,LP_PSC6 ;пока не ноль, продолжаем цикл LD L,C ;восстанавливаем значение x-масшт. POP DE ;восстан-ем координаты начала линии INC D ;переход к следующей линии в экране DEC H ;уменьшаем счетчик масштаба по y JR NZ,LP_PSC5 ;и крутимся, пока он не достигнет 0 LD H,B ;восстанавливаем значение y-масшт. POP DE ;восстан-ем координаты начала точки LD A,E ;переход к началу следующего ADD A,L ; прямоугольника, изображающего LD E,A ; одну точку изображения (вправо) POP BC ;восстанавливаем байт д-х и счетчик DEC C ;уменьшаем счетчик битов в байте B JR NZ,GO_PSC7 ;если есть еще биты, то переход DEC SP ;иначе - считываем со стека POP BC ; следующий байт данных в регистр B LD C,#08 ;устанавливаем счетчик битов GO_PSC7 EXX ;переход к альтернативным регистрам DEC E ;уменьшаем счетчик точек в строчке JR NZ,LP_PSC4 ;если еще есть точки, то крутимся EXX ;вернулись к осн. набору регистров EX AF,AF' ;восстанавливаем из альтернативного LD E,A ; аккумулятора x-координату строчки LD A,D ;переход к началу следующего прямо- ADD A,H ; угольника, изображающего одну LD D,A ; точку изображения (вниз) EXX ;переход к альтернативным регистрам DEC B ;уменьшаем счетчик строк спрайта EXX ;вернулись к осн. набору регистров JR NZ,LP_PSC3 ;цикл, если строчки не закончились RET ;выход из процедуры ;--------------------------------------------------------------; 3; end of 40 New Best Routines (graphic) ; ;--------------------------------------------------------------; 2 Шестнадцатеричный дамп библиотеки F270: 5A 11 FF 5A 01 E0 02 ED :F6 F278: B8 3A 00 5B 12 1D 20 FC :02 F280: 12 C9 11 00 40 62 6B 23 :8E F288: 01 1F 00 ED B0 AF 12 13 :0B F290: 7A FE 58 38 F0 C9 11 FF :53 F298: 57 62 6B 2B 01 1F 00 ED :E6 F2A0: B8 AF 12 1B CB 72 20 F1 :74 F2A8: C9 11 00 40 D5 01 20 00 :AA F2B0: 7B 81 6F 7A 30 02 C6 08 :87 F2B8: 67 ED B0 D1 7C FE 58 30 :81 F2C0: 12 14 7A E6 07 20 E5 7B :BF F2C8: C6 20 5F 38 DF 7A D6 08 :6E F2D0: 57 18 D9 AF 12 1C 20 FC :03 F2D8: 1E E0 14 CB 5A 28 F4 C9 :E6 F2E0: 11 FF 57 D5 01 20 00 7B :AA F2E8: 91 6F 7A 30 02 D6 08 67 :CB F2F0: ED B8 D1 CB 74 28 12 7A :4B F2F8: 15 E6 07 20 E6 7B D6 20 :63 F300: 5F 38 E0 7A C6 08 57 18 :21 F308: DA AF 12 1D 20 FC 12 1E :FF F310: 1F 15 CB 72 20 F3 C9 21 :71 F318: FF 57 B7 06 20 CB 16 2B :4A F320: 10 FB CB 74 20 F4 C9 21 :5B F328: 00 40 0E C0 B7 06 20 CB :D1 F330: 1E 23 10 FB 0D 20 F5 C9 :5A F338: 11 00 40 62 6B 01 20 00 :6A F340: 24 7C E6 07 20 09 7D 81 :E7 F348: 6F 38 04 7C D6 08 67 E5 :8C F350: ED B0 D1 7C FE 58 38 E3 :9E F358: AF 12 1C 20 FC C9 11 FF :1D F360: 57 62 6B 01 20 00 7C 25 :39 F368: E6 07 20 09 7D 91 6F 38 :26 F370: 04 7C C6 08 67 E5 ED B8 :A2 F378: D1 CB 74 20 E4 AF 12 1D :5D F380: 20 FC 12 C9 2A 00 5B 11 :00 F388: 00 40 1A B6 12 23 13 7A :4D F390: FE 58 38 F6 C9 21 FF 57 :47 F398: 7E 2F 77 2B CB 74 20 F8 :31 F3A0: C9 2A 00 5B 54 5D 06 08 :A0 F3A8: 7E F5 23 10 FB 06 08 F1 :3B F3B0: 12 13 10 FB C9 2A 00 5B :21 F3B8: 06 08 3E 01 CB 1E 17 30 :28 F3C0: FB 77 23 10 F5 C9 2A 00 :40 F3C8: 5B 06 08 E5 3E 80 CB 1E :B0 F3D0: 1F 23 30 FA E1 F5 10 F3 :08 F3D8: 06 08 F1 77 23 10 FB C9 :38 F3E0: 2A 00 5B 11 FF 5A 1A A5 :81 F3E8: B4 12 1B CB 5A 20 F7 C9 :C1 F3F0: ED 5B 00 5B 21 FF 5A 7E :7E F3F8: BB 20 01 72 2B CB 5C 20 :AB F400: F6 C9 2A 00 5B 7C FE C0 :72 F408: D0 9F F5 E5 D1 14 C8 15 :07 F410: CD 5A F4 20 F7 08 7B B7 :70 F418: 28 09 1D CD 5A F4 28 F6 :93 F420: 1C 28 E9 CD 5A F4 20 E4 :60 F428: 7E B1 77 7A B7 28 13 15 :43 F430: CD 5A F4 28 04 08 78 18 :03 F438: 07 08 3C 3D 20 02 79 D5 :24 F440: 08 14 7A FE BF 30 D9 14 :A4 F448: CD 5A F4 28 04 08 A7 18 :4A F450: 05 08 38 02 37 D5 08 15 :B4 F458: 18 C6 06 07 7A 1F 37 1F :26 F460: 1F E6 5F 67 AB A0 AB 0F :24 F468: 0F 0F 6F 7A AC A0 AC 67 :C2 F470: 7B A0 47 3E 80 28 03 0F :BE F478: 10 FD 4F A6 C9 ED 5B 00 :7F F480: 5B 2A 4B 5C 7E 23 01 12 :54 F488: 00 FE E0 30 13 FE 80 C8 :E3 F490: 0E 05 30 0F FE 60 30 08 :6C F498: FE 41 28 12 4E 23 46 23 :DF F4A0: 09 18 E1 CB 6F 28 F5 CB :B8 F4A8: 7E 23 20 F0 18 F9 4E 23 :CF F4B0: 46 23 78 B1 C8 0B 7E FE :85 F4B8: 30 20 11 7A FE C0 30 F1 :66 F4C0: E5 C5 CD 5A F4 7E B1 77 :1F F4C8: C1 E1 18 E5 D6 35 20 01 :87 F4D0: 1D 3D 20 01 14 3D 20 01 :B1 F4D8: 15 3D 20 D5 1C 18 D2 2A :43 F4E0: 04 5B 2C 2D C8 24 25 C8 :65 F4E8: 2A 06 5B 3E BF BC D8 2A :22 F4F0: 00 5B BC D8 ED 5B 02 5B :78 F4F8: BA D8 7B BD 30 01 EB 7A :4C F500: BC 30 02 54 67 7A 94 3C :E8 F508: D9 47 D9 7B 95 3C D9 4F :6A F510: D9 F5 33 0E 08 7B 08 E5 :84 F518: C5 CD 5A F4 C1 E1 C6 FF :54 F520: CB 18 0D 20 04 C5 33 0E :2F F528: 08 7B 1D BD 20 E9 08 5F :EA F530: 7A 15 BC 20 E0 3E 08 91 :47 F538: 20 03 79 3B C1 4F ED 5B :5C F540: 06 5B 7B 08 D9 59 D9 08 :2C F548: CB 00 08 C5 2A 04 5B 44 :A2 F550: 4D D5 D5 E5 C5 CD 5A F4 :01 F558: 79 C1 08 38 05 08 2F A6 :A9 F560: 18 02 08 B6 77 E1 1C 2D :CE F568: 20 E9 69 D1 14 25 20 E2 :DB F570: 60 D1 7B 85 5F C1 0D 20 :E3 F578: 04 3B C1 0E 08 D9 1D 20 :99 F580: C5 D9 08 5F 7A 84 57 D9 :A8 F588: 05 D9 20 B6 C9 00 00 00 :FA Сохранение: SAVE "nbestg.c" CODE 62000,861 * * *
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября