寒假开始了,预期 3月份~4月份会有面向下学期及暑期的实习招聘,利用寒假机会掌握一些数字 IC 基础知识(比如状态机、FIFO、同步、分频等),并且加强 Verilog 手撕代码的能力,对于 IC 设计、IC 验证通用,相关的知识点及真题也在对应题目下给出了链接,可以辅助学习,希望对大家有帮助。
牛客 Verilog 刷题入门篇1~24 + 进阶篇1~34 题解代码,所有代码均能通过测试,配合视频讲解效果更佳。本文给出代码,部分题目给出必要说明。
很多题目本身出题有些问题,着重理解题目,没必要钻牛角尖。
24届实习、秋招抱团取暖:692036083
24届秋招备战群(FPGA、通信基带、数字IC、模拟IC、嵌入式相关求职方向)
【FPGA探索者】公众号回复【刷题】获取 PDF 版本及每题对应的讲解。
目录
入门篇1~24题
VL1 四选一多路器
VL2 异步复位的串联T触发器
VL3 奇偶校验(实际上应该是奇偶检测)
VL4 移位运算与乘法
VL5 位拆分与运算
VL6 多功能数据处理器
VL7 求两个数的差值
VL8 使用generate...for语句简化代码
VL9 使用子模块实现三输入数的大小比较
VL10 使用函数实现数据大小端转换
VL11 4位数值比较器电路
VL12 4bit超前进位加法器电路
VL13 优先编码器电路1
VL14 用优先编码器1实现键盘编码电路
VL15 优先编码器2——8线-3线优先编码器
VL16 使用8线-3线优先编码器实现16线-4线优先编码器
VL17~20 不建议做
VL21 根据状态转移表实现时序电路
VL22 使用状态转移图实现时序电路
VL23 ROM的简单实现
VL24 边沿检测
进阶篇1~34题
VL1 输入序列连续的序列检测
VL2 还有无关项的序列检测
VL3 不重叠序列检测
VL4 输入序列不连续的序列检测
VL5 信号发生器
VL6 数据串转并电路
VL7 数据累加输出
VL8 非整数倍数据位宽转换24to128
VL9 非整数倍数据位宽转换8to12
VL10 整数倍数据位宽转换8to16
VL11 非重叠的序列检测
VL12 重叠序列检测
VL13 时钟分频(偶数)
VL14 自动贩售机1
VL15 自动贩售机2
VL16 占空比50%的奇数分频
VL17 任意小数分频(8.7分频)
VL18 无占空比要求的奇数分频
VL19 根据状态转移写状态机-三段式
VL20 根据状态转移写状态机-两段式
VL21 异步FIFO
VL22 同步FIFO
VL23 格雷码计数器
VL24 多bit MUX同步器
VL25 脉冲同步电路
VL26 简易秒表
VL27 可置位计数器
VL28 加减计数器
VL29 单端口RAM
VL30 RAM的简单实现
VL31 Johnson Counter 约翰逊计数器
VL32 流水线乘法器
VL33 交通灯
VL34 游戏机计费程序
视频讲解合集:视频讲解: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
使用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视频讲解合集: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 版本及每题对应的讲解。
往期推荐