User Tag List

Показано с 1 по 10 из 87

Тема: Edge Grinder для ZS GMX

Древовидный режим

Предыдущее сообщение Предыдущее сообщение   Следующее сообщение Следующее сообщение
  1. #11

    Регистрация
    03.07.2021
    Адрес
    г. Кировск
    Сообщений
    922
    Спасибо Благодарностей отдано 
    87
    Спасибо Благодарностей получено 
    211
    Поблагодарили
    156 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Насколько понял, восстановление фона под спрайтами не производится, вместо этого перерисовывается весь экран (фон) целиком.
    Зато не понял, почему при ширине экрана 80 байт пересылаются только 78. Или так и задумано?
    Предположил, что крайний ряд является буфером скроллера, но идет же просто пересылка без сдвигов. Непонятно.
    Указано, что карта лежит рядами по 78 байт. А почему так? Она еще и вверх-вниз может скроллиться в игре?
    Или откуда эта цифра в 78 байт? Поподробнее о формате хранения куска карты в странице, если можно.

    Начнем оптимизировать)) Первое, что сразу бросается в глаза: очень много лишних действий внутри циклов вывода строк.
    Скажем, каждый раз вычисляется один и тот же адрес для IX, хотя задавать его нужно всего один раз _перед_ циклом.
    Для пар IX/IY обмен с памятью жрет много + тут в цикле берем адрес из таблицы, - огромные потери, около 100 тактов на линию.
    Перебрасываем 160 линий, 160х100=16000, если кусками лево-право (работают оба цикла) - уже 32000, это только приблизительно.
    Убрав одно лишь задание IX внутри каждого цикла, можно выкинуть кусок кода в красной скобке. Стрелки - команды для оптимизации.



    Второе: внутри каждого цикла по две команды LD BC,(nn) - очень расточительно в плане затрат времени. Выделено стрелками.
    Команды LD BC/DE,(nn) и обратные - LD (nn),BC/DE - жрут на 4 такта и на байт больше памяти, чем такие же с HL,
    поэтому везде, где можно, желательно для обмена с памятью использовать пару HL. Это общая рекомендация для любого кода.
    Конкретно в этом примере чтение BC еще и вставлено в цикл, причем циклов два (левый и правый столбец) - теряем много тактов.
    Напрашивается прямая загрузка в регистры вместо косвенной (из памяти), размещая переменные сразу в коде циклов.

    Теперь посмотрим, как избавиться от таблицы переходов по цепочкам LDI, да и от шести килобайт с этими цепочками заодно.
    Целых 6 кило места, которого и так вечно не хватает - слишком жирно. Есть способ скользить по коду намного проще.
    Размещаем цепочки LDI с максимальной длиной строки (78) прямо в циклах, заодно убрав схему возврата (LD BC,nn:PUSH BC:RET)
    и повторную загрузку после них BC из PrintMapCol, которая станет не нужна, т.к. IX будем задавать перед циклом:

    Код:
            dup     78
            ldi
            edup
    dup и edup с числом - директивы для повтора строк кода между ними, могут зависеть от конкретного ассемблера.
    Процедур две (для левой и правой части), поэтому цепочек с LDI тоже будет две. 2 по 160 байт всяко лучше, чем 6 кило.
    Осталось переделать обе процедуры "прыжка" в нужное нам место, и возврат по RET отпадает за ненадобностью.
    Ниже новый листинг. Все исходные переменные в шапке оставил, но MapLeftPart, MapRightPart и PrintMapCol2 не используются.
    Можно еще поиграть с размещением переменных из шапки в коде, но они будут вне циклов - на скорости уже не скажется.

    Скрытый текст

    Код:
    BaseScrAddr     equ     #c000   ;адрес экрана
    RightCol        equ     #4d     ;последний столбик справа (#4d=77)
    MapLeftPart     dw      0       ;число столбцов в левой части экрана для карты  - не нужна, переделана в skip_L
    MapRightPart    dw      0       ;число столбцов в правой части экрана для карты - не нужна, переделана в skip_R
    PrintMapPag     db      0       ;страница памяти с которой начинается карта
    PrintMapCol     dw      0       ;номер текущего столбика для печати
    PrintMapCol2    dw      0       ;количество столбцов для переноса справа - не нужна, вычисляем IX до цикла
    PrintMapAddr    dw      0       ;текущий адрес карты
    
    MapPrintTable   ;эти две переменные больше не нужны
    MapPrintCode    ;т.к. убираем таблицу адресов и цепочки LDI
    
    ;печать готовой карты из памяти
    MapPrint 
    
            ld      a,(PrintMapPag) ;включаем нужную страницу
            call    PageSlot2G
            ld hl,  (PrintMapAddr)
            ld de,  BaseScrAddr
            ld bc,  (PrintMapCol)   ;ширина левой части
            inc     c
            dec     c
            jp      z,MapPrint3     ;если C=0, левую часть не рисуем. !JP вместо JR
            ld      a,80
            sub     c
            ld      (skip_R+1),a    ;ширина пропуска правой части
            rlc     c               ;умножаем на 2 (LDI - 2 байта)
            ld      ix,MapPr_L+2    ;адрес начала строки LDI'шек
            add     ix,bc           ;получаем в IX адрес прыжка
            ld      a,160           ;кол-во строк
    
    MapPr_L jp      (ix)            ;начало цикла левой части
    
            dup     78
            ldi                     ;перенос
            edup
    
    skip_R  ld      bc,0            ;в C загружена ширина пропуска, B=0
            ex      de,hl
            add     hl,bc
            ex      de,hl
            add     hl,bc
            dec     a
            jp      nz,MapPr_L      ;JP вместо JR, т.к. команды LDI развернуты в цикле - у JR не хватит смещения
        
    
    MapPrint3                       ;печать (или не печать) правой части из след. страницы
    
            ld      a,(PrintMapCol)
            cp      RightCol+1
            jp      z,MapPrintE     ;!JP вместо JR. А по уму достаточно команды RET Z
    
            ld      a,(PrintMapPag) ;включаем нужную страницу
            inc     a
            call    PageSlot2G
            ld      hl,(PrintMapAddr)
            ld      de,BaseScrAddr  ;или ld d,BaseScrAddr/256 (нам нужен только старший байт)
            ld      bc,(PrintMapCol)
            ld      e,c
            ld      b,0
            ld      a,78            ;сразу отнимаем 2, зачем лишняя команда (sub 2)
            sub     c
            rlca                    ;умножаем на 2
            ld      c,a             ;смещение для jp (ix)
            ld      ix,MapPr_R+2
            add     ix,bc
            ld      a,80
            sub     l
            ld      (skip_L+1),a    ;пропуск левой части
            ld      l,b             ;b=0
            ld a,   160
    
    MapPr_R jp      (ix)            ;начало цикла правой части
    
            dup     78
            ldi
            edup
    
    skip_L  ld      bc,0
            ex      de,hl
            add     hl,bc
            ex      de,hl
            add     hl,bc
            dec     a
            jp      nz,MapPr_R      ;JP вместо JR
        
    
    MapPrintE       ; можно удалить метку и RET, если ниже MapPrint3 поставить RET Z вместо JP Z
            ret
    [свернуть]


    Процедура обсчета следующей строки (do_scroll_new) остается без изменений.
    Что еще добавить... код не проверялся (набивался в блокноте), возможны глюки =)) Если возникнут вопросы - задавай.
    И все равно непонятна фишка с числом 78. Не запуская код и не имея представления о схеме карты. Прошу разъяснить.
    Последний раз редактировалось reddie; 17.07.2021 в 22:33.

    Эти 2 пользователя(ей) поблагодарили reddie за это полезное сообщение:

    Evgeny Muchkin(18.07.2021), izzx(17.07.2021)

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. EYEACHE2 и Across The Edge на GMX
    от Evgeny Muchkin в разделе Демо
    Ответов: 1
    Последнее: 12.08.2019, 21:23
  2. Ответов: 0
    Последнее: 24.11.2017, 03:24
  3. ZX BUS EDGE!
    от ZXFanat в разделе Устройства ввода
    Ответов: 10
    Последнее: 15.07.2013, 19:16

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •