打印

STR9指令速度

[复制链接]
5187|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zljun|  楼主 | 2007-3-30 12:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
"Sequential burst operation up to 96M"

经测试,顺序执行时确实能达到96M的速度。
但是跳转指令的执行速度很慢。一个跳转指令大约需要5个指令周期。

谁有办法让跳转指令的执行效率更高点呀?
沙发
shiqiang| | 2007-3-30 14:49 | 只看该作者

关注中

关注中,支持一下。

使用特权

评论回复
板凳
telnet| | 2007-3-30 16:58 | 只看该作者

加 branch queue 的选项,否则改改程序吧

arm 9 的跳转成功一定要有至少3个延迟,跳转不成功到时没有延迟,所以你只有修改程序将if语句的内容 变为主程序的一部分。

使用特权

评论回复
地板
zljun|  楼主 | 2007-3-30 18:05 | 只看该作者

指令速度

我的测试程序如下:
u16 * addr1=(u16 *)(0x2C000000),* addr2=(u16 *)(0x2C000000)+ 0xFFFF;
u16 data1=0x0,data2=0xFFFF;
while(1)
{
    *addr1 = data1;   //往EMI总线上写0 
    *addr2 = data2;   //往EMI总线上写1    
}

它们的汇编代码:

0X0025CC  STRH R9 [R7, #0]
0X0025D0  STRH R9 [R8, #0]
0X0025D4  B 0X0025CC

结果发现高电平比低电平多出50ns(96M时钟),也就是说指令"B 0X0025CC"用了5个指令周期。

不知道你说的 branch queue 选项是什么意思,是在哪加呢?

使用特权

评论回复
5
telnet| | 2007-3-31 17:23 | 只看该作者

branch queue

首先说说 arm的特性,您只有到exe阶段之后才能的到目的地址(但是这也是个了不起的方法),同时由于要重新刷新pipe line 然后去取目的地址,以及flash的滞后性,所以会造成较大延迟。
为了平衡这个弱项,cpu 会在取跳转指令的时候会同时检查branch queue, 如果这个地址存在,那么对应的项中就包含着跳转的目的地址,cpu 在下一次就会去取目的地址而不是 brach 后面的指令。到底跳转成功与否要到id 之后才可以知道。这样如果成功几乎没有延迟。对于上面代码的结果,我想你应该没有打开这个选项。

我确信st 的arm 9有这个功能因为我曾经问过浪淘沙,是要设置一个寄存器具体哪一个我忘记了。
你找找你的datasheet吧。
祝你顺利。

使用特权

评论回复
6
香水城| | 2007-4-1 11:40 | 只看该作者

Branch Queue是STR9在ARM核心之外的一个非常重要的扩充

5楼说的是对的。

明天我们会有人回答如何使用Branch Queue的问题。谢谢!

使用特权

评论回复
7
zljun|  楼主 | 2007-4-2 09:54 | 只看该作者

branch queue

我想你指的branch queue就是Pre-Fetch Queue and branch cache.
我在程序中已经将它打开了,要不然顺序执行的指令速度都达不到96M.
我用的打开Pre-Fetch Queue and branch cache的代码如下:
SCU_PFQBCCmd(ENABLE);

使用特权

评论回复
8
telnet| | 2007-4-2 12:19 | 只看该作者

目前没有板子,只有猜测

1)确定程序是在内部flash(它是哈佛结构).
2)如果1成立验证如下前3句代码中的高低之差


