483 lines
16 KiB
Systemverilog
483 lines
16 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_slave_translator/altera_merlin_slave_translator.sv#1 $
|
||
|
// $Revision: #1 $
|
||
|
// $Date: 2015/08/09 $
|
||
|
// $Author: swbranch $
|
||
|
|
||
|
// -------------------------------------
|
||
|
// Merlin Slave Translator
|
||
|
//
|
||
|
// Translates Universal Avalon MM Slave
|
||
|
// to any Avalon MM Slave
|
||
|
// -------------------------------------
|
||
|
//
|
||
|
//Notable Note: 0 AV_READLATENCY is not allowed and will be converted to a 1 cycle readlatency in all cases but one
|
||
|
//If you declare a slave with fixed read timing requirements, the readlatency of such a slave will be allowed to be zero
|
||
|
//The key feature here is that no same cycle turnaround data is processed through the fabric.
|
||
|
|
||
|
//import avalon_utilities_pkg::*;
|
||
|
|
||
|
`timescale 1 ns / 1 ns
|
||
|
|
||
|
module altera_merlin_slave_translator #(
|
||
|
parameter
|
||
|
//Widths
|
||
|
AV_ADDRESS_W = 32,
|
||
|
AV_DATA_W = 32,
|
||
|
AV_BURSTCOUNT_W = 4,
|
||
|
AV_BYTEENABLE_W = 4,
|
||
|
UAV_BYTEENABLE_W = 4,
|
||
|
|
||
|
//Read Latency
|
||
|
AV_READLATENCY = 1,
|
||
|
|
||
|
//Timing
|
||
|
AV_READ_WAIT_CYCLES = 0,
|
||
|
AV_WRITE_WAIT_CYCLES = 0,
|
||
|
AV_SETUP_WAIT_CYCLES = 0,
|
||
|
AV_DATA_HOLD_CYCLES = 0,
|
||
|
|
||
|
//Optional Port Declarations
|
||
|
USE_READDATAVALID = 1,
|
||
|
USE_WAITREQUEST = 1,
|
||
|
USE_READRESPONSE = 0,
|
||
|
USE_WRITERESPONSE = 0,
|
||
|
|
||
|
//Variable Addressing
|
||
|
AV_SYMBOLS_PER_WORD = 4,
|
||
|
AV_ADDRESS_SYMBOLS = 0,
|
||
|
AV_BURSTCOUNT_SYMBOLS = 0,
|
||
|
BITS_PER_WORD = clog2_plusone(AV_SYMBOLS_PER_WORD - 1),
|
||
|
UAV_ADDRESS_W = 38,
|
||
|
UAV_BURSTCOUNT_W = 10,
|
||
|
UAV_DATA_W = 32,
|
||
|
|
||
|
AV_CONSTANT_BURST_BEHAVIOR = 0,
|
||
|
UAV_CONSTANT_BURST_BEHAVIOR = 0,
|
||
|
CHIPSELECT_THROUGH_READLATENCY = 0,
|
||
|
|
||
|
// Tightly-Coupled Options
|
||
|
USE_UAV_CLKEN = 0,
|
||
|
AV_REQUIRE_UNALIGNED_ADDRESSES = 0
|
||
|
) (
|
||
|
|
||
|
// -------------------
|
||
|
// Clock & Reset
|
||
|
// -------------------
|
||
|
input wire clk,
|
||
|
input wire reset,
|
||
|
|
||
|
// -------------------
|
||
|
// Universal Avalon Slave
|
||
|
// -------------------
|
||
|
|
||
|
input wire [UAV_ADDRESS_W - 1 : 0] uav_address,
|
||
|
input wire [UAV_DATA_W - 1 : 0] uav_writedata,
|
||
|
input wire uav_write,
|
||
|
input wire uav_read,
|
||
|
input wire [UAV_BURSTCOUNT_W - 1 : 0] uav_burstcount,
|
||
|
input wire [UAV_BYTEENABLE_W - 1 : 0] uav_byteenable,
|
||
|
input wire uav_lock,
|
||
|
input wire uav_debugaccess,
|
||
|
input wire uav_clken,
|
||
|
|
||
|
output logic uav_readdatavalid,
|
||
|
output logic uav_waitrequest,
|
||
|
output logic [UAV_DATA_W - 1 : 0] uav_readdata,
|
||
|
output logic [1:0] uav_response,
|
||
|
// input wire uav_writeresponserequest,
|
||
|
output logic uav_writeresponsevalid,
|
||
|
|
||
|
// -------------------
|
||
|
// Customizable Avalon Master
|
||
|
// -------------------
|
||
|
output logic [AV_ADDRESS_W - 1 : 0] av_address,
|
||
|
output logic [AV_DATA_W - 1 : 0] av_writedata,
|
||
|
output logic av_write,
|
||
|
output logic av_read,
|
||
|
output logic [AV_BURSTCOUNT_W - 1 : 0] av_burstcount,
|
||
|
output logic [AV_BYTEENABLE_W - 1 : 0] av_byteenable,
|
||
|
output logic [AV_BYTEENABLE_W - 1 : 0] av_writebyteenable,
|
||
|
output logic av_begintransfer,
|
||
|
output wire av_chipselect,
|
||
|
output logic av_beginbursttransfer,
|
||
|
output logic av_lock,
|
||
|
output wire av_clken,
|
||
|
output wire av_debugaccess,
|
||
|
output wire av_outputenable,
|
||
|
|
||
|
input logic [AV_DATA_W - 1 : 0] av_readdata,
|
||
|
input logic av_readdatavalid,
|
||
|
input logic av_waitrequest,
|
||
|
|
||
|
input logic [1:0] av_response,
|
||
|
// output logic av_writeresponserequest,
|
||
|
input wire av_writeresponsevalid
|
||
|
|
||
|
);
|
||
|
|
||
|
function integer clog2_plusone;
|
||
|
input [31:0] Depth;
|
||
|
integer i;
|
||
|
begin
|
||
|
i = Depth;
|
||
|
for(clog2_plusone = 0; i > 0; clog2_plusone = clog2_plusone + 1)
|
||
|
i = i >> 1;
|
||
|
end
|
||
|
endfunction
|
||
|
|
||
|
function integer max;
|
||
|
//returns the larger of two passed arguments
|
||
|
input [31:0] one;
|
||
|
input [31:0] two;
|
||
|
if(one > two)
|
||
|
max=one;
|
||
|
else
|
||
|
max=two;
|
||
|
endfunction // int
|
||
|
|
||
|
localparam AV_READ_WAIT_INDEXED = (AV_SETUP_WAIT_CYCLES + AV_READ_WAIT_CYCLES);
|
||
|
localparam AV_WRITE_WAIT_INDEXED = (AV_SETUP_WAIT_CYCLES + AV_WRITE_WAIT_CYCLES);
|
||
|
localparam AV_DATA_HOLD_INDEXED = (AV_WRITE_WAIT_INDEXED + AV_DATA_HOLD_CYCLES);
|
||
|
localparam LOG2_OF_LATENCY_SUM = max(clog2_plusone(AV_READ_WAIT_INDEXED + 1),clog2_plusone(AV_DATA_HOLD_INDEXED + 1));
|
||
|
localparam BURSTCOUNT_SHIFT_SELECTOR = AV_BURSTCOUNT_SYMBOLS ? 0 : BITS_PER_WORD;
|
||
|
localparam ADDRESS_SHIFT_SELECTOR = AV_ADDRESS_SYMBOLS ? 0 : BITS_PER_WORD;
|
||
|
localparam ADDRESS_HIGH = ( UAV_ADDRESS_W > AV_ADDRESS_W + ADDRESS_SHIFT_SELECTOR ) ?
|
||
|
AV_ADDRESS_W :
|
||
|
UAV_ADDRESS_W - ADDRESS_SHIFT_SELECTOR;
|
||
|
localparam BURSTCOUNT_HIGH = ( UAV_BURSTCOUNT_W > AV_BURSTCOUNT_W + BURSTCOUNT_SHIFT_SELECTOR ) ?
|
||
|
AV_BURSTCOUNT_W :
|
||
|
UAV_BURSTCOUNT_W - BURSTCOUNT_SHIFT_SELECTOR;
|
||
|
localparam BYTEENABLE_ADDRESS_BITS = ( clog2_plusone(UAV_BYTEENABLE_W) - 1 ) >= 1 ? clog2_plusone(UAV_BYTEENABLE_W) - 1 : 1;
|
||
|
|
||
|
|
||
|
// Calculate the symbols per word as the power of 2 extended symbols per word
|
||
|
wire [31 : 0] symbols_per_word_int = 2**(clog2_plusone(AV_SYMBOLS_PER_WORD[UAV_BURSTCOUNT_W : 0] - 1));
|
||
|
wire [UAV_BURSTCOUNT_W-1 : 0] symbols_per_word = symbols_per_word_int[UAV_BURSTCOUNT_W-1 : 0];
|
||
|
|
||
|
// +--------------------------------
|
||
|
// |Backwards Compatibility Signals
|
||
|
// +--------------------------------
|
||
|
assign av_clken = (USE_UAV_CLKEN) ? uav_clken : 1'b1;
|
||
|
assign av_debugaccess = uav_debugaccess;
|
||
|
|
||
|
// +-------------------
|
||
|
// |Passthru Signals
|
||
|
// +-------------------
|
||
|
|
||
|
reg [1 : 0] av_response_delayed;
|
||
|
|
||
|
always @(posedge clk, posedge reset) begin
|
||
|
if (reset) begin
|
||
|
av_response_delayed <= 2'b0;
|
||
|
end else begin
|
||
|
av_response_delayed <= av_response;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always_comb
|
||
|
begin
|
||
|
if (!USE_READRESPONSE && !USE_WRITERESPONSE) begin
|
||
|
uav_response = '0;
|
||
|
end else begin
|
||
|
if (AV_READLATENCY != 0 || USE_READDATAVALID) begin
|
||
|
uav_response = av_response;
|
||
|
end else begin
|
||
|
uav_response = av_response_delayed;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
// assign av_writeresponserequest = uav_writeresponserequest;
|
||
|
assign uav_writeresponsevalid = av_writeresponsevalid;
|
||
|
|
||
|
//-------------------------
|
||
|
//Writedata and Byteenable
|
||
|
//-------------------------
|
||
|
|
||
|
always@* begin
|
||
|
av_byteenable = '0;
|
||
|
av_byteenable = uav_byteenable[AV_BYTEENABLE_W - 1 : 0];
|
||
|
end
|
||
|
|
||
|
always@* begin
|
||
|
av_writedata = '0;
|
||
|
av_writedata = uav_writedata[AV_DATA_W - 1 : 0];
|
||
|
end
|
||
|
|
||
|
// +-------------------
|
||
|
// |Calculated Signals
|
||
|
// +-------------------
|
||
|
|
||
|
logic [UAV_ADDRESS_W - 1 : 0 ] real_uav_address;
|
||
|
|
||
|
function [BYTEENABLE_ADDRESS_BITS - 1 : 0 ] decode_byteenable;
|
||
|
input [UAV_BYTEENABLE_W - 1 : 0 ] byteenable;
|
||
|
|
||
|
for(int i = 0 ; i < UAV_BYTEENABLE_W; i++ ) begin
|
||
|
if(byteenable[i] == 1) begin
|
||
|
return i;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return '0;
|
||
|
|
||
|
endfunction
|
||
|
|
||
|
reg [AV_BURSTCOUNT_W - 1 : 0] burstcount_reg;
|
||
|
reg [AV_ADDRESS_W - 1 : 0] address_reg;
|
||
|
always@(posedge clk, posedge reset) begin
|
||
|
if(reset) begin
|
||
|
burstcount_reg <= '0;
|
||
|
address_reg <= '0;
|
||
|
end else begin
|
||
|
burstcount_reg <= burstcount_reg;
|
||
|
address_reg <= address_reg;
|
||
|
if(av_beginbursttransfer) begin
|
||
|
burstcount_reg <= uav_burstcount [ BURSTCOUNT_HIGH - 1 + BURSTCOUNT_SHIFT_SELECTOR : BURSTCOUNT_SHIFT_SELECTOR ];
|
||
|
address_reg <= real_uav_address [ ADDRESS_HIGH - 1 + ADDRESS_SHIFT_SELECTOR : ADDRESS_SHIFT_SELECTOR ];
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
logic [BYTEENABLE_ADDRESS_BITS-1:0] temp_wire;
|
||
|
|
||
|
always@* begin
|
||
|
if( AV_REQUIRE_UNALIGNED_ADDRESSES == 1) begin
|
||
|
temp_wire = decode_byteenable(uav_byteenable);
|
||
|
real_uav_address = { uav_address[UAV_ADDRESS_W - 1 : BYTEENABLE_ADDRESS_BITS ], temp_wire[BYTEENABLE_ADDRESS_BITS - 1 : 0 ] };
|
||
|
end else begin
|
||
|
real_uav_address = uav_address;
|
||
|
end
|
||
|
|
||
|
av_address = real_uav_address[ADDRESS_HIGH - 1 + ADDRESS_SHIFT_SELECTOR : ADDRESS_SHIFT_SELECTOR ];
|
||
|
if( AV_CONSTANT_BURST_BEHAVIOR && !UAV_CONSTANT_BURST_BEHAVIOR && ~av_beginbursttransfer )
|
||
|
av_address = address_reg;
|
||
|
end
|
||
|
|
||
|
always@* begin
|
||
|
av_burstcount=uav_burstcount[BURSTCOUNT_HIGH - 1 + BURSTCOUNT_SHIFT_SELECTOR : BURSTCOUNT_SHIFT_SELECTOR ];
|
||
|
if( AV_CONSTANT_BURST_BEHAVIOR && !UAV_CONSTANT_BURST_BEHAVIOR && ~av_beginbursttransfer )
|
||
|
av_burstcount = burstcount_reg;
|
||
|
end
|
||
|
|
||
|
always@* begin
|
||
|
av_lock = uav_lock;
|
||
|
end
|
||
|
|
||
|
// -------------------
|
||
|
// Writebyteenable Assignment
|
||
|
// -------------------
|
||
|
always@* begin
|
||
|
av_writebyteenable = { (AV_BYTEENABLE_W){uav_write} } & uav_byteenable[AV_BYTEENABLE_W - 1 : 0];
|
||
|
end
|
||
|
|
||
|
// -------------------
|
||
|
// Waitrequest Assignment
|
||
|
// -------------------
|
||
|
|
||
|
reg av_waitrequest_generated;
|
||
|
reg av_waitrequest_generated_read;
|
||
|
reg av_waitrequest_generated_write;
|
||
|
reg waitrequest_reset_override;
|
||
|
reg [ ( LOG2_OF_LATENCY_SUM ? LOG2_OF_LATENCY_SUM - 1 : 0 ) : 0 ] wait_latency_counter;
|
||
|
|
||
|
always@(posedge reset, posedge clk) begin
|
||
|
if(reset) begin
|
||
|
wait_latency_counter <= '0;
|
||
|
waitrequest_reset_override <= 1'h1;
|
||
|
end else begin
|
||
|
waitrequest_reset_override <= 1'h0;
|
||
|
wait_latency_counter <= '0;
|
||
|
if( ~uav_waitrequest | waitrequest_reset_override )
|
||
|
wait_latency_counter <= '0;
|
||
|
else if( uav_read | uav_write )
|
||
|
wait_latency_counter <= wait_latency_counter + 1'h1;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
always @* begin
|
||
|
|
||
|
av_read = uav_read;
|
||
|
av_write = uav_write;
|
||
|
av_waitrequest_generated = 1'h1;
|
||
|
av_waitrequest_generated_read = 1'h1;
|
||
|
av_waitrequest_generated_write = 1'h1;
|
||
|
|
||
|
if(LOG2_OF_LATENCY_SUM == 1)
|
||
|
av_waitrequest_generated = 0;
|
||
|
|
||
|
if(LOG2_OF_LATENCY_SUM > 1 && !USE_WAITREQUEST) begin
|
||
|
av_read = wait_latency_counter >= AV_SETUP_WAIT_CYCLES && uav_read;
|
||
|
av_write = wait_latency_counter >= AV_SETUP_WAIT_CYCLES && uav_write && wait_latency_counter <= AV_WRITE_WAIT_INDEXED;
|
||
|
av_waitrequest_generated_read = wait_latency_counter != AV_READ_WAIT_INDEXED;
|
||
|
av_waitrequest_generated_write = wait_latency_counter != AV_DATA_HOLD_INDEXED;
|
||
|
|
||
|
if(uav_write)
|
||
|
av_waitrequest_generated = av_waitrequest_generated_write;
|
||
|
else
|
||
|
av_waitrequest_generated = av_waitrequest_generated_read;
|
||
|
|
||
|
end
|
||
|
|
||
|
if(USE_WAITREQUEST) begin
|
||
|
uav_waitrequest = av_waitrequest;
|
||
|
end else begin
|
||
|
uav_waitrequest = av_waitrequest_generated | waitrequest_reset_override;
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
// --------------
|
||
|
// Readdata Assignment
|
||
|
// --------------
|
||
|
|
||
|
reg[(AV_DATA_W ? AV_DATA_W -1 : 0 ): 0] av_readdata_pre;
|
||
|
|
||
|
always@(posedge clk, posedge reset) begin
|
||
|
if(reset)
|
||
|
av_readdata_pre <= 'b0;
|
||
|
else
|
||
|
av_readdata_pre <= av_readdata;
|
||
|
end
|
||
|
|
||
|
always@* begin
|
||
|
uav_readdata = {UAV_DATA_W{1'b0}};
|
||
|
if( AV_READLATENCY != 0 || USE_READDATAVALID ) begin
|
||
|
uav_readdata[AV_DATA_W-1:0] = av_readdata;
|
||
|
end else begin
|
||
|
uav_readdata[AV_DATA_W-1:0] = av_readdata_pre;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// -------------------
|
||
|
// Readdatavalid Assigment
|
||
|
// -------------------
|
||
|
reg[(AV_READLATENCY>0 ? AV_READLATENCY-1:0) :0] read_latency_shift_reg;
|
||
|
reg top_read_latency_shift_reg;
|
||
|
|
||
|
always@* begin
|
||
|
uav_readdatavalid=top_read_latency_shift_reg;
|
||
|
if(USE_READDATAVALID) begin
|
||
|
uav_readdatavalid = av_readdatavalid;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always@* begin
|
||
|
top_read_latency_shift_reg = uav_read & ~uav_waitrequest & ~waitrequest_reset_override;
|
||
|
if(AV_READLATENCY == 1 || AV_READLATENCY == 0 ) begin
|
||
|
top_read_latency_shift_reg=read_latency_shift_reg;
|
||
|
end
|
||
|
if (AV_READLATENCY > 1) begin
|
||
|
top_read_latency_shift_reg = read_latency_shift_reg[(AV_READLATENCY ? AV_READLATENCY-1 : 0)];
|
||
|
end
|
||
|
end
|
||
|
|
||
|
always@(posedge reset, posedge clk) begin
|
||
|
if (reset) begin
|
||
|
read_latency_shift_reg <= '0;
|
||
|
end else if (av_clken) begin
|
||
|
read_latency_shift_reg[0] <= uav_read && ~uav_waitrequest & ~waitrequest_reset_override;
|
||
|
for (int i=0; i+1 < AV_READLATENCY ; i+=1 ) begin
|
||
|
read_latency_shift_reg[i+1] <= read_latency_shift_reg[i];
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// ------------
|
||
|
// Chipselect and OutputEnable
|
||
|
// ------------
|
||
|
reg av_chipselect_pre;
|
||
|
wire cs_extension;
|
||
|
reg av_outputenable_pre;
|
||
|
|
||
|
assign av_chipselect = (uav_read | uav_write) ? 1'b1 : av_chipselect_pre;
|
||
|
assign cs_extension = ( (^ read_latency_shift_reg) & ~top_read_latency_shift_reg ) | ((| read_latency_shift_reg) & ~(^ read_latency_shift_reg));
|
||
|
assign av_outputenable = uav_read ? 1'b1 : av_outputenable_pre;
|
||
|
|
||
|
always@(posedge reset, posedge clk) begin
|
||
|
if(reset)
|
||
|
av_outputenable_pre <= 1'b0;
|
||
|
else if( AV_READLATENCY == 0 && AV_READ_WAIT_INDEXED != 0 )
|
||
|
av_outputenable_pre <= 0;
|
||
|
else
|
||
|
av_outputenable_pre <= cs_extension | uav_read;
|
||
|
end
|
||
|
|
||
|
always@(posedge reset, posedge clk) begin
|
||
|
if(reset) begin
|
||
|
av_chipselect_pre <= 1'b0;
|
||
|
end else begin
|
||
|
av_chipselect_pre <= 1'b0;
|
||
|
if(AV_READLATENCY != 0 && CHIPSELECT_THROUGH_READLATENCY == 1) begin
|
||
|
//The AV_READLATENCY term is only here to prevent chipselect from remaining asserted while read and write fall.
|
||
|
//There is no functional impact as 0 cycle transactions are treated as 1 cycle on the other side of the translator.
|
||
|
if(uav_read) begin
|
||
|
av_chipselect_pre <= 1'b1;
|
||
|
end else if(cs_extension == 1) begin
|
||
|
av_chipselect_pre <= 1'b1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// -------------------
|
||
|
// Begintransfer Assigment
|
||
|
// -------------------
|
||
|
reg end_begintransfer;
|
||
|
|
||
|
always@* begin
|
||
|
av_begintransfer = ( uav_write | uav_read ) & ~end_begintransfer;
|
||
|
end
|
||
|
|
||
|
always@ ( posedge clk or posedge reset ) begin
|
||
|
if(reset) begin
|
||
|
end_begintransfer <= 1'b0;
|
||
|
end else begin
|
||
|
if(av_begintransfer == 1 && uav_waitrequest && ~waitrequest_reset_override)
|
||
|
end_begintransfer <= 1'b1;
|
||
|
else if(uav_waitrequest)
|
||
|
end_begintransfer <= end_begintransfer;
|
||
|
else
|
||
|
end_begintransfer <= 1'b0;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
// -------------------
|
||
|
// Beginbursttransfer Assigment
|
||
|
// -------------------
|
||
|
reg end_beginbursttransfer;
|
||
|
reg in_transfer;
|
||
|
|
||
|
always@* begin
|
||
|
av_beginbursttransfer = uav_read ? av_begintransfer : (av_begintransfer && ~end_beginbursttransfer && ~in_transfer);
|
||
|
end
|
||
|
|
||
|
always@ ( posedge clk or posedge reset ) begin
|
||
|
if(reset) begin
|
||
|
end_beginbursttransfer <= 1'b0;
|
||
|
in_transfer <= 1'b0;
|
||
|
end else begin
|
||
|
end_beginbursttransfer <= uav_write & ( uav_burstcount != symbols_per_word );
|
||
|
if(uav_write && uav_burstcount == symbols_per_word)
|
||
|
in_transfer <=1'b0;
|
||
|
else if(uav_write)
|
||
|
in_transfer <=1'b1;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
endmodule
|