сборка 68k - эффективно очистить, начиная с адреса

Это мой фрагмент для очистки данных с адреса SCREEN до 600 байт.

    lea SCREEN,a3
    move.w  #(600/4)-1,d0   ; bytes / 4 bytes (long)
clear_data:
   clr.l    (a3)+
   dbra d0,clear_data

Это работает, однако мне интересно, как добиться того же результата, не зацикливаясь на 600/4 раза. В основном, я думаю, указать прямо на ЭКРАН и сделать что-то вроде

; point PC to SCREEN ?
dcb.b 600,0

Возможно ли?

РЕДАКТИРОВАТЬ ОТВЕТ

Все еще используя программный код, этот цикл примерно в 2 раза быстрее (Курс украден из RamJam):

    lea SCREEN,a3
    move.w  #(600/32)-1,d0   ; bytes / 32 bytes (long*8)
clear_data:
    clr.l    (a3)+
    clr.l    (a3)+
    clr.l    (a3)+
    clr.l    (a3)+
    clr.l    (a3)+
    clr.l    (a3)+
    clr.l    (a3)+
    clr.l    (a3)+
    dbra d0,clear_data

Однако, как упоминает Питер в ответе, использование блиттера (если оно предусмотрено аппаратным обеспечением) может значительно оптимизировать производительность.


person Fabrizio Stellato    schedule 28.06.2018    source источник
comment
Я не очень хорошо знаком с M68K, но я думаю, что вы хотите dbnz для своего цикла (dbra будет бесконечным циклом), и что это более эффективно, чем вы думаете, если вы не используете оригинальный чип 68000 (более поздние модели добавлены особый случай для dbXX с одной инструкцией внутри цикла).   -  person jasonharper    schedule 28.06.2018
comment
DBRA не является бесконечным циклом; он завершается, когда соответствующий регистр достигает -1. DBxx завершается, когда счетчик циклов достигает -1 ИЛИ условие истинно   -  person vogomatix    schedule 06.09.2018


Ответы (3)


Нет, сохранение 4 байтов за раз в цикле, вероятно, настолько хорошо, насколько это возможно. Возможно, немного развернуться, чтобы уменьшить накладные расходы на цикл, если этот жесткий цикл не увеличивает пропускную способность памяти на любом оборудовании m68k, которое вам нужно. А может и нет: @jasonharper комментирует, что более поздние чипы m68k имеют специальную поддержку циклов с двумя инструкциями.


dcb.b 600,0 - это вещь времени сборки, которая собирает байты в ваш выходной файл.

Вы не можете «запустить» его во время выполнения. Помните, что исходный код asm не запускается напрямую; это способ создания двоичных файлов, содержащих машинный код и/или данные m68k.

Вы можете использовать директивы данных, смешанные с инструкциями, для «ручного» кодирования инструкций, указав нужные байты машинного кода, но 600 байтов нулей будут просто декодированы как некоторые инструкции m68k. (Я не проверял, как 00 00 декодирует на m68k.)


Некоторые компьютеры на базе m68k имели аппаратные чипы для работы с большими блоками памяти. Обычно это называлось блиттер-чипом (Википедия). например некоторые настольные компьютеры Atari m68k, такие как Mega STe, имели чип BLiTTER.

Вы можете запустить несколько инструкций на ЦП, чтобы запрограммировать блиттер на очистку или копирование большого блока памяти, в то время как ЦП будет выполнять другие инструкции. По сути, это механизм копирования DMA.

person Peter Cordes    schedule 28.06.2018
comment
Ну, так как я на Amiga, промокашка выглядит хорошо! Но я все еще должен получить на это - person Fabrizio Stellato; 28.06.2018

Используйте MOVEM, чтобы по-настоящему прожечь память настроек!

Я рекомендую вам не использовать CLR.L; если вы посмотрите на тайминги часов, вы обнаружите, что они кажутся довольно неэффективными. Лучше загрузить регистр со значением, которое вы хотите установить в память, а затем MOVE.L ,(A0)+

Однако для максимальной скорости используйте MOVEM.L для установки/очистки больших областей памяти. Это в 2-3 раза быстрее, чем при использовании CLR или стандартного MOVE.L.

Вот пример подпрограммы, которая устанавливает 64-байтовые блоки, а затем устанавливает любые оставшиеся длинные слова, но ее можно настроить.

         ORG     $2000
         MOVE.L  #MEMSTART,A0        ; memory to clear
         MOVE.L  #ZEROS,A1           ; value to set memory to e.g. 0
         MOVE.L  #600,D7             ; number of bytes
         BSR     SETBLOCK
         STOP    #2700

SETBLOCK
         ; MOVEM doesn't support destination = (Ax)+, 
         ; does support destination = -(Ax)
         ADD.L   D7,A0               ; so start at end

         LSR.L   #2,D7               ; divide by 4 for Long words.
         MOVE.L  D7,D6
         LSR.L   #4,D6               ; # of 16 longword blocks 
         BEQ.S   NOBLOCK             ; branch if no none
         SUBQ.L  #1,D6               ; one less so DBRA works
         MOVEM.L (A1),D0-D4/A2-A4    ; 8 registers = 32 bytes 

