VHDL设计进阶:逻辑综合的原则以及可综合的代码设计风格

分享到:
186
下一篇 >

 4.5.1 always块语言指导原则

使用always块进行可综合的代码设计时需要注意以下几个问题。

(1)每个always块只

integer[:]

(6)always块中应该避免组合反馈回路。每次执行always块时,在生成组合逻辑的always块中赋值的所有信号必需都有明确的值;否则需要设计者在设计中加入电平敏感的锁存器来保持赋值前的*后一个值。

只有这样,综合器才

input a,b,c;

reg e,d;

always @(a or b or c) begin

      e = d & a & b;       //因为d没有在敏感电平列表中,所以d变化时,e不 c;

end

(7)对一个寄存器型(reg)或整型(integer)变量的赋值只允许在一个always块内进行,如果在另一always块也对其赋值,这是非法的。

(8)把某一信号值赋为'bx,综合器就把它解释成无关状态,因而综合器为其生成的硬件电路*简洁。

4.5.2  可综合风格的Verilog HDL模块实例

1.组合逻辑电路设计实例

例4.6:8位带进位端的加法器的设计实例(利用简单的算法描述)。

module adder_8(cout,sum,a,b,cin);               //模块声明

      output cout;

      output [7:0] sum;

      input cin;

      input[7:0] a,b;                             //端口声明

      assign {cout,sum} = a + b + cin;          //加法器算法

endmodule

 

例4.7:指令译码电路的设计实例(利用电平敏感的always块来设计组合逻辑)。

'define plus     3'd0                         //操作码的宏定义

'define minus    3'd1

'define band     3'd2

'define bor      3'd3'

'define unegate  3'd4

module alu(out,opcode,a,b);                 //模块声明

      output [7:0] out;

      input [2:0] opcode;

      input [7:0] a,b;                       //端口声明

      reg   [7:0] out;                      //寄存器声明

      always @(opcode or a or b) begin       //用电平敏感的always块描述组合逻辑

            case(opcode)

                  'plus: out = a + b;         //算术运算

                  'minus: out = a - b;

                  'band: out = a & b;          //位运算

                  'bor:  out = a 比较后重组信号的组合逻辑(利用task和电平敏感的always块设计)。

module sort4(ra,rb,rc,rd,a,b,c,d);         //模块声明

      output [t:0] ra, rb, rc, rd;

      input [t:0] a, b, c, d;               //端口声明

      reg [t:0] ra, rb, rc, rd;

      reg [t:0] va, vb, vc, vd;             //寄存器声明

      parameter t=3;                            //参数声明

      always @(a or b or c or d) begin       //用电平敏感的always块描述组合逻辑

           {va,vb,vc,vd}={a,b,c,d};

           sort2(va,vc);                        //信号重组

           sort2(vb,vd);

           sort2(va,vb);

           sort2(vc,vd);

           sort2(vb,vc);

           {ra,rb,rc,rd}={va,vb,vc,vd};

      end

      task sort2;                             //x与y互换任务

            inout [t:0] x,y;

            reg [t:0] tmp;

            if(x > y) begin

                 tmp = x;               //使用临时变量tmp保存x的值

                 x = y;

                 y = tmp;

      end

      endtask

endmodule

 

例4.9:比较器的设计实例(利用赋值语句设计组合逻辑)。

module compare(equal,a,b);              //模块声明

      output equal;

      input [size-1:0] a,b;            //端口声明

      parameter size=1;                  //参数声明

      assign  equal =(a==b)? 1 : 0;  //比较器

endmodule

 

例4.10:3-8译码器设计实例(利用赋值语句设计组合逻辑)。

module decoder(out,in);             //模块声明

      output [7:0] out;

      input [2:0] in;                 //端口声明

      assign  out = 1'b1<

                                          //将移位结果赋予out

endmodule

 

例4.11:3-8编码器的设计实例。

编码器设计方案一。

module encoder1(none_on,out,in);            //模块声明

      output none_on;

      output [2:0] out;

      input [7:0] in;                         //端口声明

      reg [2:0] out;

      reg none_on;                              //寄存器声明

      always @(in) begin: local                //in有变化时,触发

            integer  i;                           //变量声明

            out = 0;

            none_on = 1;                         //初始化

            for( i=0; i<8; i=i+1 ) begin      //for循环语句

                 if( in[i] ) begin         //将in中值为1的位编码

                      out = i;

                      none_on = 0;

                 end

            end

      end

endmodule

 

编码器设计方案二。

module encoder2 ( none_on,out2,out1,out0,h,g,f,e,d,c,b,a);     //模块声明

      input h,g,f,e,d,c,b,a;

      output none_on,out2,out1,out0;         //端口声明

      wire [3:0] outvec;                      //向量声明

      assign outvec =                           //使用assign语句实现输出向量赋值

            h ? 4'b0111 : g ? 4'b0110 : f ? 4'b0101:

            e ? 4'b0100 : d ? 4'b0011 : c ? 4'b0010 :

            b ? 4'b0001 : a ? 4'b0000 : 4'b1000;

      assign none_on = outvec[3];            //使用assign语句进行编码

      assign    out2 = outvec[2];

      assign    out1 = outvec[1];

      assign    out0 = outvec[0];

endmodule

 

编码器设计方案三。

