跟我写ARM处理器之二:主体结构的确定
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的精神,一点点的解决问题,走向最后的成功,欢迎提出有疑问的地方。
ARM处理器主体结 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)