FPGA基础模块练习(基于牛客刷题)4

VL25 输入序列连续的序列检测

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);

	reg [2:0]cnt;
	always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
	cnt<=3'b000;
	else if(cnt==3'd7)
	cnt<=0;
	else
	cnt<=cnt+3'b1;
	end

	reg sig1,sig2,sig3,sig4,sig5,sig6,sig7,sig8;
	always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		sig1<=1'b0;
		sig2<=1'b0;
		sig3<=1'b0;
		sig4<=1'b0;
		sig5<=1'b0;
		sig6<=1'b0;
		sig7<=1'b0;
		sig8<=1'b0;
	end
	else
		case(cnt)
		3'b000: sig1=(a==0)?1:0;
		3'b001: sig2=(a==1)?1:0;
		3'b010: sig3=(a==1)?1:0;
		3'b011: sig4=(a==1)?1:0;
		3'b100: sig5=(a==0)?1:0;
		3'b101: sig6=(a==0)?1:0;
		3'b110: sig7=(a==0)?1:0;
		3'b111: sig8=(a==1)?1:0;
  default: begin		
		sig1<=1'b0;
		sig2<=1'b0;
		sig3<=1'b0;
		sig4<=1'b0;
		sig5<=1'b0;
		sig6<=1'b0;
		sig7<=1'b0;
		sig8<=1'b0; 
		end
	endcase
	end
	always@(*)
	if(!rst_n)
	match<=1'b0;
	else
	match=sig1&sig2&sig3&sig4&sig5&sig6&sig7;

endmodule

我用这种方法进行计算,但是数据不对,经过debug可知,实际输入数据是一长串,而并非简单的输入8位判断8位,因此需要换一种思路去求解。

官方解答方案:

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);

	reg [7:0] a_tem;
	
	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			begin 
				match <= 1'b0;
			end
		else if (a_tem == 8'b0111_0001)
			begin
				match <= 1'b1;
			end
		else 
			begin	
				match <= 1'b0;
			end
		
	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			begin 
				a_tem <= 8'b0;
			end
		else 
			begin
				a_tem <= {a_tem[6:0],a};
			end
endmodule

按照官方思路,利用状态机进行求解:

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);

reg [3:0]state;
reg matchbuf;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
match<=1'b0;
state<=1'b0;
end
else
 	case(state)
		4'b0000: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b0001:4'b000; match=0; end
		4'b0001: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b0010:4'b000; match=0; end
		4'b0010: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b0011:4'b000; match=0; end
		4'b0011: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b0100:4'b000; match=0; end
		4'b0100: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b0101:4'b000; match=0; end
		4'b0101: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b0110:4'b000; match=0; end
		4'b0110: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b0111:4'b000; match=0; end
		4'b0111: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b1000:4'b000; match=0; end
		4'b1000: begin match=1;state=4'b0000;end
	default: begin state=4'b0000;match=0;end
	endcase
endmodule

VL26 含有无关项的序列检测

与上一题类似,直接照抄修改即可:

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);
reg [3:0]state;
reg matchbuf;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
	match<=1'b0;
	state<=1'b0;
end
else
 	case(state)
		4'b0000: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b0001:4'b000; match=0; end
		4'b0001: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b0010:4'b000; match=0; end
		4'b0010: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b0011:4'b000; match=0; end
		// 4'b0011: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b0100:4'b000; match=0; end
		// 4'b0100: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b0101:4'b000; match=0; end
		// 4'b0101: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b0110:4'b000; match=0; end
		4'b0011: begin state=4'b0100; match=0; end
		4'b0100: begin state=4'b0101; match=0; end
		4'b0101: begin state=4'b0110; match=0; end
		4'b0110: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b0111:4'b000; match=0; end
		4'b0111: begin matchbuf=(a==1)?1:0; state=(a==1)?4'b1000:4'b000; match=0; end
		4'b1000: begin matchbuf=(a==0)?1:0; state=(a==0)?4'b1001:4'b000; match=0; end
		4'b1001: begin match=1;state=4'b0000;end
		// 4'b1000: begin match=1;state=4'b0000;end
	default: begin state=4'b0000;match=0;end
	endcase
  
endmodule