ZAPBLOCK MOVEM.L D0-D4/A2-A4,-(A0)   ; 8 x 4 = 32 bytes
         MOVEM.L D0-D4/A2-A4,-(A0)   ; 8 x 4 again for 64 bytes
         DBRA    D6,ZAPBLOCK         ; loop ends when D7=-1
NOBLOCK  AND.W   #$0F,D7             ; how many long words left
         BEQ.S   NONE
         ; do any remainder
         SUBQ.W  #1,D7               ; 1 less so DBRA works
         MOVE.L  (A1),D0             ; pattern in D0 if not there b4
ZAP      MOVE.L  D0,-(A0)            ; set memory long word at a time
         DBRA    D7,ZAP
NONE
         RTS

ZEROS    DC.L    0,0,0,0,0,0,0,0      ; 8x4 = 32
         ORG     $2500
MEMSTART DS.B    600

В этом примере используются D0-D4 и A2-A4, чтобы получить 8 регистров для установки 32 байтов за раз, повторяющихся дважды для 64 байтов. Нет причин, по которым вы не можете добавить больше инструкций MOVEM в цикл ZAPBLOCK для записи в 128, 256 или более байтов для каждой итерации цикла, соответственно изменив инструкции LSR/AND.

Обратите внимание, что DBRA работает только со словами, поэтому будет установлено только 65k x размер блока. Это можно исправить, например, используя SUBQ и BGT вместо DBRA.

По какой-то причине я припоминаю, что инструкция CLR выполняла как чтение, так и запись на некоторых 68-килобайтных компьютерах.

Время

Сравнивая 3 варианта, предполагая стандартный 68000 с 16-битной шиной данных...

  1. Использование CLR

    LOOP:  
           CLR (A0)+      12+8
            DBRA D7,LOOP   10/14
    

30 циклов для каждого длинного слова, 20 для каждого длинного слова с несколькими очистками.

  1. Использование MOVE.L

        MOVEQ #0,D0        ; 4
    LOOP:
        MOVE.L D0,(A0)+    ; 12
        DBRA   D7,LOOP     ; 10/14
    

22 цикла на длинное слово, 12 на длинное слово с несколькими операциями MOVE.L.

  1. Использование MOVEM.L

    LOOP:
        MOVEM.L  D0-D4/A2-A4,-(A0)    ;  8+8*8 = 72
        MOVEM.L  D0-D4/A2-A4,-(A0)    ;  8+8*8 = 72
        DBRA     D6,LOOP              ;  10/14
    

154 цикла на итерацию, но всего около 9,5 циклов на длинное слово. Это, вероятно, конкурентоспособно с производительностью аппаратного блиттера.

person vogomatix    schedule 29.08.2018
comment
На hackaday.io/project/6150-beckman-du600-reverse-engineering/log/ есть несколько реальных показателей производительности для использования move-multiple (movem.l). - person Peter Cordes; 29.08.2018
comment
Давным-давно в далекой-далекой галактике я переписал ОС Atari ST, чтобы использовать такие трюки :) - person vogomatix; 29.08.2018

Метод Vogomatix 3 на самом деле быстрый, но не настолько, как заявлено. По какой-то причине он не упомянул в этом примере начальное время настройки загрузки регистра, что весьма важно.

Вы должны добавить 'Moveq # 0, d0-4 (16 циклов), затем 4 адресных регистра: 12 циклов, каждый reg x 4 равен 48, поэтому 64 цикла для настройки.

При 218 циклах/итерации это ~13,6 циклов на длинное слово; не так хорошо, как решение 2.

Самое быстрое, что я нашел, это максимизировать сколько угодно регистров (обычно используется 13), а затем:

movem.l (An),a0-4/d0-7; 13 Longs    12+8n    = 116 cycles
movem.l a0-4/d0-7,(An);              8+8n   = 112 cycles

Вышеупомянутая строка перемещения в память (112 циклов) затем может быть повторена для любого требуемого количества операций записи. Скорость cyc/long не догоняет скорость в предыдущих примерах до тех пор, пока в одном цикле итераций не будет записано по крайней мере 48 или более циклов, и к этому времени мы получим чуть менее 12 cyc/long. Так, например. 128 длинных, мы получаем 1300 циклов или около 10,2 циклов/длинных. Чем больше записей, тем ниже уменьшается скользящее среднее значение установки и выполнения цикла, пока оно постепенно не приблизится к теоретическому значению 8+8n циклов на длинный лимит.

Вы также можете еще больше повысить эффективность итераций, используя все регистры (16), но тогда у вас возникнет сложность в виде более жесткого управления потоком данных из-за наличия 15 регистров и хитрых обходных путей для регистра A7, который используется для SP, если используются все 16.

person mrbombermillzy    schedule 21.06.2020
comment
218 циклов/итерация — не лучший способ указать накладные расходы; это применимо только в том случае, если вы повторяете настройку внутри цикла на каждой итерации. Или, если вы зафиксируете количество итераций равным 1, в этом случае просто скажите это вместо того, чтобы вызывать его для каждой итерации. Как вы обсудите позже, полезной вещью являются амортизированные накладные расходы и точка безубыточности по сравнению с более простым циклом с использованием меньшего количества регистров. - person Peter Cordes; 21.06.2020