From 7399deb17d31c7f5649e876825c7820dcd1628f5 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 24 May 2019 14:03:34 +0300 Subject: [PATCH] Added Avalon master templates --- .../Avalon_MM_Masters_Readme.pdf | Bin 0 -> 132740 bytes .../burst_read_master.v | 256 +++++++++++++++ .../burst_write_master.v | 305 ++++++++++++++++++ avalon_mm_master_templates/custom_master.v | 211 ++++++++++++ .../custom_masters_hw.tcl | 291 +++++++++++++++++ .../latency_aware_read_master.v | 247 ++++++++++++++ avalon_mm_master_templates/write_master.v | 191 +++++++++++ 7 files changed, 1501 insertions(+) create mode 100644 avalon_mm_master_templates/Avalon_MM_Masters_Readme.pdf create mode 100644 avalon_mm_master_templates/burst_read_master.v create mode 100644 avalon_mm_master_templates/burst_write_master.v create mode 100644 avalon_mm_master_templates/custom_master.v create mode 100644 avalon_mm_master_templates/custom_masters_hw.tcl create mode 100644 avalon_mm_master_templates/latency_aware_read_master.v create mode 100644 avalon_mm_master_templates/write_master.v diff --git a/avalon_mm_master_templates/Avalon_MM_Masters_Readme.pdf b/avalon_mm_master_templates/Avalon_MM_Masters_Readme.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2bc969ed70dc672fe43fa8cc95b5ee459a6d4562 GIT binary patch literal 132740 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 (FIFODEPTH - MAXBURSTCOUNT - 4); // make sure there are fewer reads posted than room in the FIFO + + + // tracking FIFO + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + reads_pending <= 0; + end + else + begin + if(increment_address == 1) + begin + if(master_readdatavalid == 0) + begin + reads_pending <= reads_pending + burst_count; + end + else + begin + reads_pending <= reads_pending + burst_count - 1; // a burst read was posted, but a word returned + end + end + else + begin + if(master_readdatavalid == 0) + begin + reads_pending <= reads_pending; // burst read was not posted and no read returned + end + else + begin + reads_pending <= reads_pending - 1; // burst read was not posted but a word returned + end + end + end + end + + + // read data feeding user logic + assign user_data_available = !fifo_empty; + scfifo the_master_to_user_fifo ( + .aclr (reset), + .clock (clk), + .data (master_readdata), + .empty (fifo_empty), + .q (user_buffer_data), + .rdreq (user_read_buffer), + .usedw (fifo_used), + .wrreq (master_readdatavalid) + ); + defparam the_master_to_user_fifo.lpm_width = DATAWIDTH; + defparam the_master_to_user_fifo.lpm_numwords = FIFODEPTH; + defparam the_master_to_user_fifo.lpm_showahead = "ON"; + defparam the_master_to_user_fifo.use_eab = (FIFOUSEMEMORY == 1)? "ON" : "OFF"; + defparam the_master_to_user_fifo.add_ram_output_register = "OFF"; + defparam the_master_to_user_fifo.underflow_checking = "OFF"; + defparam the_master_to_user_fifo.overflow_checking = "OFF"; + +endmodule diff --git a/avalon_mm_master_templates/burst_write_master.v b/avalon_mm_master_templates/burst_write_master.v new file mode 100644 index 0000000..90d45da --- /dev/null +++ b/avalon_mm_master_templates/burst_write_master.v @@ -0,0 +1,305 @@ +/* + Legal Notice: (C)2007 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 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. +*/ + +/* + + Author: JCJB + Date: 11/04/2007 + + This bursting write master is passed a word aligned address, length in bytes, + and a 'go' bit. The master will continue to post full length bursts until + the length register reaches a value less than a full burst. A single final + burst is then posted when enough data has been buffered and then the done bit + will be asserted. + + To use this master you must simply drive the control signals into this block, + and also write the data to the exposed write FIFO. To read from the exposed FIFO + use the 'user_write_buffer' signal to push data into the FIFO 'user_buffer_data'. + The signal 'user_buffer_full' is asserted whenever the exposed buffer is full. + You should not attempt to write data to the exposed FIFO if it is full. + +*/ + +// altera message_off 10230 + + +module burst_write_master ( + clk, + reset, + + // control inputs and outputs + control_fixed_location, + control_write_base, + control_write_length, + control_go, + control_done, + + // user logic inputs and outputs + user_write_buffer, + user_buffer_data, + user_buffer_full, + + // master inputs and outputs + master_address, + master_write, + master_byteenable, + master_writedata, + master_burstcount, + master_waitrequest +); + + + parameter DATAWIDTH = 32; + parameter MAXBURSTCOUNT = 4; + parameter BURSTCOUNTWIDTH = 3; + parameter BYTEENABLEWIDTH = 4; + parameter ADDRESSWIDTH = 32; + parameter FIFODEPTH = 32; // must be at least twice MAXBURSTCOUNT in order to be efficient + parameter FIFODEPTH_LOG2 = 5; + parameter FIFOUSEMEMORY = 1; // set to 0 to use LEs instead + + + + input clk; + input reset; + + // control inputs and outputs + input control_fixed_location; // this only makes sense to enable when MAXBURSTCOUNT = 1 + input [ADDRESSWIDTH-1:0] control_write_base; + input [ADDRESSWIDTH-1:0] control_write_length; + input control_go; + output wire control_done; + + // user logic inputs and outputs + input user_write_buffer; + input [DATAWIDTH-1:0] user_buffer_data; + output wire user_buffer_full; + + // master inputs and outputs + input master_waitrequest; + output reg [ADDRESSWIDTH-1:0] master_address; + output wire master_write; + output wire [BYTEENABLEWIDTH-1:0] master_byteenable; + output wire [DATAWIDTH-1:0] master_writedata; + output reg [BURSTCOUNTWIDTH-1:0] master_burstcount; + + // internal control signals + reg control_fixed_location_d1; + reg [ADDRESSWIDTH-1:0] length; + wire final_short_burst_enable; // when the length is less than MAXBURSTCOUNT * # of bytes per word (BYTEENABLEWIDTH) (i.e. end of the transfer) + wire final_short_burst_ready; // when there is enough data in the FIFO for the final burst + wire [BURSTCOUNTWIDTH-1:0] burst_boundary_word_address; // represents the word offset within the burst boundary + wire [BURSTCOUNTWIDTH-1:0] first_short_burst_count; + wire [BURSTCOUNTWIDTH-1:0] final_short_burst_count; + wire first_short_burst_enable; // when the transfer doesn't start on a burst boundary + wire first_short_burst_ready; // when there is enough data in the FIFO to get the master back into burst alignment + wire full_burst_ready; // when there is enough data in the FIFO for a full burst + wire increment_address; // this increments the 'address' register when write is asserted and waitrequest is de-asserted + wire burst_begin; // used to register the registers 'burst_address' and 'burst_count_d1' as well as drive the master_address and burst_count muxes + wire read_fifo; + wire [FIFODEPTH_LOG2-1:0] fifo_used; // going to combined used with the full bit + wire [BURSTCOUNTWIDTH-1:0] burst_count; // watermark of the FIFO, it has a latency of 2 cycles + reg [BURSTCOUNTWIDTH-1:0] burst_counter; + reg first_transfer; // need to keep track of the first burst so that we don't incorrectly increment the address + + + + // registering the control_fixed_location bit + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + control_fixed_location_d1 <= 0; + end + else + begin + if (control_go == 1) + begin + control_fixed_location_d1 <= control_fixed_location; + end + end + end + + + // set when control_go fires, and reset once the first burst starts + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + first_transfer <= 0; + end + else + begin + if (control_go == 1) + begin + first_transfer <= 1; + end + else if (burst_begin == 1) + begin + first_transfer <= 0; + end + end + end + + + // master address (held constant during burst) + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + master_address <= 0; + end + else + begin + if (control_go == 1) + begin + master_address <= control_write_base; + end + else if ((first_transfer == 0) & (burst_begin == 1) & (control_fixed_location_d1 == 0)) + begin + master_address <= master_address + (master_burstcount * BYTEENABLEWIDTH); // we don't want address + BYTEENABLEWIDTH for the first access + end + end + end + + + // master length logic + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + length <= 0; + end + else + begin + if (control_go == 1) + begin + length <= control_write_length; + end + else if (increment_address == 1) + begin + length <= length - BYTEENABLEWIDTH; // always performing word size accesses + end + end + end + + + + // register the master burstcount (held constant during burst) + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + master_burstcount <= 0; + end + else + begin + if (burst_begin == 1) + begin + master_burstcount <= burst_count; + end + end + end + + + + // burst counter. This is set to the burst count being posted then counts down when each word + // of data goes out. If it reaches 0 (i.e. not reloaded after 1) then the master stalls due to + // a lack of data to post a new burst. + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + burst_counter <= 0; + end + else + begin + if (control_go == 1) + begin + burst_counter <= 0; + end + else if (burst_begin == 1) + begin + burst_counter <= burst_count; + end + else if (increment_address == 1) // decrements each write, burst_counter will only hit 0 if burst begin doesn't fire on the next cycle + begin + burst_counter <= burst_counter - 1; + end + end + end + + + + + // burst boundaries are on the master "width * maximum burst count". The burst boundary word address will be used to determine how far off the boundary the transfer starts from. + assign burst_boundary_word_address = ((master_address / BYTEENABLEWIDTH) & (MAXBURSTCOUNT - 1)); + + // first short burst enable will only be active on the first transfer (if applicable). It will either post the amount of words remaining to reach the end of the burst + // boundary or post the remainder of the transfer whichever is shorter. If the transfer is very short and not aligned on a burst boundary then the same logic as the final short transfer is used + assign first_short_burst_enable = (burst_boundary_word_address != 0) & (first_transfer == 1); + assign first_short_burst_count = ((burst_boundary_word_address & 1'b1) == 1'b1)? 1 : // if the burst boundary isn't a multiple of 2 then must post a burst of 1 to get to a multiple of 2 for the next burst + (((MAXBURSTCOUNT - burst_boundary_word_address) < (length / BYTEENABLEWIDTH))? + (MAXBURSTCOUNT - burst_boundary_word_address) : final_short_burst_count); + assign first_short_burst_ready = (fifo_used > first_short_burst_count) | ((fifo_used == first_short_burst_count) & (burst_counter == 0)); + + // when there isn't enough data for a full burst at the end of the transfer a short burst is sent out instead + assign final_short_burst_enable = (length < (MAXBURSTCOUNT * BYTEENABLEWIDTH)); + assign final_short_burst_count = (length/BYTEENABLEWIDTH); + assign final_short_burst_ready = (fifo_used > final_short_burst_count) | ((fifo_used == final_short_burst_count) & (burst_counter == 0)); // this will add a one cycle stall between bursts, since fifo_used has a cycle of latency, this only affects the last burst + + // since the fifo has a latency of 1 we need to make sure we don't under flow + assign full_burst_ready = (fifo_used > MAXBURSTCOUNT) | ((fifo_used == MAXBURSTCOUNT) & (burst_counter == 0)); // when fifo used watermark equals the burst count the statemachine must stall for one cycle, this will make sure that when a burst begins there really is enough data present in the FIFO + + + assign master_byteenable = -1; // all ones, always performing word size accesses + assign control_done = (length == 0); + assign master_write = (control_done == 0) & (burst_counter != 0); // burst_counter = 0 means the transfer is done, or not enough data in the fifo for a new burst + + // fifo controls and the burst_begin responsible for timing most of the circuit, burst_begin starts the writing statemachine + assign burst_begin = (((first_short_burst_enable == 1) & (first_short_burst_ready == 1)) + | ((final_short_burst_enable == 1) & (final_short_burst_ready == 1)) + | (full_burst_ready == 1)) + & (control_done == 0) // since the FIFO can have data before the master starts we need to disable this bit from firing when length = 0 + & ((burst_counter == 0) | ((burst_counter == 1) & (master_waitrequest == 0) & (length > (MAXBURSTCOUNT * BYTEENABLEWIDTH)))); // need to make a short final burst doesn't start right after a full burst completes. + + assign burst_count = (first_short_burst_enable == 1)? first_short_burst_count : // alignment correction gets priority, if the transfer is short and unaligned this will cover both + (final_short_burst_enable == 1)? final_short_burst_count : MAXBURSTCOUNT; + + assign increment_address = (master_write == 1) & (master_waitrequest == 0); // writing is occuring without wait states + assign read_fifo = increment_address; + + + + // write data feed by user logic + scfifo the_user_to_master_fifo ( + .aclr (reset), + .usedw (fifo_used), + .clock (clk), + .data (user_buffer_data), + .almost_full (user_buffer_full), + .q (master_writedata), + .rdreq (read_fifo), + .wrreq (user_write_buffer) + ); + defparam the_user_to_master_fifo.lpm_width = DATAWIDTH; + defparam the_user_to_master_fifo.lpm_numwords = FIFODEPTH; + defparam the_user_to_master_fifo.lpm_showahead = "ON"; + defparam the_user_to_master_fifo.almost_full_value = (FIFODEPTH - 2); + defparam the_user_to_master_fifo.use_eab = (FIFOUSEMEMORY == 1)? "ON" : "OFF"; + defparam the_user_to_master_fifo.add_ram_output_register = "OFF"; // makes timing the burst begin single simplier + defparam the_user_to_master_fifo.underflow_checking = "OFF"; + defparam the_user_to_master_fifo.overflow_checking = "OFF"; + +endmodule diff --git a/avalon_mm_master_templates/custom_master.v b/avalon_mm_master_templates/custom_master.v new file mode 100644 index 0000000..e828ea9 --- /dev/null +++ b/avalon_mm_master_templates/custom_master.v @@ -0,0 +1,211 @@ +/* +This file is a simple top level that will generate one of four types of +Avalon-MM master. As a result all the ports must be declared and it will be +up to the component .tcl file to stub unused signals. +*/ + +// altera message_off 10034 + +module custom_master ( + clk, + reset, + + // control inputs and outputs + control_fixed_location, + control_read_base, + control_read_length, + control_write_base, + control_write_length, + control_go, + control_done, + control_early_done, + + // user logic inputs and outputs + user_read_buffer, + user_write_buffer, + user_buffer_input_data, + user_buffer_output_data, + user_data_available, + user_buffer_full, + + // master inputs and outputs + master_address, + master_read, + master_write, + master_byteenable, + master_readdata, + master_readdatavalid, + master_writedata, + master_burstcount, + master_waitrequest +); + + parameter MASTER_DIRECTION = 0; // 0 for read master, 1 for write master + parameter DATA_WIDTH = 32; + parameter MEMORY_BASED_FIFO = 1; // 0 for LE/ALUT FIFOs, 1 for memory FIFOs (highly recommend 1) + parameter FIFO_DEPTH = 32; + parameter FIFO_DEPTH_LOG2 = 5; + parameter ADDRESS_WIDTH = 32; + parameter BURST_CAPABLE = 0; // 1 to enable burst, 0 to disable it + parameter MAXIMUM_BURST_COUNT = 2; + parameter BURST_COUNT_WIDTH = 2; + + + input clk; + input reset; + + // control inputs and outputs + input control_fixed_location; + input [ADDRESS_WIDTH-1:0] control_read_base; // for read master + input [ADDRESS_WIDTH-1:0] control_read_length; // for read master + input [ADDRESS_WIDTH-1:0] control_write_base; // for write master + input [ADDRESS_WIDTH-1:0] control_write_length; // for write master + input control_go; + output wire control_done; + output wire control_early_done; // for read master + + // user logic inputs and outputs + input user_read_buffer; // for read master + input user_write_buffer; // for write master + input [DATA_WIDTH-1:0] user_buffer_input_data; // for write master + output wire [DATA_WIDTH-1:0] user_buffer_output_data; // for read master + output wire user_data_available; // for read master + output wire user_buffer_full; // for write master + + // master inputs and outputs + output wire [ADDRESS_WIDTH-1:0] master_address; + output wire master_read; // for read master + output wire master_write; // for write master + output wire [(DATA_WIDTH/8)-1:0] master_byteenable; + input [DATA_WIDTH-1:0] master_readdata; // for read master + input master_readdatavalid; // for read master + output wire [DATA_WIDTH-1:0] master_writedata; // for write master + output wire [BURST_COUNT_WIDTH-1:0] master_burstcount; // for bursting read and write masters + input master_waitrequest; + + +generate // big generate if statement to select the approprate master depending on the direction and burst parameters +if(MASTER_DIRECTION == 0) +begin + if(BURST_CAPABLE == 1) + begin + burst_read_master a_burst_read_master( + .clk (clk), + .reset (reset), + .control_fixed_location (control_fixed_location), + .control_read_base (control_read_base), + .control_read_length (control_read_length), + .control_go (control_go), + .control_done (control_done), + .control_early_done (control_early_done), + .user_read_buffer (user_read_buffer), + .user_buffer_data (user_buffer_output_data), + .user_data_available (user_data_available), + .master_address (master_address), + .master_read (master_read), + .master_byteenable (master_byteenable), + .master_readdata (master_readdata), + .master_readdatavalid (master_readdatavalid), + .master_burstcount (master_burstcount), + .master_waitrequest (master_waitrequest) + ); + defparam a_burst_read_master.DATAWIDTH = DATA_WIDTH; + defparam a_burst_read_master.MAXBURSTCOUNT = MAXIMUM_BURST_COUNT; + defparam a_burst_read_master.BURSTCOUNTWIDTH = BURST_COUNT_WIDTH; + defparam a_burst_read_master.BYTEENABLEWIDTH = DATA_WIDTH/8; + defparam a_burst_read_master.ADDRESSWIDTH = ADDRESS_WIDTH; + defparam a_burst_read_master.FIFODEPTH = FIFO_DEPTH; + defparam a_burst_read_master.FIFODEPTH_LOG2 = FIFO_DEPTH_LOG2; + defparam a_burst_read_master.FIFOUSEMEMORY = MEMORY_BASED_FIFO; + end + else + begin + latency_aware_read_master a_latency_aware_read_master( + .clk (clk), + .reset (reset), + .control_fixed_location (control_fixed_location), + .control_read_base (control_read_base), + .control_read_length (control_read_length), + .control_go (control_go), + .control_done (control_done), + .control_early_done (control_early_done), + .user_read_buffer (user_read_buffer), + .user_buffer_data (user_buffer_output_data), + .user_data_available (user_data_available), + .master_address (master_address), + .master_read (master_read), + .master_byteenable (master_byteenable), + .master_readdata (master_readdata), + .master_readdatavalid (master_readdatavalid), + .master_waitrequest (master_waitrequest) + ); + defparam a_latency_aware_read_master.DATAWIDTH = DATA_WIDTH; + defparam a_latency_aware_read_master.BYTEENABLEWIDTH = DATA_WIDTH/8; + defparam a_latency_aware_read_master.ADDRESSWIDTH = ADDRESS_WIDTH; + defparam a_latency_aware_read_master.FIFODEPTH = FIFO_DEPTH; + defparam a_latency_aware_read_master.FIFODEPTH_LOG2 = FIFO_DEPTH_LOG2; + defparam a_latency_aware_read_master.FIFOUSEMEMORY = MEMORY_BASED_FIFO; + end +end +else +begin + if(BURST_CAPABLE == 1) + begin + burst_write_master a_burst_write_master( + .clk (clk), + .reset (reset), + .control_fixed_location (control_fixed_location), + .control_write_base (control_write_base), + .control_write_length (control_write_length), + .control_go (control_go), + .control_done (control_done), + .user_write_buffer (user_write_buffer), + .user_buffer_data (user_buffer_input_data), + .user_buffer_full (user_buffer_full), + .master_address (master_address), + .master_write (master_write), + .master_byteenable (master_byteenable), + .master_writedata (master_writedata), + .master_burstcount (master_burstcount), + .master_waitrequest (master_waitrequest) + ); + defparam a_burst_write_master.DATAWIDTH = DATA_WIDTH; + defparam a_burst_write_master.MAXBURSTCOUNT = MAXIMUM_BURST_COUNT; + defparam a_burst_write_master.BURSTCOUNTWIDTH = BURST_COUNT_WIDTH; + defparam a_burst_write_master.BYTEENABLEWIDTH = DATA_WIDTH/8; + defparam a_burst_write_master.ADDRESSWIDTH = ADDRESS_WIDTH; + defparam a_burst_write_master.FIFODEPTH = FIFO_DEPTH; + defparam a_burst_write_master.FIFODEPTH_LOG2 = FIFO_DEPTH_LOG2; + defparam a_burst_write_master.FIFOUSEMEMORY = MEMORY_BASED_FIFO; + end + else + begin + write_master a_write_master( + .clk (clk), + .reset (reset), + .control_fixed_location (control_fixed_location), + .control_write_base (control_write_base), + .control_write_length (control_write_length), + .control_go (control_go), + .control_done (control_done), + .user_write_buffer (user_write_buffer), + .user_buffer_data (user_buffer_input_data), + .user_buffer_full (user_buffer_full), + .master_address (master_address), + .master_write (master_write), + .master_byteenable (master_byteenable), + .master_writedata (master_writedata), + .master_waitrequest (master_waitrequest) + ); + defparam a_write_master.DATAWIDTH = DATA_WIDTH; + defparam a_write_master.BYTEENABLEWIDTH = DATA_WIDTH/8; + defparam a_write_master.ADDRESSWIDTH = ADDRESS_WIDTH; + defparam a_write_master.FIFODEPTH = FIFO_DEPTH; + defparam a_write_master.FIFODEPTH_LOG2 = FIFO_DEPTH_LOG2; + defparam a_write_master.FIFOUSEMEMORY = MEMORY_BASED_FIFO; + end +end +endgenerate + + +endmodule diff --git a/avalon_mm_master_templates/custom_masters_hw.tcl b/avalon_mm_master_templates/custom_masters_hw.tcl new file mode 100644 index 0000000..d3c2cb6 --- /dev/null +++ b/avalon_mm_master_templates/custom_masters_hw.tcl @@ -0,0 +1,291 @@ +# TCL File Generated by Component Editor 8.0 +# Sat May 31 20:41:17 PDT 2008 +# DO NOT MODIFY + + + +# +----------------------------------- +# | module burst_read_master +# | +set_module_property DESCRIPTION "Custom Avalon-MM Masters" +set_module_property NAME master_template +set_module_property VERSION 1.0 +set_module_property GROUP "Templates" +set_module_property AUTHOR JCJB +set_module_property ICON_PATH ALTERA_LOGO_ANIM.gif +set_module_property DISPLAY_NAME master_template +set_module_property TOP_LEVEL_HDL_FILE custom_master.v +set_module_property TOP_LEVEL_HDL_MODULE custom_master +set_module_property INSTANTIATE_IN_SYSTEM_MODULE true +set_module_property EDITABLE false +set_module_property SIMULATION_MODEL_IN_VERILOG false +set_module_property SIMULATION_MODEL_IN_VHDL false +set_module_property SIMULATION_MODEL_HAS_TULIPS false +set_module_property SIMULATION_MODEL_IS_OBFUSCATED false +# | +# +----------------------------------- + + +set_module_property ELABORATION_CALLBACK elaborate_me +set_module_property VALIDATION_CALLBACK validate_me + + +# +----------------------------------- +# | files +# | +add_file custom_master.v {SYNTHESIS SIMULATION} +add_file burst_write_master.v {SYNTHESIS SIMULATION} +add_file burst_read_master.v {SYNTHESIS SIMULATION} +add_file write_master.v {SYNTHESIS SIMULATION} +add_file latency_aware_read_master.v {SYNTHESIS SIMULATION} +# | +# +----------------------------------- + +# +----------------------------------- +# | parameters +# | + +# Avalon Master Settings +add_parameter MASTER_DIRECTION Integer 0 "Sets the master direction between read (0) and write (1) transfers" +set_parameter_property MASTER_DIRECTION VISIBLE true +set_parameter_property MASTER_DIRECTION DISPLAY_NAME "Master Direction" +set_parameter_property MASTER_DIRECTION GROUP "Avalon-MM Master Properties" +set_parameter_property MASTER_DIRECTION AFFECTS_PORT_WIDTHS true +set_parameter_property MASTER_DIRECTION ALLOWED_RANGES {"0:Read" "1:Write"} + +add_parameter DATA_WIDTH Integer 32 "Width of the data path" +set_parameter_property DATA_WIDTH VISIBLE true +set_parameter_property DATA_WIDTH DISPLAY_NAME "Data Width" +set_parameter_property DATA_WIDTH GROUP "Avalon-MM Master Properties" +set_parameter_property DATA_WIDTH AFFECTS_PORT_WIDTHS true +set_parameter_property DATA_WIDTH ALLOWED_RANGES {8 16 32 64 128 256 512 1024} + +add_parameter ADDRESS_WIDTH Integer "32" "Address Width" +set_parameter_property ADDRESS_WIDTH VISIBLE true +set_parameter_property ADDRESS_WIDTH DISPLAY_NAME "Address Width" +set_parameter_property ADDRESS_WIDTH GROUP "Avalon-MM Master Properties" +set_parameter_property ADDRESS_WIDTH AFFECTS_PORT_WIDTHS true +set_parameter_property ADDRESS_WIDTH ALLOWED_RANGES {32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 14 13 12 11 10 9 8 7 6 5 4} + + +# Burst Settings +add_parameter BURST_CAPABLE Integer 0 "Enable bursting" +set_parameter_property BURST_CAPABLE VISIBLE true +set_parameter_property BURST_CAPABLE DISPLAY_NAME "Burst Capable" +set_parameter_property BURST_CAPABLE GROUP "Burst Properties" +set_parameter_property BURST_CAPABLE AFFECTS_PORT_WIDTHS true +set_parameter_property BURST_CAPABLE ALLOWED_RANGES {"0:Disabled" "1:Enabled"} + +add_parameter MAXIMUM_BURST_COUNT Integer "2" "Maximum Burst Count" +set_parameter_property MAXIMUM_BURST_COUNT VISIBLE true +set_parameter_property MAXIMUM_BURST_COUNT DISPLAY_NAME "Maximum Burst Count" +set_parameter_property MAXIMUM_BURST_COUNT GROUP "Burst Properties" +set_parameter_property MAXIMUM_BURST_COUNT AFFECTS_PORT_WIDTHS false +set_parameter_property MAXIMUM_BURST_COUNT ALLOWED_RANGES {1 2 4 8 16 32 64 128} + +add_parameter BURST_COUNT_WIDTH Integer "2" "Enable bursting" +set_parameter_property BURST_COUNT_WIDTH VISIBLE false +set_parameter_property BURST_COUNT_WIDTH DISPLAY_NAME "Burst Count Width" +set_parameter_property BURST_COUNT_WIDTH GROUP "Burst Properties" +set_parameter_property BURST_COUNT_WIDTH AFFECTS_PORT_WIDTHS true +set_parameter_property BURST_COUNT_WIDTH ALLOWED_RANGES {1:8} + + +# Other Settings +add_parameter FIFO_DEPTH Integer "32" "FIFO depth" +set_parameter_property FIFO_DEPTH VISIBLE true +set_parameter_property FIFO_DEPTH DISPLAY_NAME "FIFO Depth" +set_parameter_property FIFO_DEPTH GROUP "Other Properties" +set_parameter_property FIFO_DEPTH AFFECTS_PORT_WIDTHS false +set_parameter_property FIFO_DEPTH ALLOWED_RANGES {4 8 16 32 64 128 256} + +add_parameter FIFO_DEPTH_LOG2 Integer "5" "log2(FIFO Depth)" +set_parameter_property FIFO_DEPTH_LOG2 VISIBLE false +set_parameter_property FIFO_DEPTH_LOG2 DISPLAY_NAME "log2(FIFO Depth)" +set_parameter_property FIFO_DEPTH_LOG2 GROUP "Other Properties" +set_parameter_property FIFO_DEPTH_LOG2 AFFECTS_PORT_WIDTHS false +set_parameter_property FIFO_DEPTH_LOG2 ALLOWED_RANGES {2:8} + +add_parameter MEMORY_BASED_FIFO Integer 1 "Select false if you want register based (0) FIFO instead of memory (1)" +set_parameter_property MEMORY_BASED_FIFO VISIBLE true +set_parameter_property MEMORY_BASED_FIFO DISPLAY_NAME "Memory based FIFO" +set_parameter_property MEMORY_BASED_FIFO GROUP "Other Properties" +set_parameter_property MEMORY_BASED_FIFO AFFECTS_PORT_WIDTHS false +set_parameter_property MEMORY_BASED_FIFO ALLOWED_RANGES {"1:Memory" "0:Logic"} +# | +# +----------------------------------- + +# +----------------------------------- +# | connection point clock_reset +# | +add_interface clock_reset clock end +set_interface_property clock_reset ptfSchematicName "" + +add_interface_port clock_reset clk clk Input 1 +add_interface_port clock_reset reset reset Input 1 +# | +# +----------------------------------- + +# +----------------------------------- +# | connection point avalon_master +# | +add_interface avalon_master avalon start +set_interface_property avalon_master linewrapBursts false +set_interface_property avalon_master adaptsTo "" +set_interface_property avalon_master doStreamReads false +set_interface_property avalon_master doStreamWrites false +set_interface_property avalon_master burstOnBurstBoundariesOnly false + +set_interface_property avalon_master ASSOCIATED_CLOCK clock_reset + +add_interface_port avalon_master master_address address Output -1 +add_interface_port avalon_master master_read read Output 1 +add_interface_port avalon_master master_write write Output 1 +add_interface_port avalon_master master_byteenable byteenable Output -1 +add_interface_port avalon_master master_readdata readdata Input -1 +add_interface_port avalon_master master_readdatavalid readdatavalid Input 1 +add_interface_port avalon_master master_writedata writedata Output -1 +add_interface_port avalon_master master_burstcount burstcount Output -1 +add_interface_port avalon_master master_waitrequest waitrequest Input 1 +# | +# +----------------------------------- + +# +----------------------------------- +# | connection point control +# | +add_interface control conduit end + +set_interface_property control ASSOCIATED_CLOCK clock_reset + +add_interface_port control control_fixed_location export Input 1 +add_interface_port control control_read_base export Input -1 +add_interface_port control control_write_base export Input -1 +add_interface_port control control_read_length export Input -1 +add_interface_port control control_write_length export Input -1 +add_interface_port control control_go export Input 1 +add_interface_port control control_done export Output 1 +add_interface_port control control_early_done export Output 1 +# | +# +----------------------------------- + +# +----------------------------------- +# | connection point user +# | +add_interface user conduit end + +set_interface_property user ASSOCIATED_CLOCK clock_reset + +add_interface_port user user_read_buffer export Input 1 +add_interface_port user user_buffer_output_data export Output -1 +add_interface_port user user_data_available export Output 1 +add_interface_port user user_write_buffer export Input 1 +add_interface_port user user_buffer_input_data export Input -1 +add_interface_port user user_buffer_full export Output 1 +# | +# +----------------------------------- + + + + + + +proc elaborate_me {} { + + # set all the new port widths + set the_data_width [get_parameter_value DATA_WIDTH] + set the_byteenable_width [expr {$the_data_width / 8} ] + set the_address_width [get_parameter_value ADDRESS_WIDTH] + set the_burst_count_width [get_parameter_value BURST_COUNT_WIDTH] + + + set_port_property control_read_base WIDTH $the_address_width + set_port_property control_read_length WIDTH $the_address_width + set_port_property control_write_base WIDTH $the_address_width + set_port_property control_write_length WIDTH $the_address_width + set_port_property user_buffer_input_data WIDTH $the_data_width + set_port_property user_buffer_output_data WIDTH $the_data_width + set_port_property master_address WIDTH $the_address_width + set_port_property master_byteenable WIDTH $the_byteenable_width + set_port_property master_readdata WIDTH $the_data_width + set_port_property master_writedata WIDTH $the_data_width + set_port_property master_burstcount WIDTH $the_burst_count_width + + + # determine the master direction and burst capabilities + set the_master_direction [get_parameter_value MASTER_DIRECTION] + set the_burst_capable [get_parameter_value BURST_CAPABLE] + + + # switch between read and write master signals (excluding burstcount) + if { $the_master_direction == 0 } { + set_port_property control_read_base TERMINATION false + set_port_property control_read_length TERMINATION false + set_port_property control_write_base TERMINATION true + set_port_property control_write_length TERMINATION true + set_port_property control_early_done TERMINATION false + set_port_property user_read_buffer TERMINATION false + set_port_property user_write_buffer TERMINATION true + set_port_property user_buffer_input_data TERMINATION true + set_port_property user_buffer_output_data TERMINATION false + set_port_property user_data_available TERMINATION false + set_port_property user_buffer_full TERMINATION true + set_port_property master_read TERMINATION false + set_port_property master_write TERMINATION true + set_port_property master_readdata TERMINATION false + set_port_property master_readdatavalid TERMINATION false + set_port_property master_writedata TERMINATION true + } else { + set_port_property control_read_base TERMINATION true + set_port_property control_read_length TERMINATION true + set_port_property control_write_base TERMINATION false + set_port_property control_write_length TERMINATION false + set_port_property control_early_done TERMINATION true + set_port_property user_read_buffer TERMINATION true + set_port_property user_write_buffer TERMINATION false + set_port_property user_buffer_input_data TERMINATION false + set_port_property user_buffer_output_data TERMINATION true + set_port_property user_data_available TERMINATION true + set_port_property user_buffer_full TERMINATION false + set_port_property master_read TERMINATION true + set_port_property master_write TERMINATION false + set_port_property master_readdata TERMINATION true + set_port_property master_readdatavalid TERMINATION true + set_port_property master_writedata TERMINATION false + } + + # enable/disable the burstcount signal + if { $the_burst_capable == 0 } { + set_port_property master_burstcount TERMINATION true + } else { + set_port_property master_burstcount TERMINATION false + } +} + + +proc validate_me {} { + + # read in all the parameter that matter for validation + set the_burst_capable [get_parameter_value BURST_CAPABLE] + set the_maximum_burst_count [get_parameter_value MAXIMUM_BURST_COUNT] + set the_fifo_depth [get_parameter_value FIFO_DEPTH] + + # when burst is enabled check to make sure FIFO depth is at least twice as large (also enable/disable burst count) + if { $the_burst_capable == 1 } { + set_parameter_property MAXIMUM_BURST_COUNT ENABLED true + if { $the_fifo_depth < [expr {$the_maximum_burst_count * 2}] } { + send_message Error "The FIFO Depth must be at least twice as large as Maximum Burst Count." + } + } else { + set_parameter_property MAXIMUM_BURST_COUNT ENABLED false + } + + + set the_burst_count [get_parameter_value MAXIMUM_BURST_COUNT] + set the_burst_count_width [expr {(log($the_burst_count) / log(2)) + 1}] + + set the_fifo_depth [get_parameter_value FIFO_DEPTH] + set the_fifo_depth_log2 [expr {log($the_fifo_depth) / log(2)}] + + set_parameter_value BURST_COUNT_WIDTH $the_burst_count_width + set_parameter_value FIFO_DEPTH_LOG2 $the_fifo_depth_log2 +} diff --git a/avalon_mm_master_templates/latency_aware_read_master.v b/avalon_mm_master_templates/latency_aware_read_master.v new file mode 100644 index 0000000..fc019e7 --- /dev/null +++ b/avalon_mm_master_templates/latency_aware_read_master.v @@ -0,0 +1,247 @@ +/* + Legal Notice: (C)2007 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 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. +*/ + +/* + + Author: JCJB + Date: 11/04/2007 + + This latency aware read master is passed a word aligned address, length in bytes, + and a 'go' bit. The master will continue to post reads until the length register + reaches a value of zero. When all the reads return the done bit will be asserted. + + To use this master you must simply drive the control signals into this block, + and also read the data from the exposed read FIFO. To read from the exposed FIFO + use the 'user_read_buffer' signal to pop data from the FIFO 'user_buffer_data'. + The signal 'user_data_available' is asserted whenever data is available from the + exposed FIFO. + +*/ + +// altera message_off 10230 + + +module latency_aware_read_master ( + clk, + reset, + + // control inputs and outputs + control_fixed_location, + control_read_base, + control_read_length, + control_go, + control_done, + control_early_done, + + // user logic inputs and outputs + user_read_buffer, + user_buffer_data, + user_data_available, + + // master inputs and outputs + master_address, + master_read, + master_byteenable, + master_readdata, + master_readdatavalid, + master_waitrequest +); + + parameter DATAWIDTH = 32; + parameter BYTEENABLEWIDTH = 4; + parameter ADDRESSWIDTH = 32; + parameter FIFODEPTH = 32; + parameter FIFODEPTH_LOG2 = 5; + parameter FIFOUSEMEMORY = 1; // set to 0 to use LEs instead + + input clk; + input reset; + + + // control inputs and outputs + input control_fixed_location; + input [ADDRESSWIDTH-1:0] control_read_base; + input [ADDRESSWIDTH-1:0] control_read_length; + input control_go; + output wire control_done; + output wire control_early_done; // don't use this unless you know what you are doing! + + // user logic inputs and outputs + input user_read_buffer; + output wire [DATAWIDTH-1:0] user_buffer_data; + output wire user_data_available; + + // master inputs and outputs + input master_waitrequest; + input master_readdatavalid; + input [DATAWIDTH-1:0] master_readdata; + output wire [ADDRESSWIDTH-1:0] master_address; + output wire master_read; + output wire [BYTEENABLEWIDTH-1:0] master_byteenable; + + // internal control signals + reg control_fixed_location_d1; + wire fifo_empty; + reg [ADDRESSWIDTH-1:0] address; + reg [ADDRESSWIDTH-1:0] length; + reg [FIFODEPTH_LOG2-1:0] reads_pending; + wire increment_address; + wire too_many_pending_reads; + reg too_many_pending_reads_d1; + wire [FIFODEPTH_LOG2-1:0] fifo_used; + + + + + // registering the control_fixed_location bit + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + control_fixed_location_d1 <= 0; + end + else + begin + if (control_go == 1) + begin + control_fixed_location_d1 <= control_fixed_location; + end + end + end + + + + // master address logic + assign master_address = address; + assign master_byteenable = -1; // all ones, always performing word size accesses + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + address <= 0; + end + else + begin + if(control_go == 1) + begin + address <= control_read_base; + end + else if((increment_address == 1) & (control_fixed_location_d1 == 0)) + begin + address <= address + BYTEENABLEWIDTH; // always performing word size accesses + end + end + end + + + + // master length logic + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + length <= 0; + end + else + begin + if(control_go == 1) + begin + length <= control_read_length; + end + else if(increment_address == 1) + begin + length <= length - BYTEENABLEWIDTH; // always performing word size accesses + end + end + end + + + + // control logic + assign too_many_pending_reads = (fifo_used + reads_pending) >= (FIFODEPTH - 4); + assign master_read = (length != 0) & (too_many_pending_reads_d1 == 0); + assign increment_address = (length != 0) & (too_many_pending_reads_d1 == 0) & (master_waitrequest == 0); + assign control_done = (reads_pending == 0) & (length == 0); // master done posting reads and all reads have returned + assign control_early_done = (length == 0); // if you need all the pending reads to return then use 'control_done' instead of this signal + + + always @ (posedge clk) + begin + if (reset == 1) + begin + too_many_pending_reads_d1 <= 0; + end + else + begin + too_many_pending_reads_d1 <= too_many_pending_reads; + end + end + + + + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + reads_pending <= 0; + end + else + begin + if(increment_address == 1) + begin + if(master_readdatavalid == 0) + begin + reads_pending <= reads_pending + 1; + end + else + begin + reads_pending <= reads_pending; // a read was posted, but another returned + end + end + else + begin + if(master_readdatavalid == 0) + begin + reads_pending <= reads_pending; // read was not posted and no read returned + end + else + begin + reads_pending <= reads_pending - 1; // read was not posted but a read returned + end + end + end + end + + + // read data feeding user logic + assign user_data_available = !fifo_empty; + scfifo the_master_to_user_fifo ( + .aclr (reset), + .clock (clk), + .data (master_readdata), + .empty (fifo_empty), + .q (user_buffer_data), + .rdreq (user_read_buffer), + .usedw (fifo_used), + .wrreq (master_readdatavalid) + ); + defparam the_master_to_user_fifo.lpm_width = DATAWIDTH; + defparam the_master_to_user_fifo.lpm_numwords = FIFODEPTH; + defparam the_master_to_user_fifo.lpm_showahead = "ON"; + defparam the_master_to_user_fifo.use_eab = (FIFOUSEMEMORY == 1)? "ON" : "OFF"; + defparam the_master_to_user_fifo.add_ram_output_register = "OFF"; + defparam the_master_to_user_fifo.underflow_checking = "OFF"; + defparam the_master_to_user_fifo.overflow_checking = "OFF"; + +endmodule diff --git a/avalon_mm_master_templates/write_master.v b/avalon_mm_master_templates/write_master.v new file mode 100644 index 0000000..dd04d0f --- /dev/null +++ b/avalon_mm_master_templates/write_master.v @@ -0,0 +1,191 @@ +/* + Legal Notice: (C)2007 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 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. +*/ + +/* + + Author: JCJB + Date: 11/04/2007 + + This simple write master is passed a word aligned address, length in bytes, + and a 'go' bit. The master will continue to post writes until the length register + reaches zero. When the length register reaches zero the 'done' bit is asserted. + + To use this master you must simply drive the control signals into this block, + and also write the data to the exposed write FIFO. To read from the exposed FIFO + use the 'user_write_buffer' signal to push data into the FIFO 'user_buffer_data'. + The signal 'user_buffer_full' is asserted whenever the exposed buffer is full. + You should not attempt to write data to the exposed FIFO if it is full. + +*/ + + +// altera message_off 10230 + +module write_master ( + clk, + reset, + + // control inputs and outputs + control_fixed_location, + control_write_base, + control_write_length, + control_go, + control_done, + + // user logic inputs and outputs + user_write_buffer, + user_buffer_data, + user_buffer_full, + + // master inputs and outputs + master_address, + master_write, + master_byteenable, + master_writedata, + master_waitrequest +); + + + parameter DATAWIDTH = 32; + parameter BYTEENABLEWIDTH = 4; + parameter ADDRESSWIDTH = 32; + parameter FIFODEPTH = 32; + parameter FIFODEPTH_LOG2 = 5; + parameter FIFOUSEMEMORY = 1; // set to 0 to use LEs instead + + + + input clk; + input reset; + + // control inputs and outputs + input control_fixed_location; // this only makes sense to enable when MAXBURSTCOUNT = 1 + input [ADDRESSWIDTH-1:0] control_write_base; + input [ADDRESSWIDTH-1:0] control_write_length; + input control_go; + output wire control_done; + + // user logic inputs and outputs + input user_write_buffer; + input [DATAWIDTH-1:0] user_buffer_data; + output wire user_buffer_full; + + // master inputs and outputs + input master_waitrequest; + output wire [ADDRESSWIDTH-1:0] master_address; + output wire master_write; + output wire [BYTEENABLEWIDTH-1:0] master_byteenable; + output wire [DATAWIDTH-1:0] master_writedata; + + + // internal control signals + reg control_fixed_location_d1; + reg [ADDRESSWIDTH-1:0] address; // this increments for each word + reg [ADDRESSWIDTH-1:0] length; + wire increment_address; // this increments the 'address' register when write is asserted and waitrequest is de-asserted + wire read_fifo; + wire user_buffer_empty; + + + + // registering the control_fixed_location bit + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + control_fixed_location_d1 <= 0; + end + else + begin + if (control_go == 1) + begin + control_fixed_location_d1 <= control_fixed_location; + end + end + end + + + + // master word increment counter + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + address <= 0; + end + else + begin + if (control_go == 1) + begin + address <= control_write_base; + end + else if ((increment_address == 1) & (control_fixed_location_d1 == 0)) + begin + address <= address + BYTEENABLEWIDTH; // always performing word size accesses + end + end + end + + + // master length logic + always @ (posedge clk or posedge reset) + begin + if (reset == 1) + begin + length <= 0; + end + else + begin + if (control_go == 1) + begin + length <= control_write_length; + end + else if (increment_address == 1) + begin + length <= length - BYTEENABLEWIDTH; // always performing word size accesses + end + end + end + + + + // controlled signals going to the master/control ports + assign master_address = address; + assign master_byteenable = -1; // all ones, always performing word size accesses + assign control_done = (length == 0); + assign master_write = (user_buffer_empty == 0) & (control_done == 0); + + assign increment_address = (user_buffer_empty == 0) & (master_waitrequest == 0) & (control_done == 0); + assign read_fifo = increment_address; + + // write data feed by user logic + scfifo the_user_to_master_fifo ( + .aclr (reset), + .clock (clk), + .data (user_buffer_data), + .full (user_buffer_full), + .empty (user_buffer_empty), + .q (master_writedata), + .rdreq (read_fifo), + .wrreq (user_write_buffer) + ); + defparam the_user_to_master_fifo.lpm_width = DATAWIDTH; + defparam the_user_to_master_fifo.lpm_numwords = FIFODEPTH; + defparam the_user_to_master_fifo.lpm_showahead = "ON"; + defparam the_user_to_master_fifo.use_eab = (FIFOUSEMEMORY == 1)? "ON" : "OFF"; + defparam the_user_to_master_fifo.add_ram_output_register = "OFF"; + defparam the_user_to_master_fifo.underflow_checking = "OFF"; + defparam the_user_to_master_fifo.overflow_checking = "OFF"; + +endmodule