跟我写ARM处理器之二:主体结构的确定
第一个是MLA R1,R2,R3,R0。它的意思是:R1=R2*R3 + R0。如果我们要实现这一条指令的话,一个32×32的乘法器需要,一个32+32的加法器是跑不了的。现在定义几个节点:Rm = R2; Rs=R3; sec_operand(第二操作数的意思)=mult_rm_rs[31:0](mult_rm_rs的低32位);Rn=R0;则结果等于:Rn + sec_operand。
第二个是:SUB R1,R0, R2, LSL #2。它的意思是:R1=R0 - R2<2。看了我前面文章的知道,这个指令同样可以像前面一样套入:Rm=R2; Rs=32b100; sec_operand=mult_rm_rs[31:0];Rn=R0;结果等于:Rn - sec_operand。
第三个是:LDR R1,[R0,R2,LSR #2]!。这是一条取RAM的数据进入寄存器的指令,取地址是:R0+R2>>2。并把取地址保存回R0。现在比较难计算的是: R0+R2>>2。但是这个同样也可以往前两个模式一样靠:Rm=R2; Rs=32b0100_0000_0000_0000_0000_0000_0000_0000,那么sec_operand = mult_rm_rs[63:32]正好等于:R2>>2。如果Rn=R0,取地址就等于:Rn+sec_operand。这个地址还要送入R0中。
看到这,大家明白了本核的核心结构了吧。网友先别赞我眼光如炬,目光如神,一眼看出核心所在。实际上我在写第一版的时候,绝没想到把移位交给乘法器来完成,也是傻傻地参考别人文档写了一个桶形移位器。但后来灵光一现,觉得既然乘法器避免不了,如果只让他在MUL指令的时候使用,其他指令的时候闲着,那多么没意思呀。这样乘法器复用起来,让它参与了大部分指令运算。
好了,我们要做的事是这样的。指令到来,准备Rm, Rs, Rn,为生成sec_operand产生控制信号,决定Rn和sec_operand之间是加还是减,那么最后生成的结果要么送入寄存器组,要么作为地址参与读写操作。就这么简单!
前面的这一套完成了,我想ARM核也就成功了大半了。
上面解决了做什么的问题,随之而来的是怎么做的问题。可能大家首先想到的是三级流水线。为什么是三级呢?为什么不是两级呢?两级有什么不好?我告诉你们,两级同样可以,无非是关键路径长一点。我接下来,就要做两级,没有什么能束缚我们!实际上,很多项目用不到30、40MHz的速度,10M,20M也是可以接受,100ns,50ns内,我那一套乘加结构同样能满足。口说无凭,看看我代码中是如何生成:Rm,Rs, sec_operand,Rn的:
注:以下非正式代码,讲解举例所用
/*
always @ ( * )
if ( code_is_ldrh1|code_is_ldrsb1|code_is_ldrsh1 )
code_rm ={code[11:7],code[3:0]};
else if ( code_is_b )
code_rm ={{6{code[23]}},code[23:0],2b0};
else if ( code_is_ldm )
case( code[24:23] )
2d0 : code_rm ={(code_sum_m - 1b1),2b0};
2d1 : code_rm =0;
2d2 : code_rm ={code_sum_m,2b0};
2d3 : code_rm =3b100;
endcase
else if ( code_is_swp )
code_rm =0;
else if ( code_is_ldr0 )
code_rm =code[11:0];
else if ( code_is_msr1|code_is_dp2 )
code_rm =code[7:0];
else if ( code_is_multl & code[22] & code_rma[31] )
code_rm =~code_rma + 1b1;
else if ( ( (code[6:5]==2b10) & code_rma[31] ) & (code_is_dp0|code_is_dp1|code_is_ldr1))
code_rm =~code_rma;
else
code_rm =code_rma;
always @ ( * )
case ( code[3:0] )
4h0 : code_rma =r0;
4h1 : code_rma =r1;
4h2 : code_rma =r2;
4h3 : code_rma =r3;
4h4 : code_rma =r4;
4h5 : code_rma =r5;
4h6 : code_rma =r6;
4h7 : code_rma =r7;
4h8 : code_rma =r8;
4h9 : code_rma =r9;
4ha : code_rma =ra;
4hb : code_rma =rb;
4hc : code_rma =rc;
4hd : code_rma =rd;
4he : code_rma =re;
4hf : code_rma =rf;
endcase
*/
我有if else这个法宝,你不管来什么指令,我都给你准备好Rm。这就像一台脱粒机,你只要在送货口送东西即可。你送麦子脱麦子,你送玉米脱玉米。你的Rm来自于寄存器组,那好我用code_rma来给你选中,送入Rm这个送货口。你的Rm来自代码,就是一套立即数,那我就把code[11:0]送入Rm,下面的程式有了正确的输入,你只要把最后的正确结果,送给寄存器组即可。
再看看Rs的生成:
注:以下非正式代码,讲解举例所用
/*
always @ ( * )
if ( code_is_dp0|code_is_ldr1 )
code_rot_num =( code[6:5] == 2b00 ) ? code[11:7] : ( ~code[11:7]+1b1 );
else if ( code_is_dp1 )
code_rot_num =( code[6:5] == 2b00 ) ? code_rsa[4:0] : ( ~code_rsa[4:0]+1b1 );
else if ( code_is_msr1|code_is_dp2 )
code_rot_num ={ (~code[11:8]+1b1),1b0 };
else
code_rot_num =5b0;
always @ ( * )
if ( code_is_multl )
if ( code[22] & code_rsa[31] )
code_rs =~code_rsa + 1b1;
else
code_rs =code_rsa;
e
ARM处理器主体结 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)