目录(点击题目直达)

0 引言

  最近通过HDLBits学习verilog,写下此文记录下学习过程和一些心得,文中不对之处请各位批评指正。此文仅为3 Circuits一章题目,更多题目请见:
【HDLBits答案及思路(仅供参考,1 Getting Started与2 Verilog Language)】
【HDLBits答案及思路(仅供参考,4 Verification: Reading Simulations与5 Verification: Writing Testbenches)(暂未更新)】
  所有代码都通过了HDLBits网站验证,但是可能在写文修改格式时出现一些问题,所以发现有不正确之处,请联系我修改。同时,我的方法不一定是最优解决方案,仅供参考,如果朋友有更好的解决思路,也希望能够不吝赐教。注:HDLBits中模块端口声明并没有指定数据类型,我也不打算修改。
  文中括号外标题对应于HDLBits首页中的标题,括号内的标题对应于具体题目左上角的标题,如● Getting Started (Step one),Getting Started是进入主页面后看到的标题,Step one是做题时左上角显示的标题。

3 Circuits

3.1 Combinational Logic

3.1.1 Basic Gates

● Wire (Exams/m2014 q4h)
module top_module (
    input in,
    output out);
    
	assign out=in;
endmodule
● GND (Exams/m2014 q4i)
module top_module (
    output out);
    
	assign out=1'b0;
endmodule
● NOR (Exams/m2014 q4e)
module top_module (
    input in1,
    input in2,
    output out);
    
	assign out=~(in1 | in2);
endmodule
● Another gate (Exams/m2014 q4f)
module top_module (
    input in1,
    input in2,
    output out);
    
	assign out=in1 & ~in2;
endmodule
● Two gates (Exams/m2014 q4g)
module top_module (
    input in1,
    input in2,
    input in3,
    output out);
    
	assign out=(~(in1^in2))^in3;
endmodule
● More logic gates (Gates)
module top_module( 
    input a, b,
    output out_and,
    output out_or,
    output out_xor,
    output out_nand,
    output out_nor,
    output out_xnor,
    output out_anotb
);

	assign out_and=a&b;
	assign out_or=a|b;
	assign out_xor=a^b;
	assign out_nand=~(a&b);
	assign out_nor=~(a|b);
	assign out_xnor=~(a^b);
	assign out_anotb=a&~b;
endmodule
● 7420 chip (7420)
module top_module ( 
    input p1a, p1b, p1c, p1d,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
    
	assign p1y=~(p1a & p1b & p1c & p1d);
	assign p2y=~(p2a & p2b & p2c & p2d);
endmodule
● Truth tables (Truthtable1)
module top_module( 
    input x3,
    input x2,
    input x1,  // three inputs
    output f   // one output
);

	assign f= ~x3&x2&~x1 | ~x3&x2&x1 | x3&~x2&x1 | x3&x2&x1;
endmodule
● Two-bit equality (Mt2015 eq2)
module top_module (
    input [1:0] A,
    input [1:0] B,
    output z ); 
    
	assign z=(A==B)?1'b1:1'b0;
endmodule
● Simple circuit A (Mt2015 q4a)
module top_module (
    input x,
    input y,
    output z);
    
	assign z=(x^y)&x;
endmodule
● Simple circuit B (Mt2015 q4b)
module top_module (
    input x,
    input y,
    output z );
    
	assign z=~(x^y);
endmodule
● Combine circuits A and B (Mt2015 q4)
module top_module (
    input x,
    input y,
    output z);
    
    //A电路为(x^y)&x
    //B电路为~(x^y)
	assign z=(((x^y)&x)|(~(x^y))) ^ (((x^y)&x)&(~(x^y)));
endmodule

注:A电路为(x^y)&x,B电路为~(x^y)

● Ring or vibrate? (Ringer)
module top_module (
    input ring,
    input vibrate_mode,
    output ringer,       // Make sound
    output motor         // Vibrate
);

	assign motor=vibrate_mode & ring;
	assign ringer=~vibrate_mode & ring;
endmodule

注:verilog为硬件语言,其代码思路应该是从输出到输入(输出在输入为何种情况才成立,即等于1),而非软件编程的输入到输出(输入为A时输出是什么)。

● Thermostat (Thermostat)
module top_module (
    input too_cold,
    input too_hot,
    input mode,
    input fan_on,
    output heater,
    output aircon,
    output fan
); 

	assign heater=(mode==1&&too_cold==1)?1'b1:1'b0;
	assign aircon=(mode==0&&too_hot==1)?1'b1:1'b0;
	assign fan=(heater==1||aircon==1||fan_on==1)?1'b1:1'b0;
endmodule
● 3-bit population count (Popcount3)
module top_module( 
    input [2:0] in,
    output [1:0] out );
    
	integer i;
	always@(*)begin
    	out=2'b0;
    	for(i=0;i<3;i=i+1)begin
        	out=in[i]==1?out+1'b1:out;
    	end
	end
endmodule
● Gates and vectors (Gatesv)
module top_module( 
    input [3:0] in,
    output [2:0] out_both,
    output [3:1] out_any,
    output [3:0] out_different );
    
	assign out_both=in[2:0] & in[3:1];
	assign out_any=in[3:1] | in[2:0];
	assign out_different=in[3:0] ^ {in[0],in[3:1]};
endmodule
● Even longer vectors (Gatesv100)
module top_module( 
    input [99:0] in,
    output [98:0] out_both,
    output [99:1] out_any,
    output [99:0] out_different );
    
	assign out_both=in[98:0] & in[99:1];
	assign out_any=in[99:1] | in[98:0];
	assign out_different=in[99:0] ^ {in[0],in[99:1]};
endmodule

3.1.2 Multiplexers

● 2-to-1 multiplexer (Mux2to1)
module top_module( 
    input a, b, sel,
    output out ); 
    
	assign out=sel==0?a:b;
endmodule
● 2-to-1 bus multiplexer (Mux2to1v)
module top_module( 
    input [99:0] a, b,
    input sel,
    output [99:0] out );
    
	assign out=sel==0?a:b;
endmodule
● 9-to-1 multiplexer (Mux9to1v)
module top_module( 
    input [15:0] a, b, c, d, e, f, g, h, i,
    input [3:0] sel,
    output [15:0] out );
    
	always@(*)begin
	    case(sel)
	        4'd0:out=a;
	        4'd1:out=b;
	        4'd2:out=c;
	        4'd3:out=d;
	        4'd4:out=e;
	        4'd5:out=f;
	        4'd6:out=g;
	        4'd7:out=h;
	        4'd8:out=i;
	        default:out=16'hffff;
	    endcase
	end
endmodule
● 256-to-1 multiplexer (Mux256to1)
module top_module( 
    input [255:0] in,
    input [7:0] sel,
    output out );
    
	assign out=in[sel];
endmodule
● 256-to-1 4-bit multiplexer (Mux256to1v)
module top_module( 
    input [1023:0] in,
    input [7:0] sel,
    output [3:0] out );
    
	/*//方法一:索引偏移
	assign out=in[sel*4+3-:4];*/
	//方法二:移位(有截断warning)
	assign out=in>>sel*4;
endmodule

注:assign中不能使用[sel*4+3:sel*4]进行索引赋值,因为此时selwire类型,不是定值。应该使用[sel*4+3-:4]索引,表示从sel*4+3位开始,向右数4位为止。

3.1.3 Arithmetic Circuits

● Half adder (Hadd)
module top_module( 
    input a, b,
    output cout, sum );
    
	assign {cout,sum}=a+b;
endmodule
● Full adder (Fadd)
module top_module( 
    input a, b, cin,
    output cout, sum );
    
	assign {cout,sum}=a+b+cin;
endmodule
● 3-bit binary adder (Adder3)
module top_module( 
    input [2:0] a, b,
    input cin,
    output [2:0] cout,
    output [2:0] sum );
    
	always@(*)begin
	    integer i;
	    for(i=0;i<3;i=i+1)begin
	        if(i==0)begin
	            {cout[i],sum[i]}=a[i]+b[i]+cin;
	        end else begin
	            {cout[i],sum[i]}=a[i]+b[i]+cout[i-1];
	        end
	    end
	end
endmodule
● Adder (Exams/m2014 q4j)
module top_module (
    input [3:0] x,
    input [3:0] y, 
    output [4:0] sum);
    
    wire [3:0]cout;
	fa fa_inst[3:0](
	    .a(x),
	    .b(y),
	    .cin({cout[2:0],1'b0}),
	    .cout(cout[3:0]),
	    .sum(sum[3:0]));
	assign sum[4]=cout[3];
	endmodule
	
	module fa(
	    input a,b,cin,
	    output cout,sum);
	    assign{cout,sum}=a+b+cin;
endmodule

注:当然也可以用generate-for循环写。

● Signed addition overflow (Exams/ece241 2014 q1c)
module top_module (
    input [7:0] a,
    input [7:0] b,
    output [7:0] s,
    output overflow
); 
    
	assign s=a+b;
	assign overflow=(a[7]^b[7]==0 && s[7]==~a[7])?1'b1:1'b0;
endmodule

注:加法溢出只会发生在a、b同时为正和同时为负的情况,具体说,a、b同时为正而结果为负或者同时为负而结果为正时发生溢出。

● 100-bit binary adder (Adder100)
module top_module( 
    input [99:0] a, b,
    input cin,
    output cout,
    output [99:0] sum );
    
	assign{cout,sum}=a+b+cin;
endmodule
● 4-digit BCD adder (Bcdadd4)
module top_module ( 
    input [15:0] a, b,
    input cin,
    output cout,
    output [15:0] sum );
    
    reg[3:0]cout_t;
	/*//方法一:数组实例化
	bcd_fadd bcd4[3:0](
	    .a(a[15:0]),
	    .b(b[15:0]),
	    .cin({cout_t[2:0],cin}),
	    .cout(cout_t[3:0]),
	    .sum(sum[15:0]));
	assign cout=cout_t[3];*/
	
	//方法二:循环例化generate-for
	genvar i;
	generate
	    for(i=0;i<4;i=i+1)begin:BCD4
	        if(i==0)begin
	            bcd_fadd bcd4(
	    .a(a[3:0]),
	    .b(b[3:0]),
	    .cin(cin),
	    .cout(cout_t[0]),
	    .sum(sum[3:0]));
	        end else begin
	            bcd_fadd bcd4(
	    .a(a[i*4+3-:4]),
	    .b(b[i*4+3-:4]),
	    .cin(cout_t[i-1]),
	    .cout(cout_t[i]),
	    .sum(sum[i*4+3-:4]));
	        end
	    end
	endgenerate
	assign cout=cout_t[3];
endmodule

3.1.4 Karnaugh Map to Circuit

● 3-variable (Kmap1)
module top_module(
    input a,
    input b,
    input c,
    output out  );
    
	/*//方法一:圈1
	assign out=a|b|c;*/
	//方法二:圈0
	assign out=~((~a)&(~b)&(~c));
endmodule

注:卡诺图圈一得最简与或表达式,圈零得最简或与表达式。圈一时1为原变量,0为反变量,如11表示a&b。圈零时0为原变量,1为反变量,如00表示a|b

● 4-variable (Kmap2)
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  ); 
    
	/*//方法一:圈1
	assign out=~b&~c | ~a&~d | a&c&d | b&c&d;*/
	//方法二:圈0
	assign out=(~a|~c|d) & (~a|~b|c) & (~b|~d|c) & (a|b|~c|~d);
endmodule
● 4-variable (Kmap3)
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  ); 
    
	/*//方法一:圈一
    assign out=a | ~b&c;*/
	//方法二:圈0
    assign out=(a|~b) & (c|~d) & (a|c);
endmodule

注:卡诺图中d表示x,也可以直接写作x,画圈时d(或x)可以根据“圈最大”原则当做01

● 4-variable (Kmap4)
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  ); 
    
    /*//方法一:以2/4列和1/3行当做一个整体;以1/3列和2/4行当做一个整体;
    assign out=(a^b)&~(c^d) | ~(a^b)&(c^d);*/
    //方法二:方法一基础上进一步简化
    assign out=(a^b)^(c^d);
