Страница Ивана Рощина > Статьи >

© Иван Рощин, Москва

ZXNet: 500:95/462.53
E-mail: bestview@mtu-net.ru
WWW: http://www.ivr.da.ru

Быстрая переброска экрана

(«ZX-Ревю» 11—12/1997)
Дата последнего редактирования: 17.03.2003.

Известно, что пересылка содержимого экранной памяти (#1800 байтов) занимает больше времени, чем промежуток между двумя прерываниями. Тем не менее, если изображение должно изменяться не каждые 1/50 секунды, а хотя бы каждые 1/25 секунды, есть способ так выполнить пересылку, что пока луч рисует текущий кадр — мы видим первую картинку; когда луч рисует следующий кадр — мы видим уже вторую картинку.

Рассмотрим, в чём заключается этот способ. Пусть в видеопамяти (#4000—#5800) находится первая картинка. После прихода импульса прерывания луч начинает рисовать изображение, начиная с верхнего края экрана, рисует бордюр и в конце концов прорисовывает самую верхнюю строку малого экрана.

+--------------------+ \
|       Бордюр       | |
|  +--------------+  | |
|  |              |  | |
|  | Малый экран  |  | | Телевизионный экран
|  |              |  | |
|  +--------------+  | |
|                    | |
+--------------------+ /

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

Переброска картинки продолжается до того, как луч прорисует весь экран. Посчитаем, сколько это займёт времени: весь экран — 320 строк, верхняя часть бордюра — 80 строк, и ещё одну строку мы специально пропустили. Т.к. время прорисовки одной строки — 224 такта, получаем (320–81)*224=53536 тактов. За это время, конечно, полностью обновить видеопамять не получится, но это пока и не нужно.

После того, как луч прорисует весь экран, поступит следующий импульс прерывания, и начнёт прорисовываться следующий кадр. Пока луч рисует верхнюю часть бордюра и верхнюю часть малого экрана (т.е. уже вторую картинку), мы, не теряя времени, перебрасываем в видеопамять оставшуюся часть второй картинки. Переброска должна быть завершена до того момента, как луч начнёт рисовать нижнюю строку малого экрана, т.е. процедура переброски должна укладываться в 53536+(80+192–1)*224=114240 тактов. А этого с избытком хватит даже для переброски картинки вместе с атрибутами (в этом случае процедура должна пересылать по очереди 8 линий картинки и атрибуты для этих 8 линий).

Это расчёты для «Пентагона-128». Фирменный Спектрум отличается от него по следующим параметрам: верхняя часть бордюра составляет 64 строки вместо 80, и на экране 312 строк вместо 320. Чтобы процедура переброски работала и на нём, она должна занимать не более (312–81)*224+(64+191)*224=108864 тактов. Но этого всё равно хватает, даже учитывая, что при записи/чтении видеопамяти ULA тормозит процессор. А вот если процессор, наоборот, будет работать быстрее (турбированный Спектрум), процедура переброски может и не дать нужного результата. Чтобы она правильно работала и в этом случае, нужно, чтобы она «укладывалась в прерывание» и завершала свою работу до того, как начнёт прорисовываться нижняя линия малого экрана).

А теперь — две программы, выполняющие одну и ту же задачу: каждые 1/25 секунды они меняют цвет экрана с белого на чёрный и наоборот. Первая программа использует LDIR, а вторая работает по рассмотренному выше алгоритму. Почувствуйте разницу!

Программа 1:

        LD      HL,#8000 ;1-я картинка.
        LD      (HL),0
        LD      DE,#8001
        LD      BC,#17FF
        LDIR

        LD      HL,#9800 ;2-я картинка.
        LD      (HL),#FF
        LD      DE,#9801
        LD      BC,#17FF
        LDIR

L1      HALT
        LD      HL,#8000
        LD      DE,#4000
        LD      BC,#1800
        LDIR
        HALT
        LD      HL,#9800
        LD      DE,#4000
        LD      BC,#1800
        LDIR

        XOR     A
        IN      A,(254)
        CPL
        AND     31
        JR      Z,L1
        RET

Программа 2:

PIC1    EQU     #8000    ;1-я картинка.
PIC2    EQU     #9800    ;2-я картинка.

        LD      HL,PIC1
        LD      (HL),0
        LD      DE,PIC1+1
        LD      BC,#17FF
        LDIR

        LD      HL,PIC2
        LD      (HL),#FF
        LD      DE,PIC2+1
        LD      BC,#17FF
        LDIR

;Строим таблички с адресами переброски:

        LD      BC,PIC1-#4000
        LD      HL,TABL1
        LD      DE,#4000
        CALL    MAKE_T
        LD      BC,PIC2-#4000
        LD      HL,TABL2
        LD      DE,#4000
        CALL    MAKE_T

;Главный цикл программы:

LOOP1   LD      HL,TABL1
        LD      DE,BUFER+100
        LD      BC,192*4
        LDIR
        CALL    MOVER

        LD      HL,TABL2
        LD      DE,BUFER+100
        LD      BC,192*4
        LDIR
        CALL    MOVER

        XOR     A
        IN      A,(254)
        CPL
        AND     31
        JR      Z,LOOP1

;---------------------------------------
;Процедура MOVER непосредственно
;выполняет пересылку:

MOVER   HALT

;Чтобы не было задержек на обработку
;прерывания, можно поставить здесь DI
;(тогда при выходе из этой процедуры
;нужно поставить EI)

        LD      (QUIT+1),SP
        LD      SP,BUFER+100

;Задержка, пока не прорисуется 1-я строка:

        LD      HL,0
        LD      DE,0
        LD      BC,#330
        LDIR

        LD      BC,#1800

;Берём со стека новые значения HL и DE,
;указывающие на следующую строку:

MMMM    POP     DE
        POP     HL

TO_LDI  LDI:LDI:LDI:LDI:LDI:LDI:LDI:LDI
        LDI:LDI:LDI:LDI:LDI:LDI:LDI:LDI
        LDI:LDI:LDI:LDI:LDI:LDI:LDI:LDI
        LDI:LDI:LDI:LDI:LDI:LDI:LDI:LDI

        JP      PE,MMMM ;Продолжаем...

QUIT    LD      SP,0
        RET

;---------------------------------------
;Процедура MAKE_T строит табличку:

MAKE_T  LD      A,D
        CP      #58
        RET     Z
        LD      (HL),E
        INC     HL
        LD      (HL),D
        INC     HL
        EX      DE,HL
        ADD     HL,BC
        EX      DE,HL
        LD      (HL),E
        INC     HL
        LD      (HL),D
        INC     HL
        EX      DE,HL
        AND     A
        SBC     HL,BC
        EX      DE,HL
        INC     D
        LD      A,D
        AND     7
        JR      NZ,MAKE_T
        LD      A,E
        SUB     #E0
        LD      E,A
        JR      NC,MAKE_T
        LD      A,D
        SUB     8
        LD      D,A
        JR      MAKE_T

;---------------------------------------

TABL1   DS      192*4
TABL2   DS      192*4

;Стек для процедуры
;обработки прерываний (если во время
;работы проц. MOVER прерывания
;запрещены, он не нужен):

BUFER   DS      100

;"Одноразовая" табличка адресов строк
;(разрушается процедурой обработки
;прерываний и нуждается в обновлении):

        DS      192*4
Страница Ивана Рощина > Статьи >