这是我的摘录,用于清除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提到的那样,使用阻击器(如果由硬件提供)可以极大地优化性能。
答案 0 :(得分:2)
否,一次循环存储4个字节可能就和您获得的一样好。如果紧密的循环无法最大化您所关心的任何m68k硬件上的内存带宽,也许可以降低循环开销。也许不是:@jasonharper评论说,后来的m68k芯片特别支持2条指令循环。
dcb.b 600,0
是一个汇编时事物,它将字节组合到您的输出文件中。
您不能在运行时“运行”它。请记住,asm源代码不会直接运行;这是一种创建包含m68k机器代码和/或数据的二进制文件的方法。
您可以将数据指令与指令混合使用,通过指定所需的机器代码字节来“手动”编码指令,但是600字节的零将仅作为某些m68k指令进行解码。 (我没有检查00 00
在m68k上如何解码。)
某些基于m68k的计算机具有用于处理大块内存的硬件芯片。通常将其称为blitter chip (Wikipedia)。例如一些Atari m68k台式机(例如Mega STe)配备了BLiTTER芯片。
您可以在CPU上运行一些指令,以便在CPU继续运行其他指令时,对清除器进行编程以清除或复制大块内存。这基本上是DMA复制引擎。
答案 1 :(得分:2)
使用MOVEM真正烧完设置内存!
我建议您不要使用CLR.L;如果您查看时钟时序,您会发现它似乎效率很低。最好先将要设置内存的值加载到寄存器中,然后再加载MOVE.L,(A0)+
但是,要获得极快的速度,请使用 MOVEM.L 设置/清除大面积的内存。它比使用CLR或标准MOVE.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位数据总线...
使用CLR
LOOP:
CLR (A0)+ 12+8
DBRA D7,LOOP 10/14
每个长字30个循环,每个长字20个,具有多次清除。
使用MOVE.L
MOVEQ #0,D0 ; 4
LOOP:
MOVE.L D0,(A0)+ ; 12
DBRA D7,LOOP ; 10/14
每个长字22个周期,每个长字12个周期,并具有多个MOVE.L操作。
使用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个循环。这可能与硬件缓冲器的性能竞争。
答案 2 :(得分:1)
Vogomatix方法3实际上是快速的,但还没有达到要求的范围。由于某些原因,他在此示例中省略了初始寄存器加载建立时间,这非常重要。
您必须添加'Moveq#0,d0-4(16个周期),然后添加4个地址寄存器:每个reg 12个周期x 4为48,因此设置需要64个周期。
在218 cyc /迭代时,每个长字的〜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 cyc /长。 写的次数越多,周期设置+执行滚动平均值就降低得越低,直到它逐渐接近理论上每个长极限的8 + 8n周期为止。
您还可以通过使用所有寄存器(16)进一步最大化迭代效率,但是如果使用15个寄存器和用于SP的寄存器A7(如果使用全部16个寄存器)的棘手变通方法,则将使硬数据流控制更加复杂