VL42 无占空比要去的奇数分频
`timescale 1ns/1ns module odd_div ( input wire rst , input wire clk_in , output wire clk_out5 ); //*************code***********// reg [ 2:0] data_cnt ; always @(posedge clk_in or negedge rst) begin if (!rst) begin data_cnt <= 'd0; end else begin if(data_cnt == 3'd4) begin data_cnt <= 3'd0; end else begin data_cnt <= data_cnt + 1'd1; end end end reg clk_out_cache ; always @(posedge clk_in or negedge rst) begin if (!rst) begin clk_out_cache <= 1'b0; end else if (data_cnt == 3'd0 || data_cnt == 3'd2) begin clk_out_cache <= ~clk_out_cache; end else begin clk_out_cache <= clk_out_cache; end end assign clk_out5 = clk_out_cache; endmodule
VL43 根据状态转移写状态机-三段式
`timescale 1ns/1ns module fsm1( input wire clk , input wire rst , input wire data , output reg flag ); //*************code***********// parameter s0 = 3'b000; parameter s1 = 3'b001; parameter s2 = 3'b010; parameter s3 = 3'b100; reg [2:0] st_cur,next_cur; always @(posedge clk or negedge rst) begin if (!rst) begin st_cur <= s0; end else begin st_cur <= next_cur; end end always @(*) begin case (st_cur) s0:begin next_cur = (data)?s1:s0; end s1: begin next_cur = (data)?s2:s1; end s2: begin next_cur = (data)?s3:s2; end s3: begin next_cur = (data)?s0:s3; end default: next_cur = s0; endcase end always @(posedge clk or negedge rst) begin if(!rst) begin flag <= 1'b0; end else begin if(st_cur == s3) begin if (data) begin flag <= 1'b1; end else begin flag <= 1'b0; end end else begin flag <= 1'b0; end end end //*************code***********// endmodule
VL44 根据状态转移写状态机-二段式
`timescale 1ns/1ns module fsm2( input wire clk , input wire rst , input wire data , output reg flag ); //*************code***********// parameter s0 = 4'b0000; parameter s1 = 4'b0001; parameter s2 = 4'b0010; parameter s3 = 4'b0100; parameter s4 = 4'b1000; reg [3:0] st_cur,next_cur; always @(posedge clk or negedge rst) begin if (!rst) begin st_cur <= s0; end else begin st_cur <= next_cur; end end always @(*) begin if(!rst) begin flag <= 1'b0; // next_cur = s0; end case (st_cur) s0: begin next_cur = data?s1:s0; flag <= 1'b0; end s1: begin next_cur = data?s2:s1; flag <= 1'b0; end s2: begin next_cur = data?s3:s2; flag <= 1'b0; end s3: begin next_cur = data?s4:s3; flag <= 1'b0; end s4: begin next_cur = data?s1:s0; flag <= 1'b1; end default: begin next_cur = s0; flag <= 1'b0; end endcase end //*************code***********// endmodule
03 跨时钟域传输
VL45 异步FIFO
`timescale 1ns/1ns /***************************************RAM*****************************************/ module dual_port_RAM #( parameter DEPTH = 16 , //ram的存储空间8*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#( //8为宽,数据深度为16,则用4位地址可以表示 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); //定义地址宽度 //定义双端口ram的读写地址 wire [ADDR_WIDTH-1:0] wr_adr ;//双端口ram的写地址 wire [ADDR_WIDTH-1:0] rd_adr ;//双端口ram的读地址 reg [ADDR_WIDTH:0] wr_adr_ptr ;//写指针 reg [ADDR_WIDTH:0] rd_adr_ptr ;//读指针 //转换为格雷码进行打拍操作 wire [ADDR_WIDTH:0] wr_adr_gray ;//写地址指针二进制转化为格雷码 reg [ADDR_WIDTH:0] wr_adr_gray1 ;//打一拍缓存 reg [ADDR_WIDTH:0] wr_adr_gray2 ;//打两拍缓存 wire [ADDR_WIDTH:0] rd_adr_gray ;//读地址指针二进制转化为格雷码 reg [ADDR_WIDTH:0] rd_adr_gray1 ;//打一拍缓存 reg [ADDR_WIDTH:0] rd_adr_gray2 ;//打两拍缓存 //读写地址比控制指针少一位 assign wr_adr = wr_adr_ptr[ADDR_WIDTH-1:0]; assign rd_adr = rd_adr_ptr[ADDR_WIDTH-1:0]; //写地址指针控制 always @(posedge wclk or negedge wrstn) begin if (!wrstn) begin wr_adr_ptr <= 'd0; end else begin if(winc && (~wfull)) begin wr_adr_ptr <= wr_adr_ptr + 1'b1; end else begin wr_adr_ptr <= wr_adr_ptr; end end end //读地址指针控制 always @(posedge rclk or negedge rrstn) begin if (!rrstn) begin rd_adr_ptr <= 'd0; end else begin if(rinc && (~rempty)) begin rd_adr_ptr <= rd_adr_ptr + 1'b1; end else begin rd_adr_ptr <= rd_adr_ptr; end end end //二进制指针转化为格雷码 assign wr_adr_gray = (wr_adr_ptr >> 1) ^ wr_adr_ptr; assign rd_adr_gray = (rd_adr_ptr >> 1) ^ rd_adr_ptr; reg [ADDR_WIDTH:0] wr_adr_gray_reg ;//写地址指针二进制转化为格雷码 always @(posedge wclk or negedge wrstn) begin if (!wrstn) begin wr_adr_gray_reg <= 'd0; end else begin wr_adr_gray_reg <= wr_adr_gray; end end reg [ADDR_WIDTH:0] rd_adr_gray_reg ;//写地址指针二进制转化为格雷码 always @(posedge rclk or negedge rrstn) begin if (!rrstn) begin rd_adr_gray_reg <= 'd0; end else begin rd_adr_gray_reg <= rd_adr_gray; end end //格雷码的同步 读时钟域同步到写时钟域 always @(posedge wclk or negedge wrstn) begin if (!wrstn) begin rd_adr_gray1 <= 'd0; rd_adr_gray2 <= 'd0; end else begin rd_adr_gray1 <= rd_adr_gray_reg; rd_adr_gray2 <= rd_adr_gray1; end end //格雷码的同步 写时钟域同步到读时钟域 always @(posedge rclk or negedge rrstn) begin if (!rrstn) begin wr_adr_gray1 <= 'd0; wr_adr_gray2 <= 'd0; end else begin wr_adr_gray1 <= wr_adr_gray_reg; wr_adr_gray2 <= wr_adr_gray1; end end assign rempty = (rd_adr_gray_reg == wr_adr_gray2) ? 1'b1 : 1'b0; assign wfull = (wr_adr_gray_reg[ADDR_WIDTH] != rd_adr_gray2[ADDR_WIDTH]) && (wr_adr_gray[ADDR_WIDTH-1] != rd_adr_gray2[ADDR_WIDTH-1]) && (wr_adr_gray[ADDR_WIDTH-2:0] == rd_adr_gray2[ADDR_WIDTH-2:0]); dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH)) u_dual_port_RAM( .wclk(wclk), .rclk(rclk), .wenc(winc && (~wfull)), .renc(rinc && (~rempty)), .waddr(wr_adr), .raddr(rd_adr), .wdata(wdata), .rdata(rdata) ); endmodule
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] ;//开辟宽度为WIDTH,深度为DEPTH的RAM_MEM //向RAM_MEM中写入数据,其中waddr写地址 always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end //从RAM_MEM读出数据,其中raddr为读地址 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) ; 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 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 dual_port_RAM #( .DEPTH(DEPTH), .WIDTH(WIDTH) ) dual_port_RAM_U0( .wclk(clk), .wenc(winc&&~wfull), .waddr(waddr[ADDR_WIDTH-1:0]), .wdata(wdata), .rclk(clk), .renc(rinc&&~rempty), .raddr(raddr[ADDR_WIDTH-1:0]), .rdata(rdata) ); endmodule