Verilog实例分析-task与function的使用

       这篇博客是我在学生时代的第一篇博客,有人会问你没玩过微博吗?我说:‘’我没有玩过”。我不知道大家因为因为什么原因爱上现在你所从事的行业或者所学的专业,虽然我的经验很少,但我认为学习任何东西你都要为了心中那个小小的信念去学习,只有那样你才能不时地产生“原来如此”的心声。好了,说一下我写博客的目的吧!首先,是为了记录自己在学习过程中的感悟,并将其分享给大家,帮助那些需要帮助的人清楚的搞明白一些一些问题;其次,我希望通过写这种技术博客来发泄感情,博主是一个感情比较丰富的人,不过由于一些原因现在只希望将感情给予自己将来所从事的行业。

       好了,闲话少说,Verilog是一种硬件描述语言,想必大家早已知道。有一些初学者或者对硬件描述缺乏深入思考的人认为它是这样的

       “Verilog是一种编程语言,它应该和C语言差不多吧,你看它们的关键字有好多都是相同的。语言吗!都差不多”。

       我想说:不错,Verilog是一种语言,它的全名是VerilogHDL(Verilog hardware description language),中国名字叫“硬件描述语言”。在这里顺便说一下,一些专业技术名词的英文命名其实是非常贴切的,相反,翻译成中文后变得模棱两可,产生歧义,不容易为读者所理解。所以大家尽量去看英文原著。

       有人说Verilog的可综合关键词就有那几个:if,else,else if,case,endcase,begin,end,module,endmodule,always,assign,input,output,inout,reg,wire,其实不然,Verilog可综合的关键字还有一些,比如while,repeat,function,task等等。只是大家在用的时候要注意。时刻记住Verilog是一种硬件 描述语言,描述是啥意思,描述就是说电路此时已经在你的脑中构建出来了,你通过这种语言告诉计算机,然后让它帮你产生相应的电路。

     下面我们分别用task和function的形式来描述一个四位二进制全加器,闲话不多说,下面我们看着代码来分析,我认为这样效率会 比较高。同时,这也是一种不错的教学手段,那就是“先抛出问题激起他人学习的兴趣,然后在你的引导下将他人从云里雾里拉出来”。毕竟 ,晴朗的天空才是大家的最爱。

     四位二进制全加器的function形式实现:

module full_adder_4(A,B,CIN,S,COUT);

input[3:0] A;
input[3:0] B;
input CIN;
output[3:0] S;
output COUT;
wire[3:0] S0,S1,S2,S3;

function signed[1:0] ADD;
//port declaration
 input A;
 input B;
 input CIN;
//internal node signals declaration
 reg S,COUT;
 
 begin
 S=A^B^CIN;
 COUT=(A&B)|(A&CIN)|(B&CIN);
 ADD={COUT,S};
 end
 
 endfunction
 
 assign S0=ADD(A[0],B[0],CIN);   //第一位求和
 assign S1=ADD(A[1],B[1],S0[1]); //第二位求和
 assign S2=ADD(A[2],B[2],S1[1]); //第三位求和
 assign S3=ADD(A[3],B[3],S2[1]); //第三位求和
 
 assign S={S3[0],S2[0],S1[0],S0[0]};
 assign COUT=S3[1];
 
 endmodule 
 
 
 
 

四位二进制全加器的task形式实现:

module full_adder(A,B,CIN,S,COUT);
input[3:0] A;
input[3:0] B;
input CIN;
output[3:0] S;
output COUT;
reg[3:0] S0,S1,S2,S3;

task ADD;

input A;
input B;
input CIN;
output[1:0] SUM;



reg S;
reg COUT;

begin
 S=A^B^CIN;
 COUT=(A&B)|(A&CIN)|(B&CIN);
 SUM={COUT,S};
end

endtask

always@(*) //A or B or CIN
begin
ADD(A[0],B[0],CIN,S0);
ADD(A[1],B[1],S0[1],S1);
ADD(A[2],B[2],S1[1],S2);
ADD(A[3],B[3],S2[1],S3);
end
 assign S={S3[0],S2[0],S1[0],S0[0]};
 assign COUT=S3[1];


endmodule

  上面的这两种描述形式所产生的RTL视图是一样的,也就是说它们映射后的硬件电路是一样的。并且要告诉大家,与task的输出端口相连的并非一定要reg类型变量,wire类型变量也可以,并且 它们综合后的结果是一样的(有的博客或其他地方说必须为reg类型变量,其实,这种说法欠妥)。其实,这一点也不难理解,你想一下这是纯组合逻辑电路,除了那些与或非运算符外,其他的应该全部映射为连线,阻塞 赋值符号应该映射为连线与门电路端口或者连线与模块端口的连接结点,这样才会产生想要的电路。在这种情况下,中间变量就 没有必要一定为reg类型,wire类型也可以。

猜你喜欢

转载自blog.csdn.net/weixin_40446812/article/details/81741300