endmodule
● Minimum SOP and POS (Exams/ece241 2013 q2)
module top_module (
    input a,
    input b,
    input c,
    input d,
    output out_sop,
    output out_pos
); 

    /*//方法一:圈1,sop (sum of product)
    assign out_sop=c&d | ~a&~b&c;*/
    //方法二:圈0,pos (product of sum)
    assign out_pos=c & (~a|d) & (~b|d);
endmodule

注:卡诺图如下:卡诺图

● Karnaugh map (Exams/m2014 q3)
module top_module (
    input [4:1] x, 
    output f );
    
    /*//方法一:圈1,sop
    assign f=~x[1]&x[3] | x[1]&x[2]&~x[3];*/
    //方法二:圈0,pos
    assign f=(x[1]|x[3]) & (~x[1]|x[2]) & (~x[1]|~x[3]);
endmodule
● Karnaugh map (Exams/2012 q1g)
module top_module (
    input [4:1] x,
    output f
); 
    /*//法一:SOP
    assign f=x[3]&~x[1] | ~x[2]&~x[4] | x[2]&x[3]&x[4];*/
    //法二:POS
    assign f=(~x[2]|x[3]) & (x[3]|~x[4]) & (~x[1]|x[2]|~x[4]) & (~x[1]|~x[2]|x[4]);
endmodule
● K-map implemented with a multiplexer (Exams/ece241 2014 q3)
module top_module (
    input c,
    input d,
    output [3:0] mux_in
); 
    /*//方法一:使用数选器,基于S&D | ~S&C
    //二选一数选器实现或操作
    assign mux_in[0]=d==1?d:c;
    assign mux_in[1]=1'b0;
    assign mux_in[2]=d==0?1'b1:1'b0;
    //二选一数选器实现与操作
    assign mux_in[3]=c==1?d:c;*/
    
    //方法二:使用基础门(圈一)
    assign mux_in[0]=c|d;
    assign mux_in[1]=1'b0;
    assign mux_in[2]=~d;
    assign mux_in[3]=c&d;
endmodule

注:此题重点为如何用二选一数选器实现&|的功能。考虑有一个数选器输出为~SA + SB,即assign out=(S==1)?B:A;。此时将信号AS连接,得到AB;将信号BS连接,得到~BA + B = ~BA + B + BA = A + B

3.2 Sequential Logic

3.2.1 Latches and Flip-Flops

● D flip-flop (Dff)
module top_module (
    input clk,
    input d,
    output reg q );

    always@(posedge clk)begin
        q<=d;
    end
endmodule
● D flip-flops (Dff8)
module top_module (
    input clk,
    input [7:0] d,
    output [7:0] q
);
    
    always@(posedge clk)begin
        q<=d;
    end
endmodule
● DFF with reset (Dff8r)
module top_module (
    input wire clk,
    input wire reset,
    input wire[7:0] d,
    output reg[7:0] q
);
    
    always@(posedge clk)begin
        q<=reset==1?1'b0:d;
    end
endmodule

注:同步复位(synchronous reset):复位信号不作为敏感列表always@(posedge clk);异步复位(asynchronous reset):复位信号作为敏感列表always@(posedge clk or posedge reset)

● DFF with reset value (Dff8p)
module top_module (
    input clk,
    input reset,
    input [7:0] d,
    output [7:0] q
);

    always@(negedge clk)begin
        q<=reset==1?8'h34:d;
    end
endmodule
● DFF with asynchronous reset (Dff8ar)
module top_module (
    input clk,
    input areset,   // active high asynchronous reset
    input [7:0] d,
    output [7:0] q
);

    always@(posedge clk or posedge areset)begin
        q<=areset==1?8'd0:d;
    end
endmodule
● DFF with byte enable (Dff16e)
module top_module (
    input clk,
    input resetn,
    input [1:0] byteena,
    input [15:0] d,
    output [15:0] q
);

    always@(posedge clk)begin
        if(resetn==0)begin
            q<=16'd0;
        end else begin
            case(byteena)
                2'b10:q<={d[15:8],q[7:0]};
                2'b01:q<={q[15:8],d[7:0]};
                2'b11:q<={d[15:8],d[7:0]};
                default:q<=q;
            endcase
        end
    end
endmodule

注:byteena[1]控制输入数据d的高八位,byteena[0]控制输入数据d的低八位,未被控制部分保持输出

● D Latch (Exams/m2014 q4a)
module top_module (
    input d, 
    input ena,
    output q);

    always@(*)begin
        q<=ena==1?d:q;
    end
endmodule

注:1)锁存器是电平敏感,不是边沿敏感;2)锁存器虽然是电平敏感,但是是时序电路,用非阻塞赋值<=

● DFF (Exams/m2014 q4b)
module top_module (
    input clk,
    input d, 
    input ar,   // asynchronous reset
    output q);

    always@(posedge clk or posedge ar)begin
        q<=ar==1?1'b0:d;
    end
endmodule
● DFF (Exams/m2014 q4c)
module top_module (
    input clk,
    input d, 
    input r,   // synchronous reset
    output q);

    always@(posedge clk)begin
        q<=r==1?1'b0:d;
    end
endmodule
● DFF+gate (Exams/m2014 q4d)
module top_module (
    input clk,
    input in, 
    output out);

    always@(posedge clk)begin
        out<=in^out;
    end
endmodule
● Mux and DFF (Mt2015 muxdff)
module top_module (
	input clk,
	input L,
	input r_in,
	input q_in,
	output reg Q);

    always@(posedge clk)begin
        Q<=L==1?r_in:q_in;
    end
endmodule

注:此题仅需要描述一级电路即可,如图红框。Mux and DFF

● Mux and DFF (Exams/2014 q4a)
module top_module (
    input clk,
    input w, R, E, L,
    output Q
);
    always@(posedge clk)begin
        Q<=L==1?R:(E==1?w:Q);
    end
endmodule

注:此题仅需要描述一级电路即可,如图红框。
Mux and DFF

● DFFs and gates (Exams/ece241 2014 q4)
module top_module (
    input clk,
    input x,
    output z
); 
    
    wire q1,q2,q3;
    always@(posedge clk)begin
        q1 <= x^q1;
        q2 <= x&~q2;
        q3 <= x|~q3;
    end
    
    assign z = ~(q1|q2|q3);
    
endmodule
● Create circuit from truth table (Exams/ece241 2013 q7)
module top_module (
    input clk,
    input j,
    input k,
    output Q); 
    
    always@(posedge clk)begin
        Q<=j&~k | ~(j|k)&Q | (j&k)&~Q;
    end
