mor1kx-bemicrocv/ip/altera/ddr3/altera_default_burst_conver...

190 lines
6.8 KiB
Systemverilog

// (C) 2001-2015 Altera Corporation. All rights reserved.
// Your use of Altera Corporation's design tools, logic functions and other
// software and tools, and its AMPP partner logic functions, and any output
// files 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 Altera Program License Subscription
// Agreement, Altera MegaCore Function License Agreement, or other applicable
// license agreement, including, without limitation, that your use is for the
// sole purpose of programming logic devices manufactured by Altera and sold by
// Altera or its authorized distributors. Please refer to the applicable
// agreement for further details.
// $Id: //acds/rel/15.1/ip/merlin/altera_merlin_burst_adapter/new_source/altera_default_burst_converter.sv#1 $
// $Revision: #1 $
// $Date: 2015/08/09 $
// $Author: swbranch $
// --------------------------------------------
// Default Burst Converter
// Notes:
// 1) If burst type FIXED and slave is AXI,
// passthrough the transaction.
// 2) Else, converts burst into non-bursting
// transactions (length of 1).
// --------------------------------------------
`timescale 1 ns / 1 ns
module altera_default_burst_converter
#(
parameter PKT_BURST_TYPE_W = 2,
parameter PKT_BURSTWRAP_W = 5,
parameter PKT_ADDR_W = 12,
parameter PKT_BURST_SIZE_W = 3,
parameter IS_AXI_SLAVE = 0,
parameter LEN_W = 2
)
(
input clk,
input reset,
input enable,
input [PKT_BURST_TYPE_W - 1 : 0] in_bursttype,
input [PKT_BURSTWRAP_W - 1 : 0] in_burstwrap_reg,
input [PKT_BURSTWRAP_W - 1 : 0] in_burstwrap_value,
input [PKT_ADDR_W - 1 : 0] in_addr,
input [PKT_ADDR_W - 1 : 0] in_addr_reg,
input [LEN_W - 1 : 0] in_len,
input [PKT_BURST_SIZE_W - 1 : 0] in_size_value,
input in_is_write,
output reg [PKT_ADDR_W - 1 : 0] out_addr,
output reg [LEN_W - 1 : 0] out_len,
output reg new_burst
);
// ---------------------------------------------------
// AXI Burst Type Encoding
// ---------------------------------------------------
typedef enum bit [1:0]
{
FIXED = 2'b00,
INCR = 2'b01,
WRAP = 2'b10,
RESERVED = 2'b11
} AxiBurstType;
// -------------------------------------------
// Internal Signals
// -------------------------------------------
wire [LEN_W - 1 : 0] unit_len = {{LEN_W - 1 {1'b0}}, 1'b1};
reg [LEN_W - 1 : 0] next_len;
reg [LEN_W - 1 : 0] remaining_len;
reg [PKT_ADDR_W - 1 : 0] next_incr_addr;
reg [PKT_ADDR_W - 1 : 0] incr_wrapped_addr;
reg [PKT_ADDR_W - 1 : 0] extended_burstwrap_value;
reg [PKT_ADDR_W - 1 : 0] addr_incr_variable_size_value;
// -------------------------------------------
// Byte Count Converter
// -------------------------------------------
// Avalon Slave: Read/Write, the out_len is always 1 (unit_len).
// AXI Slave: Read/Write, the out_len is always the in_len (pass through) of a given cycle.
// If bursttype RESERVED, out_len is always 1 (unit_len).
generate if (IS_AXI_SLAVE == 1)
begin : axi_slave_out_len
always_ff @(posedge clk, posedge reset) begin
if (reset) begin
out_len <= {LEN_W{1'b0}};
end
else if (enable) begin
out_len <= (in_bursttype == FIXED) ? in_len : unit_len;
end
end
end
else // IS_AXI_SLAVE == 0
begin : non_axi_slave_out_len
always_comb begin
out_len = unit_len;
end
end
endgenerate
always_comb begin : proc_extend_burstwrap
extended_burstwrap_value = {{(PKT_ADDR_W - PKT_BURSTWRAP_W){in_burstwrap_reg[PKT_BURSTWRAP_W - 1]}}, in_burstwrap_value};
addr_incr_variable_size_value = {{(PKT_ADDR_W - 1){1'b0}}, 1'b1} << in_size_value;
end
// -------------------------------------------
// Address Converter
// -------------------------------------------
// Write: out_addr = in_addr at every cycle (pass through).
// Read: out_addr = in_addr at every new_burst. Subsequent addresses calculated by converter.
always_ff @(posedge clk, posedge reset) begin
if (reset) begin
next_incr_addr <= {PKT_ADDR_W{1'b0}};
out_addr <= {PKT_ADDR_W{1'b0}};
end
else if (enable) begin
next_incr_addr <= next_incr_addr + addr_incr_variable_size_value;
if (new_burst) begin
next_incr_addr <= in_addr + addr_incr_variable_size_value;
end
out_addr <= incr_wrapped_addr;
end
end
always_comb begin
incr_wrapped_addr = in_addr;
if (!new_burst) begin
// This formula calculates addresses of WRAP bursts and works perfectly fine for other burst types too.
incr_wrapped_addr = (in_addr_reg & ~extended_burstwrap_value) | (next_incr_addr & extended_burstwrap_value);
end
end
// -------------------------------------------
// Control Signals
// -------------------------------------------
// Determine the min_len.
// 1) FIXED read to AXI slave: One-time passthrough, therefore the min_len == in_len.
// 2) FIXED write to AXI slave: min_len == 1.
// 3) FIXED read/write to Avalon slave: min_len == 1.
// 4) RESERVED read/write to AXI/Avalon slave: min_len == 1.
wire [LEN_W - 1 : 0] min_len;
generate if (IS_AXI_SLAVE == 1)
begin : axi_slave_min_len
assign min_len = (!in_is_write && (in_bursttype == FIXED)) ? in_len : unit_len;
end
else // IS_AXI_SLAVE == 0
begin : non_axi_slave_min_len
assign min_len = unit_len;
end
endgenerate
// last_beat calculation.
wire last_beat = (remaining_len == min_len);
// next_len calculation.
always_comb begin
remaining_len = in_len;
if (!new_burst) remaining_len = next_len;
end
always_ff @(posedge clk, posedge reset) begin
if (reset) begin
next_len <= 1'b0;
end
else if (enable) begin
next_len <= remaining_len - unit_len;
end
end
// new_burst calculation.
always_ff @(posedge clk, posedge reset) begin
if (reset) begin
new_burst <= 1'b1;
end
else if (enable) begin
new_burst <= last_beat;
end
end
endmodule