您尚未登录。

楼主 # 2021-10-22 16:44:37

echo
会员
注册时间: 2020-04-16
已发帖子: 358
积分: 363.5

8051的双DPTR指针快速复制测试

众所周知,标准8051只有一个DPTR指针,通过DPTR访问XRAM速度是比较慢的,尤其是从XRAM的一个缓冲区搬数据到另外一个缓冲区,更是雪上加霜。

看到CH55x的头文件了提到了新增的A5指令,配合双DPTR指针,可以快速在XRAM中搬数据,写了段代码测试了下,从XRAM的的一个缓冲区搬255字节到另外一个缓冲区,对比对象是C标准库中的memcpy函数。同时由于CH55x的DPTR支持自增操作,把DPTR自增也作为一个变量一起测试一下。

结论如图:
TestDualDPTR.jpg

  • mempcy函数:420us

  • A5指令不开自增:128us

  • A5指令开自增:128us

从测试结果来看,A5指令配合双DPTR速度提高了大约3.3倍,节省的时间还是相当可观的。DPTR自增对运行时间几乎无影响,按说循环中节省了一条INC指令,应该能提高一点速度呀,奇怪。

完整代码如下:

/*
New Instruction:   MOVX @DPTR1,A
Instruction Code:  0xA5
Instruction Cycle: 1
Instruction Operation:
   step-1. write ACC @DPTR1 into xdata SRAM embedded chip
   step-2. increase DPTR1
ASM example:
       INC  XBUS_AUX
       MOV  DPTR,#TARGET_ADDR ;DPTR1
       DEC  XBUS_AUX
       MOV  DPTR,#SOURCE_ADDR ;DPTR0
       MOV  R7,#xxH
 LOOP: MOVX A,@DPTR ;DPTR0
       INC  DPTR    ;DPTR0, if need
       DB   0A5H    ;MOVX @DPTR1,A & INC DPTR1
       DJNZ R7,LOOP
*/

extern UINT8X Ep1Buffer[];
extern UINT8X syscall_buf[];

BOOL VerifyMemory(void)
{
	uint8_t i = 0;

	for(i=0; i<0xFF; i++)
	{
		if(Ep1Buffer[i] != syscall_buf[i])
		{
			return FALSE;
		}
	}

	return TRUE;
}

void testDualDPTR(void)
{
	// memcpy
	memset(syscall_buf, 0, 0xFF);
	P33 = 1;
	memcpy(syscall_buf, Ep1Buffer, 0xFF);
	P33 = 0;
	if(VerifyMemory())
	{
	#pragma ASM
		SETB P33
		NOP
		CLR P33
	#pragma ENDASM
	}

	// Dual DPTR without AUTO_INC
	memset(syscall_buf, 0, 0xFF);
#pragma ASM
	SETB P33
	ORL  XBUS_AUX, #01H     ;DPS=1
	MOV  DPTR, #syscall_buf ;DPTR1
	ANL  XBUS_AUX, #0FEH    ;DPS=0
	MOV  DPTR, #Ep1Buffer   ;DPTR0
	MOV  R7,#0FFH
L0: MOVX A, @DPTR           ;DPTR0
	INC  DPTR               ;DPTR0++
	DB   0A5H               ;MOVX @DPTR1,A & INC DPTR1
	DJNZ R7, L0
	CLR P33
#pragma ENDASM
	if(VerifyMemory())
	{
	#pragma ASM
		SETB P33
		NOP
		CLR P33
	#pragma ENDASM
	}

	// Dual DPTR with AUTO_INC
	memset(syscall_buf, 0, 0xFF);
#pragma ASM
	SETB P33
	ORL  XBUS_AUX, #05H     ;bDPTR_AUTO_INC=1 DPS=1
	MOV  DPTR, #syscall_buf ;DPTR1
	ANL  XBUS_AUX, #0FEH    ;DPS=0
	MOV  DPTR, #Ep1Buffer   ;DPTR0
	MOV  R7,#0FFH
L1: MOVX A, @DPTR           ;DPTR0
	DB   0A5H               ;MOVX @DPTR1,A & INC DPTR1
	DJNZ R7, L1
	ANL  XBUS_AUX, #0FBH    ;bDPTR_AUTO_INC=0
	CLR P33
#pragma ENDASM
	if(VerifyMemory())
	{
	#pragma ASM
		SETB P33
		NOP
		CLR P33
	#pragma ENDASM
	}
}

离线

#1 2021-10-22 17:03:36

Blueskull
会员
注册时间: 2020-02-20
已发帖子: 458
积分: 444.5

Re: 8051的双DPTR指针快速复制测试

