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

2-1/7.

"Учебно-тренировочная" оптимизация кода 1-го "кадра", с "упором" на


обеспечение максимальной скорости отработки процедуры.

Итак, в части касающейся дроблений, для обеспечения полномасштабной,


компромиссной оптимизации (основная задача - обеспечение максимальной скорости
отработки процедуры), нужно:

1. В 1-м "кадре", обойти все массивы байтов с числовыми значениями FFh


(они подтверждают ранее установленные состояния).
2. В дальнейшем, обойти массивы байтов, которые подтверждают ранее
установленные состояния, и массивы байтов с любой "начинкой", которые
уничтожать нельзя (сохранение фиксированных элементов картинки).

Вопрос: "А каков практический смысл в компромиссной оптимизации кода картинки


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

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

Эти "живописные дела" делаются в "штатной, Виндовской рисовалке" Paint.


Отличная программа. Работа на уровне пикселей. Очень часто ей пользуюсь.
Если кто-то из Вас с ней не дружит, то советую подружиться. Не прогадаете.
Примечание: любую картинку, имеющую место быть на мониторе компьютера
(в том числе и картинку окна любой открытой программы), можно
скопировать в буфер обмена, нажав на клавишу Prt Sc SysRq.
Далее, вставляете содержимое буфера обмена, например, все в тот же Paint,
и делайте с картинкой все что хотите.
В числителе дроби - номер байта (байтов), который обходится.
В знаменателе дроби - адрес байта (байтов), который обходится (HEX).
И то, и другое - в пределах страницы графического модуля.
Таким образом, имеет место быть некая "карта байтов", с числовыми значениями FFh,
которые нужно обойти.
Вопрос: "Зачем"?
Ответ: затем, чтобы попусту не тратить вполне приличное время на подтверждение
ранее установленных (в 0-м "кадре") состояний (FFh).
За счет этого и обеспечивается выигрыш по времени.
Не трудно догадаться о том, что в данном случае, о каком-то значительном выигрыше
по времени (по сравнению с временем отработки одного, полного цикла "матери") речи
не идет (имеют место быть достаточно "худосочные" массивы), но в других случаях, он
может оказаться весьма существенным.
Вывод: картинки выгодно "ваять" не абы как, а с "хитрым прищуром на перспективу"
обеспечения наибольшей эффективности компромиссной оптимизации (в дальнейшем,
постараюсь "просканировать" принцип такого "ваяния").
В данном же случае, речь идет о "въезде" в достаточно конкретную, универсальную и
"дубовую механику" обхода того, что нужно обойти.
Вопрос: "Как это делается"?
Ответ: см. "нижележащее" (в части касающейся 5-й страницы 1-го кристалла):

;....................................
;....................................
;....................................
;------------------------------------------------------------------------------

2
; Запись в 5-ю страницу 1-го кристалла
;------------------------------------------------------------------------------
call STRANICA_5 ; Выбор 5-й страницы.
call STOLB_1 ; Выбор адреса 1-го столбца (00h).
movlw .2 ; 2 прохода.
movwf Temp ;

WR_5 movf Temp,W ;


sublw .2 ;
movwf Reg ;
call TEXT_5 ; Переход в ПП TEXT_5.
movwf PortC ;
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5 ;
;++++++++++++++++++++++++++++++++++++
; Обход №1.
;++++++++++++++++++++++++++++++++++++
movlw b'01000100' ; Выбор адреса 5-го столбца (04h).
movwf PortC ;
call STROB ;
;---> Возврат по стеку из ПП STROB
movlw .8 ; 8 проходов.
movwf Temp ;

WR_5_1 movf Temp,W ;


sublw .8 ;
movwf Reg ;
call TEXT_5_1 ; Переход в ПП TEXT_5_1.
movwf PortC ;
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5_1 ;
;++++++++++++++++++++++++++++++++++++
; Обход №2.
;++++++++++++++++++++++++++++++++++++
movlw b'01001110' ; Выбор адреса 15-го столбца (0Eh).
movwf PortC ;
call STROB ;
;---> Возврат по стеку из ПП STROB
movlw .4 ; 4 прохода.
movwf Temp ;

WR_5_2 movf Temp,W ;


