01 апреля 2021

           Этюды 
Alone Coder 

   Если   выполняется  долгая  операция  и
негде  поставить  честный процентомер (на─
пример, это сильно замедлило бы работу),то
можно написать так:
       ld a,r
       add a,a
       call showprogress
   Теперь  процентомер будет вызываться  в
128 раз реже.
   Используется  в ZXRar  и в  графическом
редакторе Scratch.

                 * * *

   Переворот   строки  байтов  (de=начало,
bc=длина):
       ld h,b
       ld l,c
       add hl,de ;hl=конец+1
       srl b
       rr c ;bc=wid/2 
mirrorbytes0 
       dec hl
       ld a,(de)
       ldi
       dec hl
       ld (hl),a
       jp pe,mirrorbytes0

                 * * *

   В прошлый раз мы не показали,как подго─
товиться к циклу djnz:dec c:jr nz:
       ld a,c
       dec bc
       inc b
       ld c,b ;bc=1..256 => c=1,
               ;bc=257..512 => c=2...
       ld b,a

                 * * *

   В дополнение к "Этюдам" в #11 (там было
определение  AY )  -  определение  наличия
TurboSound FM: оно важно,потому что плейер 
под TFM работает с ожиданием регистра ста─
туса, которого нет на обычном AY.
   Алгоритм:
  - включаем  FM режим и режим чтения ста─
туса.
  - пишем  в  0-й регистр число с установ─
ленным битом 7.
  - немного ожидаем.
  - читаем регистр, смотрим 7-й бит.
   Если  нолик, то  это TFM, и он готов. А
если  нет  (то есть прочиталось записанное
число или пустая шина), то это не TFM.
   В Evo SDK это выглядит так:

       LD BC,#FFFD
       LD A,%11111000
       OUT (C),A ;FM on,status rg read on
       ld d,b
       dec d
       jr nz,$-1 ;pause
       XOR A
       OUT (C),A ;select rg 0
       dec d
       jr nz,$-1 ;pause
       LD B,#BF
       OUT (C),B ;write some data in rg 0
       dec d
       jr nz,$-1 ;pause
       inc a ;a=1
       LD B,#FF
       INF ;read status (P=ready)
       JP P,tfmpresent ;a=1
       xor a ;TFM not present 
tfmpresent 
       ld (TURBOFMON),a

  NB: при  текущей  реализации  вайтов  в
ZX Evo нельзя работать с TFM на частоте 14  
МГц. Нужно  временно  включать 3,5 МГц при 
работе с портами TFM! Иначе звук портится. 
В эмуляторе это обнаружить нельзя! 

                 * * *

   Наши  постоянные читатели помнят услов─
ное сложение с константой за фиксированное
время: 
;CY=flag 
;a=исходное значение 
       jc $+4
       jr $+4
       add a,что условно прибавить 
;a=result 
:19 t 

   Дополним его условным сложением с реги─
стром за фиксированное время: 
;CY=flag 
;a=исходное значение 
;b=что условно прибавить 
       jr c,$+6
       nop
       jp $+5
       ret nc
       add a,b 
;a=result 
:21 t 

   Или так: 
;CY=flag 
;с=исходное значение 
;b=что условно прибавить 
       sbc a,a
       and b
       [add a,c] ;не надо, если исходно 0
       ld c,a 
;a=result 
:12(16) t 

                 * * *

   Как перейти  на  следующий  столбец EGA
экрана на  АТМ-Turbo (если экран подключен
в 4000, 8000):
       ld a,0x9f ;0xa0,если не используем
                          ;верхние 8 линий
       cp h
       ld bc,0x4000
       adc hl,bc
       jp pe,nextstq ;в половине случаев
                   ;8000->с000 (надо 6000)
               ;или a000->e001 (надо 4001)
      inc a ;если используем верх.8 линий
       xor h
       ld h,a 
nextstq 

   Если  экран  подключен в 8000, c000, то
переход можно делать так:
       bit 6,h
       set 6,h
       jr z,$+2+4+2+2+1
       ld a,h
       xor 0x60
       ld h,a
       and 0x20
       jr nz,$+3
       inc hl

   В некоторых случаях выгоднее для всех 4
вариантов  расположения  спрайта по X сде─
лать  свою  ветку  запоминания  адресов  в
стек, например (в Супер Марио ):

      macro COUNTSCRADDR
       add a,(hl)
       inc h
       ld c,a
       adc a,(hl)
       sub c
       ld l,c
      endm

      macro NEXTCOLUMNS0
       ld h,a ;.00
       push hl
       set 6,h ;.10
       push hl
       xor 0x20
       ld h,a ;.01
       push hl
       set 6,h ;.11
      endm
      macro NEXTCOLUMNS1
       ld c,a
       xor 0x40
       ld h,a ;.10
       push hl
       xor 0x60
       ld h,a ;.01
       push hl
       set 6,h ;.11
       push hl
       ld h,c ;.00
       inc hl
      endm
      macro NEXTCOLUMNS2
       ld h,a
       set 5,h ;.01
       push hl
       set 6,h ;.11
       push hl
       ld h,a ;.00
       inc hl
       push hl
       set 6,h ;.10
      endm
      macro NEXTCOLUMNS3
       ld c,a
       xor 0x60
       ld h,a ;.11
       push hl
       ld h,c ;.00
       inc hl
       push hl
       set 6,h ;.10
       push hl
       ld a,h ;не старое, т.к. был inc hl
       xor 0x60
       ld h,a ;.01
      endm