0X0025CC  STRH R9 [R7, #0]
0X0025D0  STRH R9 [R8, #0]
0X0025C4  STRH R9 [R7, #0]
0X0025D8  STRH R9 [R8, #0]

0X0025DC  B 0X0025CC
3)如果2的结果是高低相等,而且也确定打开了branch queue,如果是我就只有怀疑st了 :-)。 

使用特权

评论回复
9
zljun|  楼主 | 2007-4-2 15:16 | 只看该作者

RE telnet

我原本的程序就是:
while(1)
{
    *addr1 = data1;   //往EMI总线上写0 
    *addr2 = data2;   //往EMI总线上写1   
    *addr1 = data1;   //往EMI总线上写0 
    *addr2 = data2;   //往EMI总线上写1
    *addr1 = data1;   //往EMI总线上写0 
    *addr2 = data2;   //往EMI总线上写1 
}
和你现在的一样。


使用特权

评论回复
10
telnet| | 2007-4-2 15:54 | 只看该作者

有一个问题!

我的疏忽,回头看到你往奇地址写双字节(*addr2 = data2;   //往EMI总线上写1 )难道不会产生异常么?!,换成偶地址去测上面的代码。

使用特权

评论回复
11
zljun|  楼主 | 2007-4-2 17:51 | 只看该作者

RE telnet

addr2=(u16 *)(0x2C000000)+ 0xFFFF;
addr2就是一个偶地址,因为以上语句相当于:
addr2=(u16 *)(0x2C000000+ 2*0xFFFF);

使用特权

评论回复
12
浪淘沙| | 2007-4-2 18:54 | 只看该作者

关于“STR9指令速度”的问题:请楼主把所有代码发上来

包括你的初始化部分,我们帮你看看。

另你这样测试指令速度不一定合适,等我们看了你的代码再来讨论。

使用特权

评论回复
13
xwj| | 2007-4-2 19:12 | 只看该作者

流水线被打断会增加额外的时间,但预测准确的话可以不增

LZ还是先检查下自己的设置和程序写法吧

真要这么计较速度的话就该考虑用DSP了,都能0耗时循环


而且速度的测试也不是这样测的,很多IC的内部时钟和外部总线速度相差极大,IO速度更慢,怎么测的对?

使用特权

评论回复
14
zljun|  楼主 | 2007-4-3 13:18 | 只看该作者

代码

#define DELAY5 asm("nop");asm("nop");asm("nop");asm("nop");asm("nop") 
#define DELAY10 DELAY5;DELAY5

void SCU_Configuration(void); 
void GPIO_Configuration(void);
void EMI_Configuration(void);
int main()
{
  
  #ifdef DEBUG
    debug();
  #endif
   
  /* Configure the system clocks */
  SCU_Configuration();

  /* Configure the GPIO ports */
  GPIO_Configuration();
    
  EMI_Configuration();    
  
  u16 * addr1=(u16 *)0x2C000000,* addr2=(u16 *)0x2C000000+ 0xFFFF;
  u16 data1=0x0,data2=0xFFFF;
  while(data1<data2)
  {
    *addr1 = data1;   //往EMI总线上写0 
    *addr2 = data2;   //往EMI总线上写1    
    *addr1 = data1;   //往EMI总线上写0 
    *addr2 = data2;   //往EMI总线上写1
    *addr1 = data1;   //往EMI总线上写0 
    *addr2 = data2;   //往EMI总线上写1
  }      
}
void SCU_Configuration(void)
{  
  SCU_PFQBCCmd(ENABLE);
  FMI_Config(FMI_READ_WAIT_STATE_2, FMI_WRITE_WAIT_STATE_1, FMI_PWD_ENABLE,
                FMI_LVD_ENABLE, FMI_FREQ_HIGH);
  
  SCU_MCLKSourceConfig(SCU_MCLK_OSC);
  DELAY10;DELAY10;DELAY10;DELAY10;DELAY10;DELAY10;
  SCU_PLLCmd(DISABLE);
  SCU_RCLKDivisorConfig(SCU_RCLK_Div1);
  SCU_PCLKDivisorConfig(SCU_PCLK_Div2);
  SCU_HCLKDivisorConfig(SCU_HCLK_Div1);
  SCU_FMICLKDivisorConfig(SCU_FMICLK_Div1);
  SCU_EMIBCLKDivisorConfig(SCU_EMIBCLK_Div1);  
  SCU_PLLFactorsConfig(125, 12, 2);//96M 
  SCU_PLLCmd(ENABLE);
  SCU_MCLKSourceConfig(SCU_MCLK_PLL);    
  
  
  SCU->SCR0 |=0x10;//96K SRAM
  SCU->SCR0 &=0xF7;         

  /* Enable the GPIO Clock */
  SCU_APBPeriphClockConfig(__GPIO0, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO1, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO2, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO3, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO4, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO5, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO6, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO7, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO8, ENABLE);
  SCU_APBPeriphClockConfig(__GPIO9, ENABLE);
   
}

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  
  GPIO_DeInit(GPIO0);
  GPIO_DeInit(GPIO1);
  GPIO_DeInit(GPIO2);
  GPIO_DeInit(GPIO3);
  GPIO_DeInit(GPIO4);
  GPIO_DeInit(GPIO5);
  GPIO_DeInit(GPIO6);  
  GPIO_DeInit(GPIO7);  
  GPIO_DeInit(GPIO8);
  GPIO_DeInit(GPIO9);
        
  /* Gonfigure EMI */
  GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ;
  GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable;
  GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2;
  GPIO_Init (GPIO7, &GPIO_InitStructure);
  GPIO_Init (GPIO8, &GPIO_InitStructure);
  GPIO_Init (GPIO9, &GPIO_InitStructure);
  
  GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ;
  GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable;
  GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt3;
  GPIO_Init (GPIO7, &GPIO_InitStructure); 
}
/* 16位复用模式 */
void EMI_Configuration(void)
{
  EMI_InitTypeDef EMI_InitStruct;
    
  /* Enable EMI clock */
  SCU_AHBPeriphClockConfig( __EMI, ENABLE ); 
  SCU_EMIModeConfig( SCU_EMI_MUX ); 
  SCU_EMIALEConfig( SCU_EMIALE_LEN1,SCU_EMIALE_POLLow );   
  GPIO_EMIConfig( ENABLE ); 
  
  EMI_DeInit(); 
  EMI_StructInit( &EMI_InitStruct );
  EMI_InitStruct.EMI_Bank_MemWidth=EMI_Width_HalfWord; 
  EMI_InitStruct.EMI_PageModeRead_Selection=EMI_NormalMode;
  EMI_InitStruct.EMI_Bank_IDCY =0xf;
  EMI_InitStruct.EMI_Bank_WSTRD =0xf;
  EMI_InitStruct.EMI_Bank_WSTWR =0xf;
  EMI_InitStruct.EMI_Bank_WSTROEN=0xf;
  EMI_InitStruct.EMI_Bank_WSTWEN=0x0f;   
  
  EMI_InitStruct.EMI_Bank_WSTRD =0x04;
  EMI_InitStruct.EMI_Bank_WSTROEN=0x03;
  EMI_InitStruct.EMI_Bank_WSTWR =0x04;
  EMI_InitStruct.EMI_Bank_WSTWEN=0x03;
  
  EMI_Init( EMI_Bank0, &EMI_InitStruct );
}

使用特权

评论回复
15
zljun|  楼主 | 2007-4-3 13:28 | 只看该作者

P8口上的波形

    -------       ----       ----       -------
___|       |_____|    |_____|    |_____|       |__

较宽的高脉冲为160ns,较窄的高脉冲为50ns,低脉冲为60ns。

如果将程序中的while(data1<data2)改成while(1),则结果如下:

较宽的高脉冲为100ns,较窄的高脉冲为50ns,低脉冲为60ns。

测量仪器是采样周期为10ns的逻辑分析仪。

使用特权

评论回复
16
zljun|  楼主 | 2007-4-3 13:31 | 只看该作者

结论

一条“B 0X0025CC”的执行时间是100-50=50ns。
两条“B 0X00xxxx”的执行时间是160-50=110ns。

使用特权

评论回复
17
telnet| | 2007-4-3 14:52 | 只看该作者

谢谢你的结果!

能否将时钟频率降为10M,想看看同样程序的P8口上的波形!仅仅单从指令上看,低脉冲也应该是一个时钟(10n),所以我的建议是忽略对外部操作的延迟,延长指令时间能够更清楚地看到P8口上的波形执行指令的个数,同时使用while(1)。

使用特权

评论回复
18
香水城| | 2007-4-3 17:36 | 只看该作者

telnet的主意不错

我们在测试检查楼主提供的程序,看看配置是否正确。

使用特权

评论回复
19
zljun|  楼主 | 2007-4-6 17:16 | 只看该作者

香水城,测试结果有否改进?

怎么没人回答我的问题了呢?
我现在的项目对速度要求很高,如果每个while语句都得多费110ns-60ns=50ns的时间,很心疼呀。

使用特权

评论回复
20
lut1lut| | 2007-4-9 11:39 | 只看该作者

配置的问题

不知道楼主最终是想要看CPU跑在最快的速度(96MHz)还是EMI跑在最快的速度(66MHz)时候的情况。
在这个配置里,EMI已经被配置在了96MHz,已经超出了datasheet的上限值
另外,楼主用的oscillator用的是多少?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

55

帖子

0

粉丝