Inferno #06
03 декабря 2004

For Coderz - Маленькие программерские хитрости.

           Этюды
             1. Опрос клавиш
    независимо от состояния Caps Lock.

   Допустим, нужно опросить клавишу "R". В
аккумуляторе уже есть код какой-то нажатой
клавиши.Но неизвестно состояние Caps Lock.
 

         OR 32
        CP "r"

   Именно  так сделано в ZXUnRar, при этом
не  приходится   принудительно  делать  LD
(IY+48),8 [Caps Lock on], и  потому  маску 
названия файла можно вводить,не переключая
системные  переменные. Аналогично делается
проверка расширений файла и прочих иденти-
фикаторов, которые  могут  быть записаны в
разном регистре.


             2. Опрос клавиш
        чуть короче стандартного.

   Обычный  цикл  опроса  через 5,(IY+1) и
переменную 23560 (LAST_K) можно сократить:
 

         LD HL,23560
         LD A,(HL)
        LD (HL),H ;символ #5C всё равно
                  ;неклавиатурный

   ...и дальше проверка допустимых клавиш.
   После  этого  компьютер  готов к приёму
следующей  клавиши. Это  важно  для клавиш
прокрутки и т.п. (Для  удобства  прокрутки
никогда  не забывайте установить константы 
клавиатуры  REPDEL=#5C09  и  REPPER=#5C0A. 
Первую  желательно приравнять к 15, вторую 
- к 1 .) 


 3. Проверка трёхсимвольности расширения.

   Очень короткая.Выработана при оптимиза-
ции ZXRar, она же в ACEdit:

 goodH3 
         PUSH AF
         CP "A
         JR NC,$+3
         LD A,B
         AND 32
         ADD A,65
         LD L,A
         POP AF
         CALL etoAN
         JR C,goodH3N
         LD A,B
         CALL etoAN
         JR C,goodH3N
         LD A,H
         CP 32 ;2sym
         CALL NZ,etoAN
        RET NC
 goodH3N LD B,32,H,B 
        RET
 etoAN 
         CP "0
         RET C
         CP ":
         CCF
         RET NC
         SUB L
         RET C
         ADD A,-26
        RET

   Вызывают её с параметрами: A,B,H - сим-
волы  расширения  в порядке следования. На
выходе B и H либо сохраняются (если расши-
рение трёхсимвольное),либо затираются про-
белами (если оно односимвольное). Критерий
жёстче, чем  у  Ивана Рощина: ни для каких
"xAs" исключение  не делается; имя  должно 
содержать  буквы одного какого-то регистра
и цифры.Запрещён разрывающий пробел.Пробел
может  быть в конце (для 2-символьных рас-
ширений). Имена,начинающиеся с цифры,могут
иметь  2-м  и  3-м знаками цифры или буквы
одинакового регистра.Имена,начинающиеся не
с цифробуквы, считаются односимвольными.


        4. Move для TR-DOS диска.

   Практически в любую системную программу
