Вы находитесь на странице: 1из 17

2-1/6.

Оптимизация кодов элементов картинок ("наведение, в этой мути,


элементарного порядка"). Разновидности алгоритмов "идеальной" и
"компромиссной" оптимизации (техническая составляющая).

На данный момент, имеется программа "объемом" в 2121 слово.


Основная часть этого "объема" приходится на группы команд, работающих с кодами
картинок.
Таким образом, в части касающейся этих групп команд, "суперактуальной" становится
проблема, связанная с обеспечением эффективной оптимизации кодов этих элементов.
Но прежде чем, по-деловому и в рабочем порядке, "завалить эту проблему", нужно,
как минимум, понять, в чем она заключается (что именно нужно "завалить"?).
Далее à "по цепочке здравого смысла".
И при этом нужно учесть то, что речь идет о "волосатом, вражеском кулаке"
внушительного размера.
Такой, если как следует "приложится", то оставит после себя не только "фингал", но и
"сотрясение мозга".
Вывод: о технике безопасности забывать не нужно.
Вздох. Выдох. Поехали.
На первый взгляд, никакой выдающейся проблемы нет:
- в таблицах вычисляемых переходов, нужно просто "поубивать" все массивы "нулевых"
байтов, а оставить только те массивы байтов данных, числовые значения которых
отличны от нуля,
- соответствующим образом (обходы "усопших") скорректировать содержимое тех групп
команд, которые "обслуживают" эти "урезанные", вычисляемые переходы.
Примечание: "нулевыми" байтами я буду называть те байты данных, числовые
значения которых = 0, а массивами "нулевых" байтов я буду называть те массивы
байтов данных, которые состоят из "нулевых" байтов.
Это и было, частично, проделано ранее:

1. Вспомните о ранее "убиенных" (пусть "земля им будет пухом"), "нулевых" байтах,


"дислоцировавшихся" правее самой правой "птички", распустившей свои крылья на
2-й странице 2-го кристалла.
Они были "убиты" (не выводились на индикацию) за счет того, что в соответствующий
момент, заполнение страницы байтами данных было просто-напросто прекращено
переходом на другую страницу (инструкция Set Page).
Именно таким образом и была обеспечена сохранность нижней половины солнца.
Так нужно поступать в том случае, когда необходимо "убить" массив "нулевых" байтов,
расположенный в самом конце страницы графического модуля (массив "примыкает к
правому краю" страницы).

2. Если массив "нулевых" байтов расположен не в самом конце страницы, а например,


в ее середине, то его можно "убить" за счет "прыжка" через то "место" (адресное
"пространство"), в котором "дислоцируется" этот массив.
Для организации такого "прыжка", применяется инструкция Set Address.
Именно таким образом и была обеспечена "сохранность" боеголовки.

3. Если массив "нулевых" байтов расположен в самом начале страницы, то его можно
"убить" за счет организации заполнения страницы не с ее начала (c 1-го столбца.
Адрес 00h), а с первого, "ненулевого" столбца.
При этом, применяется та же инструкция Set Address.
Хотя ранее, этот случай и не имел место быть, но об этом совсем не трудно
догадаться.

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


оптимизацией кодов всяческих картинок, есть от чего "оттолкнуться".
Проще говоря, "старт" дан и теперь нужно достойно "пробежать дистанцию".
Достаточно незамысловатый и одновременно "глубинный" ("сермяжный". Это для тех,
кто уважает Ильфа и Петрова) смысл этого "старта" состоит в следующем:

1
если, в процессе вывода на индикацию текущих элементов картинки, нужно
сохранить элемент картинки, выведенный на индикацию ранее, то нужно
просто обойти ("объехать", "перескочить" и т.п.) массив байтов этого элемента
картинки (недопущение записи "нового по верху старого"), после чего продолжить
вывод на индикацию элементов текущей картинки.
Любая разновидность этого обхода так или иначе сводится к "убийству"
соответствующего массива "нулевых" байтов текущего вычисляемого перехода.
На другой лад: "убийство" того или иного массива "нулевых" байтов, который
изначально входит в состав таблицы вычисляемого перехода (в "материнскую"
таблицу), связано с реализацией одной из разновидностей обхода адресного
"пространства" соответствующего массива.
Закономерный и уважаемый вопрос: "А это дельце можно провернуть применительно к
содержимому всего дисплея"?
Ответ: можно. Вне всякого сомнения. Лишь бы было что обходить ("плотность
застройки" позволяла).
Вопрос: "Как это сделать по-умному, ведь количество массивов "нулевых" байтов,
которые нужно обойти, может быть значительно? Эти массивы могут иметь различный
объем, и они могут быть разбросаны, по площади дисплея, различными способами"?
А вот на этот вопрос, парой предложений не ответишь.
Значит, необходимо разобраться с деталями.
Для того чтобы "заоптимизировать" код картинки, нужно решить 2 задачи:

Задача №1

Для того чтобы осознанно (а не абы как) осуществить оптимизацию


чего-либо, нужно узнать критерий/критерии этой оптимизации
(получить ответ на вопрос: "Что такое хорошо и что такое плохо"?).

Задача №2

Оптимизация, в идеале, имеет две "глобальные" составляющие:


- минимизация времени исполнения того, что оптимизируется,
- минимизация количества команд, обеспечивающих исполнение того,
что оптимизируется.

Сложность решения этих задач заключается в том, что их не получится "раздолбать"


по-отдельности.
Эти задачи нужно "долбать" в комплексе (два "сиамских близнеца").
На мой взгляд, "раскрутку" лучше всего начать с определения числового значения
интервала времени исполнения цикла вывода на индикацию одного байта данных.
Применительно к рассматриваемым программам, величина этого интервала времени
равна времени отработки 34 м.ц. (в данном случае, 34 мкс.).
Реплика: совсем не слабо … Особенно, если учитывать, что нижний предел этого
интервала времени находится в "районе" 8 мкс. (при Fкв. = 4 Мгц., это 8 м.ц.)
Примечание: для того чтобы увидеть эту "цифирь" своими глазами, нужно, в программе
12864_2.asm, заблокировать первую команду программы (goto START), а вместо нее
поставить, например, goto RRR.
Метку RRR можно выставить, например, на команде call STRANICA_1 (чтобы быстро
попасть в "сектор обстрела").
Далее, нужно выставить точку остановки на команде movf Temp,W (помечена меткой
WR_1), "добраться" до этой команды (можно в "автомате", а можно и "пошагово"),
сбросить секундомер в ноль и щелкнуть по зеленому светофору.
То же самое можно сделать и в любой другой, аналогичной процедуре.
"Цифирь" будет одной и той же (34 м.ц.).
Таким образом, 1024 байта данных ("сплошное" заполнение дисплея) будут обработаны
за 34 х 1024 = 34816 м.ц. ("тихий ужас")
С учетом остальных команд процедуры и "волшебных" комбинаций команд,
обеспечивающих "безбяковые прыжки" (если они нужны), получается немногим больше.
2
Итак, "убийство" одного байта данных (любого) уменьшает время исполнения полного
цикла вывода данных на индикацию на время исполнения 34-х машинных циклов.
"Зер гут"!!!
Особенно с учетом того, что массив может состоять из нескольких "нулевых" байтов, и
таких массивов может быть несколько.
Но следует учесть то, что этот вывод буквально (в части касающейся выигрыша в 34
м.ц.) применим только к двум разновидностям оптимизации, относящимся к массивам
"нулевых" байтов, которые располагаются либо в начале, либо в конце страницы
графического модуля (не путать со страницами памяти программ ПИКа).
Например, рассмотренный ранее, случай сохранения нижней половиной солнца:
"материнская" таблица (та, в которой 64 байта) заканчивалась массивом "нулевых"
байтов, который и "убит" (см. вычисляемые переходы ПП TEXT122 и TEXT222), в
комплексе с соответствующей организацией обхода "покойников" (ПП WR122 и WR222).
В этом, конкретном случае, "убит" массив байтов, состоящий аж из 17-ти "нулевых"
байтов данных.
В конечном итоге, это привело к уменьшению времени отработки цикла вывода данных
на индикацию (по сравнению с "матерью") аж на:

34 м.ц. х 17 = 578 м.ц. (578 мкс.),


плюс, "усопло" 17 команд retlw … ,

что по всем параметрам (уменьшение и времени отработки, и количества команд), есть


один из элементов оптимизации, близкой к идеальной.
Кто после этого скажет, что я сейчас занимаюсь ерундой и не по делу "пудрю Вам
мозги"?
Это вовсе не ерунда, а диаметрально противоположное ("инвертированная ерунда" или
"важняк").
Тому, кто этого не понимает или не хочет понять, графические модули
противопоказаны (будет "аллергия & понос").
Еще раз, и более конкретно, акцентирую Ваше внимание на том, что "до того", cейчас
и "после того", речь идет об "убийствах" тех массивов "нулевых" байтов данных,
которые, в случае их отработки,
- либо подтверждают нули, ранее выведенные на индикацию в предыдущем
"кадре",
- либо "уничтожают", ранее выведенные на индикацию, элементы картинки.
Указанное выше, относится (в комплексе)
- и к последнему: "спасение от уничтожения" нижней половины солнца,
- и к первому: обход массивов "нулевых" байтов, расположенных левее и правее
нижней половины солнца (зачем подтверждать ранее выведенные на индикацию
нули?).

Детальную "раскрутку" начну с самого простого.


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

- либо массив "нулевых" байтов, расположенный в самом начале страницы,


- либо массив "нулевых" байтов, расположенный в самом конце страницы,
- либо массивы "нулевых" байтов, расположенные и в самом начале страницы,
и в самом конце страницы.

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

3
1. Eсли массив "нулевых" байтов расположен в самом начале страницы
графического модуля, то сразу же после выбора текущей страницы
(инструкция Set Page), нужно выполнить инструкцию Set Address, и тем
самым обойти ("перепрыгнуть") адресное "пространство" этого массива.

2. Eсли массив "нулевых" байтов расположен в самом конце страницы


графического модуля, то сразу же после завершения вывода на индикацию
последнего байта самого правого элемента текущей картинки, нужно перейти
на начало заполнения следующей страницы графического модуля
(инструкция Set Page).

3. Eсли массив "нулевых" байтов расположен "и там, и сям", то нужно


сделать и то, и другое (см. пункты 1 и 2).

Примечание: любая, даже самая "паршивая" оптимизация, связана с


"жизнеутверждающим убийством". Иначе "вши замучают".
Таким образом, если страницы графического модуля начинаются или заканчиваются
массивами "нулевых" байтов, то каких-то выдающихся проблем нет.
Соответствующие "убийства" однозначно приводят и к уменьшению количества команд,
и к уменьшению времени отработки цикла вывода данных на индикацию (максимальная
степень эффективности оптимизации).
А если конкретно, то в данном случае, "убийство" каждого такого "нулевого" байта
данных дает выигрыш:
- в одну команду retlw …
- и в 34 м.ц.
Для осуществления этих "убийств", нужно:

- убрать ("стереть в порошок", "расстрелять", "посадить на кол" и т.п.), из таблицы


вычисляемого перехода, соответствующий массив "нулевых" байтов данных,
- в соответствии с количеством "усопших паразитов" (туда им и дорога), уменьшить
(по отношению к числу .64) числовое значение константы, определяющей
количество сценариев вычисляемого перехода,
- в зависимости от того, на каком "конце" (левом или правом) страницы
графического модуля произошло "убийство", нужно либо выполнить инструкцию
Set Address (выбор столбца: "левый" вариант), либо выполнить инструкцию
Set Page (выбор страницы: "правый" вариант).

Ну и океюшки.
Часть "вшей отправилась к праотцам" (гигиена - залог здоровья).
Но это относится только к тем "вшам", у которых большие проблемы с мозгами в том
смысле, что они, по своей недальновидности, и от недостатка ума, "резвились" на
"открытом пространстве".
Вот и "дорезвились"… ("снайперы" свое дело знают).
Но остались самые "хитропопые". Те, что мимикрируют и в волосах прячутся.
Зачит, их нужно "вычислить" и "поубивать к …".
В противном случае, будет нечто эквивалентное неожиданному "удару в пах" (там,
кстати, волосы растут), причем, не в чей-то, а в свой, любимый.
Будет очень больно.
Так что, исходя из прагматических (и прочих) соображений, лучше "озвереть не после
того, а до того" (народная мудрость повышенной степени мудрости. Называется
упреждением).
Вот Вам и потенциальный "объект приложения дубины", а заодно и соответствующая
"идеология".
Собственно говоря, искать-то и нечего. Проблема à "на прямой наводке".
Объясню научно-популярно.

4
Гнусавый и ехидный (и вообще, отвратительный & мерзкий) голос из-за кулис:
"А ну-ка, разлюбезный, доложи про свою оптимизацию, в случае дислокации массива
нулевых байтов где-нибудь в серединке страницы графического модуля".
Так бы и пришиб вражину, но он прав (в смысле "глубинной" сути подвоха).
Война?
Тот же голос из-за кулис: "Она самая. Если опрохвостишься, то пощады не жди.
С удовольствием загрызу".
ОК. Война так война. Жить стало гораздо интереснее.
Вопрос к Вам: "Вы еще не догадались, кто прячется за кулисами"?
Ответ: собственная бестолковость. То есть, природный враг рода человеческого.
Чем-то сатану напоминает.
Формулирую суть подвоха.
С целью обеспечения максимальной простоты рассуждений, предполагается, что после
вывода на индикацию картинки 1-го "кадра", в пределах одной, текущей страницы
графического модуля, которую, в дальнейшем, нужно заполнить (не важно, чем
именно), имеется некий массив байтов, который расположен, например, в средней
части строки, и который нужно обойти.
Для того чтобы его обойти, нужно "раздробить" изначально единую, "материнскую"
процедуру обработки 64-х байтов данных, на две части.
Доказательством этому может служить, рассмотренная ранее, процедура вывода байтов
данных в 3-ю страницу 2-го кристалла, которая обеспечивает не только сохранение
боеголовки ракеты (обход), но и дальнейшее заполнение текущей строки.
Такое дробление достаточно комфортно для восприятия и обеспечивает наиболее
оптимальный способ адресного "прыжка" через массив байтов.
Ниже Вы видите то, как это реализовано программно ("вырезка" из программы
предыдущего подраздела).
"Драматургия": обход боеголовки, а заодно и "нулевых" байтов кода картинки 1-го
"кадра" (тех, которые, с разных "боков", "прислонились" к боеголовке), с последующим
выводом на индикацию самой правой "птички".
Это выглядит так:
;.....................................
;--------------------------------------------------------------------------------
; Запись 1-го сценария в 3-ю страницу 2-го кристалла
;--------------------------------------------------------------------------------
call STRANICA_3 ;
call STOLB_1 ;
movlw .31 ;
movwf Temp ;

WR132 movf Temp,W ;


sublw .31 ;
movwf Reg ; То же самое, только
call TEXT132 ; переход происходит
movwf PortC ; в ПП TEXT132,
movlw high WRITE_D; с числом проходов .31.
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR132 ;
;------------------------------------
; Продолжение работы на 3-й странице.
;------------------------------------
movlw b'01111010' ; Выбор адреса 59-го столбца
; (инструкция "Set Address").
movwf PortC ; Вывод команды выбора адреса столбца
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
movlw .6 ;
movwf Temp ;

WR132_1 movf Temp,W ;

5
sublw .6 ;
movwf Reg ; То же самое, только
call TEXT132_1 ; переход происходит
movwf PortC ; в ПП TEXT132_1,
movlw high WRITE_D; с числом проходов .6.
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR132_1 ;
;.....................................
;.....................................

;--------------------------------------------------------------------------------
; Данные 3-й страницы 2-го кристалла
;--------------------------------------------------------------------------------
TEXT132 movlw high STR132 ;
movwf PCLATH ;
movf Reg,W ;
addlw low STR132 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR132 dt 0x40,0x40,0x40,0x40,0x3F,0x00,0x00,0x00
dt 0x00,0x00,0x04,0x0C,0x1C,0x3C,0x7F,0xFF ; 31 штука.
dt 0xFF,0x7F,0x3C,0x1C,0x0C,0x04,0x00,0x00
dt 0x01,0x01,0x02,0x04,0x02,0x01,0x01
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;;; ,0x00
;;; dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 26 штук.
;;; dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; ОБХОДИТСЯ.
;;; dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
;;; dt 0x00
;---------------------------------------------------
; Продолжение (формирование самой правой "птички").
;---------------------------------------------------
TEXT132_1 movlw high STR132_1;
movwf PCLATH ;
movf Reg,W ;
addlw low STR132_1;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR132_1 dt 0x00,0x04,0x04,0x08,0x04,0x04 ; 6 штук
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;;; ,0x00 ; 1 штука.
;..................................... ; ОБХОДИТСЯ.
-----------------
Итого: 64 штуки.

Серым цветом выделены те массивы "нулевых" байтов, которые обходятся.


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

6
Так как этим массивом заканчивается страница ("контачит" с "границей" страницы), то и
хлопот с ним нет: он просто обходится путем "скоропостижного" перехода (намек на
причину "кончины усопшего") на следующую страницу, осуществленного сразу же
после окончания формирования картинки самой правой "птички".
В данном же случае, нужно особо поинтересоваться (с пристрастием) деталями того
обхода, который привел к дроблению программной процедуры.
"Детское умозаключение": организация процедуры обхода массива "нулевых" байтов,
связанная с дроблением, предполагает введение в текст программы дополнительных
команд.
Их отработка происходит не за ноль секунд.
То есть, на это нужно время.
Незамысловатый вывод: чем большим будет количество обходов, связанных с
дроблением, тем большим будет и количество дополнительных команд.
С точки зрения выигрыша по количеству команд, это, естественно, не есть "зер гут".
А как на счет выигрыша по времени?
Это требует расчета.
В данном случае, "цена" организации одного обхода составляет 23 дополнительных
команды и 10 м.ц. дополнительной задержки (время исполнения группы команд от
movlw b'01111010' до movwf Temp включительно).
При этом следует учесть то, что ПП WR132 и WR132_1, по своей "конструкции",
одинаковы, и поэтому время обработки одного байта данных, в обеих этих ПП, тоже
будет одинаковым (34 м.ц.)
В связи с тем, что интервал времени вывода на индикацию одного байта данных
довольно-таки значителен, то по времени, получается выигрыш даже в случае обхода
массива, состоящего из одного-разъединственного, "нулевого" байта ("мал клоп, да
вонюч").
И в самом деле, 34 м.ц. – 10 м.ц. = выигрыш в 24 м.ц.
Но при этом, текст программы, в итоге (минус 1 команда retlw …), увеличивается на
23 – 1 = 22 команды.
А если предположить, что обходится не один "нулевой" байт, а несколько "нулевых"
байтов?
Например, при обходе массива, состоящего из 5-ти "нулевых" байтов, выигрыш по
времени составит уже не 24 м.ц., а (34х5) – 10 = 160 м.ц., а количество дополнительных
команд сократится до 23 – 5 = 18-ти.
Если обходится массив из 16-ти "нулевых" байтов, то выигрыш по времени составит
534 м.ц., а количество дополнительных команд сократится до 23 – 16 = 7-ми.
И так далее. Различные варианты просчитать не сложно.
В том числе и с несколькими обходами, производимыми по ходу заполнения одной
страницы, и т.д.
Как сами понимаете, различных вариантов - множество, и проанализировать их все
весьма проблематично.
Значит, нужно сформулировать общий принцип оптимизации кода картинки, в части
касающейся "дислокации" массивов "нулевых" байтов в "промежутках" между массивами
"ненулевых" байтов.
Естественно, что нужно всячески стремиться к идеалу, то есть, к как можно большему
выигрышу и по командам, и по времени.
Потенциально, подобного рода выигрыша добиться можно, но только в тех случаях,
когда имеется достаточно большое количество "объемных" массивов "нулевых" байтов.
А если "нулевые просветы" между элементами картинки малы (массивы "нулевых"
байтов малого "объема") и их много?
С точки зрения обеспеспечения выигрыша по количеству команд, сие весьма
прискорбно.
Но при этом, однозначно, будет иметь место быть выигрыш по времени.
То есть, с точки зрения выигрыша по времени, целесообразно "поубивать" все массивы
"нулевых" байтов, вплоть до массивов, состоящих из одного "нулевого" байта.
Подсчитываю "боевые потери".
"Объем" программы увеличится на количество команд равное
23X - Y
X - количество "убиенных" массивов "нулевых" байтов (количество обходов),
7
Y - суммарное количество "убиенных", "нулевых" байтов (команд retlw 0x00).
Если результат этого вычитания положительный, то имеет место быть проигрыш по
количеству команд (по сравнению с "матерью").
Если результат этого вычитания отрицательный, то имеет место быть выигрыш по
количеству команд (по сравнению с той же "матерью").
Примечание: эта формула верна только для той "конструкции" процедуры вывода
байтов данных на индикацию, которая рассмотрена ранее.
А теперь самое время выпить стаканчик пивка (чтобы нули с единицами друг на друга
не наезжали), выкурить сигаретку, "почесать за ухом" и прикинуть что к чему.
Получается то, что "воплощение в жизнь" такого "хитрого и скользкого" способа
оптимизации, при высокой "плотности застройки" (маленькие "просветы" между
элементами картинки), может привести к довольно-таки приличному увеличению
"объема" текста программы.
В некоторых случаях, это увеличение может оказаться настолько "приличным", что
количество команд программы может превысить "объем" памяти программ
применяемого типа ПИКа.
Вывод: "ушки нужно держать востро".
Из этого следуют простейшие, жизненные умозаключения:
1. Если свободного объема памяти программ ПИКа предостаточно, то можно
произвести оптимизацию в полном объеме.
2. Если, для осуществления полномасштабной оптимизации, свободного объема
памяти программ ПИКа не достаточно, то нужно либо произвести оптимизацию
не в полном объеме, либо, если это не устраивает, перейти на тот тип ПИКа,
который имеет больший "объем" памяти программ.

Общий, "парадоксальный" вывод: оптимизированная процедура вывода на


индикацию, в графический модуль, байтов данных, содержащая в себе большее
(в том числе и значительно) количество команд, чем "материнская" процедура,
будет отрабатываться быстрее "материнской" процедуры (в том числе и
значительно быстрее).
Вот такие "чудеса бывают на белом свете".
В контексте сказанного, возникает закономерный вопрос: "Какая же это оптимизация,
если в результате ее осуществления, увеличивается количество команд"?
Ответ на этот вопрос "упирается" в другой вопрос: "Что важнее, выигрыш по командам
или выигрыш по времени"?
И ответить на него придется, так в данном случае, "идеальная" оптимизация (выигрыш
и по времени, и по количеству команд), хотя и может иметь место быть, но в
большинстве случаев, маловероятна.
В принципе, рассуждения просты.
Если в памяти программ ПИКа имеется "свободное место", то почему бы его не
использовать? Ведь "добро все-равно пропадает".
Это с одной стороны.
С другой стороны, скорость отработки процедуры это не "хухры-мухры", а "важняк в
чистом виде".
Вывод: в условиях наличия "конфликта" между двумя составляющими
оптимизации (одно за счет другого) и наличия "резерва" памяти программ ПИКа,
приоритетным направлением работы является обеспечение максимальной
скорости отработки процедуры.
Именно на это и нужно ориентироваться, и именно достижение этого, в данном
случае, является тем, что я называю словом "оптимизация".
Вернее, "компромиссная оптимизация".
На мой взгляд, такое определение соответствует сути сказанного и в данном случае,
является более корректным, а заодно и более "мозгопрошибаемым".
Итак, "навожу порядок" в терминологии.
Просто "оптимизация" предполагает выигрыш и по скорости, и по количеству команд.
"Компромиссная оптимизация" предполагает выигрыш по одной составляющей
оптимизации, за счет проигрыша по другой составляющей.
"Перетекание" одного в другое зависит от достаточно большого количества причин.

8
Такого рода классификацию лучше всего производить по итогу работы, путем
банального сопоставления итогового результата с количеством команд и временем
отработки "матери".
Уфф… "Ну и тяжкая это работа, из болота тащить бегемота".
"Тащу" дальше.
Вы думаете, что сейчас будет "счастье"?
Как бы не так.
"Вышележащие" рассуждения производились без учета такого "важняка", как "картинка
по умолчанию" (это моя самодеятельность).
Картинка по умолчанию есть не что иное, как результат инициализации графического
модуля (0-й "кадр").
Вопрос: "Что выводится на индикацию после окончания инициализации графического
модуля (по умолчанию): нули или единицы? Это важно или нет"?
Ответ.
Очень хотелось бы верить в то, что по умолчанию, на индикацию выводятся нули, то
есть, результатом инициализации графического модуля является запись нулей во все
его ячейки оперативной памяти.
Это желаемое, но как "вычислить" действительное?
А на удивление просто: после окончания программной процедуры инициализации
графического модуля, нужно "врезать мертвяк" (goto $).
После этого, Вы увидите черный прямоугольник (см. левее).
Вопрос: "Что это такое"?
Ответ: сие есть объективный результат инициализации:
картинка по умолчанию.
Проще говоря, 0-й ("проматеринский") "кадр".
Именно с него и начинается "все сущее".
Вывод: результатом инициализации графического модуля является запись
единиц во все ячейки его оперативной памяти.
ЁКЛМН, а заодно и ЁПРСТ!!! Желанные нули "моль съела".
А "универсальное счастье" было так близко …
Ай-да разработчики. Вот удружили, так удружили …
Получается, что если руководствоваться наработанными, на данный момент,
правилами, то компромиссную оптимизацию 1-го "кадра" производить "опасно".
И в самом деле, если ее произвести в соответствии с ранее "нарытыми" правилами,
то в тех "местах", которые обходятся, на индикацию будут выведены байты 0-го
"кадра", с числовым значением FFh, которые нужны так же, как лыжи зайцу.
Почему? А вспомните-ка о наличии, в графическом модуле, оперативной памяти.
Если, в 1-м "кадре", будет осуществлен обход "массива" нулевых байтов текущей
таблицы вычисляемого перехода, то в тех ячейках оперативной памяти графического
модуля, которые будут обойдены, сохранится то, что в них "лежало до того".
То есть, FFh.
И именно эта "фигня" (и это еще мягко сказано) будет выведена на индикацию.
Подтверждение сказанного:

Сие "безобразие" есть результат некой "псевдокомпромиссной оптимизации" (без учета


существующих реалий) кода 1-го "кадра", в части касающейся 1-й страницы 1-го
кристалла.
Я специально "издевался над программой", чтобы показать Вам это.

9
В "обойденных местах", на индикацию выводятся, сохраненные в оперативной памяти
графического модуля, байты 0-го "кадра" (числовое значение FFh).
Естественно, что такая "псевдокомпромиссная оптимизация", и даром не нужна.
Она нужна только "камикадзе".

"Жизнеутверждающие: выводы:

1. При выводе на индикацию картинки 1-го "кадра", в тех случаях, когда


таблицы вычисляемых переходов не содержат в себе байтов с
числовым значением FFh, эти вычисляемые переходы должны быть
отработаны в полном объеме (64 байта).
2. Если эти таблицы содержат в себе байты с числовым значением FFh,
то такие массивы можно обойти по принципу, сформулированному
выше (зачем подтверждать ранее установленные состояния?).

Первое означает отсутствие компромиссной оптимизации кода страницы.


Второе означает наличие компромиссной оптимизации кода страницы, но только
спицифической (по отношению к рассмотренному ранее).
Обращаю Ваше внимание на то, что эти выводы справедливы только для 1-го
"кадра".
В части касающейся технического аспекта (не путать с организационным),
"псевдокомпромиссная оптимизация" отличается от компромиссной оптимизации только
тем, что в результате обхода, "спасаются от уничтожения" не байты с числовым
значением 00h, а байты с числовым значением FFh.
Это означает то, что в техническом аспекте, никакой стратегической разницы, между
этими разновидностями оптимизации, нет ("клоны").
Таким образом, имеется немалый практический смысл в "росписи" деталей
программной реализации "псевдокомпромиссной оптимизации".
И тем более, что в "обойденных местах", на индикацию выводятся байты 0-го "кадра"
(FFh), которые "распрекрасно метят" эти обходы (заметит даже тот, кто не хочет
замечать).
По-моему, это выглядит очень наглядно и удобно для восприятия, так как четко видны
те массивы байтов (включая и количество байтов в том или ином массиве), которые
обходятся.
Соответствующая программная "свистопляска" выглядит так:
....................................
;================================================================================
; Заполнение страниц 1-го кристалла.
;================================================================================
; Запись в 1-ю страницу 1-го кристалла
;--------------------------------------------------------------------------------
; Обход №1.
;++++++++++++++++++++++++++++++++++++
; Подготовительные операции.
;------------------------------------
call STRANICA_1 ; Выбор 1-й страницы.

movlw b'01000010' ; Выбор адреса 3-го столбца (02h).


movwf PortC ; Вывод команды выбора адреса столбца
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB

movlw .4 ; Назначение
movwf Temp ; числа проходов.
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Циклическая ПП заполнения байтами данных столбцов страницы.
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
WR_1 movf Temp,W ; Число проходов --> в W.
sublw .4 ; .4 - Temp = ... (результат --> в W).
movwf Reg ; В регистр Reg записывается номер текущего

10
; сценария вычисляемого перехода.
;-------------------------------------
; Отработка ПП, в состав которой
; входит вычисляемый переход.
;-------------------------------------
call TEXT_1 ; Переход в ПП TEXT_1.
;---> Возврат по стеку из ПП TEXT_1
;-------------------------------------
; Вывод на индикацию текущего байта
; данных ("лежит" в W).
;-------------------------------------
movwf PortC ; Установка на линиях DB7...DB0 числового
; значения текущего байта данных.
movlw high WRITE_D; Установка в PCH числового значения старшего
movwf PCLATH ; байта адреса (в PC) первой команды
; ПП WRITE_D (через W).
call WRITE_D ; Переход в ПП WRITE_D (с предустановленным
; значением PCH).
;---> Возврат по стеку из ПП WRITE_D
decfsz Temp,F ; Число проходов уменьшается на 1.
goto WR_1 ; Если результат не=0, то переход на
; обработку следующего байта данных.
; Если =0, то запись в 1-ю страницу
; заканчивается и программа исполняется далее
;++++++++++++++++++++++++++++++++++++
; Обход №2.
;++++++++++++++++++++++++++++++++++++

movlw b'01001010' ; Выбор адреса 11-го столбца (0Ah).


movwf PortC ; Вывод команды выбора адреса столбца
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
movlw .4 ;
movwf Temp ;

WR_1_1 movf Temp,W ;


sublw .4 ;
movwf Reg ; То же самое, только
call TEXT_1_1 ; переход происходит
movwf PortC ; в ПП TEXT_1_1.
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_1_1 ;
;++++++++++++++++++++++++++++++++++++
; Обход №3.
;++++++++++++++++++++++++++++++++++++
movlw b'01010010' ; Выбор адреса 19-го столбца (12h).
movwf PortC ; Вывод команды выбора адреса столбца
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
movlw .4 ;
movwf Temp ;

WR_1_2 movf Temp,W ;


sublw .4 ;
movwf Reg ; То же самое, только
call TEXT_1_2 ; переход происходит
movwf PortC ; в ПП TEXT_1_2.
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
11
goto WR_1_2 ;
;++++++++++++++++++++++++++++++++++++
; Обход №4.
;++++++++++++++++++++++++++++++++++++
movlw b'01011010' ; Выбор адреса 27-го столбца (1Ah).
movwf PortC ; Вывод команды выбора адреса столбца
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
movlw .4 ;
movwf Temp ;

WR_1_3 movf Temp,W ;


sublw .4 ;
movwf Reg ; То же самое, только
call TEXT_1_3 ; переход происходит
movwf PortC ; в ПП TEXT_1_3.
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_1_3 ;
;++++++++++++++++++++++++++++++++++++
; Обход №5.
;++++++++++++++++++++++++++++++++++++
movlw b'01100010' ; Выбор адреса 35-го столбца (22h).
movwf PortC ; Вывод команды выбора адреса столбца
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
movlw .4 ;
movwf Temp ;

WR_1_4 movf Temp,W ;


sublw .4 ;
movwf Reg ; То же самое, только
call TEXT_1_4 ; переход происходит
movwf PortC ; в ПП TEXT_1_4.
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_1_4 ;
;++++++++++++++++++++++++++++++++++++
; Обход №6.
;++++++++++++++++++++++++++++++++++++
movlw b'01101000' ; Выбор адреса 41-го столбца (28h).
movwf PortC ; Вывод команды выбора адреса столбца
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
movlw .16 ;
movwf Temp ;

WR_1_5 movf Temp,W ;


sublw .16 ;
movwf Reg ; То же самое, только
call TEXT_1_5 ; переход происходит
movwf PortC ; в ПП TEXT_1_5.
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_1_5 ;
;++++++++++++++++++++++++++++++++++++
; Обход №7.
12
;++++++++++++++++++++++++++++++++++++
movlw b'01111011' ; Выбор адреса 60-го столбца (3Bh). 1
movwf PortC ; Вывод команды выбора адреса столбца 2
; на линии DB7...DB0.
call STROB ; Строб ("запуск в работу"). 3
;---> Возврат по стеку из ПП STROB
movlw .2 ; 4
movwf Temp ; 5

WR_1_6 movf Temp,W ; 6


sublw .2 ; 7
movwf Reg ; То же самое, только 8
call TEXT_1_6 ; переход происходит 9
movwf PortC ; в ПП TEXT_1_6. 10
movlw high WRITE_D; 11
movwf PCLATH ; 12
call WRITE_D ; 13
decfsz Temp,F ; 14
goto WR_1_6 ; 15
;--------------------------------------------------------------------------------
; Запись во 2-ю страницу 1-го кристалла
;--------------------------------------------------------------------------------
....................................
....................................
;--------------------------------------------------------------------------------
; Данные 1-й страницы 1-го кристалла
;-------------------------------------------------------------------------------
; Обход №1.
;++++++++++++++++++++++++++++++++++++
TEXT_1 movlw high STR_1 ; Установка в PCH числового значения старшего
movwf PCLATH ; байта адреса (в PC) первой команды
; (retlw ...) табличного перехода
; (помечена меткой STR_1).
;--------------------------------------
; Анализ выхода или нет за пределы
; текущего блока памяти программ.
;--------------------------------------
movf Reg,W ; Номер сценария вычисляемого перехода --> W.
addlw low STR_1 ; Суммирование номера сценария и числового
; значения младшего байта адреса (в PC)
; ПП STR_1 (через W).
;---------------------------------------------
; Проверка на наличие или отсутствие переноса
; (PCH+1 или этого делать не нужно?).
;---------------------------------------------
btfsc Status,C ; Перенос был или нет?
incf PCLATH,F ; Если был, то PCLATH+1 (PCH+1=...).
movf Reg,W ; Если не был, то инкремента содержимого PCH
; не происходит и номер сценария вычисляемого
; перехода (в любом случае) копируется в W.
;--------------------------------------
; Табличный, вычисляемый переход.
;--------------------------------------
addwf PCL,F ; Приращение PCL на величину содержимого W.
; 0x00,0x00,
STR_1 dt 0xFE,0x02,0x02,0xFE
; ,0x00,0x00
;++++++++++++++++++++++++++++++++++++
; Обход №2.
;++++++++++++++++++++++++++++++++++++
TEXT_1_1 movlw high STR_1_1;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_1_1 ;
btfsc Status,C ;
incf PCLATH,F ;
13
movf Reg,W ;

addwf PCL,F ;
; 0x00,0x00,
STR_1_1 dt 0xFC,0x24,0x24,0x18
; ,0x00,0x00
;++++++++++++++++++++++++++++++++++++
; Обход №3.
;++++++++++++++++++++++++++++++++++++
TEXT_1_2 movlw high STR_1_2;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_1_2 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
; 0x00,0x00,
STR_1_2 dt 0x78,0x84,0x84,0x78
; ,0x00,0x00
;++++++++++++++++++++++++++++++++++++
; Обход №4.
;++++++++++++++++++++++++++++++++++++
TEXT_1_3 movlw high STR_1_3;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_1_3 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
; 0x00,0x00,
STR_1_3 dt 0xFC,0x94,0x94,0x64
; ,0x00,0x00
;++++++++++++++++++++++++++++++++++++
; Обход №5.
;++++++++++++++++++++++++++++++++++++
TEXT_1_4 movlw high STR_1_4;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_1_4 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
; 0x00,0x00,
STR_1_4 dt 0xF8,0x24,0x24,0xF8
; ,0x00,0x00
;++++++++++++++++++++++++++++++++++++
; Обход №6.
;++++++++++++++++++++++++++++++++++++
TEXT_1_5 movlw high STR_1_5;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_1_5 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_1_5 dt 0x10,0x38,0x54,0x92,0x10,0x10,0x10,0x10
dt 0x81,0x42,0x24,0x18,0x18,0x24,0x42,0x81
;++++++++++++++++++++++++++++++++++++
14
; Обход №7.
;++++++++++++++++++++++++++++++++++++
TEXT_1_6 movlw high STR_1_6; 16
movwf PCLATH ; 17
movf Reg,W ; 18
addlw low STR_1_6 ; 19
btfsc Status,C ; 20
incf PCLATH,F ; 21
movf Reg,W ; 22

addwf PCL,F ; 23
; 0x00,0x00,0x00,
STR_1_6 dt 0x66,0x66
; ,0x00,0x00,0x00
;--------------------------------------------------------------------------------
; Данные 2-й страницы 1-го кристалла
;--------------------------------------------------------------------------------
....................................

Примечание: если кто-то из Вас пожелает увидеть своими глазами "вышележащую"


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

В процедуре обхода №7, обратите внимание на цифры, выделенные зеленым цветом.


Это и есть те 23 дополнительные команды, которые нужны для организации одной
процедуры обхода.
Общее количество дополнительных команд, требуемых для организации 6-ти обходов
(самый первый обход - "материнский". Не считаю):
23 х 6 = 138
Минус, в общей сложности, 26 "убитых" команд retlw 0x00. Получается:
138 – 26 = 112
Это и есть то количество команд, на которое увеличится "объем" программы, по
сравнению с "материнской".
Это - "в минусах".
Посмотрим, что "в плюсах".
26 "убитых" байта данных "тянут" на "грубый" выигрыш по времени
26 х 34 = 884 м.ц.
Минус 6 х 10 = 60 м.ц. дополнительной задержки. Получается:
884 – 60 = 824 м.ц. (в данном случае, 824 мкс.)
Это и есть выигрыш по времени.
Процедура вывода данных на индикацию, по сравнению с "материнской" ("сплошное"
заполнение) будет отрабатываться на 824 мкс. быстрее.
Проверил в MPLAB. Соответствует.
Согласитесь со мной, что речь идет о достаточно существенном выигрыше по
времени.
И это с учетом того, что сие есть выигрыш от компромиссной оптимизации (пусть
даже и "псевдо". На суть не влияет) всего одной страницы.
А ведь этих страниц - 16 штук.
Конечно же, компромиссная оптимизация может быть и не такой эффективной, но в
любом случае, выигрыш по времени будет.
Нужно только как следует понять ее суть и освоить тот "набор инструментов", с
помощью которого "проворачивается это дельце".
Во всем этом "действе", присутствует "явно выраженный" критерий компромиссной
оптимизации.
Критерий компромиссной оптимизации учитывает технический (не
организационный!) аспект компромиссной оптимизации.
То есть, если нужно обойти какой-то массив байтов, состоящий из байтов (или даже
из одного байта) с числовым значением 00h или FFh, то это делается не абы как, а

15
по определенным "правилам игры", которые есть не что иное, как вполне
определенный алгоритм программной организации обхода.
Как именно Вы этим "добром" распорядитесь - Ваше личное дело.
Мнения могут быть разными.
Можно даже забыть все это как кошмарный сон и "гнать сплошняк".
Только осмелюсь напоминить, что "шустрые программы под каждым кустом не
валяются".
По нашим "тяп-ляповским" временам, каждая такая программа - "на вес золота".
Поэтому и "трепыхаюсь".
И не нужно смущаться тем, что рассмотривается "псевдокомпромиссная оптимизация",
в результате которой на индикацию выводятся "кракозябры".
В данном случае, по отношению к 0-му "кадру", этот "номер не прошел", но он
"пройдет на ура" в дальнейшем.
Вопрос: "Почему"?
Ответ: потому, что 1-й "кадр" "убъет" картинку по умолчанию (0-й "кадр").
То есть, "по верху" 0-го "кадра", будет что-то записано, и после этого, про 0-й "кадр",
можно забыть, как про кошмарный сон.
Ну ладно, с "программным механизмом" реализации обходов более-менее разобрались
(надеюсь на это), но после этого возникает мощнейший вопрос:

"Каков критерий выбора того, что нужно обходить"? (критерий обхода)

Критерий обхода, учитывает организационный аспект компромиссной


оптимизации.
При этом, большое значение имеет то, с каким именно "кадром" происходит работа, и
то, каковым было содержимое предыдущего "кадра", а также и "место дислокации" (в
пределах страницы графического модуля) массива байтов, который нужно обойти.
Вопросец совсем не слабый.
Особенно с учетом того, что графический модуль "помнит" картинку, выведенную на
индикацию ранее.
Причем, он, каналья, помнит даже то, что ужасно мешает текущим делам.
Вывод: в ладоши хлопать рановато.
Пока в ладоши хлопает тот, кто сидит за кулисами.
Но "упорные, русские колобки продолжают следствие".
А они, как известно, круглые, шустрые и катятся куда хотят.
Вот и я "покатился", в ставшее уже почти родным, глухое и заповедное место, в
котором нет "ни Макара, ни прикрепленных к нему телят".
"Докатился".
"Окидываю орлиным взором текущее поле битвы" (ей-Богу, скоро превращусь в "гибрид
Мюнхаузена с Кутузовым").
Полный штиль. Только леший за леском ухает.
Это хуже всего. Эквивалентно максимальной степени коварства.
Если бы Змей Горыныч, со своим огнеметом, прилетел, то было бы проще.
Значит нужно по-шпионски провоцировать, выявлять места дислокации вероятного
противника и колошматить его от души, пока у него сопли не потекут.
Вот этим нужным & полезным делом и займусь.
Но только в следующем подразделе.

"Практикум по конструированию устройств на PIC контроллерах"      http://ikarab.narod.ru       E-mail: karabea@lipetsk.ru


16
17