//synchronous fifo
module FIFO_syn #(
parameter WIDTH = 16, // the fifo wide
parameter DEPTH = 1024, // deepth
parameter ADDR_WIDTH = clogb2(DEPTH) // bit wide
// parameter PROG_EMPTY = 100, // this what we set to empty
// parameter PROG_FULL = 800 // this what we set to full
)
(
input sys_clk ,
input sys_rst_n ,
input wr_en ,
input rd_en ,
input [WIDTH-1: 0] din ,
output reg full ,
output reg empty , /// 1 is real empty 0 is no empty
output reg [WIDTH-1:0] dout
);
//========================================================================================//
// define parameter and internal signals //
//======================================================================================//
reg [WIDTH-1 : 0] ram[DEPTH-1 : 0] ; // this we set a 15:0 total 1024 number ram
reg [ADDR_WIDTH-1 : 0] wr_addr ; // this is write pointer
reg [ADDR_WIDTH-1 : 0] rd_addr ; // this is read pointer
reg [ADDR_WIDTH-1 : 0] fifo_cnt ;
//=========================================================================================//
// next is main code //
//=========================================================================================//
// we set a function let me to count the number
function integer clogb2; // remember integer has symbol reg has no symbol
input[31:0]value;
begin
value=value-1;
for(clogb2=0;value>0;clogb2=clogb2+1)
value=value>>1;
end
endfunction
// this you can see from the PPT 5-74
//=================================================== next is used to read
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 0)
rd_addr <= {ADDR_WIDTH{1'b0}};
else if(rd_en && !empty)
begin
rd_addr <= rd_addr+1'd1;
dout <= ram[rd_addr];
end
else
begin
rd_addr <= rd_addr;
dout <= dout;
end
end
//=================================================== next is used to write
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 0)
begin
wr_addr <= {ADDR_WIDTH{1'b0}} ; // this let pointer to zero
end
else if( wr_en && !full )
begin // no full and wr_en and whether to write prog_full there
wr_addr <= wr_addr + 1'b1 ;
ram[wr_addr] <= din ;
end
else
wr_addr <= wr_addr ;
end
//============================================================== next is used to set fifo_cnt
always@(posedge sys_clk or negedge sys_rst_n )
begin
if(sys_rst_n == 0)
begin
fifo_cnt <= {ADDR_WIDTH{1'b0}};
end
else if(wr_en && !full && !rd_en)
begin
fifo_cnt <= fifo_cnt + 1'b1 ;
end
else if(rd_en && !empty && !wr_en)
begin
fifo_cnt <= fifo_cnt - 1'b1 ;
end
else
fifo_cnt <= fifo_cnt ;
end
//========================================================== next is empty
// we set counter so when the count is zero empty
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 0)
begin
empty <= 1'b1 ; // begin we set empty to high
end
// there is two possibilties first no write fifo_cnt is all zero
//second is no write it will be change to zero is just a will empty signal
else
empty <= (!wr_en && (fifo_cnt[ADDR_WIDTH-1:1] == 'b0))&&((fifo_cnt[0] == 1'b0) || rd_en);
end
//============================================================ next is full
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 0 )
full <= 1'b1;//reset:1
else
full <= (!rd_en && (fifo_cnt[ADDR_WIDTH-1:1]=={(ADDR_WIDTH-1){1'b1}})) && ((fifo_cnt[0] == 1'b1) || wr_en);
end
endmodule
module uumultiplier #(
parameter NUMBER1 = 8 ,
parameter NUMBER2 = 8
)(
input [NUMBER1-1 : 0] input1 ,
input [NUMBER2-1 : 0] input2 ,
input clk ,
input rst_n ,
input begin_en ,
output reg finish_en ,
output reg [NUMBER1+NUMBER2 : 0] out
);
//======================================================================================\
// define parameter and internal signal \
//======================================================================================\
reg [1:0] LCD = 2'b10 ;
reg [1:0] LCD1 ;
//==========================================================================================\
// next is main code \\
//===========================================================================================\\
always@(posedge clk or negedge rst_n) begin
if(rst_n == 0)
begin
out <= 0 ;
end
else
LCD1 <= LCD ;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
begin
out <= 0 ;
end
else if(begin_en && finish_en )
begin
out <= input1 * input2 ;
LCD <= {LCD[0],LCD[1]} ;
end
else
out <= out ;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
begin
finish_en <= 1'b1 ;
end
else if(LCD == LCD1)
begin
finish_en <= 1'b1 ;
end
else
finish_en <= 1'b0 ;
end
endmodule
//DUal ended RAM
module RAM #(
parameter WIDTH = 8 ,
parameter DEPTH = 16 ,
parameter ADD_WIDTH = clogb2(DEPTH)
)(
input wr_clk ,
input rd_clk ,
input wr_en ,
input rd_en ,
input [WIDTH-1 : 0 ] din ,
input [ADD_WIDTH-1 : 0] wr_address ,
output reg [WIDTH-1 : 0 ] dout ,
input [ADD_WIDTH-1 : 0] rd_address
);
//==================================================================================\\
// define parameter and internal signal \\
//==================================================================================\\
reg [WIDTH - 1 : 0 ] ram [DEPTH - 1 : 0] ;
//==================================================================================\\
// next is main code \\
//==================================================================================\\
function integer clogb2 ;
input [31:0] value ;
begin
value = value - 1 ;
for(clogb2 = 0 ; value > 0 ; clogb2 = clogb2 + 1)
value = value >> 1 ;
end
endfunction
// write
always@(posedge wr_clk)
begin
if(wr_en) begin
ram[wr_address] <= din ;
end
end
//read
always@(posedge rd_clk)
begin
if(rd_en) begin
dout <= ram[rd_address] ;
end
end
endmodule
module dig_top #(
parameter FIFO_WIDTH = 8 ,
parameter FIFO_DEPTH = 8 ,
parameter FIFO_ADDR_WIDTH = clogb2(FIFO_DEPTH) ,
parameter NUMBER1 = 8 ,
parameter NUMBER2 = 2 ,
parameter RAM_WIDTH = NUMBER1+NUMBER2+1 ,
parameter RAM_DEPTH = 8 ,
parameter RAM_ADDR_WIDTH = clogb2(RAM_DEPTH)
)(
input sys_clk ,
input sys_rst_n ,
input wr_en ,
input rd_en ,
input [FIFO_WIDTH-1 : 0] din ,
input RAM_rd_en ,
input [RAM_ADDR_WIDTH-1 : 0] wr_address ,
input [RAM_ADDR_WIDTH-1 : 0] rd_address ,
output wire [RAM_WIDTH-1 : 0] dout
);
//=============================================================================\
// define parameter and internal signals \
//=============================================================================\
wire full ;
wire empty ;
wire [FIFO_WIDTH-1 : 0] dout1 ;
wire finish_en ;
wire [RAM_WIDTH-1 : 0 ] dout2 ;
//===============================================================================\
// next is main code \
//=================================================================================\
function integer clogb2 ;
input [31:0] value ;
begin
value = value - 1 ;
for( clogb2 = 0 ; value > 0 ; clogb2 = clogb2 + 1)
value = value >>1 ;
end
endfunction
FIFO_syn # (
.WIDTH(FIFO_WIDTH),
.DEPTH(FIFO_DEPTH),
.ADDR_WIDTH(FIFO_ADDR_WIDTH)
)
FIFO_syn_inst (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.wr_en(wr_en),
.rd_en(rd_en),
.din(din),
.full(full),
.empty(empty),
.dout(dout1)
);
uumultiplier # (
.NUMBER1(NUMBER1),
.NUMBER2(2'b10)
)
uumultiplier_inst (
.input1(dout1),
.input2(2'b10),
.clk(sys_clk),
.rst_n(sys_rst_n),
.begin_en(rd_en),
.finish_en(finish_en),
.out(dout2)
);
RAM # (
.WIDTH(RAM_WIDTH),
.DEPTH(RAM_DEPTH),
.ADD_WIDTH(RAM_ADDR_WIDTH)
)
RAM_inst (
.wr_clk(sys_clk),
.rd_clk(sys_clk),
.wr_en(finish_en),
.rd_en(RAM_rd_en),
.din(dout2),
.wr_address(wr_address),
.dout(dout),
.rd_address(rd_address)
);
endmodule
`timescale 1ns/1ns
module top_tb #(
parameter FIFO_WIDTH = 4 ,
parameter FIFO_DEPTH = 8 ,
parameter FIFO_ADDR_WIDTH = 3 ,
parameter NUMBER1 = 4 ,
parameter NUMBER2 = 2 ,
parameter RAM_WIDTH = 7 ,
parameter RAM_DEPTH = 8 ,
parameter RAM_ADDR_WIDTH = 3
);
reg sys_clk ;
reg sys_rst_n ;
reg wr_en ;
reg rd_en ;
reg [FIFO_WIDTH-1 : 0] din ;
reg RAM_rd_en ;
reg [RAM_ADDR_WIDTH-1 : 0] wr_address ;
reg [RAM_ADDR_WIDTH-1 : 0] rd_address ;
wire [RAM_WIDTH-1 : 0] dout ;
reg [11:0 ] cnt ;
dig_top # (
.FIFO_WIDTH(FIFO_WIDTH),
.FIFO_DEPTH(FIFO_DEPTH),
.FIFO_ADDR_WIDTH(FIFO_ADDR_WIDTH),
.NUMBER1(NUMBER1),
.NUMBER2(NUMBER2),
.RAM_WIDTH(RAM_WIDTH),
.RAM_DEPTH(RAM_DEPTH),
.RAM_ADDR_WIDTH(RAM_ADDR_WIDTH)
)
dig_top_inst (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.wr_en(wr_en),
.rd_en(rd_en),
.din(din),
.RAM_rd_en(RAM_rd_en),
.wr_address(wr_address),
.rd_address(rd_address),
.dout(dout)
);
always #5 sys_clk = ~sys_clk ;
initial begin
sys_clk = 1;
sys_rst_n = 0;
#100
sys_rst_n = 1;
end
always #10 sys_clk = ~sys_clk;
initial begin
sys_clk = 0 ;
sys_rst_n = 1 ;
wr_en = 0 ;
rd_en = 0 ;
wr_address = 1 ;
rd_address = 1 ;
#10
sys_rst_n = 0;
#10
sys_rst_n = 1 ;
#10
// next is write
wr_en = 1 ;
rd_en = 1 ;
din = 2 ;
// RAM read
RAM_rd_en = 1 ;
end
endmodule