为了能够合理使用三段式状态机,因此我按照三段式状态机进行重新编写。

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);
	reg [3:0]state;
	reg [3:0]nextstate;
	reg matchbuf;
	//状态转换状态机
	always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		state<=4'b0000;
	else
		state<=nextstate;
	end

	//输出状态机
	always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		match<=0;
	else if(state==4'b1001)
		match<=1;
	else
		match<=0;
	end

	//组合逻辑状态机,描述不同状态的不同性能
	always@(*)begin
		case(state)
		4'b0000: begin nextstate=(a==0)?4'b0001:4'b000;	matchbuf=0;end
		4'b0001: begin nextstate=(a==1)?4'b0010:4'b000; matchbuf=0;end
		4'b0010: begin nextstate=(a==1)?4'b0011:4'b000; matchbuf=0;end
		4'b0011: begin nextstate=4'b0100; matchbuf=0;end
		4'b0100: begin nextstate=4'b0101; matchbuf=0;end
		4'b0101: begin nextstate=4'b0110; matchbuf=0;end
		4'b0110: begin nextstate=(a==1)?4'b0111:4'b000; matchbuf=0;end
		4'b0111: begin nextstate=(a==1)?4'b1000:4'b000; matchbuf=0;end
		4'b1000: begin nextstate=(a==0)?4'b1001:4'b000; matchbuf=0;end
		4'b1001: begin nextstate=4'b0000;matchbuf=1;end
		default: nextstate=4'b0000;
		endcase
	end
  
endmodule

费了点劲儿,不过感觉熟练了不少。妈的女朋友还在生气,13点04分,不想睡觉了继续做吧。

VL27 不重叠序列检测

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	output reg match,
	output reg not_match
	);
    
    parameter ZERO=0, ONE=1, TWO=2, THREE=3, FOUR=4, FIVE=5, SIX=6, FAIL=7;
    reg [2:0] state, nstate;
    reg [2:0] cnt;
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            cnt <= 0;
        else
            cnt <= cnt==6? 1: cnt+1; 
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            state <= ZERO;
        else
            state <= nstate;
    end
    
    always@(*) begin
        if(~rst_n)
            nstate = ZERO;
        else
            case(state)
                ZERO : nstate = data? FAIL : ONE;
                ONE  : nstate = data? TWO  : FAIL;
                TWO  : nstate = data? THREE: FAIL;
                THREE: nstate = data? FOUR : FAIL;
                FOUR : nstate = data? FAIL : FIVE;
                FIVE : nstate = data? FAIL : SIX;
                SIX  : nstate = data? FAIL : ONE;
                FAIL : nstate = cnt==6&&data==0? ONE: FAIL;
                default: nstate = ZERO;
            endcase
    end
    
    always@(*) begin
        if(~rst_n) begin
            match     = 0;
            not_match = 0;
        end
        else begin
            match     = cnt==6&&state==SIX;
            not_match = cnt==6&&state==FAIL;
        end
    end
    
endmodule

通过写状态机来解决这个问题。

VL28 输入序列不连续的序列检测

暂时先不做这个了,妈的有点麻最近,tp简历挂,劳资双九也能挂?

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	input data_valid,
	output reg match
	);

	reg [2:0] state;
	reg matchbuf;
	always@(posedge clk or negedge rst_n)
	if(!rst_n)begin
		match<=0;
		state<=3'b000;
	end
	else if(data_valid)begin
		case(state)
			3'b000: begin state=(data==0)?3'b001:3'b000; match=0;end
			3'b001: begin state=(data==1)?3'b010:3'b000; match=0;end
			3'b010: begin state=(data==1)?3'b011:3'b000; match=0;end
			3'b011: begin match=(data==0)?1:0; state=3'b100; end
			3'b100: begin state=3'b000; match=0;end
			default: begin state=3'b000; match=0;end
			// 3'b100: state=(data==1)?3'b011:3'b000;
		endcase
	end
	else
		match<=0;

endmodule

按照波形图实现该功能,测试一下用tb来调试这个程序。

`timescale 1ns/1ns
module testbench();

	reg clk,rst_n;
	reg data;
	reg data_valid;
	wire match;

always#1 clk = ~clk;

initial begin
	$dumpfile("out.vcd");
	$dumpvars(0,testbench);
	clk = 1;
	rst_n = 0;
	data = 0;
	data_valid = 0;
	#20;
	rst_n = 1;
	#2;
	data = 0;
	#2;
	data = 1;
	#2;
	data = 1;
	#2;
	data_valid = 1;
	#2;
	data = 1;
	#2;
	data = 0;
	#2;
	data = 1;
	#2;
	data = 0;
	#2;
	data = 0;
	#2;
	data_valid = 0;
	#2;
	data_valid = 1;
	data = 1;
	#2;
	data = 1;
	#2;
	data = 0;

	#80;
	$finish;

end

sequence_detect dut(
	.clk(clk),
	.rst_n(rst_n),

	.data(data),
	.data_valid(data_valid),
	.match(match)
);
endmodule

tb测试结果如下:

可见,在正确的位置出现了脉冲波形,证明了算法的可行性。

VL29 信号发生器

在波形图上提供出一个信息:

//方波的周期是20,锯齿波的周期是21,三角波的周期是40,且wave的最大值是20。

解答为:

`timescale 1ns/1ns
module signal_generator(
	input clk,
	input rst_n,
	input [1:0] wave_choise,
	output reg [4:0]wave
	);

    reg [4:0] cnt;
    reg flag;
    
  	// 方波模式下,计数器控制
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            cnt <= 0;
        else
            cnt <= wave_choise!=0 ? 0:
                   cnt        ==19? 0:
                   cnt + 1;
    end
    
  	// 三角波模式下,标志位控制
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            flag <= 0;
        else
            flag <= wave_choise!=2 ? 0:
                    wave       ==1 ? 1:
                    wave       ==19? 0:
                    flag;
    end
    
  
  	// 更新wave信号
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) 
            wave <= 0;
        else 
            case(wave_choise)
                0      : wave <= cnt == 9? 20    : 
                                 cnt ==19? 0     :
                                 wave;
                1      : wave <= wave==20? 0     : wave+1;
                2      : wave <= flag==0 ? wave-1: wave+1;
                default: wave <= 0;
            endcase
    end