CH552的DPTR自增有坑,在USB传输时,USB的DMA可能修改DPTR用的bank,同时用户代码使用DPTR自增可能导致数据混乱。几个字节几十个字节测不出来,有时候几十KB都测不出来,但是有极其小的概率,大概几百KB一次的概率会触发。

离线

楼主 #2 2021-10-22 18:12:51

echo
会员
注册时间: 2020-04-16
已发帖子: 358
积分: 363.5

Re: 8051的双DPTR指针快速复制测试

Blueskull 说:

CH552的DPTR自增有坑,在USB传输时,USB的DMA可能修改DPTR用的bank,同时用户代码使用DPTR自增可能导致数据混乱。几个字节几十个字节测不出来,有时候几十KB都测不出来,但是有极其小的概率,大概几百KB一次的概率会触发。

那就不用它了,保持bDPTR_AUTO_INC一直为0,从测试结果来看,打开DPTR自增对加快复制速度也没有什么作用。

离线

#3 2021-10-22 22:50:19

Blueskull
会员
注册时间: 2020-02-20
已发帖子: 458
积分: 444.5

Re: 8051的双DPTR指针快速复制测试

@echo

对复制到非DPTR,比如外设,有用啊。

比如考虑如下场景:

__xdata uint8_t *buf;
int len;

while(len--)
{
    SPI0_DATA=*buf++;
    while(!S0_FREE);
}

这个代码可以优化成:

XBUS_AUX=0x00; // Select DPTR0
SAFE_MOD=*buf; // Load DPTR addresses from xdata pointer
SAFE_MOD=0x00; // Prevent 0x55, 0xaa patterns
XBUS_AUX=0x04; // Select DPTR0 and enable auto increment

while(len--)
{
    __asm("movx @a, DPTR");
    __asm("mov SPI0_DATA, @a");
    while(!S0_FREE);
}

XBUS_AUX=0x00; // Disable DPTR auto increment

速度确实会快很多(SDCC操作DPTR默认每次都加载DPTR寄存器,非常保守,但是非常低效),但是每隔几百KB就会错乱一次,SPI收到的数据和USB发过来的对不上。

最近编辑记录 Blueskull (2021-10-22 22:50:28)

离线

楼主 #4 2021-10-23 09:04:42

echo
会员
注册时间: 2020-04-16
已发帖子: 358
积分: 363.5

Re: 8051的双DPTR指针快速复制测试

@Blueskull
理论上会减少一条INC DPTR指令,时间应该能少一个周期,不过我原文实测的结果是没有差别。

离线

#5 2021-10-23 12:29:54

Blueskull
会员
注册时间: 2020-02-20
已发帖子: 458
积分: 444.5

Re: 8051的双DPTR指针快速复制测试

echo 说:

@Blueskull
理论上会减少一条INC DPTR指令,时间应该能少一个周期,不过我原文实测的结果是没有差别。


SDCC假设中断程序可能随时操作DPTR,因此生成的代码会每一次都重新加载DPTR寄存器。


// r6 is DPH, r7 is DPL
mov r5, r7
mov r4, r6
inc r5

// if(r5==0x00) r4++;

mov DPH, r4
mov DPL, r5
movx @a, DPTR
...

不知道为什么SDCC的xdata操作这么保守,但是确实可靠,就是慢。

离线

楼主 #6 2021-10-25 10:43:19

echo
会员
注册时间: 2020-04-16
已发帖子: 358
积分: 363.5

Re: 8051的双DPTR指针快速复制测试

经过 @Alexi2008 大佬指点,找到了开不开地址自增运行时间一样都是128us的原因。
DJNZ指令如果位于奇地址,会增加一个周期,刚好吃掉INC DPTR指令省下来的那个周期。看了下汇编代码,确实开地址自增以后的DJNZ指令在奇地址。
改一下代码,让两条DJNZ指令都位于偶地址,再次测试,结果如下:
TestDualDPTR_DJNZ_EVEN.jpg

  • mempcy函数:420us

  • A5指令不开自增:128us

  • A5指令开自增:97us

可以看到,打开地址自增以后,运行时间从128us降低到了97us,提升也不少。极限情况下,A5指令可以比memcpy函数快4.33倍。

离线

#7 2021-10-27 21:37:51

Blueskull
会员
注册时间: 2020-02-20
已发帖子: 458
积分: 444.5

Re: 8051的双DPTR指针快速复制测试

给CH552洗白一下,CH552的DPTR自增没问题,我的代码有问题。今天把之前的codebase重构了一下,现在USB双缓冲+DPTR自增SPI回环+USB回环测试稳如老狗。

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn