Verilog刷题

1. (2.4.6)优先译码器
每个输入端有着不同的重要性,只要更重要的输入端输入了有效信号,我们就不再考虑来自其他次重要输入端的输入信号。
优先译码器真值表:
输入第一个1出现哪个位置输出几

module top_module (
input [3:0] in,
output reg [1:0] pos);
always @(*) begin // Combinational always block
	case (in)
		4'h0: pos = 2'h0;	// I like hexadecimal because it saves typing.
		4'h1: pos = 2'h0;
		4'h2: pos = 2'h1;
		4'h3: pos = 2'h0;
		4'h4: pos = 2'h2;
		4'h5: pos = 2'h0;
		4'h6: pos = 2'h1;
		4'h7: pos = 2'h0;
		4'h8: pos = 2'h3;
		4'h9: pos = 2'h0;
		4'ha: pos = 2'h1;
		4'hb: pos = 2'h0;
		4'hc: pos = 2'h2;
		4'hd: pos = 2'h0;
		4'he: pos = 2'h1;
		4'hf: pos = 2'h0;
		default: pos = 2'b0;	
	endcase
end
endmodule

2.(2.4.7)casez
casez语句表明设定为z的位数可以不关心,只关心设定为1、0的位。

3.(2.5.1)三目选择运算符
错误代码:定义x,y不要忘记位宽

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//
	
    // assign intermediate_result1 = compare? true: false;
	wire		x;
    wire 	 y;
    
    assign x = (a>b) ? b : a;
    assign y = (c>x) ? x : c;
    assign min = (d>y) ? y : d;
endmodule

4.(2.5.2)递减运算符
对一个向量内的位进行操作:
在这里插入图片描述

在这里插入图片描述
5.(2.5.4)for循环
不要忘记begin-end

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

6.(2.5.5)generate
(1)行波进位加法器ripple-carry adder
N-bit加法器可以根据1-bit全加器组合而成。每个全加器的输出进位cout作为下一个全加器的输入进位cin
在这里插入图片描述
(2)generate语句
generate语句的最主要功能就是对module、reg、assign、always、task等语句或者模块进行复制。
generate_for语句:
(a)、必须使用genvar申明一个正整数变量,用作for循环的判断。(genvar是generate语句中的一种变量类型,用在generate_for中声明正整数变量。)
(b)、需要复制的语句必须写到begin_end语句里面。就算只有一句!!!!!!
(c)、begin_end需要有一个类似于模块名的名字。

例:使用generate例化100个全加器或者做100次全加器的运算,需要注意第一次比较特殊,第一次的进位来自输入,而不是前一位的进位,所以需要分开写。

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

7.(2.5.6)使用generate语句例化
使用generate例化100个BCD adder,需要注意第一次比较特殊,第一次的进位来自输入,而不是前一位的进位,所以需要分开写。
不要忘记最后输出进位。

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

8.(3.1.17)100位输入向量与相邻位数关系
out_both:每一位都与左边一位进行与操作;如果是最高位,则不进行。
out_any:每一位都与右边一位进行或操作;如果是最低位,则不进行。
out_different:每一位都与左边一位进行异或操作;如果是最高位,则与最低位进行异或。

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[99:1] & in[98:0];
    assign out_any = in[99:1] | in[98:0];
    assign out_different = {in[0],in[99:1]} ^ in;
endmodule

9.(3.1.2.4) 256-to-1 选择器
创建一个 1 位宽、256:1 的多路复用器。256 个输入全部打包到一个 256 位输入向量中。sel=0 应选择 in[0],sel=1 选择位 in[1],sel=2 选择位 in[2],依此类推。

module top_module( 
    input [255:0] in,
    input [7:0] sel,
    output out );
    
    assign out = in[sel];        
endmodule

10. (3.1.2.5)4位宽 256-to-1 4-bit 多路选择器
创建一个 4 位宽、256:1 的多路复用器。256 个 4 位输入全部封装到单个 1024 位输入向量中。sel=0 应选择位 in[3:0],sel=1 选择位 in[7:4],sel=2 选择位 in[11:8],依此类推。
用向量部分选择处理

module top_module( 
    input [1023:0] in,
    input [7:0] sel,
    output [3:0] out );
    assign out = in[sel *4 +: 4];
endmodule

(1). 向量名 [起始位+:位宽]:从起始位开始(包括起始位), 宽度为位宽,从起始位递增到位宽的一段向量区域。
如:

wire [31:0] a;  a[0 +: 8] 等效为 a[7 : 0]; // 起始位 在最右侧
wire [0:31] b;  b[0 +: 8] 等效为 b[0 : 7]; // 起始位 在最左侧

(2).向量名 [起始位-:位宽]:从起始位开始(包括起始位), 宽度为位宽,从起始位递减到位宽的一段向量区域。如:

wire [31 : 0] a;  a[7-: 8] 等效为 a[7 : 0]; // 起始位 在最左侧
wire [0 : 31] b;  b[7-: 8] 等效为 b[0 : 7]; // 起始位 在最右侧

(3).起始位可以是变量,但位宽必须是常量

11. (3.1.3.5)补码相加溢出

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] & ~s[7]) | (~a[7] & ~b[7] & s[7]);
endmodule

12. (3.1.4.4)同或异或卡诺图化简
在这里插入图片描述
红色:a、b的同或 与上 c、d的异或 ;
蓝色:a、b的异或与上 c、d的同或 。

13. (3.1.4.5)最大项最小项
具有四个输入(a、b、c、d)的单输出数字系统在输入端出现 2、7 或 15 时生成逻辑 1,当 0、1、4、5、6、9、10、13 或 14 出现时生成逻辑 0。数字 3、8、11 和 12 的输入条件在此系统中从未出现。
SOP 积之和 圈1和doncare项(最小项)
pos 和之积 圈0和doncare项 之后 整体取反
在这里插入图片描述
14. (3.1.4.8)使用多路复用器实现的K-map
当输入cd为00时,则需要ab为10输出才为1,所以应该使mux_in[0]=1,其他情况同理。
在这里插入图片描述

module top_module (
    input c,
    input d,
    output [3:0] mux_in
); 
    assign mux_in[0] = (~c & d)|(c & d)|(c & ~d);
    assign mux_in[1] =1'b0;
    assign mux_in[2] = (~c & ~d)|(c & ~d);
    assign mux_in[3] = c & d;
endmodule

15. (3.2.1.6)16D触发器
仅需要修改部分触发器中的值。字节使能信号控制当前时钟周期中16个寄存器中哪个字节需被修改。byteena[1]控制高字节d[15:8],而byteena[0]控制低字节d[7:0]。

\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) 
            q <= 16'd0;
        else
            case(byteena)
                2'b00:	q <= q;
                2'b01:	q <= {q[15:8],d[7:0]};
                2'b10:	q <= {d[15:8],q[7:0]};
                2'b11:  q <= d;  
            default:;
        endcase
    end
endmodule

16. (3.2.1.16)双边边沿检测

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] anyedge
);
    wire [7:0]in_r;
    always@(posedge clk)begin
       in_r <= in;
       anyedge = in ^ in_r;
    end
endmodule

17. (3.2.1.17)边沿捕获
对于32位矢量中的每个位,当输入信号在一个时钟周期内从1变为下一个时钟周期的0时,就可以捕获。"捕获 "意味着输出将保持1,直到寄存器被复位(同步复位)。每个输出位的行为就像一个SR触发器:在1到0转换发生后的周期,输出位应该被设置(到1)。当复位为高电平时,输出位应在正的时钟边沿复位(至0)。

输入为32位的数据,捕获每一位的下降沿,如果检测到下降沿,输出中对应的位置高且保持直到检测到reset为高;如果某一个时钟上升沿同时检测到输入数据位的下降沿和reset为高,则reset优先,即输出为低。

module top_module (
    input clk,
    input reset,
    input [31:0] in,
    output [31:0] out
);
    reg [31:0] r_in;
    always @ (posedge clk)
        begin 
            r_in <= in;
            if(reset)
                out <= 0;
            else
                for(int i = 0; i <=31; i ++)
                    begin 
                        if(~in[i] & r_in[i])
                            out[i] <= 1;
                        else
                            out[i] <= out[i];
                    end
        end            
endmodule

或者

reg [31:0]in_r;
    always @(posedge clk )begin
        in_r <= in;
    end
    always @(posedge clk )begin
        if(reset)
            out <= 'd0;
        else
            out <= ~in & in_r |out;
    end

18. (3.2.1.18)双边边沿触发器
首先 always@(posedge clk or negedge clk)这种语句肯定是不能综合的;其次也不能用两个always块分别在时钟上升沿、时钟下降沿进行操作,这涉及到多驱动问题。

比较合适的方法是设计两个中间变量,分别在时钟上升沿、时钟下降沿进行赋值,最后使用组合逻辑输出。

module top_module (
    input clk,
    input d,
    output q
);
reg q1, q2;
    assign q = clk ? q1 : q2;
    
    always@(posedge clk)
    begin
        q1 <= d;
    end
    always@(negedge clk)
    begin
        q2 <= d;
    end
endmodule

或者 任何一个数异或一个数再异或同一个数,将得到本身

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

19. (3.2.2.5)1-12计数器
例化count4模块

module count4(
	input clk,
	input enable,
	input load,
	input [3:0] d,
	output reg [3:0] Q
);

使能信号enable:直接把c_enable连到这里就可以
载入信号load:结合c_load可以实现复位清零,以及最大值清零
载入值c_load:同上

module top_module (
    input clk,
    input reset,
    input enable,
    output [3:0] Q,
    output c_enable,
    output c_load,
    output [3:0] c_d
); //

    count4 the_counter (clk, c_enable, c_load, c_d ,Q );
    assign c_enable = enable;
    assign c_load = reset|((Q=='d12)&&(enable==1'b1));
	assign c_d = c_load ? 4'd1 :4'dx;
endmodule

20. (3.2.2.6)计数器1000
设计一个周期为1000的计数器.题目给出了一个4位的BCD模块,例化三次这个模块,第一次例化计数10次(每个时钟周期+1),第二次例化计数10次(在第一次例化每计数10次时加+1),第三次例化计数10次(在第二次例化每计数10次时加+1),这样就实现了每1000个时钟周期+1,对应的输出信号的频率也就变成了1hz。

