我是靠谱客的博主 故意世界,最近开发中收集的这篇文章主要介绍《牛客刷verilog》Part II Verilog进阶挑战前言Part I Verilog快速入门Part II Verilog进阶挑战Part III Verilog企业真题后记,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
前言
- 之前刷过HDLbits上面的题目,点击链接可以查看详细笔记:verilog练习:hdlbits网站系列完结!
- 最近又想刷一下牛客上面的题目,可以点击链接与小编一起刷题:牛客刷题
- 小编不才,文中如有不当之处,可以在评论中互相交流。此处题目推荐看牛客的评论区,再提一嘴,注意积累自己的基本功
算法、设计模式、软件等
Part I Verilog快速入门
- 此处内容,点击链接跳转:《牛客刷verilog》Part I Verilog快速入门
Part II Verilog进阶挑战
01 序列检测
VL25 输入序列连续的序列检测
答案1:状态机法
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input a,
output reg match
);
parameter IDLE = 4'b0000;
parameter S0 = 4'b0001;
parameter S1 = 4'b0011;
parameter S2 = 4'b0010;
parameter S3 = 4'b0110;
parameter S4 = 4'b0111;
parameter S5 = 4'b0101;
parameter S6 = 4'b0100;
parameter S7 = 4'b1100;
reg [3:0] cur_state, next_state;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
cur_state <= IDLE;
next_state <= IDLE;
end else begin
cur_state <= next_state;
end
always@(*)
case(cur_state)
IDLE : next_state = (a==0)?S0:IDLE;
S0 : next_state = (a==1)?S1:S0;
S1 : next_state = (a==1)?S2:S0;
S2 : next_state = (a==1)?S3:S0;
S3 : next_state = (a==0)?S4:IDLE;
S4 : next_state = (a==0)?S5:IDLE;
S5 : next_state = (a==0)?S6:IDLE;
S6 : next_state = (a==1)?S7:IDLE;
S7 : next_state = (a==0)?S0:IDLE;
default: next_state = IDLE;
endcase
always@(posedge clk or negedge rst_n)
if (!rst_n)
match <= 1'b0;
else if (cur_state == S7)
match <= 1'b1;
else
match <= 1'b0;
endmodule
- 再说一个方法,这个方法我会称之为
移位寄存器法
答案2:移位寄存器法
// `define SIZE 8
// `define SEQ 8'b01110001
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input a,
output reg match
);
reg [7:0] reg_8_a;
always@(posedge clk or negedge rst_n)
if (!rst_n)
reg_8_a <= 'b0;
else
reg_8_a <={reg_8_a[6:0],a};
always@(posedge clk or negedge rst_n)
if (!rst_n)begin
match <= 1'b0;
end
else if (reg_8_a == 8'b01110001)
match <= 1'b1;
else
match <= 1'b0;
endmodule
- 为了可重用,想引入参数化设计。优化代码如下:
`define SIZE 8
`define SEQ 8'b01110001
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input a,
output reg match
);
reg [`SIZE - 1:0] reg_a;
always@(posedge clk or negedge rst_n)
if (!rst_n)
reg_a <= 'b0;
else
reg_a <={reg_a[`SIZE - 2:0],a};
always@(posedge clk or negedge rst_n)
if (!rst_n)begin
match <= 1'b0;
end
else if (reg_a == `SEQ)
match <= 1'b1;
else
match <= 1'b0;
endmodule
复盘
-
题目不难,基本思想就是实现如下的状态转移图。(等熟练了,也可以不画)
-
上述的状态编码,使用了
格雷码
,并没有使用8421码
,也没有使用独热码
-
为了可重用设计,推荐使用
移位寄存器法
VL26 含有无关项的序列检测
答案1:状态机法
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input a,
output reg match
);
parameter IDLE = 4'b0000;
parameter S0 = 4'b0001;
parameter S1 = 4'b0011;
parameter S2 = 4'b0010;
parameter S3 = 4'b0110;
parameter S4 = 4'b0111;
parameter S5 = 4'b0101;
parameter S6 = 4'b0100;
parameter S7 = 4'b1100;
parameter S8 = 4'b1101;
reg [3:0] cur_state, next_state;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
cur_state <= IDLE;
next_state <= IDLE;
end else begin
cur_state <= next_state;
end
always@(*)
case(cur_state)
IDLE : next_state = (a==0)?S0:IDLE;
S0 : next_state = (a==1)?S1:S0;
S1 : next_state = (a==1)?S2:S0;
S2 : next_state = S3;
S3 : next_state = S4;
S4 : next_state = S5;
S5 : next_state = (a==1)?S6:IDLE;
S6 : next_state = (a==1)?S7:IDLE;
S7 : next_state = (a==0)?S8:IDLE;
S8 : next_state = (a==0)?S0:IDLE;
default: next_state = IDLE;
endcase
always@(posedge clk or negedge rst_n)
if (!rst_n)
match <= 1'b0;
else if (cur_state == S8)
match <= 1'b1;
else
match <= 1'b0;
endmodule
答案2:移位寄存器法
`define SIZE 9
`define SEQ 9'011XXX110
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input a,
output reg match
);
reg [`SIZE - 1:0] reg_a;
always@(posedge clk or negedge rst_n)
if (!rst_n)
reg_a <= 'b0;
else
reg_a <={reg_a[`SIZE - 2:0],a};
always@(posedge clk or negedge rst_n)
if (!rst_n)begin
match <= 1'b0;
end
else if (reg_a[8:6] == 3'b011 && reg_a[2:0] == 3'b110)
match <= 1'b1;
else
match <= 1'b0;
endmodule
复盘
- 和上题一样
VL27 不重叠序列检测
答案
`define SIZE 6
`define SEQ 6'b011100
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input data,
output reg match,
output reg not_match
);
reg [`SIZE - 1:0] reg_a;
always@(posedge clk or negedge rst_n)
if (!rst_n)
reg_a <= 'b0;
else
reg_a <={reg_a[`SIZE - 2:0],data};
reg [2:0] cnt;
always@(posedge clk or negedge rst_n)
if (!rst_n)begin
cnt <= 1'b0;
end
else if (cnt == 3'd5)
cnt <= 1'b0;
else
cnt <= cnt + 1'b1;
always@(posedge clk or negedge rst_n)begin
if (!rst_n)begin
match <= 1'b0;
not_match <= 1'b0;
end
else if (cnt == 3'd5)begin
if ({reg_a[`SIZE - 2:0],data} == `SEQ)begin
match <= 1'b1;
end
else begin
not_match <= 1'b1;
end
end
else begin
match <= 1'b0;
not_match <= 1'b0;
end
end
endmodule
复盘
- 注意,此题是要求最后一个数,
输入最后1bit立马输出标志位
,不是下一个时钟周期输出! - 前面两题是两个时钟周期才输出。
VL28 输入序列不连续的序列检测
答案
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input data,
input data_valid,
output reg match
);
reg [3:0] reg_data;
always@(posedge clk or negedge rst_n)
if(!rst_n)
reg_data <= 'd0;
else if(data_valid)
reg_data <= {reg_data[2:0],data};
else
reg_data <= data;
always@(posedge clk or negedge rst_n)
if (!rst_n)
match <= 'b0;
else if({reg_data[2:0],data} == 'b0110)
match <= 'b1;
else
match <= 'b0;
endmodule
复盘
- 如果你习惯这种写法,就不用费尽心思去写状态机了。
02 时序逻辑
VL29 信号发生器
答案
`timescale 1ns/1ns
module signal_generator(
input clk,
input rst_n,
input [1:0] wave_choise,
output reg [4:0]wave
);
reg [4:0] cnt;
reg flag;
// 方波模式下,计数器控制
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
cnt <= 0;
else
cnt <= wave_choise!=0 ? 0:
cnt ==19? 0:
cnt + 1;
end
// 三角波模式下,标志位控制
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
flag <= 0;
else
flag <= wave_choise!=2 ? 0:
wave ==1 ? 1:
wave ==19? 0:
flag;
end
// 更新wave信号
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
wave <= 0;
else
case(wave_choise)
0 : wave <= cnt == 9? 20 :
cnt ==19? 0 :
wave;
1 : wave <= wave==20? 0 : wave+1;
2 : wave <= flag==0 ? wave-1: wave+1;
default: wave <= 0;
endcase
end
endmodule
复盘
- 没看明白题目
- 看题解
VL30 数据串转并电路
答案1
`timescale 1ns/1ns
module s_to_p(
input clk ,
input rst_n ,
input valid_a ,
input data_a ,
output reg ready_a ,
output reg valid_b ,
output reg [5:0] data_b
);
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
ready_a <= 1'b0;
end
else begin
ready_a <= 1'b1;
end
reg [5:0] data_b_reg;
reg [2:0] cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
data_b_reg <= 'd0;
data_b <= 'd0;
valid_b <= 1'b0;
cnt <= 1'b0;
end
else if (valid_a)begin
data_b_reg <= {data_a, data_b_reg[5:1]};
if(cnt == 3'd5)begin
data_b <= {data_a, data_b_reg[5:1]};
valid_b <= 1'b1;
cnt <= 'd0;
end
else begin
valid_b <= 1'b0;
data_b <= data_b;
cnt <= cnt + 1'b1;
end
end
else begin
data_b_reg <= data_b_reg;
end
endmodule
答案2
`timescale 1ns/1ns
module s_to_p(
input clk ,
input rst_n ,
input valid_a ,
input data_a ,
output reg ready_a ,
output reg valid_b ,
output reg [5:0] data_b
);
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
ready_a <= 1'b0;
end
else begin
ready_a <= 1'b1;
end
reg [5:0] data_b_reg;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
data_b_reg <= 'd0;
end
else if (valid_a)begin
data_b_reg <= {data_a, data_b_reg[5:1]};
end
else begin
data_b_reg <= data_b_reg;
end
reg [2:0] cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
cnt <= 'd0;
end
else if (valid_a)begin
if (cnt == 'd5)
cnt <= 'd0;
else
cnt <= cnt + 1'b1;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
valid_b <= 1'b0;
end
else if(cnt == 3'd5)begin
valid_b <= 1'b1;
end
else begin
valid_b <= 1'b0;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
data_b <= 'd0;
end
else if(cnt == 3'd5)begin
data_b <= {data_a, data_b_reg[5:1]};
end else begin
data_b <= data_b;
end
endmodule
复盘
- 仔细点就行。
VL31 数据累加输出
答案
`timescale 1ns/1ns
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] cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt <= 'b0;
else if(ready_a && valid_a)begin
if(cnt == 2'd3)
cnt <= 'd0;
else
cnt <= cnt + 1'b1;
end
else begin
cnt <= cnt;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
valid_b <= 'b0;
end
else if(cnt==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
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
data_out <= 'b0;
end
else if(ready_a && valid_a)begin
if(cnt == 2'd0 )begin
data_out <= data_in;
end
else begin
data_out <= data_out + data_in ;
end
end
assign ready_a = ~valid_b | ready_b;
endmodule
复盘
- 注意观察各个信号间的关系
VL32 非整数倍数据位宽转换24to128
答案
`timescale 1ns/1ns
module width_24to128(
input clk ,
input rst_n ,
input valid_in ,
input [23:0] data_in ,
output reg valid_out ,
output reg [127:0] data_out
);
reg [3:0] cnt;
always@(posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 'b0;
else if (valid_in) begin
if(cnt == 'd15)
cnt <= 4'd0;
else
cnt <= cnt + 1'b1;
end
else
cnt <= cnt;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
valid_out <= 1'b0;
end
else if (valid_in && (cnt == 'd5 || cnt == 'd10 || cnt == 'd15)) begin
valid_out <= 1'b1;
end else begin
valid_out <= 1'b0;
end
reg [127:0] data_out_reg;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
data_out<= 'd0;
data_out_reg <= 'd0;
end
else if (valid_in) begin
if (cnt == 'd5) begin
data_out <= {data_out_reg,data_in[23:16]};
data_out_reg <= data_in[15:0];
end if (cnt == 'd10)begin
data_out <= {data_out_reg,data_in[23:8]};
data_out_reg <= data_in[7:0];
end if (cnt == 'd15)begin
data_out <= {data_out_reg,data_in};
data_out_reg <= 'd0;
end else begin
data_out_reg <= {data_out_reg,data_in};
end
end
else begin
data_out_reg <= data_out_reg;
end
endmodule
复盘
- 注意理解5、10、15处的逻辑位置
- 我们通常使用计数器来判断输出条件
VL33 非整数倍数据位宽转换8to12
答案
`timescale 1ns/1ns
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 [2:0] cnt;
always@(posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 'd0;
else if (valid_in) begin
if(cnt == 'd2)
cnt <= 'd0;
else
cnt <= cnt + 1'b1;
end
else
cnt <= cnt;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
valid_out <= 1'b0;
end
else if (valid_in && (cnt == 'd1 || cnt == 'd2)) begin
valid_out <= 1'b1;
end else begin
valid_out <= 1'b0;
end
reg [11:0] data_out_reg;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
data_out<= 'd0;
data_out_reg <= 'd0;
end
else if (valid_in) begin
if (cnt == 'd1) begin
data_out <= {data_out_reg,data_in[7:4]};
data_out_reg <= data_in[3:0];
end if (cnt == 'd2)begin
data_out <= {data_out_reg,data_in};
data_out_reg <= 'd0;
end else begin
data_out_reg <= {data_out_reg,data_in};
end
end
else begin
data_out_reg <= data_out_reg;
end
endmodule
复盘
- 和上题思路一致
VL34 整数倍数据位宽转换8to16
答案
`timescale 1ns/1ns
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)
if (!rst_n)
cnt <= 'd0;
else if (valid_in) begin
if(cnt == 'd1)
cnt <= 'd0;
else
cnt <= cnt + 1'b1;
end
else
cnt <= cnt;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
valid_out <= 1'b0;
end
else if (valid_in && cnt == 'd1) begin
valid_out <= 1'b1;
end else begin
valid_out <= 1'b0;
end
reg [15:0] data_out_reg;
always@(posedge clk or negedge rst_n)
if (!rst_n) begin
data_out<= 'd0;
data_out_reg <= 'd0;
end
else if (valid_in) begin
if (cnt == 'd1) begin
data_out <= {data_out_reg,data_in};
data_out_reg <= data_in;
end else begin
data_out_reg <= {data_out_reg,data_in};
end
end
else begin
data_out_reg <= data_out_reg;
end
endmodule
复盘
- 和上题思路一致
VL35 状态机-非重叠的序列检测
答案1:寄存器写法
`define SEQR 5'b10111
`timescale 1ns/1ns
module sequence_test1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
reg [4:0] data_reg;
always@(posedge clk or negedge rst)
if(!rst)
data_reg <= 'd0;
else
data_reg <= {data_reg,data};
reg flag_bit = 1'b1;
always@(posedge clk or negedge rst)
if(!rst)
flag <= 1'b0;
else if(flag_bit && {data_reg,data} == `SEQR)begin
flag <= 1'b1;
flag_bit <= 1'b0;
end
else
flag <= 1'b0;
//*************code***********//
endmodule
答案2:状态机法
`define SEQR 5'b10111
`timescale 1ns/1ns
module sequence_test1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
parameter IDLE = 4'b0000;
parameter S0 = 4'b0001;
parameter S1 = 4'b0011;
parameter S2 = 4'b0010;
parameter S3 = 4'b0110;
parameter S4 = 4'b0111;
parameter S5 = 4'b0101;
parameter S6 = 4'b0100;
parameter S7 = 4'b1100;
reg [3:0] cur_state, next_state;
always@(posedge clk or negedge rst)
if (!rst) begin
cur_state <= IDLE;
next_state <= IDLE;
end else begin
cur_state <= next_state;
end
always@(*)
case(cur_state)
IDLE : next_state = (data==1)?S0:IDLE;
S0 : next_state = (data==0)?S1:IDLE;
S1 : next_state = (data==1)?S2:IDLE;
S2 : next_state = (data==1)?S3:S1;
S3 : next_state = (data==1)?S4:S1;
S4 : next_state = S5;
default: next_state = IDLE;
endcase
always@(*)
if (cur_state == S4)
flag <= 1'b1;
else
flag <= 1'b0;
//*************code***********//
endmodule
复盘
- 这和1、2、3、4题一致
VL36 状态机-重叠序列检测
答案1:寄存器法
`timescale 1ns/1ns
`define SEQR 4'b1011
module sequence_test2(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
reg [3:0] data_reg;
always@(posedge clk or negedge rst)
if(!rst)
data_reg <= 'd0;
else
data_reg <= {data_reg,data};
reg cnt = 1'b1;
always@(posedge clk or negedge rst)
if(!rst)
flag <= 1'b0;
else if(data_reg == `SEQR)begin
flag <= 1'b1;
end
else
flag <= 1'b0;
//*************code***********//
endmodule
方法2:状态机法
`timescale 1ns/1ns
`define SEQR 4'b1011
module sequence_test2(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
//*************code***********//
parameter IDLE = 4'b0000;
parameter S0 = 4'b0001;
parameter S1 = 4'b0011;
parameter S2 = 4'b0010;
parameter S3 = 4'b0110;
parameter S4 = 4'b0111;
parameter S5 = 4'b0101;
parameter S6 = 4'b0100;
parameter S7 = 4'b1100;
reg [3:0] cur_state, next_state;
always@(posedge clk or negedge rst)
if (!rst) begin
cur_state <= IDLE;
next_state <= IDLE;
end else begin
cur_state <= next_state;
end
always@(*)
case(cur_state)
IDLE : next_state = (data==1)?S0:IDLE;
S0 : next_state = (data==0)?S1:IDLE;
S1 : next_state = (data==1)?S2:IDLE;
S2 : next_state = (data==1)?S3:S0;
S3 : next_state = (data==1)?S0:S1;
default: next_state = IDLE;
endcase
always@(posedge clk or negedge rst)
if (!rst)
flag <= 1'b0;
else if (cur_state == S3)
flag <= 1'b1;
else
flag <= 1'b0;
//*************code***********//
endmodule
VL37 时钟分频(偶数)
答案1:计数器法
`timescale 1ns/1ns
module even_div
(
input wire rst ,
input wire clk_in,
output wire clk_out2,
output wire clk_out4,
output wire clk_out8
);
//*************code***********//
/*-------------------------------------------------------------
二分频
-----------------------------------------------------------*/
reg clk_out2_reg;
always@(posedge clk_in or negedge rst)
if(!rst)
clk_out2_reg <= 1'b0;
else
clk_out2_reg <= ~clk_out2_reg;
assign clk_out2 = clk_out2_reg;
/*-------------------------------------------------------------
四分频
-----------------------------------------------------------*/
reg [1:0] cnt_4;
always@(posedge clk_in or negedge rst)
if(!rst)
cnt_4 <= 'd0;
// else if(cnt_4 == 'd3)
// cnt_4 <= 1'b0;
else
cnt_4 <= cnt_4 + 1'b1;
reg clk_out4_reg;
always@(posedge clk_in or negedge rst)
if(!rst)
clk_out4_reg <= 1'b0;
else if(cnt_4 < 2'd2)
clk_out4_reg <= 1'b1;
else
clk_out4_reg <= 1'b0;
assign clk_out4 = clk_out4_reg;
/*-------------------------------------------------------------
八分频
-----------------------------------------------------------*/
reg [2:0] cnt_8;
always@(posedge clk_in or negedge rst)
if(!rst)
cnt_8 <= 'b0;
// else if(cnt_8 == 'd7)
// cnt_8 <= 1'b0;
else
cnt_8 <= cnt_8 + 1'b1;
reg clk_out8_reg;
always@(posedge clk_in or negedge rst)
if(!rst)
clk_out8_reg <= 1'b0;
else if(cnt_8 < 3'd4)
clk_out8_reg <= 1'b1;
else
clk_out8_reg <= 1'b0;
assign clk_out8 = clk_out8_reg;
//*************code***********//
endmodule
答案2:寄存器级联法
`timescale 1ns/1ns
module even_div
(
input wire rst ,
input wire clk_in,
output wire clk_out2,
output wire clk_out4,
output wire clk_out8
);
//*************code***********//
reg clk_out2_reg, clk_out4_reg, clk_out8_reg;
always@(posedge clk_in or negedge rst) begin
if(~rst)
clk_out2_reg <= 0;
else
clk_out2_reg <= ~clk_out2_reg;
end
always@(posedge clk_out2 or negedge rst) begin
if(~rst)
clk_out4_reg <= 0;
else
clk_out4_reg <= ~clk_out4_reg;
end
always@(posedge clk_out4 or negedge rst) begin
if(~rst)
clk_out8_reg <= 0;
else
clk_out8_reg <= ~clk_out8_reg;
end
assign clk_out2 = clk_out2_reg;
assign clk_out4 = clk_out4_reg;
assign clk_out8 = clk_out8_reg;
//*************code***********//
endmodule
答案3:取巧思路
`timescale 1ns/1ns
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
复盘
- 推荐一篇文章【数字IC手撕代码】Verilog偶数分频|题目|原理|设计|仿真(二分频,四分频,六分频,八分频,偶数分频及特殊占空比)
VL38 自动贩售机1
答案
`timescale 1ns/1ns
module seller1(
input wire clk ,
input wire rst ,
input wire d1 ,
input wire d2 ,
input wire d3 ,
output reg out1,
output reg [1:0]out2
);
//*************code***********//
parameter IDLE = 4'b0000;
parameter S0 = 4'b0001;
parameter S1 = 4'b0011;
parameter S2 = 4'b0010;
parameter S3 = 4'b0110;
parameter S4 = 4'b0111;
parameter S5 = 4'b0101;
// parameter S6 = 4'b0100;
// parameter S7 = 4'b1100;
reg [3:0] cur_state, next_state;
always@(posedge clk or negedge rst)
if (!rst) begin
cur_state <= IDLE;
end else begin
cur_state <= next_state;
end
always@(*)
case(cur_state)
IDLE :
begin
if(d1)
next_state = S0;
else if(d2)
next_state = S1;
else if(d3)
next_state = S3;
else
next_state = next_state;
end
S0 :
begin
if(d1)
next_state = S1;
else if(d2)
next_state = S2;
else if(d3)
next_state = S4;
else
next_state = next_state;
end
S1 :
begin
if(d1)
next_state = S2;
else if(d2)
next_state = S3;
else if(d3)
next_state = S5;
else
next_state = next_state;
end
default: next_state = IDLE;
endcase
always@(posedge clk or negedge rst)
if (!rst)begin
out1 <= 'd0;
out2 <= 'd0;
end
else begin
case(next_state)
S2:begin out1 <= 1'b1;out2 <= 2'b00;end
S3:begin out1 <= 1'b1;out2 <= 2'b01;end
S4:begin out1 <= 1'b1;out2 <= 2'b10;end
S5:begin out1 <= 1'b1;out2 <= 2'b11;end
default:begin out1 <= 1'b0;out2 <= 2'b00;end
endcase
end
//*************code***********//
endmodule
复盘
本题可以抽象为三输入二输出
,存在状态0 0.5 1 1.5 2 2.5 3
七个状态,
这样输出信号的特性应该为: out1饮料为一位,out2找零为2位(0 1 2 3个0.5元)
因此先做状态转移图:
- 注意,0.5/1/2是不会同时给信号的;在钱数大于2.5时就不能再继续投币了,在下一拍就要回到IDLE。
VL39 自动贩售机2
答案
`timescale 1ns/1ns
module seller2(
input wire clk ,
input wire rst ,
input wire d1 ,
input wire d2 ,
input wire sel ,
output reg out1,
output reg out2,
output reg out3
);
//*************code***********//
parameter IDLE = 4'b0000;
parameter S0 = 4'b0001;
parameter S1 = 4'b0011;
parameter S2 = 4'b0010;
parameter S3 = 4'b0110;
parameter S4 = 4'b0111;
parameter S5 = 4'b0101;
// parameter S6 = 4'b0100;
// parameter S7 = 4'b1100;
reg [3:0] cur_state, next_state;
always@(posedge clk or negedge rst)
if (!rst) begin
cur_state <= IDLE;
end else begin
cur_state <= next_state;
end
always@(*)
case(cur_state)
IDLE :
begin
if(d1)
next_state = S0;
else if(d2)
next_state = S1;
else
next_state = next_state;
end
S0 :
begin
if(d1)
next_state = S1;
else if(d2)
next_state = S2;
else
next_state = next_state;
end
S1 :
begin
if(d1)
next_state = S2;
else if(d2)
next_state = S3;
else
next_state = next_state;
end
S2 :
begin
if(sel == 0)begin
next_state = IDLE;
end else begin
if(d1)
next_state = S3;
else if(d2)
next_state = S4;
else
next_state = next_state;
end
end
S3 :
begin
if(sel == 0)begin
next_state = IDLE;
end else begin
if(d1)
next_state = S4;
else if(d2)
next_state = S5;
else
next_state = next_state;
end
end
default: next_state = IDLE;
endcase
always@(posedge clk or negedge rst)
if (!rst)begin
out1 <= 'd0;
out2 <= 'd0;
out3 <= 'd0;
end
else begin
case(next_state)
S2:
begin
if(sel == 0) begin
out1 <= 1'b1;
out2 <= 1'b0;
out3 <= 1'b0;
end else begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
end
S3:
begin
if(sel == 0) begin
out1 <= 1'b1;
out2 <= 1'b0;
out3 <= 1'b1;
end else begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
end
S4:
begin
out1 <= 1'b0;
out2 <= 1'b1;
out3 <= 1'b0;
end
S5:
begin
out1 <= 1'b0;
out2 <= 1'b1;
out3 <= 1'b1;
end
default:
begin
out1 <= 1'b0;
out2 <= 1'b0;
out3 <= 1'b0;
end
endcase
end
//*************code***********//
endmodule
复盘
- 经典的三段式,状态转移图如下:
- 第一段,时序逻辑寄存下一个状态
- 第二段,组合逻辑计算下一个状态
- 第三段,输出当前状态需要输出的条件
- 如果觉得代码不好看,可以继续更改格式
VL40 占空比50%的奇数分频
答案
`define CNT 3'd7
`timescale 1ns/1ns
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 == `CNT - 1 )
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 == `CNT / 2 || count_p == `CNT - 1 ) 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 == `CNT - 1)
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 == `CNT / 2 || count_n == `CNT - 1 ) begin
clk_n <= ~clk_n;
end
end
end
assign clk_out7 = clk_p | clk_n;
endmodule
复盘
-
前面的答案使用了
上升沿计数器
和下降沿计数器
分别分别生成了两个时钟
,然后将其或
即可 -
参考 Verilog笔记——奇数分频和小数分频
-
其实,我们也可以不使用两个计数器
`define CNT 3'd7
`timescale 1ns/1ns
module odo_div_or (
input wire rst ,
input wire clk_in,
output wire clk_out7
);
//*************code***********//
reg [2:0] count; //计数
reg clk_p; //上升沿分频
reg clk_n; //下降沿分频
//沿计数
always @ ( posedge clk_in or negedge rst )
begin
if( !rst )
count <= 3'b0;
else if( count == `CNT - 1 )
count <= 3'b0;
else
count <= count + 1'b1;
end
//上升沿分频
always @ ( posedge clk_in or negedge rst )
begin
if( !rst ) begin
clk_p <= 1'b0;
end
else begin
if( count == `CNT / 2 || count == `CNT - 1 ) begin
clk_p <= ~clk_p;
end
end
end
//下降沿分频
always @ ( negedge clk_in or negedge rst )
begin
if( !rst ) begin
clk_n <= 1'b0;
end
else begin
if( count == `CNT / 2 || count == `CNT - 1 ) begin
clk_n <= ~clk_n;
end
end
end
assign clk_out7 = clk_p | clk_n;
endmodule
- 推荐文章 【数字IC手撕代码】Verilog奇数分频|题目|原理|设计|仿真(三分频,五分频,奇数分频及特殊占空比)
VL41 任意小数分频
答案
复盘
VL42 无占空比要去的奇数分频
答案
复盘
VL43 根据状态转移写状态机-三段式
答案
复盘
VL44 根据状态转移写状态机-二段式
03 跨时钟域传输
VL45 异步FIFO
答案
`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*****************************************/
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) - 1 + 1;
//通过深度换算出需要多少位宽,因为fifo在最高位需要一个标志位产生满信号,上述再+1
//第二步:给RAM申明缺少的端口信号
///
reg [ADDR_WIDTH:0] waddr,raddr;//写地址,读地址
wire wenc,renc;//写使能信号,读使能信号
//第三步:写地址操作,什么时候写
///
always@(posedge wclk or negedge wrstn) begin
if(!wrstn) begin
waddr <= 'd0;
end
else begin
if(wenc) begin
waddr <= waddr + 1'b1;
end
else begin
waddr <= waddr;
end
end
end
assign wenc = winc && ~wfull;//写使能信号
//第四步:读地址操作,什么时候读
///
always@(posedge rclk or negedge rrstn) begin
if(!rrstn) begin
raddr <= 'd0;
end
else begin
if(renc) begin
raddr <= raddr + 1'b1;
end
else begin
raddr <= raddr;
end
end
end
assign renc = rinc && ~rempty;//读使能信号
//第五步:产生空满信号---->异步 涉及到 跨时钟域同步
//空信号是在读时钟域产生,所以需要将写时钟域的写地址同步到读时钟域
//满信号是在写时钟域产生,所以需要将读时钟域的读地址同步到写时钟域
//---->推荐将跨时钟域的地址转换为格雷码再同步
///
///
//5.1 生成格雷码地址
///
reg [ADDR_WIDTH:0] waddr_gray,raddr_gray;//写地址格雷码,读地址格雷码
always@(posedge wclk or negedge wrstn) begin
if(!wrstn) begin
waddr_gray <= 'd0;
end
else begin
waddr_gray <= waddr ^ (waddr >> 1);
end
end
always@(posedge rclk or negedge rrstn) begin
if(!rrstn) begin
raddr_gray<= 'd0;
end
else begin
raddr_gray <= raddr ^ (raddr >> 1);
end
end
///
//5.2 将格雷码地址同步到相应的时钟域
///
reg [ADDR_WIDTH:0] addr_w2r_reg,addr_w2r;
always@(posedge rclk or negedge rrstn) begin
if(!rrstn) begin
addr_w2r_reg <= 'd0;
addr_w2r <= 'd0;
end
else begin
addr_w2r_reg <= waddr_gray;
addr_w2r <= addr_w2r_reg;
end
end
reg [ADDR_WIDTH:0] addr_r2w_reg,addr_r2w;
always@(posedge wclk or negedge wrstn) begin
if(!wrstn) begin
addr_r2w_reg <= 'd0;
addr_r2w <= 'd0;
end
else begin
addr_r2w_reg <= raddr_gray;
addr_r2w <= addr_r2w_reg;
end
end
///
//5.3 产生空满信号
///
assign wfull = (waddr_gray == {~addr_r2w[ADDR_WIDTH:ADDR_WIDTH-1],addr_r2w[ADDR_WIDTH-2:0]});
assign rempty = (raddr_gray == addr_w2r);
//第一步:例化双口RAM
///
dual_port_RAM
#(
.DEPTH(DEPTH)
,.WIDTH(WIDTH)
)
dual_port_RAM_inst
(
.wclk (wclk )
,.wenc (wenc )
,.waddr (waddr[ADDR_WIDTH - 1 : 0] ) //深度对2取对数,得到地址的位宽。
,.wdata (wdata ) //数据写入
,.rclk (rclk )
,.renc (renc )
,.raddr (raddr[ADDR_WIDTH - 1 : 0] ) //深度对2取对数,得到地址的位宽。
,.rdata (rdata ) //数据输出
);
endmodule
复盘
- 异步fifo,而且还是通过双口RAM充当存储结构
- 常规的思路就是,
先进行例化,缺什么信号,补什么信号
。具体的步骤已经在答案中做了详细的注释 - 推荐查看【FPGA——基础篇】同步FIFO与异步FIFO——Verilog实现了解不使用双口RAM如何手撕。
VL46 同步FIFO
答案
`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************************************/
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) - 1 + 1;
//通过深度换算出需要多少位宽,因为fifo在最高位需要一个标志位产生满信号,上述再+1
//第二步:给RAM申明缺少的端口信号
///
reg [ADDR_WIDTH:0] waddr,raddr;//写地址,读地址
wire wenc,renc;//写使能信号,读使能信号
//第三步:写地址操作,什么时候写
///
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
waddr <= 'd0;
end
else begin
if(wenc) begin
waddr <= waddr + 1'b1;
end
else begin
waddr <= waddr;
end
end
end
assign wenc = winc && ~wfull;//写使能信号
//第四步:读地址操作,什么时候读
///
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
raddr <= 'd0;
end
else begin
if(renc) begin
raddr <= raddr + 1'b1;
end
else begin
raddr <= raddr;
end
end
end
assign renc = rinc && ~rempty;//读使能信号
//第五步:产生空满信号
///
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
wfull <= 'd0;
rempty <= 'd0;
end
else begin
wfull <= ((waddr[ADDR_WIDTH] != raddr[ADDR_WIDTH]) && (waddr[ADDR_WIDTH-1:0] == raddr[ADDR_WIDTH-1:0]));
rempty <= raddr == waddr;
end
end
//第一步:例化双口RAM
///
dual_port_RAM
#(
.DEPTH(DEPTH)
,.WIDTH(WIDTH)
)
dual_port_RAM_inst
(
.wclk (clk )
,.wenc (wenc )
,.waddr (waddr ) //深度对2取对数,得到地址的位宽。
,.wdata (wdata ) //数据写入
,.rclk (clk )
,.renc (renc )
,.raddr (raddr ) //深度对2取对数,得到地址的位宽。
,.rdata (rdata ) //数据输出
);
endmodule
复盘
- 同步fifo,而且还是通过双口RAM充当存储结构
- 常规的思路就是,
先进行例化,缺什么信号,补什么信号
。具体的步骤已经在答案中做了详细的注释 - 推荐查看【FPGA——基础篇】同步FIFO与异步FIFO——Verilog实现了解不使用双口RAM如何手撕。
VL47 格雷码计数器
答案
- 什么逆天计数器,两个时钟周期
`timescale 1ns/1ns
module gray_counter(
input clk,
input rst_n,
output reg [3:0] gray_out
);
reg [4:0] bin_cnt = 'd0;
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
bin_cnt <= 'd0;
end
else begin
bin_cnt <= bin_cnt + 'd1;
end
end
wire [3:0] bin;
assign bin = bin_cnt[4:1];
always @ (*)
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
module gray_counter(
input clk,
input rst_n,
output reg [3:0] gray_out
);
reg [4:0] bin_cnt = 'd0;
always @ (posedge clk or rst_n)
begin
if( ~rst_n ) begin
bin_cnt <= 'd0;
gray_out <= 'd0;
end
else begin
bin_cnt <= bin_cnt + 'd1;
gray_out <= bin_cnt[4:1] ^ (bin_cnt[4:1]>>1);
end
end
endmodule
既然是两个时钟周期出结果,我们可以先讲时钟进行二分频,在该时钟下完成计数器累加
`timescale 1ns/1ns
module gray_counter(
input clk,
input rst_n,
output reg [3:0] gray_out
);
reg clk2;
always @ (posedge clk or negedge rst_n)
if(!rst_n)
clk2 <= 'b0;
else
clk2 <= ~clk2;
reg [3:0] bin_cnt = 'd0;
always @ (posedge clk2 or negedge rst_n)
begin
if( !rst_n ) begin
bin_cnt <= 'd0;
end
else begin
bin_cnt <= bin_cnt + 'd1;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
gray_out <= 0;
end
else begin
gray_out = (bin_cnt >> 1) ^ bin_cnt;
end
end
endmodule
复盘
- 格雷码与二进制的转换
VL48 多bit MUX同步器
答案
`timescale 1ns/1ns
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
);
reg data_en_b,data_en_b_reg;
reg [3:0] data_in_b,data_in_b_reg;
always@(posedge clk_b or negedge brstn) begin
if(!brstn)begin
{data_en_b,data_en_b_reg} <= 'd0;
{data_in_b,data_in_b_reg} <= 'd0;
end
else begin
{data_en_b,data_en_b_reg} <= {data_en_b_reg,data_en};
{data_in_b,data_in_b_reg} <= {data_in_b_reg,data_in};
end
end
always@(posedge clk_b or negedge brstn) begin
if(!brstn)begin
dataout <= 'd0;
end
else if (data_en_b)begin
dataout <= data_in_b;
end
else begin
dataout <= dataout;
end
end
endmodule
复盘
- 注意对比异步FIFO的格雷码跨时钟域同步
VL49 脉冲同步电路
答案
`timescale 1ns/1ns
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
复盘
04 计数器
VL50 简易秒表
答案
`timescale 1ns/1ns
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 <= 'd0;
end
else if (minute == 'd60)begin
second <= 'd0;
end
else if (second == 'd60)begin
second <= 'd1;
end
else begin
second <= second + 'd1;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
minute <= 'd0;
end
// else if (minute == 'd60)begin
// minute <= minute;
// end
else if(second == 'd60)begin
minute <= minute + 'd1;
end
else begin
minute <= minute;
end
end
endmodule
复盘
- 就是简单的计数器
- 注意思考,被注释掉的三行代码,
VL51 可置位计数器
答案
`timescale 1ns/1ns
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] cnt;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 'd0;
end
else if(set) begin
cnt <= set_num;
end
else begin
cnt <= cnt + 1'b1;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
zero <= 'd0;
end
else if(cnt == 'd0)begin
zero <= 1'b1;
end else begin
zero <= 1'b0;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
number <= 'd0;
end
else begin
number <= cnt;
end
end
endmodule
复盘
- 计数器的基础上,增加了设置计数器数值的功能
VL52 加减计数器
答案
`timescale 1ns/1ns
module count_module(
input clk,
input rst_n,
input mode,
output reg [3:0]number,
output reg zero
);
reg [3:0] cnt;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 'd0;
end
else if(mode) begin
if(cnt == 'd9) begin
cnt <= 'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
else begin
if(cnt == 'd0) begin
cnt <= 'd9;
end
else begin
cnt <= cnt - 1'b1;
end
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
zero <= 'd0;
end
else if(cnt == 'd0)begin
zero <= 1'b1;
end else begin
zero <= 1'b0;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
number <= 'd0;
end
else begin
number <= cnt;
end
end
endmodule
复盘
- 就是在计数器的逻辑上增加了一些基本条件
05 存储器
VL53 单端口RAM
答案
`timescale 1ns/1ns
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] mem [127:0];
reg[3:0] data;
integer i;
always@(posedge clk or negedge rst) begin
if(!rst)begin
for(i = 0; i < 128; i = i + 1)begin
mem[i] = 'd0;
end
end
else if(enb)
mem[addr] <= w_data;
end
reg [3:0] r_data_reg;
always@(*) begin
r_data_reg = 'd0;
if(~enb)
r_data_reg = mem[addr];
end
// always@(negedge clk or negedge rst) begin
// if(!rst)begin
// r_data_reg <= 'd0;
// end
// else if(~enb)
// r_data_reg <= mem[addr];
// end
assign r_data = r_data_reg;
//*************code***********//
endmodule
复盘
- enb=1的时候是写,addr就是写地址,enb=0的时候读,addr就是读地址。
- 深度是128bit, 宽度是4bit. 使用reg [3:0] ram_reg[127:0]表示。这个初始化不能用 ram_reg <= 'd0; 需要用一个for循环来实现初始化。
- 注意思考被注释的逻辑与上述组合逻辑的区别
VL54 RAM的简单实现
答案
`timescale 1ns/1ns
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 [255:0];
integer i; // 不可综合
// reg [8:0] i;
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
for(i=0;i<256;i=i+1)
RAM[i] <= 0;
else if(write_en)
RAM[write_addr] <= write_data;
else
RAM[write_addr] <= RAM[write_addr];
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
read_data <= 0;
else if(read_en)
read_data <= RAM[read_addr];
else
read_data <= read_data;
end
endmodule
复盘
- 最基本的双口RAM
06 综合
VL55 Johnson Counter
答案
`timescale 1ns/1ns
module JC_counter(
input clk ,
input rst_n,
output reg [3:0] Q
);
always@(posedge clk or negedge rst_n)
if(!rst_n)
Q <= 'd0;
else
Q <= {~Q[0],Q[3:1]};
endmodule
复盘
- 实现思路:将最后一位
取反
,挪到最高位
VL56 流水线乘法器
答案
`timescale 1ns/1ns
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 [7:0] addr01;
reg [7:0] addr23;
wire [7:0] temp0 ;
wire [7:0] temp1 ;
wire [7:0] temp2 ;
wire [7:0] temp3 ;
assign temp0 = mul_b[0]? {4'b0, mul_a} : 'd0;
assign temp1 = mul_b[1]? {3'b0, mul_a, 1'b0} : 'd0;
assign temp2 = mul_b[2]? {2'b0, mul_a, 2'b0} : 'd0;
assign temp3 = mul_b[3]? {1'b0, mul_a, 3'b0} : 'd0;
always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin
addr01 <= 'd0;
addr23 <= 'd0;
mul_out <= 'd0;
end
else begin
addr01 <= temp0 + temp1;
addr23 <= temp2 + temp3;
mul_out <= addr01 + addr23;
end
end
endmodule
复盘
- 略
VL57 交通灯
答案
- 略
复盘
VL58 游戏机计费程序
答案
- 略
复盘
Part III Verilog企业真题
- 如果你想练习真题,可以点击链接:《牛客刷verilog》Part III Verilog企业真题
后记
推荐相关文章
- 校招Verilog篇刷题
- B站-FPGA数字IC牛客Verilog刷题
- FPGA数字IC刷题58道Verilog题解代码及视频讲解【FPGA探索者】【同步/异步FIFO】【跨时钟】
最后
以上就是故意世界为你收集整理的《牛客刷verilog》Part II Verilog进阶挑战前言Part I Verilog快速入门Part II Verilog进阶挑战Part III Verilog企业真题后记的全部内容,希望文章能够帮你解决《牛客刷verilog》Part II Verilog进阶挑战前言Part I Verilog快速入门Part II Verilog进阶挑战Part III Verilog企业真题后记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复