sublw .4 ;
movwf Reg ;
call TEXT_5_2 ; Переход в ПП TEXT_5_2.
movwf PortC ;
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5_2 ;
;++++++++++++++++++++++++++++++++++++
; Обход №3.
;++++++++++++++++++++++++++++++++++++
movlw b'01010100' ; Выбор адреса 21-го столбца (14h).
movwf PortC ;
call STROB ;
;---> Возврат по стеку из ПП STROB
movlw .15 ; 15 проходов.
movwf Temp ;
3
WR_5_3 movf Temp,W ;
sublw .15 ;
movwf Reg ;
call TEXT_5_3 ; Переход в ПП TEXT_5_3.
movwf PortC ;
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5_3 ;
;++++++++++++++++++++++++++++++++++++
; Обход №4.
;++++++++++++++++++++++++++++++++++++
movlw b'01100100' ; Выбор адреса 37-го столбца (24h).
movwf PortC ;
call STROB ;
;---> Возврат по стеку из ПП STROB
movlw .8 ; 8 проходов.
movwf Temp ;

WR_5_4 movf Temp,W ;


sublw .8 ;
movwf Reg ;
call TEXT_5_4 ; Переход в ПП TEXT_5_4.
movwf PortC ;
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5_4 ;
;++++++++++++++++++++++++++++++++++++
; Обход №5.
;++++++++++++++++++++++++++++++++++++
movlw b'01101101' ; Выбор адреса 46-го столбца (2Dh).
movwf PortC ;
call STROB ;
;---> Возврат по стеку из ПП STROB
movlw .5 ; 5 проходов.
movwf Temp ;

WR_5_5 movf Temp,W ;


sublw .5 ;
movwf Reg ;
call TEXT_5_5 ; Переход в ПП TEXT_5_5.
movwf PortC ;
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5_5 ;
;++++++++++++++++++++++++++++++++++++
; Обход №6.
;++++++++++++++++++++++++++++++++++++
movlw b'01110100' ; Выбор адреса 53-го столбца (34h).
movwf PortC ;
call STROB ;
;---> Возврат по стеку из ПП STROB
movlw .8 ; 8 проходов.
movwf Temp ;

WR_5_6 movf Temp,W ;


sublw .8 ;
movwf Reg ;
call TEXT_5_6 ; Переход в ПП TEXT_5_6.
movwf PortC ;
4
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5_6 ;
;++++++++++++++++++++++++++++++++++++
; Обход №7.
;++++++++++++++++++++++++++++++++++++
movlw b'01111101' ; Выбор адреса 62-го столбца (3Dh).
movwf PortC ;
call STROB ;
;---> Возврат по стеку из ПП STROB
movlw .3 ; 3 прохода.
movwf Temp ;

WR_5_7 movf Temp,W ;


sublw .3 ;
movwf Reg ;
call TEXT_5_7 ; Переход в ПП TEXT_5_7.
movwf PortC ;
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_5_7 ;
; Переход на заполнение следующей страницы.

;....................................
;....................................
;....................................

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

addwf PCL,F ;
STR_5 dt 0x00,0x00
;;; ,0xFF,0xFF,
; Выводятся 2 байта. 2 байта обходятся.
;++++++++++++++++++++++++++++++++++++
; Обход №1.
;++++++++++++++++++++++++++++++++++++
TEXT_5_1 movlw high STR_5_1;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_5_1 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_5_1 dt 0x00,0x00,0x00,0x00
dt 0x00,0x00,0x00,0x00
;;; ,0xFF,0xFF,
; Выводятся 8 байтов. 2 байта обходятся.
;++++++++++++++++++++++++++++++++++++
; Обход №2.
;++++++++++++++++++++++++++++++++++++