endmodule

注:电路连接示意图:电路连接图

● Detect an edge (Edgedetect)
module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    
    integer i;
    reg [7:0]in_copy;
    always@(posedge clk)begin
        in_copy<=in;
        for(i=0;i<8;i=i+1)begin
            pedge[i]<=(in[i]==1&&in_copy[i]==0)?1'b1:1'b0;
        end
    end
endmodule

注:输入信号的上升沿检测,in_copy用于保存前一时钟的输入值,in为当前时钟的输入值。非阻塞赋值。

● Detect both edges (Edgedetect2)
module top_module (
    input clk,
    input [7:0] in,
    output [7:0] anyedge
);
    
    integer i;
    reg [7:0]in_copy;
    always@(posedge clk)begin
        in_copy<=in;
        for(i=0;i<8;i=i+1)begin
            anyedge[i]<=in[i]^in_copy[i]==1?1'b1:1'b0;
        end
    end
endmodule

注:输入信号的任意边沿检测。

● Edge capture register (Edgecapture)
module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    
    integer i;
    reg [31:0]in_copy;
    always@(posedge clk)begin
    	//in_copy<=in; //放在此处或最后一行均可
        if(reset)begin
            out<=0;
        end else begin
            for(i=0;i<32;i=i+1)begin
                out[i]<=in[i]==0&&in_copy[i]==1?1'b1:out[i];
            end
        end
        in_copy<=in; //放在第一行或此处均可,因为是非阻塞赋值
    end
endmodule

注:带复位的输入信号下降沿检测。注意题目中"Capture" 表示检测到下降沿后一直为1,直到出现复位信号。in_copy<=in;放在always块的第一行或最后一行均可,因为是非阻塞赋值,只是放在最后一行更符合人的思维习惯。

● Dual-edge triggered flip-flop (Dualedge)
module top_module (
    input clk,
    input d,
    output q
);
    
    /*//法一:有毛刺
    reg q1,q2;
    always@(posedge clk)begin
        q1<=d;
    end
    always@(negedge clk)begin
        q2<=d;
    end
    assign q=clk==1?q1:q2;*/
    //法二:无毛刺
    reg q1,q2;
    always@(posedge clk)begin
        q1<=d^q2;
    end
    always@(negedge clk)begin
        q2<=d^q1;
    end
    assign q=q1^q2;
endmodule

注:双边沿检测。always@(posedge clk or negedge clk)不允许的。方法一利用时钟信号值判断上下沿,可能存在毛刺,参考博客;方法二巧妙利用了异或的特性,不存在毛刺,参考博客,上升沿时:q=q1^q2=(d^q2)^q2=d,下降沿时:q=q1^q2=q1^(d^q1)=d

3.2.2 Counters

● Four-bit binary counter (Count15)
module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);
	
    always@(posedge clk)begin
        q <= reset==1?4'd0:q+1'b1;
    end
endmodule
● Decade counter (Count10)
module top_module (
    input clk,
    input reset,        // Synchronous active-high reset
    output [3:0] q);
	
    /*//方法一:三目运算符
    always@(posedge clk)begin
    	q <= reset==1||q==4'd9 ? 4'd0 : q+1'b1;
    end*/
    //方法二:if-else结构
    always@(posedge clk)begin
        if(reset)begin
    		q <= 4'd0;
        end else begin
            if(q==4'd9)begin
                q <= 4'd0;
            end else begin
                q <= q + 1'b1;
            end
        end
    end
endmodule

注:0-9计数。

● Decade counter again (Count1to10)
module top_module (
    input clk,
    input reset,
    output [3:0] q);
    
    always@(posedge clk)begin
        q<=reset==1||q==10?4'd1:q+1'b1;
    end
endmodule

注:1-10计数。

● Slow decade counter (Countslow)
module top_module (
    input clk,
    input slowena,
    input reset,
    output [3:0] q);
    
    always@(posedge clk)begin
        if(reset)begin
            q<=4'd0;
        end else begin
            if(slowena && q==9)begin
                q<=4'd0;
            end else if(slowena) begin
                q<=q+1'b1;
            end else begin
                q<=q;
            end
        end
    end
endmodule

注:带控制和复位的0-9计数。

● Counter 1-12 (Exams/ece241 2014 q7a)
module top_module (
    input clk,
    input reset,
    input enable,
    output [3:0] Q,
    output c_enable,
    output c_load,
    output [3:0] c_d
);
    
    always@(*)begin
        if(reset)begin
            c_d<=4'd1;
            c_load<=1'b1;
        end else begin
            if(enable && Q==4'd12)begin
                c_d<=4'd1;
                c_load<=1'b1;
            end else begin
                c_d<=c_d; //此种写法有latch警告
                //c_d<=1'b0; //也可赋0
                c_load<=1'b0;
            end
        end
    end
    assign c_enable=enable;
    count4 count4_inst (
        .clk(clk),
        .enable(c_enable),
        .load(c_load),
        .d(c_d),
        .Q(Q));
endmodule

注:此题主要是要理解题目意图,题目的意思是用c_enable, c_load, c_d[3:0]信号去控制四位二进制计数器count4c_enable控制count4的使能enable c_load控制数据输入count4 c_d[3:0]控制输入count4的数据。参考博客

● Counter 1000 (Exams/ece241 2014 q7b)
module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
);
    wire [3:0]q0,q1,q2;
    
    bcdcount counter0 (
        .clk(clk),
        .reset(reset),
        .enable(c_enable[0]),
        .Q(q0));
    bcdcount counter1 (
        .clk(clk),
        .reset(reset),
        .enable(c_enable[1]),
        .Q(q1));
    bcdcount counter2 (
        .clk(clk),
        .reset(reset),
        .enable(c_enable[2]),
        .Q(q2));
    assign c_enable[0]=reset?1'b0:1'b1;
    assign c_enable[1]=q0[3]&q0[0];
    assign c_enable[2]=q1[3]&q1[0] & q0[3]&q0[0];
    assign OneHertz = q2[3]&q2[0] & q1[3]&q1[0] & q0[3]&q0[0];
endmodule

注:每级计数器每计数十次向前进位一次。

● 4-digit decimal counter (Countbcd)
module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    
    //同步电路写法
    wire [3:0] qcarry;
    wire ena_4;
    assign qcarry[0]=q[3]&q[0];
    assign qcarry[1]=q[7]&q[4];
    assign qcarry[2]=q[11]&q[8];
    assign qcarry[3]=q[15]&q[12];

    assign ena[1]=qcarry[0];
    assign ena[2]=qcarry[0] & qcarry[1];
    assign ena[3]=qcarry[0] & qcarry[1] & qcarry[2];
    assign ena_4=qcarry[0] & qcarry[1] & qcarry[2] & qcarry[3];
    
    always@(posedge clk)begin
        if(reset | ena[1])begin
            q[3:0]<=4'd0;
        end else begin
            q[3:0]<=q[3:0]+1'b1;
        end
    end
    
    always@(posedge clk)begin
        if(reset | ena[2])begin
            q[7:4]<=4'd0;
        end else if(ena[1])begin
            q[7:4]<=q[7:4]+1'b1;
        end else begin
            q[7:4]<=q[7:4];
        end
    end
    
    always@(posedge clk)begin
        if(reset | ena[3])begin
            q[11:8]<=4'd0;
        end else if(ena[2])begin
            q[11:8]<=q[11:8]+1'b1;
        end else begin
            q[11:8]<=q[11:8];
        end
    end
    
    always@(posedge clk)begin
        if(reset | ena_4)begin
            q[15:12]<=4'd0;
        end else if(ena[3])begin
            q[15:12]<=q[15:12]+1'b1;
        end else begin
            q[15:12]<=q[15:12];
        end
    end
endmodule

注:此处采用同步连接的方式,应该也可以采用异步连接方式(此处未给出,有兴趣可以思考讨论)。我用异步连接方式描述该电路时遇到的问题:1、复位时异步电路立即复位导致验证不通过;2、为了解决异步复位的问题,使用异步复位同步释放结构,随之而来的新问题是整个电路输出延后了两拍(周期)。异步复位同步释放参考博客。下图为同步连接电路图(字丑见谅)。
同步连接电路图

● 12-hour clock (Count clock)
module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    //同步电路写法
    wire hh_l,hh_h,mm_l,mm_h,ss_l,ss_h,hh_pm;
    assign ss_l=ss[3]&ss[0];         //每xx:xx:x9
    assign ss_h=ss[6]&ss[4] & ss_l;  //每xx:xx:59
    assign mm_l=mm[3]&mm[0] & ss_h;  //每xx:x9:59
    assign mm_h=mm[6]&mm[4] & mm_l;  //每xx:59:59
    assign hh_l=hh[3]&hh[0] & mm_h;  //每x9:59:59
    assign hh_h=hh[4]&hh[1] & mm_h;  //每12:59:59
    assign hh_pm=hh[4]&hh[0] & mm_h; //每11:59:59
    
    always@(posedge clk)begin
        if(reset)begin
            ss<=8'h00;
        end else if(ena)begin
            if(ss_h)begin
                ss<=8'h00; //每59秒准备清零
            end else if(ss_l)begin
                ss<={ss[7:4]+1'b1,4'h0}; //每9秒准备进位
            end else begin
                ss<={ss[7:4],ss[3:0]+1'b1}; //每秒准备加一
            end
        end else begin
            ss<=ss;
        end
    end//秒
    
    always@(posedge clk)begin
        if(reset)begin
            mm<=8'h00;
        end else if(ena)begin
            if(mm_h)begin
                mm<=8'h00; //每59分59秒准备清零
            end else if(mm_l)begin
                mm<={mm[7:4]+1'b1,4'h0}; //每9分59秒准备进位
            end else if(ss_h)begin
                mm<={mm[7:4],mm[3:0]+1'b1}; //每59秒准备加一分
            end else begin
                mm<=mm;
            end
        end else begin
            mm<=mm;
        end
    end//分
    
    always@(posedge clk)begin
        if(reset)begin
            hh<=8'h12;
        end else if(ena)begin
            if(hh_h)begin
                hh<=8'h01; //每12时59分59秒时准备“清零”
            end else if(hh_l)begin
                hh<={hh[7:4]+1'b1,4'h0}; //每9时59分59秒准备进位
            end else if(mm_h)begin
                hh<={hh[7:4],hh[3:0]+1'b1}; //每59分59秒加一时
            end else begin
                hh<=hh;
            end
        end else begin
            hh<=hh;
        end
    end//时
    
    always@(posedge clk)begin
        if(reset)begin
            pm<=1'b0;
        end else if(ena)begin
            if(hh_pm)begin
                pm<=~pm; //每11时59分59秒PM指示翻转
            end else begin
                pm<=pm;
            end
        end else begin
            pm<=pm;
        end
    end//PM指示
endmodule

注:准确把握何时复位、进位即可,同样采用的是同步连接方式。问题:可以用异步连接实现吗?

3.2.3 Shift Registers

● 4-bit shift register (Shift4)
module top_module(
    input clk,
    input areset,  // async active-high reset to zero
    input load,
    input ena,
    input [3:0] data,
    output reg [3:0] q); 
	
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            q<=4'd0;
        end else if(load)begin
            q<=data;
        end else if(ena)begin
            q<=q>>1;
        end else begin
            q<=q;
        end
    end
endmodule
● Left/right rotator (Rotate100)
module top_module(
    input clk,
    input load,
    input [1:0] ena,
    input [99:0] data,
    output reg [99:0] q); 
	
    always@(posedge clk)begin
        if(load)begin
            q<=data;
        end else begin
            case(ena)
            	2'b00:q<=q;
                2'b01:q<={q[0],q[99:1]};
                2'b10:q<={q[98:0],q[99]};
            	2'b11:q<=q;
            	default:q<=q;
        	endcase
        end
    end
endmodule
● Left/right arithmetic shift by 1 or 8 (Shift18)
module top_module(
    input clk,
    input load,
    input ena,
    input [1:0] amount,
    input [63:0] data,
    output reg [63:0] q); 
	
    //位操作写法
    always@(posedge clk)begin
        if(load)begin
            q<=data;
        end else if(ena)begin
            case(amount)
                2'b00:q<={q[63-1:0],{1{1'b0}}}; //左移,与逻辑左移相同
                2'b01:q<={q[63-8:0],{8{1'b0}}};
                2'b10:q<={q[63],{1{q[63]}},q[62:0+1]}; //右移,符号位不变,空余位补符号位
                2'b11:q<={q[63],{8{q[63]}},q[62:0+8]};
                default:q<=q;
            endcase
        end else begin
            q<=q;
        end
    end
