1

这是我将数据从 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 次的情况下达到相同的结果。基本上我想直接指向 SCREEN 并做类似的事情

; 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

但是,正如 Peter 在回答中提到的那样,使用 blitter(如果由硬件提供)可以极大地优化性能。

4

3 回答 3

4

使用MOVEM真正烧穿设置内存!

我建议你不要使用 CLR.L;如果您查看时钟计时,您会发现它似乎效率很低。最好使用您要设置内存的值加载一个寄存器,然后 MOVE.L ,(A0)+

但是,为了获得极快的速度,请使用MOVEM.L设置/清除大面积的内存。它比使用 CLR 或标准 M​​OVE.L 快 2 到 3 倍

这是一个设置 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 个字节。没有理由不能向 ZAPBLOCK 循环添加更多 MOVEM 指令,以便为每次循环迭代写入 128、256 或更多字节,从而相应地更改 LSR/AND 指令。

请注意,DBRA 仅对字进行操作,因此这只会设置 65k x 块大小。这可以修复,例如使用 SUBQ 和 BGT,而不是 DBRA。

出于某种原因,我记得 CLR 指令在一些 68k 上进行了读取和写入

定时

比较 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 个周期。这可能与硬件 blitter 的性能相媲美。

于 2018-08-29T16:09:34.193 回答
2

不,在循环中一次存储 4 个字节可能与您所能获得的一样好。也许展开一点以减少循环开销,如果那个紧密的循环没有在你关心的任何 m68k 硬件上最大化内存带宽。或者可能不是:@jasonharper 评论说后来的 m68k 芯片特别支持 2 指令循环。


dcb.b 600,0是一个组装时的东西,它将字节组装到你的输出文件中。

您不能在运行时“运行”它。请记住,asm 源不直接运行;这是一种创建包含 m68k 机器代码和/或数据的二进制文件的方法。

您可以使用与指令混合的数据指令通过指定所需的机器代码字节来“手动”编码指令,但 600 字节的零只会解码为一些 m68k 指令。(我没有检查00 00m68k 上的解码方式。)


一些基于 m68k 的计算机具有用于处理大块内存的硬件芯片。这通常被称为blitter chip (Wikipedia)。例如,一些 Atari m68k 台式机,如 Mega STe,具有 BLiTTER 芯片。

您可以在 CPU 上运行一些指令来对 blitter 进行编程以清除或复制一大块内存,同时 CPU 继续运行其他指令。这基本上是一个 DMA 复制引擎。

于 2018-06-28T18:40:14.933 回答
1

Vogomatix 方法 3 实际上很快,但没有声称的那么快。出于某种原因,他在此示例中省略了非常重要的初始寄存器加载设置时间。

您必须添加 'Moveq #0,d0-4(16 个周期),然后是 4 个地址寄存器:每个 reg x 4 的 12 个周期为 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 个周期)行,但需要多次写入。直到在一个迭代循环中写入至少 48 个或更多时,cyc/long 速度才赶上前面的示例速度,此时我们的 cyc/long 不到 12 个。因此,例如 128 个长周期,我们得到 1300 个周期或大约 10.2 个周期/长周期。写入次数越多,循环设置+执行滚动平均值越低,直到它慢慢接近理论上的每长限制 8+8n 循环。

您还可以通过使用所有寄存器 (16) 进一步最大限度地提高迭代效率,但是如果使用所有 16 个寄存器,则通过使用 15 个寄存器和用于 SP 的寄存器 A7 的棘手变通方法,您会遇到更难的数据流控制的复杂性。

于 2020-06-21T20:14:28.357 回答