5
TEXT_5_2 movlw high STR_5_2;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_5_2 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_5_2 dt 0x00,0x00
dt 0x00,0x00
;;; ,0xFF,0xFF,
; Выводятся 4 байта. 2 байта обходятся.
;++++++++++++++++++++++++++++++++++++
; Обход №3.
;++++++++++++++++++++++++++++++++++++
TEXT_5_3 movlw high STR_5_3;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_5_3 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_5_3 dt 0x0C,0x0C,0x0C,0x0C
dt 0x0C,0x0C,0x0C,0x0C,0x0F,0x07,0x00,0x00
dt 0x00,0x00,0x7F
;;; ,0xFF,
; Выводятся 15 байтов. 1 байт обходится.
;++++++++++++++++++++++++++++++++++++
; Обход №4.
;++++++++++++++++++++++++++++++++++++
TEXT_5_4 movlw high STR_5_4;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_5_4 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_5_4 dt 0xC0,0xC0,0xC0,0xC0
dt 0xC0,0xC0,0xC0,0xC0
;;; ,0xFF,
; Выводятся 8 байтов. 1 байт обходится.
;++++++++++++++++++++++++++++++++++++
; Обход №5.
;++++++++++++++++++++++++++++++++++++
TEXT_5_5 movlw high STR_5_5;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_5_5 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_5_5 dt 0x7F,0x00,0x00
dt 0x00,0x00
;;; ,0xFF,0xFF,
; Выводятся 5 байтов. 2 байта обходятся.
;++++++++++++++++++++++++++++++++++++
; Обход №6.
;++++++++++++++++++++++++++++++++++++
TEXT_5_6 movlw high STR_5_6;
6
movwf PCLATH ;
movf Reg,W ;
addlw low STR_5_6 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_5_6 dt 0xC1,0xC1,0xC1,0xC1
dt 0xC1,0xC1,0xC1,0xC1
;;; ,0xFF,
; Выводятся 8 байтов. 1 байт обходится.
;++++++++++++++++++++++++++++++++++++
; Обход №7.
;++++++++++++++++++++++++++++++++++++
TEXT_5_7 movlw high STR_5_7;
movwf PCLATH ;
movf Reg,W ;
addlw low STR_5_7 ;
btfsc Status,C ;
incf PCLATH,F ;
movf Reg,W ;

addwf PCL,F ;
STR_5_7 dt 0x7F,0x00,0x00
; Выводятся 3 байта.
;....................................
;....................................
;....................................

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