endmodule

注:算术右移方法:符号位不变,右移n位空出来的位用符号位补充。例如:1000_1101右移2位为1110_0011

● 5-bit LFSR (Lfsr5)
module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 5'h1
    output [4:0] q
); 
    
    always@(posedge clk)begin
        if(reset)begin
            q<=5'd1;
        end else begin
            q[4]<=q[0]^1'b0;
            q[3]<=q[4];
            q[2]<=q[3]^q[0];
            q[1]<=q[2];
            q[0]<=q[1];
        end
    end
endmodule

注:线性反馈移位寄存器(Linear Feedback Shift Register, LFSR)的反馈函数为异或网络,参与异或的位称为抽头(tap)。n位(级)的LFSR共产生2^n-1个状态,不包含的状态为全零态。

● 3-bit LFSR (Mt2015 lfsr)
module top_module (
	input [2:0] SW,      // R
	input [1:0] KEY,     // L and clk
	output [2:0] LEDR);  // Q
    
    always@(posedge KEY[0])begin
        LEDR[0]<=KEY[1]==1?SW[0]:LEDR[2];
        LEDR[1]<=KEY[1]==1?SW[1]:LEDR[0];
        LEDR[2]<=KEY[1]==1?SW[2]:LEDR[1]^LEDR[2];
    end
endmodule
● 32-bit LFSR (Lfsr32)
module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 32'h1
    output [31:0] q
); 
    
    integer i;
    always@(posedge clk)begin
        if(reset)begin
            q<=32'd1;
        end else begin
            for(i=0;i<32;i=i+1)begin
                if(i==31)begin
                    q[i]<=q[0]^1'b0;
                end else if(i==0 || i==1 || i==21) begin
                    q[i]<=q[i+1]^q[0];
                end else begin
                    q[i]<=q[i+1];
                end
            end
        end
    end
endmodule

注:线性反馈移位寄存器的反馈从最左端(MSB)输入。问题:为什么以下写法是错误的?错误信息:索引32超出范围。

///错误写法///
module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 32'h1
    output [31:0] q
); 
    
    reg [7:0]i;
    always@(posedge clk)begin
        if(reset)begin
            q<=32'd1;
        end else begin
            for(i=8'd0;i<8'd32;i=i+1'd1)begin
                case(i)
                    8'd0 :q[i]<=q[i+1]^q[0];
                    8'd1 :q[i]<=q[i+1]^q[0];
                    8'd21:q[i]<=q[i+1]^q[0];
                    8'd31:q[i]<=q[0]^1'b0;
                    default:q[i]<=q[i+1];
                endcase
            end
        end
    end
endmodule
///错误写法///
● Shift register (Exams/m2014 q4k)
module top_module (
    input clk,
    input resetn,   // synchronous reset
    input in,
    output out);
	
    wire [2:0]q;
    always@(posedge clk)begin
        if(!resetn)begin
            out<=1'b0;
            q<=3'd0;
        end else begin
            q[2]<=in;
            q[1]<=q[2];
            q[0]<=q[1];
            out<=q[0];
        end
    end
endmodule
● Shift register (Exams/2014 q4b)
module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
);
    
	/*//方法一:generate-for结构
    genvar i;
    generate
        for(i=0;i<4;i=i+1)begin:ShiftReg4
            if(i==3)begin
            	MUXDFF MUXDFF_inst(
                	.clk(KEY[0]),
                	.E(KEY[1]),
                	.L(KEY[2]),
                	.w(KEY[3]),
                	.R(SW[i]),
                	.Q(LEDR[i]));
            end else begin
                MUXDFF MUXDFF_inst(
                	.clk(KEY[0]),
                	.E(KEY[1]),
                	.L(KEY[2]),
                    .w(LEDR[i+1]),
                	.R(SW[i]),
                	.Q(LEDR[i]));
            end
        end
    endgenerate*/
    
    //方法二:数组实例化
    MUXDFF MUXDFF_inst[3:0](
        .clk({4{KEY[0]}}),
        .E({4{KEY[1]}}),
        .L({4{KEY[2]}}),
        .w({KEY[3],LEDR[3:1]}),
        .R(SW),
    	.Q(LEDR));
endmodule

module MUXDFF (
    input w,E,R,L,clk,
	output Q);
	
    always@(posedge clk)begin
    	Q<=L==1?R:(E==1?w:Q);
    end
