牛客 Verilog 刷题入门篇1~24 + 进阶篇1~34 题解代码,所有代码均能通过测试,配合视频讲解效果更佳。本文给出代码,部分题目给出必要说明。 很多题目本身出题有些问题,着重理解题目,没必要钻牛角尖。
【FPGA探索者】公众号回复【刷题】获取 PDF 版本及每题对应的讲解。
目录
视频讲解合集:
https://space.bilibili.com/507257163/channel/collectiondetail?sid=260755
扫码刷题
使用assign连续赋值语句 + 三目运算符 ? :
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module mux4_1(
input [1:0]d1,d2,d3,d0,
input [1:0]sel,
output [1:0]mux_out
);
//*************code***********//
assign mux_out = (sel == 2'b00) ? d3 : ((sel == 2'b01) ? d2 : (sel == 2'b10) ? d1 : d0);
//*************code***********//
endmodule
使用always过程赋值语句 + case语句
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module mux4_1(
input [1:0]d1,d2,d3,d0,
input [1:0]sel,
output [1:0]mux_out
);
//*************code***********//
reg [1:0] mux_out_reg;
always @ (*)
begin
case(sel)
2'b00:mux_out_reg = d3;
2'b01:mux_out_reg = d2;
2'b10:mux_out_reg = d1;
2'b11:mux_out_reg = d0;
default : mux_out_reg = d0;
endcase
end
assign mux_out = mux_out_reg;
//*************code***********//
endmodule
题解 | Verilog刷题解析及对应笔试面试注意点【1-5】(涉及复位、有符号数问题等)
注意 T 触发器的概念,来 1 翻转,来 0 保持。 注意理解同步复位和异步复位。联发科数字IC简答题(9)——异步复位同步释放问题
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module Tff_2 (
input wire data, clk, rst,
output reg q
);
// 1. 复位
//2. T触发器,D触发器
//*************code***********//
reg q1;
always @ (posedge clk or negedge rst)
begin
if(!rst) begin
q1 <= 1'b0;
end
else begin
if( data )
q1 <= ~q1;
else
q1 <= q1;
end
end
always @ (posedge clk or negedge rst)
begin
if(!rst) begin
q <= 1'b0;
end
else begin
if( q1 )
q <= ~q;
else
q <= q;
end
end
//*************code***********//
endmodule
实际上这里做的是奇偶检测,如果是奇数个 1 则结果为 1,使用单目运算符 ^ 即可。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module odd_sel(
input [31:0] bus,
input sel,
output check
);
//*************code***********//
wire check_tmp;
// 单目运算符
assign check_tmp = ^bus;
// assign check = (sel == 1'b1) ? check_tmp : ~check_tmp;
reg check_reg;
always @ (*) begin
if(sel) begin
check_reg = check_tmp;
end
else begin
check_reg = ~check_tmp;
end
end
assign check = check_reg;
//*************code***********//
endmodule
FSM 有限状态机思想,计数值就是状态。 注意在第一次获得数据的时候进行暂存。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module multi_sel(
input [7:0]d ,
input clk,
input rst,
output reg input_grant,
output reg [10:0]out
);
//*************code***********//
reg [1:0] count; // 0 1 2 3
always @ (posedge clk or negedge rst)
begin
if(~rst) begin
count <= 2'b0;
end
else begin
count <= count + 1'b1;
end
end
// FSM 有限状态机思想,计数值就是状态
reg [7:0] d_reg;
always @ (posedge clk or negedge rst)
begin
if(~rst) begin
out <= 11'b0;
input_grant <= 1'b0;
d_reg <= 8'b0;
end
else begin
case( count )
2'b00 : begin
out <= d;
d_reg <= d;
input_grant <= 1'b1;
end
2'b01 : begin
out <= d_reg + {d_reg, 1'b0}; // *1 + *2
input_grant <= 1'b0;
end
2'b10 : begin
out <= d_reg + {d_reg, 1'b0} + {d_reg, 2'b0};
input_grant <= 1'b0;
end
2'b11 : begin
out <= {d_reg, 3'b0};
input_grant <= 1'b0;
end
default : begin
out <= d;
input_grant <= 1'b0;
end
endcase
end
end
//*************code***********//
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out, // wire
output validout // wire
);
//*************code***********//
reg [15:0] d_reg;
wire [3:0] d0;
wire [3:0] d1;
wire [3:0] d2;
wire [3:0] d3;
assign d0 = d_reg[3:0];
assign d1 = d_reg[7:4];
assign d2 = d_reg[11:8];
assign d3 = d_reg[15:12];
reg [4:0] out_reg;
reg validout_reg;
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
out_reg <= 5'b0;
validout_reg <= 1'b0;
d_reg <= 16'b0;
end
else begin
case( sel )
2'b00 : begin
d_reg <= d;
out_reg <= 5'b0;
validout_reg <= 1'b0;
end
2'b01 : begin
d_reg <= d_reg;
out_reg <= d_reg[3:0] + d_reg[7:4];// d0 + d1;
validout_reg <= 1'b1;
end
2'b10 : begin
d_reg <= d_reg;
out_reg <= d0 + d2;
validout_reg <= 1'b1;
end
2'b11 : begin
d_reg <= d_reg;
out_reg <= d0 + d3;
validout_reg <= 1'b1;
end
default : begin
out_reg <= 5'b0;
validout_reg <= 1'b0;
end
endcase
end
end
assign out = out_reg;
assign validout = validout_reg;
//*************code***********//
endmodule
题解 | Verilog刷题解析及对应笔试面试注意点【6-9】(涉及==和===、for展开问题等)
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module data_select(
input clk,
input rst_n,
input signed[7:0]a,
input signed[7:0]b,
input [1:0]select,
output reg signed [8:0]c
);
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
c <= 9'b0;
end
else begin
case ( select )
2'b00 : begin
c <= {a[7], a};
end
2'b01 : begin
c <= {b[7], b};
end
2'b10 : begin
c <= {a[7], a} + {b[7], b};
end
2'b11 : begin
c <= {a[7], a} - {b[7], b};
end
default : begin
c <= 9'b0;
end
endcase
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module data_minus(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
output reg [8:0]c
);
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
c <= 8'b0;
end
else begin
if( a > b ) begin
c <= a - b;
end
else begin
c <= b - a;
end
end
end
endmodule
分别给出generate...for和for的代码,可以对比不同点。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module gen_for_module(
input [7:0] data_in,
output [7:0] data_out
);
// 1. 必须使用 genvar 声明循环变量
// begin后面必须起个名字
genvar ii;
generate for(ii = 0; ii < 8; ii = ii+1)
begin : aaa_i
assign data_out[ii] = data_in[7-ii];
end
endgenerate
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module gen_for_module(
input [7:0] data_in,
output [7:0] data_out
);
// 2. for
integer i;
reg [7:0] dout_reg;
always @ (*) begin
for(i = 0; i < 8; i = i+1) begin
dout_reg[i] = data_in[7-i];
end
end
assign data_out = dout_reg;
endmodule
需要调用3个模块,这里很多同学可能疑惑为什么用3个而不是2个。
第一个模块:比较 T 时刻的 a 和 b,T+1 时刻出来 tmp1; 第二个模块:比较 T 时刻的 a 和 c,T+1 时刻出来 tmp2; 第三个模块:比较 T+1 时刻的 tmp1 和 tmp2,T+2 时刻出来 d;
如果只用2个子模块,那么 T 时刻比较 a 和 b 得到 tmp1,再比较 tmp1 和 c 的时候是 T+1 时刻的 c 和 T+1 时刻的 tmp1,而 tmp1 代表的是 T 时刻 a 和 b 的较小值,所以这时候比较的 T 时刻的 a、b 和 T+1 时刻的 c,显然不符合要求。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module main_mod(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
input [7:0]c,
output [7:0]d
);
// T 时刻的 a 和 b,T+1 时刻出来 tmp1
wire [7:0] tmp1; // a b 的最小值
child_mod U0(
.clk ( clk ),
.rst_n ( rst_n ),
.a ( a ),
.b ( b ),
.d ( tmp1 )
);
// T 时刻的 a 和 c,T+1 时刻出来 tmp2
wire [7:0] tmp2; // a c 的最小值
child_mod U1(
.clk ( clk ),
.rst_n ( rst_n ),
.a ( a ),
.b ( c ),
.d ( tmp2 )
);
// T+1 时刻的 tmp1 和 tmp2,T+2 时刻出来 d
child_mod U2(
.clk ( clk ),
.rst_n ( rst_n ),
.a ( tmp1 ),
.b ( tmp2 ),
.d ( d )
);
endmodule
// 子模块
module child_mod(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
output [7:0]d
);
reg [7:0] d_reg;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
d_reg <= 8'b0;
end
else begin
if( a > b )
d_reg <= b;
else
d_reg <= a;
end
end
assign d = d_reg;
endmodule
组合逻辑的子模块,就不存在时序逻辑中的延时问题,所以调用的时候用2个子模块就可以完成3个数的比较,为了符合时序波形的要求,多打一拍。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module main_mod(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
input [7:0]c,
output [7:0]d
);
wire [7:0] tmp1; // a b 的最小值
child_mod U0(
.a ( a ),
.b ( b ),
.d ( tmp1 )
);
wire [7:0] tmp2; // a c 的最小值
child_mod U1(
.a ( tmp1 ),
.b ( c ),
.d ( tmp2 )
);
reg [7:0] d_reg;
reg [7:0] d_reg2;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
d_reg <= 8'b0;
d_reg2 <= 8'b0;
end
else begin
d_reg <= tmp2;
d_reg2 <= d_reg;
end
end
assign d = d_reg2;
endmodule
module child_mod(
input [7:0]a,
input [7:0]b,
output [7:0]d
);
assign d = (a>b) ? b : a;
endmodule
题解 | Verilog刷题解析【10】function和task的使用、相关笔试题
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module function_mod(
input clk,
input rst_n,
input [3:0]a,
input [3:0]b,
output [3:0]c,
output [3:0]d
);
/*
function <返回值的类型或范围>函数名;
<端口说明语句>
<变量类型说明语句>
begin
<语句>
end
endfunction
*/
function [3:0] begin_end;
input [3:0] data_in;
begin
begin_end[0] = data_in[3];
begin_end[1] = data_in[2];
begin_end[2] = data_in[1];
begin_end[3] = data_in[0];
end
endfunction
assign c = begin_end(a);
assign d = begin_end(b);
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module comparator_4(
input [3:0] A ,
input [3:0] B ,
output wire Y2 , //A>B
output wire Y1 , //A=B
output wire Y0 //A<B
);
assign Y2 = (A[3]>B[3]) | ((A[3]==B[3])&&(A[2]>B[2])) | ((A[3]==B[3])&&(A[2]==B[2])&&(A[1]>B[1])) | ((A[3]==B[3])&&(A[2]==B[2])&&(A[1]==B[1])&&(A[0]>B[0]));
assign Y1 = (A[3]==B[3])&&(A[2]==B[2])&&(A[1]==B[1])&&(A[0]==B[0]);
assign Y0 = (~Y2) & (~Y1);
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module lca_4(
input [3:0] A_in ,
input [3:0] B_in ,
input C_1 ,
output wire CO ,
output wire [3:0] S
);
wire [3:0] G;
wire [3:0] P;
assign G[0] = A_in[0] & B_in[0];
assign G[1] = A_in[1] & B_in[1];
assign G[2] = A_in[2] & B_in[2];
assign G[3] = A_in[3] & B_in[3];
assign P[0] = A_in[0] ^ B_in[0];
assign P[1] = A_in[1] ^ B_in[1];
assign P[2] = A_in[2] ^ B_in[2];
assign P[3] = A_in[3] ^ B_in[3];
wire [3:0] C;
assign S[0] = P[0] ^ C_1;
assign S[1] = P[1] ^ C[0];
assign S[2] = P[2] ^ C[1];
assign S[3] = P[3] ^ C[2];
assign CO = C[3];
assign C[0] = G[0] | P[0]&C_1;
assign C[1] = G[1] | P[1]&C[0];
assign C[2] = G[2] | P[2]&C[1];
assign C[3] = G[3] | P[3]&C[2];
endmodule
13~20不建议做了,没有太大意义,这里只给出13~16的代码。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module encoder_0(
input [8:0] I_n ,
output reg [3:0] Y_n
);
always @ (*)
begin
casex(I_n)
9'b1_1111_1111 : Y_n = 4'b1111;
9'b0_xxxx_xxxx : Y_n = 4'b0110;
9'b1_0xxx_xxxx : Y_n = 4'b0111;
9'b1_10xx_xxxx : Y_n = 4'b1000;
9'b1_110_xxxx : Y_n = 4'b1001;
9'b1_1110_xxxx : Y_n = 4'b1010;
9'b1_1111_0xxx : Y_n = 4'b1011;
9'b1_1111_10xx : Y_n = 4'b1100;
9'b1_1111_110x : Y_n = 4'b1101;
9'b1_1111_1110 : Y_n = 4'b1110;
default : Y_n = 4'b1111;
endcase
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module encoder_0(
input [8:0] I_n ,
output reg [3:0] Y_n
);
always @(*)
begin
casex(I_n)
9'b111111111 : Y_n = 4'b1111;
9'b0xxxxxxxx : Y_n = 4'b0110;
9'b10xxxxxxx : Y_n = 4'b0111;
9'b110xxxxxx : Y_n = 4'b1000;
9'b1110xxxxx : Y_n = 4'b1001;
9'b11110xxxx : Y_n = 4'b1010;
9'b111110xxx : Y_n = 4'b1011;
9'b1111110xx : Y_n = 4'b1100;
9'b11111110x : Y_n = 4'b1101;
9'b111111110 : Y_n = 4'b1110;
default : Y_n = 4'b1111;
endcase
end
endmodule
module key_encoder(
input [9:0] S_n ,
output wire[3:0] L ,
output wire GS
);
wire [3:0] LL;
encoder_0 U0(
.I_n( S_n[9:1] ) ,
.Y_n( LL )
);
assign L = ~LL;
assign GS = ((LL == 4'b1111) && (S_n[0] == 1)) ? 0 : 1;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module encoder_83(
input [7:0] I ,
input EI ,
output wire [2:0] Y ,
output wire GS ,
output wire EO
);
reg [2:0] Y_Reg;
reg GS_Reg;
reg EO_Reg;
always @ (*)
begin
if( EI == 1'b0 ) begin
Y_Reg = 3'b0;
GS_Reg = 1'b0;
EO_Reg = 1'b0;
end
else begin
casex(I)
8'b0000_0000 : begin
Y_Reg = 3'b0;
GS_Reg = 1'b0;
EO_Reg = 1'b1;
end
8'b1xxx_xxxx : begin
Y_Reg = 3'b111;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
8'b01xx_xxxx : begin
Y_Reg = 3'b110;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
8'b001x_xxxx : begin
Y_Reg = 3'b101;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
8'b0001_xxxx : begin
Y_Reg = 3'b100;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
8'b0000_1xxx : begin
Y_Reg = 3'b011;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
8'b0000_01xx : begin
Y_Reg = 3'b010;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
8'b0000_001x : begin
Y_Reg = 3'b001;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
8'b0000_0001 : begin
Y_Reg = 3'b000;
GS_Reg = 1'b1;
EO_Reg = 1'b0;
end
endcase
end
end
assign Y = Y_Reg;
assign GS = GS_Reg;
assign EO = EO_Reg;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module encoder_83(
input [7:0] I ,
input EI ,
output wire [2:0] Y ,
output wire GS ,
output wire EO
);
assign Y[2] = EI & (I[7] | I[6] | I[5] | I[4]);
assign Y[1] = EI & (I[7] | I[6] | ~I[5]&~I[4]&I[3] | ~I[5]&~I[4]&I[2]);
assign Y[0] = EI & (I[7] | ~I[6]&I[5] | ~I[6]&~I[4]&I[3] | ~I[6]&~I[4]&~I[2]&I[1]);
assign EO = EI&~I[7]&~I[6]&~I[5]&~I[4]&~I[3]&~I[2]&~I[1]&~I[0];
assign GS = EI&(I[7] | I[6] | I[5] | I[4] | I[3] | I[2] | I[1] | I[0]);
//assign GS = EI&(| I);
endmodule
module encoder_164(
input [15:0] A ,
input EI ,
output wire [3:0] L ,
output wire GS ,
output wire EO
);
wire [2:0] Y_1;
wire GS_1;
wire EO_1;
encoder_83 U0(
.I(A[15:8]) ,
.EI(EI) ,
.Y(Y_1) ,
.GS(GS_1) ,
.EO(EO_1)
);
wire [2:0] Y_0;
wire GS_0;
wire EO_0;
encoder_83 U1(
.I(A[7:0]) ,
.EI(EO_1) ,
.Y(Y_0) ,
.GS(GS_0) ,
.EO(EO_0)
);
assign GS = GS_1 | GS_0;
assign EO = EO_0;
assign L[3] = GS_1;
assign L[2] = Y_1[2] | Y_0[2];
assign L[1] = Y_1[1] | Y_0[1];
assign L[0] = Y_1[0] | Y_0[0];
endmodule
FSM有限状态机问题,两段式。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module seq_circuit(
input A ,
input clk ,
input rst_n,
output wire Y
);
reg [1:0] curr_state;
reg [1:0] next_state;
// one step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
curr_state <= 2'b00;
next_state <= 2'b00;
end
else begin
curr_state <= next_state;
end
end
// two step
always @ (*)
begin
case(curr_state)
2'b00 : next_state = (A == 1'b1) ? 2'b11 : 2'b01;
2'b01 : next_state = (A == 1'b1) ? 2'b00 : 2'b10;
2'b10 : next_state = (A == 1'b1) ? 2'b01 : 2'b11;
2'b11 : next_state = (A == 1'b1) ? 2'b10 : 2'b00;
default : next_state = 2'b00;
endcase
end
assign Y = (curr_state == 2'b11) ? 1 : 0;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module seq_circuit(
input C ,
input clk ,
input rst_n,
output wire Y
);
reg [1:0] curr_state;
reg [1:0] next_state;
// one step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
curr_state <= 2'b00;
next_state <= 2'b00;
end
else begin
curr_state <= next_state;
end
end
// two step
always @ (*)
begin
case(curr_state)
2'b00 : next_state = (C == 1'b1) ? 2'b01 : 2'b00;
2'b01 : next_state = (C == 1'b1) ? 2'b01 : 2'b11;
2'b10 : next_state = (C == 1'b1) ? 2'b10 : 2'b00;
2'b11 : next_state = (C == 1'b1) ? 2'b10 : 2'b11;
default : next_state = 2'b00;
endcase
end
assign Y = ((curr_state == 2'b11) | ((curr_state == 2'b10)&&(C == 1'b1)) )? 1 : 0;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module rom(
input clk,
input rst_n,
input [7:0]addr,
output [3:0]data
);
reg [3:0] romreg[7:0];
integer i;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
romreg[0] <= 4'd0;
romreg[1] <= 4'd2;
romreg[2] <= 4'd4;
romreg[3] <= 4'd6;
romreg[4] <= 4'd8;
romreg[5] <= 4'd10;
romreg[6] <= 4'd12;
romreg[7] <= 4'd14;
end
else begin
// romreg[0] <= romreg[0];
// ...
// romreg[7] <= romreg[7];
for(i = 0; i < 8; i = i+1) begin : rom_i
romreg[i] <= romreg[i];
end
end
end
assign data = romreg[addr];
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module edge_detect(
input clk,
input rst_n,
input a,
output reg rise,
output reg down
);
reg a1;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
a1 <= 1'b0;
rise <= 1'b0;
down <= 1'b0;
end
else begin
a1 <= a;
if(a & ~a1)
rise <= 1'b1;
else
rise <= 1'b0;
if(~a & a1)
down <= 1'b1;
else
down <= 1'b0;
end
end
endmodule
刷题地址:
三段式状态机解决。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module sequence_detect (
input clk,
input rst_n,
input a,
output reg match
);
// 独热码编码 只有1 bit是1
parameter IDLE = 9'b000000001;
parameter S0 = 9'b000000010;
parameter S1 = 9'b000000100;
parameter S2 = 9'b000001000;
parameter S3 = 9'b000010000;
parameter S4 = 9'b000100000;
parameter S5 = 9'b001000000;
parameter S6 = 9'b010000000;
parameter S7 = 9'b100000000;
reg [8:0] cs, ns;
// one step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
// two step
always @ (*)
begin
case(cs)
IDLE : ns = (a == 1'b0) ? S0 : IDLE;
S0 : ns = (a == 1'b1) ? S1 : S0;
S1 : ns = (a == 1'b1) ? S2 : S0;
S2 : ns = (a == 1'b1) ? S3 : S0;
S3 : ns = (a == 1'b0) ? S4 : S0;
S4 : ns = (a == 1'b0) ? S5 : S0;
S5 : ns = (a == 1'b0) ? S6 : S0;
S6 : ns = (a == 1'b1) ? S7 : S0;
S7 : ns = (a == 1'b1) ? IDLE : S0;
default : ns = IDLE;
endcase
end
wire match_tmp;
assign match_tmp = (cs == S7);
// three step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
match <= 1'b0;
end
else begin
match <= match_tmp;
end
end
endmodule
寄存器存储比较。也可以考虑用状态机。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module sequence_detect (
input clk,
input rst_n,
input a,
output reg match
);
reg [3:0] count;
reg [8:0] data;
reg flag;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
count <= 4'b0;
flag <= 1'b0;
data <= 9'b0;
end
else begin
if( count == 4'd8) begin
count <= 4'd0;
data[count] <= a;
flag <= 1'b1;
end
else begin
count <= count + 4'd1;
data[count] <= a;
flag <= 1'b0;
end
end
end
wire match_tmp;
assign match_tmp = (flag == 1'b1) && (data[8:6] == 3'b011) && (data[2:0] == 3'b110);
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
match <= 1'b0;
end
else begin
match <= match_tmp;
end
end
endmodule
计数器其实就是一个简化的状态机模型,不同的计数值就是不同的状态。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module sequence_detect (
input clk,
input rst_n,
input data,
output reg match,
output reg not_match
);
reg [2:0] count;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
count <= 3'b0;
end
else begin
if(count == 3'd5)
count <= 3'b0;
else
count <= count + 1'b1;
end
end
reg [5:0] seq;
always @ (*)
begin
case(count)
3'd0 : seq[5] = data;
3'd1 : seq[4] = data;
3'd2 : seq[3] = data;
3'd3 : seq[2] = data;
3'd4 : seq[1] = data;
3'd5 : seq[0] = data;
default : seq = 6'b0;
endcase
end
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
match <= 1'b0;
not_match <= 1'b0;
end
else begin
if(count == 3'd5) begin
if(seq == 6'b011100) begin
match <= 1'b1;
not_match <= 1'b0;
end
else begin
match <= 1'b0;
not_match <= 1'b1;
end
end
else begin
match <= 1'b0;
not_match <= 1'b0;
end
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module sequence_detect(
input clk,
input rst_n,
input data,
input data_valid,
output reg match
);
// one step
reg [1:0] cs, ns;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
cs <= 2'b0;
end
else begin
cs <= ns;
end
end
// two step
always @ (*)
begin
case(cs)
2'b00 : begin
if(data_valid) begin
ns = (data==1'b0) ? 2'b01 : 2'b00;
end
else begin
ns = cs;
end
end
2'b01 : begin
if(data_valid) begin
ns = (data==1'b1) ? 2'b10 : 2'b01;
end
else begin
ns = cs;
end
end
2'b10 : begin
if(data_valid) begin
ns = (data==1'b1) ? 2'b11 : 2'b00;
end
else begin
ns = cs;
end
end
2'b11 : begin
if(data_valid) begin
ns = 2'b00;
end
else begin
ns = cs;
end
end
endcase
end
// three step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
match <= 1'b0;
end
else begin
if(cs == 2'b11 && data == 1'b0 && data_valid == 1'b1)
match <= 1'b1;
else
match <= 1'b0;
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module signal_generator(
input clk,
input rst_n,
input [1:0] wave_choise,
output reg [4:0]wave
);
reg [4:0] count; // 计数0~19
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
count <= 5'b0;
end
else begin
if(wave_choise == 2'b00) begin
if(count == 5'd19) begin
count <= 5'b0;
end
else begin
count <= count + 1'b1;
end
end
end
end
reg flag;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
wave <= 5'b0;
flag <= 1'b1; //指示 开始阶段的三角波处在下降
end
else begin
case(wave_choise)
2'b00 : begin
if(count == 5'd9) begin
wave <= 5'd20;
end
else if(count >= 5'd19)begin
wave <= 5'd0;
end
else begin
wave <= wave;
end
end
2'b01 : begin
if(wave >= 5'd20) begin
wave <= 5'b0;
end
else begin
wave <= wave + 1'b1;
end
end
2'b10 : begin
if(flag == 1'b0) begin
if(wave >= 5'd20) begin
flag <= 1'b1;
wave <= wave - 1'b1;
end
else begin
wave <= wave + 1'b1;
end
end
else begin
if(wave == 5'd0) begin
flag <= 1'b0;
wave <= wave + 1'b1;
end
else begin
wave <= wave - 1'b1;
end
end
end
default : wave <= 5'b0;
endcase
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
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 [2:0] count;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
count <= 3'b0;
ready_a <= 1'b0;
end
else begin
ready_a <= 1'b1;
if(valid_a) begin
if(count == 3'd5) begin
count <= 3'd0;
end
else begin
count <= count + 3'd1;
end
end
end
end
reg [5:0] data_b_reg;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
data_b <= 6'b0;
valid_b <= 1'b0;
data_b_reg <= 6'b0;
end
else begin
if(valid_a) begin
data_b_reg <= {data_a, data_b_reg[5:1]};
if(count == 3'd5) begin
valid_b <= 1'd1;
data_b <= {data_a, data_b_reg[5:1]};
end
else begin
valid_b <= 1'd0;
data_b <= data_b;
end
end
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module valid_ready(
input clk ,
input rst_n ,
input [7:0] data_in ,
input valid_a ,
input ready_b ,
output ready_a ,
output reg valid_b ,
output reg [9:0] data_out
);
reg [1:0] count;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
count <= 2'b0;
end
else begin
if(valid_a & ready_a) begin
if( count == 2'd3)
count <= 2'd0;
else
count <= count + 2'd1;
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
data_out <= 10'b0;
end
else begin
if(valid_a && ready_a) begin
if(count == 2'd0) begin
data_out <= data_in;
end
else begin
data_out <= data_out + data_in;
end
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
valid_b <= 1'b0;
end
else begin
if(count == 2'd3 && valid_a && ready_a) begin
valid_b <= 1'b1;
end
else if(valid_b && ready_b)begin
valid_b <= 1'b0;
end
else begin
valid_b <= valid_b;
end
end
end
assign ready_a = ~valid_b | ready_b;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
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;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
cnt <= 4'd0;
end
else begin
if( valid_in ) begin
cnt <= cnt + 4'd1;
end
end
end
reg [15:0] data_reg;
reg [127:0] data_out_r;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
data_out <= 128'b0;
valid_out <= 1'b0;
data_out_r <= 128'b0;
end
else begin
if(valid_in) begin
case(cnt)
4'd0 : begin
data_out_r[127:104] <= data_in;
valid_out <= 1'b0;
end
4'd1 : begin
data_out_r[103:80] <= data_in;
valid_out <= 1'b0;
end
4'd2 : begin
data_out_r[79:56] <= data_in;
valid_out <= 1'b0;
end
4'd3 : begin
data_out_r[55:32] <= data_in;
valid_out <= 1'b0;
end
4'd4 : begin
data_out_r[31:8] <= data_in;
valid_out <= 1'b0;
end
4'd5 : begin
data_out <= {data_out_r[127:8], data_in[23:16]};
data_out_r[127:112] <= data_in[15:0];
valid_out <= 1'b1;
end
4'd6 : begin
data_out_r[111:88] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd7 : begin
data_out_r[87:64] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd8 : begin
data_out_r[63:40] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd9 : begin
data_out_r[39:16] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd10 : begin
data_out <= {data_out_r[127:16], data_in[23:8]};
data_out_r[127:120] <= data_in[7:0];
valid_out <= 1'b1;
end
4'd11 : begin
data_out_r[119:96] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd12 : begin
data_out_r[95:72] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd13 : begin
data_out_r[71:48] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd14 : begin
data_out_r[47:24] <= data_in[23:0];
valid_out <= 1'b0;
end
4'd15 : begin
data_out_r[23:0] <= data_in[23:0];
data_out <= {data_out_r[127:24], data_in[23:0]};
valid_out <= 1'b1;
end
endcase
end
else begin
valid_out <= 1'b0;
end
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module width_8to12(
input clk ,
input rst_n ,
input valid_in ,
input [7:0] data_in ,
output reg valid_out,
output reg [11:0] data_out
);
reg [1:0] cnt;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
cnt <= 2'b0;
end
else begin
if(valid_in) begin
if(cnt == 2'd2)
cnt <= 2'd0;
else
cnt <= cnt + 2'd1;
end
end
end
reg [7:0] data_reg;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
data_out <= 12'b0;
valid_out <= 1'b0;
data_reg <= 8'b0;
end
else begin
if(valid_in) begin
case(cnt)
2'd0 : begin
data_reg <= data_in;
valid_out <= 1'b0;
end
2'd1 : begin
data_out <= {data_reg[7:0], data_in[7:4]};
data_reg[3:0] <= data_in[3:0];
valid_out <= 1'b1;
end
2'd2 : begin
data_out <= {data_reg[3:0], data_in[7:0]};
valid_out <= 1'b1;
end
default : begin
data_reg <= 8'b0;
data_out <= 12'b0;
valid_out <= 1'b0;
end
endcase
end
else begin
valid_out <= 1'b0;
end
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module width_8to16(
input clk ,
input rst_n ,
input valid_in ,
input [7:0] data_in ,
output reg valid_out,
output reg [15:0] data_out
);
reg cnt;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
cnt <= 1'b0;
end
else begin
if(valid_in) begin
cnt <= cnt + 1'b1; // cnt = ~cnt;
end
end
end
reg [7:0] data_reg;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
data_out <= 16'b0;
valid_out <= 1'b0;
end
else begin
if(valid_in) begin
if(cnt == 1'b0) begin
data_reg <= data_in;
valid_out <= 1'b0;
end
else begin
data_out <= {data_reg, data_in};
valid_out <= 1'b1;
end
end
else begin
valid_out <= 1'b0;
end
end
end
endmodule
检测序列10111,非重叠检测,即 101110111 只会被检测通过一次。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module sequence_test1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
// one-hot独热码
parameter IDLE = 6'b000001;
parameter S0 = 6'b000010;
parameter S1 = 6'b000100;
parameter S2 = 6'b001000;
parameter S3 = 6'b010000;
parameter S4 = 6'b100000;
// one step
reg [5:0] cs;
reg [5:0] ns;
always @ (posedge clk or negedge rst)
begin
if(~rst) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
// two step
always @ (*)
begin
case(cs)
IDLE : ns = (data == 1'b1) ? S0 : IDLE;
S0 : ns = (data == 1'b0) ? S1 : S0;
S1 : ns = (data == 1'b1) ? S2 : IDLE;
S2 : ns = (data == 1'b1) ? S3 : S1;
S3 : ns = (data == 1'b1) ? S4 : S1;
S4 : ns = (data == 1'b1) ? S0 : IDLE;
default : ns = IDLE;
endcase
end
//three step
always @ (posedge clk or negedge rst)
begin
if(~rst) begin
flag <= 1'b0;
end
else begin
//if(ns == S4) begin
if(cs == S3 && data == 1'b1) begin
flag <= 1'b1;
end
else begin
flag <= 1'b0;
end
end
end
//*************code***********//
endmodule
检测序列 1011,进行重叠检测,即 10110111 会被检测通过 2 次。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module sequence_test2(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
parameter IDLE = 5'b00001;
parameter S0 = 5'b00010;
parameter S1 = 5'b00100;
parameter S2 = 5'b01000;
parameter S3 = 5'b10000;
// one step
reg [4:0] cs;
reg [4:0] ns;
always @ (posedge clk or negedge rst) begin
if(~rst) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
// two step
always @ (*) begin
case(cs)
IDLE : ns = (data == 1'b1) ? S0 : IDLE;
S0 : ns = (data == 1'b0) ? S1 : S0;
S1 : ns = (data == 1'b1) ? S2 : IDLE;
S2 : ns = (data == 1'b1) ? S3 : S1;
S3 : ns = (data == 1'b1) ? S0 : S1;
default : ns = IDLE;
endcase
end
//three step
always @ (posedge clk or negedge rst) begin
if(~rst) begin
flag <= 1'b0;
end
else begin
if(cs == S3) begin
flag <= 1'b1;
end
else begin
flag <= 1'b0;
end
end
end
endmodule
为了匹配题目给的参考波形,这里的计数器用了减法计数。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module even_div
(
input wire rst ,
input wire clk_in,
output wire clk_out2,
output wire clk_out4,
output wire clk_out8
);
//*************code***********//
reg [2:0] cnt8;
always @ (posedge clk_in or negedge rst) begin
if(~rst) begin
cnt8 <= 3'b0;
end
else begin
cnt8 <= cnt8 - 3'd1;
end
end
assign clk_out2 = cnt8[0];
assign clk_out4 = cnt8[1];
assign clk_out8 = cnt8[2];
endmodule
典型状态机问题。米利型和摩尔型两种解决方式。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
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***********//
parameter IDLE = 3'b001;
parameter S0 = 3'b010;
parameter S1 = 3'b100;
reg [2:0] cs, ns;
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
always @ (d1, d2, d3, rst)
begin
if( ~rst ) begin
ns = IDLE;
end
else begin
case( cs )
IDLE : begin
case({d1, d2, d3})
3'b000 : ns = ns;
3'b100 : ns = S0;
3'b010 : ns = S1;
3'b001 : ns = IDLE;
default : ns = IDLE;
endcase
end
S0 : begin
case({d1, d2, d3})
3'b000 : ns = ns;
3'b100 : ns = S1;
3'b010 : ns = IDLE;
3'b001 : ns = IDLE;
default : ns = IDLE;
endcase
end
S1 : begin
if({d1, d2, d3} == 3'b000)
ns = ns;
else
ns = IDLE;
end
default : begin
if({d1, d2, d3} == 3'b000)
ns = ns;
else
ns = IDLE;
end
endcase
end
end
reg out1_reg;
reg [1:0] out2_reg;
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
out1_reg <= 1'b0;
out2_reg <= 2'b0;
end
else begin
case(cs)
IDLE : begin
if({d1, d2, d3} == 3'b001) begin
out1_reg <= 1'b1;
out2_reg <= 2'd1;
end
else begin
out1_reg <= 1'b0;
out2_reg <= 2'd0;
end
end
S0 : begin
case({d1, d2, d3})
3'b010 : begin
out1_reg <= 1'b1;
out2_reg <= 2'd0;
end
3'b001 : begin
out1_reg <= 1'b1;
out2_reg <= 2'd2;
end
default : begin
out1_reg <= 1'b0;
out2_reg <= 2'd0;
end
endcase
end
S1 : begin
case({d1, d2, d3})
3'b100 : begin
out1_reg <= 1'b1;
out2_reg <= 2'd0;
end
3'b010 : begin
out1_reg <= 1'b1;
out2_reg <= 2'd1;
end
3'b001 : begin
out1_reg <= 1'b1;
out2_reg <= 2'd3;
end
default : begin
out1_reg <= 1'b0;
out2_reg <= 2'd0;
end
endcase
end
default : begin
out1_reg <= 1'b0;
out2_reg <= 2'd0;
end
endcase
end
end
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
out1 <= 1'b0;
out2 <= 2'b0;
end
else begin
out1 <= out1_reg;
out2 <= out2_reg;
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
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***********//
parameter IDLE = 7'b0000001;
parameter S05 = 7'b0000010;
parameter S10 = 7'b0000100;
parameter S15 = 7'b0001000;
parameter S20 = 7'b0010000;
parameter S25 = 7'b0100000;
parameter S30 = 7'b1000000;
reg [6:0] cs, ns;
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
always @ (d1, d2, sel, rst, cs)
begin
if( ~rst ) begin
ns = IDLE;
end
else begin
case( cs )
IDLE : begin
case({d1, d2})
2'b10 : ns = S05;
2'b01 : ns = S10;
default : ns = ns;
endcase
end
S05 : begin
case({d1, d2})
2'b10 : ns = S10;
2'b01 : ns = S15;
default : ns = ns;
endcase
end
S10 : begin
case({d1, d2})
2'b10 : ns = S15;
2'b01 : ns = S20;
default : ns = ns;
endcase
end
S15 : begin
// 1.5 还是 2.5
if(sel == 1'b0) begin
ns = IDLE;
end
else begin
case({d1, d2})
2'b10 : ns = S20;
2'b01 : ns = S25;
default : ns = ns;
endcase
end
end
S20 : begin
// 1.5 还是 2.5
if(sel == 1'b0) begin
ns = IDLE;
end
else begin
case({d1, d2})
2'b10 : ns = S25;
2'b01 : ns = S30;
default : ns = ns;
endcase
end
end
S25 : begin
ns = IDLE;
end
S30 : begin
ns = IDLE;
end
default : begin
ns = IDLE;
end
endcase
end
end
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
else begin
case(ns)
IDLE : begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
S05 : begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
S10 : begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
S15 : begin
if(sel == 1'b0) begin
out1 <= 1'b1;
out2 <= 1'b0;
out3 <= 1'b0;
end
else begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
end
S20 : begin
if(sel == 1'b0) begin
out1 <= 1'b1;
out2 <= 1'b0;
out3 <= 1'b1;
end
else begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
end
S25 : begin
if(sel == 1'b0) begin
out1 <= 1'b0;
out2 <= 1'd0;
out3 <= 1'b0;
end
else begin
out1 <= 1'b0;
out2 <= 1'd1;
out3 <= 1'b0;
end
end
S30 : begin
if(sel == 1'b0) begin
out1 <= 1'b0;
out2 <= 1'd0;
out3 <= 1'b0;
end
else begin
out1 <= 1'b0;
out2 <= 1'd1;
out3 <= 1'b1;
end
end
default : begin
out1 <= 1'b0;
out2 <= 1'd0;
out3 <= 1'b0;
end
endcase
end
end
endmodule
7 分频,50% 占空比。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module odo_div_or (
input wire rst ,
input wire clk_in,
output wire clk_out7
);
//*************code***********//
reg [2:0] count_p; //上升沿计数
reg [2:0] count_n; //下降沿计数
reg clk_p; //上升沿分频
reg clk_n; //下降沿分频
//上升沿计数
always @ ( posedge clk_in or negedge rst )
begin
if( !rst )
count_p <= 3'b0;
else if( count_p == 3'd6 )
count_p <= 3'b0;
else
count_p <= count_p + 1'b1;
end
//上升沿分频
always @ ( posedge clk_in or negedge rst )
begin
if( !rst ) begin
clk_p <= 1'b0;
end
else begin
if( count_p == 3'd3 || count_p == 3'd6 ) begin
clk_p <= ~clk_p;
end
end
end
//下降沿计数
always @ ( negedge clk_in or negedge rst )
begin
if( !rst )
count_n <= 3'b0;
else if( count_n == 3'd6 )
count_n <= 3'b0;
else
count_n <= count_n + 1'b1;
end
//下降沿分频
always @ ( negedge clk_in or negedge rst )
begin
if( !rst ) begin
clk_n <= 1'b0;
end
else begin
if( count_n == 3'd3 || count_n == 3'd6 ) begin
clk_n <= ~clk_n;
end
end
end
assign clk_out7 = clk_p | clk_n;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module div_M_N(
input wire clk_in,
input wire rst,
output wire clk_out
);
parameter M_N = 8'd87;
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
reg [6:0] cnt;
always @ (posedge clk_in or negedge rst)
begin
if( ~rst ) begin
cnt <= 7'd0;
end
else begin
if(cnt == 7'd86)
cnt <= 7'b0;
else
cnt <= cnt + 7'b1;
end
end
reg [2:0] cnt_8;
reg [3:0] cnt_9;
always @ (posedge clk_in or negedge rst)
begin
if( ~rst ) begin
cnt_8 <= 3'd0;
cnt_9 <= 4'd0;
end
else begin
if(cnt < c89) begin
cnt_8 <= cnt_8 + 1'b1;
end
else begin
if(cnt_9 == div_o - 1)
cnt_9 <= 4'd0;
else
cnt_9 <= cnt_9 + 1'b1;
end
end
end
reg clk_o_r;
always @ (posedge clk_in or negedge rst)
begin
if( ~rst ) begin
clk_o_r <= 1'b0;
end
else begin
if(cnt < c89) begin
if(cnt_8 < 3'd4)
clk_o_r <= 1'b1;
else
clk_o_r <= 1'b0;
end
else begin
if(cnt_9 < 3'd4)
clk_o_r <= 1'b1;
else
clk_o_r <= 1'b0;
end
end
end
assign clk_out = clk_o_r;
endmodule
该题目虽然说的是无占空比要求,但是实际只给了一种参考波形,只要自己写的和这个参考波形不一样就报错,所以不需要管参考波形,自己会奇数分频即可。
下方给出的代码能够通过测试,5分频,占空比40%,简单易理解。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
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) begin
if(~rst) begin
cnt <= 3'b0;
end
else begin
if(cnt == 3'd4) begin
cnt <= 3'd0;
end
else begin
cnt <= cnt + 3'd1;
end
end
end
reg clk_out5_r;
always @ (posedge clk_in or negedge rst) begin
if(~rst) begin
clk_out5_r <= 3'b0;
end
else begin
case( cnt )
3'd0 : clk_out5_r <= 1'b1;
3'd1 : clk_out5_r <= 1'b1;
3'd2 : clk_out5_r <= 1'b0;
3'd3 : clk_out5_r <= 1'b0;
3'd4 : clk_out5_r <= 1'b0;
default : clk_out5_r <= 1'b0;
endcase
end
end
assign clk_out5 = clk_out5_r;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module fsm1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
parameter S0 = 4'b0001;
parameter S1 = 4'b0010;
parameter S2 = 4'b0100;
parameter S3 = 4'b1000;
reg [3:0] cs, ns;
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
cs <= S0;
end
else begin
cs <= ns;
end
end
always @ (*)
begin
case(cs)
S0 : ns = (data == 1'b1) ? S1 : S0;
S1 : ns = (data == 1'b1) ? S2 : S1;
S2 : ns = (data == 1'b1) ? S3 : S2;
S3 : ns = (data == 1'b1) ? S0 : S3;
default : ns = S0;
endcase
end
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
flag <= 1'b0;
end
else begin
if( cs == S3 && data == 1'b1) begin
flag <= 1'b1;
end
else begin
flag <= 1'b0;
end
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module fsm2(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
parameter S0 = 5'b00001;
parameter S1 = 5'b00010;
parameter S2 = 5'b00100;
parameter S3 = 5'b01000;
parameter S4 = 5'b10000;
reg [4:0] cs, ns;
always @ (posedge clk or negedge rst)
begin
if( ~rst ) begin
cs <= S0;
end
else begin
cs <= ns;
end
end
always @ (*)
begin
case(cs)
S0 : ns = (data == 1'b1) ? S1 : S0;
S1 : ns = (data == 1'b1) ? S2 : S1;
S2 : ns = (data == 1'b1) ? S3 : S2;
S3 : ns = (data == 1'b1) ? S4 : S3;
S4 : ns = (data == 1'b1) ? S1 : S0;
default : ns = S0;
endcase
end
always @ (*)
begin
flag = (cs == S4);
end
//assign flag = (cs == S4);
endmodule
`timescale 1ns/1ns
/********RAM***********/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
,input [WIDTH-1:0] wdata //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/********AFIFO*********/
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module asyn_fifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input wclk ,
input rclk ,
input wrstn ,
input rrstn ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output wire wfull ,
output wire rempty ,
output wire [WIDTH-1:0] rdata
);
localparam ADDR_WIDTH = $clog2(DEPTH);
reg [ADDR_WIDTH:0] waddr;
reg [ADDR_WIDTH:0] raddr;
always @ (posedge wclk or negedge wrstn) begin
if(~wrstn) begin
waddr <= 'b0;
end
else begin
if( winc && ~wfull ) begin
waddr <= waddr + 1'b1;
end
else begin
waddr <= waddr;
end
end
end
always @ (posedge rclk or negedge rrstn) begin
if(~rrstn) begin
raddr <= 'b0;
end
else begin
if( rinc && ~rempty ) begin
raddr <= raddr + 1'b1;
end
else begin
raddr <= raddr;
end
end
end
wire [ADDR_WIDTH:0] waddr_gray;
wire [ADDR_WIDTH:0] raddr_gray;
assign waddr_gray = waddr ^ (waddr>>1);
assign raddr_gray = raddr ^ (raddr>>1);
reg [ADDR_WIDTH:0] waddr_gray_reg;
always @ (posedge wclk or negedge wrstn) begin
if(~wrstn) begin
waddr_gray_reg <= 'd0;
end
else begin
waddr_gray_reg <= waddr_gray;
end
end
reg [ADDR_WIDTH:0] raddr_gray_reg;
always @ (posedge rclk or negedge rrstn) begin
if(~rrstn) begin
raddr_gray_reg <= 'd0;
end
else begin
raddr_gray_reg <= raddr_gray;
end
end
reg [ADDR_WIDTH:0] addr_r2w_t;
reg [ADDR_WIDTH:0] addr_r2w;
always @ (posedge wclk or negedge wrstn) begin
if(~wrstn) begin
addr_r2w_t <= 'd0;
addr_r2w <= 'd0;
end
else begin
addr_r2w_t <= raddr_gray_reg;
addr_r2w <= addr_r2w_t;
end
end
reg [ADDR_WIDTH:0] addr_w2r_t;
reg [ADDR_WIDTH:0] addr_w2r;
always @ (posedge rclk or negedge rrstn) begin
if(~rrstn) begin
addr_w2r_t <= 'd0;
addr_w2r <= 'd0;
end
else begin
addr_w2r_t <= waddr_gray_reg;
addr_w2r <= addr_w2r_t;
end
end
assign wfull = (waddr_gray_reg == {~addr_r2w[ADDR_WIDTH:ADDR_WIDTH-1], addr_r2w[ADDR_WIDTH-2:0]});
assign rempty = (raddr_gray_reg == addr_w2r);
// 例化双口RAM,作者:FPGA探索者
dual_port_RAM
#(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM_U0
(
.wclk(wclk),
.wenc(winc&&~wfull),
.waddr(waddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。
.wdata(wdata), //数据写入
.rclk(rclk),
.renc(rinc&&~rempty),
.raddr(raddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。
.rdata(rdata) //数据输出
);
endmodule
注意: (1)在例化双口 RAM 的时候,读写使能 renc/wenc 信号如果只是传入 rinc 和 winc 也能通过题目的波形测试,但是仔细思考其实不对,此时如果是满的情况下有外部的写使能 winc,虽然写地址不变,但是对于 RAM 来讲写使能还是有效的,会覆盖数据,所以这里的 RAM 写使能信号 wenc = winc && (~wfull),RAM 读使能 renc = rinc && (~rempty),这样才能保证不会在空满情况下对RAM的误操作; (2)虽然通过了波形测试,但是自己下来可以测试下空的时候继续读、满的时候继续写的极限情况,看是否出错,考虑空满信号是应该用时序逻辑产生 or 组合逻辑产生? (3)视频里的“真双口RAM”描述是错误的,实际这里应该是简单双口 RAM,具体的去比可以参考:Xilinx的分布式RAM和块RAM——单口、双口、简单双口、真双口的区别
`timescale 1ns/1ns
/***********RAM************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
,input [WIDTH-1:0] wdata //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/******SFIFO************/
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module sfifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input clk ,
input rst_n ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output reg wfull ,
output reg rempty ,
output wire [WIDTH-1:0] rdata
);
localparam ADDR_WIDTH = $clog2(DEPTH);
reg [ADDR_WIDTH:0] waddr;
reg [ADDR_WIDTH:0] raddr;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
waddr <= 'b0;
end
else begin
if( winc && ~wfull ) begin
waddr <= waddr + 1'b1;
end
else begin
waddr <= waddr;
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
raddr <= 'b0;
end
else begin
if( rinc && ~rempty ) begin
raddr <= raddr + 1'b1;
end
else begin
raddr <= raddr;
end
end
end
//assign wfull = (raddr == {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH-1:0]});
//assign rempty = (raddr == waddr);
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
wfull <= 'b0;
rempty <= 'b0;
end
else begin
wfull <= (raddr == {~waddr[ADDR_WIDTH], waddr[ADDR_WIDTH-1:0]});
rempty <= (raddr == waddr);
end
end
// RAM例化,注意读写使能端口的信号
dual_port_RAM
#(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM_U0
(
.wclk(clk),
.wenc(winc&&~wfull),
.waddr(waddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。
.wdata(wdata), //数据写入
.rclk(clk),
.renc(rinc&&~rempty),
.raddr(raddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。
.rdata(rdata) //数据输出
);
endmodule
题目有问题,转格雷码的计数器是两个时钟才会加1。所以,考虑对二进制的计数使用5位,取高四位的时候相当于两个 clk 变化一次,然后用二进制转格雷码。
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module gray_counter(
input clk,
input rst_n,
output reg [3:0] gray_out
);
// 题目有问题,转格雷码的计数器是两个时钟加1
// 这样对二进制的计数使用5位,取高四位的时候相当于两个clk变化一次
reg [4:0] cnt_bin;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
cnt_bin <= 5'b0;
end
else begin
cnt_bin <= cnt_bin + 5'b1;
end
end
wire [3:0] bin;
assign bin = cnt_bin[4:1];
always @ (gray_out, bin)
begin
//gray_out = bin ^ (bin>>1);
gray_out[3] = bin[3];
gray_out[2] = bin[3] ^ bin[2];
gray_out[1] = bin[2] ^ bin[1];
gray_out[0] = bin[1] ^ bin[0];
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module mux(
input clk_a ,
input clk_b ,
input arstn ,
input brstn ,
input [3:0] data_in ,
input data_en ,
output reg [3:0] dataout
);
// clk_a 时钟域的 data_en 寄存
reg data_en_a_reg;
always @ (posedge clk_a or negedge arstn)
begin
if( ~arstn ) begin
data_en_a_reg <= 1'b0;
end
else begin
data_en_a_reg <= data_en;
end
end
// clk_a 时钟域的 data_in 寄存
reg [3:0] data_in_a_reg;
always @ (posedge clk_a or negedge arstn)
begin
if( ~arstn ) begin
data_in_a_reg <= 4'b0;
end
else begin
data_in_a_reg <= data_in;
end
end
reg data_en_b_t;
reg data_en_b;
always @ (posedge clk_b or negedge brstn)
begin
if( ~brstn ) begin
data_en_b_t <= 1'b0;
data_en_b <= 1'b0;
end
else begin
data_en_b_t <= data_en_a_reg;
data_en_b <= data_en_b_t;
end
end
always @ (posedge clk_b or negedge brstn)
begin
if( ~brstn ) begin
dataout <= 4'b0;
end
else begin
if(data_en_b)
dataout <= data_in_a_reg;
else
dataout <= dataout;
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module pulse_detect(
input clk_fast ,
input clk_slow ,
input rst_n ,
input data_in ,
output dataout
);
reg data_in_fast;
always @ (posedge clk_fast or negedge rst_n)
begin
if(~rst_n) begin
data_in_fast <= 1'b0;
end
else begin
if(data_in == 1'b1)
data_in_fast <= ~data_in_fast;
else
data_in_fast <= data_in_fast;
end
end
reg data_in_slow_t1;
reg data_in_slow_t2;
reg data_in_slow_t3;
always @ (posedge clk_slow or negedge rst_n)
begin
if(~rst_n) begin
data_in_slow_t1 <= 1'b0;
data_in_slow_t2 <= 1'b0;
data_in_slow_t3 <= 1'b0;
end
else begin
data_in_slow_t1 <= data_in_fast;
data_in_slow_t2 <= data_in_slow_t1;
data_in_slow_t3 <= data_in_slow_t2;
end
end
assign dataout = data_in_slow_t2 ^ data_in_slow_t3;
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module count_module(
input clk,
input rst_n,
output reg [5:0]second,
output reg [5:0]minute
);
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
second <= 6'b0;
minute <= 6'b0;
end
else begin
if(minute == 6'd60) begin
second <= second;
minute <= minute;
end
else if(second == 6'd60) begin
second <= 6'b1;
minute <= minute + 6'b1;
end
else begin
second <= second + 6'b1;
end
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module count_module(
input clk,
input rst_n,
input set,
input [3:0] set_num,
output reg [3:0]number,
output reg zero
);
reg [3:0] num_tmp;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
num_tmp <= 4'b0;
end
else begin
if(set) begin
num_tmp <= set_num;
end
else begin
num_tmp <= num_tmp + 4'b1;
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
number <= 4'b0;
end
else begin
number <= num_tmp;
end
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
zero <= 4'b0;
end
else begin
zero <= (num_tmp == 4'b0);
end
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module count_module(
input clk,
input rst_n,
input mode,
output reg [3:0]number,
output reg zero
);
reg [3:0] num_tmp;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
num_tmp <= 4'b0;
end
else begin
if(mode == 1'b1) begin
if(num_tmp == 4'd9)
num_tmp <= 4'd0;
else
num_tmp <= num_tmp + 4'd1;
end
else begin
if(num_tmp == 4'd0)
num_tmp <= 4'd9;
else
num_tmp <= num_tmp - 4'd1;
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
number <= 4'b0;
end
else begin
number <= num_tmp;
end
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
zero <= 1'b0;
end
else begin
zero <= (num_tmp == 4'b0);
end
end
endmodule
单口RAM、简单双口RAM、真双口RAM 可以参考:Xilinx的分布式RAM和块RAM——单口、双口、简单双口、真双口的区别
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module RAM_1port(
input clk,
input rst,
input enb,
input [6:0]addr,
input [3:0]w_data,
output wire [3:0]r_data
);
//*************code***********//
reg [3:0] ram_reg[127:0];
reg [3:0] ram_data;
integer i;
always @ (posedge clk or negedge rst)
begin
if(~rst) begin
for(i = 0; i < 128; i = i+1) begin
ram_reg[i] <= 4'b0;
end
end
else begin
if(enb) begin // write
ram_reg[addr] <= w_data;
end
else begin
ram_reg[addr] <= ram_reg[addr];
end
end
end
assign r_data = enb ? 4'b0 : ram_reg[addr];
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module ram_mod(
input clk,
input rst_n,
input write_en,
input [7:0]write_addr,
input [3:0]write_data,
input read_en,
input [7:0]read_addr,
output reg [3:0]read_data
);
reg [3:0] ram_reg[7:0];
integer i;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
for(i = 0; i < 8; i = i+1) begin
ram_reg[i] <= 4'b0;
end
end
else begin
if(write_en) begin
ram_reg[write_addr] <= write_data;
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
read_data <= 4'b0;
end
else begin
if(read_en) begin
read_data <= ram_reg[read_addr];
end
end
end
endmodule
FPGA/数字IC笔试题——Verilog实现 N 位 Johnson Counter【约翰逊计数器】【扭环形计数器】
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module JC_counter(
input clk ,
input rst_n,
output reg [3:0] Q
);
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
Q <= {4{1'b0}};
else
Q <= {~Q[0], Q[4-1:1]};
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module JC_counter(
input clk ,
input rst_n,
output reg [3:0] Q
);
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
Q <= {4{1'b0}};
else if(!Q[0])
Q <= {1'b1,Q[4-1:1]};
else
Q <= {1'b0,Q[4-1:1]};
end
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module multi_pipe#(
parameter size = 4
)(
input clk ,
input rst_n ,
input [size-1:0] mul_a ,
input [size-1:0] mul_b ,
output reg [size*2-1:0] mul_out
);
reg [size*2-1:0] mul_a_t [size-1:0];
integer i;
integer j;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
for(i = 0; i < size; i = i+1) begin
mul_a_t[i] <= 'b0;
end
end
else begin
for(j = 0; j < size; j = j+1) begin
mul_a_t[j] <= mul_b[j] ? mul_a << j : 'b0;
end
end
end
reg [size*2-1:0] sum_t[size-1:0];
integer n;
always @ (*)
begin
for(n = 0; n < size; n = n+1) begin
if(n == 0)
sum_t[0] = mul_a_t[0];
else
sum_t[n] = sum_t[n-1] + mul_a_t[n];
end
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
mul_out <= 'b0;
end
else begin
mul_out <= sum_t[size-1];
end
end
endmodule
题目描述很不明确,根据多次测试波形,得到以下注意点: (1)复位状态:red/yellow/green 均为 0,倒计时数 clock = 10; (2)复位以后,有 2 个时钟的复位释放期,在此期间,red/yellow/green 均为 0,倒计时 clock = 9、8;2 个周期以后,red = 1,yellow/green 均为 0,倒计时 clock = 10,从此开始进行红灯倒计时; (3)交通灯颜色变化顺序:红、黄、绿; (4)倒计时范围:红灯 10、9、...、1;黄灯 5、4、...、1;绿灯 60、59、...、1; (5)当有行人按钮按下,倒计时立刻变化(考虑时序逻辑 or 组合逻辑);
`timescale 1ns / 1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module triffic_light (
input rst_n, //异位复位信号,低电平有效
input clk, //时钟信号
input pass_request,
output wire[7:0]clock,
output reg red,
output reg yellow,
output reg green
);
// 1. 使用 3 个计数器,分别计数红、黄、绿
// 2. 使用 1 个计数器,根据计数值的范围分别表示红、黄、绿
// 0~9: 红色 10
// 10~14:黄色 5
// 15~74:绿色 60
reg [6:0] count75;
reg flag;
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
count75 <= 7'b0;
flag <= 1'b0;
end
else begin
if(pass_request) begin
if(count75 <= 7'd65)
count75 <= 7'd65;
else
count75 <= count75 + 7'b1;
end
else begin
if(flag == 1'b0) begin
if(count75 == 7'd2) begin
flag <= 1'b1;
count75 <= 7'b0;
end
else begin
count75 <= count75 + 7'b1;
end
end
else begin
if(count75 == 7'd74)
count75 <= 7'b0;
else
count75 <= count75 + 7'b1;
end
end
end
end
// 红、黄、绿
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n) begin
red <= 1'b0;
yellow <= 1'b0;
green <= 1'b0;
end
else begin
if(count75 >=0 && count75 < 9 || count75 == 7'd74) begin
if(flag == 1'b0 && count75 != 7'd2)
red <= 1'b0;
else
red <= 1'b1;
yellow <= 1'b0;
green <= 1'b0;
end
else if(count75 >=9 && count75 < 14) begin
red <= 1'b0;
yellow <= 1'b1;
green <= 1'b0;
end
else if(count75 >=14 && count75 < 74) begin
red <= 1'b0;
yellow <= 1'b0;
green <= 1'b1;
end
else begin
red <= red;
yellow <= yellow;
green <= green;
end
end
end
// 倒计时
reg [7:0] clock_t;
always @ (rst_n, pass_request, count75, flag) begin
if(~rst_n) begin
clock_t = 8'd10;
end
else begin
if(count75 >=0 && count75 <= 9) begin
clock_t = 8'd10 - count75;
end
else if(count75 >=10 && count75 <= 14) begin
clock_t = 8'd15 - count75;
end
else if(count75 >=15 && count75 <= 74) begin
clock_t = 8'd75 - count75;
end
else begin
clock_t = clock_t;
end
end
end
assign clock = clock_t;
endmodule
`timescale 1ns / 1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module triffic_light_tb();
reg rst_n; //异位复位信号,低电平有效
reg clk; //时钟信号
reg pass_request;
wire [7:0]clock;
wire red;
wire yellow;
wire green;
initial begin
clk = 0;
rst_n = 0;
pass_request = 0;
#15;
rst_n = 1;
#1000;
pass_request = 1;
#10;
pass_request = 0;
#500;
$stop;
end
always #5 clk = ~clk;
triffic_light triffic_light_U0
(
.rst_n(rst_n), //异位复位信号,低电平有效
.clk(clk), //时钟信号
.pass_request(pass_request),
.clock(clock),
.red(red),
.yellow(yellow),
.green(green)
);
endmodule
`timescale 1ns/1ns
//////////////////////////////////////
// 作者: FPGA探索者,FPGA_Explorer
//////////////////////////////////////
module game_count (
input rst_n, //异位复位信号,低电平有效
input clk, //时钟信号
input [9:0]money,
input set,
input boost,
output reg[9:0]remain,
output reg yellow,
output reg red
);
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0) begin
remain <= 10'd0;
end
else begin
if(set == 1'b1)
remain <= remain + money;
else if(boost == 1'b1) begin
if(remain <= 10'd2)
remain <= 10'd0;
else
remain <= remain - 10'd2;
end
else if(boost == 1'b0) begin
if(remain <= 10'd1)
remain <= 10'd0;
else
remain <= remain - 10'd1;
end
else
remain <= remain;
end
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
yellow <= 1'b0;
else begin
if((remain > 10'd0) && (remain < 10'd10))
yellow <= 1'b1;
else
yellow <= 1'b0;
end
end
always @ (posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0) begin
red <= 1'b0;
end
else begin
if(remain < 10'd1)
red <= 1'b1;
else
red <= 1'b0;
end
end
endmodule
FPGA探索者
视频讲解合集:
https://space.bilibili.com/507257163/channel/collectiondetail?sid=260755
https://www.nowcoder.com/exam/oj?tab=Verilog%E7%AF%87&topicId=302&fromPut=pc_zh_s_1540795715
【FPGA探索者】公众号回复【刷题】获取 PDF 版本及每题对应的讲解。