Содержимое "раздробленной" таблицы (активное содержимое "подтаблиц") выделено
темно-красным цветом.
Так как в данном случае, "табличные координаты" числовых значений байтов
сохранены, то наблюдается некая "текстовая разбросанность" этих байтов.
Естественно, что ничто не мешает сдвинуть соответствующие числовые значения
байтов влево, и вообще, сформировать "подтаблицу" так, как Вам угодно.
В данном случае, в соответствии с числом массивов байтов, которые нужно обойти,
"материнская" таблица (64 байта) дробится на 8 частей.
После вывода на индикацию последнего массива, происходит переход на заполнение
следующей страницы.
Не следует пугаться объема этой процедуры, а также и общего объема программы,
так как все дробления происходят по одному и тому же, достаточно "дубовому",
принципу (без каких бы то ни было выдающихся "выкрутасов").
Нужно только безошибочно назначить адрес 1-го байта той или иной "подтаблицы" и
количество байтов, входящих в ее состав.
Короче, работа на внимательность.
У кого с этим человеческим качеством все ОК, у того и проблем не будет.
Я бы не сказал, что это сложно.
Даже если Вы и ошибётесь в назначении оного, и "дисплей помертвеет", то никакой
трагедии из этого делать не нужно.
В этом случае, "русские колобки" поступают так: нужно просто последовательно,
начиная, например, с самой верхней процедуры, "поврезать", в их концы (после goto
WR_...), "мертвяки" (goto $).
Только при врезке последующего "мертвяка", не забудьте убрать предыдущий.
С помощью этого нехитрого приема и анализа результата его применения ("ловля на
живца", в "железе"), можно "железобетонно" обнаружить, в какой именно "подтаблице"
имеет место быть ошибка, а затем и устранить ее.
Заверяю Вас, ничего сложного в этом нет: в "сектор обстрела" можно выйти
элементарно (логика - детская).
С точки зрения защиты психики от неблагоприятного воздействия этой "огроменной
портянки", выгодно руководствоваться мудрейшим, жизненным правилом типа
7
"объем - по барабану".
Мотивация: если есть четкое понимание того что делаешь, плюс, внимание, то на этот
объем, по большому счету, можно "наплевать" (в пределах разумного. Совсем уж
"шапками закидывать" не стоит).
Естественно, что сия стратегия "жизнеспособна" при условии, что в памяти программ
ПИКа, "есть где разгуляться".

Программа, в которой полномасштабно, в соответствии с "картой обходов" (см. рис. 2),


реализован алгоритм компромиссной оптимизации 1-го "кадра", называется 12864_3.asm
(прилагается).
Визуальный результат работы этой программы точно такой же, как и результат работы
программы 12864_1.asm, но с одним существенным отличием: программа 12864_3.asm
отрабатывается быстрее программы 12864_1.asm на 904 мкс.
Может быть, в данном случае, и покажется, что "девиденды маловаты", но следует
учесть то, что "плотность застройки" 1-го "кадра", байтами с числовым значением FFh,
достаточно низка.
То есть, обходятся достаточно "худосочные" массивы байтов (максимум - 2 байта).
Но ведь может обходиться и нечто более существенное.
В этом случае, выигрыш по скорости будет прямо пропорционально соответствовать
"силе жизнеутверждающего пинка".
Причем, можно добиться существенного выигрыша по скорости, с использованием
малого количества дополнительных команд.
Просто специфика всего этого "хитрого действа" такова, что нужно ориентироваться на
конкретные "конструкции" картинок или их элементов, и в зависимости от этого,
принимать те или иные решения.
Программа 12864_3.asm не удобна в том смысле, что процедуры работы со
страницами графического модуля "разорваны" на 2 части, и они, по тексту программы,
находятся далековато друг от друга.
Чтобы понять что к чему, приходится существенно прокручивать "портянку" текста
программы, что не совсем удобно.
Поэтому я "сваял" программу 12864_4.asm (прилагается), в которой таких "разрывов"
нет.
Правда за это пришлось "заплатить" дополнительными, безусловными переходами (15
штук) на начало заполнения следующих страниц графического модуля.
Пояснение: без них будет "Гитлер капут".
Конечно это не самый выгодный вариант, но зато "все в куче".
Думаю, что это поможет Вам при "въезде" в дробления.

А теперь о том, что связано с переходами между страницами памяти программ ПИКа.
MPLAB - очень мудрая "программулина".
Она предупреждает о каждом переходе с одной страницы памяти программ ПИКа на
другую.
Это выглядит так ("привязка" к программе 12864_3.asm):

Это предупреждение имеет примерно такой подтекст:

8
Message[306]: Уважаемый пользователь. В том, что Вы наваяли, имеет место
быть переход из одной страницы памяти программ в другую. Кабы чего
плохого не случилось. Советую озаботиться".

И эти сообщения игнорировать не в коем разе нельзя (вспомните про "Гитлер капут").

Если такое сообщение имеет место быть, то нужно


- щелкнуть по нему и "выйти в сектор обстрела",
- в "секторе обстрела", перед командой call или goto (на нее указывает курсор),
нужно "врезать волшебную" комбинацию команд, о которой было упомянуто ранее.

"Общелкав" таким немудреным образом все сообщения Message[306] и "врезав" в


текст программы соответствующие "противобяковые" группы команд, можно совершенно
не опасаться "прыжковых бяк".
Все будет в полнейшем ОКее. Комфорт - стопроцентный.
Проверил лично.
И "лазить" по памяти программ (окно ROM) не нужно ("блюдечко с голубой
каемочкой").
Примечание: обращаю Ваше внимание на то, что после обеспечения условий
"безбякового" перехода с одной страницы памяти программ ПИКа на другую, сообщения
Message[306] не "исчезают". "Убить" их можно только их исключением из списка
ошибок (директива ERRORLEVEL). Но зачем "убивать друга"?
Такой комфорт, прежде всего, хорош тем, что позволяет отказаться от "массированного
применения" неоправданно большого количества "волшебных" комбинаций команд, а
использовать только те из них, которые действительно необходимы.
Этот ОКей так убедителен и сокрушителен, что даже диву даешься, каких заоблачных
высот достигла шахматная мысль (это я о Нью-Васюках и об Остапе Бендере
вспомнил).
Ну раз уж речь зашла о шахматах, то скажу так: игра продолжается.
Болевые точки нащупаны. Мускул более-менее протренирован (пока, на манекене).
Потихоньку грядет неумолимый "ход конем": компромиссная оптимизация того, что
очень существенно.
А именно, всего того "безобразия", которое имеет место быть от 2-го цикла вывода
данных на индикацию и далее.

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

10