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 0000000..2bc969e Binary files /dev/null and b/avalon_mm_master_templates/Avalon_MM_Masters_Readme.pdf differ diff --git a/avalon_mm_master_templates/burst_read_master.v b/avalon_mm_master_templates/burst_read_master.v new file mode 100644 index 0000000..8ed1e9e --- /dev/null +++ b/avalon_mm_master_templates/burst_read_master.v @@ -0,0 +1,256 @@ +/* + 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 read 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 and 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 burst_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_burstcount, + master_waitrequest +); + + parameter DATAWIDTH = 32; + parameter MAXBURSTCOUNT = 4; + parameter BURSTCOUNTWIDTH = 3; + 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, it's going to fire when the last read is posted, not when the last data returns! + + // 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; + output wire [BURSTCOUNTWIDTH-1:0] master_burstcount; + + // 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 [BURSTCOUNTWIDTH-1:0] burst_count; + wire [BURSTCOUNTWIDTH-1:0] first_short_burst_count; + wire first_short_burst_enable; + wire [BURSTCOUNTWIDTH-1:0] final_short_burst_count; + wire final_short_burst_enable; + wire [BURSTCOUNTWIDTH-1:0] burst_boundary_word_address; + reg burst_begin; + wire too_many_reads_pending; + 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 + 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 + (burst_count * BYTEENABLEWIDTH); // always performing word size accesses, increment by the burst count presented + 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 - (burst_count * BYTEENABLEWIDTH); // always performing word size accesses, decrement by the burst count presented + 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 master_burstcount = burst_count; + assign control_done = (length == 0) & (reads_pending == 0); // need to make sure that the reads have returned before firing the done bit + assign control_early_done = (length == 0); // advanced feature, you should use 'control_done' if you need all the reads to return first + assign master_read = (too_many_reads_pending == 0) & (length != 0); + assign burst_boundary_word_address = ((address / BYTEENABLEWIDTH) & (MAXBURSTCOUNT - 1)); + assign first_short_burst_enable = (burst_boundary_word_address != 0); + assign final_short_burst_enable = (length < (MAXBURSTCOUNT * BYTEENABLEWIDTH)); + + 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) : (length / BYTEENABLEWIDTH)); + assign final_short_burst_count = (length / BYTEENABLEWIDTH); + + assign burst_count = (first_short_burst_enable == 1)? first_short_burst_count : // this will get the transfer back on a burst boundary, + (final_short_burst_enable == 1)? final_short_burst_count : MAXBURSTCOUNT; + assign increment_address = (too_many_reads_pending == 0) & (master_waitrequest == 0) & (length != 0); + assign too_many_reads_pending = (reads_pending + fifo_used) >= (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