module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //
    wire [3:0]one,ten,hund;//记得加位宽
    bcdcount counter0 (clk, reset, c_enable[0],one);
    bcdcount counter1 (clk, reset, c_enable[1],ten);
    bcdcount counter2 (clk, reset, c_enable[2],hund);	
    assign c_enable = {one =='d9&&ten=='d9,one=='d9,1'b1};
    // c_enable[0]=1'b1:个位计数;c_enable[1]=(one=='d9):十位计数;c_enable[2]=(one=='d9&&ten=='d9):百位计数;
    assign OneHertz = (one=='d9 && ten=='d9 && hund=='d9);
endmodule

21. (3.2.2.7)4位BCD计数器

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    
    wire en0,en1,en2,en3;
    assign en0 = 1'b1;
    assign en1 = (q[3:0]=='d9); 
    assign en2 = (q[3:0]=='d9 && q[7:4]=='d9); 
    assign en3 = (q[3:0]=='d9 && q[7:4]=='d9 && q[11:8]=='d9); 
    
    assign ena = {q[3:0]=='d9&&q[7:4]=='d9&&q[11:8]=='d9, q[7:4]=='d9&&q[3:0]=='d9, q[3:0]=='d9}; 
    
BCDcounter BCDcounter0(
    .clk	(clk),
    .reset	(reset),
    .ena	(en0),
    .q		(q[3:0])
);    
BCDcounter BCDcounter1(
    .clk	(clk),
    .reset	(reset),
    .ena	(en1),
    .q		(q[7:4])
);          
BCDcounter BCDcounter2(
    .clk	(clk),
    .reset	(reset),
    .ena	(en2),
    .q		(q[11:8])
);           
BCDcounter BCDcounter3(
    .clk	(clk),
    .reset	(reset),
    .ena	(en3),
    .q		(q[15:12])
);   
endmodule
           
module BCDcounter(
	input clk,
    input reset,
    input ena,
    output [3:0]q
);
    always@(posedge clk)begin
        if(reset)
            q <= 'd0;
        else if(ena)begin
        	if(q == 'd9)
        	    q<= 'd0;
        	else 
        	    q <= q + 1'b1;
        end
    end
endmodule

22. (3.2.2.8)12小时制计数器
有复位信号,且复位的优先级高于使能端,复位信号有效时能复位到12点,其中pm 表示 AM 为 0,PM 为 1。
要求实现的时间是1点到12点。
出现错误:直接计数到59输出的是3c,使用BCD计数器正确。
计数时使用十进制计数器无法启动,改成十六进制正确。
pm翻转时,时分秒分别是11、59、59。

module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    reg pm1;
    always@(posedge clk)begin
        if(reset)
            pm1 <= 'h0;
        else if((hh=='h11)&(mm=='h59)&(ss=='h59))
            pm1 <= ~pm1;
    end
    assign pm = pm1;
BCD1 BCD1(
    .clk	(clk),
    .reset	(reset),
    .ena	(ena&(mm=='h59)&(ss=='h59)),//有使能信号且秒分都记满则时开始计数
    .hh		(hh)
);
BCD2 BCD2_1(
    .clk	(clk),
    .reset	(reset),
    .ena	(ena&&(ss=='h59)),//有使能信号且秒记满分开始计数
    .ms		(mm)
);    
BCD2 BCD2_2(
    .clk	(clk),
    .reset	(reset),
    .ena	(ena), //有使能信号,秒开始计数
    .ms		(ss)
); 
endmodule

//12计数器
module BCD1(
    input clk,
    input reset,
    input ena,
    output [7:0]hh
);
    always@(posedge clk)begin
        if(reset)
            hh <= 'h12;
        else if(ena)begin
            if(hh == 'h12)
                hh <= 'd1;
            else if(hh[3:0]=='h9)begin
                hh[3:0] <= 'd0;
                hh[7:4] <= hh[7:4] + 1'b1;
            end
            else
                hh[3:0] <= hh[3:0] + 1'b1;
        end      
    end
endmodule
//60计数器
module BCD2(
    input clk,
    input reset,
    input ena,
    output [7:0]ms
);
    always@(posedge clk)begin
        if(reset)
            ms <= 'd0;
        else if(ena)begin
            if(ms == 'h59)
                ms <= 'd0;
            else if(ms[3:0]=='h9)begin
                ms[3:0] <= 'd0;
                ms[7:4] <= ms[7:4] + 1'b1;
            end
            else 
                ms[3:0] <= ms[3:0] + 1'b1;
        end      
    end
endmodule	

23. (3.2.3.1)4位移位寄存器
load:加载带有 data[3:0] 的移位寄存器,而不是移位。
ena:向右移动(q[3] 变为零,q[0] 移出并消失)。

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)
            q <= 'd0;
        else if(load)
            q <= data;
        else if(ena)
            q <= q >> 1'b1;
        else
            q <= q;
    end
endmodule

24. (3.2.3.3)算术移位寄存器
算数左移:和逻辑左移一样。空出来的位用0补;
算数右移:算术移位,也就是包含符号位的移位,对于正数来说,最高位为0,对于负数来说,最高位为1,所以进行算术移位时,如果是左移,那不用管符号位的问题,如果是右移,就要将符号位补在高位。比如:5位数字11000算术右移1为11100,而逻辑右移将产生01100;5位数字01000算术右移1等于00100,而逻辑右移将产生相同的结果,因为原始数字是非负的。

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)
           q <= data;
            else begin
                if(ena)
                case(amount)
                    2'b00: q <= q<<1;
                    2'b01: q <= q<<8;
                    2'b10: 
                        q<= {q[63],q[63:1]};
                    2'b11: 
                        q <= {{8{q[63]}},q[63:8]};
                endcase
            end
    end
endmodule

25. (3.2.3.4)线性反馈移位寄存器
线性反馈移位寄存器(linear feedback shift register, LFSR)是指,给定前一状态的输出,将该输出的线性函数再用作输入的移位寄存器。异或运算是最常见的单比特线性函数:对寄存器的某些位进行异或操作后作为输入,再对寄存器中的各比特进行整体移位(百度百科定义)。
在这里插入图片描述

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

26. (3.2.3.9)三输入LUT
用8个D触发器创建一个8位移位寄存器。标记D触发器的输出分别为Q[0]到Q[7]。移位寄存器输入称为S,输入Q[0] (MSB先移位)。使能输入enable控制是否移位,扩展电路使其有3个额外的输入A,B,C和一个输出Z。电路的行为应该如下:当ABC为000时,Z=Q[0],当ABC为001时,Z=Q[1],以此类推。
即输入的时候是个移位寄存器,输出是根据“地址”来“随机读取

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 )
            Q <= {Q[6:0],S};
        else 
            Q <= Q;
    end
    assign Z = Q[{A,B,C}];
endmodule

27. (3.2.4.1)规则90
在每个时间步中,每个单元的下一个状态是单元的两个当前邻居的异或。
在这个电路中,创建一个512单元系统(q(511:0)),并在每个时钟周期中前进一个时间步长。加载(load)表明系统的状态应该加载data[511:0]至q中,假设边界(q[0]和q[512])都为零。
这个只要用输入q左移1位异或上输入q右移1位即可

module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 
always @(posedge clk)begin
	if(load)
       q[511:0] <= data[511:0];
	else
        q <= (q<<1'b1)^(q>>1'b1);
end
endmodule

28. (3.2.4.3)康威的生命游戏
“游戏”是在二维单元格上进行的,其中每个单元格要么是 1(活)要么是 0(死)。在每个时间步长中,每个单元格都会根据其拥有的邻居数量而改变状态:

0-1 邻居:单元格变为 0。
2 个邻居:单元状态不变。
3 个邻居:单元格变为 1。
4+ 邻居:单元格变为 0。
使用 16x16 的环形线圈,其中两侧环绕到网格的另一侧。例如,角单元格 (0,0) 有 8 个相邻单元:(15,1)、(15,0)、(15,15)、(0,1)、(0,15)、(1,1)、(1,0) 和 (1,15)。

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 
    
    reg [3:0]cout;
    integer i;
    always@(posedge clk)begin
        if(load)
            q <= data;
        else 
            for(i=0;i<256;i=i+1)begin
                if(i==0)
                    cout = q[1]+q[16]+q[17]+q[15]+q[31]+q[255]+q[240]+q[241];
                else if(i==15)
                    cout = q[14]+q[16]+q[30]+q[31]+q[254]+q[255]+q[240]+q[0];
                else if(i==240)
                    cout = q[1]+q[15]+q[255]+q[241]+q[239]+q[224]+q[225]+q[0];
                else if(i==255)
                    cout = q[15]+q[14]+q[238]+q[224]+q[254]+q[240]+q[239]+q[0];
                else if(i>0&i<15)
                    cout = q[i-1]+q[i+1]+q[i+239]+q[i+240]+q[i+241]+q[i+15]+q[i+16]+q[i+17];
                else if(i>240&i<255)
                    cout = q[i-1]+q[i+1]+q[i-239]+q[i-240]+q[i-241]+q[i-15]+q[i-16]+q[i-17];
                else if(i%16==0)
                    cout = q[i+1]+q[i+15]+q[i+16]+q[i+17]+q[i+31]+q[i-16]+q[i-15]+q[i-1];
                else if(i%16==15)
                    cout = q[i-1]+q[i-15]+q[i-16]+q[i-17]+q[i-31]+q[i+15]+q[i+16]+q[i+1];
                else
                    cout = q[i-1]+q[i+1]+q[i-16]+q[i-17]+q[i-15]+q[i+15]+q[i+16]+q[i+17];
                case (cout)
                    4'd2: q[i] <= q[i];
                    4'd3: q[i] <= 1'b1;
                    default: q[i] <= 1'b0;
                endcase
            end	
    end
endmodule

29. (3.2.5.5)独热码
在这里插入图片描述

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[D]&in) | (state[B]&in);
assign next_state[C] = (state[B]&~in) | (state[D]&~in);
assign next_state[D] = (state[C]&in);
 
//组合逻辑实现输出
assign out = (state[D]);
 
endmodule

30. (3.2.5.9)摩尔FSM
根据水位变化情况输出不同状态,有三个传感器S1,S2,S3,可以将水库分成四部分,低于S1时,输出FR1,FR2,FR3;水位介于S1
S2时,输出输出FR1,FR2;水位介于S2S3时,输出输出FR1;水位高于S3时,可以认为FR1,FR2,FR3全为零;同时还会将上一刻水位状态和现在的水位状态进行比较,如果高于现在水位,需要打开(三角)FR,否则不需要打开。
在这里插入图片描述

设计4个状态,状态的变化应该都发生在临近状态之间:

S0:水位低于S1。当检测到S1传感器有效时,说明水位超过了S1,状态跳转到S1;其他情况则保持水位不变。
S1:水位在S1~S2。当检测到S2传感器有效时,说明水位超过了S2,状态跳转到S2;当检测到S1传感器无效时,说明水位在S1之下,状态跳转到S0;其他情况则保持水位不变。
S2:水位在S2~S3。当检测到S3传感器有效时,说明水位超过了S3,状态跳转到S3;当检测到S2传感器无效时,说明水位在S2之下,状态跳转到S1;其他情况则保持水位不变。
S3:水位超过S3。当检测到S3传感器无效时,说明水位在S3之下,状态跳转到S2;其他情况则保持水位不变。
输出FR1、FR2、FR3根据所在状态对照上图进行输出即可。

dfr的输出原则是水位发生了下降则dfr输出1,所以需要比较次态和现态的关系。举例,若现态为S1,次态为S0,则说明水位下降,dfr输出1;若现态为S1,次态为S2,则说明水位上升,dfr输出0;若现态为S1,次态为S1,则说明水位不变,dfr输出不变(dfr <= dfr)。

module top_module(
    input 		clk		,			//输入时钟
    input 		reset	,           //高电平有效的复位信号
    input [3:1]	s		,           //输入信号	
	output 		fr3		,			//输出信号
    output 		fr2		,			//输出信号
    output 		fr1		,           //输出信号
    output 		dfr					//输出信号
);
 
//------------<状态机参数定义>------------------------------------------
//使用独热码进行状态定义
parameter	S0 = 4'b0001	, 		//低于S1
			S1 = 4'b0010	, 		//S1~S2
			S2 = 4'b0100	, 		//S2~S3
			S3 = 4'b1000	; 		//超过S3
 
//------------<reg定义>-------------------------------------------------
reg	[3:0]	cur_state	,			//定义现态寄存器 
			next_state	;			//定义次态寄存器
 
//三段式状态机第一段:同步时序描述状态转移
always @(posedge clk) begin    
	if(reset)
		cur_state <= S0;
	else 
		cur_state <= next_state;
end
 
//三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
always @(*) begin
	if(reset)
		next_state = S0;
	else
		case(cur_state)
				S0:	
					if(s == 3'b001)			//检测到S1传感器,代表水位上升,水位在S1-S2
						next_state = S1;
					else					//水位无变化
						next_state = S0;
				S1:	
					if(s == 3'b011)			//检测到S1、S2传感器,代表水位上升,水位超过了S2-S3
						next_state = S2;
					else if(s == 3'b000)	//没有检测到传感器,代表水位下降,水位在S1之下
						next_state = S0;	
					else					//水位无变化
						next_state = S1;
				S2:	
					if(s == 3'b111)			//检测到S1、S2、S3传感器,代表水位上升,水位超过了S3
						next_state = S3;
					else if(s == 3'b001)	//检测到S1传感器,代表水位下降,水位在S1-S2
						next_state = S1;	
					else					//水位无变化
						next_state = S2;
				S3:	
					if(s == 3'b011)			//检测到S1、S2传感器,代表水位下降,水位超过了S2-S3
						next_state = S2;
					else					//水位无变化
						next_state = S3;					
				default:next_state = S0;
		endcase
end
 
//三段式状态机第三段:时序逻辑描述输出
always @(posedge clk) begin   
    if(reset)begin
		fr1 <= 1'b1;
		fr2 <= 1'b1;
		fr3 <= 1'b1;
		dfr <= 1'b1;
	end
	else 
		case(next_state)
			S0:begin
				fr1 <= 1'b1;
				fr2 <= 1'b1;
				fr3 <= 1'b1;
				dfr <= 1'b1;				
			end	
			S1:begin
				fr1 <= 1'b1;
				fr2 <= 1'b1;
				fr3 <= 1'b0;
				if (cur_state == S0)			//上一个状态是S0,说明水位升高了
					dfr <= 1'b0;				//不打开开关
				else if (cur_state == S1)		//上一个状态是S1,说明水位没变化
					dfr <= dfr;					//开关保持不变
				else 							//上一个状态是S2,说明水位降低了
					dfr <= 1'b1;				//打开开关					
			end		
			S2:begin
				fr1 <= 1'b1;
				fr2 <= 1'b0;
				fr3 <= 1'b0;
				if (cur_state == S1)			//上一个状态是S1,说明水位升高了
					dfr <= 1'b0;				//不打开开关
				else if (cur_state == S2)		//上一个状态是S2,说明水位没变化
					dfr <= dfr;					//开关保持不变
				else 							//上一个状态是S3,说明水位降低了
					dfr <= 1'b1;				//打开开关					
			end	
			S3:begin
				fr1 <= 1'b0;
				fr2 <= 1'b0;
				fr3 <= 1'b0;
				if (cur_state == S2)			//上一个状态是S2,说明水位升高了
					dfr <= 1'b0;				//不打开开关				
				else 							//上一个状态是S3,说明水位没变化
					dfr <= dfr;					//开关保持不变					
			end		
			default:begin
				fr1 <= 1'b1;
				fr2 <= 1'b1;
				fr3 <= 1'b1;
				dfr <= 1'b1;			
			end	
		endcase
end
 
endmodule

31. (3.2.5.12)lemming3
在这里插入图片描述
当旅鼠处于地面(ground为1)走动时,一旦dig为1则旅鼠处于挖掘状态,digging输出1;直到ground为0则旅鼠处于掉落状态(aaah为1)
fall 的优先级高于 dig,而 dig 的优先级高于切换方向的优先级。
32. (3.2.5.14)FSM onehot
在这里插入图片描述

module top_module(
    input in,
    input [9:0] state,
    output [9:0] next_state,
    output out1,
    output out2);

    parameter 	s0=4'd0,
    			s1=4'd1,
    			s2=4'd2,
    			s3=4'd3,
    			s4=4'd4,
    			s5=4'd5,
    			s6=4'd6,
    			s7=4'd7,
    			s8=4'd8,
    			s9=4'd9;
    
    assign next_state[s0] = ~in&(state[s0]|state[s1]|state[s2]|state[s3]|state[s4]|state[s7]|state[s8]|state[s9]);
    assign next_state[s1] = in&(state[s0]|state[s8]|state[s9]);
    assign next_state[s2] = in&state[s1];
    assign next_state[s3] = in&state[s2];
    assign next_state[s4] = in&state[s3];
    assign next_state[s5] = in&state[s4];
    assign next_state[s6] = in&state[s5];
    assign next_state[s7] = in&(state[s6]|state[s7]);
    assign next_state[s8] = ~in&(state[s5]);
    assign next_state[s9] = ~in&(state[s6]);
    
    assign out1 = state[s8]|state[s9];
    assign out2 = state[s7]|state[s9];
endmodule

33. (3.2.5.15)FSM ps2
第一个状态D1判断接受数据流的起始字节,如果是起始字节,则紧接着的两个字节为数据流的一部分,数据流总共三个字节,接受完毕之后的下一个时钟周期,输出接受完毕信号Done,于此同时,判断是否接受到了下一个数据流的起始字节,如果是则继续接受下两个字节,否则进入状态D1,继续判断是否接受到起始字节。
在这里插入图片描述

module top_module(
    input clk,
    input [7:0] in,
    input reset,    // Synchronous reset
    output done); //
    
    reg [3:0]state,n_state;
    parameter s0=4'b0001,
    		s1=4'b0010,
    		s2=4'b0100,
    		s3=4'b1000;
    // State transition logic (combinational)
    always@(posedge clk)begin
        if(reset)
            state <= s0;
        else
            state <= n_state;
    end
    // State flip-flops (sequential)
    always@(*)begin
        if(reset)
            n_state = s0;
        else case(state)
            s0:
                if(in[3])
                    n_state = s1;
            	else 
                    n_state = s0;
            s1:
                n_state = s2;
            s2:
                n_state = s3;
            s3:
                if(in[3])
                    n_state = s1;
            	else
                    n_state = s0;
            default:;
        endcase  
    end
    // Output logic
    always@(posedge clk)begin
        if(reset)
            done <= 1'b0;
        else case(n_state)
            s3: done <= 1'b1;
            default:done <= 1'b0;
        endcase
    end
endmodule

34. (3.2.5.17)serial receiver
在这里插入图片描述
IDLE: 初始状态,检测到输入in为高电平后跳转到DATA状态,否则保持该状态
DATA: 在这个状态有个从0开始的计数器cnt,当计数器计数到7时,代表接收到了8-bit数据,计数到8时输入信号若为1,则代表该信号为终止信号,一次传输结束,跳转到状态STOP;若输入信号为0,则代表传输错误,跳转到状态ERROR,继续等待终止信号的到来;若计数器小于8,则保持该状态(传输未结束)
ERROR: 检测到输入in为0后代表传输依然错误,保持在该状态,继续检测终止信号;检测到输入in为1后代表传输结束,由于该次传输出现了错误,所以直接跳转到初始状态
STOP: 检测到输入in为0后代表检测到了一个新的起始信号,接下来就可以接收数据,所以跳转到状态DATA;若检测到输入in为1(空闲状态)则跳转到IDLE状态

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 

    reg [3:0]cnt;
    reg [3:0]state,n_state;
    parameter IDEL=	4'b0001,
    		DATA  =	4'b0010,
    		ERROR =	4'b0100,
    		STOP  =	4'b1000;
    always@(posedge clk)begin
        if(reset)
            state <= IDEL;
        else 
            state <= n_state;
    end
    always@(*)begin
        if(reset)
            n_state = IDEL;
        else case(state)
            IDEL:
                if(!in)
                    n_state = DATA;
            	else
                    n_state = IDEL;
            DATA:
                if(cnt == 4'd8)begin
                    if(in)
                    	n_state = STOP;
                    else
                        n_state = ERROR;
                end
                else
                    n_state = DATA;
            ERROR:
                if(in)
                    n_state = IDEL;
            	else
                    n_state = ERROR;
            STOP:
                if(!in)
                    n_state = DATA;
            	else
                    n_state = IDEL;
            default:
                n_state = IDEL;
        endcase  
    end
    
    always@(posedge clk)begin
        if(reset)
            done <= 1'b0;
        else case(n_state)
            STOP:done <= 1'b1;
            default:done <= 1'b0;
        endcase
    end
    
    always@(posedge clk)begin
        if(reset)
            cnt <= 4'd0;
        else if(state == DATA)begin
        	if(cnt==4'd8)
            	cnt <= 4'd0;
        	else
            	cnt <= cnt + 1'b1;    
   	 	end
        else
            cnt <= cnt;
    end
endmodule

35. (3.2.5.18)serial receiver and datapath
在上题的基础上增加一个将接收到的8-bit有效信号输出。
设计一个reg变量out_byte_temp去接收数据,在DATA状态, out_byte_temp通过移位操作完成串并转换,也就是接收了8-bit数据;在STOP状态,将out_byte_temp赋值给out_byte输出。
增加的程序

 reg [7:0]out_tmp;
 
 always@(posedge clk)begin
        if(reset)begin
            done <= 1'b0;
        end
        else case(n_state)
            STOP:begin
                done <= 1'b1;
                out_byte <= out_tmp;
            end
            default:begin
                done <= 1'b0;
                out_byte <= 'd0;
            end
        endcase     
    end
    
always@(posedge clk )begin
        if(reset)
            out_tmp <= 'd0;
        else if(n_state == DATA)   //注意这里是n_state
            out_tmp <= {in,out_tmp[7:1]};
        else
            out_tmp <= out_tmp;
    end

36. (3.2.5.19)serial receiver with parity checking 奇偶校验
parity: 在码流中每检测到一个1,则输出odd翻转一次,而数据位+奇校验位=9位数据中若满足要求则有奇数个1,那么odd输出则为1,若不满足校验要求,则是偶数个1使得校验位odd输出为0。也就是说这个奇偶校验模块实际上是一个判断位,用于对9位数据做奇校验判断。

因为只能使用该模块对9位数据做校验,所以在不接收9位数据的其他时态需要一定对该模块复位。

在上题的基础上,需要在STOP状态拉高done信号,在本题增加了奇校验后,需要在此模块同时对odd信号做判断,若为真,需说明校验成功,同时输出数据和拉高done信号;若为0,则说明数据接收时序没问题,但接收的数据不符合校验要求(传输过程出现错误),不输出数据、不拉高done信号。

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //

	wire odd;
    wire reset_odd;//复位信号无效或者在接收数据时,不对奇偶校验模块复位,其它时间一直对该模块复位
    reg [3:0]cnt;
    reg [7:0]out_tmp;
    reg [7:0]state,n_state;
    parameter IDEL	=4'b0001,
    		DATA	=4'b0010,
    		ERROR	=4'b0100,
    		STOP	=4'b1000;
//状态机第一段
    always@(posedge clk)begin
        if(reset)
            state <= IDEL;
        else 
            state <= n_state;
    end
    //状态机第二段
    always@(*)begin
        if(reset)
            n_state = IDEL;
        else case(state)
            IDEL:
                if(!in)
                    n_state = DATA;
            	else
                	n_state = IDEL;
            DATA:
                if(cnt=='d9)begin
                    if(in)
                    	n_state = STOP;
                    else
                        n_state = ERROR;
                end
            	else
                    n_state = DATA;
            ERROR:
                if(in)
                    n_state = IDEL;
            	else
                    n_state = ERROR;
            STOP:
                if(!in)
                    n_state = DATA;
            	else
                    n_state = IDEL;
            default:n_state = IDEL;
        endcase
    end
    //状态机第三段
    always@(posedge clk)begin
        if(reset)
            done <= 1'b0;
        else case(n_state)
            STOP:begin
                if(odd)
                    done <= 1'b1;
                else 
                	done <= 1'b0;
             	out_byte <= out_tmp;
            end
            default:begin
                done <= 1'b0;
                out_byte <= 'd0;
            end
        endcase
    end
    //输出数据计数器
    always@(posedge clk)begin
        if(reset)
            cnt <= 'd0;
        else if(state == DATA)begin
            if(cnt == 'd9)
                cnt <= 'd0;
            else 
                cnt <= cnt + 1'b1;
        end
        else
            cnt <= cnt;
    end
    //数据寄存
    always@(posedge clk)begin
        if(reset)
            out_tmp <= 'd0;
        else if(state == DATA && cnt <= 'd7)
            out_tmp <= {in,out_tmp[7:1]};
        else
            out_tmp <= out_tmp;
    end
   //奇偶校验复位,在不接收9位数据的其他时态需要一定对该模块复位。
    assign reset_odd = reset | (!(state == DATA));
    
parity parity(
    .clk	(clk),
    .reset	(reset_odd),
    .in		(in),
    .odd	(odd)
);
    
endmodule

37. (3.2.5.20)sequence recognition 序列检测
检测到连续的5个1就拉高disc一个周期(一定要是111_110这种结构,不能是11111_1这种结构,这种属于检测到了连续的6个1,下同);检测到连续的6个1就拉高flag一个周期;检测到连续的7个1就拉高flag一个周期;检测到连续的8个1就拉高flag2个周期(从第7个开始,1越多flag高电平的时间越长)。

module top_module(
    input 	clk,
    input 	reset,    // Synchronous reset
    input 	in,
    output 	disc,
    output 	flag,
    output 	err
);
//定义状态机状态
parameter	S    = 4'd0,	
			S1   = 4'd1,	
			S2   = 4'd2,	
			S3   = 4'd3,	
			S4   = 4'd4,	
			S5   = 4'd5,	
			DISC = 4'd6,	
			S6   = 4'd7,	
			FALG = 4'd8,	
			S7   = 4'd9,
			ERRO = 4'd10;
reg	[3:0]	cur_state, next_state	;   		
//三段式状态机第一段					
always @(posedge clk)begin
	if(reset)
		cur_state <= S;
	else
		cur_state <= next_state;
end
//三段式状态机第二段
always@(*)begin
	next_state = S;
	case(cur_state)
		S		: 	next_state = in ? S1 : S;
		S1		: 	next_state = in ? S2 : S;
		S2		: 	next_state = in ? S3 : S;
		S3		: 	next_state = in ? S4 : S;
		S4		: 	next_state = in ? S5 : S;
		S5		: 	next_state = in ? S6 : DISC;
		S6		: 	next_state = in ? ERRO : FALG;
        DISC	: 	next_state = in ? S1 : S;
		FALG	: 	next_state = in ? S1 : S;	
		ERRO	: 	next_state = in ? ERRO : S;	
		default	:	next_state = S;
	endcase
end	
//三段式状态机第三段
always @(posedge clk)begin
	if(reset)begin
		disc <= 1'b0;
		flag <= 1'b0;
		err  <= 1'b0;
	end
	else
		case(next_state)				
			DISC:begin
				disc <= 1'b1;			
				flag <= 1'b0;
				err  <= 1'b0;
			end
			FALG:begin
				disc <= 1'b0;
				flag <= 1'b1;
				err  <= 1'b0;
			end
			ERRO:begin
				disc <= 1'b0;
				flag <= 1'b0;
				err  <= 1'b1;
			end			
			default:begin
				disc <= 1'b0;
				flag <= 1'b0;
				err  <= 1'b0;
			end
		endcase
end
 
endmodule

**38. (3.2.5.21)design a mealy FSM **
实现一个 Mealy 型有限状态机,该状态机可识别名为 x 的输入信号上的序列“101”。您的 FSM 应该有一个输出信号 z,当检测到“101”序列时,该信号被断言到 logic-1。您的 FSM 还应该具有低位有效异步复位。状态机中可能只有 3 种状态。您的 FSM 应该可以识别重叠的序列。
在这里插入图片描述
S :初始状态,检测到1后跳转到状态S1,不然保持在该状态,输出均为0
S1:检测到0后跳转到S2,检测到1维持在该状态
S2 :此时已经检测到了“10”,若继续检测到1,则“101”检测成功,状态跳转到S1(重复检测),且输出1;若检测到0,则跳转到S

module top_module (
    input clk,
    input aresetn,    // Asynchronous active-low reset
    input x,
    output z ); 

    parameter s0=3'b001,//初始状态
    		s1=3'b010,//
    		s2=3'b100;
    reg[2:0]state, n_state;
    always@(posedge clk or negedge aresetn)begin
        if(!aresetn)
            state <= s0;
        else
            state <= n_state;
    end
    
    always@(*)begin
        if(!aresetn)
            n_state = s0;
        else case(state)
            s0:
                if(x)
                    n_state = s1;
            	else
                    n_state = s0;
            s1:
                if(!x)
                    n_state = s2;
            	else
                    n_state = s1;
            s2:
                if(x)
                    n_state = s1;//重叠检测
            	else
                    n_state = s0;
            default:n_state =  s0;               
        endcase
    end
     
    assign z = (state == s2 && x == 1'b1) ? 1'b1 : 1'b0; //mealy状态机少一个状态,输出时条件需加上最后一个状态的条件
    //输出使用时序逻辑会延后一个周期
endmodule

米利型和摩尔型的区别

39. (3.2.5.22)Serial two’s complementer (moore FSM)补码状态机
二进制补码:从LSB到MSB,第一个1时正式开始补码输出1,之后则开始取反(遇1输出0,遇0输出1。

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 
    reg [2:0]state,n_state;
    parameter A=3'b001,
    		B=3'b010,
    		C=3'b100;
    
    always@(posedge clk or posedge areset)begin
        if(areset) 
            state <= A;
        else
            state <= n_state;
    end
        
    always@(*)begin
        if(areset)
            n_state = A;
        else case(state)
            A: n_state = (x==1) ? B : A;
            B: n_state = (x==1) ? C : B;
            C: n_state = (x==1) ? C : B;
            default: n_state = A;
        endcase
    end
    
    assign z = (state == B) ;//取现态而不是次态
endmodule

40. (3.2.5.23)Serial two’s complementer (mealy FSM)补码状态机
在这里插入图片描述
A:检测到1,立马输出1,且跳转到下一个状态B;检测到0则继续保持该状态,说明没有检测到第一个1
B: 检测到0,则输出相反的1,状态不变;检测到1,则输出相反的0,状态不变

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 
    reg [1:0]state,n_state;
    parameter A=2'b001,
    		B=2'b010;
    
    always@(posedge clk or posedge areset)begin
        if(areset) 
            state <= A;
        else
            state <= n_state;
    end
        
    always@(*)begin
        if(areset)
            n_state = A;
        else case(state)
            A: n_state = (x==1) ? B : A;
            B: n_state = B;
            default: n_state = A;
        endcase
    end
    
    assign z = (state==A && x==1) | (state == B && x==0) ;
    
endmodule

41. (3.2.5.24)Q3a FSM
大概意思是状态机复位状态在A,检测到s为1后进入状态B,在状态B每隔三个时钟周期就检查一次这三个时钟周期内w为高的时钟周期个数是否为2,若是则拉高输出z一个周期。

状态机设计两个状态A、B。在状态B设计一个计数器1从0-2循环计数,这样就把B状态分隔成了每3个周期的小段。再设计一个计数器2,来计数输入w为1的个数。这样就可以根据w为高的次数来对应的拉高输出z。

module top_module (
    input clk,
    input reset,   // Synchronous reset
    input s,
    input w,
    output z
);
    reg [1:0]cnt1,cnt2;
    reg [1:0]state,n_state;
    parameter A=2'b01,
    		B=2'b10;
    
    always@(posedge clk)begin
        if(reset)
            state <= A;
        else
            state <= n_state;
    end
    
    always@(*)begin
        if(reset)
            n_state = A;
        else case(state)
            A:
                if(s==1)
                    n_state = B;
            	else
                    n_state = A;
            B:
                n_state = B;
        endcase
    end
    
    always@(posedge clk)begin
        if(reset)
            z <= 1'b0;
        else case(n_state)
            A: z <= 1'b0;
            B:
                if(cnt1=='d2)begin
                    if((cnt2=='d1&&w)|(cnt2=='d2&&!w))
                        z <= 1'b1;
                    else
                        z <= 1'b0;
                end
            	else
                	z <= 1'b0;
            default: z<= 1'b0;             
        endcase
    end    
      
    always@(posedge clk)begin
        if (reset)
            cnt1 <= 'd0;
        else if(state == B)begin
            if(cnt1=='d2) 
                cnt1 <= 'd0;
            else
                cnt1 <= cnt1 + 1'b1;
        end
        else
            cnt1 <= 'd0;
    end
    
    always@(posedge clk)begin
        if(reset)
            cnt2 <= 'd0;
        else if(state == B)begin
            if(cnt1=='d2)
                cnt2 <= 'd0;
            else if(w)
                cnt2 <= cnt2 + 1'b1;
            else
                cnt2 <= cnt2;         
        end 
        else
            cnt2 <= 'd0;
    end
    
endmodule

42. (3.2.5.26)Q3c FSM logic
在这里插入图片描述
这题基本上跟上题是一样的,只不过现态变成了输入,而不是中间变量。

module top_module (
    input clk,
    input [2:0] y,
    input x,
    output Y0,
    output z
);
    reg [2:0]state,n_state;
    parameter A=3'b000,
    		B=3'b001,
    		C=3'b010,
    		D=3'b011,
    		E=3'b100;
   always@(*)begin
        case(y)
            A: n_state = (x) ? B : A;
            B: n_state = (x) ? E : B;
            C: n_state = (x) ? B : C;
            D: n_state = (x) ? C : B;
            E: n_state = (x) ? E : D;
            default:n_state = A;
        endcase
    end
    
    assign Y0 = (n_state == B)|(n_state == D);
    assign z = (y == D)|(y == E);
    
endmodule

43. (3.2.5.28)Q6c FSM one-hot next-state logic
为下一状态信号 Y2 和 Y4 编写逻辑表达式

always @(*) begin
        next_state[0]    <=  w ? y[1] || y[4] : 1'b0;
        next_state[1]    <=  w ? 1'b0 : y[1];
        next_state[2]    <=  w ? 1'b0 : y[6] || y[2];
        next_state[3]    <=  w ? y[2] || y[3] || y[5] || y[6]: 1'b0;
        next_state[4]    <=  w ? 1'b0 : y[5] || y[3];
        next_state[5]    <=  w ? 1'b0 : y[4];
    end
 
assign  Y2   =   next_state[1];
assign  Y4   =   next_state[3];

 always@(*)begin
        case(y[6:1]) 
            A:next=w?A:B;
            B:next=w?D:C;
            C:next=w?D:E;
            D:next=w?A:F;
            E:next=w?D:E;
            F:next=w?D:C;
            default:;
        endcase
    end
assign Y2 = y[1]&&(~w);
assign Y4  = w&&(y[2] || y[3] || y[5] || y[6]);

44. (3.2.5.33)another FSM
只要断言了复位输入,FSM就保持在开始状态,称为状态a。当复位信号被取消断言时,下一个时钟边缘之后,FSM必须将输出f设为1,持续一个时钟周期。然后,FSM必须监控x的输入。当x在三个连续的时钟周期中产生值1,0,1时,那么g应该在下一个时钟周期中设为1。当g = 1时,FSM必须监控y的输入。如果在最多两个时钟周期内y值为1,则FSM需要永久保持g = 1(即直到复位)。但是如果在两个时钟周期内y没有变为1,则FSM应该将g永久设置为0(直到复位)。

IDLE : 初始状态,复位结束后跳转到状态OUT_F
OUT_F: 这个状态用来将f拉高一个时钟周期
S : 序列“101”检测的初始状态,若检测到x为1,则跳转到状态S1;若检测到,则保持该状态
S1 : 若检测到x为0,则跳转到状态S10;若检测到x为1,则保持该状态
S10 : 若检测到x为1,则跳转到状态S101;若检测到x为0,则跳转到状态S
S101 : 此时已经检测到了序列“101”,需要判断接下来y是否变成了1:若检测到y为1,则跳转到状态P1,说明输 出g应该永久拉高;若检测到y为0,说明第一个周期不满足条件,则跳转到状态JUG,在状态JUG在判断是否满足条件
P1 : 永远保持在此状态,用来输出永恒的g=1
JUG : 若检测到y为1,则跳转到状态P1,说明输出g应该永久拉高;若检测到y为0,则跳转到状态P0,说明输出g应该永久拉拉低
P0 : 永远保持在此状态,用来输出永恒的g=0
在这里插入图片描述

module top_module (
    input clk,
    input resetn,    // active-low synchronous reset
    input x,
    input y,
    output f,
    output g
); 
    reg [3:0]state,n_state;
    parameter IDEL=4'b0000,		//初始状态
    		OUT_F	=4'b0001,	//输出f的状态
    		C	=4'b0010,		//检测“101”序列的初始状态
    		C1	=4'b0011,		//检测‘1’
    		C10	=4'b0100,		//检测‘10’
    		C101=4'b0101,		//检测‘101’
    		G1	=4'b0110,		//输出永久的g=1
    		E	=4'b0111,		//检测
    		G0	=4'b1000;		//输出永久的g=0
    		
    always@(posedge clk)begin
        if(!resetn)
            state <= IDEL;
        else
            state <= n_state;
    end
    always@(*)begin
        if(!resetn)
            n_state = IDEL;
        else case(state)
            IDEL: n_state = OUT_F;
            OUT_F:n_state = C;
            C:	  n_state = (x) ? C1  :C;
            C1:	  n_state = (!x)? C10 :C1;  //如果是0则变为10正确,如果是1则11继续检测0
            C10:  n_state = (x) ? C101:C;   //如果是1则跳到101正确,如果是0则100检测错误回到序列检测初始状态
            C101: n_state = (y) ? G1 : E;    //y=1则跳到G1永久输出g=1,y=0则跳到E继续检测
            G1:	  n_state = G1;
            E:	  n_state = (y) ? G1 : G0;       //y=1则跳到G1永久输出g=1,y=0则跳到G0输出g=0
            G0:	  n_state = G0;
            default: n_state = IDEL;
        endcase
    end
    always@(posedge clk)begin
        if(!resetn)begin
            f <= 1'b0;
            g <= 1'b0;
        end
        else case(n_state)
            OUT_F:f<=1'b1;
            C101:g<=1'b1;//
            G1:g<=1'b1;
            E:g<=1'b1;	                     //C101和E状态也输出g=1
            default:begin
            	f <= 1'b0;
            	g <= 1'b0;
        	end
        endcase 
    end
endmodule

45. (3.3.4)enable shift register
为控制移位寄存器的FSM的一部分,我们希望能够在检测到合适的位模式时,使移位寄存器精确地为4个时钟周期。我们在Exams/review2015_fsmseq中处理序列检测,所以FSM的这部分只处理4个周期的移位寄存器启用。
当FSM被重置时,置位shift_ena 4个周期,然后0永远(直到重置)。

这道题的意思是,如果复位信号有效,shift_ena信号就为1;当复位信号撤销以后,shift_ena信号保持4个周期高电平后变为0。
使用一个计数器计数,reset该计数器复位到0,shift_ena高电平期间计数(在此期间计数0-3),计数到3后计数器清零。
shift_ena在复位有效后拉高,在计数器计数到3后拉低。

module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);
    
    reg [3:0]cnt;
    always@(posedge clk)begin
        if(reset)
            shift_ena <= 1'b1;
        else if(cnt == 'd3)
            shift_ena <= 1'b0;
        else
            shift_ena <= shift_ena;
    end
            
	always@(posedge clk)begin
	    if(reset)
	        cnt <= 'd0;
        else if(shift_ena)    //shift_ena有效时cnt自加
	        cnt <= cnt + 1'b1;
	    else
	        cnt <= cnt;
	end
endmodule

46. (3.3.5)FSM:The complete FSM
首先检测序列“1101”,检测到后停止检测,拉高shift_ena4个时钟周期,然后拉高counting直到输入done_counting为1,然后拉高done直到输入ack为1。
在这里插入图片描述
S:初始状态,开始检测1101序列的第一个1,若检测到1,则跳转到S1,若检测到0,则保持该状态
S1:若检测到1,则说明可能是1101序列的第二个1,所以状态跳转到S11, 若检测到0,则状态跳转到S,去检测1101的第一个1
S11:若检测到0,则说明可能是1101序列的0,所以状态跳转到S110, 若检测到1,则保持在该状态
S110:若检测到1,则说明是1101序列的最后一个1,所以状态跳转到B0, 若检测到0,则状态跳转到S,去检测1101的第一个1
B0:直接跳转到B1
B1:直接跳转到B2
B2:直接跳转到B3
B3:直接跳转到COUNT
COUNT:当counting为1时跳转到状态WAIT,不然一直停留在该状态
WAIT:当ack为0时跳转到状态S,不然一直停留在该状态

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output shift_ena,
    output counting,
    input done_counting,
    output done,
    input ack );
	
    reg [3:0]cur_state,next_state;
    parameter	S     = 4'd0,
			S1    = 4'd1,
			S11   = 4'd2,
			S110  = 4'd3,
			B0    = 4'd4,
			B1    = 4'd5,
			B2    = 4'd6,
			B3    = 4'd7,
			COUNT = 4'd8,
			WAIT  = 4'd9;

    always@(posedge clk)begin
        if(reset) 
            cur_state <= S;
        else
            cur_state  <= next_state;
    end
    
    always@(*)begin
        //if(reset) 
            //next_state = S;
        //else 
            case(cur_state)
            S:
                next_state = (data) ? S1 :S;
            S1:
                next_state = (data) ? S11 :S;
			S11:
                next_state = (!data) ? S110 :S11;
			S110:
                next_state = (data) ? B0 :S;//如果data为1则检测到序列1101,立刻跳到B0状态,不需要状态1101,加这个状态会延后一个周期
			B0:
                next_state = B1;
			B1:
                next_state = B2;
			B2:
                next_state = B3;
			B3:
                next_state = COUNT;
			COUNT:
                next_state = (done_counting) ? WAIT : COUNT;
			WAIT:
                next_state = (ack) ? S : WAIT;
            default: next_state = S;
        endcase
    end

    assign shift_ena = (cur_state == B0)||(cur_state == B1)||(cur_state == B2)||(cur_state == B3);
    assign counting = (cur_state == COUNT);
    assign done = (cur_state == WAIT);
  
endmodule

47. (3.3.6)the complete timer
在数据流中检测到序列 1101 后,电路需要将接下来的 4bit 数据移入移位寄存器。4bit 数据决定了计数器的计数周期,称为 delay[3:0]。首先到达的比特作为数据的高位。在 FSM 中增加计数器状态,计数周期为 (delay[3:0] + 1 )* 1000 个时钟周期。同时输出 count 当前剩余的计数周期,输出当前剩余计数周期的千位(比如,还剩1000个周期输出 1,还剩 999 个周期时输出 0)。当计数停止后,count 的输出可以为任意数。

当计数完成后,电路置高 done 信号通知上层应用计数器计数完成,等待 ack 信号置高后,状态机清除 done 信号,返回空闲状态等待捕获下一个 1101 序列。

在这里插入图片描述

思路:
首先需要找到序列“1101”,接下来的码流输出的4个数据(高位在前)+1,再乘以1000,就是接下来要延时的时间。延时完成后,拉高done,直到ack拉高(响应了),再重新开始新一轮。count输出的是计数的千位数,比如计数器还是1999,那么输出为1。

S : 初始状态,检测到1,则跳转到S1,否则保持该状态
S1 : 检测到1,则跳转到S11,否则跳转到S
S11 : 检测到0,则跳转到S110,否则保持该状态
S110 : 检测到1,则跳转到DELAY ,否则跳转到S
DELAY : 在次状态延时4个时钟周期(cnt_delay从0-3),用来接收输入码流上接下来的4个数据,作为延时的时间
COUNT : 延时状态,直到延时到指定的时间
WAIT : 在次状态等待akc响应信号

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output [3:0] count,
    output counting,
    output done,
    input ack );

    reg [15:0]cnt;
    reg [1:0]cnt_delay;
    reg [3:0]delay;
    
    reg[2:0]state,n_state;
    parameter S		= 3'd0,
    		S1		= 3'd1,
    		S11		= 3'd2,
    		S110	= 3'd3,
    		DELAY	= 3'd4,
    		COUNT	= 3'd5,
    		WAIT	= 3'd6;
    always@(posedge clk)begin
        if(reset)
            state  <= S;
        else
            state <= n_state;
    end
    always@(*)begin
        if(reset)
            n_state  = S;
        else case(state)
            S:
                n_state = (data) ? S1 : S;
            S1:		
                n_state = (data) ? S11 : S;
			S11:
                n_state = (!data) ? S110 : S11;
			S110:
                n_state = (data) ? DELAY : S;
			DELAY:begin
            	    if(cnt_delay=='d3)
            	    	n_state = COUNT;
            	    else
            	        n_state = DELAY;
            	end
			COUNT:begin
                if(cnt=='d0)
            	    	n_state = WAIT;
            	    else
            	        n_state = COUNT;
            	end
			WAIT:
                n_state = (!ack) ? WAIT : S;
            default: n_state = S;
        endcase
    end
    
    assign count = cnt/1000;
    assign counting=(state == COUNT);
    assign done = (state == WAIT);
    
    always@(posedge clk)begin
        if(reset)
            cnt <= 'd0;
        else if(state == DELAY)
            cnt <= (delay + 1'b1) *1000 -1'b1;
        else if(state == COUNT)
            cnt <= cnt - 1'b1;
        else
            cnt <= cnt;
    end
        
    always@(posedge clk)begin
        if(reset)
            cnt_delay <= 'd0;
        else if(state == DELAY)
           cnt_delay <= cnt_delay + 1'b1; 
       else
           cnt_delay <= cnt_delay;     
    end
    always@(*)begin
        if(state == DELAY)
            case(cnt_delay)
                0: delay[3] = data;
                1: delay[2] = data;
                2: delay[1] = data;
                3: delay[0] = data;
                default:;
            endcase
        else
            delay = 4'b0000;
    end
endmodule

48. (3.3.7)FSM:one-hot logic equations
在这里插入图片描述

module top_module(
    input d,
    input done_counting,
    input ack,
    input [9:0] state,    // 10-bit one-hot current state
    output B3_next,
    output S_next,
    output S1_next,
    output Count_next,
    output Wait_next,
    output done,
    output counting,
    output shift_ena
); //

    // You may use these parameters to access state bits using e.g., state[B2] instead of state[6].
    parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;
   
    assign B3_next = (state[B2]);
    assign S_next = (!d && state[S]) || (!d && state[S1]) || (!d && state[S110]) || (ack && state[Wait]);
    assign S1_next = (d && state[S]); 
    assign Count_next = (state[B3])||(!done_counting && state[Count]);
    assign Wait_next = (done_counting && state[Count]) || (!ack && state[Wait]);
    assign done = (state[Wait]);
    assign counting = (state[Count]);
    assign shift_ena = (state[B0])||(state[B1])||(state[B2])||(state[B3]);
    
endmodule

49. (4.2.5)combinational circuit 5
根据下面的时序图实现这个组合逻辑电路。
在这里插入图片描述
可以看出这是一个4输入、1输出的组合电路,且输出是根据c的取值来的,所以这个是个4选1电路(MUX4),所以可以用case语句来根据c的取值来进行输出。

 module top_module (
    input [3:0] a,
    input [3:0] b,
    input [3:0] c,
    input [3:0] d,
    input [3:0] e,
    output [3:0] q );
 
    always@(*)begin
        case(c)
            4'd0:		q = b;
        	4'd1:		q = e;
            4'd2:		q = a;
        	4'd3:		q = d;
         	default:   	q = 4'hf;
        endcase
    end
endmodule

50. (4.2.10)sequential circuit 10
在这里插入图片描述
可以看到当输出q为高电平时,a、b、state三个中总是有奇数个高电平,所以q是a、b、state三个的偶校验位:q = a ^ b ^ state;

再来观察state的变化,state的变化都发生在(a == b)时,且变化的值为a(或者说b),当a不等于b时,state保持不变。

module top_module (
    input clk,
    input a,
    input b,
    output q,
    output state  );
 
    assign q = a ^ b ^ state;
    
    always @(posedge clk)begin
        if(a == b)
        	state <= a;
        else
            state <= state;
    end
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值