HITDAQ/FPGA_firmware/q_sys/synthesis/submodules/fifo_with_byteenables.v
2024-10-11 14:49:54 +02:00

186 lines
5.4 KiB
Verilog

// (C) 2001-2019 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other
// software and tools, and its AMPP partner logic functions, and any output
// files from any of the foregoing (including device programming or simulation
// files), and any associated documentation or information are expressly subject
// to the terms and conditions of the Intel Program License Subscription
// Agreement, Intel FPGA IP License Agreement, or other applicable
// license agreement, including, without limitation, that your use is for the
// sole purpose of programming logic devices manufactured by Intel and sold by
// Intel or its authorized distributors. Please refer to the applicable
// agreement for further details.
/*
This FIFO module behaves similar to scfifo in legacy mode. It has an
output latency of 1 or 2 clock cycles and does not support look ahead
mode. Unlike scfifo this FIFO allows you to write to any of the byte
lanes before committing the word. This allows you to write the full
word in multiple clock cycles and then you assert the "push" signal to
commit the data. To read data out of the FIFO assert "pop" and wait
1 or 2 clock cycles for valid data to arrive.
Version 1.1
1.0 - Uses 'altsyncram' which will not be optimized away if the
FIFO inputs are grounded. This will need to be replaced
with inferred memory once Quartus II supports inferred
with byte enables (currently it instantiates multiple
seperate memories.
1.1 - Seperated the asynchronous reset into seperate async. and sync.
resets.
*/
// synthesis translate_off
`timescale 1ns / 1ps
// synthesis translate_on
// turn off superfluous verilog processor warnings
// altera message_level Level1
// altera message_off 10034 10035 10036 10037 10230 10240 10030
module fifo_with_byteenables (
clk,
areset,
sreset,
write_data,
write_byteenables,
write,
push,
read_data,
pop,
used,
full,
empty
);
parameter DATA_WIDTH = 32;
parameter FIFO_DEPTH = 128;
parameter FIFO_DEPTH_LOG2 = 7; // this impacts the width of the used port so it can't be local
parameter LATENCY = 1; // number of clock cycles after asserting 'pop' that valid data comes out
input clk;
input areset;
input sreset;
input [DATA_WIDTH-1:0] write_data;
input [(DATA_WIDTH/8)-1:0] write_byteenables;
input write;
input push; // when you have written to all the byte lanes assert this to commit the word (you can use it at the same time as the byte enables)
output wire [DATA_WIDTH-1:0] read_data;
input pop; // use this to read a word out of the FIFO
output wire [FIFO_DEPTH_LOG2:0] used;
output wire full;
output wire empty;
reg [FIFO_DEPTH_LOG2-1:0] write_address;
reg [FIFO_DEPTH_LOG2-1:0] read_address;
reg [FIFO_DEPTH_LOG2:0] internal_used;
wire internal_full;
wire internal_empty;
always @ (posedge clk or posedge areset)
begin
if (areset)
begin
write_address <= 0;
end
else
begin
if (sreset)
begin
write_address <= 0;
end
else if (push == 1)
begin
write_address <= write_address + 1'b1;
end
end
end
always @ (posedge clk or posedge areset)
begin
if (areset)
begin
read_address <= 0;
end
else
begin
if (sreset)
begin
read_address <= 0;
end
else if (pop == 1)
begin
read_address <= read_address + 1'b1;
end
end
end
// TODO: Change this to an inferrered RAM when Quartus II supports byte enables for inferred RAM
altsyncram the_dp_ram (
.clock0 (clk),
.wren_a (write),
.byteena_a (write_byteenables),
.data_a (write_data),
.address_a (write_address),
.q_b (read_data),
.address_b (read_address)
);
defparam the_dp_ram.operation_mode = "DUAL_PORT"; // simple dual port (one read, one write port)
defparam the_dp_ram.lpm_type = "altsyncram";
defparam the_dp_ram.read_during_write_mode_mixed_ports = "DONT_CARE";
defparam the_dp_ram.power_up_uninitialized = "TRUE";
defparam the_dp_ram.byte_size = 8;
defparam the_dp_ram.width_a = DATA_WIDTH;
defparam the_dp_ram.width_b = DATA_WIDTH;
defparam the_dp_ram.widthad_a = FIFO_DEPTH_LOG2;
defparam the_dp_ram.widthad_b = FIFO_DEPTH_LOG2;
defparam the_dp_ram.width_byteena_a = (DATA_WIDTH/8);
defparam the_dp_ram.numwords_a = FIFO_DEPTH;
defparam the_dp_ram.numwords_b = FIFO_DEPTH;
defparam the_dp_ram.address_reg_b = "CLOCK0";
defparam the_dp_ram.outdata_reg_b = (LATENCY == 2)? "CLOCK0" : "UNREGISTERED";
always @ (posedge clk or posedge areset)
begin
if (areset)
begin
internal_used <= 0;
end
else
begin
if (sreset)
begin
internal_used <= 0;
end
else
begin
case ({push, pop})
2'b01: internal_used <= internal_used - 1'b1;
2'b10: internal_used <= internal_used + 1'b1;
default: internal_used <= internal_used;
endcase
end
end
end
assign internal_empty = (read_address == write_address) & (internal_used == 0);
assign internal_full = (write_address == read_address) & (internal_used != 0);
assign used = internal_used; // this signal reflects the number of words in the FIFO
assign empty = internal_empty; // combinational so it'll glitch a little bit
assign full = internal_full; // dito
endmodule