можно вставить функцию удаления файла, она
есть  среди  стандартных  вызовов #3D13. А
функции  Move среди стандартных нет, но её
можно  вызвать, тогда не придётся писать и
отлаживать  страшный алгоритм. (Пока отла-
дишь,он тебе диск с исходниками запорет;)) 

 MOVEDISK 
         LD HL,MOVER,(EMCALL+1),HL
        LD C,H
         CALL eM3D13
         LD HL,#3D13,(EMCALL+1),HL
        JR prcREPR
 MOVER 
         LD HL,5806
        PUSH HL
         LD A,H;-2
         LD (#5D15),A ;NO MSG
         LD (#5D1F),A ;NO LDIR?
        JP 15663

   В этом виде процедура (5806, сами пони-
маете) настроена на использование драйвера
с обработкой ошибок.У меня он обычно такой
(не  поддерживает  Retry/Abort/Ignore и не
всегда стабилен с No disk, на входе глушит
звук и выключает IM2, на выходе включает):

 eM3D13 
         LD (EMBC+1),BC
         LD (EMBC+4),DE
         LD (EMBC+7),HL
         LD (EMSP+1),SP
        CALL AYOFF ;обычная глушилка AY
 EMREP  LD DE,#5C00,BC,#400,HL,SYSBUF,SP,HL 
         JR NZ,$+3
         EX DE,HL
        LDIR
 DRV     LD A,0,C,1 
         CALL #3D13
        LD A,(DRV) ;PUSH:POP глючит в MOVE
        CP -1
        LD ($-1),A
         LD C,#18
        CALL NZ,#3D13
 EMBC    LD BC,0,DE,0,HL,0 
        LD A,7
        CP C
        JR C,EMCALL
        LD A,195,(23746),A
EMCALL  CALL #3D13 
 EMLDIQ  LD HL,(23796) 
         PUSH HL
         LD DE,#5C00,BC,#400
         LD HL,SYSBUF
         LDIR
         POP HL
        LD (23796),HL
 EMSP    LD SP,0 
         LD A,201,(23746),A
        DI
 EMQq    LD DE,IMTAB+256,A,IMER,(DE),A 
         DEC D
         LD (DE),A
         INC E
         JR NZ,$-2
         LD A,D,I,A
         IM 2
         OR A
        RET
POPEMQ  POP AF 
 EMQ     CALL EMQq 
         EI
        RET
 ONERR 
         EX (SP),HL
         LD A,L
         CP 8020
         JR NZ,EMREP
         CALL 8020
         JR NC,EMSP
         POP HL
        RET
 

 23747/8 уже должен быть адрес ONERR )
   Процедуре нужно 4 килобайта буфера меж-
ду адресом, лежащим  в STKEND (23653/4), и
регистром  SP. Другим подпрограммам TR-DOS
(например,delete и #18) требовалось макси- 
мум  257 байт, не считая  стека. Со стеком
нужно  измерять  в каждом отдельном случае
так: в конце  бейсик-области  (обязательно
ниже  STKEND, поэтому нужно корректировать
STKEND ) разместить  некие данные, сохран- 
ность  которых  проверять  после  дисковых
операций. Когда найдёте минимальный размер
стека, лучше сделать сверх него запас в 16
байт, т.к. глубина  стека в разных версиях
TR-DOS разная. Например,рамдиску нужен бо- 
лее  глубокий стек, ведь он должен опреде-
лить текущую страничку,а потом включить её
обратно.


  5. Случайное число в нужном диапазоне.

   Пусть  у вас имеется алгоритм генерации
случайного числа от 0 до 255. Например:

[cut] 
Я писал так: 

LD HL,(SEED) 
LD A,H 
AND 31 
LD H,A 
INC H,L 
LD A,(HL) 
LD (SEED),HL 

Можешь  вместо  INC H,L вписать сложение с 
чем-нибудь  или даже умножение на, скажем, 
5, потом сложение.Главное,проследить,чтобы 
период повторения был побольше и процедура 
не долго шагала в близких адресах (там по- 
дряд нули бывают, или ff-ки, или текстовые 
мессаги). 

Вероятности чисел будут равны их частоте в 
ПЗУ. Если надо более равномерное распреде- 
ление, то: 

LD HL,(SEED) 
LD A,H 
AND 31 
LD H,A 
INC L 
LD A,(HL) 
INC H 
RLCA 
XOR (HL) 
LD (SEED),HL 

А вот  процедура  из Wolf2004, независимая 
от ПЗУ (т.е. полностью  предсказуемая  при 
переносе с компьютера на компьютер): 

LD HL,(SEED) 
LD B,H,C,L 
DB ")))) 
ADD HL,BC 
LD BC,20981 
ADD HL,BC 
LD (SEED),HL 
LD A,H 

Но только  последовательности типа цветных 
квадратиков  я ей не генерировал. Она была 
написана для одиночных значений. 
[end cut] 

   Чтобы превратить это число в число, бо-
лее-менее равновероятно распределённое ме-
жду 0 и n-1, лучше делать не так:
 

         LD C,n
         SUB C
         JR NC,$-1
        ADD A,C

   а так:
 

         ADD A,n
        JR NC,$-2

   В этом совет и заключается.


         6. Печать сообщений 8x8.

   Пусть  у  нас  имеется процедура печати
буквы 8x8. Очень часто требуется.Например,
такая:

 PR88    PUSH DE,HL 
         LD H,0,L,A ;если FNT кратен 1024,
         DB ")))"   ;то надо заменить эти
         LD BC,FNT ;команды на классические
         ADD HL,BC ;rlca:l,a,h,'FNT/4:db"))
         LD B,8
         LD A,(HL),(DE),A
         INC L,D
         DJNZ $-4
         POP HL,DE
         INC E
        RET

   Собственно,это может быть и печать бук-
вами другого размера. А нам нужно с её по-
мощью напечатать, например, меню в окошке,
причём  так, чтобы  в тексте было поменьше
лишних пробелов  и управляющих кодов. Точ-
нее, чтобы был только один управляющий код
- 13 (Enter) и терминатор - 0.

   Делается так:

 PRTXTCR LD DE,0 
         LD A,E
         ADD A,32
         LD E,A
         JR NC,$+6
         LD A,D
         ADD A,8
        LD D,A
;Вот отсюда процедуру нужно вызывать 
PRTXT   LD (PRTXTCR+1),DE 
 PRTXT0  LD A,(HL) 
         INC HL
         CP 13
         JR Z,PRTXTCR
         RET C
         CALL PR88
        JR PRTXT

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


              7. Регистр R.

   Прибавить число к младшим 7 битам реги-
стра R, чтобы скорректировать этот регистр
после какой-то задержки, можно так:
 

         LD A,R
         RLCA
         ADD A,число*2
         RRCA
        LD R,A


  8. Условная компиляция (продолжение).

   Если  вы хотите получить при компиляции
число, равное  0, если  metka=0, и 1, если
metka<>0, то делайте не так: 

IFN metka 
metka=1 
ENDIF 

   а так:

metka=~metka<1~&1 

   Где  ~metka  понимается   ALASM'ом  как
0~+metka, т.е. metka-1. (Если интересно,то 
-~metka, равно  как  и ~-metka, понимается 
как -1-metka, и это короче написать в виде
metka~ .) 
   Пригождается  для  создания  логических
переменных,который можно применять в слож-
ных  условиях типа IFN metka1&metka2. Так,
например, сделано в ACEdit.
   А ZASM'овское выражение  IFUSED заменя-
ется на IF ~?метка. И,раз пошёл разговор о
нём,то IFDEF превращается IF ?метка, IFN в
IF, а IF в IFN. 

   Кстати, рекомендую  для экономии памяти
все таблицы вида DB #xx,#yy... заменять на
DD xxyy..., а вида  DW #xxyy,#zztt... - на 
DD yyxxttzz... 
 

   P.S.: Vitamin велел написать,что комме-
нтировать куски программы можно через IF 1 
...ENDIF. Лично я использую IFN 0...ENDIF. 

A. Coder 




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
News - Умельцы из Молдовы нагрели на круглую сумму несколько падких на эротику американцев.
Ottyag - ничего.
wArЫz! - Psychoz #5, Polesse 18, 19, 19a, Dune #7, Reflex #1, Specinfo #4, Space Wolf #1, Optron 43, Don News 14, Plutonium #17.

В этот день...   26 сентября