module encoder3 ( none_on,out2,out1,out0,h,g,f,e,d,c,b,a);     //模块声明

      input h,g,f,e,d,c,b,a;

      output none_on,out2,out1,out0;      //端口声明

      wire [3:0] outvec;                    //向量声明

      assign {none_on,out2,out1,out0} = outvec;   //与上例的编码方式一致

      always @( a or b or c or d or e or f or g or h) begin

            if(h)       outvec=4'b0111;     //使用if_else语句实现向量赋值

            else if(g) outvec=4'b0110; //共9个分支,其中向量的低3位有8种编码方式

            else if(f) outvec=4'b0101;

            else if(e) outvec=4'b0100;

            else if(d) outvec=4'b0011;

            else if(c) outvec=4'b0010;

            else if(b) outvec=4'b0001;

            else if(a) outvec=4'b0000;

            else         outvec=4'b1000;

      end

endmodule

例4.12:多路器的设计实例。

使用assign赋值语句、case语句或if-else语句可以生成多路器电路。如果条件语句(case或if-else)中分支条件是互斥的话,综合器奇偶校验位生成器设计实例。

module parity( even_numbits,odd_numbits,input_bus);  //模块声明

      output even_numbits, odd_numbits;

      input [7:0] input_bus;                  //端口声明

      assign odd_numbits = ^input_bus; //当input_bus中1的个数为奇数时,输出为1

      assign even_numbits = ~odd_numbits;  //此时输出even_numbits为0

endmodule

 

例4.14:三态输出驱动器设计实例(用连续赋值语句建立三态门模型)。

三态输出驱动器设计方案一。

module trist1( out,in,enable);            //模块声明

      output out;

      input in, enable;                     //端口声明

      assign  out = enable? in: 'bz;      //使用assign语句判断enable的值

endmodule

 

三态输出驱动器设计方案二。

module trist2( out,in,enable );    //模块声明

      output out;

      input in,enable;                //端口声明

      bufif1 mybuf1(out, in, enable); //bufif1是一个 Verilog门级原语(primitive)

                                         //通过实例化该原语,实现三态门的调用

endmodule

 

例4.15:三态双向驱动器设计实例。

module bidir(tri_inout,out,in,en,b);         //模块声明

      inout tri_inout;

      output out;

      input in,en,b;                             //端口声明

      assign tri_inout = en? in : 'bz;       //三态门的输入为in

      assign out = tri_inout ^ b;             //三态门的输出为b

endmodule

2.时序逻辑电路设计实例

例4.16:触发器设计实例。

module dff( q,data,clk);                  //模块声明

      output q;

      input data,clk;                       //端口声明

      reg q;

      always @( posedge clk ) begin      //边缘检测

            q = data;                        //通过always语句,实现触发器

      end

endmodule

 

例4.17:电平敏感型锁存器设计实例一(assign语句)。

module latch1( q,data,clk);                //模块声明

      output q;

      input data,clk;                        //端口声明

      assign q = clk ? data : q;           //通过assign语句,实现的是一个锁存器

endmodule

 

例4.18:带置位和复位端的电平敏感型锁存器设计实例二(assign语句)。

module latch2( q,data,clk,set,reset);   //模块声明

      output q;

      input data,clk,set,reset;           //端口声明

      assign q= reset ? 0 : ( set? 1:(clk? data : q ) );

                                               //通过assign语句,实现的是一个锁存器

                                               //其中,set为置位端,reset为复位端

                                               //在clk为高电平时,锁存data,否则保持q值

endmodule

 

例4.19:电平敏感型锁存器设计实例三(always块)。

module latch3( q, data, clk);           //模块声明

      output q;

      input data,clk;                      //端口声明

      reg q;

      always @(clk or data) begin       //电平检测

            if(clk)                         //clk为高电平时,q锁存data值

                  q = data;

      end

endmodule

 

  注意 有的综合器会产生一个警告信息,提示将产生了一个电平敏感型锁存器。因为此例中设计的就是一个电平敏感型锁存器,所以这个警告信息是没有问题的。

 

例4.20:移位寄存器设计实例。

module shifter( din,clk,clr,dout);         //模块声明

      input din,clk,clr;

      output [7:0] dout;                     //端口声明

      reg [7:0] dout;

      always @(posedge clk) begin

            if(clr)                             //清零

                   dout = 8'b0;

            else begin

                   dout = dout<<1;             //左移一位

                   dout[0] = din;             //把输入信号放入寄存器的*低位

            end

      end

endmodule

例4.21:8位计数器设计实例一。

module counter1( out, cout, data, load, cin, clk);     //模块声明

      output [7:0] out;

      output cout;

      input [7:0] data;

      input load, cin, clk;                //端口声明

      reg [7:0] out;

      always @(posedge clk) begin         //边缘检测

            if( load )                        //加载信号检测

                 out = data;

            else

                 out = out + cin;

            end

      assign cout= & out & cin;           //只有当out[7:0]的所有各位都为1

                                               //并且进位cin也为1时才8位计数器设计实例二。

module counter2( out, cout, data, load, cin, clk);     //模块声明

      output [7:0] out;

      output cout;

      input [7:0] data;

      input load, cin, clk;                     //端口声明

      reg [7:0] out;

      reg cout;

      reg [7:0] preout;                         //寄存器声明

      always @(posedge clk) begin              //边缘检测

            out = preout;                         //触发器

            end

      //计算计数器和进位的下一个状态,为提高性能,load不应影响进位

      always @( out or data or load or cin ) begin

            {cout, preout} = out + cin;        //进位操作

            if(load) preout = data;             //判断加载信号

            end

endmodule

你可能感兴趣: 设计应用 编码器 硬件
无觅相关文章插件,快速提升流量