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

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

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

md_flag为1b0就达到目的了。

rom_en, code_flag, cmd_flag在一般情况下都是1b1,但是如果PC值一改变,那么就需要同时被赋值给1b0。不过rom_en和code_flag,cmd_flag有区别: rom_en是立即生效,code_flag/cmd_flag要在下一个时钟生效。rom_en下一个时钟是要有效的,因为要读新的PC值。

改变PC有三种情况:

1,中断发生:我们命名为:int_all。只要中断发生,PC要么等于0,4,8,10,1C等等。

2,从寄存器里给PC赋值:一般情况是:MOV PC,R0。在小孩阶段,已经可以给出新的PC值了,这个和中断类似。我们命名为:to_rf_vld。

3,从RAM里面取值给PC赋值:一般是LDR PC [PC,#0x0018],那么在小孩阶段,发出读指令,我们命名为:cha_rf_vld;在幽灵阶段,新的PC出现,但还没写入PC(R15),这时,也是不能执行任何指令的,我们命名为:go_rf_vld。

下面是我写的rom_en, code_flag, cmd_flag赋值语句,可以对照体会一下。发扬古人“格”物“格”竹子的精神,设想一下,是不是那么回事!

wire rom_en;

assign rom_en =cpu_en & ( ~(int_all | to_rf_vld | cha_rf_vld | go_rf_vld | wait_en | hold_en ) );

regcode_flag;

always @ ( posedge clk or posedge rst )

if ( rst )

code_flag <= #`DEL 1d0;

else if ( cpu_en )

if ( int_all | to_rf_vld | cha_rf_vld | go_rf_vld | ldm_rf_vld )

code_flag <= #`DEL0;

else

code_flag <= #`DEL1;

else;

reg cmd_flag;

always @ ( posedge clk or posedge rst )

if ( rst )

cmd_flag <= #`DEL 1d0;

else if ( cpu_en )

if ( int_all )

cmd_flag <= #`DEL0;

else if ( ~hold_en )

if ( wait_en | to_rf_vld | cha_rf_vld | go_rf_vld )

cmd_flag <= #`DEL0;

else

cmd_flag <= #`DELcode_flag;

else;

else;

ldm_rf_vld是在执行LDM指令时,改变R15的情况,这个情况比较特殊,以后再讲。

除了这个,还有wait_en和hold_en。我还是举例子说明吧。

1,wait_en

如果R0 = 0x0, R1=0x0。紧接着会执行下面两条指令:1, MOV R0,#0xFFFF; 2, ADD R1,R1,[R0,LSL #4]。执行完后,正确的结果应该是:R1=0xFFFF0。

rom_encode_flagcmd_flag

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

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

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

XADD R1,R1,[R0,LSL #4]MOV R0,#0xFFFF

如上图在“小孩”阶段:正在执行MOV R0,#0xFFFF,但是R0这个寄存器里面存放的是0x0,而不是0xFFFF。因为在小孩阶段,只是要写R1,但是并没有写入,在下一个时钟生效。但是“婴儿”阶段,要执行ADD R1,R1,[R0, LSL #4],必须先对R0移位。那么它取得R0的来源是从case语句,是从R0这个寄存器里得来的,而不是“小孩”阶段执行的结果得来的。

所以如果出项这样的情况:上一条指令的输出,正好是下一条指令的输入。那么下一条指令是不能执行,必须要缓一个周期执行。也就是说在两条指令之间插入一个空指令,让R0得到新的值,再执行下一条语句,就不会出错。wait_en就表示这种情况。

如果wait_en == 1b1,那么rom_en==1b0,表示ADD R1,R1,[R0,LSL #4]还没执行呢,先不用取下一条指令。code_flag不受wait_en影响;cmd_flag<=1b0;下一个时钟,表示这是一条空指令,并不执行。

2,hold_en

简而言之,就是在cmd_flag这一阶段的指令一个时钟执行不下去,需要多个时钟。比如说:LDMIA R13! {R0-R3},需要从RAM里面读四个数,送入相应的寄存器。我们只有一个RAM的读写端口,执行这条命令需要启动这个读写端口四次。那么就要告诉rom_en,你不能取新数呐。所以我们在LDMIA R13! {R0-R3}占用的4个周期里,前三个时,让hold_en==1b1。那么在这段时间内,rom_en==1b0, cmd_flag不受影响。因为这时执行有效,cmd_flag必须保持开始的1b1不变。

好了,这一节,先写到这,希望大家也发挥divide & conquer的精神,一点点的解决问题,走向最后的成功,欢迎提出有疑问的地方。

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

网站地图

Top