endmodule

VL30 数据串转并电路

图中波形有一些问题,按照官方解法如下:

`timescale 1ns/1ns
module s_to_p(
	input 				clk 		,   
	input 				rst_n		,
	input				valid_a		,
	input	 			data_a		,
 
 	output	reg 		ready_a		,
 	output	reg			valid_b		,
	output  reg [5:0] 	data_b
);
reg 	[5:0]		data_reg;
reg 	[2:0]		data_cnt;

always @(posedge clk or negedge rst_n ) begin
	if(!rst_n) 
		ready_a <= 'd0;
	else 
		ready_a <= 1'd1;
end
always @(posedge clk or negedge rst_n ) begin
	if(!rst_n) 
		data_cnt <= 'd0;
	else if(valid_a && ready_a)
		data_cnt <= (data_cnt == 3'd5) ? 'd0 : (data_cnt + 1'd1);
end
always @(posedge clk or negedge rst_n ) begin
	if(!rst_n) 
		data_reg <= 'd0;
	else if(valid_a && ready_a)
		data_reg <= {data_a, data_reg[5:1]};
end

always @(posedge clk or negedge rst_n ) begin
	if(!rst_n)begin
		valid_b <= 'd0;
		data_b <= 'd0;
	end 
	else if(data_cnt == 3'd5)begin
		valid_b <= 1'd1;
		data_b <= {data_a, data_reg[5:1]};
	end
	else
		valid_b <= 'd0;
end
endmodule

VL32 非整数倍数据位宽转换24to128

麻了,这个位置是不固定的,需要修改不同的位数,解法如题,后续需要再仔细思考思考。

`timescale 1ns/1ns

module width_24to128(
	input 				clk 		,   
	input 				rst_n		,
	input				valid_in	,
	input	[23:0]		data_in		,
 
 	output	reg			valid_out	,
	output  reg [127:0]	data_out
);
    reg [3:0]   cnt;
    reg [127:0] data_lock;
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            cnt <= 0;
        else
            cnt <= ~valid_in? cnt:cnt+1;
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            valid_out <= 0;
        else
            valid_out <= (cnt==5 || cnt==10 || cnt==15)&&valid_in;
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            data_lock <= 0;
        else
            data_lock <= valid_in? {data_lock[103:0], data_in}: data_lock;
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            data_out <= 0;
        else if(cnt==5)
            data_out <= valid_in? {data_lock[119:0], data_in[23:16]}: data_out;
        else if(cnt==10)
            data_out <= valid_in? {data_lock[111:0], data_in[23: 8]}: data_out;
        else if(cnt==15)
            data_out <= valid_in? {data_lock[103:0], data_in[23: 0]}: data_out;
        else
            data_out <= data_out;
    end
endmodule

lv38 自动贩卖机

`timescale 1ns/1ns
module seller1(
	input wire clk  ,
	input wire rst  ,
	input wire d1 ,
	input wire d2 ,
	input wire d3 ,
	
	output reg out1,
	output reg [1:0]out2
);
//*************code***********//
reg [2:0]money;
always@(posedge clk or negedge rst)
if(!rst)
money<=0;
else if(d1)
money<=money+3'd1;
else if(d2)
money<=money+3'd2;
else if(d3)
money<=money+3'd4;
else if(money>3||money==3)
money<=0;

always@(posedge clk or negedge rst)
if(!rst)
out1<=0;
else if(money>3||money==3)
out1<=1;
else
out1<=0;

always@(posedge clk or negedge rst)
if(!rst)
out2<=0;
else if(money>3||money==3)
out2<=money-3'd3;
else
out2<=0;


//*************code***********//
endmodule

喜极而泣,第一次一遍过,没有用debug。

LV39 自动贩卖机2

`timescale 1ns/1ns

