verilog自学笔记

(1}驱动与赋值:

wire类型是被驱动的,该值不被保存,再任一仿真步进上都需要重新计算。

reg类型是被赋值的,再仿真过程中被一直保持,直到下一个赋值出现。

wire A_xor_wire;

assign #1 A_xor_wire = eq0 ^ eq1;

两者描述目的一样,但第一个实际是连续驱动的过程,在仿真的任意时刻A_xor_wire的值为eq0与eq1的异或;第二个只在eq0或eq1发生改变时,才会将计算的值赋给A_xor_wire,在其他时刻A_xor_wire的值需要被保持。

连续赋值assign语句左侧必须是net类型(如wire类型),过程赋值always块中的赋值语句左侧必须是reg类型。

reg A_xor_wire;

always @ (eq0 or eq1)

A_xor_wire = #1 eq0 ^ eq1;

{2}若无特别定义,input,output都默认为wire类型

即module (input a output c);默认为module (input wire a output wire c);

(3)xor 异或;xnor同或(异或非)

(4)vector向量的定义:

如:wire [3:0] vec1;

向量的维度在向量名之前。

(4)implicit nets:

wire [2:0] a,c;

assign a = 3'b001;

assign b = a; // b = 1; 产生implicit net

assign c = b; // c = 001; bug

未声明时b默认为为一位wire,所以要把第三个赋值语句会报错;

