概述
47.格雷码计数器
reg [3:0] bin_out;
wire [3:0] gray_wire;
//格雷码转二进制
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
bin_out <= 4'b0;
else begin
bin_out[3] = gray_wire[3];
bin_out[2] = gray_wire[2]^bin_out[3];
bin_out[1] = gray_wire[1]^bin_out[2];
bin_out[0] = gray_wire[0]^bin_out[1];
end
end
//二进制加一
reg [3:0] bin_addr;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
bin_addr <= 4'd0;
end
else
bin_addr <= bin_out +1'b1;
end
//二级制转格雷码
assign gray_wire = (bin_addr >> 1 ) ^ bin_addr;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
gray_out <= 4'b0;
end
else
gray_out <= gray_wire;
end
46.同步FIFO
在例化双口 RAM 的时候,读写使能 renc/wenc 信号如果只是传入 rinc 和 winc 也能通过题目的波 形测试,但是仔细思考其实不对,此时如果是满的情况下有外部的写使能 winc,虽然写地址不变,但是对于 RAM 来讲写使能还是有效的,会覆盖数据,所以这里的 RAM 写使能信号 wenc = winc && (~wfull),RAM 读使能 renc = rinc && (~rempty),这样才能保证不会在空满情况下对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************************************/
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);//局部参数 //深度对2取对数,得到地址的位宽
reg [ADDR_WIDTH:0] waddr;
reg [ADDR_WIDTH:0] raddr;
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
always@(posedge clk or negedge rst_n)begin //写操作
if(!rst_n)
waddr <= 'b0;
else begin
if(winc && ~wfull)
waddr <= waddr + 1'b1;
else
waddr <= waddr;
end
end
always@(posedge clk or negedge rst_n)begin //读操作
if(!rst_n)
raddr <= 'b0;
else begin
if(rinc && ~rempty)
raddr <= raddr + 1'b1;
else
raddr <= raddr;
end
end
dual_port_RAM //RAM例化
#(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM_U0
(
.wclk(clk),
.rclk(clk),
.wenc(winc&&~wfull),
.waddr(waddr[ADDR_WIDTH-1:0]),
.wdata(wdata),
.renc(rinc&&~rempty),
.raddr(raddr[ADDR_WIDTH-1:0]),
.rdata(rdata)
);
endmodule
45.异步FIFO
在同步FIFO基础上,进行异步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);
reg [ADDR_WIDTH:0] waddr;
reg [ADDR_WIDTH:0] raddr;
always@(posedge wclk or negedge wrstn)begin //写操作
if(!wrstn)
waddr <= 'b0;
else
if(winc && ~wfull)
waddr <= waddr + 1'b1;
else
waddr <= waddr;
end
always@(posedge rclk or negedge rrstn)begin //读操作
if(!rrstn)
raddr <= 'b0;
else
if(rinc && ~rempty)
raddr <= raddr + 1'b1;
else
raddr <= raddr;
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)
waddr_gray_reg <= 'b0;
else
waddr_gray_reg <= waddr_gray;
end
reg [ADDR_WIDTH:0] raddr_gray_reg;
always@(posedge rclk or negedge rrstn)begin
if(!rrstn)
raddr_gray_reg <= 'b0;
else
raddr_gray_reg <= raddr_gray;
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 <= 'b0;
addr_r2w <= 'b0;
end
else begin
addr_r2w_t <= raddr_gray_reg; //2级寄存器,将读地址传输
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 <= 'b0;
addr_w2r <= 'b0;
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);
dual_port_RAM //例化双口RAM
#(
.DEPTH(DEPTH),
.WIDTH(WIDTH)
)
dual_port_RAM_U0
(
.wclk(wclk),
.wenc(winc&&~wfull),
.waddr(waddr[ADDR_WIDTH-1:0]),
.wdata(wdata),
.rclk(rclk),
.renc(rinc&&~rempty),
.raddr(raddr[ADDR_WIDTH-1:0]),
.rdata(rdata)
);
48.多bit MUX同步器
-
data_in
:数据输入;data_en
:输入数据有效;dataout
数据输出。 - 输入数据暂存在
data_reg
中,使能信号data_en
用打两拍的方式跨时钟域传输到时钟域B,最后data_out
根据使能信号更新数据。
reg [3:0] data_reg;
reg data_en_a,data_en_b0,data_en_b1;
always@(posedge clk_a or negedge arstn)begin clk_a 时钟域的 data_in 寄存
if(!arstn)
data_reg <= 'b0;
else
data_reg <= data_in;
end
always@(posedge clk_a or negedge arstn)begin // clk_a时钟域的 data_en寄存
if(!arstn)
data_en_a <= 'b0;
else
data_en_a <= data_en;
end
always@(posedge clk_b or negedge brstn)begin //data_en 打两拍传输
if(!brstn)begin
data_en_b0 <= 'b0;
data_en_b1 <= 'b0;
end
else begin
data_en_b0 <= data_en_a;
data_en_b1 <= data_en_b0;
end
end
always@(posedge clk_b or negedge brstn) begin
if(~brstn)
dataout <= 0;
else
dataout <= data_en_b1? data_reg: dataout;
end
endmodule
49. 脉冲同步电路(快时钟到慢时钟、翻转展宽)
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;
最后
以上就是明理钢铁侠为你收集整理的IC笔试牛客网verilog刷题总结四的全部内容,希望文章能够帮你解决IC笔试牛客网verilog刷题总结四所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复