prcharxy 
;de=gfx 
;la=yx 
;CY=0 
       ld h,tytoscr/256
      rra
      jr c,prcharxy_nextcolumns13
      rra
      jr c,prcharxy_nextcolumns2 
prcharxy_nextcolumns0 
       COUNTSCRADDR
       NEXTCOLUMNS0
       jp prcharxy_scrok 
prcharxy_nextcolumns2 
       COUNTSCRADDR
       NEXTCOLUMNS2
       jp prcharxy_scrok 
prcharxy_nextcolumns13 
      srl a
      jr c,prcharxy_nextcolumns3 
prcharxy_nextcolumns1 
       COUNTSCRADDR
       NEXTCOLUMNS1
       jp prcharxy_scrok 
prcharxy_nextcolumns3 
       COUNTSCRADDR
       NEXTCOLUMNS3 
prcharxy_scrok 

   Запоминается 3 адреса,четвёртый остаёт─
ся в регистрах. Ширина спрайта в этой игре
равна  8  пикселей, но это  не ограничение
метода, а  особенность  кода самой игры. В
Evo SDK каждый слой экрана  отрисовывается 
целиком, и там тоже запоминается 4 адреса.

   В залитом 3D движке под ATM-Turbo 2 ис─
пользуется такой код:

       ld (hl),a ;0x0000
       set 6,h
       ld (hl),a ;0x4000
       add hl,bc ;bc=0xe000
       ld (hl),a ;0x2000
       set 6,h
       ld (hl),a ;0x6000
       add hl,de ;de=0xa001

   Можно для экономии регистровой пары его
переписать на sbc hl,bc ... add hl,bc: inc 
hl или на res 6,h:set 5,h ... add hl,bc. 


                 * * *

   Как  возвращать  ошибки из процедур на─
верх? Я обычно по ошибке выхожу в исходную
точку программы с восстановлением стека.Но
пусть мы хотим обработку ошибок с правиль─
ным освобождением ресурсов.
   Пусть  ошибка  возвращается  как  CY=1.
Простейший способ в стиле iS-DOS:
       <делаем что-то>
       call proc1
       ret c
       <делаем что-то>
       call proc2
       ret c
       <делаем что-то>
       jp proc3
   При  этом можно даже вернуть тип ошибки
в каком-нибудь  регистре  через  все  про─
цедуры.
   Во  многих практических случаях всё со─
держимое <делаем что-то> - просто присваи─
вания типа ld rp,() и ld (),rp, которые не
меняют флаги. Поэтому можно писать так:
       <присваивания>
       call proc1
       <присваивания>
       call nc,proc2
       ret c
       <присваивания>
       jp proc3
   (Использовалось в GIF converter by DIS/
XPJ .) 
   Но тут, если мы хотим вернуть тип ошиб─
ки, придётся  запретить  использовать этот
регистр в присваиваниях.

                 * * *

   Как можно сделать процедуру захвата ре─
сурса (например, открытие  файла), которая
сама освободит его на выходе из блока:

openresource 
;if success, autopush closeresource 
;out: nz=error 
...open resource (out: nz=error)... 
       ret nz ;error
       ld hl,closeresource
       ex (sp),hl
       jp (hl)

closeresource 
;out: nz=error 
...close resource (out: nz=error)... 
       ret

   Использование:

work_with_resource 
;out: nz=error 
       call openresource1
       ret nz ;error
       call openresource2
       ret nz ;error 
...work with resources 1 and 2... 
       ret

   Применяется в Nedovigator'е.

                 * * *

   Опять-таки  в  дополнение  к "Этюдам" в 
#11 - ещё  один  способ  вызова функции по 
номеру (номера заняты не подряд):

;a=команда 
       ld hl,tcmds ;адрес списка команд
       ld bc,ncmds ;число команд в списке
       cpir
       jp nz,ошибка
       add hl,bc
       add hl,bc
       add hl,bc
       ld a,(hl)
       inc hl
       ld h,(hl)
       ld l,a
       jp (hl)

   Список команд:

tcmds 
       db 'a'
       db 's'
       db 'd'
       ...
       db 'x' 
ncmds=$-tcmds 
;дальше в обратном порядке лежат адреса 
;обработчиков: 
       dw PROC_x
       ...
       dw PROC_d
       dw PROC_s
       dw PROC_a

   Используется в NedoOS - из-за поддержки
нумерации  команд от CP/M и MSX-DOS. Самые
частые команды лежат в начале списка CPIR.
Когда  номера команд идут подряд, CPIR уже
не  нужен, достаточно перехода по таблице.
Это значительно быстрее!
   Вот вариант от NEO SPECTRUMAN'а:
       ld h,tab ;7
       ld h,(hl) ;7
       jp (hl) ;4
   А вот из Супер Марио под NedoOS:
       ;ld l,a
       or 0xc0 ;7
       ld h,a ;4
       jp (hl) ;4



Other articles:


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

Similar articles:
History - The story of KrNews VTS'a.
Warning - Memo to the user network SPbZXNet.
little about my - Telephone Directory: The Great Luke.
HOT GAMES - Top Ten ot Magic Soft.

В этот день...   21 November