微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 跟我写ARM处理器之二:主体结构的确定

跟我写ARM处理器之二:主体结构的确定

时间:11-10 来源:互联网 点击:

ls if ( cod_is_mult )

code_rs =code_rsa;

else begin

code_rs =32b0;

code_rs[code_rot_num] = 1b1;

end

always @ ( * )

case ( code[11:8] )

4h0 : code_rsa =r0;

4h1 : code_rsa =r1;

4h2 : code_rsa =r2;

4h3 : code_rsa =r3;

4h4 : code_rsa =r4;

4h5 : code_rsa =r5;

4h6 : code_rsa =r6;

4h7 : code_rsa =r7;

4h8 : code_rsa =r8;

4h9 : code_rsa =r9;

4ha : code_rsa =ra;

4hb : code_rsa =rb;

4hc : code_rsa =rc;

4hd : code_rsa =rd;

4he : code_rsa =re;

4hf : code_rsa =rf;

endcase

*/

Sec_operand的例子就不用举了吧,无非是根据指令选择符合该指令的要求,来送给下一级的加/减法器。

所以说,这样的两级流水线我们同样可以完成。现在使用三级流水线,关键路径是26ns。如果使用两级流水线,绝对在50 ns以内。工作在20MHz的ARM,同样也是受低功耗用户们欢迎的。有兴趣的,在看完我的文章后,把ARM核改造成两级流水线。

现在要转换一个观念。以前的说法:第一级取代码;第二级解释代码,第三级执行代码。现在要转换过来,只有两级,第一级:取代码;第二级执行代码。而现在我做成第三级,是因为一级执行不完,所以要分两级执行。所以是:第一级取代码;第二级执行代码阶段一(主要是乘法);第三级执行代码阶段二(主要是加/减法)。

也许有人要问,那解释代码为什么不安排一级?是因为我觉得解释代码太简单,根本不需要安排一级,这一点,我在下一节会讲到。

既然这个核是三级流水线,还是从三级流水线讲起。我把三级流水线的每一级给了一个标志信号,分别是:rom_en, code_flag, cmd_flag。rom_en对应第一级取代码,如果rom_en==1b1表示需要取代码,那这个代码其实还处在ROM内,我们命名为“胎儿”;如果code_flag==1b1表示对应的code处于执行阶段一,可以命名为“婴儿”;如果cmd_flag==1b1,表示对应的code处于执行阶段二,命名为“小孩”。当这个指令最终执行结束,可以认为它死去了,命名为“幽灵”。

rom_encode_flagcmd_flag

-----------------

|胎儿|婴儿小孩-->幽灵

-----------------

现在,我们模拟一下这个执行过程吧。一般ROM里面从0开始的前几条指令都是跳转指令,以hello这个例程为例,存放的是:LDR PC,[PC,#0x0018];连续五条都是这样的。

刚上电时,rom_en==1b1,表示要取number 0号指令:

rom_en==1b1code_flagcmd_flag

(addr=0)

-----------------

|胎儿|婴儿小孩-->幽灵

-----------------

LDR PC,[PC,#0x0018]

第一个clock后;第一条指令LDR PC,[PC,#0x0018]到了婴儿阶段。

rom_en==1b1code_flagcmd_flag

(addr=4)

-----------------

|胎儿|婴儿小孩-->幽灵

-----------------

LDR PC,[PC,#0x0018]LDR PC,[PC,#0x0018]

第二个clock后,第一条指令LDR PC,[PC,#0x0018]到了小孩阶段。

rom_en==1b1code_flagcmd_flag

(addr=8)

-----------------

|胎儿|婴儿小孩-->幽灵

-----------------

(addr=8)(addr=4)(addr=0)

LDR PC,[PC,#0x0018]LDR PC,[PC,#0x0018]LDR PC,[PC,#0x0018]

当“小孩”== LDR PC,[PC,#0x0018]时,不能再取addr==8的指令了。因为addr=0时的LDR PC,[PC,#0x0018]更改了PC的值,不仅不能取新的code,连处于婴儿阶段的code也不能执行了。如果执行的话,那就是错误执行。为了避免addr=4的LDR PC,[PC,#0x0018]执行,我们可以给每一个阶段打一个标签tag,比如code_flag对应婴儿,cmd_flag对应小孩。只有在cmd_flag==1b1时,指令才执行。如下图所示。

rom_en==1b0code_flagcmd_flag

(addr=8)0-->0 -->

-----------------

|胎儿|婴儿小孩-->幽灵

-----------------

(addr=8)(addr=4)(addr=0)

LDR PC,[PC,#0x0018]LDR PC,[PC,#0x0018]LDR PC,[PC,#0x0018]

(修改PC)

发出读指令

一旦有修改PC,那么rom_en立即赋值为1b0。code_flag, cmd_flag在下一个时钟赋给1b0。表示在下一个时钟“婴儿”和“小孩”都是非法的,不能执行。但是新的PC值不是立即得到的,因为LDR指令是要从RAM取数据,在小孩阶段只能发出读指令,在一个时钟,新的PC值才出现在ram_rdata,但还没有出现在R15里面,所以要等一个时钟。

rom_en==1b0code_flag==1b0cmd_flag==1b0

(addr=8)

-----------------

|胎儿|婴儿小孩-->幽灵

-----------------

(addr=8)(addr=8)(addr=4)(addr=0 )

XLDR PC,[PC,#0x0018]LDR PC,[PC,#0x0018]LDR PC,[PC,#0x0018]

ram_rdata=NEW PC

在空闲的这个周期内,为了让指令不执行,只要赋值:rom_en, code_flag, c

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top