当前位置:  开发笔记 > 编程语言 > 正文

为什么在C/C++/rtl中没有类似LDIR功能的Z80?

如何解决《为什么在C/C++/rtl中没有类似LDIR功能的Z80?》经验,为你挑选了5个好方法。

在Z80机器代码中,一种将缓冲区初始化为固定值的廉价技术,比如所有空白.所以一大堆代码可能看起来像这样.

LD HL, DESTINATION             ; point to the source
LD DE, DESTINATION + 1         ; point to the destination
LD BC, DESTINATION_SIZE - 1    ; copying this many bytes
LD (HL), 0X20                  ; put a seed space in the first position
LDIR                           ; move 1 to 2, 2 to 3...

结果是DESTINATION的内存块完全填满了空白.我已经尝试了memmove和memcpy,并且无法复制这种行为.我希望memmove能够正确地完成它.

memmove和memcpy为什么会这样?

有没有合理的方法来进行这种数组初始化?

我已经知道char array [size] = {0}用于数组初始化

我已经知道memset将为单个字符完成工作.

还有什么其他方法可以解决这个问题?



1> Ned Batcheld..:

memmove并且memcpy不要那样工作,因为它不是用于移动或复制内存的有用语义.在Z80中能够填充内存很方便,但为什么你会期望一个名为"memmove"的函数用单个字节填充内存?这是为了移动内存块.无论块如何重叠,它都是为了得到正确的答案(源字节移动到目的地)而实现的.它有助于为移动内存块获得正确的答案.

如果你想填充内存,请使用memset,它可以满足您的需求.



2> devstopfix..:

使用堆栈可以更快地消隐内存区域.尽管LDI和LDIR的使用非常普遍,但David Webb(以各种方式推动ZX Spectrum,如包括边界在内的全屏幕倒计时)提出了这种技术,速度提高了4倍:

保存堆栈指针,然后将其移动到屏幕的末尾.

将HL寄存器对加载为零,

进入一个巨大的循环推动HL进入堆栈.

堆栈向上移动屏幕并向下移动通过内存,在此过程中,清除屏幕.

上面的解释取自David Webbs游戏Starion的评论.

Z80例程可能看起来像这样:

  DI              ; disable interrupts which would write to the stack.
  LD HL, 0
  ADD HL, SP      ; save stack pointer
  EX DE, HL       ; in DE register
  LD HL, 0
  LD C, 0x18      ; Screen size in pages
  LD SP, 0x4000   ; End of screen
PAGE_LOOP:
  LD B, 128       ; inner loop iterates 128 times
LOOP:
  PUSH HL         ; effectively *--SP = 0; *--SP = 0;
  DJNZ LOOP       ; loop for 256 bytes
  DEC C
  JP NZ,PAGE_LOOP
  EX DE, HL
  LD SP, HL       ; restore stack pointer
  EI              ; re-enable interrupts

但是,这个例程的速度要快两倍.LDIR每21个周期复制一个字节.内循环每24个循环复制两个字节 - 11个循环PUSH HL,13 个循环DJNZ LOOP.要获得近4倍的速度,只需展开内循环:

LOOP:
   PUSH HL
   PUSH HL
   ...
   PUSH HL         ; repeat 128 times
   DEC C
   JP NZ,LOOP

这是每两个字节非常接近11个周期,比每个LDIR字节的21个周期快约3.8倍.

毫无疑问,这项技术已被多次重新发明.例如,它出现在1980年的子逻辑的飞行模拟器1中,用于TRS-80.


16位DEC不设置任何标志,但8位DEC确实如此.将循环重写为C上的内循环和B上的外循环将解决该问题,因为使用比II B更快的IIRC的DJNZ; JNZ LOOP分开.当然,这需要内环超过B ......
我使用的更快的方法是在循环中放入几个"PUSH HL"指令.因此,如果您正在清除2K内存,则可以使用16"PUSH HL"并且仅循环2K/16(256)次.

3> Onorio Caten..:

我相信这符合C和C++的设计理念.正如Bjarne的Stroustrup的一次说的C++设计的主要指导原则之一就是"你不要用什么,你不支付".而丹尼斯里奇可能没有用完全相同的词语说出来,我相信这也是一个指导原则,告知他的C设计(以及后来人的C设计).现在您可能会认为如果您分配内存,它应该自动初始化为NULL,我倾向于同意您的看法.但这需要机器周期,如果你在每个周期都很关键的情况下进行编码,这可能不是一个可接受的权衡.基本上C和C++试图避开你的方式 - 因此如果你想要初始化的东西,你必须自己做.



4> Konrad Rudol..:

memmove和memcpy为什么会这样?

可能是因为没有针对Z80硬件的特定的现代C++编译器?写一个.;-)

这些语言没有指定给定硬件如何实现任何东西.这完全取决于编译器和库的程序员.当然,为每个可以想象的硬件配置编写一个自己的,高度指定的版本是很多工作.那就是原因.

有没有合理的方法来进行这种数组初始化?有没有合理的方法来进行这种数组初始化?

好吧,如果一切都失败了,你总是可以使用内联汇编.除此之外,我期望std::fill在良好的STL实施中表现最佳.是的,我完全清楚我的期望太高,而且std::memset在实践中往往表现更好.



5> Mark Ransom..:

您展示的Z80序列是最快的方式 - 1978年.那是30年前.从那时起,处理器已经取得了很大进展,而今天这是最慢的方式.

Memmove设计为在源和目标范围重叠时工作,因此您可以将一块内存向上移动一个字节.这是C和C++标准指定行为的一部分.Memcpy未指定; 它可能与memmove完全相同,或者可能有所不同,具体取决于编译器决定如何实现它.编译器可以自由选择比memmove更有效的方法.

推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有