endmodule
● 3-input LUT (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[7]<=Q[6];
            Q[6]<=Q[5];
            Q[5]<=Q[4];
            Q[4]<=Q[3];
            Q[3]<=Q[2];
            Q[2]<=Q[1];
            Q[1]<=Q[0];
            Q[0]<=S;
        end else begin
            Q<=Q;
        end
    end
    
    always@(*)begin
        case({A,B,C})
            3'd0:Z=Q[0];
            3'd1:Z=Q[1];
            3'd2:Z=Q[2];
            3'd3:Z=Q[3];
            3'd4:Z=Q[4];
            3'd5:Z=Q[5];
            3'd6:Z=Q[6];
            3'd7:Z=Q[7];
        endcase
    end
endmodule

3.2.4 More Circuits

● Rule 90 (Rule90)
module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 
    
    integer i;
    always@(posedge clk)begin
        if(load)begin
            q<=data;
        end else begin
            for(i=0;i<512;i=i+1)begin
                if(i==0)begin
                    q[i]<=1'b0^q[i+1];
                end else if(i==511)begin
                    q[i]<=q[i-1]^1'b0;
                end else begin
                    q[i]<=q[i-1]^q[i+1];
                end
            end
        end
    end
endmodule

注:每位的下一状态为左右相邻位的异或,边界位q[-1]q[512]0

● Rule 110 (Rule110)
module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q
);
    
    integer i; //left(A):i+1,center(B):i,right(C):i-1
    always@(posedge clk)begin
        if(load)begin
            q<=data;
        end else begin
            for(i=0;i<512;i=i+1)begin
                if(i==0)begin
                    q[i]<=(q[i]^1'b0) | (~q[i+1]&1'b0);
                end else if(i==511)begin
                    q[i]<=(q[i]^q[i-1]) | (~1'b0&q[i-1]);
                end else begin
                    q[i]<=(q[i]^q[i-1]) | (~q[i+1]&q[i-1]); //B^C + ~A&B 或者 B^C + ~A&C
                end
            end
        end
    end
endmodule

注:从真值表画出卡诺图,逻辑表达式为B^C + !A&B 或者 B^C + !A&Cleft(A):i+1;center(B):i;right(C):i-1
在这里插入图片描述

● Conway’s Game of Life 16x16 (Conwaylife)
module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 
	
    integer i;
    reg [3:0]sum;
    always@(posedge clk)begin
        if(load)begin
            q<=data;
        end else begin
            for(i=0;i<256;i=i+1)begin
                if(i==0 || i==15 || i==240 || i==255)begin //四个角
                    if(i==0)begin
                        sum=q[i+255]+q[i+1]+q[i+241]+q[i+240]+q[i+31]+q[i+15]+q[i+16]+q[i+17]; //0
                    end else if(i==15)begin
                        sum=q[i-1]+q[i+1]+q[i-15]+q[i+240]+q[i+239]+q[i+15]+q[i+16]+q[i+225]; //15
                    end else if(i==240)begin
                        sum=q[i-1]+q[i+1]+q[i-15]+q[i-16]+q[i-225]+q[i+15]+q[i-240]+q[i-239]; //240
                    end else if(i==255)begin
                        sum=q[i-1]+q[i-255]+q[i-15]+q[i-16]+q[i-17]+q[i-241]+q[i-240]+q[i-31]; //255
                    end
                end else if((0<i && i<15) || (240<i && i<255) || (i%16==15) || (i%16==0))begin //四条边
                    if(0<i && i<15)begin
                        sum=q[i-1]+q[i+1]+q[i+239]+q[i+240]+q[i+241]+q[i+15]+q[i+16]+q[i+17]; //上边
                    end else if(240<i && i<255) begin
                        sum=q[i-1]+q[i+1]+q[i-15]+q[i-16]+q[i-17]+q[i-239]+q[i-240]+q[i-241]; //下边
                    end else if(i%16==15) begin
                        sum=q[i-1]+q[i-15]+q[i-31]+q[i-16]+q[i-17]+q[i+15]+q[i+16]+q[i+1]; //左边
                    end else if(i%16==0) begin
                        sum=q[i+15]+q[i+1]+q[i-15]+q[i-16]+q[i-1]+q[i+31]+q[i+16]+q[i+17]; //右边
                    end
                end else begin //中间
                    sum=q[i-1]+q[i+1]+q[i-15]+q[i-16]+q[i-17]+q[i+15]+q[i+16]+q[i+17];
                end
                case(sum)
                    4'd2:q[i]<=q[i];
                    4'd3:q[i]<=1'b1;
                    default:q[i]<=1'b0;
                endcase
            end
        end
    end
endmodule

注:16×16的矩阵,计算每个元素周围8个元素的和,并以此判断下一状态。黄底红字为边界元素应该补齐的位,绿底为四个角的元素,橙底代表除四个角以外的边界上的元素,蓝底代表中间的元素。上面时序电路中用了阻塞赋值,不推荐此种写法,单纯做题。 此题也可以用SV写,但我不会。
在这里插入图片描述

3.2.5 Finite State Machines

● Simple FSM 1 (asynchronous reset) (Fsm1)
module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output out);

    parameter A=1'b0, B=1'b1; 
    reg state, next_state;
	
    always @(posedge clk or posedge areset) begin
        // 状态转移
        if(areset)begin
            state<=B;
        end else begin
            state<=next_state;
        end
    end
    
    always @(*) begin
        // 状态转移逻辑
        case({in,state})
            {1'b0,A}:next_state=B;
            {1'b0,B}:next_state=A;
            {1'b1,A}:next_state=A;
            {1'b1,B}:next_state=B;
            default:next_state=next_state;
        endcase
    end
	
    // 输出
    assign out = state;
endmodule

注:三段式状态机,第一段写状态的转移(时序电路);第二段写具体的状态转移逻辑(组合电路);第三段写状态的输出(可时序可组合)。

● Simple FSM 1 (synchronous reset) (Fsm1s)
// Note the Verilog-1995 module declaration syntax here:
module top_module(clk, reset, in, out);
    input clk;
    input reset;    // Synchronous reset to state B
    input in;
    output out;
    reg out;

    parameter A=1'b0, B=1'b1;
    reg present_state, next_state;

    //状态转移
    always @(posedge clk) begin
        if (reset) begin  
        	present_state <= B;
        end else begin
            present_state <= next_state;
        end
    end
    
    //状态转移逻辑
    always @(*) begin
        case( {in,present_state} )
            {1'b0,A}: next_state <= B;
            {1'b0,B}: next_state <= A;
            {1'b1,A}: next_state <= A;
            {1'b1,B}: next_state <= B;
            default: next_state <= present_state;
        endcase
    end
    
    //状态输出
    always @(*) begin
        out = present_state;
    end
endmodule

注:同步复位T触发器。

● Simple FSM 2 (asynchronous reset) (Fsm2)
module top_module(
    input clk,
    input areset,    // Asynchronous reset to OFF
    input j,
    input k,
    output out);
	
    parameter OFF=1'b0, ON=1'b1;
    reg state, next_state;
    
    //状态转移
    always @(posedge clk or posedge areset) begin
        if(areset)begin
            state <= OFF;
        end else begin
            state <= next_state;
        end
    end
    
    //状态转移逻辑
    always @(*) begin
        if(j==1 && state==OFF) begin
            next_state = ON; //OFF→ON
        end else if(k==1 && state==ON) begin
            next_state = OFF; //ON→OFF
        end else begin
            next_state = state; //状态不变
        end
    end
    
    //状态输出
    always @(*) begin
        out = state;
    end
endmodule

注:异步复位JK触发器。

● Simple FSM 2 (synchronous reset) (Fsm2s)
module top_module(
    input clk,
    input reset,    // Synchronous reset to OFF
    input j,
    input k,
    output out);
	
    parameter OFF=1'b0, ON=1'b1; 
    reg state, next_state;
	
    //状态转移
    always @(posedge clk) begin
        if(reset)begin
            state <= OFF;
        end else begin
            state <= next_state;
        end
    end
    
    //状态转移逻辑
    always @(*) begin
        case(state)
            ON:begin
                if(k==1)begin
                    next_state = OFF;
                end else begin
                    next_state = ON;
                end
            end
            OFF:begin
                if(j==1)begin
                    next_state = ON;
                end else begin
                    next_state = OFF;
                end
            end
        endcase
    end
	
    //状态输出
    assign out = state;
endmodule

注:同步复位JK触发器。

● Simple state transitions 3 (Fsm3comb)
module top_module(
    input in,
    input [1:0] state,
    output [1:0] next_state,
    output out);

    parameter A=2'b00, B=2'b01, C=2'b10, D=2'b11;

    //状态转移逻辑
    always@(*)begin
        if(in==0)begin
            case(state)
                A: next_state = A;
                B: next_state = C;
                C: next_state = A;
                D: next_state = C;
                default:next_state = state;
            endcase
        end else begin
            case(state)
                A: next_state = B;
                B: next_state = B;
                C: next_state = D;
                D: next_state = B;
                default:next_state = state;
            endcase
        end
    end

    //状态输出
    always@(*)begin
        case(state)
			A: out = 1'b0;
			B: out = 1'b0;
			C: out = 1'b0;
			D: out = 1'b1;
			default:out = out;
		endcase
    end
endmodule
● Simple one-hot state transitions 3 (Fsm3onehot)
module top_module(
    input in,
    input [3:0] state,
    output [3:0] next_state,
    output out);

    parameter A=0, B=1, C=2, D=3;

    //状态转移逻辑:采用独热码,写出下一状态每个位的表达式
    assign next_state[A] = state[A]&(~in) | state[C]&(~in);
    assign next_state[B] = state[A]&in | state[B]&in | state[D]&in;
    assign next_state[C] = state[B]&(~in) | state[D]&(~in);
    assign next_state[D] = state[C]&in;

    //状态输出
    assign out = state[D];
endmodule

注:独热码编码描述状态。

● Simple FSM 3 (asynchronous reset) (Fsm3)
module top_module(
    input clk,
    input in,
    input areset,
    output out);
	
    /*//方法一:非独热码编码,四个state分别为:A=2'd0,B=2'd1,C=2'd2,D=2'd3
    reg [1:0]state, next_state;
    parameter A=2'd0, B=2'd1, C=2'd2, D=2'd3;
    
    //状态转移
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            state <= A;
        end else begin
            state <= next_state;
        end
    end

    //状态转移逻辑
    always@(*)begin
        if(in==0)begin
            case(state)
                A: next_state = A;
                B: next_state = C;
                C: next_state = A;
                D: next_state = C;
                default: next_state = state; //保持当前状态不变
            endcase
        end else begin
            case(state)
                A: next_state = B;
                B: next_state = B;
                C: next_state = D;
                D: next_state = B;
                default: next_state = state; //保持当前状态不变
            endcase
        end
    end
    
    //状态输出
    always@(*)begin
        case(state)
            A: out = 1'b0;
            B: out = 1'b0;
            C: out = 1'b0;
            D: out = 1'b1;
            default: out = out; //保持当前状态不变
        endcase
    end*/
    
    //方法二:独热码编码,四个state分别为:4'b0001,4'b0010,4'b0100,4'b1000
    reg [3:0]state,next_state;
    parameter A=4'd0, B=4'd1, C=4'd2, D=4'd3;
    
    //状态转移
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            state <= 4'b0001; //注意复位到state的第一个状态4'b0001
        end else begin
            state <= next_state;
        end
    end

    //状态转移逻辑
    always@(*)begin
    	next_state[A] = state[A]&(~in) | state[C]&(~in);
    	next_state[B] = state[A]&in | state[B]&in | state[D]&in;
    	next_state[C] = state[B]&(~in) | state[D]&(~in);
    	next_state[D] = state[C]&in;
    end

    //状态输出
    always@(*)begin
    	out = state[D];
    end
endmodule

注:采用方法二时注意复位到state的第一个状态为4'b0001,定义的A,B,C,D用于表示位而非状态。

● Simple FSM 3 (synchronous reset) (Fsm3s)
module top_module(
    input clk,
    input in,
    input reset,
    output out);

    /*// 方法一:不采用独热码编码,四个状态为:A(2'd0),B(2'd1),C(2'd2),D(2'd3)
    parameter A=2'd0, B=2'd1, C=2'd2, D=2'd3;
    reg [1:0]state, next_state;
    
    // 状态转移
    always@(posedge clk)begin
        if(reset)begin
            state <= A;
        end else begin
            state <= next_state;
        end
    end

    // 状态转移逻辑
    always@(*)begin
        if(~in)begin
            case(state)
                A: next_state = A;
                B: next_state = C;
                C: next_state = A;
                D: next_state = C;
                default: next_state = state;
            endcase
        end else begin
            case(state)
                A: next_state = B;
                B: next_state = B;
                C: next_state = D;
                D: next_state = B;
                default: next_state = state;
            endcase
        end
    end

    // 状态输出
    always@(*)begin
        out = (state==D) ? 1'b1 : 1'b0;
    end*/
    
    // 方法二:独热码编码,四个状态为:A(4'b0001),B(4'b0010),C(4'b0100),D(4'b1000)
	parameter A=2'd0, B=2'd1, C=2'd2, D=2'd3;
    reg [3:0]state, next_state;
    
    // 状态转移
    always@(posedge clk)begin
        if(reset)begin
            state <= 4'b0001;
        end else begin
            state <= next_state;
        end
    end

    // 状态转移逻辑
    always@(*)begin
        next_state[A] = state[A]&(~in) | state[C]&(~in) ;
        next_state[B] = state[A]&in | state[B]&in | state[D]&in ;
        next_state[C] = state[B]&(~in) | state[D]&(~in) ;
        next_state[D] = state[C]&in ;
    end

    // 状态输出
    always@(*)begin
        out = state[D];
    end
endmodule

注:采用方法二时注意复位到state的第一个状态为4'b0001,定义的A,B,C,D用于表示位而非状态。

● Design a Moore FSM (Exams/ece241 2013 q4)
module top_module (
    input clk,
    input reset,
    input [3:1] s,
    output fr3,
    output fr2,
    output fr1,
    output dfr
);
	
    parameter A=2'd0, B=2'd1, C=2'd2, D=2'd3;
    reg [1:0]curr_state, next_state;
    reg [2:0]fr_pre;
    
    always@(posedge clk)begin
        fr_pre <= {fr3,fr2,fr1}; // 记录前一时刻的流量阀开关情况,流量阀侧面反应了水位,流量阀开得多表示水位低
    end
    
    // 状态转移
    always@(posedge clk)begin
        if(reset)begin
            curr_state <= A;
        end else begin
            curr_state <= next_state;
        end
    end
    
    // 状态转移逻辑
    always@(*)begin
        casez(s)
            3'b000: next_state = A; //没有传感器“工作”
        	3'b001: next_state = B; //传感器S1“工作”
            3'b01z: next_state = C; //传感器S2“工作”,此时S1肯定也在“工作”
        	3'b1zz: next_state = D; //传感器S3“工作”,此时S1、S2肯定也在“工作”
        	default: next_state = 3'hx;
        endcase
    end
    
    // 状态输出
    always@(*)begin
        if(curr_state==A)begin
        	dfr = 1'b1;
        end else if(curr_state==D)begin
            dfr = 1'b0;
        end else begin
            if( {fr3,fr2,fr1}>fr_pre )begin
            	dfr = 1'b1; // 上一时刻水位高于当前时刻
            end else if( {fr3,fr2,fr1}<fr_pre )begin
                dfr = 1'b0; // 上一时刻水位低于当前时刻
            end else begin
                dfr = dfr; // 上一时刻水位等于当前时刻
            end
        end
        
        case(curr_state)
            A: {fr3, fr2, fr1} = {1'b1, 1'b1, 1'b1};
            B: {fr3, fr2, fr1} = {1'b0, 1'b1, 1'b1};
            C: {fr3, fr2, fr1} = {1'b0, 1'b0, 1'b1};
            D: {fr3, fr2, fr1} = {1'b0, 1'b0, 1'b0};
            default: {fr3, fr2, fr1} = 3'hx;
        endcase
    end
endmodule

注:此题主要在于dfr的判断,dfr只有在复位和上一时刻水位高于当前时刻时才为1。流量阀fr3, fr2, fr1的开(1)(0)情况可以侧面反应水位,流量阀开得多表示水位低。我的解法报了锁存warning,可以通过HDLBits网页的Solution查看作者的解法

● Lemmings 1 (Lemmings1)
module top_module(
    input clk,
    input areset,    // 复位向左走
    input bump_left,
    input bump_right,
    output walk_left,
    output walk_right);
	
    parameter LEFT=1'd0, RIGHT=1'd1;
    reg state, next_state;
	
    // 状态转移
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            state <= LEFT;
        end else begin
            state <= next_state;
        end
    end
    
    // 状态转移逻辑
    always@(*)begin
        if(state==LEFT)begin
            casez( {bump_left,bump_right} )
                2'b1z: next_state = RIGHT;
                default: next_state = LEFT;
            endcase
        end else begin
            casez( {bump_left,bump_right} )
                2'bz1: next_state = LEFT;
                default: next_state = RIGHT;
            endcase
        end
    end
	
    // 状态输出
    always@(*)begin
        walk_left = state==LEFT ? 1'b1 : 1'b0;
        walk_right = state==RIGHT ? 1'b1 : 1'b0;
    end
endmodule

注:画出状态转移图即可。
Lemmings1

● Lemmings 2 (Lemmings2)
module top_module(
    input clk,
    input areset,    // 复位向左走
    input bump_left,
    input bump_right,
    input ground,
    output walk_left,
    output walk_right,
    output aaah );
	
    parameter left=2'd0, right=2'd1, fall_l=2'd2, fall_r=2'd3;
    reg [1:0]state, next, temp;
    
    // 状态转移
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            state <= left;
        end else begin
            state <= next;
        end
    end
    
    // 状态转移逻辑
    always@(*)begin
        case(state)
            left:
            	if(ground)begin
                    next = bump_left ? right : left;
                end else begin
                    next = fall_l;
                end
            right:
            	if(ground)begin
                    next = bump_right ? left : right;
                end else begin
                    next = fall_r;
                end
            fall_l: next = ground==1 ? left : fall_l;
            fall_r: next = ground==1 ? right : fall_r;
            default: next = 2'hx;
        endcase
    end
    
    // 状态输出
    always@(*)begin
        case(state)
            left: {walk_left, walk_right, aaah} = {1'b1, 1'b0, 1'b0};
            right: {walk_left, walk_right, aaah} = {1'b0, 1'b1, 1'b0};
            fall_l: {walk_left, walk_right, aaah} = {1'b0, 1'b0, 1'b1};
            fall_r: {walk_left, walk_right, aaah} = {1'b0, 1'b0, 1'b1};
            default: {walk_left, walk_right, aaah} = 3'hx;
        endcase
    end  
endmodule

注:状态转移图(字丑见谅):
Lemmings2

● Lemmings 3 (Lemmings3)
module top_module(
    input clk,
    input areset,    // Freshly brainwashed Lemmings walk left.
    input bump_left,
    input bump_right,
    input ground,
    input dig,
    output walk_left,
    output walk_right,
    output aaah,
    output digging ); 
	
    parameter left=3'd0, right=3'd1, fall_l=3'd2, fall_r=3'd3, dig_l=3'd4, dig_r=3'd5;
    reg [2:0]state, next;
    
    // 状态转移
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            state <= left;
        end else begin
            state <= next;
        end
    end
    
    // 状态转移逻辑
    always@(*)begin
        case(state)
            left:
                casez({ground,dig,bump_left,bump_right})
                	4'b0zzz: next = fall_l;
                    4'b11zz: next = dig_l;
                    4'b101z: next = right;
                    4'b100z: next = left;
                    default: next = state;
            	endcase
            right:
                casez({ground,dig,bump_left,bump_right})
                	4'b0zzz: next = fall_r;
                    4'b11zz: next = dig_r;
                    4'b10z1: next = left;
                    4'b10z0: next = right;
                    default: next = state;
            	endcase
            fall_l:
                casez({ground,dig,bump_left,bump_right})
                	4'b1zzz: next = left;
                    default: next = state;
            	endcase
            fall_r:
                casez({ground,dig,bump_left,bump_right})
                	4'b1zzz: next = right;
                    default: next = state;
            	endcase
            dig_l:
                casez({ground,dig,bump_left,bump_right})
                	4'b0zzz: next = fall_l;
                    default: next = state;
            	endcase
            dig_r:
                casez({ground,dig,bump_left,bump_right})
                	4'b0zzz: next = fall_r;
                    default: next = state;
            	endcase
            default:next = 3'hx;
        endcase
    end
    // 状态输出
    always@(*)begin
        case(state)
            left:   {walk_left,walk_right,aaah,digging} = 4'b1000;
            right:  {walk_left,walk_right,aaah,digging} = 4'b0100;
            fall_l: {walk_left,walk_right,aaah,digging} = 4'b0010;
            fall_r: {walk_left,walk_right,aaah,digging} = 4'b0010;
            dig_l:  {walk_left,walk_right,aaah,digging} = 4'b0001;
            dig_r:  {walk_left,walk_right,aaah,digging} = 4'b0001;
            default:{walk_left,walk_right,aaah,digging} = 4'hx;
        endcase
    end
endmodule

注:状态转移图:
Lemmings3

● Lemmings 4 (Lemmings4)
module top_module(
    input clk,
    input areset,    // Freshly brainwashed Lemmings walk left.
    input bump_left,
    input bump_right,
    input ground,
    input dig,
    output walk_left,
    output walk_right,
    output aaah,
    output digging );

    parameter left=3'd0, right=3'd1, fall_l=3'd2, fall_r=3'd3,  dig_l=3'd4, dig_r=3'd5, splatter=3'd6;
    reg [2:0]state, next;
    reg [4:0]cnt;
    
    /*// 方法一:用 fall_l和fall_r 两种状态做掉落时间判断条件(当前状态)
    always@(posedge clk)begin
        if((state==fall_l) || (state==fall_r))begin
            cnt <= cnt==5'd20 ? cnt : cnt+1'd1; // 方法一:cnt==5'd20
        end else begin
            cnt <= 5'd0;
        end
    end*/
    /*// 方法二:用输入信号 ground 做掉落时间判断条件
    always@(posedge clk)begin
        if(ground==0)begin
            cnt <= cnt==5'd21 ? cnt : cnt+1'd1; // 方法二:cnt==5'd21
        end else begin
            cnt <= 5'd0;
        end
    end*/
    // 方法三:用 fall_l和fall_r 两种状态做掉落时间判断条件(下一状态)
    always@(posedge clk)begin
        if((next==fall_l) || (next==fall_r))begin
            cnt <= cnt==5'd21 ? cnt : cnt+1'd1; // 方法三:cnt==5'd21
        end else begin
            cnt <= 5'd0;
        end
    end
    
    // 状态转移
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            state <= left;
        end else begin
            state <= next;
        end
    end
    
    // 状态转移逻辑
    always@(*)begin
        case(state)
            left:
                casez({ground,dig,bump_left,bump_right})
                    4'b0zzz: next = fall_l;
                    4'b11zz: next = dig_l;
                    4'b101z: next = right;
                    4'b100z: next = left;
                    default: next = state;
                endcase
            right:
                casez({ground,dig,bump_left,bump_right})
                    4'b0zzz: next = fall_r;
                    4'b11zz: next = dig_r;
                    4'b10z1: next = left;
                    4'b10z0: next = right;
                    default: next = state;
                endcase
            fall_l:
                if(cnt==21 && ground==1)begin // 方法一:cnt==5'd20;方法二:cnt==5'd21;方法三:cnt==5'd21
                    next = splatter;
                end else begin
                    casez({ground,dig,bump_left,bump_right})
                        4'b1zzz: next = left;
                        default: next = state;
                    endcase
                end
            fall_r:
                if(cnt==21 && ground==1)begin // 方法一:cnt==5'd20;方法二:cnt==5'd21;方法三:cnt==5'd21
                    next = splatter;
                end else begin
                    casez({ground,dig,bump_left,bump_right})
                        4'b1zzz: next = right;
                        default: next = state;
                    endcase
                end
            dig_l:
                casez({ground,dig,bump_left,bump_right})
                    4'b0zzz: next = fall_l;
                    default: next = state;
                endcase
            dig_r:
                casez({ground,dig,bump_left,bump_right})
                    4'b0zzz: next = fall_r;
                    default: next = state;
                endcase
            splatter: next = state;
            default:next = 3'hx;
        endcase
    end
    
    // 状态输出
    always@(*)begin
        case(state)
            left:     {walk_left,walk_right,aaah,digging} = 4'b1000;
            right:    {walk_left,walk_right,aaah,digging} = 4'b0100;
            fall_l:   {walk_left,walk_right,aaah,digging} = 4'b0010;
            fall_r:   {walk_left,walk_right,aaah,digging} = 4'b0010;
            dig_l:    {walk_left,walk_right,aaah,digging} = 4'b0001;
            dig_r:    {walk_left,walk_right,aaah,digging} = 4'b0001;
            splatter: {walk_left,walk_right,aaah,digging} = 4'b0000;
            default:  {walk_left,walk_right,aaah,digging} = 4'hx;
        endcase
    end
endmodule

注: 方法一(当前状态做判断条件)和方法二(输入做判断条件)、方法三(下一状态做判断条件)计数cnt不同的原因是因为:方法一利用状态机第一段(状态转移)中的变量,该always块是一个时序电路,对其内部的变量的赋值要在块结束后才会执行(即需要延迟一拍,非阻塞赋值);而方法二、三是利用状态机第二段(状态转移逻辑)中的变量,该always块是一个组合电路,对其内部的变量的赋值立即执行(阻塞赋值),因此方法一比方法二、三少计数一次。状态转移图:
Lemmings4

● One-hot FSM (Fsm onehot)
module top_module(
    input in,
    input [9:0] state,
    output [9:0] next_state,
    output out1,
    output out2);
    
    parameter s0=0, s1=1, s2=2, s3=3, s4=4, s5=5, s6=6, s7=7, s8=8, s9=9;
    
    // 状态转移逻辑
    always@(*)begin
        next_state[s0] = ~in & (state[s0] | state[s1] | state[s2] | state[s3] | state[s4] | state[s7] | state[s8] | state[s9]);
        next_state[s1] = in & (state[s0] | state[s8] | state[s9]);
        next_state[s2] = in & state[s1];
        next_state[s3] = in & state[s2];
        next_state[s4] = in & state[s3];
        next_state[s5] = in & state[s4];
        next_state[s6] = in & state[s5];
        next_state[s7] = in & (state[s6] | state[s7]);
        next_state[s8] = ~in & state[s5];
        next_state[s9] = ~in & state[s6];
    end
    
    // 状态输出
    always@(*)begin
        out1 = state[s8] | state[s9];
        out2 = state[s7] | state[s9];
    end
endmodule
● PS/2 packet parser (Fsm ps2)
module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output done);
	
    parameter byte1=2'd0, byte2=2'd1, byte3=2'd2, finish=2'd3;
    reg [1:0] state, next;
    
    // 状态转移
    always@(posedge clk)begin
        if(reset)begin
            state <= byte1;
        end else begin
            state <= next;
        end
    end

    // 状态转移逻辑
    always@(*)begin
        case(state)
            byte1:   next = in[3]==1 ? byte2 : byte1;
            byte2:   next = byte3;
            byte3:   next = finish;
            finish:  next = in[3]==1 ? byte2 : byte1;
            default: next = 2'hx;
        endcase
    end
    
    // 状态输出
	always@(*)begin
        case(state)
            byte1:   done = 1'b0;
            byte2:   done = 1'b0;
            byte3:   done = 1'b0;
            finish:  done = 1'b1;
            default: done = 1'hx;
        endcase
    end
endmodule

注:此题不能用3个状态机进行描述的原因:我的理解是3个状态机不能描述输入in[3]=1与完成done=1同时发生的状态,即第一个波形图所描述情形。状态转移图:
在这里插入图片描述

● PS/2 packet parser and datapath (Fsm ps2data)
module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output [23:0] out_bytes,
    output done);
	
    parameter byte1=2'd0, byte2=2'd1, byte3=2'd2, finish=2'd3;
    reg [1:0] state, next;
	reg [23:0] out_mem;
    
    // 状态转移
    always@(posedge clk)begin
        if(reset)begin
            state <= byte1;
        end else begin
            state <= next;
        end
    end
    
    // 状态转移逻辑
    always@(*)begin
        case(state)
			byte1:  next = in[3]==1 ? byte2 : byte1;
			byte2:  next = byte3;
			byte3:  next = finish;
			finish: next = in[3]==1 ? byte2 : byte1;
			default:next = 2'hx;
		endcase
    end
	
    // 状态输出
	always@(*)begin
        case(state)
            byte1:  done = 1'b0;
            byte2:  done = 1'b0;
            byte3:  done = 1'b0;
			finish: done = 1'b1;
			default:done = 1'hx;
		endcase
    end
    
    // 保存datapath
    always@(posedge clk)begin
    	case(state)
    		byte1:  out_mem[23:16] <= in;
    		byte2:  out_mem[15:8] <= in;
    		byte3:  out_mem[7:0] <= in;
     		finish: out_mem[23:16] <= in[3]==1 ? in : 8'd0;
			default:out_mem = 24'hx;
		endcase
    end
    assign out_bytes = state==finish ? out_mem : 24'hx;
endmodule
● Serial receiver (Fsm serial)
module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
);
	/*// 方法一:将中间态data0-data7分别描述
    parameter data0=4'd0,data1=4'd1, data2=4'd2, data3=4'd3, data4=4'd4, data5=4'd5, data6=4'd6, data7=4'd7;
    parameter idle=4'd8, start=4'd9, stop=4'd10, error=4'd11;
    reg [3:0] state, next;
	
	// 状态转移
	always@(posedge clk)begin
		if(reset)begin
			state <= idle;
		end else begin
			state <= next;
		end
	end
	
	// 状态转移逻辑
	always@(*)begin
		case(state)
			idle:   next = in==0 ? start : idle;
			start:  next = data0;
            data0:  next = data1;
            data1:  next = data2;
            data2:  next = data3;
            data3:  next = data4;
            data4:  next = data5;
            data5:  next = data6;
            data6:  next = data7;
            data7:  next = in==1 ? stop : error;
            error:  next = in==1 ? idle : state;
            stop:   next = in==0 ? start : idle;
			default:next = 4'hx;
		endcase
	end
	
	// 状态输出
	assign done = state==stop ? 1'b1 : 1'b0;*/
    
    // 方法二:将中间态data0-data7用计数器描述
    parameter idle=3'd0, start=3'd1, data=3'd2, stop=3'd3, error=3'd4;
    reg [2:0] state, next;
    reg [3:0] cnt;
	
    // data计数
    always@(posedge clk)begin
        cnt <= state==data ? cnt+1'b1 : 4'd0; // 可改为 cnt <= next==data ? cnt+1'b1 : 4'd0;
	end
    
	// 状态转移
	always@(posedge clk)begin
		if(reset)begin
			state <= idle;
		end else begin
			state <= next;
		end
	end
	
	// 状态转移逻辑
	always@(*)begin
		case(state)
			idle:   next = in==0 ? start : idle;
			start:  next = data;
            data:
                if(cnt==7)begin    // 计数用 cnt <= next==data ? cnt+1'b1 : 4'd0; 时,对应 cnt==8
                    next = in==1 ? stop : error;
                end else begin
                    next = state;
                end
            error:  next = in==1 ? idle : state;
            stop:   next = in==0 ? start : idle;
			default:next = 4'hx;
		endcase
	end
	
	// 状态输出
	assign done = state==stop ? 1'b1 : 1'b0;
endmodule

注:状态转移图:
在这里插入图片描述

● Serial receiver and datapath (Fsm serialdata)
module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
);
    
    /*// 方法一:将中间态data0-data7分别描述
    parameter data0=4'd0,data1=4'd1, data2=4'd2, data3=4'd3, data4=4'd4, data5=4'd5, data6=4'd6, data7=4'd7;
    parameter idle=4'd8, start=4'd9, stop=4'd10, error=4'd11;
    reg [3:0] state, next;
    reg [7:0] out_mem;
	
	// 状态转移
	always@(posedge clk)begin
		if(reset)begin
			state <= idle;
		end else begin
			state <= next;
		end
	end
	
	// 状态转移逻辑
	always@(*)begin
		case(state)
			idle:   next = in==0 ? start : idle;
			start:  next = data0;
            data0:  next = data1;
            data1:  next = data2;
            data2:  next = data3;
            data3:  next = data4;
            data4:  next = data5;
            data5:  next = data6;
            data6:  next = data7;
            data7:  next = in==1 ? stop : error;
            error:  next = in==1 ? idle : state;
            stop:   next = in==0 ? start : idle;
			default:next = 4'hx;
		endcase
	end
	
    // data保存
    always@(*)begin
		case(next)
            data0:  out_mem[0] = in;
            data1:  out_mem[1] = in;
            data2:  out_mem[2] = in;
            data3:  out_mem[3] = in;
            data4:  out_mem[4] = in;
            data5:  out_mem[5] = in;
            data6:  out_mem[6] = in;
            data7:  out_mem[7] = in;
            default:out_mem = out_mem;
		endcase
	end
    
	// 状态输出
	assign done = state==stop ? 1'b1 : 1'b0;
    assign out_byte = state==stop ? out_mem : 8'hx;*/
    
    /*// 方法二:将中间态data0-data7用计数器描述(利用下一状态)
    parameter idle=3'd0, start=3'd1, data=3'd2, stop=3'd3, error=3'd4;
    reg [2:0] state, next;
    reg [3:0] cnt;
    reg [7:0] out_mem;
	
    // data计数
    always@(posedge clk)begin
        cnt <= next==data ? cnt+1'b1 : 4'd0;
	end
    
	// 状态转移
	always@(posedge clk)begin
		if(reset)begin
			state <= idle;
		end else begin
			state <= next;
		end
	end
	
	// 状态转移逻辑
	always@(*)begin
		case(state)
			idle:   next = in==0 ? start : idle;
			start:  next = data;
            data:
                if(cnt==8)begin
                    next = in==1 ? stop : error;
                end else begin
                    next = state;
                end
            error:  next = in==1 ? idle : state;
            stop:   next = in==0 ? start : idle;
			default:next = 4'hx;
		endcase
	end
    
    // data保存
    always@(posedge clk)begin
        if(next==data)begin
            out_mem[cnt] <= in;
        end else begin
            out_mem <= out_mem;
        end
    end
	
	// 状态输出
	assign done = state==stop ? 1'b1 : 1'b0;
    assign out_byte = state==stop ? out_mem : 8'd0;*/
    
    // 方法三:将中间态data0-data7用计数器描述(利用当前状态)
    parameter idle=3'd0, start=3'd1, data=3'd2, stop=3'd3, error=3'd4;
    reg [2:0] state, next;
    reg [3:0] cnt;
    reg [7:0] out_mem;
	
    // data计数
    always@(posedge clk)begin
        cnt <= state==data ? cnt+1'b1 : 4'd0;
	end
    
	// 状态转移
	always@(posedge clk)begin
		if(reset)begin
			state <= idle;
		end else begin
			state <= next;
		end
	end
	
	// 状态转移逻辑
	always@(*)begin
		case(state)
			idle:   next = in==0 ? start : idle;
			start:  next = data;
            data:
                if(cnt==7)begin
                    next = in==1 ? stop : error;
                end else begin
                    next = state;
                end
            error:  next = in==1 ? idle : state;
            stop:   next = in==0 ? start : idle;
			default:next = 4'hx;
		endcase
	end
    
    // data保存
    always@(posedge clk)begin
        if(state==start || state==data)begin
            if(state==start)begin
            	out_mem[0] <= in;
            end else begin
                out_mem[cnt+1] <= in;
            end
        end else begin
            out_mem <= out_mem;
        end
    end
	
	// 状态输出
	assign done = state==stop ? 1'b1 : 1'b0;
    assign out_byte = state==stop ? out_mem : 8'd0;
endmodule
● Serial receiver with parity checking (Fsm serialdp)
module top_module(
    input wire			clk,
    input wire			in,
    input wire			reset,
    output reg	[7:0]	out_byte,
    output reg			done
);
    
	localparam IDLE=3'd0, START=3'd1, DATA=3'd2, PARITY=3'd3, DONE=3'd4, ERROR=3'd5;
    
    reg		[2:0]		curr, next;
    reg		[3:0]		cnt;
    reg		[7:0]		out_t;
    wire 				odd, rst_par;
    reg					par;
    
    // State transitions
    always@(posedge clk)begin
        if(reset)begin
            curr <= IDLE;
        end else begin
            curr <= next;
        end
    end
    
    // State logic
    always@(*)begin
        case(curr)
            IDLE	: next = in==0 ? START : curr;
            START	: next = DATA;
            DATA	: next = cnt==8 ? PARITY : curr;
            PARITY	: next = in==1 ? DONE : ERROR;
            DONE	: next = in==0 ? START : IDLE;
            ERROR	: next = in==1 ? IDLE : curr;
            default	: next = IDLE;
        endcase
    end
    
    // Data counter and save in
    always@(posedge clk)begin
        cnt <= next==DATA ? cnt+1'b1 : 4'h0;
        out_t[cnt] <= next==DATA ? in : out_t[cnt];
    end
    
    // State output
    // 方法一:利用当前状态对输出进行判断
    // 获取奇偶校验结果
    always@(posedge clk)begin
        par <= curr==PARITY ? odd : par;
    end
    
    // State output
    always@(*)begin
		out_byte = (curr==DONE && par==1) ? out_t : 8'hx;
		done = (curr==DONE && par==1) ? 1'b1 : 1'b0;
    end
    
    /*// 方法二:利用下一状态对输出进行判断
    always@(posedge clk)begin
        out_byte <= (next==DONE && odd==1) ? out_t : 8'hx;
		done <= (next==DONE && odd==1) ? 1'b1 : 1'b0;
    end*/
	
    // Parity checking
    assign rst_par = next==START;
    parity u_parity(
        .clk(clk),
        .reset(rst_par),
        .in(in),
        .odd(odd));
    
endmodule

注:状态转移图如下。为了更好理解方法一可以查看下方波形图。
在这里插入图片描述
波形图

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