module seller2(
	input wire clk  ,
	input wire rst  ,
	input wire d1 ,
	input wire d2 ,
	input wire sel ,
	
	output reg out1,
	output reg out2,
	output reg out3
);
//*************code***********//
//0.17-0.192

reg [7:0]money;
always@(posedge clk or negedge rst)
if(!rst)
money<=0;
else if(d1)
money<=money+3'd1;
else if(d2)
money<=money+3'd2;
else if(~sel&&money==3)begin
money<=0;end
else if(~sel&&money==4)begin
money<=0;end
else if(sel&&money==5)begin
money<=0;end
else if(sel&&money==6)begin
money<=0;end

always@(posedge clk or negedge rst)
if(!rst)begin
	out1<=0;
	out2<=0;
	out3<=0;
end
else if(~sel&&money==3)begin
out1<=1;out2<=0;out3<=0;end
else if(~sel&&money==4)begin
out1<=1;out2<=0;out3<=1;end
else if(sel&&money==5)begin
out1<=0;out2<=1;out3<=0;end
else if(sel&&money==6)begin
out1<=0;out2<=1;out3<=1;end
else
begin
out1<=0;out2<=0;out3<=0;
end




//*************code***********//
endmodule

LV40 奇数分频

奇数分频通过设置上升沿和下降沿的两组分频后的时钟信号,进行or取并集,从而实现奇数分频。

代码如图:

`timescale 1ns/1ns


module odo_div_or
  #(parameter N = 7)
   (
    input    wire  rst ,
    input    wire  clk_in,
    output   wire  clk_out7
    );



   reg [3:0]            cnt ;
   always @(posedge clk_in or negedge rst) begin
      if (!rst) begin
         cnt    <= 'b0 ;
      end
      else if (cnt == N-1) begin
         cnt    <= 'b0 ;
      end
      else begin
         cnt    <= cnt + 1'b1 ;
      end
   end

   reg                  clkp ;
   always @(posedge clk_in or negedge rst) begin
      if (!rst) begin
         clkp <= 1'b0 ;
      end
      else if (cnt == (N>>1)) begin 
        clkp <= 1 ;
      end
      else if (cnt == N-1) begin 
        clkp <= 0 ;
      end
   end
  

   reg                  clkn ;
   always @(negedge clk_in or negedge rst) begin
      if (!rst) begin
         clkn <= 1'b0 ;
      end
      else if (cnt == (N>>1) ) begin 
        clkn <= 1 ;
      end
      else if (cnt == N-1) begin 
        clkn <= 0 ;
      end
   end


   assign clk_out7 = clkp | clkn ;


endmodule

按照同样的逻辑进行修改,代码为:

`timescale 1ns/1ns


module odo_div_or
  #(parameter N = 7)
   (
    input    wire  rst ,
    input    wire  clk_in,
    output   wire  clk_out7
    );

    reg [2:0]cnt;
    always@(posedge clk_in or negedge rst)
    if(!rst)
    cnt<=0;
    else if(cnt==6)
    cnt<=0;
    else
    cnt<=cnt+3'd1;

    reg clkp;
    always@(posedge clk_in or negedge rst)
    if(!rst)
    clkp<=0;
    else if(cnt==3)
    clkp<=1'd1;
    else if(cnt==6)
    clkp<=1'd0;

    reg clkn;
    always@(negedge clk_in or negedge rst)
    if(!rst)
    clkn<=0;
    else if(cnt==3)
    clkn<=1'd1;
    else if(cnt==6)
    clkn<=1'd0;

    assign clk_out7=clkn||clkp;


endmodule

经测试能够实现功能。

LV42 无占空比要求

奇奇怪怪,没啥意思,题目要求和答案不符合、。

`timescale 1ns/1ns

module odd_div (    
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out5
);
//*************code***********//
reg [2:0]cnt;
always@(posedge clk_in or negedge rst)
if(!rst)
cnt<=0;
else if(cnt==4)
cnt<=0;
else   
cnt<=cnt+3'd1;

reg clkn;
always@(posedge clk_in or negedge rst)
if(!rst)
clkn<=0;
else if(cnt==0)
clkn<=1;
else if(cnt==2)
clkn<=0;

reg clkp;
always@(negedge clk_in or negedge rst)
if(!rst)
clkp<=0;
else if(cnt==1)
clkp<=1;
else if(cnt==2)
clkp<=0;

assign clk_out5=clkn||clkp;

//*************code***********//
endmodule

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值