添加`default_nettype none指令会使上面第二个语句就开始报错,使bug更容易发现。

(5)

数组array

reg [7:0] vec1 [254:0]; // 255个元素,每个为8位的reg

reg vec2 [254:0]; //255个元素,每个为1位的reg

(6)

module top_module( 
    input [3:0] in,
    output out_and,
    output out_or,
    output out_xor
);
    
    //and(out_and,in[3],in[2],in[1],in[0]);
    //assign out_and = in[3] & in[2] & in[1] & in[0];
    assign out_and = & in;
    
    //or(out_or,in[3],in[2],in[1],in[0]);
    //assign out_or = in[3]|in[2]|in[1]|in[0];
    assign out_or = |in;
    
    //xor(out_xor,in[3],in[2],in[1],in[0]);
    //assign out_xor = in[3] ^ in[2]^in[1]^in[0];
    assign out_xor = ^in;
endmodule

(7)按位操作符:

~ : ~m,将m每个位取反。

& : m & n,将m每个位与n相应位相与。

| : m | n,将m每个位与n相应位相或。

^ : m ^ n,将m每个位与n相应位相异或。

~^ 或 ^~ : m ~^ n或m ^~ n,将m每个位与n相应位相异或非。

规约操作符:

& : &m,将m所有位相与(1位结果)。

~& : ~&m,将m所有位相与非(1位结果)。

| : |m,将m所有位相或(1位结果)。

~| : ~|m,将m所有位相或非(1位结果)。

^ : ^m,将m所有位相异或(1位结果)。

~*或^~ : ~^m或^~m,将m所有位相异或非(1位结果)。

(8)向量的级联

如 input [15:0] in;

output [23:0] out;

assign out[15:0] = {in[7:0] , in[15:8]};

assign {out[15:8] , out[7:0]} = in;

以上两个赋值语句描述的结果相同,都是将in的两个字节交换赋值给out的低16位。

assign out = {in[7;0] , in[15:8]};

这条赋值语句为了匹配左边out的24位,右边需要扩展到24位,将[23:16]赋值0,所以最后out[15:0]与前两条相同,out[23:16]每位都为0,而前两句对out[23:16]没有赋值。

如 

module top_module (
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );

    // assign { ... } = { ... };
    assign {w,x,y,z} = {a,b,c,d,e,f,2'b11};
endmodule
 

建立一个电路,将8位数字扩展到32位。这需要连续24个符号位的拷贝(即复制位[7]24次),然后是8位数字本身

module top_module (
    input [7:0] in,
    output [31:0] out );//

    //assign out = {{24{in[7]}},in};
    assign out = in[7]?{{24{1'b1}},in}:{{24{1'b0}},in};
endmodule
————————————————
版权声明:本文为CSDN博主「杰之行」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/haojie_duan/article/details/113245637

(9)模块实例化

通过位置或名称将要调用模块的模块的wire与被调用的模块的端口连接起来:

module mod_a (input in1, input in2, output out);

        //module body

endmodule

现在top_module中调用mod_a:

module top_module (input a, input b, output out);

        // mod_a instance1 (a, b, out);     此为位置,实例化一个mod_a类型的模块,将它命名为“instance1”,其端口位置必须与mod_a的端口位置严格对应。

        mod_a instance2 (.out(out),

                                      .in1(a),

                                      .in2(b));       //此为名称,中略,这种方法端口位置不影响

endmodule

(10)always用法,case用法

例:

    always @(*) begin
        case (sel)
            2'b00:q = d;           //case后只能跟一个赋值语句。
            2'b01:q = q0;
            2'b10:q = q1;
            2'b11:q = q2;
            default:;               //指的是上面没有说明到的其他情况
        endcase
    end

always @后如果是“*”那么说明是组合逻辑电路,如果是posedge,negedge就是时序逻辑电路。

(11)有三种赋值方法

1)对于时序逻辑,即always模块的敏感表为沿敏感信号(多为时钟或复位的正沿或负沿),统一用非阻塞赋值。

2)对于always模块的敏感表为电平敏感信号的组合逻辑,统一用阻塞赋值。

3)对于assign描述的组合逻辑,称为连续赋值语句,统一用阻塞赋值,变量被定义为wire型信号。

例:

reg [3:0] cnt_out_plus;

always @(cnt_out) 

        cnt_out_plus = cnt_out + 1;

注意:1)虽然cnt_out_plus为reg类型,但always模块的敏感表为电平敏感信号,所以为纯组合逻                   辑。

           2)为什么不用 cnt_out = cnt_out + 1; 因为这样会产生组合逻辑环,为大忌。

        时序的always块的输出不会像其他两个一样立即可见,而是会在输出处会生成一个寄存器,在下一个敏感源到来时才能看到这个输出。也就是说时序的always块的输出是延时的。

(12)always块里的if语句

always @(*) begin
    if (condition) begin
        out = x;
    end
    else begin
        out = y;
    end
end

(12.1)if 语句注意

if(条件..1){undefined

     要执行的语句;
}

if(条件..2){undefined

   要执行的语句
}

双if是每一个if都会进行判断,依次对if进行判断,互相之间不会影响;


if(条件..1){undefined

    执行的语句
}else if(条件..2){undefined

   执行的语句
}

这个if和else if 之间是有联系的,当不满足if中的条件的时候,就会去执行else if ,如果if中的条件已经满足了,就不会去判断else if中的条件了
————————————————
版权声明:本文为CSDN博主「libin_gogogo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/libin_gogogo/article/details/78265973

(13)使用带有条件运算符的连续赋值

assign out = (condition) ? x : y;

(14)case-z 的使用

always @(*) begin
    casez (in[3:0])
        4'bzzz1: out = 0;   // in[3:1] can be anything
        4'bzz1z: out = 1;
        4'bz1zz: out = 2;
        4'b1zzz: out = 3;
        default: out = 0;
    endcase
end

z代表不关心的值。有时会用?或x代替z。

(15)奇偶校验电路可以用异或来实现:

偶数个1异或的结果总为0,奇数个1异或的结果总为1。

(16)倒序题 for循环的使用

注意每位与1异或只能实现每位值反转,并不能实现倒序。

如 4c...63倒序

                   0100 1100 ... 0110 0011

        倒序:1100 0110 ... 0011 0010

  与1异或: 1011 0011 ... 1001 1100 

所以可用for循环实现倒序,循环次数变量要声明为integer

在always组合逻辑块中使用:

integer i;
    always @(*) begin
        for (i=0;i<=99;i++)
            out[i] = in[99-i];
    end

也可以在assign语句中使用,但要用generate包起来:

  generate
        genvar i;
        for (i=0;i<=99;i++) begin:reverse
            assign out[i] = in[99-i];
        end
    endgenerate

(17)generate

可用于对矢量中的多个位进行重复操作时,或者当进行多个模块的实例引用的重复操作时

generate语法

  • 定义genvar,作为generate种的循环变量。
  • generate语句中定义的for语句,必须要有begin,为后续增加标签做准备。
  • begin必须要有名称,也就是必须要有标签,因为标签会作为generate循环的实例名称。

generate语句有generate-for,generate-if,generate-case三种语句

generate-for语句

(1) 必须有genvar关键字定义for语句的变量。

(2)for语句的内容必须加begin和end(即使就一句)。

(3)for语句必须有个名字。

例题:100位加法器

module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );
    //always @(*) begin
    //    {cout[0],sum[0]} = a[0] + b[0] + cin;
    //end
    //integer i;
    //always @(*) begin
    //    for (i=1;i<=99;i++) begin
    //        {cout[i],sum[i]} = a[i] + b[i] + cout[i-1];
    //    end
    //end
generate 
    genvar i;
    for (i=0;i<=99;i++) begin:adder
        if (i == 0) begin
             fulladder fulladder_inst (a[0],b[0],cin,cout[0],sum[0]);
        end
        else begin
             fulladder fulladder_inst (a[i],b[i],cout[i-1],cout[i],sum[i]);
        end
    end
endgenerate
endmodule
module fulladder (input a,input b,input cin,output cout,output sum);
    assign {cout,sum} = a + b + cin;
endmodule

(18)verilog与c的不同导致的错误

例一:Bcdadd100

You are provided with a BCD one-digit adder named bcd_fadd that adds two BCD digits and carry-in, and produces a sum and carry-out.

module bcd_fadd (
    input [3:0] a,
    input [3:0] b,
    input     cin,
    output   cout,
    output [3:0] sum );

Instantiate 100 copies of bcd_fadd to create a 100-digit BCD ripple-carry adder. Your adder should add two 100-digit BCD numbers (packed into 400-bit vectors) and a carry-in to produce a 100-digit sum and carry out.

module top_module( 
    input [399:0] a, b,
    input cin,
    output cout,
    output [399:0] sum );
    wire [99:0] c;
    genvar i;
    generate 
        for (i=0;i<=99;i++) begin:adder
            if (i==0) begin
                bcd_fadd bcd_fadd_inst (a[3:0],b[3:0],cin,c[0],sum[3:0]);
            end
            else begin
                bcd_fadd bcd_fadd_inst (a[4*i+3:4*i],b[4*i+3:4*i],c[i-1],c[i],sum[4*i+3:4*i]); //
            end
        end
        assign cout = c[99];
    endgenerate
endmodule

例二:Mux256to1v

Create a 4-bit wide, 256-to-1 multiplexer. The 256 4-bit inputs are all packed into a single 1024-bit input vector. sel=0 should select bits in[3:0], sel=1 selects bits in[7:4], sel=2 selects bits in[11:8], etc.

module top_module( 
    input [1023:0] in,
    input [7:0] sel,
    output [3:0] out );
    always @(*) begin
        out = in[4*sel+3:4*sel];    //报错
    end
endmodule

例二“4*sel+3:4*sel”这么写会报错“sel不是常量”,而例一中情况则不会。

例二有两种修改方法:

1)out = out = in[4*sel+3 -:4];

表示in的序号4*sel+3以下(包括自己在内)的连续4位。

同理也可以写成:

out = out = in[4*sel +:4];

表示in的序号4*sel以上(包括自己在内)的连续4位。

2)out = {in[4*sel+3],in[4*sel+2],in[4*sel+1],in[4*sel]};

直接拆开把四位级联起来,不用“:”的方式表示。

(19)溢出的判断(补码运算)

计算结果最高位与次高位的进位情况,如果最高位和次高位同时产生进位,即所谓双进位,则这种进位属于允许的自然丢弃。如果只有最高位或者只有次高位产生进位,即只有单进位,则这种进位属于溢出。

所以overflow = cout[最高位] ^ cout[最高位-1];

或者:

由于只有两个正数(负数)相加才可能发生溢出。

所以overflow = a[最高位] & b[最高位] & ~sum[最高位] | ~a[最高位] & ~b[最高位] & sum[最高位]

(20)同步复位,异步复位

(47条消息) 三种复位方式: 同步复位、异步复位、异步复位同步释放_坚持-CSDN博客_异步复位同步释放

同步复位:只在时钟上升沿(如果电路是下降沿有效,那么复位也是下降沿有效)时才有效。

always @ (posedge clk) begin
                  if (!Rst_n)
                    ...
            end

异步复位:无论时钟沿是否到来,只要复位信号有效,就对系统进行复位。

always @ (posedge clk,negedge Rst_n) begin
                   if (!Rst_n)
                      ...
            end

(21)建立时间,保持时间,恢复时间,去除时间。

触发器再时钟有效沿(上升沿或下降沿)来临时对数据进行采样,但实际器件无法做到瞬间完成数据的采样,需要数据再时钟沿前后稳定一段时间,即引入建立时间与保持时间的概念。

1)建立时间Tsu(Setup):时钟有效沿来临之前数据必须保持稳定的最小时间。

2)保持时间Th(Hold):时钟有效沿来临之后数据必须保持稳定的最小时间。

与同步电路中的建立时间,保持时间类似,异步控制信号(如寄存器的异步复位信号)同样需要与时钟满足recovery time和removal time才能有效进行复位操作,防止输出亚稳态。

3)恢复时间(recovery):撤销复位时,恢复到非复位状态的异步控制信号的电平必须在时钟有效沿到来前保持不变的最小时间。

4)去除时间(removal):复位时,已处于复位状态的异步控制信号的电平必须在时钟有效沿后继续保持不变的最小时间。 

(22)边沿检测

Edgedetect

For each bit in an 8-bit vector, detect when the input signal changes from 0 in one clock cycle to 1 the next (similar to positive edge detection). The output bit should be set the cycle after a 0 to 1 transition occurs.

Here are some examples. For clarity, in[1] and pedge[1] are shown separately.

 module top_module (
    input clk,
    input [7:0] in,
    output reg [7:0] pedge
);
    reg [7:0] in_1;
    always @(posedge clk) begin
        in_1 <= in; 
        pedge <= in & ~in_1;
    end
endmodule

“in_1 <= in;”  //将本次输入电平保存至in_1,因为为非阻塞赋值,所以会有一个时钟周期的延时

“pedge <= in & ~in_1;”  //将本次输入电平与前一次的保存电平的反进行与操作,探测上升沿

另外写成这样也可以:

    always @(posedge clk) begin
        in_1 <= in;
    end
   
    always @(posedge clk) begin
        pedge <= in & ~in_1;
    end


(23)上升(下降)沿捕获锁存

探测输入信号每一位的下降沿,若其中部分位有下降沿,则下一周期输出对应位高电平并锁存,直到复位信号reset到来才复位为0。
注意:下降沿捕获均为按位操作,其中一位下降沿只影响对应位的输出,其他位不受影响。

如果这样写会出错:

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    reg [31:0] in_1;
    always @(posedge clk) begin
        if (reset) begin
            out <= 32'b0;
        end
        else begin
            in_1 <= in;
            out <= ~in & in_1 | out;
        end
    end
endmodule

因为若是reset为1,那么在此时钟周期内 in_1 <= in;不会执行,在红色箭头处,reset复位,执行out赋值0,在此时钟周期不再执行in_1 <= in,直到蓝色箭头处,才重新执行,因此此处in_1值为10,而不是0,进而造成out值错误。

所以:

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    reg [31:0] in_1;
    
    always @(posedge clk) begin
        in_1 <= in;
    end
    
    always @(posedge clk) begin
        if (reset) begin
            out <= 32'b0;
        end
        else begin
            out <= ~in & in_1 | out;
        end
    end
    
endmodule

(24)clk双边沿触发Dualedge

You're familiar with flip-flops that are triggered on the positive edge of the clock, or negative edge of the clock. A dual-edge triggered flip-flop is triggered on both edges of the clock. However, FPGAs don't have dual-edge triggered flip-flops, and always @(posedge clk or negedge clk) is not accepted as a legal sensitivity list.

Build a circuit that functionally behaves like a dual-edge triggered flip-flop:

方法一:

module top_module (
    input clk,
    input d,
    output q
);
    reg q_pedge;
    reg q_nedge;

    always @(posedge clk) begin
        q_pedge <= d;
    end
    
    always @(negedge clk) begin
        q_nedge <= d;
    end
    
    assign q = clk?q_pedge:q_nedge;
    
endmodule

方法二:

module top_module (
    input clk,
    input d,
    output q
);
    reg q_d1;
    reg q_d2;
    
    always @(posedge clk) begin
        q_d1 <= d ^ q_d2;
    end
    
    always @(negedge clk) begin
        q_d2 <= d ^ q_d1;
    end
    
    assign q = q_d1 ^ q_d2;
    
endmodule

 (25)计数器Exams/ece241 2014 q7b

From a 1000 Hz clock, derive a 1 Hz signal, called OneHertz, that could be used to drive an Enable signal for a set of hour/minute/second counters to create a digital wall clock. Since we want the clock to count once per second, the OneHertz signal must be asserted for exactly one cycle each second. Build the frequency divider using modulo-10 (BCD) counters and as few other gates as possible. Also output the enable signals from each of the BCD counters you use (c_enable[0] for the fastest counter, c_enable[2] for the slowest).

The following BCD counter is provided for you. Enable must be high for the counter to run. Reset is synchronous and set high to force the counter to zero. All counters in your circuit must directly use the same 1000 Hz signal.

module bcdcount (
	input clk,
	input reset,
	input enable,
	output reg [3:0] Q
);
module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //
    //wire [3:0] q0,q1,q2;
    //assign c_enable[0] = 1'b1;
    //assign c_enable[1] = q0 == 4'd9;
    //assign c_enable[2] = q1 == 4'd9 && q0 == 4'd9;
    //assign OneHertz = q2 == 4'd9 && q1 == 4'd9 && q0 == 4'd9;
    //  bcdcount counter0 (clk, reset, c_enable[0],q0);
   	//	bcdcount counter1 (clk, reset, c_enable[1],q1);
    //	bcdcount counter2 (clk, reset, c_enable[2],q2);
    wire [11:0] q;
    assign c_enable = {q[7:4] == 4'd9 && q[3:0] == 4'd9, q[3:0] == 4'd9 , 1'b1};
    //assign c_enable = {q[7:0] == 8'h99, q[3:0] == 4'd9 , 1'b1};
    assign OneHertz = q[11:8] == 4'd9 && q[7:4] == 4'd9 && q[3:0] == 4'd9;
    //assign OneHertz = q[11:0] == 12'h999;
    bcdcount counter0 (clk, reset, c_enable[0],q[3:0]);
    bcdcount counter1 (clk, reset, c_enable[1],q[7:4]);
    bcdcount counter2 (clk, reset, c_enable[2],q[11:8]);
endmodule

 (26)parameter的使用

(49条消息) Verilog中的parameter_qq_16923717的博客-CSDN博客_parameter verilog

(27)Count clock

Create a set of counters suitable for use as a 12-hour clock (with am/pm indicator). Your counters are clocked by a fast-running clk, with a pulse on ena whenever your clock should increment (i.e., once per second).

reset resets the clock to 12:00 AM. pm is 0 for AM and 1 for PM. hh, mm, and ss are two BCD (Binary-Coded Decimal) digits each for hours (01-12), minutes (00-59), and seconds (00-59). Reset has higher priority than enable, and can occur even when not enabled.

The following timing diagram shows the rollover behaviour from 11:59:59 AM to 12:00:00 PM and the synchronous reset and enable behaviour.

module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 

    wire [1:0] ena_ss;
    wire [1:0] ena_mm;
    wire ena_hh_r;
    wire [7:0] hh_r;
    
    assign ena_ss[0] = ena && (ss[3:0] == 4'h9);
    assign ena_ss[1] = ena_ss[0] && (ss[7:4] == 4'h5);
    assign ena_mm[0] = ena_ss[1] && (mm[3:0] == 4'h9);
    assign ena_mm[1] = ena_mm[0] && (mm[7:4] == 4'h5);
    assign ena_hh_r = ena_mm[1] && (hh_r[3:0] == 4'hb);

    BCD_count #(.START(4'h0),.END(4'h9)) ss9 (clk,reset,ena,ss[3:0]);
    BCD_count #(.START(4'h0),.END(4'h5)) ss5 (clk,reset,ena_ss[0],ss[7:4]);
    
    BCD_count #(.START(4'h0),.END(4'h9)) mm9 (clk,reset,ena_ss[1],mm[3:0]);
    BCD_count #(.START(4'h0),.END(4'h5)) mm5 (clk,reset,ena_mm[0],mm[7:4]);
    
    BCD_count #(.START(4'h0),.END(4'hb)) hhb (clk,reset,ena_mm[1],hh_r[3:0]);
    BCD_count #(.START(4'h0),.END(4'h1)) hh1 (clk,reset,ena_hh_r,hh_r[7:4]);
    
    assign pm = (hh_r[7:4] == 4'h1);
    assign hh[7:0] = (hh_r[3:0] == 4'h0) ? 8'h12 : ((hh_r[3:0] > 4'h9) ? {4'h1,hh_r[3:0] - 4'ha}:{4'h0,hh_r[3:0]});
    
endmodule

module BCD_count (input clk,
                  input reset,
                  input ena,
                  output reg [3:0] q);
    
    parameter START = 4'h0, END = 4'h9;
    always @(posedge clk) begin
        if (reset)
            q <= START;
        else if (ena)
            q <= (q == END) ? START:q + 4'h1;
        else
            q <= q;
    end
    
endmodule

 方法二:

module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    always @(posedge clk) begin
            if (reset) begin
                pm <= 1'h0;
                ss[7:0] <= 8'h0;
                mm[7:0] <= 8'h0;
                hh[7:0] <= 8'h12;
            end
            else if (ena) begin
                if (ss[3:0] != 4'h9) begin
                    ss[3:0] <= ss[3:0] + 4'h1;
                end
                else begin
                    ss[3:0] <= 4'h0;
                    ss[7:4] <= ss[7:4] + 4'h1;
                    if (ss[7:4] == 4'h5) begin
                        ss[7:4] <= 4'h0;
                        mm[3:0] <= mm[3:0] + 4'h1;
                        if (mm[3:0] == 4'h9) begin
                            mm[3:0] <= 4'h0;
                            mm[7:4] <= mm[7:4] + 4'h1;
                            if (mm[7:4] == 4'h5) begin
                                mm[7:4] <= 4'h0;
                                hh[3:0] <= hh[3:0] + 4'h1;
                                if (hh[3:0] == 4'h9) begin
                                    hh[3:0] = 4'h0;
                                    hh[7:4] <= hh[7:4] + 4'h1;
                                end
                                if (hh[7:4] == 4'h1 && hh[3:0] == 4'h1) begin
                                    pm <= ~pm;
                                    hh[3:0] <= hh[3:0] + 4'h1;
                                end
                                if (hh[7:4] == 4'h1 && hh[3:0] == 4'h2) begin
                                    hh[7:0] <= {4'h0,4'h1};
                                end
                            end
                        end
                    end
                end
            end
    end
                    
endmodule

 注意:在

  if (mm[7:4] == 4'h5) begin
                                mm[7:4] <= 4'h0;
                                hh[3:0] <= hh[3:0] + 4'h1;
                                if (hh[3:0] == 4'h9) begin
                                    hh[3:0] = 4'h0;
                                    hh[7:4] <= hh[7:4] + 4'h1;
                                end
                                if (hh[7:4] == 4'h1 && hh[3:0] == 4'h1) begin
                                    pm <= ~pm;
                                    hh[3:0] <= hh[3:0] + 4'h1;
                                end
                                if (hh[7:4] == 4'h1 && hh[3:0] == 4'h2) begin
                                    hh[7:0] <= {4'h0,4'h1};
                                end
                            end

 处,如果之前reset过,那么hh[7:0] = 8'h12,在红线处hh[3:0]加4'h1,那么进入下面if判断时hh[7:0] = 8'h13,使得hh[7:0]输出13,14,15等等,为什么不是这样?

因为hh[3:0] <= hh[3:0] + 4'h1;为非阻塞赋值,虽然进入if判断之前已经做了加法,但其输出要到下一个敏感表才生效,进入if判断的仍是原来的值。

关于非阻塞赋值和begin end块的问题 - FPGA/ASIC/IC前端设计 - EETOP 创芯网论坛 (原名:电子顶级开发网) -

方法二更新版本:

module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    always @(posedge clk) begin
            if (reset) begin
                pm <= 1'h0;
                ss[7:0] <= 8'h0;
                mm[7:0] <= 8'h0;
                hh[7:0] <= 8'h12;
            end
            else if (ena) begin
                if (ss[3:0] == 4'h9) begin
                    ss[3:0] <= 4'h0;  
                    if (ss[7:4] == 4'h5) begin
                        ss[7:4] <= 4'h0;
                        if (mm[3:0] == 4'h9) begin
                            mm[3:0] <= 4'h0;
                            if (mm[7:4] == 4'h5) begin
                                mm[7:4] <= 4'h0;
                                if (hh[3:0] == 4'h9) begin
                                    hh[3:0] = 4'h0;
                                    hh[7:4] <= hh[7:4] + 4'h1;
                                end
                                else if (hh[7:4] == 4'h1 && hh[3:0] == 4'h1) begin
                                    pm <= ~pm;
                                    hh[3:0] <= hh[3:0] + 4'h1;
                                end
                                else if (hh[7:4] == 4'h1 && hh[3:0] == 4'h2) begin
                                    hh[7:0] <= {4'h0,4'h1};
                                end
                                else
                                    hh[3:0] <= hh[3:0] + 4'h1;
                            end
                            else
                                mm[7:4] <= mm[7:4] + 4'h1;
                        end
                        else
                            mm[3:0] <= mm[3:0] + 4'h1;
                    end
                    else ss[7:4] = ss[7:4] + 4'h1;
                end 
                else 
                    ss[3:0] <= ss[3:0] + 4'h1;
            end
    end
endmodule  

(28)Exams/ece241 2013 q12

module top_module (
    input clk,
    input enable,
    input S,
    input A, B, C,
    output Z ); 
	
    reg [7:0] Q;
    
    always @(posedge clk) begin
        if (enable) begin
            Q <= {Q[6:0],S};
        end
        //case({A,B,C})
            //3'b000: Z = Q[0];
            //3'b001: Z = Q[1];
            //3'b010: Z = Q[2];
            //3'b011: Z = Q[3];
            //3'b100: Z = Q[4];
            //3'b101: Z = Q[5];
            //3'b110: Z = Q[6];
            //3'b111: Z = Q[7];
        //endcase
    end
    assign Z = Q[{A,B,C}];            
endmodule

如果用注释里的代码如上图所示输出会落后一个时钟周期,因为它是时序逻辑的,触发条件为时钟上升沿,而连续赋值语句是组合逻辑的。

根据题目所示,这是三输入查找表,所以此多路复用器也应该是组合逻辑的,而不是时序的。

  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值