diff --git a/Makefile b/Makefile index eb6ec03..c0027f5 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,7 @@ cores: make -C $(LIB_HW_DIR)/contrib/nf_endianess_manager_v1_0_0/ make -C $(LIB_HW_DIR)/std/axis_fifo_v1_0_0/ make -C $(LIB_HW_DIR)/std/nf_axis_converter_v1_0_0/ + make -C $(LIB_HW_DIR)/std/nf_data_sink_v1_0_0/ make -C $(LIB_HW_DIR)/std/nf_mac_attachment_v1_0_0/ make -C $(LIB_HW_DIR)/std/input_arbiter_v1_0_0/ make -C $(LIB_HW_DIR)/std/output_queues_v1_0_0/ diff --git a/hw/lib/common/hdl/top.v b/hw/lib/common/hdl/top.v index db27bc5..45c7e38 100644 --- a/hw/lib/common/hdl/top.v +++ b/hw/lib/common/hdl/top.v @@ -28,7 +28,7 @@ module top #( parameter SIMULATIOM = "FALSE", - parameter BOARD = "AU280", + parameter BOARD = "AU250", // Greg: was "AU280" parameter C_NF_DATA_WIDTH = 512 , parameter C_NF_TUSER_WIDTH = 128, parameter C_IF_DATA_WIDTH = 512, @@ -183,6 +183,10 @@ module top #( end end + // Moved instantiation here to remove synth warning + wire core_clk; + wire locked; + reg [9:0] core_rst_cnt = 10'd0; reg core_rst_reg; always @ (posedge core_clk) begin @@ -199,9 +203,6 @@ module top #( wire axis_aclk, axil_aclk_250m; wire axis_rst, axil_rst_250m; - wire core_clk; - wire locked; - clk_wiz_1 u_clk_wiz_1 ( .clk_out1(core_clk), .reset (axis_rst), diff --git a/hw/lib/std/axi_sim_transactor_v1_0_0/hdl/axi_sim_transactor.vhd b/hw/lib/std/axi_sim_transactor_v1_0_0/hdl/axi_sim_transactor.vhd index 1c46c8f..48a121e 100755 --- a/hw/lib/std/axi_sim_transactor_v1_0_0/hdl/axi_sim_transactor.vhd +++ b/hw/lib/std/axi_sim_transactor_v1_0_0/hdl/axi_sim_transactor.vhd @@ -56,11 +56,11 @@ use xil_defaultlib.axis_sim_pkg.all; entity axi_sim_transactor is generic ( STIM_FILE : string := "../../reg_stim.axi"; - EXPECT_FILE : string := "../../reg_expect.axi"; + EXPECT_FILE : string := "../../reg_expect.axi"; LOG_FILE : string := "../../reg_stim.log" ); port ( - axi_aclk : in std_logic; + axi_aclk : in std_logic; axi_resetn : in std_logic; -- AXI Lite interface -- @@ -87,9 +87,9 @@ entity axi_sim_transactor is M_AXI_RVALID : in std_logic; M_AXI_RREADY : out std_logic; - activity_trans_sim : out std_logic; - activity_trans_log : out std_logic; - barrier_req_trans : out std_logic; + activity_trans_sim : out std_logic; + activity_trans_log : out std_logic; + barrier_req_trans : out std_logic; barrier_proceed : in std_logic ); end; @@ -162,7 +162,7 @@ begin end loop; end procedure; - ----------------------------------------------------------------------- + ----------------------------------------------------------------------- variable l: line; variable i: integer; variable c: character; @@ -180,7 +180,7 @@ begin wait_cycle; end loop; - activity_trans_sim <= '0'; + activity_trans_sim <= '0'; barrier_req_trans <= '0'; -- begin reading stimuli @@ -190,40 +190,40 @@ begin lookahead_char( l, c, ok ); next when not ok; - if c = 'B' then - read_char( l, c ); - parse_int( l, i ); - quiescent; - wait for ( i * 1 ns); - wait_cycle; - write(l, integer'image(now / 1 ns) & string'(" ns.") & string'(" Info: barrier request transactor")); - writeline( output, l ); - wait for (1 ns); - barrier_req_trans <= '1'; - while (barrier_proceed = '0') loop - wait until (barrier_proceed = '1'); - end loop; - wait for (1 ns); - barrier_req_trans <= '0'; - wait until (barrier_proceed = '0'); - write(l, integer'image(now / 1 ns) & string'(" ns.") & string'("Info: barrier complete transactor")); - writeline( output, l ); - - elsif c = 'N' then - read_char( l, c ); - parse_int( l, v ); - quiescent; - wait for ( v * 1 ns); - wait_cycle; - - elsif c = 'S' then -- wait for relative time (ns) - read_char( l, c ); -- discard operator - parse_int( l, i ); - quiescent; - wait for ( i * 1 ns); - wait_cycle; - - -- operator @(N): wait until absolute time N ns + if c = 'B' then + read_char( l, c ); + parse_int( l, i ); + quiescent; + wait for ( i * 1 ns); + wait_cycle; + write(l, integer'image(now / 1 ns) & string'(" ns.") & string'(" Info: barrier request transactor")); + writeline( output, l ); + wait for (1 ns); + barrier_req_trans <= '1'; + while (barrier_proceed = '0') loop + wait until (barrier_proceed = '1'); + end loop; + wait for (1 ns); + barrier_req_trans <= '0'; + wait until (barrier_proceed = '0'); + write(l, integer'image(now / 1 ns) & string'(" ns.") & string'("Info: barrier complete transactor")); + writeline( output, l ); + + elsif c = 'N' then + read_char( l, c ); + parse_int( l, v ); + quiescent; + wait for ( v * 1 ns); + wait_cycle; + + elsif c = 'S' then -- wait for relative time (ns) + read_char( l, c ); -- discard operator + parse_int( l, i ); + quiescent; + wait for ( i * 1 ns); + wait_cycle; + + -- operator @(N): wait for time N ns elsif c = '@' then -- wait until absolute time (ns) read_char( l, c ); -- discard operator parse_int( l, i ); @@ -231,87 +231,89 @@ begin wait for ( i * 1 ns); wait_cycle; - elsif c = 'R' then - read_char( l, c ); - parse_int( l, i ); - report "Time is " & integer'image(now / 1 ns) & string'(" ns."); - write(l, string'("Read Register!")); - writeline( output, l ); - quiescent; - wait for ( i * 1 ns); - wait_cycle; - - elsif c = 'W' then + elsif c = 'R' then + read_char( l, c ); + parse_int( l, i ); + report "Time is " & integer'image(now / 1 ns) & string'(" ns."); + write(l, string'("Read Register!")); + writeline( output, l ); + quiescent; + wait for ( i * 1 ns); + wait_cycle; + + elsif c = 'W' then read_char( l, c ); parse_int( l, i ); - report "Time is " & integer'image(now / 1 ns) & string'(" ns."); - write(l, string'("Write Register!")); - writeline( output, l ); + report "Time is " & integer'image(now / 1 ns) & string'(" ns."); + write(l, string'("Write Register!")); + writeline( output, l ); quiescent; wait for ( i * 1 ns); wait_cycle; - elsif c = 'D' then + elsif c = 'D' then read_char( l, c ); parse_int( l, i ); - report "Time is " & integer'image(now / 1 ns) & string'(" ns."); - write(l, string'("Info: delaying ") & integer'image(i) & string'(" ns")); - writeline( output, l ); - quiescent; + report "Time is " & integer'image(now / 1 ns) & string'(" ns."); + write(l, string'("Info: delaying ") & integer'image(i) & string'(" ns")); + writeline( output, l ); + quiescent; wait for ( i * 1 ns); wait_cycle; - + else - activity_trans_sim <= '1'; - -- parse out each component of the stimulus - parse_slv( l, w_req_addr, dontcare ); - w_pending := sl( not dontcare ); - w_req_valid <= w_pending; - read_char( l, c ); -- discard ',' - parse_slv( l, w_req_data, dontcare ); - if w_pending = '1' then - assert not dontcare - report STIM_FILE & ": malformed write request: missing data" - severity warning; - end if; - read_char( l, c ); -- discard ',' - - parse_slv( l, w_req_strb, dontcare ); - if w_pending = '1' then - assert not dontcare - report STIM_FILE & ": malformed write request: missing byte lane strobe" - severity warning; - end if; - read_char( l, c ); -- discard ',' - parse_slv( l, r_req_addr, dontcare ); - r_pending := sl( not dontcare ); - r_req_valid <= r_pending; - wait_cycle; - -- block until accepted - while ((w_pending and not w_req_ready) or (r_pending and not r_req_ready)) = '1' loop - wait_cycle; - end loop; - w_req_valid <= '0'; - r_req_valid <= '0'; - -- wait for transactions to return, as required - read_char( l, c ); -- read terminal wait flag - if c = '.' then -- '.' == wait for result - while (w_pending or r_pending) = '1' loop - wait_cycle; - if w_rsp_valid = '1' and w_rsp_addr = w_req_addr then - w_pending := '0'; - end if; - if r_rsp_valid = '1' and r_rsp_addr = r_req_addr then - r_pending := '0'; - end if; - end loop; - elsif c = ',' then -- continue immediately - else - assert false - report STIM_FILE & ": bad input: expected terminal ',' or '.'" - severity failure; - end if; - activity_trans_sim <= '0'; + activity_trans_sim <= '1'; + -- parse out each component of the stimulus + parse_slv( l, w_req_addr, dontcare ); + w_pending := sl( not dontcare ); + w_req_valid <= w_pending; + read_char( l, c ); -- discard ',' + parse_slv( l, w_req_data, dontcare ); + if w_pending = '1' then + assert not dontcare + report STIM_FILE & ": malformed write request: missing data" + severity warning; + end if; + read_char( l, c ); -- discard ',' + + parse_slv( l, w_req_strb, dontcare ); + if w_pending = '1' then + assert not dontcare + report STIM_FILE & ": malformed write request: missing byte lane strobe" + severity warning; + end if; + read_char( l, c ); -- discard ',' + parse_slv( l, r_req_addr, dontcare ); + r_pending := sl( not dontcare ); + r_req_valid <= r_pending; + wait_cycle; + -- block until accepted + while ((w_pending and not w_req_ready) or (r_pending and not r_req_ready)) = '1' loop + wait_cycle; + end loop; + w_req_valid <= '0'; + r_req_valid <= '0'; + -- wait for transactions to return, as required + read_char( l, c ); -- read terminal wait flag + + if c = '.' then -- '.' == wait for result + while (w_pending or r_pending) = '1' loop + wait_cycle; + if w_rsp_valid = '1' and w_rsp_addr = w_req_addr then + w_pending := '0'; + end if; + if r_rsp_valid = '1' and r_rsp_addr = r_req_addr then + r_pending := '0'; + end if; + end loop; + elsif c = ',' then -- continue immediately + else + assert false + report STIM_FILE & ": bad input: expected terminal ',' or '.'" + severity failure; + end if; + + activity_trans_sim <= '0'; end if; deallocate(l); -- finished with input line end loop; @@ -323,7 +325,7 @@ begin write( l, STIM_FILE & string'(": end of stimuli @ ") & integer'image(now / 1 ns) & string'(" ns.") ); writeline( output, l ); wait; - end process; + end process; -- Stimulation expected: process @@ -339,15 +341,15 @@ begin lp := lp - 1; end loop; end procedure; - ----------------------------------------------------------------------- + ----------------------------------------------------------------------- - variable l: line; + variable l: line; variable i: integer; - variable t, p: integer :=0; + variable t, p: integer :=0; variable c: character; variable ok, dontcare: boolean; - variable write_pending, read_pending: std_logic; - + variable write_pending, read_pending: std_logic; + begin -- NB: Reset is ignored except at the beginning of simulation. @@ -356,86 +358,87 @@ begin wait_cycle; end loop; - -- begin reading stimuli + -- begin reading stimuli while not endfile( expect ) loop -- Main dispatch: Get and parse input readline( expect, l ); lookahead_char( l, c, ok ); next when not ok; - if c = 'B' then - read_char( l, c ); - parse_int( l, i ); - wait for ( i * 1 ns); - wait_cycle; + if c = 'B' then + read_char( l, c ); + parse_int( l, i ); + wait for ( i * 1 ns); + wait_cycle; - elsif c = 'R' then - read_char( l, c ); - parse_int( l, i ); - v := v + 1; - wait for ( i * 1 ns); - wait_cycle; + elsif c = 'R' then + read_char( l, c ); + parse_int( l, i ); + v := v + 1; + wait for ( i * 1 ns); + wait_cycle; - elsif c = 'W' then -- wait until absolute time (ns) + elsif c = 'W' then -- wait until absolute time (ns) read_char( l, c ); -- discard operator parse_int( l, i ); wait for ( i * 1 ns); wait_cycle; - -- operator @(N): wait until absolute time N ns + -- operator @(N): wait until absolute time N ns elsif c = '@' then -- wait until absolute time (ns) read_char( l, c ); -- discard operator parse_int( l, i ); wait for ( i * 1 ns); wait_cycle; - elsif c = '+' then -- wait for relative time (ns) - read_char( l, c ); -- discard operator - parse_int( l, i ); - wait for ( i * 1 ns); + elsif c = '+' then -- wait for relative time (ns) + read_char( l, c ); -- discard operator + parse_int( l, i ); + wait for ( i * 1 ns); wait_cycle; else - parse_slv( l, addr_r, dontcare ); - read_pending := sl( not dontcare ); - read_char( l, c ); -- discard ',' - parse_slv( l, data_r, dontcare ); - if read_pending = '1' then - assert not dontcare - report EXPECT_FILE & ": malformed read request: missing data" - severity warning; - end if; - wait_cycle; - -- block until accepted - while (read_pending and not r_req_ready) = '1' loop - wait_cycle; - end loop; - -- wait for transactions to return, as required - read_char( l, c ); -- read terminal wait flag - if c = '.' then -- '.' == wait for result - while (read_pending) = '1' loop - wait_cycle; - if r_rsp_valid = '1' and addr_r = r_rsp_addr then - read_pending := '0'; - end if; - end loop; - elsif c = ',' then -- continue immediately - else - assert false - report STIM_FILE & ": bad input: expected terminal ',' or '.'" - severity failure; - end if; + parse_slv( l, addr_r, dontcare ); + read_pending := sl( not dontcare ); + read_char( l, c ); -- discard ',' + parse_slv( l, data_r, dontcare ); + if read_pending = '1' then + assert not dontcare + report EXPECT_FILE & ": malformed read request: missing data" + severity warning; + end if; + wait_cycle; + -- block until accepted + while (read_pending and not r_req_ready) = '1' loop + wait_cycle; + end loop; + -- wait for transactions to return, as required + read_char( l, c ); -- read terminal wait flag + if c = '.' then -- '.' == wait for result + while (read_pending) = '1' loop + wait_cycle; + if r_rsp_valid = '1' and addr_r = r_rsp_addr then + read_pending := '0'; + end if; + end loop; + elsif c = ',' then -- continue immediately + else + assert false + report STIM_FILE & ": bad input: expected terminal ',' or '.'" + severity failure; + end if; end if; deallocate(l); -- finished with input line end loop; - -- End of stimuli. + -- End of stimuli. write( l, string'("") ); writeline( output, l ); write( l, EXPECT_FILE & string'(": end of stimuli @ ") & integer'image(now / 1 ns) & string'(" ns.") ); writeline( output, l ); wait; - end process; + end process; -- Expected + -------------------------------------------------------------------------------------------------- @@ -453,60 +456,60 @@ begin end function; variable l: line; - variable g: integer; - variable b: integer := 0; + variable g: integer; + variable b: integer := 0; begin - activity_trans_log <= '0'; - - if rising_edge( axi_aclk ) then - if w_rsp_valid = '1' then - activity_trans_log <= '1'; - hwrite( l, w_rsp_addr, RIGHT, w_rsp_addr'length/4 ); - write( l, string'(" <- ") ); - hwrite( l, w_rsp_data, RIGHT, w_rsp_data'length/4 ); - write( l, string'(" (" & result_str( w_rsp_rsp ) & ")") & - ht & ht & string'("# ") & integer'image(now / 1 ns) & string'(" ns") ); - writeline( log, l ); - end if; - if r_rsp_valid = '1' then - activity_trans_log <= '1'; - hwrite( l, r_rsp_addr, RIGHT, r_rsp_addr'length/4 ); - write( l, string'(" -> ") ); - if addr_r = r_rsp_addr then - - for g in 0 to 31 loop - if (data_r(g) = '0') and (r_rsp_data(g) = 'X') then - b := 1; - end if; - end loop; - - if data_r = r_rsp_data then - hwrite( l, r_rsp_data, RIGHT, r_rsp_data'length/4 ); - write( l, string'(" (" & result_str( r_rsp_rsp ) & ")") & ht & ht & string'("# ") & integer'image(now / 1 ns) & string'(" ns") ); - elsif b = 1 then - hwrite( l, r_rsp_data, RIGHT, r_rsp_data'length/4 ); - write( l, string'(" (" & result_str( r_rsp_rsp ) & ")") & ht & ht & string'("# ") & integer'image(now / 1 ns) & string'(" ns") & string'(" ## ") & string'("WARNING! Undefined bits -- check waveforms!!!!") ); - elsif data_r /= r_rsp_data and b = 0 then - activity_trans_log <= '0'; - write( l, string'("Data Error: register error!!!! ")); - write( l, string'("Seen from user: ")); - hwrite( l, data_r); - write( l, string'(" but expected from system: ")); - hwrite( l, r_rsp_data, RIGHT, r_rsp_data'length/4 ); - end if; - else - activity_trans_log <= '0'; - write( l, string'("Address Error: register error!!!! ")); - write( l, string'("Seen from user: ")); - hwrite( l, addr_r); - write( l, string'(" but expected from system: ")); - hwrite( l, r_rsp_addr, RIGHT, r_rsp_addr'length/4 ); - end if; - writeline( log, l ); - end if; - end if; - + activity_trans_log <= '0'; + + if rising_edge( axi_aclk ) then + if w_rsp_valid = '1' then + activity_trans_log <= '1'; + hwrite( l, w_rsp_addr, RIGHT, w_rsp_addr'length/4 ); + write( l, string'(" <- ") ); + hwrite( l, w_rsp_data, RIGHT, w_rsp_data'length/4 ); + write( l, string'(" (" & result_str( w_rsp_rsp ) & ")") & + ht & ht & string'("# ") & integer'image(now / 1 ns) & string'(" ns") ); + writeline( log, l ); + end if; + if r_rsp_valid = '1' then + activity_trans_log <= '1'; + hwrite( l, r_rsp_addr, RIGHT, r_rsp_addr'length/4 ); + write( l, string'(" -> ") ); + if addr_r = r_rsp_addr then + + for g in 0 to 31 loop + if (data_r(g) = '0') and (r_rsp_data(g) = 'X') then + b := 1; + end if; + end loop; + + if data_r = r_rsp_data then + hwrite( l, r_rsp_data, RIGHT, r_rsp_data'length/4 ); + write( l, string'(" (" & result_str( r_rsp_rsp ) & ")") & ht & ht & string'("# ") & integer'image(now / 1 ns) & string'(" ns") ); + elsif b = 1 then + hwrite( l, r_rsp_data, RIGHT, r_rsp_data'length/4 ); + write( l, string'(" (" & result_str( r_rsp_rsp ) & ")") & ht & ht & string'("# ") & integer'image(now / 1 ns) & string'(" ns") & string'(" ## ") & string'("WARNING! Undefined bits -- check waveforms!!!!") ); + elsif data_r /= r_rsp_data and b = 0 then + activity_trans_log <= '0'; + write( l, string'("Data Error: register error!!!! ")); + write( l, string'("Seen from user: ")); + hwrite( l, data_r); + write( l, string'(" but expected from system: ")); + hwrite( l, r_rsp_data, RIGHT, r_rsp_data'length/4 ); + end if; + else + activity_trans_log <= '0'; + write( l, string'("Address Error: register error!!!! ")); + write( l, string'("Seen from user: ")); + hwrite( l, addr_r); + write( l, string'(" but expected from system: ")); + hwrite( l, r_rsp_addr, RIGHT, r_rsp_addr'length/4 ); + end if; + writeline( log, l ); + end if; + end if; + end process; fifos: entity xil_defaultlib.transactor_fifos diff --git a/hw/lib/std/barrier_v1_0_0/barrier.tcl b/hw/lib/std/barrier_v1_0_0/barrier.tcl index e0abd63..0ac9b7d 100644 --- a/hw/lib/std/barrier_v1_0_0/barrier.tcl +++ b/hw/lib/std/barrier_v1_0_0/barrier.tcl @@ -59,6 +59,20 @@ set_property description ${design} [ipx::current_core] update_ip_catalog -rebuild ipx::infer_user_parameters [ipx::current_core] +ipx::add_user_parameter {NUM_PORTS} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters NUM_PORTS] +set_property display_name {NUM_PORTS} [ipx::get_user_parameters NUM_PORTS] +set_property value {2} [ipx::get_user_parameters NUM_PORTS] +set_property value_format {long} [ipx::get_user_parameters NUM_PORTS] + +ipx::add_user_parameter {INACTIVITY_TIMEOUT} [ipx::current_core] +set_property value_resolve_type {user} [ipx::get_user_parameters INACTIVITY_TIMEOUT] +set_property display_name {INACTIVITY_TIMEOUT} [ipx::get_user_parameters INACTIVITY_TIMEOUT] +set_property value {4000} [ipx::get_user_parameters INACTIVITY_TIMEOUT] +set_property value_format {long} [ipx::get_user_parameters INACTIVITY_TIMEOUT] + +ipx::infer_user_parameters [ipx::current_core] + ipx::check_integrity [ipx::current_core] ipx::save_core [ipx::current_core] update_ip_catalog diff --git a/hw/lib/std/barrier_v1_0_0/hdl/barrier.v b/hw/lib/std/barrier_v1_0_0/hdl/barrier.v index bb9eddf..8b20235 100755 --- a/hw/lib/std/barrier_v1_0_0/hdl/barrier.v +++ b/hw/lib/std/barrier_v1_0_0/hdl/barrier.v @@ -42,8 +42,8 @@ * * Description: * Barrier control module. Aggregates barrier good notifications - * from individual modules and pushes out a global barrier good notification - * when all modules are ready. + * from individual modules and pushes out a global barrier good notification + * when all modules are ready. * * */ @@ -71,9 +71,9 @@ reg timeout; wire [NUM_PORTS:0] activity; wire activity_trans; -assign activity = {activity_stim[2] || activity_rec[2],activity_stim[1] || activity_rec[1],activity_stim[0] || activity_rec[0]}; - -assign activity_trans = {activity_trans_sim || activity_trans_log}; +// assign activity = {activity_stim[2] || activity_rec[2],activity_stim[1] || activity_rec[1],activity_stim[0] || activity_rec[0]}; +assign activity = activity_stim | activity_rec; +assign activity_trans = {activity_trans_sim | activity_trans_log}; initial begin diff --git a/hw/lib/std/nf_data_sink_v1_0_0/Makefile b/hw/lib/std/nf_data_sink_v1_0_0/Makefile new file mode 100644 index 0000000..b4044c4 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/Makefile @@ -0,0 +1,33 @@ +# +# Copyright (c) 2015 University of Cambridge +# Modified by Salvator Galea +# All rights reserved. +# +# This software was developed by +# Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ + +all: clean + vivado -mode batch -source nf_data_sink.tcl + +clean: + rm -rf ip_* vivado*.* *.xml xgui/ .Xil* *.*~ *.zip diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/README.txt b/hw/lib/std/nf_data_sink_v1_0_0/data/README.txt new file mode 100644 index 0000000..b2946c5 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/README.txt @@ -0,0 +1,16 @@ +RUnning "Generate Registers" from the Spreadsheet will produce a python script regs_gen.py + +You may need to edit this to add the following two lines: +def create_mems_list(): + return [] + +Add them just before the line +def create_regs_list() + +Then execute the script (% python regs_gen.py) +This generates three .v files. +Move them to the hdl directory + +$ mv *.v ../hdl/ + +Now you should be able to run synthesis/sims diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods b/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods new file mode 100644 index 0000000..68fd97f Binary files /dev/null and b/hw/lib/std/nf_data_sink_v1_0_0/data/module_generation_nf_data_sink.ods differ diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h new file mode 100644 index 0000000..13e84e3 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.h @@ -0,0 +1,75 @@ +// +// Copyright (c) 2015 University of Cambridge +// All rights reserved. +// +// +// File: +// nf_data_sink_regs_defines.h +// +// Description: +// This file is automatically generated with header defines for the software +// +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme. +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +// license agreements. See the NOTICE file distributed with this work for +// additional information regarding copyright ownership. NetFPGA licenses this +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +// "License"); you may not use this file except in compliance with the +// License. You may obtain a copy of the License at: +// +// http://www.netfpga-cic.org +// +// Unless required by applicable law or agreed to in writing, Work distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + +##########This text should be copied to the head file ############# + #Registers offset definitions + +#define SUME_NF_DATA_SINK_ID_0_OFFSET 0x0 +#define SUME_NF_DATA_SINK_ID_0_DEFAULT 0x0000DAD1 +#define SUME_NF_DATA_SINK_ID_0_WIDTH 32 +#define SUME_NF_DATA_SINK_VERSION_0_OFFSET 0x4 +#define SUME_NF_DATA_SINK_VERSION_0_DEFAULT 0x03081141 +#define SUME_NF_DATA_SINK_VERSION_0_WIDTH 32 +#define SUME_NF_DATA_SINK_RESET_0_OFFSET 0x8 +#define SUME_NF_DATA_SINK_RESET_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_RESET_0_WIDTH 32 +#define SUME_NF_DATA_SINK_FLIP_0_OFFSET 0xC +#define SUME_NF_DATA_SINK_FLIP_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_FLIP_0_WIDTH 32 +#define SUME_NF_DATA_SINK_DEBUG_0_OFFSET 0x10 +#define SUME_NF_DATA_SINK_DEBUG_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_DEBUG_0_WIDTH 32 +#define SUME_NF_DATA_SINK_ENABLE_0_OFFSET 0x14 +#define SUME_NF_DATA_SINK_ENABLE_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_ENABLE_0_WIDTH 32 +#define SUME_NF_DATA_SINK_PKTIN_0_OFFSET 0x18 +#define SUME_NF_DATA_SINK_PKTIN_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_PKTIN_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINLO_0_OFFSET 0x1c +#define SUME_NF_DATA_SINK_BYTESINLO_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINLO_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINHI_0_OFFSET 0x20 +#define SUME_NF_DATA_SINK_BYTESINHI_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINHI_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TIME_0_OFFSET 0x24 +#define SUME_NF_DATA_SINK_TIME_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TIME_0_WIDTH 32 +#define SUME_NF_DATA_SINK_AXI_CLK_0_OFFSET 0x28 +#define SUME_NF_DATA_SINK_AXI_CLK_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_AXI_CLK_0_WIDTH 32 +#define SUME_NF_DATA_SINK_AXIS_CLK_0_OFFSET 0x2c +#define SUME_NF_DATA_SINK_AXIS_CLK_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_AXIS_CLK_0_WIDTH 32 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/regs_gen.py b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_gen.py new file mode 100644 index 0000000..c888cbb --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_gen.py @@ -0,0 +1,1860 @@ +#! /usr/bin/env python +###################################################################################### +# NetFPGA-10G http://www.netfpga.org +# +# File: +# regs_gen.py +# +# Author: +# Noa Zilberman +# +# Description: +# This file generates the required registers-related verilog modules +# +# Copyright notice: +# Copyright (C) 2013 University of Cambridge +# +# Licence: +# This file is part of the NetFPGA 10G development base package. +# +# This file is free code: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License version 2.1 as +# published by the Free Software Foundation. +# +# This package is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the NetFPGA source package. If not, see +# http://www.gnu.org/licenses/. +# +####################################################################################### + +################################################################## +#Define the list of registers (busses) and their characteristics +################################################################## + +module_name='nf_data_sink' + +block_name=module_name.upper() + +def create_mems_list(): + return [] + +def create_regs_list(): + regsDict=[ +{'reg':"ID",'type':"RO",'endian':"little", 'name':"id",'bits':"31:0",'width':"32",'addr':"32'h0",'default':"32'h0000DAD1"}, + +{'reg':"Version",'type':"RO",'endian':"little", 'name':"version",'bits':"31:0",'width':"32",'addr':"32'h4",'default':"32'h03081141"}, + +{'reg':"Reset",'type':"WOE",'endian':"little", 'name':"reset",'bits':"31:0",'width':"32",'addr':"32'h8",'default':"32'h0"}, + +{'reg':"Flip",'type':"RWA",'endian':"little", 'name':"flip",'bits':"31:0",'width':"32",'addr':"32'hC",'default':"32'h0"}, + +{'reg':"Debug",'type':"RWA",'endian':"little", 'name':"debug",'bits':"31:0",'width':"32",'addr':"32'h10",'default':"32'h0"}, + +{'reg':"Enable",'type':"RWA",'endian':"little", 'name':"enable",'bits':"31:0",'width':"32",'addr':"32'h14",'default':"32'h0"}, + +{'reg':"PktIn",'type':"RO",'endian':"little", 'name':"pktin",'bits':"31:0",'width':"32",'addr':"32'h18",'default':"32'h0"}, + +{'reg':"BytesInLo",'type':"RO",'endian':"little", 'name':"bytesinlo",'bits':"31:0",'width':"32",'addr':"32'h1c",'default':"32'h0"}, + +{'reg':"BytesInHi",'type':"RO",'endian':"little", 'name':"bytesinhi",'bits':"31:0",'width':"32",'addr':"32'h20",'default':"32'h0"}, + +{'reg':"Time",'type':"RO",'endian':"little", 'name':"time",'bits':"31:0",'width':"32",'addr':"32'h24",'default':"32'h0"}, + +{'reg':"AXI_CLK",'type':"RO",'endian':"little", 'name':"axi_clk",'bits':"31:0",'width':"32",'addr':"32'h28",'default':"32'h0"}, + +{'reg':"AXIS_CLK",'type':"RO",'endian':"little", 'name':"axis_clk",'bits':"31:0",'width':"32",'addr':"32'h2c",'default':"32'h0"}, + +] + return(regsDict) +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang, Salvator Galea +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. NetFPGA licenses this +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at: +# +# http://www.netfpga-cic.org +# +# Unless required by applicable law or agreed to in writing, Work distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +################################################################## +# a function that writes the header of regs file +################################################################## +def write_regs_header(regsFile): + regsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') +#end of write_regs_headerdefault + +################################################################## +# a function that writes the header of regs defines file +################################################################## + +def write_defs_header(defsFile): + defsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs_defines.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs_defines\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers defintions towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_defs_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_tcl_header(tclFile): + tclFile.write('\ +#\n\ +# Copyright (c) 2015 University of Cambridge\n\ +# All rights reserved.\n\ +#\n\ +#\n\ +# File:\n\ +# '+module_name+'_regs_defines.tcl\n\ +#\n\ +# Description:\n\ +# This file is automatically generated with tcl defines for the software\n\ +#\n\ +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +# under National Science Foundation under Grant No. CNS-0855268,\n\ +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +# as part of the DARPA MRC research programme.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_START@\n\ +#\n\ +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +# license agreements. See the NOTICE file distributed with this work for\n\ +# additional information regarding copyright ownership. NetFPGA licenses this\n\ +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +# "License"); you may not use this file except in compliance with the\n\ +# License. You may obtain a copy of the License at:\n\ +#\n\ +# http://www.netfpga-cic.org\n\ +#\n\ +# Unless required by applicable law or agreed to in writing, Work distributed\n\ +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +# CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +# specific language governing permissions and limitations under the License.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_END@\n\ +#\n\ +\n') + +#end of write_tcl_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_hFile_header(hFile): + hFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.h\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_h_header + + +################################################################## +# a function that writes the header of regs table file +################################################################## +def write_tbFile_header(tbFile): + tbFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.txt\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +################################################################## +#A funtion that writes the ports of the regs moduledefault +################################################################## + +def write_regs_ports(regsFile,regsDict, memsDict): + + regsFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\ +module '+module_name+'_cpu_regs #\n\ +(\n\ +parameter C_BASE_ADDRESS = 32\'h00000000,\n\ +parameter C_S_AXI_DATA_WIDTH = 32,\n\ +parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +(\n\ + // General ports\n\ + input clk,\n\ + input resetn,\n\ + // Global Registers\n\ + input cpu_resetn_soft,\n\ + output reg resetn_soft,\n\ + output reg resetn_sync,\n\ +\n\ + // Register ports\n') + + for entry in regsDict: + if entry['type']=="RO" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="ROC" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + regsFile.write(' output reg '+entry['name']+'_reg_clear,\n') + if entry['type']=="RWS" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WO" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WOE" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="RWA" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + if entry['type']=="RWCR" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + if entry['type']=="RWCW" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + + for entry in memsDict: + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr,\n') + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data,\n') + regsFile.write(' output reg '+entry['name']+'_rd_wrn,\n') + regsFile.write(' output reg '+entry['name']+'_cmd_valid,\n') + regsFile.write(' input [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_reply,\n') + regsFile.write(' input '+entry['name']+'_reply_valid,\n') + + regsFile.write('\n\ + // AXI Lite ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +\n\ +);\n'); +#end of write_regs_ports + +################################################################## +#A funtion that writes the wires and regs of the registers module +################################################################## +def write_regs_wires(regsFile,regsDict,memsDict): + + regsFile.write('\n\ + // AXI4LITE signals\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;\n\ + reg axi_awready;\n\ + reg axi_wready;\n\ + reg [1 : 0] axi_bresp;\n\ + reg axi_bvalid;\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;\n\ + reg axi_arready;\n\ + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;\n\ + reg [1 : 0] axi_rresp;\n\ + reg axi_rvalid;\n\ +\n\ + reg resetn_sync_d;\n\ + wire reg_rden;\n\ + wire reg_wren;\n\ + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;\n\ + integer byte_index;\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + reg cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + reg '+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="RWSI" or entry['type']=="ROI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg_internal;\n\ + reg '+entry['name']+'_reg_update;\n') + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\n\ + // assign default little endian\n'); + regsFile.write('\ + wire [C_S_AXI_DATA_WIDTH-1 : 0] reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + regsFile.write('\n\ + // I/O Connections assignments\n\ + assign S_AXI_AWREADY = axi_awready;\n\ + assign S_AXI_WREADY = axi_wready;\n\ + assign S_AXI_BRESP = axi_bresp;\n\ + assign S_AXI_BVALID = axi_bvalid;\n\ + assign S_AXI_ARREADY = axi_arready;\n\ + assign S_AXI_RDATA = axi_rdata;\n\ + assign S_AXI_RRESP = axi_rresp;\n\ + assign S_AXI_RVALID = axi_rvalid;\n\ +\n'); + + +#end of write_regs_wires + + +################################################################## +#sync reset signal for better timing +################################################################## +def sync_reset(regsFile): + + regsFile.write('\n\ + //Sample reset (not mandatory, but good practice)\n\ + always @ (posedge clk) begin\n\ + if (~resetn) begin\n\ + resetn_sync_d <= 1\'b0;\n\ + resetn_sync <= 1\'b0;\n\ + end\n\ + else begin\n\ + resetn_sync_d <= resetn;\n\ + resetn_sync <= resetn_sync_d;\n\ + end\n\ + end\n\ +\n'); + +# for now, only global reset is supported, to demonstrate usage + regsFile.write('\n\ + //global registers, sampling\n\ + always @(posedge clk) resetn_soft <= #1 cpu_resetn_soft;\n'); + + +#end of sync_reset + +################################################################## +# a function that writes the logic behind the registers access +################################################################## +def write_logic(regsFile,regsDict): +# boolean first_item; + + +# axi protocol generation + + regsFile.write('\n\ + // Implement axi_awready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // slave is ready to accept write address when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_awready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_awaddr latching\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awaddr <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // Write Address latching\n\ + axi_awaddr <= S_AXI_AWADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_wready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)\n\ + begin\n\ + // slave is ready to accept write data when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_wready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement write response logic generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_bvalid <= 0;\n\ + axi_bresp <= 2\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)\n\ + begin\n\ + // indicates a valid write response is available\n\ + axi_bvalid <= 1\'b1;\n\ + axi_bresp <= 2\'b0; // OKAY response\n\ + end // work error responses in future\n\ + else\n\ + begin\n\ + if (S_AXI_BREADY && axi_bvalid)\n\ + //check if bready is asserted while bvalid is high)\n\ + //(there is a possibility that bready is always asserted high)\n\ + begin\n\ + axi_bvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_arready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + axi_araddr <= 32\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_arready && S_AXI_ARVALID)\n\ + begin\n\ + // indicates that the slave has acceped the valid read address\n\ + // Read address latching\n\ + axi_arready <= 1\'b1;\n\ + axi_araddr <= S_AXI_ARADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + else\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n\ + // Implement axi_rvalid generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rvalid <= 0;\n\ + axi_rresp <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)\n\ + begin\n\ + // Valid read data is available at the read data bus\n\ + axi_rvalid <= 1\'b1;\n\ + axi_rresp <= 2\'b0; // OKAY response\n\ + end\n\ + else if (axi_rvalid && S_AXI_RREADY)\n\ + begin\n\ + // Read data is accepted by the master\n\ + axi_rvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n'); + + + regsFile.write('\ + // Implement memory mapped register select and write logic generation\n\ +\n\ + assign reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;\n\ +\n\ +//////////////////////////////////////////////////////////////\n\ +// write registers\n\ +//////////////////////////////////////////////////////////////\n\ +\n'); + +#Handle write only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="WO" : + if first_item: + regsFile.write('\n\ +//Write only register, not cleared\n\ + //static\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + first_item=False; + + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin //write event\n\ + case (axi_awaddr)\n'); + + + for entry in regsDict: + if entry['type']=="WO" : + if entry['endian']=="little" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n'); + + +#Handle write only event registers + + first_item=True; + + for entry in regsDict: + if entry['type']=="WOE" : + if first_item: + first_item= False; + regsFile.write('\n\ +//Write only register, clear on write (i.e. event)\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + +#Handle Read/write registers, not cleared + + first_item=True; + + for entry in regsDict: + if first_item and (entry['type']=="RWS" or entry['type']=="RWA"): + first_item = False; + regsFile.write('\n\ +//R/W register, not cleared\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg_internal <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren) //write event\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not (first_item): + regsFile.write('\ + default: begin\n\ + end\n\ +\n\ + endcase\n\ + end\n'); + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write(' '+entry['name']+'_reg_update <= reg_wren && (axi_awaddr == `REG_'+entry['name'].upper()+'_ADDR);\n'); + + if not (first_item): + regsFile.write(' end\n'); + +#Handle Read/write registers, clear on read + + first_item=True; + + for entry in regsDict: + if entry['type']=="RWCR" : + if first_item: + first_item = False; + regsFile.write('\n\ +//R/W register, clear on read\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not (first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren)\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n\ +\n\ +\n\ +//clear assertions\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 reg_rden && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\n\ + end\n\ + end\n'); + + + +#Handle Read/write registers, clear on write + + first_item= True; + + for entry in regsDict: + if entry['type']=="RWCW" : + first_item = False; + regsFile.write('\n\ +//R/W register, clear on write, dynamic\n\ +// i.e. on write - write, next clock - write default value\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear_d <= #1 1\'b0;\n\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= cpu2ip_'+entry['name']+'_reg_clear_d;\n\ + cpu2ip_'+entry['name']+'_reg_clear_d <= reg_wren && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + if (reg_wren) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + if entry['endian']=="little" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index+1 )\n\ + if ( S_AXI_WSTRB[byte_index] == 1 ) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + regsFile.write('\ +\n\ +\n\ +\n\ +/////////////////////////\n\ +//// end of write\n\ +/////////////////////////\n'); + + regsFile.write('\n\ + // Implement memory mapped register select and read logic generation\n\ + // Slave register read enable is asserted when valid address is available\n\ + // and the slave is ready to accept the read address.\n\ +\n\ + // reg_rden control logic\n\ + // temperary no extra logic here\n\ + assign reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;\n'); + +#return read data + regsFile.write('\n\ + always @(*)\n\ + begin\n\ +\n\ + case ( axi_araddr /*S_AXI_ARADDR ^ C_BASE_ADDRESS*/)\n'); + + for entry in regsDict: + if entry['type']=="RO" or entry['type']=="ROC" or entry['type']=="RWS" or entry['type']=="RWI" or entry['type']=="RWSI" or entry['type']=="ROI": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = '+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = '+entry['name']+'_reg [(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width'])<32: + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + if entry['type']=="RWCW" or entry['type']=="RWA" or entry['type']=="RWCR": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = ip2cpu_'+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = ip2cpu_'+entry['name']+'_reg[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width']) < 32 : + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + regsFile.write('\ + //Default return value\n\ + default: begin\n\ + reg_data_out [31:0] = 32\'hDEADBEEF;\n\ + end\n\ +\n\ + endcase\n\ +\n\ + end//end of assigning data to IP2Bus_Data bus\n'); + +#Handle read only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="ROC" : + if first_item: + first_item=False; + regsFile.write('\n\ + //Read only registers, not cleared\n\ + //Nothing to do here....\n\ +\n\ +//Read only registers, cleared on read (e.g. counters)\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 1\'b0;\n\ + '+entry['name']+'_reg_clear_d <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 '+entry['name']+'_reg_clear_d;\n\ + '+entry['name']+'_reg_clear_d <= #1(reg_rden && (axi_araddr==`REG_'+entry['name'].upper()+'_ADDR)) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\n'); + + regsFile.write('\n\ +// Output register or memory read data\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rdata <= 0;\n\ + end\n\ + else\n\ + begin\n\ + // When there is a valid read address (S_AXI_ARVALID) with\n\ + // acceptance of read address by the slave (axi_arready),\n\ + // output the read dada\n\ + if (reg_rden)\n\ + begin\n\ + axi_rdata <= reg_data_out/*ip2bus_data*/; // register read data /* some new changes here */\n\ + end\n\ + end\n\ + end\n'); + +# end of write_logic + +################################################################## +# a function that writes the logic behind the indirect registers access +################################################################## +def write_indirect(regsFile,memsDict): + regsFile.write('\n\ + //////////////////////////////////\n\ + // Implement Indirect Access\n\ + //////////////////////////////////\n\ + \n'); + + regsFile.write('\n\ + //--------------------- Internal Parameters-------------------------\n\ + localparam NUM_INDIRECT_STATES = 6;\n\ + localparam IDLE_INDIRECT_STATE = 1;\n\ + localparam WRITE_INDIRECT_STATE = 2;\n\ + localparam WRITE_WAIT_INDIRECT_STATE = 4;\n\ + localparam READ_INDIRECT_STATE = 8;\n\ + localparam READ_WAIT_INDIRECT_STATE = 16;\n\ + localparam INDIRECT_DONE_STATE = 32;\n\ + localparam INDIRECT_WRITE = 0;\n\ + localparam INDIRECT_READ = 1;\n\ + localparam INDIRECT_WRITE_TA = 1;\n\ + localparam INDIRECT_WRITE_WS = 0;\n\ + //------------------------------------------------------------------\n\ + \n\ + reg [NUM_INDIRECT_STATES-1:0] indirect_state, indirect_state_next, indirect_state_last;\n\ + wire indirect_trigger;\n\ + wire indirect_type;\n\ + reg indirect_status, indirect_status_next;\n\ + wire [3:0] indirect_address_increment;\n\ + wire indirect_write_type;\n\ + wire [10:0] indirect_timeout;\n\ + wire [15:0] indirect_repeat_count;\n\ + reg [15:0] indirect_remaining,indirect_remaining_next;\n\ + reg [10:0] indirect_timeout_count, indirect_timeout_count_next;\n\ + reg indirect_reply_valid;\n\ + reg [31:0] indirect_address,indirect_address_next;\n\ + reg [3:0] indirect_memory_select,indirect_memory_select_next;\n\ + wire indirect_command_done;\n\ + \n\ + assign indirect_trigger = indirectcommand_reg[0];\n\ + assign indirect_type = indirectcommand_reg[4];\n\ + assign indirect_address_increment = indirectconfig_reg[3:0];\n\ + assign indirect_write_type = indirectconfig_reg[4];\n\ + assign indirect_timeout = indirectconfig_reg[15:5];\n\ + assign indirect_repeat_count = indirectconfig_reg[31:16];\n\ + \n\ + always @(*) begin\n\ + indirect_state_next = indirect_state;\n\ + indirect_status_next = indirect_status;\n\ + indirect_remaining_next = indirect_remaining;\n\ + indirect_timeout_count_next = indirect_timeout_count;\n\ + indirect_address_next = indirect_address;\n\ + indirect_memory_select_next = indirect_memory_select;\n\ + case(indirect_state)\n\ + IDLE_INDIRECT_STATE: begin\n\ + if(indirect_trigger) begin\n\ + indirect_state_next= (indirect_type == INDIRECT_WRITE) ? WRITE_INDIRECT_STATE : READ_INDIRECT_STATE;\n\ + indirect_remaining_next = (indirect_repeat_count == 0) ? 16\'h1 : indirect_repeat_count;\n\ + indirect_timeout_count_next = indirect_timeout;\n\ + indirect_address_next = indirectaddress_reg; //This is the address in the user register\n\ + indirect_memory_select_next = indirectaddress_reg[31:28];\n\ + end\n\ + end\n\ + \n\ + READ_INDIRECT_STATE: begin\n\ + indirect_state_next = READ_WAIT_INDIRECT_STATE;\n\ + end\n\ + READ_WAIT_INDIRECT_STATE: begin\n\ + if (indirect_reply_valid) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next =0;\n\ + end\n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count-1;\n\ + end\n\ + WRITE_INDIRECT_STATE: begin\n\ + indirect_state_next = WRITE_WAIT_INDIRECT_STATE;\n\ + end\n\ + WRITE_WAIT_INDIRECT_STATE: begin\n\ + if (((indirect_write_type == INDIRECT_WRITE_TA) && (indirect_reply_valid)) || ((indirect_write_type == INDIRECT_WRITE_WS) && (indirect_timeout_count==0))) begin\n\ + indirect_remaining_next = indirect_remaining - 1;\n\ + indirect_address_next = indirect_address+indirect_address_increment;\n\ + if (indirect_remaining==1) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + end\n\ + end\n\ + else \n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count==0 ? 0 : indirect_timeout_count-1;\n\ + end\n\ + INDIRECT_DONE_STATE: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + default: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + endcase // case(state)\n\ + end // always @ (*)\n\ + \n\ + assign indirect_command_done = (indirect_state==INDIRECT_DONE_STATE);\n\ + \n\ + always @(posedge clk) begin\n\ + if(~resetn_sync) begin\n\ + indirect_state <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_state_last <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_status <= #1 1\'b0;\n\ + indirect_remaining <= #1 0;\n\ + indirect_timeout_count <= #1 0;\n\ + indirect_address <= #1 0;\n\ + indirect_memory_select <= #1 0;\n\ + indirectcommand_reg <= #1 `REG_INDIRECTCOMMAND_DEFAULT;\n\ + end\n\ + else begin\n\ + indirect_state <= #1 indirect_state_next;\n\ + indirect_state_last <= #1 indirect_state;\n\ + indirect_status <= #1 indirect_status_next;\n\ + indirect_remaining <= #1 indirect_remaining_next;\n\ + indirect_timeout_count <= #1 indirect_timeout_count_next;\n\ + indirect_address <= #1 indirect_address_next;\n\ + indirect_memory_select <= #1 indirect_memory_select_next;\n\ + indirectcommand_reg <= #1 indirect_command_done ? {indirect_status,indirectcommand_reg[7:4],4\'h0} : \n\ + indirectcommand_reg_update ? indirectcommand_reg_internal: \n\ + indirectcommand_reg;\n\ + end\n\ + end \n\ + \n'); + + + for entry in memsDict: + regsFile.write('\n\ + \n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + '+entry['name']+'_addr <= #1 0;\n\ + '+entry['name']+'_data <= #1 0;\n\ + '+entry['name']+'_rd_wrn<= #1 0;\n\ + '+entry['name']+'_cmd_valid <= #1 0;\n\ + end \n\ + else begin\n\ + '+entry['name']+'_addr <= #1 indirect_address;\n\ + '+entry['name']+'_data <= #1 indirectwrdata_reg;\n\ + '+entry['name']+'_rd_wrn<= #1 indirect_type;\n\ + '+entry['name']+'_cmd_valid <= #1 ('+entry['address']+'==(indirect_memory_select<<28)) && ((indirect_state == WRITE_INDIRECT_STATE) || (indirect_state == READ_INDIRECT_STATE));\n\ + end \n\ + end\n'); + + regsFile.write('\n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + indirectreply_reg <= #1 0;\n\ + indirect_reply_valid <= #1 0; \n\ + end \n\ + else begin \n\ + indirectreply_reg <= #1 ' ); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply :'); + regsFile.write(' 0;\n\ + indirect_reply_valid <= #1 '); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply_valid :'); + regsFile.write(' 0;\n\ + end \n\ + end\n\ + \n'); +# end of write_indirect + +################################################################## +#write all the defines to the defs module +################################################################## +def write_defines(defsFile,regsDict, memsDict): + + for entry in regsDict: + defsFile.write( '\n`define REG_'+entry['name'].upper()+'_BITS\t\t\t\t'+entry['bits']+ + '\n`define REG_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define REG_'+entry['name'].upper()+'_DEFAULT\t\t\t\t'+entry['default']+ + '\n`define REG_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['addr']+'\n'); + + for entry in memsDict: + defsFile.write( '\n`define MEM_'+entry['name'].upper()+'_DATA_BITS\t\t\t\t'+entry['data_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR_BITS\t\t\t\t'+entry['addr_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define MEM_'+entry['name'].upper()+'_DEPTH\t\t\t\t'+str(2**(int(entry['addr_bits'].split(':')[0])+1))+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['address']+'\n'); + +#end of write_defines + + +################################################################## +#write all the register offsets to the h template (to be included) +################################################################## +def write_h(hFile,regsDict,memsDict): + + hFile.write('##########This text should be copied to the head file #############\n\ + #Registers offset definitions\n\n'); + + for entry in regsDict: + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + +#end of write_h + +################################################################## +#write all the register offsets to the tcl file +################################################################## +def write_tcl(tclFile,regsDict,memsDict): + + for entry in regsDict: + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + + +#end of write_tcl + +################################################################## +#write all the register offsets to table +################################################################## + +def write_tb(tbFile,regsDict,memsDict): + for entry in regsDict: + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' OFFSET 0x'+entry['addr'][4:]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); +#end of write_tb + +################################################################## +#write top module's template (i.e. include this in your module) +################################################################## +def write_module_template(moduleFile,regsDict,memsDict): + +#first write static inclusions.... + moduleFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\n\ +//parameters to be added to the top module parameters\n\ +#(\n\ + // AXI Registers Data Width\n\ + parameter C_S_AXI_DATA_WIDTH = 32,\n\ + parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +//ports to be added to the top module ports\n\ +(\n\ +// Signals for AXI_IP and IF_REG (Added for debug purposes)\n\ + // Slave AXI Ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +)\n\n'); + + first_item = True; + for entry in regsDict: + if first_item and (entry['endian']=="big") : + first_item = False; + moduleFile.write('\n\ + // define and assign default little endian\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + wire reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + +#then add design specific wires/regs: + + moduleFile.write('\n\ + // define registers\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="ROC" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + moduleFile.write(' wire '+entry['name']+'_reg_clear;\n') + if entry['type']=="RWS" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WO" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WOE" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="RWA" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + if entry['type']=="RWCR" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + if entry['type']=="RWCW" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in memsDict: + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr;\n') + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data;\n') + moduleFile.write(' wire '+entry['name']+'_rd_wrn;\n') + moduleFile.write(' wire '+entry['name']+'_cmd_valid;\n') + moduleFile.write(' reg [`MEM_'+(entry['name']).upper()+'DATA_BITS] '+entry['name']+'_reply;\n') + moduleFile.write(' reg '+entry['name']+'_reply_valid;\n') + + +#instantiate registers module + moduleFile.write('\n//Registers section\n\ + '+module_name+'_cpu_regs\n\ + #(\n\ + .C_BASE_ADDRESS (C_BASEADDR ),\n\ + .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH),\n\ + .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH)\n\ + ) '+module_name+'_cpu_regs_inst\n\ + (\n\ + // General ports\n\ + .clk (axis_aclk),\n\ + .resetn (axis_resetn),\n\ + // AXI Lite ports\n\ + .S_AXI_ACLK (S_AXI_ACLK),\n\ + .S_AXI_ARESETN (S_AXI_ARESETN),\n\ + .S_AXI_AWADDR (S_AXI_AWADDR),\n\ + .S_AXI_AWVALID (S_AXI_AWVALID),\n\ + .S_AXI_WDATA (S_AXI_WDATA),\n\ + .S_AXI_WSTRB (S_AXI_WSTRB),\n\ + .S_AXI_WVALID (S_AXI_WVALID),\n\ + .S_AXI_BREADY (S_AXI_BREADY),\n\ + .S_AXI_ARADDR (S_AXI_ARADDR),\n\ + .S_AXI_ARVALID (S_AXI_ARVALID),\n\ + .S_AXI_RREADY (S_AXI_RREADY),\n\ + .S_AXI_ARREADY (S_AXI_ARREADY),\n\ + .S_AXI_RDATA (S_AXI_RDATA),\n\ + .S_AXI_RRESP (S_AXI_RRESP),\n\ + .S_AXI_RVALID (S_AXI_RVALID),\n\ + .S_AXI_WREADY (S_AXI_WREADY),\n\ + .S_AXI_BRESP (S_AXI_BRESP),\n\ + .S_AXI_BVALID (S_AXI_BVALID),\n\ + .S_AXI_AWREADY (S_AXI_AWREADY),\n\ +\n\ + // Register ports\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="ROC" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + moduleFile.write(' .'+entry['name']+'_reg_clear ('+entry['name']+'_reg_clear),\n') + if entry['type']=="RWS" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WOE" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="RWA" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + if entry['type']=="RWCR" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + if entry['type']=="RWCW" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + + for entry in memsDict: + moduleFile.write(' .'+entry['name']+'_addr ('+entry['name']+'_addr),\n') + moduleFile.write(' .'+entry['name']+'_data ('+entry['name']+'_data),\n') + moduleFile.write(' .'+entry['name']+'_rd_wrn ('+entry['name']+'_rd_wrn),\n') + moduleFile.write(' .'+entry['name']+'_cmd_valid ('+entry['name']+'_cmd_valid ),\n') + moduleFile.write(' .'+entry['name']+'_reply ('+entry['name']+'_reply),\n') + moduleFile.write(' .'+entry['name']+'_reply_valid ('+entry['name']+'_reply_valid),\n') + + + moduleFile.write(' // Global Registers - user can select if to use\n\ + .cpu_resetn_soft(),//software reset, after cpu module\n\ + .resetn_soft (),//software reset to cpu module (from central reset management)\n\ + .resetn_sync (resetn_sync)//synchronized reset, use for better timing\n\ +);\n\ +//registers logic, current logic is just a placeholder for initial compil, required to be changed by the user\n'); + +#registers logic + + moduleFile.write('always @(posedge axis_aclk)\n\ + if (~resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 \'h0\n;') + + moduleFile.write(' end\n\ + else begin\n') + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWA" : + moduleFile.write(' ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;\n') + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear_d == 1\'b1) \n\ + ip2cpu_'+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 cpu_'+entry['name']+'_reg_clear;\n') + + moduleFile.write('\ + end\n\n') + + + +#end of write_module_template + + +######################################################################################## +# +# Main function body +# +######################################################################################## + + +# List of files to be generated. +filename_regs=''+module_name+'_cpu_regs.v' +filename_defs=''+module_name+'_cpu_regs_defines.v' +filename_template=''+module_name+'_cpu_template.v' +filename_h=''+module_name+'_regs_defines.h' +filename_tcl=''+module_name+'_regs_defines.tcl' +filename_tb=''+module_name+'_regs_defines.txt' + + +# Open the files for writing +regsFile = open(filename_regs, 'w') +defsFile = open(filename_defs, 'w') +moduleFile = open(filename_template, 'w') +hFile = open(filename_h, 'w') +tclFile = open(filename_tcl, 'w') +tbFile = open(filename_tb, 'w') + +# Write the header of each file +write_regs_header(regsFile) +write_defs_header(defsFile) +write_tcl_header(tclFile) +write_hFile_header(hFile) +write_tbFile_header(tbFile) + +#Write the regs module +#first the ports... +regsDict=create_regs_list() +memsDict=create_mems_list() +write_regs_ports(regsFile,regsDict, memsDict) + + +#then the wires... +write_regs_wires(regsFile,regsDict, memsDict) + +#resets etc..... +sync_reset(regsFile) + + +#registers logic... +write_logic(regsFile,regsDict) + +#indirect access... +if memsDict: + write_indirect(regsFile,memsDict) + +#tables... + +#close module..... +regsFile.write('endmodule\n') + +#write the defs module +write_defines(defsFile,regsDict, memsDict) + +#write the tcl module +write_tcl(tclFile,regsDict, memsDict) + +#write the default text to be copied to the h module +write_h(hFile,regsDict, memsDict) + +#write the default text to table file +write_tb(tbFile,regsDict, memsDict) + +#writes the default text to be copied to the top module +write_module_template(moduleFile,regsDict, memsDict) + + +# Close the output files +regsFile.close() +defsFile.close() +tclFile.close() +moduleFile.close() +hFile.close() +tbFile.close() diff --git a/hw/lib/std/nf_data_sink_v1_0_0/data/regs_template.txt b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_template.txt new file mode 100644 index 0000000..d90222b --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/data/regs_template.txt @@ -0,0 +1,1787 @@ +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang, Salvator Galea +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. NetFPGA licenses this +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at: +# +# http://www.netfpga-cic.org +# +# Unless required by applicable law or agreed to in writing, Work distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +################################################################## +# a function that writes the header of regs file +################################################################## +def write_regs_header(regsFile): + regsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') +#end of write_regs_headerdefault + +################################################################## +# a function that writes the header of regs defines file +################################################################## + +def write_defs_header(defsFile): + defsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs_defines.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs_defines\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers defintions towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_defs_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_tcl_header(tclFile): + tclFile.write('\ +#\n\ +# Copyright (c) 2015 University of Cambridge\n\ +# All rights reserved.\n\ +#\n\ +#\n\ +# File:\n\ +# '+module_name+'_regs_defines.tcl\n\ +#\n\ +# Description:\n\ +# This file is automatically generated with tcl defines for the software\n\ +#\n\ +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +# under National Science Foundation under Grant No. CNS-0855268,\n\ +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +# as part of the DARPA MRC research programme.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_START@\n\ +#\n\ +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +# license agreements. See the NOTICE file distributed with this work for\n\ +# additional information regarding copyright ownership. NetFPGA licenses this\n\ +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +# "License"); you may not use this file except in compliance with the\n\ +# License. You may obtain a copy of the License at:\n\ +#\n\ +# http://www.netfpga-cic.org\n\ +#\n\ +# Unless required by applicable law or agreed to in writing, Work distributed\n\ +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +# CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +# specific language governing permissions and limitations under the License.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_END@\n\ +#\n\ +\n') + +#end of write_tcl_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_hFile_header(hFile): + hFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.h\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_h_header + + +################################################################## +# a function that writes the header of regs table file +################################################################## +def write_tbFile_header(tbFile): + tbFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.txt\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +################################################################## +#A funtion that writes the ports of the regs moduledefault +################################################################## + +def write_regs_ports(regsFile,regsDict, memsDict): + + regsFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\ +module '+module_name+'_cpu_regs #\n\ +(\n\ +parameter C_BASE_ADDRESS = 32\'h00000000,\n\ +parameter C_S_AXI_DATA_WIDTH = 32,\n\ +parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +(\n\ + // General ports\n\ + input clk,\n\ + input resetn,\n\ + // Global Registers\n\ + input cpu_resetn_soft,\n\ + output reg resetn_soft,\n\ + output reg resetn_sync,\n\ +\n\ + // Register ports\n') + + for entry in regsDict: + if entry['type']=="RO" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="ROC" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + regsFile.write(' output reg '+entry['name']+'_reg_clear,\n') + if entry['type']=="RWS" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WO" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WOE" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="RWA" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + if entry['type']=="RWCR" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + if entry['type']=="RWCW" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + + for entry in memsDict: + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr,\n') + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data,\n') + regsFile.write(' output reg '+entry['name']+'_rd_wrn,\n') + regsFile.write(' output reg '+entry['name']+'_cmd_valid,\n') + regsFile.write(' input [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_reply,\n') + regsFile.write(' input '+entry['name']+'_reply_valid,\n') + + regsFile.write('\n\ + // AXI Lite ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +\n\ +);\n'); +#end of write_regs_ports + +################################################################## +#A funtion that writes the wires and regs of the registers module +################################################################## +def write_regs_wires(regsFile,regsDict,memsDict): + + regsFile.write('\n\ + // AXI4LITE signals\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;\n\ + reg axi_awready;\n\ + reg axi_wready;\n\ + reg [1 : 0] axi_bresp;\n\ + reg axi_bvalid;\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;\n\ + reg axi_arready;\n\ + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;\n\ + reg [1 : 0] axi_rresp;\n\ + reg axi_rvalid;\n\ +\n\ + reg resetn_sync_d;\n\ + wire reg_rden;\n\ + wire reg_wren;\n\ + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;\n\ + integer byte_index;\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + reg cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + reg '+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="RWSI" or entry['type']=="ROI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg_internal;\n\ + reg '+entry['name']+'_reg_update;\n') + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\n\ + // assign default little endian\n'); + regsFile.write('\ + wire [C_S_AXI_DATA_WIDTH-1 : 0] reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + regsFile.write('\n\ + // I/O Connections assignments\n\ + assign S_AXI_AWREADY = axi_awready;\n\ + assign S_AXI_WREADY = axi_wready;\n\ + assign S_AXI_BRESP = axi_bresp;\n\ + assign S_AXI_BVALID = axi_bvalid;\n\ + assign S_AXI_ARREADY = axi_arready;\n\ + assign S_AXI_RDATA = axi_rdata;\n\ + assign S_AXI_RRESP = axi_rresp;\n\ + assign S_AXI_RVALID = axi_rvalid;\n\ +\n'); + + +#end of write_regs_wires + + +################################################################## +#sync reset signal for better timing +################################################################## +def sync_reset(regsFile): + + regsFile.write('\n\ + //Sample reset (not mandatory, but good practice)\n\ + always @ (posedge clk) begin\n\ + if (~resetn) begin\n\ + resetn_sync_d <= 1\'b0;\n\ + resetn_sync <= 1\'b0;\n\ + end\n\ + else begin\n\ + resetn_sync_d <= resetn;\n\ + resetn_sync <= resetn_sync_d;\n\ + end\n\ + end\n\ +\n'); + +# for now, only global reset is supported, to demonstrate usage + regsFile.write('\n\ + //global registers, sampling\n\ + always @(posedge clk) resetn_soft <= #1 cpu_resetn_soft;\n'); + + +#end of sync_reset + +################################################################## +# a function that writes the logic behind the registers access +################################################################## +def write_logic(regsFile,regsDict): +# boolean first_item; + + +# axi protocol generation + + regsFile.write('\n\ + // Implement axi_awready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // slave is ready to accept write address when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_awready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_awaddr latching\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awaddr <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // Write Address latching\n\ + axi_awaddr <= S_AXI_AWADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_wready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)\n\ + begin\n\ + // slave is ready to accept write data when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_wready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement write response logic generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_bvalid <= 0;\n\ + axi_bresp <= 2\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)\n\ + begin\n\ + // indicates a valid write response is available\n\ + axi_bvalid <= 1\'b1;\n\ + axi_bresp <= 2\'b0; // OKAY response\n\ + end // work error responses in future\n\ + else\n\ + begin\n\ + if (S_AXI_BREADY && axi_bvalid)\n\ + //check if bready is asserted while bvalid is high)\n\ + //(there is a possibility that bready is always asserted high)\n\ + begin\n\ + axi_bvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_arready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + axi_araddr <= 32\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_arready && S_AXI_ARVALID)\n\ + begin\n\ + // indicates that the slave has acceped the valid read address\n\ + // Read address latching\n\ + axi_arready <= 1\'b1;\n\ + axi_araddr <= S_AXI_ARADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + else\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n\ + // Implement axi_rvalid generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rvalid <= 0;\n\ + axi_rresp <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)\n\ + begin\n\ + // Valid read data is available at the read data bus\n\ + axi_rvalid <= 1\'b1;\n\ + axi_rresp <= 2\'b0; // OKAY response\n\ + end\n\ + else if (axi_rvalid && S_AXI_RREADY)\n\ + begin\n\ + // Read data is accepted by the master\n\ + axi_rvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n'); + + + regsFile.write('\ + // Implement memory mapped register select and write logic generation\n\ +\n\ + assign reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;\n\ +\n\ +//////////////////////////////////////////////////////////////\n\ +// write registers\n\ +//////////////////////////////////////////////////////////////\n\ +\n'); + +#Handle write only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="WO" : + if first_item: + regsFile.write('\n\ +//Write only register, not cleared\n\ + //static\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + first_item=False; + + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin //write event\n\ + case (axi_awaddr)\n'); + + + for entry in regsDict: + if entry['type']=="WO" : + if entry['endian']=="little" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n'); + + +#Handle write only event registers + + first_item=True; + + for entry in regsDict: + if entry['type']=="WOE" : + if first_item: + first_item= False; + regsFile.write('\n\ +//Write only register, clear on write (i.e. event)\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + +#Handle Read/write registers, not cleared + + first_item=True; + + for entry in regsDict: + if first_item and (entry['type']=="RWS" or entry['type']=="RWA"): + first_item = False; + regsFile.write('\n\ +//R/W register, not cleared\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg_internal <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren) //write event\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not (first_item): + regsFile.write('\ + default: begin\n\ + end\n\ +\n\ + endcase\n\ + end\n'); + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write(' '+entry['name']+'_reg_update <= reg_wren && (axi_awaddr == `REG_'+entry['name'].upper()+'_ADDR);\n'); + + if not (first_item): + regsFile.write(' end\n'); + +#Handle Read/write registers, clear on read + + first_item=True; + + for entry in regsDict: + if entry['type']=="RWCR" : + if first_item: + first_item = False; + regsFile.write('\n\ +//R/W register, clear on read\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not (first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren)\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n\ +\n\ +\n\ +//clear assertions\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 reg_rden && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\n\ + end\n\ + end\n'); + + + +#Handle Read/write registers, clear on write + + first_item= True; + + for entry in regsDict: + if entry['type']=="RWCW" : + first_item = False; + regsFile.write('\n\ +//R/W register, clear on write, dynamic\n\ +// i.e. on write - write, next clock - write default value\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear_d <= #1 1\'b0;\n\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= cpu2ip_'+entry['name']+'_reg_clear_d;\n\ + cpu2ip_'+entry['name']+'_reg_clear_d <= reg_wren && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + if (reg_wren) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + if entry['endian']=="little" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index+1 )\n\ + if ( S_AXI_WSTRB[byte_index] == 1 ) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + regsFile.write('\ +\n\ +\n\ +\n\ +/////////////////////////\n\ +//// end of write\n\ +/////////////////////////\n'); + + regsFile.write('\n\ + // Implement memory mapped register select and read logic generation\n\ + // Slave register read enable is asserted when valid address is available\n\ + // and the slave is ready to accept the read address.\n\ +\n\ + // reg_rden control logic\n\ + // temperary no extra logic here\n\ + assign reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;\n'); + +#return read data + regsFile.write('\n\ + always @(*)\n\ + begin\n\ +\n\ + case ( axi_araddr /*S_AXI_ARADDR ^ C_BASE_ADDRESS*/)\n'); + + for entry in regsDict: + if entry['type']=="RO" or entry['type']=="ROC" or entry['type']=="RWS" or entry['type']=="RWI" or entry['type']=="RWSI" or entry['type']=="ROI": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = '+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = '+entry['name']+'_reg [(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width'])<32: + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + if entry['type']=="RWCW" or entry['type']=="RWA" or entry['type']=="RWCR": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = ip2cpu_'+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = ip2cpu_'+entry['name']+'_reg[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width']) < 32 : + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + regsFile.write('\ + //Default return value\n\ + default: begin\n\ + reg_data_out [31:0] = 32\'hDEADBEEF;\n\ + end\n\ +\n\ + endcase\n\ +\n\ + end//end of assigning data to IP2Bus_Data bus\n'); + +#Handle read only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="ROC" : + if first_item: + first_item=False; + regsFile.write('\n\ + //Read only registers, not cleared\n\ + //Nothing to do here....\n\ +\n\ +//Read only registers, cleared on read (e.g. counters)\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 1\'b0;\n\ + '+entry['name']+'_reg_clear_d <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 '+entry['name']+'_reg_clear_d;\n\ + '+entry['name']+'_reg_clear_d <= #1(reg_rden && (axi_araddr==`REG_'+entry['name'].upper()+'_ADDR)) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\n'); + + regsFile.write('\n\ +// Output register or memory read data\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rdata <= 0;\n\ + end\n\ + else\n\ + begin\n\ + // When there is a valid read address (S_AXI_ARVALID) with\n\ + // acceptance of read address by the slave (axi_arready),\n\ + // output the read dada\n\ + if (reg_rden)\n\ + begin\n\ + axi_rdata <= reg_data_out/*ip2bus_data*/; // register read data /* some new changes here */\n\ + end\n\ + end\n\ + end\n'); + +# end of write_logic + +################################################################## +# a function that writes the logic behind the indirect registers access +################################################################## +def write_indirect(regsFile,memsDict): + regsFile.write('\n\ + //////////////////////////////////\n\ + // Implement Indirect Access\n\ + //////////////////////////////////\n\ + \n'); + + regsFile.write('\n\ + //--------------------- Internal Parameters-------------------------\n\ + localparam NUM_INDIRECT_STATES = 6;\n\ + localparam IDLE_INDIRECT_STATE = 1;\n\ + localparam WRITE_INDIRECT_STATE = 2;\n\ + localparam WRITE_WAIT_INDIRECT_STATE = 4;\n\ + localparam READ_INDIRECT_STATE = 8;\n\ + localparam READ_WAIT_INDIRECT_STATE = 16;\n\ + localparam INDIRECT_DONE_STATE = 32;\n\ + localparam INDIRECT_WRITE = 0;\n\ + localparam INDIRECT_READ = 1;\n\ + localparam INDIRECT_WRITE_TA = 1;\n\ + localparam INDIRECT_WRITE_WS = 0;\n\ + //------------------------------------------------------------------\n\ + \n\ + reg [NUM_INDIRECT_STATES-1:0] indirect_state, indirect_state_next, indirect_state_last;\n\ + wire indirect_trigger;\n\ + wire indirect_type;\n\ + reg indirect_status, indirect_status_next;\n\ + wire [3:0] indirect_address_increment;\n\ + wire indirect_write_type;\n\ + wire [10:0] indirect_timeout;\n\ + wire [15:0] indirect_repeat_count;\n\ + reg [15:0] indirect_remaining,indirect_remaining_next;\n\ + reg [10:0] indirect_timeout_count, indirect_timeout_count_next;\n\ + reg indirect_reply_valid;\n\ + reg [31:0] indirect_address,indirect_address_next;\n\ + reg [3:0] indirect_memory_select,indirect_memory_select_next;\n\ + wire indirect_command_done;\n\ + \n\ + assign indirect_trigger = indirectcommand_reg[0];\n\ + assign indirect_type = indirectcommand_reg[4];\n\ + assign indirect_address_increment = indirectconfig_reg[3:0];\n\ + assign indirect_write_type = indirectconfig_reg[4];\n\ + assign indirect_timeout = indirectconfig_reg[15:5];\n\ + assign indirect_repeat_count = indirectconfig_reg[31:16];\n\ + \n\ + always @(*) begin\n\ + indirect_state_next = indirect_state;\n\ + indirect_status_next = indirect_status;\n\ + indirect_remaining_next = indirect_remaining;\n\ + indirect_timeout_count_next = indirect_timeout_count;\n\ + indirect_address_next = indirect_address;\n\ + indirect_memory_select_next = indirect_memory_select;\n\ + case(indirect_state)\n\ + IDLE_INDIRECT_STATE: begin\n\ + if(indirect_trigger) begin\n\ + indirect_state_next= (indirect_type == INDIRECT_WRITE) ? WRITE_INDIRECT_STATE : READ_INDIRECT_STATE;\n\ + indirect_remaining_next = (indirect_repeat_count == 0) ? 16\'h1 : indirect_repeat_count;\n\ + indirect_timeout_count_next = indirect_timeout;\n\ + indirect_address_next = indirectaddress_reg; //This is the address in the user register\n\ + indirect_memory_select_next = indirectaddress_reg[31:28];\n\ + end\n\ + end\n\ + \n\ + READ_INDIRECT_STATE: begin\n\ + indirect_state_next = READ_WAIT_INDIRECT_STATE;\n\ + end\n\ + READ_WAIT_INDIRECT_STATE: begin\n\ + if (indirect_reply_valid) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next =0;\n\ + end\n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count-1;\n\ + end\n\ + WRITE_INDIRECT_STATE: begin\n\ + indirect_state_next = WRITE_WAIT_INDIRECT_STATE;\n\ + end\n\ + WRITE_WAIT_INDIRECT_STATE: begin\n\ + if (((indirect_write_type == INDIRECT_WRITE_TA) && (indirect_reply_valid)) || ((indirect_write_type == INDIRECT_WRITE_WS) && (indirect_timeout_count==0))) begin\n\ + indirect_remaining_next = indirect_remaining - 1;\n\ + indirect_address_next = indirect_address+indirect_address_increment;\n\ + if (indirect_remaining==1) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + end\n\ + end\n\ + else \n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count==0 ? 0 : indirect_timeout_count-1;\n\ + end\n\ + INDIRECT_DONE_STATE: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + default: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + endcase // case(state)\n\ + end // always @ (*)\n\ + \n\ + assign indirect_command_done = (indirect_state==INDIRECT_DONE_STATE);\n\ + \n\ + always @(posedge clk) begin\n\ + if(~resetn_sync) begin\n\ + indirect_state <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_state_last <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_status <= #1 1\'b0;\n\ + indirect_remaining <= #1 0;\n\ + indirect_timeout_count <= #1 0;\n\ + indirect_address <= #1 0;\n\ + indirect_memory_select <= #1 0;\n\ + indirectcommand_reg <= #1 `REG_INDIRECTCOMMAND_DEFAULT;\n\ + end\n\ + else begin\n\ + indirect_state <= #1 indirect_state_next;\n\ + indirect_state_last <= #1 indirect_state;\n\ + indirect_status <= #1 indirect_status_next;\n\ + indirect_remaining <= #1 indirect_remaining_next;\n\ + indirect_timeout_count <= #1 indirect_timeout_count_next;\n\ + indirect_address <= #1 indirect_address_next;\n\ + indirect_memory_select <= #1 indirect_memory_select_next;\n\ + indirectcommand_reg <= #1 indirect_command_done ? {indirect_status,indirectcommand_reg[7:4],4\'h0} : \n\ + indirectcommand_reg_update ? indirectcommand_reg_internal: \n\ + indirectcommand_reg;\n\ + end\n\ + end \n\ + \n'); + + + for entry in memsDict: + regsFile.write('\n\ + \n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + '+entry['name']+'_addr <= #1 0;\n\ + '+entry['name']+'_data <= #1 0;\n\ + '+entry['name']+'_rd_wrn<= #1 0;\n\ + '+entry['name']+'_cmd_valid <= #1 0;\n\ + end \n\ + else begin\n\ + '+entry['name']+'_addr <= #1 indirect_address;\n\ + '+entry['name']+'_data <= #1 indirectwrdata_reg;\n\ + '+entry['name']+'_rd_wrn<= #1 indirect_type;\n\ + '+entry['name']+'_cmd_valid <= #1 ('+entry['address']+'==(indirect_memory_select<<28)) && ((indirect_state == WRITE_INDIRECT_STATE) || (indirect_state == READ_INDIRECT_STATE));\n\ + end \n\ + end\n'); + + regsFile.write('\n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + indirectreply_reg <= #1 0;\n\ + indirect_reply_valid <= #1 0; \n\ + end \n\ + else begin \n\ + indirectreply_reg <= #1 ' ); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply :'); + regsFile.write(' 0;\n\ + indirect_reply_valid <= #1 '); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply_valid :'); + regsFile.write(' 0;\n\ + end \n\ + end\n\ + \n'); +# end of write_indirect + +################################################################## +#write all the defines to the defs module +################################################################## +def write_defines(defsFile,regsDict, memsDict): + + for entry in regsDict: + defsFile.write( '\n`define REG_'+entry['name'].upper()+'_BITS\t\t\t\t'+entry['bits']+ + '\n`define REG_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define REG_'+entry['name'].upper()+'_DEFAULT\t\t\t\t'+entry['default']+ + '\n`define REG_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['addr']+'\n'); + + for entry in memsDict: + defsFile.write( '\n`define MEM_'+entry['name'].upper()+'_DATA_BITS\t\t\t\t'+entry['data_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR_BITS\t\t\t\t'+entry['addr_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define MEM_'+entry['name'].upper()+'_DEPTH\t\t\t\t'+str(2**(int(entry['addr_bits'].split(':')[0])+1))+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['address']+'\n'); + +#end of write_defines + + +################################################################## +#write all the register offsets to the h template (to be included) +################################################################## +def write_h(hFile,regsDict,memsDict): + + hFile.write('##########This text should be copied to the head file #############\n\ + #Registers offset definitions\n\n'); + + for entry in regsDict: + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + +#end of write_h + +################################################################## +#write all the register offsets to the tcl file +################################################################## +def write_tcl(tclFile,regsDict,memsDict): + + for entry in regsDict: + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + + +#end of write_tcl + +################################################################## +#write all the register offsets to table +################################################################## + +def write_tb(tbFile,regsDict,memsDict): + for entry in regsDict: + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' OFFSET 0x'+entry['addr'][4:]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); +#end of write_tb + +################################################################## +#write top module's template (i.e. include this in your module) +################################################################## +def write_module_template(moduleFile,regsDict,memsDict): + +#first write static inclusions.... + moduleFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\n\ +//parameters to be added to the top module parameters\n\ +#(\n\ + // AXI Registers Data Width\n\ + parameter C_S_AXI_DATA_WIDTH = 32,\n\ + parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +//ports to be added to the top module ports\n\ +(\n\ +// Signals for AXI_IP and IF_REG (Added for debug purposes)\n\ + // Slave AXI Ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +)\n\n'); + + first_item = True; + for entry in regsDict: + if first_item and (entry['endian']=="big") : + first_item = False; + moduleFile.write('\n\ + // define and assign default little endian\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + wire reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + +#then add design specific wires/regs: + + moduleFile.write('\n\ + // define registers\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="ROC" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + moduleFile.write(' wire '+entry['name']+'_reg_clear;\n') + if entry['type']=="RWS" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WO" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WOE" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="RWA" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + if entry['type']=="RWCR" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + if entry['type']=="RWCW" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in memsDict: + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr;\n') + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data;\n') + moduleFile.write(' wire '+entry['name']+'_rd_wrn;\n') + moduleFile.write(' wire '+entry['name']+'_cmd_valid;\n') + moduleFile.write(' reg [`MEM_'+(entry['name']).upper()+'DATA_BITS] '+entry['name']+'_reply;\n') + moduleFile.write(' reg '+entry['name']+'_reply_valid;\n') + + +#instantiate registers module + moduleFile.write('\n//Registers section\n\ + '+module_name+'_cpu_regs\n\ + #(\n\ + .C_BASE_ADDRESS (C_BASEADDR ),\n\ + .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH),\n\ + .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH)\n\ + ) '+module_name+'_cpu_regs_inst\n\ + (\n\ + // General ports\n\ + .clk (axis_aclk),\n\ + .resetn (axis_resetn),\n\ + // AXI Lite ports\n\ + .S_AXI_ACLK (S_AXI_ACLK),\n\ + .S_AXI_ARESETN (S_AXI_ARESETN),\n\ + .S_AXI_AWADDR (S_AXI_AWADDR),\n\ + .S_AXI_AWVALID (S_AXI_AWVALID),\n\ + .S_AXI_WDATA (S_AXI_WDATA),\n\ + .S_AXI_WSTRB (S_AXI_WSTRB),\n\ + .S_AXI_WVALID (S_AXI_WVALID),\n\ + .S_AXI_BREADY (S_AXI_BREADY),\n\ + .S_AXI_ARADDR (S_AXI_ARADDR),\n\ + .S_AXI_ARVALID (S_AXI_ARVALID),\n\ + .S_AXI_RREADY (S_AXI_RREADY),\n\ + .S_AXI_ARREADY (S_AXI_ARREADY),\n\ + .S_AXI_RDATA (S_AXI_RDATA),\n\ + .S_AXI_RRESP (S_AXI_RRESP),\n\ + .S_AXI_RVALID (S_AXI_RVALID),\n\ + .S_AXI_WREADY (S_AXI_WREADY),\n\ + .S_AXI_BRESP (S_AXI_BRESP),\n\ + .S_AXI_BVALID (S_AXI_BVALID),\n\ + .S_AXI_AWREADY (S_AXI_AWREADY),\n\ +\n\ + // Register ports\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="ROC" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + moduleFile.write(' .'+entry['name']+'_reg_clear ('+entry['name']+'_reg_clear),\n') + if entry['type']=="RWS" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WOE" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="RWA" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + if entry['type']=="RWCR" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + if entry['type']=="RWCW" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + + for entry in memsDict: + moduleFile.write(' .'+entry['name']+'_addr ('+entry['name']+'_addr),\n') + moduleFile.write(' .'+entry['name']+'_data ('+entry['name']+'_data),\n') + moduleFile.write(' .'+entry['name']+'_rd_wrn ('+entry['name']+'_rd_wrn),\n') + moduleFile.write(' .'+entry['name']+'_cmd_valid ('+entry['name']+'_cmd_valid ),\n') + moduleFile.write(' .'+entry['name']+'_reply ('+entry['name']+'_reply),\n') + moduleFile.write(' .'+entry['name']+'_reply_valid ('+entry['name']+'_reply_valid),\n') + + + moduleFile.write(' // Global Registers - user can select if to use\n\ + .cpu_resetn_soft(),//software reset, after cpu module\n\ + .resetn_soft (),//software reset to cpu module (from central reset management)\n\ + .resetn_sync (resetn_sync)//synchronized reset, use for better timing\n\ +);\n\ +//registers logic, current logic is just a placeholder for initial compil, required to be changed by the user\n'); + +#registers logic + + moduleFile.write('always @(posedge axis_aclk)\n\ + if (~resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 \'h0\n;') + + moduleFile.write(' end\n\ + else begin\n') + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWA" : + moduleFile.write(' ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;\n') + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear_d == 1\'b1) \n\ + ip2cpu_'+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 cpu_'+entry['name']+'_reg_clear;\n') + + moduleFile.write('\ + end\n\n') + + + +#end of write_module_template + + +######################################################################################## +# +# Main function body +# +######################################################################################## + + +# List of files to be generated. +filename_regs=''+module_name+'_cpu_regs.v' +filename_defs=''+module_name+'_cpu_regs_defines.v' +filename_template=''+module_name+'_cpu_template.v' +filename_h=''+module_name+'_regs_defines.h' +filename_tcl=''+module_name+'_regs_defines.tcl' +filename_tb=''+module_name+'_regs_defines.txt' + + +# Open the files for writing +regsFile = open(filename_regs, 'w') +defsFile = open(filename_defs, 'w') +moduleFile = open(filename_template, 'w') +hFile = open(filename_h, 'w') +tclFile = open(filename_tcl, 'w') +tbFile = open(filename_tb, 'w') + +# Write the header of each file +write_regs_header(regsFile) +write_defs_header(defsFile) +write_tcl_header(tclFile) +write_hFile_header(hFile) +write_tbFile_header(tbFile) + +#Write the regs module +#first the ports... +regsDict=create_regs_list() +memsDict=create_mems_list() +write_regs_ports(regsFile,regsDict, memsDict) + + +#then the wires... +write_regs_wires(regsFile,regsDict, memsDict) + +#resets etc..... +sync_reset(regsFile) + + +#registers logic... +write_logic(regsFile,regsDict) + +#indirect access... +if memsDict: + write_indirect(regsFile,memsDict) + +#tables... + +#close module..... +regsFile.write('endmodule\n') + +#write the defs module +write_defines(defsFile,regsDict, memsDict) + +#write the tcl module +write_tcl(tclFile,regsDict, memsDict) + +#write the default text to be copied to the h module +write_h(hFile,regsDict, memsDict) + +#write the default text to table file +write_tb(tbFile,regsDict, memsDict) + +#writes the default text to be copied to the top module +write_module_template(moduleFile,regsDict, memsDict) + + +# Close the output files +regsFile.close() +defsFile.close() +tclFile.close() +moduleFile.close() +hFile.close() +tbFile.close() diff --git "a/hw/lib/std/nf_data_sink_v1_0_0/data\\regs_gen.py" "b/hw/lib/std/nf_data_sink_v1_0_0/data\\regs_gen.py" new file mode 100644 index 0000000..e69de29 diff --git a/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v b/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v new file mode 100644 index 0000000..66d0178 --- /dev/null +++ b/hw/lib/std/nf_data_sink_v1_0_0/hdl/nf_data_sink.v @@ -0,0 +1,451 @@ +//- +// Copyright (C) 2010, 2011 The Board of Trustees of The Leland Stanford +// Junior University +// Copyright (C) 2010, 2011 Adam Covington +// Copyright (C) 2015 Noa Zilberman +// Copyright (C) 2021 Yuta Tokusashi +// Copyright (C) 2024 Gregory Watson +// +// All rights reserved. +// +// This software was developed by +// Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme, +// and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +// EP/P025374/1 alongside support from Xilinx Inc. +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// +/******************************************************************************* + * File: + * nf_data_sink.v + * + * Library: + * hw/std/cores/nf_data_sink + * + * Module: + * nf_data_sink + * + * Author: + * Greg Watson + * + * Description: + * Accepts incoming data and discards it. + * Provides statistics on input data rate. + * + */ + +`timescale 1ns/1ns +`include "nf_data_sink_cpu_regs_defines.v" + +module nf_data_sink +#( + // Master AXI Stream Data Width + parameter C_M_AXIS_DATA_WIDTH=1024, + parameter C_S_AXIS_DATA_WIDTH=1024, + parameter C_M_AXIS_TUSER_WIDTH=128, + parameter C_S_AXIS_TUSER_WIDTH=128, + parameter NUM_QUEUES=1, + + // AXI Registers Data Width + parameter C_S_AXI_DATA_WIDTH = 32, + parameter C_S_AXI_ADDR_WIDTH = 12, + parameter C_BASEADDR = 32'h00000000 + +) +( + // Part 1: System side signals + // Global Ports + input axis_aclk, + input axis_resetn, + + // --- Master Stream Ports (interface to data path) + // --- n.c. until we code DMA tx logic + // output [C_M_AXIS_DATA_WIDTH - 1:0] m_axis_tdata, + // output [((C_M_AXIS_DATA_WIDTH / 8)) - 1:0] m_axis_tkeep, + // output [C_M_AXIS_TUSER_WIDTH-1:0] m_axis_tuser, + // output m_axis_tvalid, + // input m_axis_tready, + // output m_axis_tlast, + + + // DMA data from Host + input [C_S_AXIS_DATA_WIDTH - 1:0] s_axis_2_tdata, + input [((C_S_AXIS_DATA_WIDTH / 8)) - 1:0] s_axis_2_tkeep, + input [C_S_AXIS_TUSER_WIDTH-1:0] s_axis_2_tuser, + input s_axis_2_tvalid, + output s_axis_2_tready, + input s_axis_2_tlast, + + // Slave AXI Ports + input S_AXI_ACLK, + input S_AXI_ARESETN, + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, + input S_AXI_AWVALID, + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB, + input S_AXI_WVALID, + input S_AXI_BREADY, + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, + input S_AXI_ARVALID, + input S_AXI_RREADY, + output S_AXI_ARREADY, + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, + output [1 : 0] S_AXI_RRESP, + output S_AXI_RVALID, + output S_AXI_WREADY, + output [1 :0] S_AXI_BRESP, + output S_AXI_BVALID, + output S_AXI_AWREADY + +); + + + function integer log2; + input integer number; + begin + log2=0; + while(2**log2 rx_queue 64b@axis_clk + .m_axis_mac_tdata (p_axis_dma_i_tdata), + .m_axis_mac_tkeep (p_axis_dma_i_tkeep), + .m_axis_mac_tvalid (p_axis_dma_i_tvalid), + .m_axis_mac_tuser_err (1'b1), // valid frame + .m_axis_mac_tuser (p_axis_dma_i_tuser), + .m_axis_mac_tlast (p_axis_dma_i_tlast), + // tx_queue 64b@axis_clk -> mac 64b@clk156 + .s_axis_mac_tdata (p_axis_dma_o_tdata), + .s_axis_mac_tkeep (p_axis_dma_o_tkeep), + .s_axis_mac_tvalid (p_axis_dma_o_tvalid), + .s_axis_mac_tuser_err (), //underrun + .s_axis_mac_tuser (p_axis_dma_o_tuser), + .s_axis_mac_tlast (p_axis_dma_o_tlast), + .s_axis_mac_tready (p_axis_dma_o_tready), + + // TX/RX DATA channels + .interface_number (8'd0), + + // NFPLUS pipeline clk & rst + .axis_aclk (clk_200), + .axis_aresetn (sys_rst_n_c), + // input from ref pipeline 256b -> MAC + .s_axis_pipe_tdata (axis_dma_o_tdata), + .s_axis_pipe_tkeep (axis_dma_o_tkeep), + .s_axis_pipe_tlast (axis_dma_o_tlast), + .s_axis_pipe_tuser (axis_dma_o_tuser), + .s_axis_pipe_tvalid (axis_dma_o_tvalid), + .s_axis_pipe_tready (axis_dma_o_tready), + // output to ref pipeline 256b -> DMA + .m_axis_pipe_tdata (axis_dma_i_tdata), + .m_axis_pipe_tkeep (axis_dma_i_tkeep), + .m_axis_pipe_tlast (axis_dma_i_tlast), + .m_axis_pipe_tuser (axis_dma_i_tuser), + .m_axis_pipe_tvalid (axis_dma_i_tvalid), + .m_axis_pipe_tready (axis_dma_i_tready) + ); + + nf_mac_attachment_ip u_nf_attachment_0 ( + // 10GE block clk & rst + .clk156 (clk_200), + .areset_clk156 (!sys_rst_n_c), + // RX MAC 64b@clk156 (no backpressure) -> rx_queue 64b@axis_clk + .m_axis_mac_tdata (p_axis_i_0_tdata), + .m_axis_mac_tkeep (p_axis_i_0_tkeep), + .m_axis_mac_tvalid (p_axis_i_0_tvalid), + .m_axis_mac_tuser_err (1'b1), // valid frame + .m_axis_mac_tuser (p_axis_i_0_tuser), + .m_axis_mac_tlast (p_axis_i_0_tlast), + // tx_queue 64b@axis_clk -> mac 64b@clk156 + .s_axis_mac_tdata (p_axis_o_0_tdata), + .s_axis_mac_tkeep (p_axis_o_0_tkeep), + .s_axis_mac_tvalid (p_axis_o_0_tvalid), + .s_axis_mac_tuser_err (), //underrun + .s_axis_mac_tuser (p_axis_o_0_tuser), + .s_axis_mac_tlast (p_axis_o_0_tlast), + .s_axis_mac_tready (p_axis_o_0_tready), + + // TX/RX DATA channels + .interface_number (8'b0000_0001), + + // NFPLUS pipeline clk & rst + .axis_aclk (clk_200), + .axis_aresetn (sys_rst_n_c), + // input from ref pipeline 256b -> MAC + .s_axis_pipe_tdata (axis_o_0_tdata), + .s_axis_pipe_tkeep (axis_o_0_tkeep), + .s_axis_pipe_tlast (axis_o_0_tlast), + .s_axis_pipe_tuser (axis_o_0_tuser), + .s_axis_pipe_tvalid (axis_o_0_tvalid), + .s_axis_pipe_tready (axis_o_0_tready), + // output to ref pipeline 256b -> DMA + .m_axis_pipe_tdata (axis_i_0_tdata), + .m_axis_pipe_tkeep (axis_i_0_tkeep), + .m_axis_pipe_tlast (axis_i_0_tlast), + .m_axis_pipe_tuser (axis_i_0_tuser), + .m_axis_pipe_tvalid (axis_i_0_tvalid), + .m_axis_pipe_tready (axis_i_0_tready) + ); + + nf_mac_attachment_ip u_nf_attachment_1 ( + // 10GE block clk & rst + .clk156 (clk_200), + .areset_clk156 (!sys_rst_n_c), + // RX MAC 64b@clk156 (no backpressure) -> rx_queue 64b@axis_clk + .m_axis_mac_tdata (p_axis_i_1_tdata), + .m_axis_mac_tkeep (p_axis_i_1_tkeep), + .m_axis_mac_tvalid (p_axis_i_1_tvalid), + .m_axis_mac_tuser_err (1'b1), // valid frame + .m_axis_mac_tuser (p_axis_i_1_tuser), + .m_axis_mac_tlast (p_axis_i_1_tlast), + // tx_queue 64b@axis_clk -> mac 64b@clk156 + .s_axis_mac_tdata (p_axis_o_1_tdata), + .s_axis_mac_tkeep (p_axis_o_1_tkeep), + .s_axis_mac_tvalid (p_axis_o_1_tvalid), + .s_axis_mac_tuser_err (p_axis_o_1_tuser), //underrun + .s_axis_mac_tuser (p_axis_o_1_tuser), + .s_axis_mac_tlast (p_axis_o_1_tlast), + .s_axis_mac_tready (p_axis_o_1_tready), + + // TX/RX DATA channels + .interface_number (8'b0000_0100), + + // NFPLUS pipeline clk & rst + .axis_aclk (clk_200), + .axis_aresetn (sys_rst_n_c), + // input from ref pipeline 256b -> MAC + .s_axis_pipe_tdata (axis_o_1_tdata), + .s_axis_pipe_tkeep (axis_o_1_tkeep), + .s_axis_pipe_tlast (axis_o_1_tlast), + .s_axis_pipe_tuser (axis_o_1_tuser), + .s_axis_pipe_tvalid (axis_o_1_tvalid), + .s_axis_pipe_tready (axis_o_1_tready), + // output to ref pipeline 256b -> DMA + .m_axis_pipe_tdata (axis_i_1_tdata), + .m_axis_pipe_tkeep (axis_i_1_tkeep), + .m_axis_pipe_tlast (axis_i_1_tlast), + .m_axis_pipe_tuser (axis_i_1_tuser), + .m_axis_pipe_tvalid (axis_i_1_tvalid), + .m_axis_pipe_tready (axis_i_1_tready) + ); + + axi_crossbar_0 u_interconnect( + .aclk (axi_clk), + .aresetn (axi_aresetn), + .s_axi_awaddr (S00_AXI_awaddr), + .s_axi_awprot (3'b010), + .s_axi_awvalid (S00_AXI_awvalid), + .s_axi_awready (S00_AXI_awready), + .s_axi_wdata (S00_AXI_wdata ), + .s_axi_wstrb (4'hf), + .s_axi_wvalid (S00_AXI_wvalid ), + .s_axi_wready (S00_AXI_wready ), + .s_axi_bresp (S00_AXI_bresp ), + .s_axi_bvalid (S00_AXI_bvalid ), + .s_axi_bready (S00_AXI_bready ), + .s_axi_araddr (S00_AXI_araddr[31:0]), + .s_axi_arprot (3'b010), + .s_axi_arvalid (S00_AXI_arvalid ), + .s_axi_arready (S00_AXI_arready ), + .s_axi_rdata (S00_AXI_rdata ), + .s_axi_rresp (S00_AXI_rresp ), + .s_axi_rvalid (S00_AXI_rvalid ), + .s_axi_rready (S00_AXI_rready ), + .m_axi_awaddr ({M2_AXI_awaddr[31:0] ,M1_AXI_awaddr[31:0] ,M0_AXI_awaddr[31:0] }), + .m_axi_awprot (), + .m_axi_awvalid ({M2_AXI_awvalid,M1_AXI_awvalid,M0_AXI_awvalid}), + .m_axi_awready ({M2_AXI_awready,M1_AXI_awready,M0_AXI_awready}), + .m_axi_wdata ({M2_AXI_wdata ,M1_AXI_wdata ,M0_AXI_wdata }), + .m_axi_wstrb ({M2_AXI_wstrb ,M1_AXI_wstrb ,M0_AXI_wstrb }), + .m_axi_wvalid ({M2_AXI_wvalid ,M1_AXI_wvalid ,M0_AXI_wvalid }), + .m_axi_wready ({M2_AXI_wready ,M1_AXI_wready ,M0_AXI_wready }), + .m_axi_bresp ({M2_AXI_bresp ,M1_AXI_bresp ,M0_AXI_bresp }), + .m_axi_bvalid ({M2_AXI_bvalid ,M1_AXI_bvalid ,M0_AXI_bvalid }), + .m_axi_bready ({M2_AXI_bready ,M1_AXI_bready ,M0_AXI_bready }), + .m_axi_araddr ({M2_AXI_araddr ,M1_AXI_araddr ,M0_AXI_araddr }), + .m_axi_arprot (), + .m_axi_arvalid ({M2_AXI_arvalid,M1_AXI_arvalid,M0_AXI_arvalid}), + .m_axi_arready ({M2_AXI_arready,M1_AXI_arready,M0_AXI_arready}), + .m_axi_rdata ({M2_AXI_rdata ,M1_AXI_rdata ,M0_AXI_rdata }), + .m_axi_rresp ({M2_AXI_rresp ,M1_AXI_rresp ,M0_AXI_rresp }), + .m_axi_rvalid ({M2_AXI_rvalid ,M1_AXI_rvalid ,M0_AXI_rvalid }), + .m_axi_rready ({M2_AXI_rready ,M1_AXI_rready ,M0_AXI_rready }) + ); + + + axi_sim_transactor_ip axi_sim_transactor_i ( + .axi_aclk (axi_clk), + .axi_resetn (axi_aresetn), + //AXI Write address channel + .M_AXI_AWADDR (S00_AXI_awaddr), + .M_AXI_AWVALID (S00_AXI_awvalid), + .M_AXI_AWREADY (S00_AXI_awready), + // AXI Write data channel + .M_AXI_WDATA (S00_AXI_wdata), + .M_AXI_WSTRB (S00_AXI_wstrb), + .M_AXI_WVALID (S00_AXI_wvalid), + .M_AXI_WREADY (S00_AXI_wready), + //AXI Write response channel + .M_AXI_BRESP (S00_AXI_bresp), + .M_AXI_BVALID (S00_AXI_bvalid), + .M_AXI_BREADY (S00_AXI_bready), + //AXI Read address channel + .M_AXI_ARADDR (S00_AXI_araddr), + .M_AXI_ARVALID (S00_AXI_arvalid), + .M_AXI_ARREADY (S00_AXI_arready), + //AXI Read data & response channel + .M_AXI_RDATA (S00_AXI_rdata), + .M_AXI_RRESP (S00_AXI_rresp), + .M_AXI_RVALID (S00_AXI_rvalid), + .M_AXI_RREADY (S00_AXI_rready), + + .activity_trans_sim (activity_trans_sim), + .activity_trans_log (activity_trans_log), + .barrier_req_trans (barrier_req_trans), + .barrier_proceed (barrier_proceed) + ); + + barrier_ip #(.NUM_PORTS(5)) barrier_i ( + .activity_stim ({activity_stim4, activity_stim3, activity_stim2, activity_stim1, activity_stim0}), + .activity_rec ({activity_rec4, activity_rec3, activity_rec2, activity_rec1, activity_rec0}), + .activity_trans_sim (activity_trans_sim), + .activity_trans_log (activity_trans_log), + .barrier_req ({barrier_req4, barrier_req3, barrier_req2, barrier_req1, barrier_req0}), + .barrier_req_trans (barrier_req_trans), + .barrier_proceed (barrier_proceed) + ); + +endmodule + diff --git a/hw/projects/reference_dma/hw/hdl/top_tb.v b/hw/projects/reference_dma/hw/hdl/top_tb.v new file mode 100644 index 0000000..c748b6c --- /dev/null +++ b/hw/projects/reference_dma/hw/hdl/top_tb.v @@ -0,0 +1,182 @@ +//- +// Copyright (c) 2015 Noa Zilberman +// All rights reserved. +// +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme. +// +// File: +// top_tb.v +// +// Module: +// top +// +// Author: Noa Zilberman +// +// Description: +// reference nic top module +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + +`timescale 1ns / 100ps + + module top_tb # ( + parameter PL_SIM_FAST_LINK_TRAINING = "TRUE", // Simulation Speedup + parameter C_DATA_WIDTH = 512, // RX/TX interface data width + parameter KEEP_WIDTH = C_DATA_WIDTH / 32, + parameter C_NF_DATA_WIDTH = 1024, // RX/TX interface data width + parameter integer USER_CLK2_FREQ = 4, + parameter REF_CLK_FREQ = 0, // 0 - 100 MHz, 1 - 125 MHz, 2 - 250 MHz + parameter AXISTEN_IF_RQ_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_CC_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_CQ_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_RC_ALIGNMENT_MODE = "FALSE", + parameter AXISTEN_IF_ENABLE_CLIENT_TAG = 0, + parameter AXISTEN_IF_RQ_PARITY_CHECK = 0, + parameter AXISTEN_IF_CC_PARITY_CHECK = 0, + parameter AXISTEN_IF_MC_RX_STRADDLE = 0, + parameter AXISTEN_IF_ENABLE_RX_MSG_INTFC = 0, + parameter [17:0] AXISTEN_IF_ENABLE_MSG_ROUTE = 18'h2FFFF +) ( + +); + + parameter PCIE_PERIOD = 4.0; + parameter XPHY_PERIOD = 6.4; + parameter real CORE_PERIOD = 2.941; + + localparam TCQ = 1; + localparam BAR0AXI = 32'h40000000; + localparam BAR1AXI = 32'h10000000; + localparam BAR2AXI = 32'h20000000; + localparam BAR3AXI = 32'h30000000; + localparam BAR4AXI = 32'h40000000; + localparam BAR5AXI = 32'h50000000; + localparam BAR0SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR1SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR2SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR3SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR4SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam BAR5SIZE = 64'hFFFF_FFFF_FFFF_FF80; + localparam throttle_percent = 50; + + reg sys_reset_n; + + reg sys_clk; + wire sys_clkp,sys_clkn; + reg xphy_clk; + wire xphy_refclk_p,xphy_refclk_n; + reg clk_ref; + wire clk_ref_p,clk_ref_n; + //----------------------------------------------------------------------------------------------------------------// + // axis interface // + //----------------------------------------------------------------------------------------------------------------// + + + + top_sim # ( + .PL_SIM_FAST_LINK_TRAINING (PL_SIM_FAST_LINK_TRAINING ), + .C_DATA_WIDTH (C_DATA_WIDTH ), + .KEEP_WIDTH (KEEP_WIDTH ), + .C_NF_DATA_WIDTH (C_NF_DATA_WIDTH ), + .USER_CLK2_FREQ (USER_CLK2_FREQ ), + .REF_CLK_FREQ (REF_CLK_FREQ ), + .AXISTEN_IF_RQ_ALIGNMENT_MODE (AXISTEN_IF_RQ_ALIGNMENT_MODE ), + .AXISTEN_IF_CC_ALIGNMENT_MODE (AXISTEN_IF_CC_ALIGNMENT_MODE ), + .AXISTEN_IF_CQ_ALIGNMENT_MODE (AXISTEN_IF_CQ_ALIGNMENT_MODE ), + .AXISTEN_IF_RC_ALIGNMENT_MODE (AXISTEN_IF_RC_ALIGNMENT_MODE ), + .AXISTEN_IF_ENABLE_CLIENT_TAG (AXISTEN_IF_ENABLE_CLIENT_TAG ), + .AXISTEN_IF_RQ_PARITY_CHECK (AXISTEN_IF_RQ_PARITY_CHECK ), + .AXISTEN_IF_CC_PARITY_CHECK (AXISTEN_IF_CC_PARITY_CHECK ), + .AXISTEN_IF_MC_RX_STRADDLE (AXISTEN_IF_MC_RX_STRADDLE ), + .AXISTEN_IF_ENABLE_RX_MSG_INTFC (AXISTEN_IF_ENABLE_RX_MSG_INTFC ), + .AXISTEN_IF_ENABLE_MSG_ROUTE (AXISTEN_IF_ENABLE_MSG_ROUTE ) + ) top_sim ( + + //PCI Express + .pcie_rxn(pcie_7x_mgt_rxn), + .pcie_rxp(pcie_7x_mgt_rxp), + .pcie_txn(pcie_7x_mgt_txn), + .pcie_txp(pcie_7x_mgt_txp), + //10G Interface + + .qsfp0_rxp(rxp), + .qsfp0_rxn(rxn), + .qsfp0_txp(txp), + .qsfp0_txn(txn), + + // PCIe Clock + .pci_clk_p(sys_clkp), + .pci_clk_n(sys_clkn), + + //200MHz Clock + .fpga_sysclk_p(clk_ref_p), + .fpga_sysclk_n(clk_ref_n), + + // 156.25 MHz clock in + .qsfp_refclk_p (xphy_refclk_p), + .qsfp_refclk_n (xphy_refclk_n), + + .sys_reset_n(sys_reset_n) + ); + +//Reset handling + // Important! polarity here is opposite the one in the actual design + initial begin + sys_reset_n = 1'b0; + #(CORE_PERIOD * 200); + sys_reset_n = 1'b1; + $display("Reset Deasserted"); + end + +//Clock generation + initial begin + sys_clk = 1'b0; + #(PCIE_PERIOD/2); + forever + #(PCIE_PERIOD/2) sys_clk = ~sys_clk; + end + + assign sys_clkp = sys_clk; + assign sys_clkn = ~sys_clk; + + + initial begin + xphy_clk = 1'b0; + #(XPHY_PERIOD/2); + forever + #(XPHY_PERIOD/2) xphy_clk = ~xphy_clk; + end + + assign xphy_refclk_p = xphy_clk; + assign xphy_refclk_n = ~xphy_clk; + + initial begin + clk_ref = 1'b0; + #(CORE_PERIOD/2); + forever + #(CORE_PERIOD/2) clk_ref = ~clk_ref; + end + + assign clk_ref_p = clk_ref; + assign clk_ref_n = ~clk_ref; + +endmodule diff --git a/hw/projects/reference_dma/hw/tcl/export_registers.tcl b/hw/projects/reference_dma/hw/tcl/export_registers.tcl new file mode 100644 index 0000000..cd2b343 --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/export_registers.tcl @@ -0,0 +1,159 @@ +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang +# Copyright (c) 2021 Yuta Tokusashi +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +# The following list include all the items that are mapped to memory segments +# The structure of each item is as follows { } + +set DEF_LIST { + {NF_DATA_SINK 0 1 nf_data_sink_v1_0_0/data/nf_data_sink_regs_defines.txt} \ +} + +set target_path $::env(NF_DESIGN_DIR)/test/ +set target_file $target_path/nf_register_defines.h + +if {[file exists ${target_path}] == 0} { + exec mkdir -p ${target_path} +} + +###################################################### +# the following function writes the license header +# into the file +###################################################### + +proc write_header { target_file } { + +# creat a blank header file +# do a fresh rewrite in case the file already exits +file delete -force $target_file +open $target_file "w" +set h_file [open $target_file "w"] +set script_path [ info script ] +set Time [clock seconds] +puts $h_file "//-" +puts $h_file "// Copyright (c) 2015,2021 University of Cambridge" +puts $h_file "// All rights reserved." +puts $h_file "//" +puts $h_file "// This software was developed by Stanford University and the University of Cambridge Computer Laboratory " +puts $h_file "// under National Science Foundation under Grant No. CNS-0855268," +puts $h_file "// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and" +puts $h_file "// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 (\"MRC2\"), " +puts $h_file "// as part of the DARPA MRC research programme," +puts $h_file "// and by the University of Cambridge Computer Laboratory under EPSRC EARL Project" +puts $h_file "// EP/P025374/1 alongside support from Xilinx Inc." +puts $h_file "//" +puts $h_file "// @NETFPGA_LICENSE_HEADER_START@" +puts $h_file "//" +puts $h_file "// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor" +puts $h_file "// license agreements. See the NOTICE file distributed with this work for" +puts $h_file "// additional information regarding copyright ownership. NetFPGA licenses this" +puts $h_file "// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the" +puts $h_file "// \"License\"); you may not use this file except in compliance with the" +puts $h_file "// License. You may obtain a copy of the License at:" +puts $h_file "//" +puts $h_file "// http://www.netfpga-cic.org" +puts $h_file "//" +puts $h_file "// Unless required by applicable law or agreed to in writing, Work distributed" +puts $h_file "// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR" +puts $h_file "// CONDITIONS OF ANY KIND, either express or implied. See the License for the" +puts $h_file "// specific language governing permissions and limitations under the License." +puts $h_file "//" +puts $h_file "// @NETFPGA_LICENSE_HEADER_END@" +puts $h_file "/////////////////////////////////////////////////////////////////////////////////" +puts $h_file "// This is an automatically generated header definitions file" +puts $h_file "// Generated by $script_path" +puts $h_file "// Generated [clock format $Time -format %D] [clock format $Time -format %H:%M:%S]" +puts $h_file "/////////////////////////////////////////////////////////////////////////////////" +puts $h_file "" + +close $h_file + +}; # end of proc write_header + + +###################################################### +# the following function writes all the information +# of a specific core into a file +###################################################### + +proc write_core {target_file prefix id has_registers lib_name} { + + +set h_file [open $target_file "a"] + +#First, read the memory map information from the reference_project defines file +source $::env(NF_DESIGN_DIR)/hw/tcl/$::env(NF_PROJECT_NAME)_defines.tcl +set public_repo_dir $::env(NFPLUS_FOLDER)/hw/lib/ + + +set baseaddr [set $prefix\_BASEADDR] +set highaddr [set $prefix\_HIGHADDR] +set sizeaddr [set $prefix\_SIZEADDR] + +puts $h_file "//######################################################" +puts $h_file "//# Definitions for $prefix" +puts $h_file "//######################################################" + +puts $h_file "#define NFPLUS_$prefix\_BASEADDR $baseaddr" +puts $h_file "#define NFPLUS_$prefix\_HIGHADDR $highaddr" +puts $h_file "#define NFPLUS_$prefix\_SIZEADDR $sizeaddr" +puts $h_file "" + +#Second, read the registers information from the library defines file +if $has_registers { + set lib_path "$public_repo_dir/std/$lib_name" + set regs_h_define_file $lib_path + set regs_h_define_file_read [open $regs_h_define_file r] + set regs_h_define_file_data [read $regs_h_define_file_read] + close $regs_h_define_file_read + set regs_h_define_file_data_line [split $regs_h_define_file_data "\n"] + + foreach read_line $regs_h_define_file_data_line { + if {[regexp "#define" $read_line]} { + puts $h_file "#define NFPLUS_[lindex $read_line 2]\_$id\_[lindex $read_line 3]\_[lindex $read_line 4] [lindex $read_line 5]" + } + } +} +puts $h_file "" +close $h_file +}; # end of proc write_core + + + +###################################################### +# the main function +###################################################### + + + +write_header $target_file + +foreach lib_item $DEF_LIST { + write_core $target_file [lindex $lib_item 0] [lindex $lib_item 1] [lindex $lib_item 2] [lindex $lib_item 3] +} + diff --git a/hw/projects/reference_dma/hw/tcl/reference_dma.tcl b/hw/projects/reference_dma/hw/tcl/reference_dma.tcl new file mode 100644 index 0000000..da4d183 --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/reference_dma.tcl @@ -0,0 +1,545 @@ +# +# Copyright (c) 2021 University of Cambridge +# All rights reserved. +# +# This software was developed by the University of Cambridge Computer +# Laboratory under EPSRC EARL Project EP/P025374/1 alongside support +# from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +#### Change design settings here ####### +set design $::env(NF_PROJECT_NAME) +set top top +set device $::env(DEVICE) +set board $::env(BOARD) +set board_name $::env(BOARD_NAME) + +set proj_dir ./project +set public_repo_dir $::env(NFPLUS_FOLDER)/hw/lib +set repo_dir ./ip_repo +set project_constraints "${public_repo_dir}/common/constraints/${board_name}_general.xdc" + +set start_time [exec date +%s] +set_param general.maxThreads 8 +set_param synth.elaboration.rodinMoreOptions "rt::set_parameter max_loop_limit 200000" +##################################### +# Design Parameters on NF_DATAPATH +##################################### +set datapath_width_bit 1024 +set datapath_freq_mhz 340 +set opl_bcam_size 16 + +set opl_cam_depth_bits [expr int(log(${opl_bcam_size})/log(2))] +##################################### +# Limit messages reported +# These are typically not helpful. +# But if you really want to see all messages +# then set suppress_unwanted_warnings to 0. +##################################### +set suppress_unwanted_warnings 0 +if {$suppress_unwanted_warnings == 1} { + set_msg_config -id "Synth 8-11241" -limit 1 + set_msg_config -id "Synth 8-6014" -limit 1 + set_msg_config -id "Synth 8-3848" -limit 1 + set_msg_config -id "Synth 8-7129" -limit 1 + set_msg_config -id "Synth 8-10592" -limit 1 + set_msg_config -id "Synth 8-7154" -limit 1 + set_msg_config -id "Synth 8-223" -limit 1 + set_msg_config -id "Synth 8-3332" -limit 1 + set_msg_config -id "Synth 8-3886" -limit 1 + set_msg_config -id "Synth 8-5396" -limit 1 +} + +##################################### +# Project Settings +##################################### +create_project -name ${design} -force -dir "./${proj_dir}" -part ${device} +set_property board_part ${board} [current_project] +set_property source_mgmt_mode DisplayOnly [current_project] +set_property top ${top} [current_fileset] +if {[string match $board_name "au280"]} { + set_property verilog_define { {BOARD_AU280} {au280} {__synthesis__} } [current_fileset] + set board_param "AU280" +} elseif {[string match $board_name "au250"]} { + set_property verilog_define { {BOARD_AU250} {__au250__} {__synthesis__} } [current_fileset] + set board_param "AU250" +} elseif {[string match $board_name "au200"]} { + set_property verilog_define { {BOARD_AU200} {__au200__} {__synthesis__} } [current_fileset] + set board_param "AU200" +} elseif {[string match $board_name "vcu1525"]} { + set_property verilog_define { {BOARD_VCU1525} {__au200__} {__synthesis__} } [current_fileset] + set board_param "VCU1525" +} +set_property generic "C_NF_DATA_WIDTH=${datapath_width_bit} BOARD=\"${board_param}\"" [current_fileset] + +puts "Creating User Datapath reference project" +##################################### +# set IP paths +##################################### +create_fileset -constrset -quiet constraints +file copy ${public_repo_dir}/ ${repo_dir} +set_property ip_repo_paths ${repo_dir} [current_fileset] +##################################### +# Project Constraints +##################################### +add_files -fileset constraints -norecurse ${project_constraints} +if {[string match $board_name "au280"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au280_timing.tcl +} elseif {[string match $board_name "au200"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au200_vcu1525_timing.tcl + add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} elseif {[string match $board_name "vcu1525"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au200_vcu1525_timing.tcl + add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} elseif {[string match $board_name "au250"]} { + add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au250_timing.tcl + add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} else { + puts "ERROR: Unknown Board type $board_name" +} +set_property is_enabled true [get_files ${project_constraints}] +set_property constrset constraints [get_runs synth_1] +set_property constrset constraints [get_runs impl_1] + +##################################### +# Project +##################################### +update_ip_catalog + +# OPL +create_ip -name switch_output_port_lookup -vendor NetFPGA -library NetFPGA -module_name switch_output_port_lookup_ip +set_property CONFIG.C_CAM_LUT_DEPTH_BITS ${opl_cam_depth_bits} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property generate_synth_checkpoint false [get_files switch_output_port_lookup_ip.xci] +reset_target all [get_ips switch_output_port_lookup_ip] +generate_target all [get_ips switch_output_port_lookup_ip] +# input_arbiter +create_ip -name input_arbiter -vendor NetFPGA -library NetFPGA -module_name input_arbiter_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property generate_synth_checkpoint false [get_files input_arbiter_ip.xci] +reset_target all [get_ips input_arbiter_ip] +generate_target all [get_ips input_arbiter_ip] +# output_queues +create_ip -name output_queues -vendor NetFPGA -library NetFPGA -module_name output_queues_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property generate_synth_checkpoint false [get_files output_queues_ip.xci] +reset_target all [get_ips output_queues_ip] +generate_target all [get_ips output_queues_ip] + +create_ip -name xilinx_shell -vendor xilinx -library xilinx -module_name xilinx_shell_ip +set_property CONFIG.MAX_PKT_LEN 1518 [get_ips xilinx_shell_ip] +set_property CONFIG.NUM_QUEUE 2048 [get_ips xilinx_shell_ip] +set_property CONFIG.NUM_PHYS_FUNC 2 [get_ips xilinx_shell_ip] +set_property CONFIG.NUM_CMAC_PORT 2 [get_ips xilinx_shell_ip] +set_property generate_synth_checkpoint false [get_files xilinx_shell_ip.xci] +reset_target all [get_ips xilinx_shell_ip] +generate_target all [get_ips xilinx_shell_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_ip.xci] +reset_target all [get_ips nf_mac_attachment_ip] +generate_target all [get_ips nf_mac_attachment_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_dma_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_DEFAULT_VALUE_ENABLE 0 [get_ips nf_mac_attachment_dma_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_dma_ip.xci] +reset_target all [get_ips nf_mac_attachment_dma_ip] +generate_target all [get_ips nf_mac_attachment_dma_ip] + +# nf_data_sink +create_ip -name nf_data_sink -vendor NetFPGA -library NetFPGA -module_name nf_data_sink_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_data_sink_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_data_sink_ip] +set_property generate_synth_checkpoint false [get_files nf_data_sink_ip.xci] +reset_target all [get_ips nf_data_sink_ip] +generate_target all [get_ips nf_data_sink_ip] + +create_ip -name axi_crossbar -vendor xilinx.com -library ip -module_name axi_crossbar_0 +set_property -dict [list \ +CONFIG.NUM_MI {3} \ +CONFIG.PROTOCOL {AXI4LITE} \ +CONFIG.CONNECTIVITY_MODE {SASD} \ +CONFIG.R_REGISTER {1} \ +CONFIG.S00_WRITE_ACCEPTANCE {1} \ +CONFIG.S01_WRITE_ACCEPTANCE {1} \ +CONFIG.S02_WRITE_ACCEPTANCE {1} \ +CONFIG.S03_WRITE_ACCEPTANCE {1} \ +CONFIG.S04_WRITE_ACCEPTANCE {1} \ +CONFIG.S05_WRITE_ACCEPTANCE {1} \ +CONFIG.S06_WRITE_ACCEPTANCE {1} \ +CONFIG.S07_WRITE_ACCEPTANCE {1} \ +CONFIG.S08_WRITE_ACCEPTANCE {1} \ +CONFIG.S09_WRITE_ACCEPTANCE {1} \ +CONFIG.S10_WRITE_ACCEPTANCE {1} \ +CONFIG.S11_WRITE_ACCEPTANCE {1} \ +CONFIG.S12_WRITE_ACCEPTANCE {1} \ +CONFIG.S13_WRITE_ACCEPTANCE {1} \ +CONFIG.S14_WRITE_ACCEPTANCE {1} \ +CONFIG.S15_WRITE_ACCEPTANCE {1} \ +CONFIG.S00_READ_ACCEPTANCE {1} \ +CONFIG.S01_READ_ACCEPTANCE {1} \ +CONFIG.S02_READ_ACCEPTANCE {1} \ +CONFIG.S03_READ_ACCEPTANCE {1} \ +CONFIG.S04_READ_ACCEPTANCE {1} \ +CONFIG.S05_READ_ACCEPTANCE {1} \ +CONFIG.S06_READ_ACCEPTANCE {1} \ +CONFIG.S07_READ_ACCEPTANCE {1} \ +CONFIG.S08_READ_ACCEPTANCE {1} \ +CONFIG.S09_READ_ACCEPTANCE {1} \ +CONFIG.S10_READ_ACCEPTANCE {1} \ +CONFIG.S11_READ_ACCEPTANCE {1} \ +CONFIG.S12_READ_ACCEPTANCE {1} \ +CONFIG.S13_READ_ACCEPTANCE {1} \ +CONFIG.S14_READ_ACCEPTANCE {1} \ +CONFIG.S15_READ_ACCEPTANCE {1} \ +CONFIG.M00_WRITE_ISSUING {1} \ +CONFIG.M01_WRITE_ISSUING {1} \ +CONFIG.M02_WRITE_ISSUING {1} \ +CONFIG.M03_WRITE_ISSUING {1} \ +CONFIG.M04_WRITE_ISSUING {1} \ +CONFIG.M05_WRITE_ISSUING {1} \ +CONFIG.M06_WRITE_ISSUING {1} \ +CONFIG.M07_WRITE_ISSUING {1} \ +CONFIG.M08_WRITE_ISSUING {1} \ +CONFIG.M09_WRITE_ISSUING {1} \ +CONFIG.M10_WRITE_ISSUING {1} \ +CONFIG.M11_WRITE_ISSUING {1} \ +CONFIG.M12_WRITE_ISSUING {1} \ +CONFIG.M13_WRITE_ISSUING {1} \ +CONFIG.M14_WRITE_ISSUING {1} \ +CONFIG.M15_WRITE_ISSUING {1} \ +CONFIG.M00_READ_ISSUING {1} \ +CONFIG.M01_READ_ISSUING {1} \ +CONFIG.M02_READ_ISSUING {1} \ +CONFIG.M03_READ_ISSUING {1} \ +CONFIG.M04_READ_ISSUING {1} \ +CONFIG.M05_READ_ISSUING {1} \ +CONFIG.M06_READ_ISSUING {1} \ +CONFIG.M07_READ_ISSUING {1} \ +CONFIG.M08_READ_ISSUING {1} \ +CONFIG.M09_READ_ISSUING {1} \ +CONFIG.M10_READ_ISSUING {1} \ +CONFIG.M11_READ_ISSUING {1} \ +CONFIG.M12_READ_ISSUING {1} \ +CONFIG.M13_READ_ISSUING {1} \ +CONFIG.M14_READ_ISSUING {1} \ +CONFIG.M15_READ_ISSUING {1} \ +CONFIG.S00_SINGLE_THREAD {1} \ +CONFIG.M00_A00_ADDR_WIDTH {16} \ +CONFIG.M01_A00_ADDR_WIDTH {16} \ +CONFIG.M02_A00_ADDR_WIDTH {16} \ +CONFIG.M00_A00_BASE_ADDR {0x0000000000000000}\ +CONFIG.M01_A00_BASE_ADDR {0x0000000000010000}\ +CONFIG.M02_A00_BASE_ADDR {0x0000000000020000}] [get_ips axi_crossbar_0] +set_property generate_synth_checkpoint false [get_files axi_crossbar_0.xci] +reset_target all [get_ips axi_crossbar_0] +generate_target all [get_ips axi_crossbar_0] + +create_ip -name axi_crossbar -vendor xilinx.com -library ip -module_name axi_crossbar_1 +set_property -dict [list \ +CONFIG.NUM_MI {3} \ +CONFIG.PROTOCOL {AXI4LITE} \ +CONFIG.CONNECTIVITY_MODE {SASD} \ +CONFIG.R_REGISTER {1} \ +CONFIG.S00_WRITE_ACCEPTANCE {1} \ +CONFIG.S01_WRITE_ACCEPTANCE {1} \ +CONFIG.S02_WRITE_ACCEPTANCE {1} \ +CONFIG.S03_WRITE_ACCEPTANCE {1} \ +CONFIG.S04_WRITE_ACCEPTANCE {1} \ +CONFIG.S05_WRITE_ACCEPTANCE {1} \ +CONFIG.S06_WRITE_ACCEPTANCE {1} \ +CONFIG.S07_WRITE_ACCEPTANCE {1} \ +CONFIG.S08_WRITE_ACCEPTANCE {1} \ +CONFIG.S09_WRITE_ACCEPTANCE {1} \ +CONFIG.S10_WRITE_ACCEPTANCE {1} \ +CONFIG.S11_WRITE_ACCEPTANCE {1} \ +CONFIG.S12_WRITE_ACCEPTANCE {1} \ +CONFIG.S13_WRITE_ACCEPTANCE {1} \ +CONFIG.S14_WRITE_ACCEPTANCE {1} \ +CONFIG.S15_WRITE_ACCEPTANCE {1} \ +CONFIG.S00_READ_ACCEPTANCE {1} \ +CONFIG.S01_READ_ACCEPTANCE {1} \ +CONFIG.S02_READ_ACCEPTANCE {1} \ +CONFIG.S03_READ_ACCEPTANCE {1} \ +CONFIG.S04_READ_ACCEPTANCE {1} \ +CONFIG.S05_READ_ACCEPTANCE {1} \ +CONFIG.S06_READ_ACCEPTANCE {1} \ +CONFIG.S07_READ_ACCEPTANCE {1} \ +CONFIG.S08_READ_ACCEPTANCE {1} \ +CONFIG.S09_READ_ACCEPTANCE {1} \ +CONFIG.S10_READ_ACCEPTANCE {1} \ +CONFIG.S11_READ_ACCEPTANCE {1} \ +CONFIG.S12_READ_ACCEPTANCE {1} \ +CONFIG.S13_READ_ACCEPTANCE {1} \ +CONFIG.S14_READ_ACCEPTANCE {1} \ +CONFIG.S15_READ_ACCEPTANCE {1} \ +CONFIG.M00_WRITE_ISSUING {1} \ +CONFIG.M01_WRITE_ISSUING {1} \ +CONFIG.M02_WRITE_ISSUING {1} \ +CONFIG.M03_WRITE_ISSUING {1} \ +CONFIG.M04_WRITE_ISSUING {1} \ +CONFIG.M05_WRITE_ISSUING {1} \ +CONFIG.M06_WRITE_ISSUING {1} \ +CONFIG.M07_WRITE_ISSUING {1} \ +CONFIG.M08_WRITE_ISSUING {1} \ +CONFIG.M09_WRITE_ISSUING {1} \ +CONFIG.M10_WRITE_ISSUING {1} \ +CONFIG.M11_WRITE_ISSUING {1} \ +CONFIG.M12_WRITE_ISSUING {1} \ +CONFIG.M13_WRITE_ISSUING {1} \ +CONFIG.M14_WRITE_ISSUING {1} \ +CONFIG.M15_WRITE_ISSUING {1} \ +CONFIG.M00_READ_ISSUING {1} \ +CONFIG.M01_READ_ISSUING {1} \ +CONFIG.M02_READ_ISSUING {1} \ +CONFIG.M03_READ_ISSUING {1} \ +CONFIG.M04_READ_ISSUING {1} \ +CONFIG.M05_READ_ISSUING {1} \ +CONFIG.M06_READ_ISSUING {1} \ +CONFIG.M07_READ_ISSUING {1} \ +CONFIG.M08_READ_ISSUING {1} \ +CONFIG.M09_READ_ISSUING {1} \ +CONFIG.M10_READ_ISSUING {1} \ +CONFIG.M11_READ_ISSUING {1} \ +CONFIG.M12_READ_ISSUING {1} \ +CONFIG.M13_READ_ISSUING {1} \ +CONFIG.M14_READ_ISSUING {1} \ +CONFIG.M15_READ_ISSUING {1} \ +CONFIG.S00_SINGLE_THREAD {1} \ +CONFIG.M00_A00_ADDR_WIDTH {16} \ +CONFIG.M01_A00_ADDR_WIDTH {16} \ +CONFIG.M02_A00_ADDR_WIDTH {16} \ +CONFIG.M00_A00_BASE_ADDR {0x0000000000000000}\ +CONFIG.M01_A00_BASE_ADDR {0x0000000000010000}\ +CONFIG.M02_A00_BASE_ADDR {0x0000000000020000}] [get_ips axi_crossbar_1] +set_property generate_synth_checkpoint false [get_files axi_crossbar_1.xci] +reset_target all [get_ips axi_crossbar_1] +generate_target all [get_ips axi_crossbar_1] + +create_ip -name axi_clock_converter -vendor xilinx.com -library ip -module_name axi_clock_converter_0 +set_property -dict { + CONFIG.PROTOCOL {AXI4LITE} + CONFIG.DATA_WIDTH {32} + CONFIG.ID_WIDTH {0} + CONFIG.AWUSER_WIDTH {0} + CONFIG.ARUSER_WIDTH {0} + CONFIG.RUSER_WIDTH {0} + CONFIG.WUSER_WIDTH {0} + CONFIG.BUSER_WIDTH {0} + CONFIG.SI_CLK.FREQ_HZ {250000000} + CONFIG.MI_CLK.FREQ_HZ ${datapath_freq_mhz}000000 + CONFIG.ACLK_ASYNC {1} + CONFIG.SYNCHRONIZATION_STAGES {3} +} [get_ips axi_clock_converter_0] +set_property generate_synth_checkpoint false [get_files axi_clock_converter_0.xci] +reset_target all [get_ips axi_clock_converter_0] +generate_target all [get_ips axi_clock_converter_0] + +#Add a clock wizard +create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name clk_wiz_1 +if {[string match "${datapath_freq_mhz}" "200"]} { +#200MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {200.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {6.000} \ + CONFIG.CLKOUT1_JITTER {119.392} \ + CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "250"]} { +#250MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {250.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {1} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {4.750} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.750} \ + CONFIG.CLKOUT1_JITTER {85.152} \ + CONFIG.CLKOUT1_PHASE_ERROR {78.266}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "260"]} { +#260MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {260.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {120.250} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.625} \ + CONFIG.CLKOUT1_JITTER {182.359} \ + CONFIG.CLKOUT1_PHASE_ERROR {351.991}] [get_ips clk_wiz_10] +} elseif {[string match "${datapath_freq_mhz}" "280"]} { +#280MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {280.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {119.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.250} \ + CONFIG.CLKOUT1_JITTER {183.720} \ + CONFIG.CLKOUT1_PHASE_ERROR {357.524}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "300"]} { +#300MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {300.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {4.000} \ + CONFIG.CLKOUT1_JITTER {111.430} \ + CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "320"]} { +#320MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {320.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {5} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.750} \ + CONFIG.CLKOUT1_JITTER {110.215} \ + CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +} elseif {[string match "${datapath_freq_mhz}" "340"]} { +#340MHz clock + set_property -dict [list \ + CONFIG.PRIM_IN_FREQ {250.000} \ + CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {340.000} \ + CONFIG.CLKIN1_JITTER_PS {40.0} \ + CONFIG.MMCM_DIVCLK_DIVIDE {25} \ + CONFIG.MMCM_CLKFBOUT_MULT_F {119.000} \ + CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ + CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ + CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.500} \ + CONFIG.CLKOUT1_JITTER {179.007} \ + CONFIG.CLKOUT1_PHASE_ERROR {357.524}] [get_ips clk_wiz_1] +} else { + puts "Error: the specified clock is error" + exit -1 +} +#360MHz clock +#set_property -dict [list \ +# CONFIG.PRIM_IN_FREQ {250.000} \ +# CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {360.000} \ +# CONFIG.CLKIN1_JITTER_PS {40.0} \ +# CONFIG.MMCM_DIVCLK_DIVIDE {25} \ +# CONFIG.MMCM_CLKFBOUT_MULT_F {121.500} \ +# CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ +# CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ +# CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.375} \ +# CONFIG.CLKOUT1_JITTER {171.636} \ +# CONFIG.CLKOUT1_PHASE_ERROR {346.603}] [get_ips clk_wiz_1] +#380MHz clock +#set_property -dict [list \ +# CONFIG.PRIM_IN_FREQ {250.000} \ +# CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {380.000} \ +# CONFIG.CLKIN1_JITTER_PS {40.0} \ +# CONFIG.MMCM_DIVCLK_DIVIDE {1} \ +# CONFIG.MMCM_CLKFBOUT_MULT_F {4.750} \ +# CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ +# CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ +# CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.125} \ +# CONFIG.CLKOUT1_JITTER {78.466} \ +# CONFIG.CLKOUT1_PHASE_ERROR {78.266}] [get_ips clk_wiz_1] +#400MHz clock +#set_property -dict [list \ +# CONFIG.PRIM_IN_FREQ {250.000} \ +# CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {400.000} \ +# CONFIG.CLKIN1_JITTER_PS {40.0} \ +# CONFIG.MMCM_DIVCLK_DIVIDE {5} \ +# CONFIG.MMCM_CLKFBOUT_MULT_F {24.000} \ +# CONFIG.MMCM_CLKIN1_PERIOD {4.000} \ +# CONFIG.MMCM_CLKIN2_PERIOD {10.0} \ +# CONFIG.MMCM_CLKOUT0_DIVIDE_F {3.000} \ +# CONFIG.CLKOUT1_JITTER {106.119} \ +# CONFIG.CLKOUT1_PHASE_ERROR {154.678}] [get_ips clk_wiz_1] +set_property generate_synth_checkpoint false [get_files clk_wiz_1.xci] +reset_target all [get_ips clk_wiz_1] +generate_target all [get_ips clk_wiz_1] + +read_verilog "./hdl/nf_datapath.v" +read_verilog -sv "${public_repo_dir}/common/hdl/top_wrapper.sv" +read_verilog -sv "${public_repo_dir}/common/hdl/nf_attachment.sv" +read_verilog "${public_repo_dir}/common/hdl/top.v" + +#Setting Synthesis options +create_run -flow {Vivado Synthesis 2020} -verbose synth +set_property write_incremental_synth_checkpoint true [get_runs synth_1] +set_property AUTO_INCREMENTAL_CHECKPOINT 1 [get_runs synth_1] +#Setting Implementation options +create_run impl -parent_run synth -flow {Vivado Implementation 2020} +set_property strategy Performance_ExplorePostRoutePhysOpt [get_runs impl_1] +set_property steps.phys_opt_design.is_enabled true [get_runs impl_1] +set_property STEPS.PHYS_OPT_DESIGN.ARGS.DIRECTIVE ExploreWithHoldFix [get_runs impl_1] +set_property STEPS.PLACE_DESIGN.ARGS.DIRECTIVE Explore [get_runs impl_1] +set_property STEPS.POST_ROUTE_PHYS_OPT_DESIGN.is_enabled true [get_runs impl_1] + +set_property STEPS.POST_ROUTE_PHYS_OPT_DESIGN.ARGS.DIRECTIVE AggressiveExplore [get_runs impl_1] +# The following implementation options will increase runtime, but get the best timing results +set_property SEVERITY {Warning} [get_drc_checks UCIO-1] +launch_runs synth +wait_on_run synth +launch_runs impl_1 +wait_on_run impl_1 +open_checkpoint project/${design}.runs/impl_1/top_postroute_physopt.dcp + +if {![file exists "../bitfiles"]} { + file mkdir "../bitfiles" +} +write_bitstream -force ../bitfiles/${design}_${board_name}.bit +write_debug_probes -file ../bitfiles/${design}_${board_name}.ltx -force + +# -- For Report -- +set end_time [exec date +%s] +set elapsed_time [expr ${end_time} - ${start_time}] +if {[catch {exec grep -A 4 "VIOLAT" project/${design}.runs/impl_1/top_timing_summary_postroute_physopted.rpt} timing_report_data]} { + set timing_report "Met" + set timing_report_data "" +} else { + set timing_report "VIOLATED" +} +puts " --- Report : ${design} for ${board_name} --- " +puts " Synth time : ${elapsed_time}" +puts " Timing Closure: ${timing_report}" +puts "${timing_report_data}" + +exit + diff --git a/hw/projects/reference_dma/hw/tcl/reference_dma_defines.tcl b/hw/projects/reference_dma/hw/tcl/reference_dma_defines.tcl new file mode 100644 index 0000000..7736288 --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/reference_dma_defines.tcl @@ -0,0 +1,68 @@ +# +# Copyright (c) 2015 Noa Zilberman +# Copyright (c) 2021 Yuta Tokusashi +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + + +####################### +# Segments Assignment # +####################### +#M00 +set M00_BASEADDR 0x00000000 +set M00_HIGHADDR 0x00000FFF +set M00_SIZEADDR 0x1000 + +#M01 +set M01_BASEADDR 0x00010000 +set M01_HIGHADDR 0x00010FFF +set M01_SIZEADDR 0x1000 + +#M02 +set M02_BASEADDR 0x00020000 +set M02_HIGHADDR 0x00020FFF +set M02_SIZEADDR 0x1000 + +##M03 +#set M03_BASEADDR 0x44030000 +#set M03_HIGHADDR 0x44030FFF +#set M03_SIZEADDR 0x1000 +# + +####################### +# IP_ASSIGNMENT # +####################### +# Note that physical connectivity must match this mapping + +# Where is this used???? + +#NF_DATA_SINK base address and size +set NF_DATA_SINK_BASEADDR $M00_BASEADDR +set NF_DATA_SINK_HIGHADDR $M00_HIGHADDR +set NF_DATA_SINK_SIZEADDR $M00_SIZEADDR + + diff --git a/hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl b/hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl new file mode 100644 index 0000000..4ecdc6e --- /dev/null +++ b/hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl @@ -0,0 +1,263 @@ +# +# Copyright (c) 2021 University of Cambridge +# All rights reserved. +# +# This software was developed by the University of Cambridge Computer +# Laboratory under EPSRC EARL Project EP/P025374/1 alongside support +# from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +puts "===== Starting hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl =====" + +#### Change design settings here ####### +set design $::env(NF_PROJECT_NAME) +set top top_sim +set sim_top top_tb +set device $::env(DEVICE) +set board $::env(BOARD) +set board_name $::env(BOARD_NAME) + +set proj_dir ./project +set public_repo_dir $::env(NFPLUS_FOLDER)/hw/lib/ +set repo_dir ./ip_repo +set project_constraints ./constraints/${board_name}_switch.xdc + +set test_name [lindex $argv 0] +source $::env(NF_DESIGN_DIR)/hw/tcl/$::env(NF_PROJECT_NAME)_defines.tcl + +set_param general.maxThreads 8 +##################################### +# Design Parameters on NF_DATAPATH +##################################### +set datapath_width_bit 1024 +set opl_bcam_size 16 +set top_sim_barrier_num_ports 5 +set opl_cam_depth_bits [expr int(log(${opl_bcam_size})/log(2))] +##################################### +# Project Settings +##################################### +create_project -name ${design} -force -dir "./${proj_dir}" -part ${device} +set_property board_part ${board} [current_project] +set_property source_mgmt_mode DisplayOnly [current_project] +set_property top ${top} [current_fileset] +puts "Creating User Datapath reference project" +##################################### +# set IP paths +##################################### +create_fileset -constrset -quiet constraints +file copy ${public_repo_dir}/ ${repo_dir} +set_property ip_repo_paths ${repo_dir} [current_fileset] + +##################################### +# Project +##################################### +update_ip_catalog +# nf_data_sink +create_ip -name nf_data_sink -vendor NetFPGA -library NetFPGA -module_name nf_data_sink_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_data_sink_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_data_sink_ip] +set_property generate_synth_checkpoint false [get_files nf_data_sink_ip.xci] +reset_target all [get_ips nf_data_sink_ip] +generate_target all [get_ips nf_data_sink_ip] +# OPL +create_ip -name switch_output_port_lookup -vendor NetFPGA -library NetFPGA -module_name switch_output_port_lookup_ip +set_property CONFIG.C_CAM_LUT_DEPTH_BITS ${opl_cam_depth_bits} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips switch_output_port_lookup_ip] +set_property generate_synth_checkpoint false [get_files switch_output_port_lookup_ip.xci] +reset_target all [get_ips switch_output_port_lookup_ip] +generate_target all [get_ips switch_output_port_lookup_ip] +# input_arbiter +create_ip -name input_arbiter -vendor NetFPGA -library NetFPGA -module_name input_arbiter_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips input_arbiter_ip] +set_property generate_synth_checkpoint false [get_files input_arbiter_ip.xci] +reset_target all [get_ips input_arbiter_ip] +generate_target all [get_ips input_arbiter_ip] +# output_queues +create_ip -name output_queues -vendor NetFPGA -library NetFPGA -module_name output_queues_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips output_queues_ip] +set_property generate_synth_checkpoint false [get_files output_queues_ip.xci] +reset_target all [get_ips output_queues_ip] +generate_target all [get_ips output_queues_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_ip.xci] +reset_target all [get_ips nf_mac_attachment_ip] +generate_target all [get_ips nf_mac_attachment_ip] + +create_ip -name nf_mac_attachment -vendor NetFPGA -library NetFPGA -module_name nf_mac_attachment_dma_ip +set_property CONFIG.C_M_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_S_AXIS_DATA_WIDTH ${datapath_width_bit} [get_ips nf_mac_attachment_dma_ip] +set_property CONFIG.C_DEFAULT_VALUE_ENABLE 0 [get_ips nf_mac_attachment_dma_ip] +set_property generate_synth_checkpoint false [get_files nf_mac_attachment_dma_ip.xci] +reset_target all [get_ips nf_mac_attachment_dma_ip] +generate_target all [get_ips nf_mac_attachment_dma_ip] + +create_ip -name barrier -vendor NetFPGA -library NetFPGA -module_name barrier_ip +set_property CONFIG.NUM_PORTS ${top_sim_barrier_num_ports} [get_ips barrier_ip] +reset_target all [get_ips barrier_ip] +generate_target all [get_ips barrier_ip] + +create_ip -name axis_sim_record -vendor NetFPGA -library NetFPGA -module_name axis_sim_record_ip0 +set_property -dict [list CONFIG.OUTPUT_FILE $::env(NF_DESIGN_DIR)/test/nf_interface_0_log.axi] [get_ips axis_sim_record_ip0] +reset_target all [get_ips axis_sim_record_ip0] +generate_target all [get_ips axis_sim_record_ip0] + +create_ip -name axis_sim_record -vendor NetFPGA -library NetFPGA -module_name axis_sim_record_ip1 +set_property -dict [list CONFIG.OUTPUT_FILE $::env(NF_DESIGN_DIR)/test/nf_interface_1_log.axi] [get_ips axis_sim_record_ip1] +reset_target all [get_ips axis_sim_record_ip1] +generate_target all [get_ips axis_sim_record_ip1] + +create_ip -name axis_sim_record -vendor NetFPGA -library NetFPGA -module_name axis_sim_record_ip2 +set_property -dict [list CONFIG.OUTPUT_FILE $::env(NF_DESIGN_DIR)/test/dma_0_log.axi] [get_ips axis_sim_record_ip2] +reset_target all [get_ips axis_sim_record_ip2] +generate_target all [get_ips axis_sim_record_ip2] + +create_ip -name axis_sim_stim -vendor NetFPGA -library NetFPGA -module_name axis_sim_stim_ip0 +set_property -dict [list CONFIG.input_file $::env(NF_DESIGN_DIR)/test/nf_interface_0_stim.axi] [get_ips axis_sim_stim_ip0] +generate_target all [get_ips axis_sim_stim_ip0] + +create_ip -name axis_sim_stim -vendor NetFPGA -library NetFPGA -module_name axis_sim_stim_ip1 +set_property -dict [list CONFIG.input_file $::env(NF_DESIGN_DIR)/test/nf_interface_1_stim.axi] [get_ips axis_sim_stim_ip1] +generate_target all [get_ips axis_sim_stim_ip1] + +create_ip -name axis_sim_stim -vendor NetFPGA -library NetFPGA -module_name axis_sim_stim_ip2 +set_property -dict [list CONFIG.input_file $::env(NF_DESIGN_DIR)/test/dma_0_stim.axi] [get_ips axis_sim_stim_ip2] +generate_target all [get_ips axis_sim_stim_ip2] + +create_ip -name axi_sim_transactor -vendor NetFPGA -library NetFPGA -module_name axi_sim_transactor_ip +set_property -dict [list CONFIG.STIM_FILE $::env(NF_DESIGN_DIR)/test/reg_stim.axi CONFIG.EXPECT_FILE $::env(NF_DESIGN_DIR)/test/reg_expect.axi CONFIG.LOG_FILE $::env(NF_DESIGN_DIR)/test/reg_stim.log] [get_ips axi_sim_transactor_ip] +reset_target all [get_ips axi_sim_transactor_ip] +generate_target all [get_ips axi_sim_transactor_ip] + + +create_ip -name axi_crossbar -vendor xilinx.com -library ip -module_name axi_crossbar_0 +set_property -dict [list \ +CONFIG.NUM_MI {3} \ +CONFIG.PROTOCOL {AXI4LITE} \ +CONFIG.CONNECTIVITY_MODE {SASD} \ +CONFIG.R_REGISTER {1} \ +CONFIG.S00_WRITE_ACCEPTANCE {1} \ +CONFIG.S01_WRITE_ACCEPTANCE {1} \ +CONFIG.S02_WRITE_ACCEPTANCE {1} \ +CONFIG.S03_WRITE_ACCEPTANCE {1} \ +CONFIG.S04_WRITE_ACCEPTANCE {1} \ +CONFIG.S05_WRITE_ACCEPTANCE {1} \ +CONFIG.S06_WRITE_ACCEPTANCE {1} \ +CONFIG.S07_WRITE_ACCEPTANCE {1} \ +CONFIG.S08_WRITE_ACCEPTANCE {1} \ +CONFIG.S09_WRITE_ACCEPTANCE {1} \ +CONFIG.S10_WRITE_ACCEPTANCE {1} \ +CONFIG.S11_WRITE_ACCEPTANCE {1} \ +CONFIG.S12_WRITE_ACCEPTANCE {1} \ +CONFIG.S13_WRITE_ACCEPTANCE {1} \ +CONFIG.S14_WRITE_ACCEPTANCE {1} \ +CONFIG.S15_WRITE_ACCEPTANCE {1} \ +CONFIG.S00_READ_ACCEPTANCE {1} \ +CONFIG.S01_READ_ACCEPTANCE {1} \ +CONFIG.S02_READ_ACCEPTANCE {1} \ +CONFIG.S03_READ_ACCEPTANCE {1} \ +CONFIG.S04_READ_ACCEPTANCE {1} \ +CONFIG.S05_READ_ACCEPTANCE {1} \ +CONFIG.S06_READ_ACCEPTANCE {1} \ +CONFIG.S07_READ_ACCEPTANCE {1} \ +CONFIG.S08_READ_ACCEPTANCE {1} \ +CONFIG.S09_READ_ACCEPTANCE {1} \ +CONFIG.S10_READ_ACCEPTANCE {1} \ +CONFIG.S11_READ_ACCEPTANCE {1} \ +CONFIG.S12_READ_ACCEPTANCE {1} \ +CONFIG.S13_READ_ACCEPTANCE {1} \ +CONFIG.S14_READ_ACCEPTANCE {1} \ +CONFIG.S15_READ_ACCEPTANCE {1} \ +CONFIG.M00_WRITE_ISSUING {1} \ +CONFIG.M01_WRITE_ISSUING {1} \ +CONFIG.M02_WRITE_ISSUING {1} \ +CONFIG.M03_WRITE_ISSUING {1} \ +CONFIG.M04_WRITE_ISSUING {1} \ +CONFIG.M05_WRITE_ISSUING {1} \ +CONFIG.M06_WRITE_ISSUING {1} \ +CONFIG.M07_WRITE_ISSUING {1} \ +CONFIG.M08_WRITE_ISSUING {1} \ +CONFIG.M09_WRITE_ISSUING {1} \ +CONFIG.M10_WRITE_ISSUING {1} \ +CONFIG.M11_WRITE_ISSUING {1} \ +CONFIG.M12_WRITE_ISSUING {1} \ +CONFIG.M13_WRITE_ISSUING {1} \ +CONFIG.M14_WRITE_ISSUING {1} \ +CONFIG.M15_WRITE_ISSUING {1} \ +CONFIG.M00_READ_ISSUING {1} \ +CONFIG.M01_READ_ISSUING {1} \ +CONFIG.M02_READ_ISSUING {1} \ +CONFIG.M03_READ_ISSUING {1} \ +CONFIG.M04_READ_ISSUING {1} \ +CONFIG.M05_READ_ISSUING {1} \ +CONFIG.M06_READ_ISSUING {1} \ +CONFIG.M07_READ_ISSUING {1} \ +CONFIG.M08_READ_ISSUING {1} \ +CONFIG.M09_READ_ISSUING {1} \ +CONFIG.M10_READ_ISSUING {1} \ +CONFIG.M11_READ_ISSUING {1} \ +CONFIG.M12_READ_ISSUING {1} \ +CONFIG.M13_READ_ISSUING {1} \ +CONFIG.M14_READ_ISSUING {1} \ +CONFIG.M15_READ_ISSUING {1} \ +CONFIG.S00_SINGLE_THREAD {1} \ +CONFIG.M00_A00_ADDR_WIDTH {16} \ +CONFIG.M01_A00_ADDR_WIDTH {16} \ +CONFIG.M02_A00_ADDR_WIDTH {16} \ +CONFIG.M00_A00_BASE_ADDR {0x0000000000200000}\ +CONFIG.M01_A00_BASE_ADDR {0x0000000000210000}\ +CONFIG.M02_A00_BASE_ADDR {0x0000000000220000}] [get_ips axi_crossbar_0] +set_property generate_synth_checkpoint false [get_files axi_crossbar_0.xci] +reset_target all [get_ips axi_crossbar_0] +generate_target all [get_ips axi_crossbar_0] + + +read_verilog "$::env(NF_DESIGN_DIR)/hw/hdl/nf_datapath.v" +read_verilog "$::env(NF_DESIGN_DIR)/hw/hdl/top_sim.v" +read_verilog "$::env(NF_DESIGN_DIR)/hw/hdl/top_tb.v" + + +update_compile_order -fileset sources_1 +update_compile_order -fileset sim_1 + +set_property top ${sim_top} [get_filesets sim_1] +set_property include_dirs ${proj_dir} [get_filesets sim_1] +set_property simulator_language Mixed [current_project] +set_property verilog_define { {SIMULATION=1} } [get_filesets sim_1] +set_property -name xsim.more_options -value {-testplusarg TESTNAME=basic_test} -objects [get_filesets sim_1] +set_property runtime {} [get_filesets sim_1] +set_property target_simulator xsim [current_project] +set_property compxlib.compiled_library_dir {} [current_project] +set_property top_lib xil_defaultlib [get_filesets sim_1] +update_compile_order -fileset sim_1 + +unset env(PYTHONPATH) +unset env(PYTHONHOME) +set env(PYTHONPATH) ".:$::env(NFPLUS_FOLDER)/tools/scripts/:$::env(NFPLUS_FOLDER)/tools/scripts/NFTest" +set output [exec $::env(PYTHON_BNRY) $::env(NF_DESIGN_DIR)/test/${test_name}/run.py] +puts $output + +launch_simulation -simset sim_1 -mode behavioral +run 10us + +puts "===== Leaving hw/projects/reference_dma/hw/tcl/reference_dma_sim.tcl =====" diff --git a/hw/projects/reference_dma/test/both_learning_sw/run.py b/hw/projects/reference_dma/test/both_learning_sw/run.py new file mode 100755 index 0000000..a856ec0 --- /dev/null +++ b/hw/projects/reference_dma/test/both_learning_sw/run.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2015 University of Cambridge +# Copyright (c) 2015 Neelakandan Manihatty Bojan, Georgina Kalogeridou +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +# Author: +# Modified by Neelakandan Manihatty Bojan, Georgina Kalogeridou + +import logging +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) + +from NFTest import * +import sys +import os +from scapy.layers.all import Ether, IP, TCP +from reg_defines_reference_dma import * + +phy2loop0 = ('../connections/conn', []) +nftest_init(sim_loop = [], hw_config = [phy2loop0]) + + +if isHW(): + # Clearing the LUT_HIT and LUT_MISS by asserting the reset_counters + nftest_regwrite(NFPLUS_INPUT_ARBITER_0_RESET(), 0x1) + nftest_regwrite(NFPLUS_OUTPUT_PORT_LOOKUP_0_RESET(), 0x101) + nftest_regwrite(NFPLUS_OUTPUT_QUEUES_0_RESET(), 0x1) + + # Reset the switch table lookup counters (value is reset every time is read) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT()) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS()) + +nftest_start() + + +routerMAC = [] +routerIP = [] +for i in range(2): + routerMAC.append("00:0a:35:03:00:0%d"%(i+1)) + routerIP.append("192.168.%s.40"%i) + +num_broadcast = 10 + +pkts = [] +pkta = [] +for i in range(num_broadcast): + pkt = make_IP_pkt(src_MAC="aa:bb:cc:dd:ee:ff", dst_MAC=routerMAC[0], + src_IP="192.168.0.1", dst_IP="192.168.1.1", pkt_len=512) + + pkt.time = ((i*(1e-8)) + (2e-6)) + pkts.append(pkt) + if isHW(): + nftest_send_phy('nf0', pkt) + nftest_expect_phy('nf1', pkt) + +if not isHW(): + nftest_send_phy('nf0', pkts) + nftest_expect_phy('nf1', pkts) + +nftest_barrier() + +num_normal = 10 + +for i in range(num_normal): + pkt = make_IP_pkt(dst_MAC="aa:bb:cc:dd:ee:ff", src_MAC=routerMAC[1], + src_IP="192.168.0.1", dst_IP="192.168.1.1", pkt_len=512) + pkt.time = (((i+5)*(1e-8)) + (2e-6)) + pkta.append(pkt) + if isHW(): + nftest_send_phy('nf1', pkt) + nftest_expect_phy('nf0', pkt) + +if not isHW(): + nftest_send_phy('nf1', pkta) + nftest_expect_phy('nf0', pkta) + +nftest_barrier() + +if isHW(): + # Now we expect to see the lut_hit and lut_miss registers incremented and we + # verify this by doing a regread_expect + rres1= nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), num_normal) + rres2= nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) + # List containing the return values of the reg_reads + mres=[rres1,rres2] +else: + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), num_normal) # lut_hit + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) # lut_miss + mres=[] + +nftest_finish(mres) diff --git a/hw/projects/reference_dma/test/both_simple_broadcast/run.py b/hw/projects/reference_dma/test/both_simple_broadcast/run.py new file mode 100755 index 0000000..10aa9ae --- /dev/null +++ b/hw/projects/reference_dma/test/both_simple_broadcast/run.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2015 University of Cambridge +# Copyright (c) 2015 Neelakandan Manihatty Bojan, Georgina Kalogeridou +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +# Author: +# Modified by Neelakandan Manihatty Bojan, Georgina Kalogeridou + +import logging +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) + +from NFTest import * +import sys +import os +from scapy.layers.all import Ether, IP, TCP +from reg_defines_reference_dma import * + +phy2loop0 = ('../connections/conn', []) +nftest_init(sim_loop = [], hw_config = [phy2loop0]) + +if isHW(): + # reset_counters (triggered by Write only event) for all the modules + nftest_regwrite(NFPLUS_INPUT_ARBITER_0_RESET(), 0x1) + nftest_regwrite(NFPLUS_OUTPUT_PORT_LOOKUP_0_RESET(), 0x101) + nftest_regwrite(NFPLUS_OUTPUT_QUEUES_0_RESET(), 0x1) + + # Reset the switch table lookup counters (value is reset every time is read) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT()) + nftest_regread(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS()) + +nftest_start() + + +routerMAC = [] +routerIP = [] +for i in range(2): + routerMAC.append("00:0a:35:03:00:0%d"%(i+1)) + routerIP.append("192.168.%s.40"%i) + +num_broadcast = 20 + +pkts = [] +for i in range(num_broadcast): + pkt = make_IP_pkt(src_MAC="aa:bb:cc:dd:ee:ff", dst_MAC=routerMAC[0], + EtherType=0x800, src_IP="192.168.0.1", + dst_IP="192.168.1.1", pkt_len=60) + + pkt.time = ((i*(1e-8)) + (2e-6)) + pkts.append(pkt) + if isHW(): + nftest_expect_phy('nf1', pkt) + nftest_send_phy('nf0', pkt) + +if not isHW(): + nftest_send_phy('nf0', pkts) + nftest_expect_phy('nf1', pkts) + +nftest_barrier() + +if isHW(): + # Expecting the LUT_MISS counter to be incremented by 0x14, 20 packets + rres1=nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) + rres2=nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), 0) + mres=[rres1,rres2] +else: + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTMISS(), num_broadcast) # lut_miss + nftest_regread_expect(NFPLUS_OUTPUT_PORT_LOOKUP_0_LUTHIT(), 0) # lut_hit + mres=[] + +nftest_finish(mres) diff --git a/hw/projects/reference_dma/test/connections/conn b/hw/projects/reference_dma/test/connections/conn new file mode 100644 index 0000000..0827e9b --- /dev/null +++ b/hw/projects/reference_dma/test/connections/conn @@ -0,0 +1,30 @@ +# +# Copyright (c) 2015 University of Cambridge +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + + +nf0:eth1 +nf1:eth2 diff --git a/hw/projects/reference_dma/test/global/setup b/hw/projects/reference_dma/test/global/setup new file mode 100644 index 0000000..1d4cdb9 --- /dev/null +++ b/hw/projects/reference_dma/test/global/setup @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2015 University of Cambridge +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +from subprocess import Popen, PIPE + +proc = Popen(["ifconfig","eth1","192.168.100.1"], stdout=PIPE) +proc = Popen(["ifconfig","eth2","192.168.101.1"], stdout=PIPE) +proc = Popen(["ifconfig","nf0","192.168.200.1"], stdout=PIPE) +proc = Popen(["ifconfig","nf1","192.168.201.1"], stdout=PIPE) diff --git a/hw/projects/reference_dma/test/sim_simple_send/run.py b/hw/projects/reference_dma/test/sim_simple_send/run.py new file mode 100755 index 0000000..cf7f3f5 --- /dev/null +++ b/hw/projects/reference_dma/test/sim_simple_send/run.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2015 University of Cambridge +# Copyright (c) 2015 Neelakandan Manihatty Bojan, Georgina Kalogeridou +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme, +# and by the University of Cambridge Computer Laboratory under EPSRC EARL Project +# EP/P025374/1 alongside support from Xilinx Inc. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +# Author: +# Modified by Neelakandan Manihatty Bojan, Georgina Kalogeridou + +import logging +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) + +from NFTest import * +import sys +import os +from scapy.layers.all import Ether +from reg_defines_reference_dma import * + +conn = ('../connections/conn', []) +nftest_init(sim_loop = ['nf0', 'nf1'], hw_config = [conn]) + +nftest_start() # BARRIER 1 + +# Enable the datasink counters +nftest_regwrite(NFPLUS_NF_DATA_SINK_0_RESET(), 0x1) # reset counters +nftest_regwrite(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x1) + +nftest_barrier() # BARRIER 2 + +# set parameters +SA = "aa:bb:cc:dd:ee:ff" +nextHopMAC = "dd:55:dd:66:dd:77" +NUM_PKTS = 5 +num_ports = 1 +pkts = [] + +print("Sending now: ") +totalPktLengths = [0,0] +# send NUM_PKTS from ports nf2c0...nf2c1 +for i in range(NUM_PKTS): + DA = "00:ca:fe:00:00:00" + pkt = Ether()/'012345678901234567890123456789012345678901234567890123456789' + pkt.time = ((i*(1e-8)) + (2e-7)) + pkts.append(pkt) + +nftest_send_dma('nf0', pkts) + +print("") + +nftest_barrier() # BARRIER 3 + +# sample the counters registers +nftest_regwrite(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x3) + +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x503) # 5 pkts. active. enabled. +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_BYTESINLO(), 0x140) +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_BYTESINHI(), 0x0) +time_clocks = nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_TIME(), 0x2) +print(f"Number of clocks sampled is {time_clocks}.") + +# Disable collection and reset counters and state. +nftest_regwrite(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x0) +# Enable collection +nftest_regwrite(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x1) + +nftest_barrier() # BARRIER 4 + +pkts = [] +pkt = Ether()/('012345678901234567890123456789012345678901234567890123456789'*20) +pkt.time = ((1e-8) + (2e-7)) +pkts.append(pkt) + +nftest_send_dma('nf0', pkts) + +nftest_barrier() # BARRIER 5 + +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x1) +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x1) + +# sample the counters registers +nftest_regwrite(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x3) + +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_ENABLE(), 0x503) # 5 pkts. active. enabled. +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_BYTESINLO(), 0x40) +nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_BYTESINHI(), 0x0) +time_clocks = nftest_regread_expect(NFPLUS_NF_DATA_SINK_0_TIME(), 0x0) +print(f"Number of clocks sampled is {time_clocks}.") + +mres=[] + +nftest_finish(mres) # BARRIER FINAL diff --git a/hw/projects/reference_switch/hw/tcl/reference_switch.tcl b/hw/projects/reference_switch/hw/tcl/reference_switch.tcl index 29276bc..12b283e 100644 --- a/hw/projects/reference_switch/hw/tcl/reference_switch.tcl +++ b/hw/projects/reference_switch/hw/tcl/reference_switch.tcl @@ -47,6 +47,26 @@ set datapath_freq_mhz 340 set opl_bcam_size 16 set opl_cam_depth_bits [expr int(log(${opl_bcam_size})/log(2))] +##################################### +# Limit messages reported +# These are typically not helpful. +# But if you really want to see all messages +# then set suppress_unwanted_warnings to 0. +##################################### +set suppress_unwanted_warnings 1 +if {$suppress_unwanted_warnings == 1} { + set_msg_config -id "Synth 8-11241" -limit 1 + set_msg_config -id "Synth 8-6014" -limit 1 + set_msg_config -id "Synth 8-3848" -limit 1 + set_msg_config -id "Synth 8-7129" -limit 1 + set_msg_config -id "Synth 8-10592" -limit 1 + set_msg_config -id "Synth 8-7154" -limit 1 + set_msg_config -id "Synth 8-223" -limit 1 + set_msg_config -id "Synth 8-3332" -limit 1 + set_msg_config -id "Synth 8-3886" -limit 1 + set_msg_config -id "Synth 8-5396" -limit 1 +} + ##################################### # Project Settings ##################################### @@ -88,9 +108,11 @@ if {[string match $board_name "au280"]} { } elseif {[string match $board_name "vcu1525"]} { add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au200_vcu1525_timing.tcl add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl -} else { +} elseif {[string match $board_name "au250"]} { add_files -fileset constraints -norecurse ${public_repo_dir}/common/constraints/au250_timing.tcl add_files -fileset constraints -norecurse ./constraints/au250_au200_vcu1525_user_timing.tcl +} else { + puts "ERROR: Unknown Board type $board_name" } set_property is_enabled true [get_files ${project_constraints}] set_property constrset constraints [get_runs synth_1] diff --git a/sw/app/dpdk/qdma_testapp/Makefile b/sw/app/dpdk/qdma_testapp/Makefile new file mode 100644 index 0000000..486d126 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/Makefile @@ -0,0 +1,100 @@ +# BSD LICENSE +# +# Copyright(c) 2017-2021 Xilinx, Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifeq ($(RTE_SDK),) +#$(error "Please define RTE_SDK environment variable") +#endif + +# Default target, can be overriden by command line or environment +RTE_TARGET ?= build + +#Default BRAM size is set to 512K +#if modified the BRAM_SIZE, the same need to be set to the driver Makefile +BRAM_SIZE ?= 524288 + +# binary name +APP = qdma_testapp + +# all source are stored in SRCS-y +SRCS-y := testapp.c pcierw.c commands.c nfds_lib.c + +ifeq ($(CONFIG_RTE_LIBRTE_QDMA_GCOV),y) + CFLAGS += -g -ftest-coverage -fprofile-arcs + LDFLAGS += -lgcov +endif + +# Build using pkg-config variables if possible +ifneq ($(shell pkg-config --exists libdpdk && echo 0),0) +$(error "no installation of DPDK found") +endif + +all: shared +.PHONY: shared static +shared: build/$(APP)-shared + ln -sf $(APP)-shared build/$(APP) +static: build/$(APP)-static + ln -sf $(APP)-static build/$(APP) + +PKGCONF ?= pkg-config + +CFLAGS += -DBRAM_SIZE=$(BRAM_SIZE) +CFLAGS += -DDPDK=1 +# CFLAGS += -DDUMP_MEMPOOL_USAGE_STATS +CFLAGS += -DPERF_BENCHMARK +# Adding NO_FILE_READ means that file is not actually read. Just use whatever data is in mbufs. +# CFLAGS += -DNO_FILE_READ + +# Add flag to allow experimental API as qdma_testapp uses rte_ethdev_set_ptype API +CFLAGS += -DALLOW_EXPERIMENTAL_API + +PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null) +CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) +LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) +LDFLAGS_STATIC = $(shell $(PKGCONF) --static --libs libdpdk) +LDFLAGS += $(shell $(PKGCONF) --libs libdpdk) + +LDFLAGS += -lrte_net_qdma + +# for shared library builds, we need to explicitly link these PMDs +LDFLAGS_SHARED += -lrte_net_qdma + +build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) + +build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) + +build: + @mkdir -p $@ + +.PHONY: clean +clean: + rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared + test -d build && rmdir -p build || true diff --git a/sw/app/dpdk/qdma_testapp/commands.c b/sw/app/dpdk/qdma_testapp/commands.c new file mode 100644 index 0000000..7053250 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/commands.c @@ -0,0 +1,1390 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2020 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2009, Olivier MATZ + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef __linux__ +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "parse_obj_list.h" +#include "pcierw.h" +#include "commands.h" +#include "qdma_regs.h" +#include "testapp.h" +#include "nfds_lib.h" + +#define ALIGN_TO_WORD_BYTES (4) +#define NUMERICAL_BASE_HEXADECIMAL (16) + +/* Command help */ +struct cmd_help_result { + cmdline_fixed_string_t help; +}; + +static void cmd_help_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, + "Demo example of command line interface in RTE\n\n" + "This is a readline-like interface that can be " + "used to\n debug your RTE application.\n\n" + "Supported Commands:\n" + "\tport_init " + " " + " " + " :port-initailization\n" + "\tport_close " + ":port-close\n" + "\tport_reset " + " " + " " + " :port-reset\n" + "\tport_remove " + ":port-remove\n" + "\treg_read
" + ":Reads Specified Register\n" + "\treg_write
" + " " + ":Writes Specified Register\n" + "\tdma_to_device " + " " + " " + ":To Transmit\n" + "\tdma_from_device " + " " + " " + ":To Receive\n" + "\treg_dump " + ":To dump all the valid registers\n" + "\treg_info_read " + ":Reads the field info for the specified number of registers\n" + "\tqueue_dump " + ":To dump the queue-context of a queue-number\n" + "\tdesc_dump " + ":To dump the descriptor-fields of a " + "queue-number\n" + "\tload_cmds " + ":To execute the list of commands from file\n" + "\thelp\n" + "\tCtrl-d " + ": To quit from this command-line type Ctrl+d\n" + "\n"); +} + +cmdline_parse_token_string_t cmd_help_help = + TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help"); + +cmdline_parse_inst_t cmd_help = { + .f = cmd_help_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "show help", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_help_help, + NULL, + }, +}; + +struct cmd_obj_port_init_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t num_queues; + cmdline_fixed_string_t st_queues; + cmdline_fixed_string_t nb_descs; + cmdline_fixed_string_t buff_size; +}; + +static void cmd_obj_port_init_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_port_init_result *res = parsed_result; + + cmdline_printf(cl, "Port-init Port:%s, num-queues:%s, st-queues: %s\n", + res->port_id, res->num_queues, res->st_queues); + + int port_id = atoi(res->port_id); + if (pinfo[port_id].num_queues) { + cmdline_printf(cl, "Error: port-id:%d already initialized\n" + "To re-initialize please close the port\n", + port_id); + return; + } + + int num_queues = atoi(res->num_queues); + int st_queues = atoi(res->st_queues); + int nb_descs = atoi(res->nb_descs); + int buff_size = atoi(res->buff_size); + + if ((num_queues < 1) || (num_queues > MAX_NUM_QUEUES)) { + cmdline_printf(cl, "Error: please enter valid number of queues," + "entered: %d max allowed: %d\n", + num_queues, MAX_NUM_QUEUES); + return; + } + + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: please enter valid port number: " + "%d\n", port_id); + return; + } + + int result = port_init(port_id, num_queues, + st_queues, nb_descs, buff_size); + + if (result < 0) + cmdline_printf(cl, "Error: Port initialization on " + "port-id:%d failed\n", port_id); + else + cmdline_printf(cl, "Port initialization done " + "successfully on port-id:%d\n", + port_id); +} + +cmdline_parse_token_string_t cmd_obj_action_port_init = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_init_result, action, + "port_init"); +cmdline_parse_token_string_t cmd_obj_port_init_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_init_result, port_id, + NULL); +cmdline_parse_token_string_t cmd_obj_port_init_num_queues = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_init_result, num_queues, + NULL); +cmdline_parse_token_string_t cmd_obj_port_init_st_queues = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_init_result, st_queues, + NULL); +cmdline_parse_token_string_t cmd_obj_port_init_nb_descs = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_init_result, nb_descs, + NULL); +cmdline_parse_token_string_t cmd_obj_port_init_buff_size = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_init_result, buff_size, + NULL); + +cmdline_parse_inst_t cmd_obj_port_init = { + .f = cmd_obj_port_init_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "port_init port-id num-queues st-queues " + "queue-ring-size buffer-size", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_port_init, + (void *)&cmd_obj_port_init_port_id, + (void *)&cmd_obj_port_init_num_queues, + (void *)&cmd_obj_port_init_st_queues, + (void *)&cmd_obj_port_init_nb_descs, + (void *)&cmd_obj_port_init_buff_size, + NULL, + }, +}; + +/* Command port-close */ +struct cmd_obj_port_close_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; +}; + +static void cmd_obj_port_close_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_port_close_result *res = parsed_result; + + cmdline_printf(cl, "Port-close on Port-id:%s\n", res->port_id); + + int port_id = atoi(res->port_id); + if (pinfo[port_id].num_queues == 0) { + cmdline_printf(cl, "Error: port-id:%d already closed\n", + port_id); + return; + } + + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: please enter valid port " + "number: %d\n", port_id); + return; + } + + port_close(port_id); + pinfo[port_id].num_queues = 0; + cmdline_printf(cl, "Port-id:%d closed successfully\n", port_id); +} + +cmdline_parse_token_string_t cmd_obj_action_port_close = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_close_result, action, + "port_close"); +cmdline_parse_token_string_t cmd_obj_port_close_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_close_result, port_id, + NULL); + +cmdline_parse_inst_t cmd_obj_port_close = { + .f = cmd_obj_port_close_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "port_close port-id ", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_port_close, + (void *)&cmd_obj_port_close_port_id, + NULL, + }, + +}; + +/* Command port-reset */ +struct cmd_obj_port_reset_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t num_queues; + cmdline_fixed_string_t st_queues; + cmdline_fixed_string_t nb_descs; + cmdline_fixed_string_t buff_size; +}; + +static void cmd_obj_port_reset_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_port_reset_result *res = parsed_result; + + cmdline_printf(cl, "Port-reset Port:%s, num-queues:%s, st-queues: %s\n", + res->port_id, res->num_queues, res->st_queues); + + int port_id = atoi(res->port_id); + int num_queues = atoi(res->num_queues); + int st_queues = atoi(res->st_queues); + int nb_descs = atoi(res->nb_descs); + int buff_size = atoi(res->buff_size); + + if ((num_queues < 1) || (num_queues > MAX_NUM_QUEUES)) { + cmdline_printf(cl, "Error: please enter valid number of queues," + "entered: %d max allowed: %d\n", + num_queues, MAX_NUM_QUEUES); + return; + } + + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: please enter valid port number: " + "%d\n", port_id); + return; + } + + int result = port_reset(port_id, num_queues, + st_queues, nb_descs, buff_size); + + if (result < 0) + cmdline_printf(cl, "Error: Port reset on " + "port-id:%d failed\n", port_id); +} + +cmdline_parse_token_string_t cmd_obj_action_port_reset = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_reset_result, action, + "port_reset"); +cmdline_parse_token_string_t cmd_obj_port_reset_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_reset_result, port_id, + NULL); +cmdline_parse_token_string_t cmd_obj_port_reset_num_queues = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_reset_result, num_queues, + NULL); +cmdline_parse_token_string_t cmd_obj_port_reset_st_queues = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_reset_result, st_queues, + NULL); +cmdline_parse_token_string_t cmd_obj_port_reset_nb_descs = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_reset_result, nb_descs, + NULL); +cmdline_parse_token_string_t cmd_obj_port_reset_buff_size = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_reset_result, buff_size, + NULL); + +cmdline_parse_inst_t cmd_obj_port_reset = { + .f = cmd_obj_port_reset_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "port_reset port-id num-queues st-queues " + "queue-ring-size buffer-size", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_port_reset, + (void *)&cmd_obj_port_reset_port_id, + (void *)&cmd_obj_port_reset_num_queues, + (void *)&cmd_obj_port_reset_st_queues, + (void *)&cmd_obj_port_reset_nb_descs, + (void *)&cmd_obj_port_reset_buff_size, + NULL, + }, +}; + +/* Command port-remove */ +struct cmd_obj_port_remove_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; +}; + +static void cmd_obj_port_remove_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_port_remove_result *res = parsed_result; + + cmdline_printf(cl, "Port-remove on Port-id:%s\n", res->port_id); + + int port_id = atoi(res->port_id); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: please enter valid port " + "number: %d\n", port_id); + return; + } + + int result = port_remove(port_id); + pinfo[port_id].num_queues = 0; + + if (result < 0) + cmdline_printf(cl, "Error: Port remove on " + "port-id:%d failed\n", port_id); +} + +cmdline_parse_token_string_t cmd_obj_action_port_remove = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_remove_result, action, + "port_remove"); +cmdline_parse_token_string_t cmd_obj_port_remove_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_port_remove_result, port_id, + NULL); + +cmdline_parse_inst_t cmd_obj_port_remove = { + .f = cmd_obj_port_remove_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "port_remove port-id ", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_port_remove, + (void *)&cmd_obj_port_remove_port_id, + NULL, + }, +}; + +/* Command Read addr */ +struct cmd_obj_reg_read_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t bar_id; + cmdline_fixed_string_t addr; +}; + +static void cmd_obj_reg_read_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_reg_read_result *res = parsed_result; + + cmdline_printf(cl, "Read Port:%s, BAR-index:%s, Address:%s\n\n", + res->port_id, res->bar_id, res->addr); + + int addr = strtol(res->addr, NULL, NUMERICAL_BASE_HEXADECIMAL); + + if (addr % ALIGN_TO_WORD_BYTES) { + cmdline_printf(cl, "ERROR: Read address must aligned to " + "a 4-byte boundary.\n\n"); + } else { + int port_id = atoi(res->port_id); + int bar_id = atoi(res->bar_id); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n " + "Please enter valid port-id\n", + port_id); + return; + } + int result = PciRead(bar_id, addr, port_id); + + cmdline_printf(cl, "Read (%d:0x%08x) = 0x%08x\n", + port_id, addr, result); + } +} + +cmdline_parse_token_string_t cmd_obj_action_reg_read = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_read_result, action, + "reg_read"); +cmdline_parse_token_string_t cmd_obj_reg_read_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_read_result, port_id, NULL); +cmdline_parse_token_string_t cmd_obj_reg_read_bar_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_read_result, bar_id, NULL); +cmdline_parse_token_string_t cmd_obj_reg_read_addr = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_read_result, addr, NULL); + +cmdline_parse_inst_t cmd_obj_reg_read = { + .f = cmd_obj_reg_read_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "reg_read port-id bar-id address", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_reg_read, + (void *)&cmd_obj_reg_read_port_id, + (void *)&cmd_obj_reg_read_bar_id, + (void *)&cmd_obj_reg_read_addr, + NULL, + }, + +}; + +/* Command Write addr */ +struct cmd_obj_reg_write_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t bar_id; + cmdline_fixed_string_t address; + cmdline_fixed_string_t value; +}; + +static void cmd_obj_reg_write_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_reg_write_result *res = parsed_result; + + cmdline_printf(cl, "Write Port:%s, Address:%s, Value:%s\n", + res->port_id, res->address, res->value); + + int bar_id = atoi(res->bar_id); + int port_id = atoi(res->port_id); + int addr = strtol(res->address, NULL, NUMERICAL_BASE_HEXADECIMAL); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n " + "Please enter valid port-id\n", port_id); + return; + } + if (addr % ALIGN_TO_WORD_BYTES) { + cmdline_printf(cl, "ERROR: Write address must aligned to a " + "4-byte boundary.\n\n"); + } else{ + int value = strtol(res->value, NULL, NUMERICAL_BASE_HEXADECIMAL); + PciWrite(bar_id, addr, value, port_id); + int result = PciRead(bar_id, addr, port_id); + cmdline_printf(cl, "Read (%d:0x%08x) = 0x%08x\n", port_id, addr, + result); + } +} + +cmdline_parse_token_string_t cmd_obj_action_reg_write = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_write_result, action, + "reg_write"); +cmdline_parse_token_string_t cmd_obj_reg_write_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_write_result, port_id, + NULL); +cmdline_parse_token_string_t cmd_obj_reg_write_bar_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_write_result, bar_id, NULL); +cmdline_parse_token_string_t cmd_obj_reg_write_address = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_write_result, address, + NULL); +cmdline_parse_token_string_t cmd_obj_reg_write_value = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_write_result, value, NULL); + +cmdline_parse_inst_t cmd_obj_reg_write = { + .f = cmd_obj_reg_write_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "reg_write port-id bar-id address value", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_reg_write, + (void *)&cmd_obj_reg_write_port_id, + (void *)&cmd_obj_reg_write_bar_id, + (void *)&cmd_obj_reg_write_address, + (void *)&cmd_obj_reg_write_value, + NULL, + }, + +}; + +/* Command do-xmit */ +struct cmd_obj_dma_to_device_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t queues; + cmdline_fixed_string_t filename; + cmdline_fixed_string_t dst_addr; + cmdline_fixed_string_t size; + cmdline_fixed_string_t loops; +}; + +static void cmd_obj_dma_to_device_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_dma_to_device_result *res = parsed_result; + int i, ifd, tot_num_desc, offset, size, r_size = 0, total_size = 0; + int ld_size = 0, loop = 0, ret, j, zbyte = 0, user_bar_idx; + off_t ret_val; + int port_id = 0, num_queues = 0, input_size = 0, num_loops = 0; + int dst_addr = 0; + uint32_t regval = 0; + unsigned int q_data_size = 0; + ds_sample_t sample_data; + + cmdline_printf(cl, "xmit on Port:%s, filename:%s, num-queues:%s\n\n", + res->port_id, res->filename, res->queues); + + ifd = open(res->filename, O_RDWR); + if (ifd < 0) { + cmdline_printf(cl, "Error: Invalid filename: %s\n", + res->filename); + return; + } + + { + port_id = atoi(res->port_id); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n " + "Please enter valid port-id\n", + port_id); + close(ifd); + return; + } + num_queues = atoi(res->queues); + if ((unsigned int)num_queues > pinfo[port_id].num_queues) { + cmdline_printf(cl, "Error: num-queues:%d are more than " + "the configured queues:%d,\n " + "Please enter valid number of queues\n", + num_queues, pinfo[port_id].num_queues); + close(ifd); + return; + } + if (num_queues == 0) { + cmdline_printf(cl, "Error: Please enter valid number " + "of queues\n"); + close(ifd); + return; + } + user_bar_idx = pinfo[port_id].user_bar_idx; + regval = PciRead(user_bar_idx, C2H_CONTROL_REG, port_id); + + input_size = atoi(res->size); + num_loops = atoi(res->loops); + dst_addr = atoi(res->dst_addr); + +#ifndef PERF_BENCHMARK + if (dst_addr + input_size > BRAM_SIZE) { + cmdline_printf(cl, "Error: (dst_addr %d + input size " + "%d) shall be less than " + "BRAM_SIZE %d.\n", dst_addr, + input_size, BRAM_SIZE); + close(ifd); + return; + } +#endif + /* For zero-byte transfers, HW expects a + * buffer of length 4kb and with desc->len as 0. + */ + if (input_size == 0) { + if ((unsigned int)num_queues <= + pinfo[port_id].st_queues) { + zbyte = 1; + } else { + cmdline_printf(cl, "Error: Zero-length support " + "is for queues with ST-mode " + "only\n"); + close(ifd); + return; + } + } + + if (input_size % num_queues) { + size = input_size / num_queues; + r_size = input_size % num_queues; + } else + size = input_size / num_queues; + + /* enable the data sink module to gather stats */ + nfds_enable(port_id); + + do { + total_size = input_size; + dst_addr = atoi(res->dst_addr); + q_data_size = 0; + /* transmit data on the number of Queues configured + * from the input file + */ + for (i = 0, j = 0; i < num_queues; i++, j++) { + dst_addr += q_data_size; + dst_addr %= BRAM_SIZE; + + if ((unsigned int)i >= + pinfo[port_id].st_queues) { + ret = + rte_pmd_qdma_set_mm_endpoint_addr( + port_id, + i, + RTE_PMD_QDMA_TX, + dst_addr); + if (ret < 0) { + close(ifd); + return; + } + } + + if (total_size == 0) + q_data_size = pinfo[port_id].buff_size; + else if (total_size == (r_size + size)) { + q_data_size = total_size; + total_size = 0; + } else { + q_data_size = size; + total_size -= size; + } + + if (q_data_size >= pinfo[port_id].buff_size) { + if (q_data_size % + pinfo[port_id].buff_size) { + tot_num_desc = (q_data_size / + pinfo[port_id].buff_size) + 1; + ld_size = q_data_size % + pinfo[port_id].buff_size; + } else + tot_num_desc = (q_data_size / + pinfo[port_id].buff_size); + } else { + tot_num_desc = 1; + ld_size = q_data_size % + pinfo[port_id].buff_size; + } + + if (port_id) + offset = (input_size/num_queues) * j; + else + offset = (input_size/num_queues) * i; + + if ((unsigned int)i < (pinfo[port_id].st_queues) + && !(regval & ST_LOOPBACK_EN)) + ret_val = lseek(ifd, 0, SEEK_SET); + else + ret_val = lseek(ifd, offset, SEEK_SET); + + if (ret_val == (off_t)-1) { + cmdline_printf(cl, "DMA-to-Device: " + "lseek func failed\n"); + close(ifd); + return; + } + + cmdline_printf(cl, "DMA-to-Device: with " + "input-size:%d, ld_size:%d," + "tot_num_desc:%d\n", + input_size, ld_size, + tot_num_desc); + ret = do_xmit(port_id, ifd, i, ld_size, + tot_num_desc, zbyte); + if (ret < 0) { + close(ifd); + return; + } + } + ++loop; + } while (loop < num_loops); + + rte_delay_us_sleep(1000000); + + nfds_get_sample(port_id, &sample_data); + cmdline_printf(cl,"\nsampled_data: periods=%d bytes=%0ld pkts=%d\n", + sample_data.num_ds_periods, + sample_data.num_bytes, + sample_data.num_packets + ); + cmdline_printf(cl,"--- Perf was %9.3f Mbps\n", + nfds_compute_performance_bps(240000000.0, &sample_data)/1000000.0); + nfds_disable(port_id); + + close(ifd); + } + cmdline_printf(cl, "\n######## DMA transfer to device is completed " + "successfully #######\n"); +} + +cmdline_parse_token_string_t cmd_obj_action_dma_to_device = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_to_device_result, action, + "dma_to_device"); +cmdline_parse_token_string_t cmd_obj_dma_to_device_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_to_device_result, port_id, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_to_device_queues = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_to_device_result, queues, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_to_device_filename = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_to_device_result, filename, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_to_device_dst_addr = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_to_device_result, dst_addr, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_to_device_size = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_to_device_result, size, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_to_device_loops = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_to_device_result, loops, + NULL); + +cmdline_parse_inst_t cmd_obj_dma_to_device = { + .f = cmd_obj_dma_to_device_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "dma_to_device port-id num-queues filename dst_addr " + "size loops", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_dma_to_device, + (void *)&cmd_obj_dma_to_device_port_id, + (void *)&cmd_obj_dma_to_device_queues, + (void *)&cmd_obj_dma_to_device_filename, + (void *)&cmd_obj_dma_to_device_dst_addr, + (void *)&cmd_obj_dma_to_device_size, + (void *)&cmd_obj_dma_to_device_loops, + NULL, + }, + +}; + +/* Command do-recv */ +struct cmd_obj_dma_from_device_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t queues; + cmdline_fixed_string_t filename; + cmdline_fixed_string_t src_addr; + cmdline_fixed_string_t size; + cmdline_fixed_string_t loops; +}; + +static void cmd_obj_dma_from_device_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_dma_from_device_result *res = parsed_result; + int i, ofd, offset, size, total_size, r_size = 0; + int mm_tdesc, mm_ld_size = 0; + int loop = 0, ret, j; + off_t ret_val; + int port_id = 0, num_queues = 0, input_size = 0, num_loops = 0; + int src_addr = 0; + unsigned int q_data_size = 0; + + cmdline_printf(cl, "recv on Port:%s, filename:%s\n", + res->port_id, res->filename); + + ofd = open(res->filename, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0666); + if (ofd < 0) { + cmdline_printf(cl, "Error: Invalid filename: %s\n", + res->filename); + return; + } + + { + port_id = atoi(res->port_id); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n " + "Please enter valid port-id\n", + port_id); + close(ofd); + return; + } + num_queues = atoi(res->queues); + if ((unsigned int)num_queues > pinfo[port_id].num_queues) { + cmdline_printf(cl, "Error: num-queues:%d are more than " + "the configured queues:%d,\n" + "Please enter valid number of queues\n", + num_queues, pinfo[port_id].num_queues); + close(ofd); + return; + } + if (num_queues == 0) { + cmdline_printf(cl, "Error: Please enter valid number " + "of queues\n"); + close(ofd); + return; + } + input_size = atoi(res->size); + num_loops = atoi(res->loops); + src_addr = atoi(res->src_addr); +#ifndef PERF_BENCHMARK + if (src_addr + input_size > BRAM_SIZE) { + cmdline_printf(cl, "Error: (src_addr %d + input " + "size %d) shall be less than " + "BRAM_SIZE %d.\n", src_addr, + input_size, BRAM_SIZE); + close(ofd); + return; + } +#endif + /* Restrict C2H zerobyte support to ST-mode queues*/ + if (input_size == 0) { + if ((unsigned int)num_queues > + pinfo[port_id].st_queues) { + cmdline_printf(cl, "Error: Zero-length support " + "is for queues with ST-mode only\n"); + close(ofd); + return; + } + } + + if (input_size % num_queues) { + size = input_size / num_queues; + r_size = input_size % num_queues; + } else + size = input_size / num_queues; + + do { + total_size = input_size; + src_addr = atoi(res->src_addr); + q_data_size = 0; + /* Transmit data on the number of Queues configured + * from the input file + */ + for (i = 0, j = 0; i < num_queues; i++, j++) { + src_addr += q_data_size; + src_addr %= BRAM_SIZE; + + if ((unsigned int)i >= + pinfo[port_id].st_queues) { + ret = + rte_pmd_qdma_set_mm_endpoint_addr( + port_id, + i, + RTE_PMD_QDMA_RX, + src_addr); + if (ret < 0) { + close(ofd); + return; + } + } + + if (total_size == (r_size + size)) { + q_data_size = total_size; + total_size = 0; + } else { + q_data_size = size; + total_size -= size; + } + + if (q_data_size >= pinfo[port_id].buff_size) { + if (q_data_size % + pinfo[port_id].buff_size) { + mm_tdesc = (q_data_size / + pinfo[port_id].buff_size) + 1; + + mm_ld_size = q_data_size % + pinfo[port_id].buff_size; + } else + mm_tdesc = (q_data_size / + pinfo[port_id].buff_size); + } else { + mm_tdesc = 1; + mm_ld_size = q_data_size % + pinfo[port_id].buff_size; + } + + if (port_id) + offset = (input_size/num_queues) * j; + else + offset = (input_size/num_queues) * i; + + ret_val = lseek(ofd, offset, SEEK_SET); + if (ret_val == (off_t)-1) { + cmdline_printf(cl, "DMA-to-Device: " + "lseek func failed\n"); + close(ofd); + return; + } + + cmdline_printf(cl, "DMA-from-Device: with " + "input-size:%d, ld_size:%d, " + "tot_num_desc:%d\n", + input_size, mm_ld_size, + mm_tdesc); + + if ((unsigned int)i < + (pinfo[port_id].st_queues)) + ret = do_recv_st(port_id, ofd, i, + q_data_size); + else + ret = do_recv_mm(port_id, ofd, i, + mm_ld_size, + mm_tdesc); + if (ret < 0) { + close(ofd); + return; + } + + ret_val = lseek(ofd, offset, SEEK_END); + if (ret_val == (off_t)-1) { + cmdline_printf(cl, "DMA-to-Device: " + "lseek func failed\n"); + close(ofd); + return; + } + } + ++loop; + } while (loop < num_loops); + close(ofd); + } + cmdline_printf(cl, "\n####### DMA transfer from device is completed " + "successfully #######\n"); +} + +cmdline_parse_token_string_t cmd_obj_action_dma_from_device = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_from_device_result, action, + "dma_from_device"); +cmdline_parse_token_string_t cmd_obj_dma_from_device_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_from_device_result, port_id, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_from_device_queues = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_from_device_result, queues, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_from_device_filename = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_from_device_result, + filename, NULL); +cmdline_parse_token_string_t cmd_obj_dma_from_device_src_addr = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_from_device_result, + src_addr, NULL); +cmdline_parse_token_string_t cmd_obj_dma_from_device_size = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_from_device_result, size, + NULL); +cmdline_parse_token_string_t cmd_obj_dma_from_device_loops = + TOKEN_STRING_INITIALIZER(struct cmd_obj_dma_from_device_result, loops, + NULL); + +cmdline_parse_inst_t cmd_obj_dma_from_device = { + .f = cmd_obj_dma_from_device_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "dma_from_device port_id num-queues filename " + "src_addr size loops", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_dma_from_device, + (void *)&cmd_obj_dma_from_device_port_id, + (void *)&cmd_obj_dma_from_device_queues, + (void *)&cmd_obj_dma_from_device_filename, + (void *)&cmd_obj_dma_from_device_src_addr, + (void *)&cmd_obj_dma_from_device_size, + (void *)&cmd_obj_dma_from_device_loops, + NULL, + }, + +}; + +struct cmd_obj_reg_dump_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; +}; + +static void cmd_obj_reg_dump_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_reg_dump_result *res = parsed_result; + + + int bar_id; + int port_id = atoi(res->port_id); + + bar_id = pinfo[port_id].config_bar_idx; + if (bar_id < 0) { + cmdline_printf(cl, "Error: fetching QDMA config BAR-id " + "on port-id:%d not supported\n Please enter " + "valid port-id\n", port_id); + return; + } + cmdline_printf(cl, "Register dump on cofig BAR-id:%d with Port-id:%s\n", + bar_id, res->port_id); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n " + "Please enter valid port-id\n", + port_id); + return; + } + rte_pmd_qdma_dbg_regdump(port_id); +} + +cmdline_parse_token_string_t cmd_obj_action_reg_dump = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_dump_result, action, + "reg_dump"); +cmdline_parse_token_string_t cmd_obj_reg_dump_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_dump_result, port_id, NULL); + +cmdline_parse_inst_t cmd_obj_reg_dump = { + .f = cmd_obj_reg_dump_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "reg_dump port-id", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_reg_dump, + (void *)&cmd_obj_reg_dump_port_id, + NULL, + }, + +}; + + +/* Command Read Info addr */ +struct cmd_obj_reg_info_read_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t reg_addr; + cmdline_fixed_string_t num_regs; +}; + +static void cmd_obj_reg_info_read_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_reg_info_read_result *res = parsed_result; + + cmdline_printf(cl, "Read Reg info Port:%s, Address:%s, Num Regs: %s\n\n", + res->port_id, res->reg_addr, res->num_regs); + + int reg_addr = strtol(res->reg_addr, NULL, NUMERICAL_BASE_HEXADECIMAL); + + if (reg_addr % ALIGN_TO_WORD_BYTES) { + cmdline_printf(cl, "ERROR: Read address must aligned to " + "a 4-byte boundary.\n\n"); + } else { + int port_id = atoi(res->port_id); + int num_regs = atoi(res->num_regs); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n " + "Please enter valid port-id\n", + port_id); + return; + } + rte_pmd_qdma_dbg_reg_info_dump(port_id, num_regs,reg_addr); + } +} + +cmdline_parse_token_string_t cmd_obj_action_reg_info_read = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_info_read_result, action, + "reg_info_read"); +cmdline_parse_token_string_t cmd_obj_reg_info_read_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_info_read_result, port_id, NULL); +cmdline_parse_token_string_t cmd_obj_reg_info_read_reg_addr = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_info_read_result, reg_addr, NULL); +cmdline_parse_token_string_t cmd_obj_reg_info_read_num_regs = + TOKEN_STRING_INITIALIZER(struct cmd_obj_reg_info_read_result, num_regs, NULL); + +cmdline_parse_inst_t cmd_obj_reg_info_read = { + .f = cmd_obj_reg_info_read_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "reg_info_read port-id reg-addr", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_reg_info_read, + (void *)&cmd_obj_reg_info_read_port_id, + (void *)&cmd_obj_reg_info_read_reg_addr, + (void *)&cmd_obj_reg_info_read_num_regs, + NULL, + }, + +}; + + +/*Command queue-context dump*/ + +struct cmd_obj_queue_dump_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t queue_id; +}; + +static void cmd_obj_queue_dump_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_queue_dump_result *res = parsed_result; + + cmdline_printf(cl, "queue-dump on Port:%s, queue-id:%s\n\n", + res->port_id, res->queue_id); + + { + int port_id = atoi(res->port_id); + int qid = atoi(res->queue_id); + int bar_id = 0x0; + + bar_id = pinfo[port_id].config_bar_idx; + if (bar_id < 0) { + cmdline_printf(cl, "Error: fetching QDMA config BAR-id " + "on port-id:%d not supported\n Please " + "enter valid port-id\n", port_id); + return; + } + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n " + "Please enter valid port-id\n", + port_id); + return; + } + if ((unsigned int)qid >= pinfo[port_id].num_queues) { + cmdline_printf(cl, "Error: queue-id:%d is greater than " + "the number of confgiured queues in " + "the port\n Please enter valid " + "queue-id\n", qid); + return; + } + rte_pmd_qdma_dbg_qinfo(port_id, qid); + } +} + +cmdline_parse_token_string_t cmd_obj_action_queue_dump = + TOKEN_STRING_INITIALIZER(struct cmd_obj_queue_dump_result, action, + "queue_dump"); +cmdline_parse_token_string_t cmd_obj_queue_dump_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_queue_dump_result, port_id, + NULL); +cmdline_parse_token_string_t cmd_obj_queue_dump_queue_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_queue_dump_result, queue_id, + NULL); + +cmdline_parse_inst_t cmd_obj_queue_dump = { + .f = cmd_obj_queue_dump_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "queue_dump port-id queue_id", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_queue_dump, + (void *)&cmd_obj_queue_dump_port_id, + (void *)&cmd_obj_queue_dump_queue_id, + NULL, + }, + +}; + +/* Command descriptor dump */ + +struct cmd_obj_desc_dump_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t port_id; + cmdline_fixed_string_t queue_id; +}; + +static void cmd_obj_desc_dump_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_desc_dump_result *res = parsed_result; + int start; + int end; + + cmdline_printf(cl, "Descriptor-dump on Port:%s, queue-id:%s\n\n", + res->port_id, res->queue_id); + { + int port_id = atoi(res->port_id); + int qid = atoi(res->queue_id); + if (port_id >= num_ports) { + cmdline_printf(cl, "Error: port-id:%d not supported\n" + "Please enter valid port-id\n", + port_id); + return; + } + if ((unsigned int)qid >= pinfo[port_id].num_queues) { + cmdline_printf(cl, "Error: queue-id:%d is greater than " + "the number of confgiured queues in " + "the port\n Please enter valid " + "queue-id\n", qid); + return; + } + + start = 0; + end = pinfo[port_id].nb_descs - 1; + rte_pmd_qdma_dbg_qdesc(port_id, qid, start, + end, RTE_PMD_QDMA_XDEBUG_DESC_C2H); + + rte_pmd_qdma_dbg_qdesc(port_id, qid, start, + end, RTE_PMD_QDMA_XDEBUG_DESC_H2C); + + if ((unsigned int)qid < pinfo[port_id].st_queues) { + rte_pmd_qdma_dbg_qdesc(port_id, qid, start, + end, RTE_PMD_QDMA_XDEBUG_DESC_CMPT); + } + } +} + +cmdline_parse_token_string_t cmd_obj_action_desc_dump = + TOKEN_STRING_INITIALIZER(struct cmd_obj_desc_dump_result, action, + "desc_dump"); +cmdline_parse_token_string_t cmd_obj_desc_dump_port_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_desc_dump_result, port_id, + NULL); +cmdline_parse_token_string_t cmd_obj_desc_dump_queue_id = + TOKEN_STRING_INITIALIZER(struct cmd_obj_desc_dump_result, queue_id, + NULL); + +cmdline_parse_inst_t cmd_obj_desc_dump = { + .f = cmd_obj_desc_dump_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "desc_dump port-id queue_id", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_desc_dump, + (void *)&cmd_obj_desc_dump_port_id, + (void *)&cmd_obj_desc_dump_queue_id, + NULL, + }, + +}; + +/*Command load commands from file */ + +struct cmd_obj_load_cmds_result { + cmdline_fixed_string_t action; + cmdline_fixed_string_t filename; +}; + +static void cmd_obj_load_cmds_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_obj_load_cmds_result *res = parsed_result; + FILE *fp; + char buff[256]; + + cmdline_printf(cl, "load-cmds from file:%s\n\n", res->filename); + fp = fopen((const char *)res->filename, "r"); + if (fp == NULL) { + cmdline_printf(cl, "Error: Invalid filename: %s\n", + res->filename); + return; + } + + rdline_reset(&cl->rdl); + { + cmdline_in(cl, "\r", 1); + while (fgets(buff, sizeof(buff), fp)) + cmdline_in(cl, buff, strlen(buff)); + + cmdline_in(cl, "\r", 1); + } + fclose(fp); +} + +cmdline_parse_token_string_t cmd_obj_action_load_cmds = + TOKEN_STRING_INITIALIZER(struct cmd_obj_load_cmds_result, action, + "load_cmds"); +cmdline_parse_token_string_t cmd_obj_load_cmds_filename = + TOKEN_STRING_INITIALIZER(struct cmd_obj_load_cmds_result, filename, + NULL); + +cmdline_parse_inst_t cmd_obj_load_cmds = { + .f = cmd_obj_load_cmds_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "load_cmds file-name", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_obj_action_load_cmds, + (void *)&cmd_obj_load_cmds_filename, + NULL, + }, + +}; + +/* CONTEXT (list of instruction) */ + +cmdline_parse_ctx_t main_ctx[] = { + (cmdline_parse_inst_t *)&cmd_obj_port_init, + (cmdline_parse_inst_t *)&cmd_obj_port_close, + (cmdline_parse_inst_t *)&cmd_obj_port_reset, + (cmdline_parse_inst_t *)&cmd_obj_port_remove, + (cmdline_parse_inst_t *)&cmd_obj_reg_read, + (cmdline_parse_inst_t *)&cmd_obj_reg_write, + (cmdline_parse_inst_t *)&cmd_obj_dma_to_device, + (cmdline_parse_inst_t *)&cmd_obj_dma_from_device, + (cmdline_parse_inst_t *)&cmd_obj_reg_dump, + (cmdline_parse_inst_t *)&cmd_obj_reg_info_read, + (cmdline_parse_inst_t *)&cmd_obj_queue_dump, + (cmdline_parse_inst_t *)&cmd_obj_desc_dump, + (cmdline_parse_inst_t *)&cmd_obj_load_cmds, + (cmdline_parse_inst_t *)&cmd_help, + NULL, +}; diff --git a/sw/app/dpdk/qdma_testapp/commands.h b/sw/app/dpdk/qdma_testapp/commands.h new file mode 100644 index 0000000..331de43 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/commands.h @@ -0,0 +1,38 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2020 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _COMMANDS_H_ +#define _COMMANDS_H_ + +extern cmdline_parse_ctx_t main_ctx[]; +#endif /* _COMMANDS_H_ */ diff --git a/sw/app/dpdk/qdma_testapp/nf_data_sink_regs_defines.h b/sw/app/dpdk/qdma_testapp/nf_data_sink_regs_defines.h new file mode 100644 index 0000000..055af40 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/nf_data_sink_regs_defines.h @@ -0,0 +1,79 @@ +// +// Copyright (c) 2015 University of Cambridge +// All rights reserved. +// +// +// File: +// nf_data_sink_regs_defines.h +// +// Description: +// This file is automatically generated with header defines for the software +// +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme. +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +// license agreements. See the NOTICE file distributed with this work for +// additional information regarding copyright ownership. NetFPGA licenses this +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +// "License"); you may not use this file except in compliance with the +// License. You may obtain a copy of the License at: +// +// http://www.netfpga-cic.org +// +// Unless required by applicable law or agreed to in writing, Work distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + + +#define SUME_NF_DATA_SINK_ID_0_OFFSET 0x0 +#define SUME_NF_DATA_SINK_ID_0_DEFAULT 0x0000DAD1 +#define SUME_NF_DATA_SINK_ID_0_WIDTH 32 +#define SUME_NF_DATA_SINK_VERSION_0_OFFSET 0x4 +#define SUME_NF_DATA_SINK_VERSION_0_DEFAULT 0x03071338 +#define SUME_NF_DATA_SINK_VERSION_0_WIDTH 32 +#define SUME_NF_DATA_SINK_RESET_0_OFFSET 0x8 +#define SUME_NF_DATA_SINK_RESET_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_RESET_0_WIDTH 32 +#define SUME_NF_DATA_SINK_FLIP_0_OFFSET 0xC +#define SUME_NF_DATA_SINK_FLIP_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_FLIP_0_WIDTH 32 +#define SUME_NF_DATA_SINK_DEBUG_0_OFFSET 0x10 +#define SUME_NF_DATA_SINK_DEBUG_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_DEBUG_0_WIDTH 32 +#define SUME_NF_DATA_SINK_ENABLE_0_OFFSET 0x14 +#define SUME_NF_DATA_SINK_ENABLE_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_ENABLE_0_WIDTH 32 +#define SUME_NF_DATA_SINK_PKTIN_0_OFFSET 0x18 +#define SUME_NF_DATA_SINK_PKTIN_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_PKTIN_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINLO_0_OFFSET 0x1c +#define SUME_NF_DATA_SINK_BYTESINLO_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINLO_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINHI_0_OFFSET 0x20 +#define SUME_NF_DATA_SINK_BYTESINHI_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINHI_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TIME_0_OFFSET 0x24 +#define SUME_NF_DATA_SINK_TIME_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TIME_0_WIDTH 32 +#define SUME_NF_DATA_SINK_AXI_CLK_0_OFFSET 0x28 +#define SUME_NF_DATA_SINK_AXI_CLK_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_AXI_CLK_0_WIDTH 32 +#define SUME_NF_DATA_SINK_AXIS_CLK_0_OFFSET 0x2c +#define SUME_NF_DATA_SINK_AXIS_CLK_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_AXIS_CLK_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_OFFSET 0x30 +#define SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_OFFSET 0x34 +#define SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_WIDTH 32 diff --git a/sw/app/dpdk/qdma_testapp/nfds_lib.c b/sw/app/dpdk/qdma_testapp/nfds_lib.c new file mode 100644 index 0000000..21a4833 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/nfds_lib.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2024 Gregory Watson + * All rights reserved. + * + * File: + * pkt_send_lib.c + * + * $Id:$ + * + * Author: + * Greg Watson + * + * Function library for pkt_send. + * + * @NETFPGA_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @NETFPGA_LICENSE_HEADER_END@ + * +*/ + +// #include +#include +#include + + +#include +// #include +#include +#include +#include +#include +#include +#include +#include + +#include "nfds_lib.h" +#include "nf_data_sink_regs_defines.h" +#include "pcierw.h" + +extern int debug; + +// Get the module ID value to check it is NF_DATA_SINK. +uint32_t nfds_get_id(int port_id) { + uint32_t id; + id = PciRead(NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ID_0_OFFSET), + port_id); + + if (id != SUME_NF_DATA_SINK_ID_0_DEFAULT) { + fprintf(stderr, "ERROR: ID register value does not match expected DATA_SINK value of 0x%0x. Saw 0x%0x.\n", + SUME_NF_DATA_SINK_ID_0_DEFAULT, id + ); + } + return id; +} + +// Enable DataSink module to start collecting data on packets sent via DMA. +void nfds_enable(int port_id) { + PciWrite(NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ENABLE_0_OFFSET), + (uint32_t) NF_DATA_SINK_ENABLE_ACTIVATE, + port_id); +} + +// Disable DataSink module. Resets all counters +void nfds_disable(int port_id) { + PciWrite(NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ENABLE_0_OFFSET), + (uint32_t) NF_DATA_SINK_ENABLE_DEACTIVATE, + port_id); +} + +// After packets have been sent, use this to make shadow copies of all registers. +// Data capture will continue. +void nfds_sample(int port_id) { + PciWrite(NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ENABLE_0_OFFSET), + (uint32_t) NF_DATA_SINK_ENABLE_SAMPLE | NF_DATA_SINK_ENABLE_ACTIVATE, + port_id); +} + +// After registers have been sampled, read them. +void nfds_get_sample(int port_id, ds_sample_t *sample_data) { + uint32_t i32; + i32 = PciRead(NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_PKTIN_0_OFFSET), + port_id + ); + sample_data->num_packets = i32; + i32 = PciRead (NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_BYTESINLO_0_OFFSET), + port_id + ); + sample_data->num_bytes = (uint64_t) i32; + i32 = PciRead (NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_BYTESINHI_0_OFFSET), + port_id + ); + + sample_data->num_bytes |= ((uint64_t) i32) << 32; + i32 = PciRead (NF_DATA_SINK_BAR, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_TIME_0_OFFSET), + port_id + ); + sample_data->num_ds_periods = i32; +} + +// int ps_get_tkeep_ds(char *ifnam, uint64_t *tkeep) { +// int rc; +// uint32_t i32; +// rc = read_register (ifnam, +// (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_OFFSET), +// &i32 +// ); +// *tkeep = (uint64_t) i32; +// if (rc == 0) { +// rc = read_register (ifnam, +// (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_OFFSET), +// &i32 +// ); +// *tkeep |= ((uint64_t) i32) << 32; +// }; +// return rc; +// } +// int ps_compute_freqs_Hz(char *ifnam, float *axi_Hz, float *axis_Hz){ +// uint32_t axi_clk_freq [2]; +// uint32_t axis_clk_freq[2]; +// int rc; +// if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXI_CLK_0_OFFSET, &axi_clk_freq[0]))) +// err(rc,"Unable to get axi clock count values from registers"); +// if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXIS_CLK_0_OFFSET, &axis_clk_freq[0]))) +// err(rc,"Unable to get axis clock count values from registers"); +// sleep(1); +// if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXI_CLK_0_OFFSET, &axi_clk_freq[1]))) +// err(rc,"Unable to get axi clock count values from registers"); +// if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXIS_CLK_0_OFFSET, &axis_clk_freq[1]))) +// err(rc,"Unable to get axis clock count values from registers"); +// *axi_Hz = (float)(axi_clk_freq[1] -axi_clk_freq[0]); +// *axis_Hz = (float)(axis_clk_freq[1]-axis_clk_freq[0]); +// return 0; +// }; + +// // Create packet, populating DA, SA, Ethtype and data. +// // Also populate socket_address though not used for raw. +// int ps_build_raw_packet(char *ifnam, int sockfd, char *sendbuf, struct sockaddr_ll *socket_address, uint32_t num_bytes) { +// struct ifreq if_idx; +// struct ifreq if_mac; +// int tx_len = 0; + +// /* Get the index of the interface to send on */ +// memset(&if_idx, 0, sizeof(struct ifreq)); +// strncpy(if_idx.ifr_name, ifnam, IFNAMSIZ-1); +// if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) +// perror("SIOCGIFINDEX"); +// /* Get the MAC address of the interface to send on */ +// memset(&if_mac, 0, sizeof(struct ifreq)); +// strncpy(if_mac.ifr_name, ifnam, IFNAMSIZ-1); +// if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) +// perror("SIOCGIFHWADDR"); + +// /* Construct the Ethernet header */ +// memset(sendbuf, 0, BUFSIZ); +// /* Ethernet header - DA */ +// sendbuf[0] = 0; +// sendbuf[1] = 1; +// sendbuf[2] = 2; +// sendbuf[3] = 3; +// sendbuf[4] = 4; +// sendbuf[5] = 0; +// /* Ethernet header - SA */ +// sendbuf[6] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0]; +// sendbuf[7] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1]; +// sendbuf[8] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2]; +// sendbuf[9] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3]; +// sendbuf[10] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4]; +// sendbuf[11] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5]; +// /* Ethertype field */ +// sendbuf[12] = htons(ETH_P_IP) >> 8; +// sendbuf[13] = htons(ETH_P_IP) & 0xff; +// tx_len += 14; + +// /* Packet data */ +// sendbuf[tx_len++] = 0xde; +// sendbuf[tx_len++] = 0xad; +// sendbuf[tx_len++] = 0xbe; +// sendbuf[tx_len++] = 0xef; +// while (tx_len < num_bytes) sendbuf[tx_len++] = 0xdd; + +// /* Index of the network device */ +// socket_address->sll_ifindex = if_idx.ifr_ifindex; +// /* Address length*/ +// socket_address->sll_halen = ETH_ALEN; +// /* Destination MAC - should be irrelevant as RAW should just send the sendbuf as raw packet*/ +// socket_address->sll_addr[0] = 0; +// socket_address->sll_addr[1] = 1; +// socket_address->sll_addr[2] = 2; +// socket_address->sll_addr[3] = 3; +// socket_address->sll_addr[4] = 4; +// socket_address->sll_addr[5] = 0; + +// return 0; +// } + + +// // Send packets of size + 4 bytes. +// // (4 bytes of CRC32 will be added to num_bytes user data.) +// int ps_send_pkt_socket(char *ifnam, uint32_t num_bytes, uint32_t num_to_send) { +// int sockfd; +// char sendbuf[BUFSIZ]; +// struct sockaddr_ll socket_address; +// int rc; + +// if (num_bytes < 60 || num_bytes > ETH_FRAME_LEN) { +// fprintf(stderr,"ERROR: ps_send_pkt_socket: packet length must >= 60 and <= ETH_FRAME_LEN (1514)"); +// return 1; +// } +// if (num_to_send < 1) { +// fprintf(stderr,"ERROR: ps_send_pkt_socket: number of pkts to send must be 1 or more."); +// return 1; +// } +// if (debug) fprintf(stderr,"INFO:ps_send_pkt_socket %s. pkt size: %0d bytes.\n", ifnam, num_bytes); + +// /* Open RAW socket to send on */ +// if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) { +// perror("socket"); +// } + +// /* Build the raw packet that will be sent many times */ +// if ((rc = ps_build_raw_packet(ifnam, sockfd, sendbuf, &socket_address, num_bytes))) +// err(rc, "Error creating raw packet."); + +// /* Send packets. sendto is blocking */ +// for (uint32_t i=0; i < num_to_send; i++) +// if (sendto(sockfd, sendbuf, num_bytes, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0) { +// printf("Send failed\n"); +// return 1; +// } + +// close(sockfd); +// return 0; +// } + +// Compute performance in bits per second +float nfds_compute_performance_bps(float axis_Hz, ds_sample_t *sampled_regs) { + float time_secs; + float bits_sent; + time_secs = sampled_regs->num_ds_periods / axis_Hz; + bits_sent = (float)(sampled_regs->num_bytes * 8); + return bits_sent / time_secs; +} diff --git a/sw/app/dpdk/qdma_testapp/nfds_lib.h b/sw/app/dpdk/qdma_testapp/nfds_lib.h new file mode 100644 index 0000000..32009b5 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/nfds_lib.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Gregory Watson + * All rights reserved. + * + * File: + * pkt_send_lib.h + * + * $Id:$ + * + * Author: + * Greg Watson + * + * Function library for pkt_send. + * + * @NETFPGA_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @NETFPGA_LICENSE_HEADER_END@ + * +*/ +#ifndef NFDS_LIB_H +#define NFDS_LIB_H + + +// Address space within the card in which nf_data_sink is located. (BAR2) +#define NF_DATA_SINK_BASE_ADDR 0x10000 +#define NF_DATA_SINK_BAR 2 + +#define NF_DATA_SINK_ENABLE_ACTIVATE 1 +#define NF_DATA_SINK_ENABLE_DEACTIVATE 0 +#define NF_DATA_SINK_ENABLE_SAMPLE (1<<1) + +#define NF_CLOCK_DIV 8 + +// Sampled data from the Datasink module +typedef struct { + uint32_t num_packets; // number of packets received + uint64_t num_bytes; // number of bytes received + uint32_t num_ds_periods; // number of clocks/NF_CLOCK_DIV from 1st to last byte. +} ds_sample_t; + +uint32_t nfds_get_id(int port_id); +void nfds_enable(int port_id); +void nfds_disable(int port_id); +void nfds_sample(int port_id); +void nfds_get_sample(int port_id, ds_sample_t *sample_data); +// int nfds_compute_freqs_Hz(char *ifnam, float *axi_Hz, float *axis_Hz); +// int nfds_build_raw_packet(char *ifnam, int sockfd, char *sendbuf, struct sockaddr_ll *socket_address, uint32_t num_bytes); +// int nfds_send_pkt_socket(char *ifnam, uint32_t num_bytes, uint32_t num_to_send); +// int nfds_get_tkeep_ds(char *ifnam, uint64_t *tkeep); +float nfds_compute_performance_bps(float axis_Hz, ds_sample_t *sampled_regs); + + +#endif \ No newline at end of file diff --git a/sw/app/dpdk/qdma_testapp/parse_obj_list.c b/sw/app/dpdk/qdma_testapp/parse_obj_list.c new file mode 100644 index 0000000..4d03816 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/parse_obj_list.c @@ -0,0 +1,196 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2020 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2009, Olivier MATZ + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "parse_obj_list.h" + +/* This file is an example of extension of libcmdline. It provides an + * example of objects stored in a list + */ + +struct cmdline_token_ops token_obj_list_ops = { + .parse = parse_obj_list, + .complete_get_nb = complete_get_nb_obj_list, + .complete_get_elt = complete_get_elt_obj_list, + .get_help = get_help_obj_list, +}; + +int +parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res, + unsigned int buf_len) +{ + struct token_obj_list *tk2 = (struct token_obj_list *)tk; + struct token_obj_list_data *tkd = &tk2->obj_list_data; + struct object *obj = NULL; + unsigned int token_len = 0; + + if (*srcbuf == 0) + return -1; + + while (!cmdline_isendoftoken(srcbuf[token_len])) + token_len++; + + SLIST_FOREACH(obj, tkd->list, next) { + if (token_len != strnlen(obj->name, OBJ_NAME_LEN_MAX)) + continue; + if (strncmp(srcbuf, obj->name, token_len)) + continue; + break; + } + if (!obj) /* not found */ + return -1; + + /* store the address of object in structure */ + if (res) + *(struct object **)res = obj; + + return token_len; +} + +int complete_get_nb_obj_list(cmdline_parse_token_hdr_t *tk) +{ + struct token_obj_list *tk2 = (struct token_obj_list *)tk; + struct token_obj_list_data *tkd = &tk2->obj_list_data; + struct object *obj = NULL; + int ret = 0; + + SLIST_FOREACH(obj, tkd->list, next) { + ret++; + } + return ret; +} + +int complete_get_elt_obj_list(cmdline_parse_token_hdr_t *tk, + int idx, char *dstbuf, unsigned int size) +{ + struct token_obj_list *tk2 = (struct token_obj_list *)tk; + struct token_obj_list_data *tkd = &tk2->obj_list_data; + struct object *obj = NULL; + int i = 0; + unsigned int len; + + SLIST_FOREACH(obj, tkd->list, next) { + if (i++ == idx) + break; + } + if (!obj) + return -1; + + len = strnlen(obj->name, OBJ_NAME_LEN_MAX); + if ((len + 1) > size) + return -1; + + if (dstbuf) + snprintf(dstbuf, size, "%s", obj->name); + + return 0; +} + + +int get_help_obj_list(__attribute__((unused)) cmdline_parse_token_hdr_t *tk, + char *dstbuf, unsigned int size) +{ + snprintf(dstbuf, size, "Obj-List"); + return 0; +} diff --git a/sw/app/dpdk/qdma_testapp/parse_obj_list.h b/sw/app/dpdk/qdma_testapp/parse_obj_list.h new file mode 100644 index 0000000..765b1ae --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/parse_obj_list.h @@ -0,0 +1,146 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2020 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2009, Olivier MATZ + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PARSE_OBJ_LIST_H_ +#define _PARSE_OBJ_LIST_H_ + +/* This file is an example of extension of libcmdline. It provides an + * example of objects stored in a list. + */ + +#include +#include + +#define OBJ_NAME_LEN_MAX 64 + +struct object { + SLIST_ENTRY(object) next; + char name[OBJ_NAME_LEN_MAX]; + cmdline_ipaddr_t ip; +}; + +/* define struct object_list */ +SLIST_HEAD(object_list, object); + +/* data is a pointer to a list */ +struct token_obj_list_data { + struct object_list *list; +}; + +struct token_obj_list { + struct cmdline_token_hdr hdr; + struct token_obj_list_data obj_list_data; +}; +typedef struct token_obj_list parse_token_obj_list_t; + +extern struct cmdline_token_ops token_obj_list_ops; + +int parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *srcbuf, + void *res, unsigned int buf_len); +int complete_get_nb_obj_list(cmdline_parse_token_hdr_t *tk); +int complete_get_elt_obj_list(cmdline_parse_token_hdr_t *tk, int idx, + char *dstbuf, unsigned int size); +int get_help_obj_list(cmdline_parse_token_hdr_t *tk, char *dstbuf, + unsigned int size); + +#define TOKEN_OBJ_LIST_INITIALIZER(structure, field, obj_list_ptr) \ +{ \ + .hdr = { \ + .ops = &token_obj_list_ops, \ + .offset = offsetof(structure, field), \ + }, \ + .obj_list_data = { \ + .list = obj_list_ptr, \ + }, \ +} + +#endif /* _PARSE_OBJ_LIST_H_ */ diff --git a/sw/app/dpdk/qdma_testapp/pcierw.c b/sw/app/dpdk/qdma_testapp/pcierw.c new file mode 100644 index 0000000..285fee9 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/pcierw.c @@ -0,0 +1,56 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2020 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pcierw.h" + +unsigned int PciRead(unsigned int bar, unsigned int offset, int port_id) +{ + + return qdma_pci_read_reg(&rte_eth_devices[port_id], bar, offset); +} + + +void PciWrite(unsigned int bar, unsigned int offset, unsigned int reg_val, + int port_id) +{ + + qdma_pci_write_reg(&rte_eth_devices[port_id], bar, offset, reg_val); + +} diff --git a/sw/app/dpdk/qdma_testapp/pcierw.h b/sw/app/dpdk/qdma_testapp/pcierw.h new file mode 100644 index 0000000..eb3385d --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/pcierw.h @@ -0,0 +1,42 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2020 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PCIERW_H__ +#define __PCIERW_H__ + +unsigned int PciRead(unsigned int bar, unsigned int offset, int port_id); +void PciWrite(unsigned int bar, unsigned int offset, unsigned int reg_val, + int port_id); +void qdma_pci_write_reg(struct rte_eth_dev *dev, uint32_t bar, uint32_t reg, + uint32_t val); +uint32_t qdma_pci_read_reg(struct rte_eth_dev *dev, uint32_t bar, uint32_t reg); +#endif diff --git a/sw/app/dpdk/qdma_testapp/qdma_regs.h b/sw/app/dpdk/qdma_testapp/qdma_regs.h new file mode 100644 index 0000000..1e9be34 --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/qdma_regs.h @@ -0,0 +1,230 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2020 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** Target definations **/ +#define QDMA_TRQ_SEL_GLBL 0x00000200 +#define QDMA_TRQ_SEL_FMAP 0x00000400 +#define QDMA_TRQ_SEL_IND 0x00000800 +#define QDMA_TRQ_SEL_C2H 0x00000A00 +#define QDMA_TRQ_SEL_H2H 0x00000E00 +#define QDMA_TRQ_SEL_C2H_MM0 0x00001000 +#define QDMA_TRQ_SEL_H2C_MM0 0x00001200 +#define QDMA_TRQ_SEL_QUEUE_PF 0x00006400 + +#define QDMA_CONFIG_BLOCK_ID 0x1fd00000UL +/** Global registers **/ +#define QDMA_GLBL_RING_SZ 0x04 +#define QDMA_GLBL_SCRATCH 0x44 +#define QDMA_GLBL_WB_ACC 0x50 +#define QDMA_RING_SZ_MSK 0x0000ffff +#define QDMA_WB_ACC_MSK 0x00000007 + +/** Fmap registers **/ +#define QID_BASE_MSK (0x000007ff) +#define QID_MAX_MSK (0x003ff800) +#define QID_MAX_SHIFT_B (11) + +/** Queue Indirect programming commands **/ + +#define QDMA_IND_Q_PRG_OFF (0x4) + +#define QDMA_CNTXT_CMD_RD (2) + +#define QDMA_CNTXT_SEL_DESC_SW_C2H (0) +#define QDMA_CNTXT_SEL_DESC_SW_H2C (1) +#define QDMA_CNTXT_SEL_DESC_HW_C2H (2) +#define QDMA_CNTXT_SEL_DESC_HW_H2C (3) +#define QDMA_CNTXT_SEL_DESC_CMPT (6) +#define QDMA_CNTXT_SEL_PFTCH (7) + +#define QID_SHIFT_B (7) +#define OP_CODE_SHIFT_B (5) +#define CTXT_SEL_SHIFT_B (1) +#define BUSY_BIT_MSK (1) + +#define WB_EN_SHIFT_B (20) +#define MM_CHAN_SHIFT_B (19) +#define MM_DESC_SZ_SHIFT_B (17) +#define ST_H2C_DESC_SZ_SHIFT_B (16) +#define DESC_RING_SZ_SHIFT_B (12) +#define ST_H2C_DESC_SZ_SHIFT_B (16) +#define MM_DESC_SZ_WB_SHIFT_B (29) +#define C2H_WB_CTXT_V_SHIFT_B (24) + +/** C2H target registers **/ +#define QDMA_C2H_CNT_TH_BASE 0x40 +#define QDMA_C2H_BUF_SZ_BASE 0xB0 + +/** PF Queue index registers */ +#define QDMA_H2C_PIDX_Q_OFF (0x04) +#define QDMA_C2H_PIDX_Q_OFF (0x08) +#define QDMA_SEL_CMPT_CIDX_Q_OFF (0x0c) + + +/** QDMA Target registers **/ +#define QDMA_C2H_MM0_CONTROL 0x00000004 +#define QDMA_H2C_MM0_CONTROL 0x00000004 +#define QDMA_MM_CTRL_START (1 << 0) + +/** QDMA Descriptor definations **/ +#define QDMA_DESC_SOP 0x1 +#define QDMA_DESC_EOP 0x1 +#define QDMA_DESC_VALID 0x1 + + +/** Queue Indirect programming registers **/ +struct __attribute__ ((packed)) q_ind_prg +{ + uint32_t ctxt_data[8]; + uint32_t ctxt_mask[8]; + uint32_t ctxt_cmd; +}; + +union __attribute__ ((packed)) h2c_c2h_ctxt +{ + struct __attribute__ ((packed)) ctxt_data + { + uint32_t data[5]; + } c_data; + struct __attribute__ ((packed)) ctxt_fields + { + uint16_t pidx; + uint16_t irq_ack:1; + uint16_t fnc_id:8; + uint16_t rsv0:7; + uint16_t qen:1; + uint16_t fcrd_en:1; + uint16_t wbi_chk:1; + uint16_t wbi_acc_en:1; + uint16_t at:1; + uint16_t fetch_max:3; + uint16_t rsv1:4; + uint16_t rng_sz:4; + uint16_t dsc_sz:2; + uint16_t byp:1; + uint16_t mm_chn:1; + uint16_t wbk_en:1; + uint16_t irq_en:1; + uint16_t port_id:3; + uint16_t irq_no_last:1; + uint16_t err:2; + uint16_t err_wb_sent:1; + uint16_t irq_req:1; + uint16_t mrkr_dis:1; + uint16_t is_mm:1; + uint64_t dsc_base; + uint16_t int_vec:11; + uint16_t int_aggr:1; + } c_fields; +}; + +union __attribute__ ((packed)) c2h_cmpt_ctxt +{ + struct __attribute__ ((packed)) c2h_cmpt_data + { + uint32_t data[5]; + } c_data; + struct __attribute__ ((packed)) c2h_cmpt_fields + { + uint32_t en_stat_desc:1; + uint32_t en_int:1; + uint32_t trig_mode:3; + uint32_t fnc_id:12; + uint32_t count_idx:4; + uint32_t timer_idx:4; + uint32_t int_st:2; + uint32_t color:1; + uint32_t size:4; + uint32_t cmpt_dsc_base_l; + uint32_t cmpt_dsc_base_h:26; + uint32_t desc_sz:2; + uint32_t pidx:16; + uint32_t cidx:16; + uint32_t valid:1; + uint32_t err:2; + uint32_t usr_trig_pend:1; + uint32_t timer_run:1; + uint32_t full_upd:1; + uint32_t ovf_chk_dis:1; + uint32_t at:1; + } c_fields; +}; + +union __attribute__ ((packed)) h2c_c2h_hw_ctxt +{ + struct __attribute__ ((packed)) hw_ctxt_data + { + uint32_t data[2]; + } c_data; + struct __attribute__ ((packed)) hw_ctxt_fields + { + uint32_t cidx:16; + uint32_t crd_use:16; + uint32_t rsvd0:8; + uint32_t pnd:1; + uint32_t idl_stp_b:1; + uint32_t event_pend:1; + uint32_t fetch_pend:4; + uint32_t rsvd1:1; + } c_fields; +}; + +union __attribute__ ((packed)) prefetch_ctxt +{ + struct __attribute__ ((packed)) pref_ctxt_data + { + uint32_t data[2]; + } c_data; + + struct __attribute__ ((packed)) pref_ctxt_fields + { + uint8_t bypass:1; + uint8_t buf_sz_idx:4; + uint8_t port_id:3; + uint32_t rsvd:18; + uint8_t err:1; + uint8_t pfch_en:1; + uint8_t pfch:1; + uint16_t sw_crdt:16; + uint8_t valid:1; + } c_fields; +}; + +#define PIDX_MSK (0) +#define Q_STATUS_MSK (0) +#define Q_STATUS_EN_MSK (3) +#define Q_STATUS_RST_MSK (1) +#define WBI_CHK_MSK (6) +#define WBI_ACC_EN_MSK (7) +#define FUNC_ID_MSK (8) +#define RING_SZ_MSK (16) +#define DESC_SZ_MSK (16) diff --git a/sw/app/dpdk/qdma_testapp/testapp.c b/sw/app/dpdk/qdma_testapp/testapp.c new file mode 100644 index 0000000..212613e --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/testapp.c @@ -0,0 +1,1132 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2021 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include /**> memset */ +#include +#include +#include /**> rte_eal_init */ +#include /**> for rte_panic */ +#include /**> rte_eth_rx_burst */ +#include /**> rte_errno global var */ +#include /**> rte_memzone_dump */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /** For SLEEP **/ +#include +#include +#include +#include +#include + +#include "pcierw.h" +#include "commands.h" +#include "qdma_regs.h" +#include "testapp.h" +#include "nfds_lib.h" +#include "nf_data_sink_regs_defines.h" + +int num_ports; +char *filename; + +struct port_info pinfo[QDMA_MAX_PORTS]; + +int do_recv_mm(int port_id, int fd, int queueid, int ld_size, int tot_num_desc) +{ + struct rte_mbuf *pkts[NUM_RX_PKTS] = { NULL }; + struct rte_device *dev; + int nb_rx = 0, i = 0, ret = 0, num_pkts; + int tdesc; +#ifdef PERF_BENCHMARK + uint64_t prev_tsc, cur_tsc, diff_tsc; +#endif + + if (tot_num_desc == 0) { + printf("Error: tot_num_desc : invalid value\n"); + return -1; + } + + rte_spinlock_lock(&pinfo[port_id].port_update_lock); + + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed. " + "Relaunch application to use the port again\n", + port_id); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } + + printf("recv start num-desc: %d, with data-len: %u, " + "last-desc-size:%d\n", + tot_num_desc, pinfo[port_id].buff_size, ld_size); + tdesc = tot_num_desc; + if (ld_size) + tdesc--; + + while (tdesc) { + if (tdesc > NUM_RX_PKTS) + num_pkts = NUM_RX_PKTS; + else + num_pkts = tdesc; +#ifdef PERF_BENCHMARK + prev_tsc = rte_rdtsc_precise(); +#endif + /* try to receive RX_BURST_SZ packets */ + nb_rx = rte_eth_rx_burst(port_id, queueid, pkts, num_pkts); + +#ifdef PERF_BENCHMARK + cur_tsc = rte_rdtsc_precise(); + diff_tsc = cur_tsc - prev_tsc; +#endif + + if (nb_rx == 0) { + printf("Error: dma_from_device failed to " + "receive packets\n"); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } +#ifdef PERF_BENCHMARK + /* Calculate average operations processed per second */ + double pkts_per_second = ((double)nb_rx * rte_get_tsc_hz() / + diff_tsc); + + /* Calculate average throughput (Gbps) in bits per second */ + double throughput_gbps = ((pkts_per_second * + pinfo[port_id].buff_size) / 1000000000); + printf("PERF_BENCHMARK: Throughput GBps %lf\n", throughput_gbps); + printf("%16s %16s %16s %16s %16s %16s%16s\n\n", + "Buf Size", "Burst Size", + "pps", "Gbps", "freq", "Cycles", + "Cycles/Buf"); + + printf("%16u %16u %16.1lf %16.1lf %16" + ""PRIu64"%16"PRIu64"%16"PRIu64"\n", + pinfo[port_id].buff_size, + nb_rx, + pkts_per_second, + throughput_gbps, + rte_get_tsc_hz(), + diff_tsc, + diff_tsc/nb_rx); +#endif + + for (i = 0; i < nb_rx; i++) { + struct rte_mbuf *mb = pkts[i]; + ret = write(fd, rte_pktmbuf_mtod(mb, void*), + pinfo[port_id].buff_size); + rte_pktmbuf_free(mb); +#ifndef PERF_BENCHMARK + printf("recv count: %d, with data-len: %d\n", i, ret); +#endif + } + tdesc = tdesc - nb_rx; + } + if (ld_size) { + struct rte_mbuf *mb; + nb_rx = rte_eth_rx_burst(port_id, queueid, pkts, 1); + if (nb_rx != 0) { + mb = pkts[0]; + ret = write(fd, rte_pktmbuf_mtod(mb, void*), ld_size); + rte_pktmbuf_free(mb); + } + } + fsync(fd); + + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + ret = 0; + + printf("DMA received number of packets: %d, on queue-id:%d\n", + nb_rx, queueid); + return ret; +} + +int do_recv_st(int port_id, int fd, int queueid, int input_size) +{ + struct rte_mbuf *pkts[NUM_RX_PKTS] = { NULL }; + int nb_rx = 0, ret = 0, tmp = 0, num_pkts, nb_pkts; + int reg_val, loopback_en; + int regval; + int user_bar_idx; + struct rte_mbuf *nxtmb; + struct rte_device *dev; + int qbase = pinfo[port_id].queue_base, diag; + unsigned int max_completion_size, last_pkt_size = 0, total_rcv_pkts = 0; + unsigned int max_rx_retry, rcv_count = 0, num_pkts_recv = 0; + unsigned int i = 0, only_pkt = 0; + +#ifdef DUMP_MEMPOOL_USAGE_STATS + struct rte_mempool *mp; +#endif //DUMP_MEMPOOL_USAGE_STATS + + rte_spinlock_lock(&pinfo[port_id].port_update_lock); + + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed. " + "Relaunch application to use the port again\n", + port_id); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } + +#ifdef DUMP_MEMPOOL_USAGE_STATS + mp = rte_mempool_lookup(pinfo[port_id].mem_pool); + + /* get the mempool from which to acquire buffers */ + if (mp == NULL) { + printf("Could not find mempool with name %s\n", + pinfo[port_id].mem_pool); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } +#endif //DUMP_MEMPOOL_USAGE_STATS + + user_bar_idx = pinfo[port_id].user_bar_idx; + PciWrite(user_bar_idx, C2H_ST_QID_REG, (queueid + qbase), port_id); + + /* As per hardware design a single completion will point to atmost + * 7 descriptors. So If the size of the buffer in descriptor is 4KB , + * then a single completion which corresponds a packet can give you + * atmost 28KB data. + * + * As per this when testing sizes beyond 28KB, one needs to split it + * up in chunks of 28KB, example : to test 56KB data size, set 28KB + * as packet length in AXI Master Lite BAR(user bar) 0x04 register and no of packets as 2 + * in AXI Master Lite BAR(user bar) 0x20 register this would give you completions or + * packets, which needs to be combined as one in application. + */ + + max_completion_size = pinfo[port_id].buff_size * 7; + + /* Calculate number of packets to receive and programming AXI Master Lite bar(user bar) */ + if (input_size == 0) /* zerobyte support uses one descriptor */ + num_pkts = 1; + else if (input_size % max_completion_size != 0) { + num_pkts = input_size / max_completion_size; + last_pkt_size = input_size % max_completion_size; + } else + num_pkts = input_size / max_completion_size; + + if ((num_pkts == 0) && last_pkt_size) { + num_pkts = 1; + only_pkt = 1; + } + + reg_val = PciRead(user_bar_idx, C2H_CONTROL_REG, port_id); + reg_val &= C2H_CONTROL_REG_MASK; + loopback_en = reg_val & ST_LOOPBACK_EN; + if (!loopback_en) { + PciWrite(user_bar_idx, C2H_PACKET_COUNT_REG, num_pkts, port_id); + + if (num_pkts > 1) + PciWrite(user_bar_idx, C2H_ST_LEN_REG, + max_completion_size, port_id); + else if ((only_pkt == 1) && (last_pkt_size)) + PciWrite(user_bar_idx, C2H_ST_LEN_REG, + last_pkt_size, port_id); + else if (input_size == 0) + PciWrite(user_bar_idx, C2H_ST_LEN_REG, input_size, + port_id); + else if (num_pkts == 1) + PciWrite(user_bar_idx, C2H_ST_LEN_REG, + max_completion_size, port_id); + + /* Start the C2H Engine */ + reg_val |= ST_C2H_START_VAL; + PciWrite(user_bar_idx, C2H_CONTROL_REG, reg_val, + port_id); + regval = PciRead(user_bar_idx, C2H_PACKET_COUNT_REG, port_id); + printf("BAR-%d is the QDMA C2H number of packets:0x%x,\n", + user_bar_idx, regval); + } + + while (num_pkts) { + if (num_pkts > NUM_RX_PKTS) + nb_pkts = NUM_RX_PKTS; + else + nb_pkts = num_pkts; + + max_rx_retry = RX_TX_MAX_RETRY; + + if ((only_pkt == 1) && (last_pkt_size)) + last_pkt_size = 0; + + /* Immediate data Enabled*/ + if ((reg_val & ST_C2H_IMMEDIATE_DATA_EN)) { + /* payload received is zero for the immediate data case. + * Therefore, no need to call the rx_burst function + * again in this case and set the num_pkts to nb_rx + * which is always Zero. + */ + diag = rte_pmd_qdma_set_immediate_data_state(port_id, + queueid, 1); + if (diag < 0) { + printf("rte_pmd_qdma_set_immediate_data_state : " + "failed\n"); + rte_spinlock_unlock( + &pinfo[port_id].port_update_lock); + return -1; + } + + nb_rx = rte_eth_rx_burst(port_id, queueid, pkts, + nb_pkts); + num_pkts = num_pkts_recv = nb_rx; + + /* Reset the queue's DUMP_IMMEDIATE_DATA mode */ + diag = rte_pmd_qdma_set_immediate_data_state(port_id, + queueid, 0); + if (diag < 0) { + printf("rte_pmd_qdma_set_immediate_data_state : " + "failed\n"); + rte_spinlock_unlock( + &pinfo[port_id].port_update_lock); + return -1; + } + } else { + /* try to receive RX_BURST_SZ packets */ + + nb_rx = rte_eth_rx_burst(port_id, queueid, pkts, + nb_pkts); + + /* For zero byte packets, do not continue looping */ + if (input_size == 0) + break; + + tmp = nb_rx; + while ((nb_rx < nb_pkts) && max_rx_retry) { + rte_delay_us(1); + nb_pkts -= nb_rx; + nb_rx = rte_eth_rx_burst(port_id, queueid, + &pkts[tmp], + nb_pkts); + tmp += nb_rx; + max_rx_retry--; + } + num_pkts_recv = tmp; + if ((max_rx_retry == 0) && (num_pkts_recv == 0)) { + printf("ERROR: rte_eth_rx_burst failed for " + "port %d queue id %d, Expected pkts = %d " + "Received pkts = %u\n", + port_id, queueid, + nb_pkts, num_pkts_recv); + break; + } + } + +#ifdef DUMP_MEMPOOL_USAGE_STATS + printf("%s(): %d: queue id = %d, mbuf_avail_count = %d, " + "mbuf_in_use_count = %d\n", + __func__, __LINE__, queueid, + rte_mempool_avail_count(mp), + rte_mempool_in_use_count(mp)); +#endif //DUMP_MEMPOOL_USAGE_STATS + for (i = 0; i < num_pkts_recv; i++) { + struct rte_mbuf *mb = pkts[i]; + while (mb != NULL) { + ret += write(fd, rte_pktmbuf_mtod(mb, void*), + rte_pktmbuf_data_len(mb)); + nxtmb = mb->next; + mb = nxtmb; + } + + mb = pkts[i]; + rte_pktmbuf_free(mb); +#ifndef PERF_BENCHMARK + printf("recv count: %u, with data-len: %d\n", + i + rcv_count, ret); +#endif + ret = 0; + } + rcv_count += i; +#ifdef DUMP_MEMPOOL_USAGE_STATS + printf("%s(): %d: queue id = %d, mbuf_avail_count = %d, " + "mbuf_in_use_count = %d, num_pkts_recv = %u\n", + __func__, __LINE__, queueid, + rte_mempool_avail_count(mp), + rte_mempool_in_use_count(mp), num_pkts_recv); +#endif //DUMP_MEMPOOL_USAGE_STATS + num_pkts = num_pkts - num_pkts_recv; + total_rcv_pkts += num_pkts_recv; + if ((num_pkts == 0) && last_pkt_size) { + num_pkts = 1; + if (!loopback_en) { + /* Stop the C2H Engine */ + reg_val = PciRead(user_bar_idx, + C2H_CONTROL_REG, + port_id); + reg_val &= C2H_CONTROL_REG_MASK; + reg_val &= ~(ST_C2H_START_VAL); + PciWrite(user_bar_idx, C2H_CONTROL_REG, reg_val, + port_id); + + /* Update number of packets as 1 and + * packet size as last packet length + */ + PciWrite(user_bar_idx, C2H_PACKET_COUNT_REG, + num_pkts, port_id); + + PciWrite(user_bar_idx, C2H_ST_LEN_REG, + last_pkt_size, port_id); + + /* Start the C2H Engine */ + reg_val = PciRead(user_bar_idx, + C2H_CONTROL_REG, + port_id); + reg_val &= C2H_CONTROL_REG_MASK; + reg_val |= ST_C2H_START_VAL; + PciWrite(user_bar_idx, C2H_CONTROL_REG, reg_val, + port_id); + } + last_pkt_size = 0; + continue; + } + } + /* Stop the C2H Engine */ + if (!loopback_en) { + reg_val = PciRead(user_bar_idx, C2H_CONTROL_REG, port_id); + reg_val &= C2H_CONTROL_REG_MASK; + reg_val &= ~(ST_C2H_START_VAL); + PciWrite(user_bar_idx, C2H_CONTROL_REG, reg_val, + port_id); + } + printf("DMA received number of packets: %u, on queue-id:%d\n", + total_rcv_pkts, queueid); + fsync(fd); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return 0; +} + +int do_xmit(int port_id, int fd, int queueid, int ld_size, int tot_num_desc, + int zbyte) +{ + struct rte_mempool *mp; + struct rte_mbuf *mb[NUM_RX_PKTS] = { NULL }; + struct rte_device *dev; + int ret = 0, nb_tx, i = 0, tdesc, num_pkts = 0, total_tx = 0, reg_val; + int tmp = 0, user_bar_idx; + int qbase = pinfo[port_id].queue_base; + uint32_t max_tx_retry; + uint32_t module_id; // the logic module inside the FPGA + +#ifdef PERF_BENCHMARK + uint64_t prev_tsc, cur_tsc, diff_tsc; +#endif + + + module_id = nfds_get_id(port_id); + if (module_id != SUME_NF_DATA_SINK_ID_0_DEFAULT) { + fprintf(stderr, "ERROR: ID register value does not match expected DATA_SINK value of 0x%0x. Saw 0x%0x.\n", + SUME_NF_DATA_SINK_ID_0_DEFAULT, module_id + ); + } + + rte_spinlock_lock(&pinfo[port_id].port_update_lock); + + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed. " + "Relaunch application to use the port again\n", + port_id); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } + + mp = rte_mempool_lookup(pinfo[port_id].mem_pool); + /* get the mempool from which to acquire buffers */ + if (mp == NULL) { + printf("Could not find mempool with name %s\n", + pinfo[port_id].mem_pool); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } + + tdesc = tot_num_desc; + user_bar_idx = pinfo[port_id].user_bar_idx; + + if (ld_size) + tdesc--; + + while (tdesc) { + if (tdesc > NUM_RX_PKTS) + num_pkts = NUM_RX_PKTS; + else + num_pkts = tdesc; + + max_tx_retry = RX_TX_MAX_RETRY; +#ifdef DUMP_MEMPOOL_USAGE_STATS + printf("%s(): %d: queue id %d, mbuf_avail_count = %d, " + "mbuf_in_use_count = %d\n", + __func__, __LINE__, queueid, + rte_mempool_avail_count(mp), + rte_mempool_in_use_count(mp)); +#endif //DUMP_MEMPOOL_USAGE_STATS + for (i = 0; i < num_pkts; i++) { + mb[i] = rte_pktmbuf_alloc(mp); + if (mb[i] == NULL) { + printf(" #####Cannot " + "allocate mbuf packet\n"); + rte_spinlock_unlock( + &pinfo[port_id].port_update_lock); + return -1; + } +#ifdef NO_FILE_READ + ret = pinfo[port_id].buff_size; // fake it. +#else + if (!zbyte) + ret = read(fd, rte_pktmbuf_mtod(mb[i], void *), + pinfo[port_id].buff_size); + if (ret < 0) { + printf("Error: Could not the read " + "input-file\n"); + rte_spinlock_unlock( + &pinfo[port_id].port_update_lock); + return -1; + } +#endif + mb[i]->nb_segs = 1; + mb[i]->next = NULL; + rte_pktmbuf_data_len(mb[i]) = (uint16_t)ret; + rte_pktmbuf_pkt_len(mb[i]) = (uint16_t)ret; + } + +#ifdef DUMP_MEMPOOL_USAGE_STATS + printf("%s(): %d: queue id %d, mbuf_avail_count = %d, " + "mbuf_in_use_count = %d, num_pkts_tx = %d\n", + __func__, __LINE__, queueid, + rte_mempool_avail_count(mp), + rte_mempool_in_use_count(mp), num_pkts); +#endif //DUMP_MEMPOOL_USAGE_STATS + + total_tx = num_pkts; + PciWrite(user_bar_idx, C2H_ST_QID_REG, (queueid + qbase), + port_id); + /* try to transmit TX_BURST_SZ packets */ + +#ifdef PERF_BENCHMARK + prev_tsc = rte_rdtsc_precise(); +#endif + nb_tx = rte_eth_tx_burst(port_id, queueid, mb, num_pkts); +#ifdef PERF_BENCHMARK + cur_tsc = rte_rdtsc_precise(); + diff_tsc = cur_tsc - prev_tsc; + /* Calculate average operations processed per second */ + double pkts_per_second = ((double)nb_tx * rte_get_tsc_hz() / + diff_tsc); + + /* Calculate average throughput (Gbps) in bits per second */ + double throughput_gbps = ((pkts_per_second * + pinfo[port_id].buff_size) / 1000000000); + printf("Throughput GBps %lf\n", throughput_gbps); + printf("%12s %12s %12s %12s %12s %12s %12s\n\n", + "Buf Size", "Burst Size", + "pps", "Gbps", "freq", "Cycles", + "Cycles/Buf"); + + printf("%12u %12u %12.4lf %12.4lf %12" + ""PRIu64"%12"PRIu64"%12"PRIu64"\n", + pinfo[port_id].buff_size, + nb_tx, + pkts_per_second, + throughput_gbps, + rte_get_tsc_hz(), + diff_tsc, + diff_tsc/nb_tx); +#endif + tmp = nb_tx; + while ((nb_tx < num_pkts) && max_tx_retry) { + printf("Couldn't transmit all the packets: Expected = %d " + "Transmitted = %d.\n" + "Calling rte_eth_tx_burst again (%d retries remaining)\n", + num_pkts, nb_tx, max_tx_retry); + rte_delay_us(1000); + num_pkts -= nb_tx; + nb_tx = rte_eth_tx_burst(port_id, queueid, &mb[tmp], + num_pkts); + tmp += nb_tx; + max_tx_retry--; + } + + if ((max_tx_retry == 0)) { + for (i = tmp; i < total_tx; i++) + rte_pktmbuf_free(mb[i]); + if (tmp == 0) { + printf("ERROR: rte_eth_tx_burst failed " + "for port %d queue %d\n", + port_id, queueid); + break; + } + } + + tdesc = tdesc - tmp; + printf("\nDMA transmitted number of packets: %d, " + "on Queue-id:%d\n", + tmp, queueid); + } + + if (ld_size) { + mb[0] = rte_pktmbuf_alloc(mp); + if (mb[0] == NULL) { + printf(" #####Cannot allocate mbuf " + "packet\n"); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } +#ifdef NO_FILE_READ + ret = ld_size; // fake it. +#else + ret = read(fd, rte_pktmbuf_mtod(mb[0], void *), ld_size); +#endif + if (ret < 0) { + printf("Error: Could not read the input-file\n"); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } + mb[0]->nb_segs = 1; + mb[0]->next = NULL; + rte_pktmbuf_data_len(mb[0]) = (uint16_t)ret; + rte_pktmbuf_pkt_len(mb[0]) = (uint16_t)ret; + + nb_tx = rte_eth_tx_burst(port_id, queueid, mb, 1); + if (nb_tx == 0) + rte_pktmbuf_free(mb[0]); + } + + reg_val = PciRead(user_bar_idx, C2H_CONTROL_REG, port_id); + reg_val &= C2H_CONTROL_REG_MASK; + if (!(reg_val & ST_LOOPBACK_EN)) { + reg_val = PciRead(user_bar_idx, H2C_STATUS_REG, port_id); + printf("BAR-%d is the QDMA H2C transfer match: 0x%x,\n", + user_bar_idx, reg_val); + + /** TO clear H2C DMA write **/ + PciWrite(user_bar_idx, H2C_CONTROL_REG, 0x1, port_id); + } + + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return 0; +} + +static int dev_reset_callback(uint16_t port_id, + enum rte_eth_event_type type, + void *param __rte_unused, void *ret_param) +{ + int ret = 0; + + RTE_SET_USED(ret_param); + printf("%s is received\n", __func__); + + if (type != RTE_ETH_EVENT_INTR_RESET) { + printf("Error: Invalid event value. " + "Expected = %d, Received = %d\n", + RTE_ETH_EVENT_INTR_RESET, type); + return -ENOMSG; + } + + ret = port_reset(port_id, pinfo[port_id].num_queues, + pinfo[port_id].st_queues, + pinfo[port_id].nb_descs, + pinfo[port_id].buff_size); + if (ret < 0) + printf("Error: Failed to reset port: %d\n", port_id); + + return ret; +} + +static int dev_remove_callback(uint16_t port_id, + enum rte_eth_event_type type, + void *param __rte_unused, void *ret_param) +{ + int ret = 0; + + RTE_SET_USED(ret_param); + printf("%s is received\n", __func__); + + if (type != RTE_ETH_EVENT_INTR_RMV) { + printf("Error: Invalid event value. " + "Expected = %d, Received = %d\n", + RTE_ETH_EVENT_INTR_RMV, type); + return -ENOMSG; + } + + ret = port_remove(port_id); + if (ret < 0) + printf("Error: Failed to remove port: %d\n", port_id); + + return 0; +} + +void port_close(int port_id) +{ + struct rte_mempool *mp; + struct rte_device *dev; + struct rte_pmd_qdma_dev_attributes dev_attr; + int user_bar_idx; + int reg_val; + int ret = 0; + + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed. " + "Relaunch application to use the port again\n", + port_id); + return; + } + + user_bar_idx = pinfo[port_id].user_bar_idx; + ret = rte_pmd_qdma_get_device_capabilities(port_id, &dev_attr); + if (ret < 0) { + printf("rte_pmd_qdma_get_device_capabilities failed for port: %d\n", + port_id); + return; + } + + if ((dev_attr.device_type == RTE_PMD_QDMA_DEVICE_SOFT) + && (dev_attr.ip_type == RTE_PMD_EQDMA_SOFT_IP)) { + PciWrite(user_bar_idx, C2H_CONTROL_REG, + C2H_STREAM_MARKER_PKT_GEN_VAL, + port_id); + unsigned int retry = 50; + while (retry) { + usleep(500); + reg_val = PciRead(user_bar_idx, + C2H_STATUS_REG, port_id); + if (reg_val & MARKER_RESPONSE_COMPLETION_BIT) + break; + + printf("Failed to receive c2h marker completion, retry count = %u\n", + (50 - (retry-1))); + retry--; + } + } + + rte_eth_dev_stop(port_id); + + rte_pmd_qdma_dev_close(port_id); + + pinfo[port_id].num_queues = 0; + + mp = rte_mempool_lookup(pinfo[port_id].mem_pool); + + if (mp != NULL) + rte_mempool_free(mp); +} + +int port_reset(int port_id, int num_queues, int st_queues, + int nb_descs, int buff_size) +{ + int ret = 0; + struct rte_device *dev; + + printf("%s is received\n", __func__); + + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed. " + "Relaunch application to use the port again\n", + port_id); + return -1; + } + + rte_spinlock_lock(&pinfo[port_id].port_update_lock); + + port_close(port_id); + + ret = rte_eth_dev_reset(port_id); + if (ret < 0) { + printf("Error: Failed to reset device for port: %d\n", port_id); + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + return -1; + } + + ret = port_init(port_id, num_queues, st_queues, + nb_descs, buff_size); + if (ret < 0) + printf("Error: Failed to initialize port: %d\n", port_id); + + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + + if (!ret) + printf("Port reset done successfully on port-id: %d\n", + port_id); + + return ret; +} + +int port_remove(int port_id) +{ + struct rte_device *dev; + int ret = 0; + + printf("%s is received\n", __func__); + + /* Detach the port, it will invoke device remove/uninit */ + printf("Removing a device with port id %d\n", port_id); + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed\n", port_id); + return 0; + } + + rte_spinlock_lock(&pinfo[port_id].port_update_lock); + + port_close(port_id); + + ret = rte_dev_remove(dev); + if (ret < 0) + printf("Failed to remove device on port_id: %d\n", port_id); + + rte_spinlock_unlock(&pinfo[port_id].port_update_lock); + + if (!ret) + printf("Port remove done successfully on port-id: %d\n", + port_id); + + return ret; +} + +static struct option const long_opts[] = { +{"filename", 1, 0, 0}, +{NULL, 0, 0, 0} +}; + +int parse_cmdline(int argc, char **argv) +{ + int cmd_opt; + int option_index; + char **argvopt; + + argvopt = argv; + while ((cmd_opt = getopt_long(argc, argvopt, "c:n:b:w", long_opts, + &option_index)) != EOF) { + switch (cmd_opt) { + case 'c': + /* eal option */ + break; + case 'n': + /* eal option */ + break; + case 'b': + /* eal option */ + break; + case 'w': + /* eal option */ + break; + case '?': + /* Long eal options */ + break; + case 0: + if (!strncmp(long_opts[option_index].name, + "filename", + sizeof("filename"))) { + + filename = optarg; + } + break; + default: + printf("please pass valid parameters as follows:\n"); + return -1; + } + } + return 0; +} + +int port_init(int port_id, int num_queues, int st_queues, + int nb_descs, int buff_size) +{ + struct rte_mempool *mbuf_pool; + struct rte_eth_conf port_conf; + struct rte_eth_txconf tx_conf; + struct rte_eth_rxconf rx_conf; + int diag, x; + uint32_t queue_base, nb_buff; + struct rte_device *dev; + + printf("Setting up port :%d.\n", port_id); + + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed. " + "Relaunch application to use the port again\n", + port_id); + return -1; + } + + snprintf(pinfo[port_id].mem_pool, RTE_MEMPOOL_NAMESIZE, + MBUF_POOL_NAME_PORT, port_id); + + /* Mbuf packet pool */ + nb_buff = ((nb_descs) * num_queues * 2); + + /* NUM_RX_PKTS should be added to every queue as that many descriptors + * can be pending with application after Rx processing but before + * consumed by application or sent to Tx + */ + nb_buff += ((NUM_RX_PKTS) * num_queues); + + mbuf_pool = rte_pktmbuf_pool_create(pinfo[port_id].mem_pool, nb_buff, + MP_CACHE_SZ, 0, buff_size + + RTE_PKTMBUF_HEADROOM, + rte_socket_id()); + + if (mbuf_pool == NULL) + rte_exit(EXIT_FAILURE, " Cannot create mbuf pkt-pool\n"); +#ifdef DUMP_MEMPOOL_USAGE_STATS + printf("%s(): %d: mpool = %p, mbuf_avail_count = %d," + " mbuf_in_use_count = %d," + "nb_buff = %u\n", __func__, __LINE__, mbuf_pool, + rte_mempool_avail_count(mbuf_pool), + rte_mempool_in_use_count(mbuf_pool), nb_buff); +#endif //DUMP_MEMPOOL_USAGE_STATS + + /* + * Make sure the port is configured. Zero everything and + * hope for sane defaults + */ + memset(&port_conf, 0x0, sizeof(struct rte_eth_conf)); + memset(&tx_conf, 0x0, sizeof(struct rte_eth_txconf)); + memset(&rx_conf, 0x0, sizeof(struct rte_eth_rxconf)); + diag = rte_pmd_qdma_get_bar_details(port_id, + &(pinfo[port_id].config_bar_idx), + &(pinfo[port_id].user_bar_idx), + &(pinfo[port_id].bypass_bar_idx)); + + if (diag < 0) + rte_exit(EXIT_FAILURE, "rte_pmd_qdma_get_bar_details failed\n"); + + printf("QDMA Config bar idx: %d\n", pinfo[port_id].config_bar_idx); + printf("QDMA AXI Master Lite bar idx: %d\n", pinfo[port_id].user_bar_idx); + printf("QDMA AXI Bridge Master bar idx: %d\n", pinfo[port_id].bypass_bar_idx); + + /* configure the device to use # queues */ + diag = rte_eth_dev_configure(port_id, num_queues, num_queues, + &port_conf); + if (diag < 0) + rte_exit(EXIT_FAILURE, "Cannot configure port %d (err=%d)\n", + port_id, diag); + + diag = rte_pmd_qdma_get_queue_base(port_id, &queue_base); + if (diag < 0) + rte_exit(EXIT_FAILURE, "rte_pmd_qdma_get_queue_base : Querying of " + "QUEUE_BASE failed\n"); + pinfo[port_id].queue_base = queue_base; + pinfo[port_id].num_queues = num_queues; + pinfo[port_id].st_queues = st_queues; + pinfo[port_id].buff_size = buff_size; + pinfo[port_id].nb_descs = nb_descs; + + for (x = 0; x < num_queues; x++) { + if (x < st_queues) { + diag = rte_pmd_qdma_set_queue_mode(port_id, x, + RTE_PMD_QDMA_STREAMING_MODE); + if (diag < 0) + rte_exit(EXIT_FAILURE, "rte_pmd_qdma_set_queue_mode : " + "Passing of QUEUE_MODE " + "failed\n"); + } else { + diag = rte_pmd_qdma_set_queue_mode(port_id, x, + RTE_PMD_QDMA_MEMORY_MAPPED_MODE); + if (diag < 0) + rte_exit(EXIT_FAILURE, "rte_pmd_qdma_set_queue_mode : " + "Passing of QUEUE_MODE " + "failed\n"); + } + + diag = rte_eth_tx_queue_setup(port_id, x, nb_descs, 0, + &tx_conf); + if (diag < 0) + rte_exit(EXIT_FAILURE, "Cannot setup port %d " + "TX Queue id:%d " + "(err=%d)\n", port_id, x, diag); + rx_conf.rx_thresh.wthresh = DEFAULT_RX_WRITEBACK_THRESH; + diag = rte_eth_rx_queue_setup(port_id, x, nb_descs, 0, + &rx_conf, mbuf_pool); + if (diag < 0) + rte_exit(EXIT_FAILURE, "Cannot setup port %d " + "RX Queue 0 (err=%d)\n", port_id, diag); + } + + diag = rte_eth_dev_start(port_id); + if (diag < 0) + rte_exit(EXIT_FAILURE, "Cannot start port %d (err=%d)\n", + port_id, diag); + + return 0; +} + +static inline void do_sanity_checks(void) +{ +#if (!defined(RTE_LIBRTE_QDMA_PMD)) + rte_exit(EXIT_FAILURE, "CONFIG_RTE_LIBRTE_QDMA_PMD must be set " + "to 'Y' in the .config file\n"); +#endif /* RTE_LIBRTE_XDMA_PMD */ + +} + +void load_file_cmds(struct cmdline *cl) +{ + FILE *fp; + char buff[256]; + + cmdline_printf(cl, "load commands from file:%s\n\n", filename); + fp = fopen((const char *)filename, "r"); + if (fp == NULL) { + cmdline_printf(cl, "Error: Invalid filename: %s\n", filename); + return; + } + + rdline_reset(&cl->rdl); + { + cmdline_in(cl, "\r", 1); + while (fgets(buff, sizeof(buff), fp)) + cmdline_in(cl, buff, strlen(buff)); + + cmdline_in(cl, "\r", 1); + } + fclose(fp); +} + +/** XDMA DPDK testapp */ + +int main(int argc, char **argv) +{ + const struct rte_memzone *mz = 0; + struct cmdline *cl; + int port_id = 0; + int ret = 0; + int curr_avail_ports = 0; + + /* Make sure the port is configured. Zero everything and + * hope for same defaults + */ + + printf("QDMA testapp rte eal init...\n"); + + /* Make sure things are initialized ... */ + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + rte_log_set_global_level(RTE_LOG_DEBUG); + + printf("Ethernet Device Count: %d\n", (int)rte_eth_dev_count_avail()); + printf("Logical Core Count: %d\n", rte_lcore_count()); + + num_ports = rte_eth_dev_count_avail(); + if (num_ports < 1) + rte_exit(EXIT_FAILURE, "No Ethernet devices found." + " Try updating the FPGA image.\n"); + + for (port_id = 0; port_id < num_ports; port_id++) + rte_spinlock_init(&pinfo[port_id].port_update_lock); + + ret = rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_RMV, + dev_remove_callback, NULL); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Failed to register dev_remove_callback\n"); + + ret = rte_eth_dev_callback_register(RTE_ETH_ALL, + RTE_ETH_EVENT_INTR_RESET, + dev_reset_callback, NULL); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Failed to register dev_reset_callback\n"); + +#if 1 + ret = parse_cmdline(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Invalid argument\n"); +#endif + + /* Make sure things are defined ... */ + do_sanity_checks(); + + mz = rte_memzone_reserve_aligned("eth_devices", RTE_MAX_ETHPORTS * + sizeof(*rte_eth_devices), 0, 0, 4096); + if (mz == NULL) + rte_exit(EXIT_FAILURE, "Failed to allocate aligned memzone\n"); + + memcpy(mz->addr, &rte_eth_devices[0], RTE_MAX_ETHPORTS * + sizeof(*rte_eth_devices)); + + cl = cmdline_stdin_new(main_ctx, "xilinx-app> "); + if (cl == NULL) + rte_panic("Cannot create cmdline instance\n"); + + /* if input commands file exists, then load commands from the file */ + if (filename != NULL) { + load_file_cmds(cl); + rte_delay_ms(100); + } else + cmdline_interact(cl); + + rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_RMV, + dev_remove_callback, NULL); + + rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_RESET, + dev_reset_callback, NULL); + + curr_avail_ports = rte_eth_dev_count_avail(); + if (!curr_avail_ports) + printf("Ports already removed\n"); + else { + for (port_id = num_ports - 1; port_id >= 0; port_id--) { + struct rte_device *dev; + + if (pinfo[port_id].num_queues) + port_close(port_id); + + printf("Removing a device with port id %d\n", port_id); + dev = rte_eth_devices[port_id].device; + if (dev == NULL) { + printf("Port id %d already removed\n", port_id); + continue; + } + /* Detach the port, it will invoke + * device remove/uninit + */ + if (rte_dev_remove(dev)) + printf("Failed to detach port '%d'\n", port_id); + } + } + + cmdline_stdin_exit(cl); + + rte_delay_ms(5000); + return 0; +} diff --git a/sw/app/dpdk/qdma_testapp/testapp.h b/sw/app/dpdk/qdma_testapp/testapp.h new file mode 100644 index 0000000..446c6bb --- /dev/null +++ b/sw/app/dpdk/qdma_testapp/testapp.h @@ -0,0 +1,94 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017-2020 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define QDMA_MAX_PORTS 256 + +#define PORT_0 0 + +#define NUM_DESC_PER_RING 1024 +#ifdef PERF_BENCHMARK +#define NUM_RX_PKTS (NUM_DESC_PER_RING - 2) +#else +#define NUM_RX_PKTS 32 +#endif +#define MAX_NUM_QUEUES 2048 +#define DEFAULT_NUM_QUEUES 64 +#define RX_TX_MAX_RETRY 20 +#define DEFAULT_RX_WRITEBACK_THRESH (64) + +#define MP_CACHE_SZ 512 +#define MBUF_POOL_NAME_PORT "mbuf_pool_%d" + +/* AXI Master Lite bar(user bar) registers */ +#define C2H_ST_QID_REG 0x0 +#define C2H_ST_LEN_REG 0x4 +#define C2H_CONTROL_REG 0x8 +#define ST_LOOPBACK_EN 0x1 +#define ST_C2H_START_VAL 0x2 +#define ST_C2H_IMMEDIATE_DATA_EN 0x4 +#define C2H_CONTROL_REG_MASK 0xF +#define H2C_CONTROL_REG 0xC +#define H2C_STATUS_REG 0x10 +#define C2H_PACKET_COUNT_REG 0x20 +#define C2H_STATUS_REG 0x18 +#define C2H_STREAM_MARKER_PKT_GEN_VAL 0x22 +#define MARKER_RESPONSE_COMPLETION_BIT 0x1 + +extern int num_ports; + +struct port_info { + int config_bar_idx; + int user_bar_idx; + int bypass_bar_idx; + unsigned int queue_base; + unsigned int num_queues; + unsigned int nb_descs; + unsigned int st_queues; + unsigned int buff_size; + rte_spinlock_t port_update_lock; + char mem_pool[RTE_MEMPOOL_NAMESIZE]; +}; + +extern struct port_info pinfo[QDMA_MAX_PORTS]; +int port_init(int port_id, int num_queues, int st_queues, + int nb_descs, int buff_size); +int do_recv_st(int port_id, int fd, int queueid, int input_size); +int do_recv_mm(int port_id, int fd, int queueid, + int ld_size, int tot_num_desc); +int do_xmit(int port_id, int fd, int queueid, + int ld_size, int tot_num_desc, int zbyte); +void load_file_cmds(struct cmdline *cl); +void port_close(int port_id); +int port_reset(int port_id, int num_queues, int st_queues, + int nb_descs, int buff_size); +int port_remove(int port_id); +int parse_cmdline(int argc, char **argv); diff --git a/sw/app/main.c b/sw/app/main.c index 0b0409c..cd6dbcc 100644 --- a/sw/app/main.c +++ b/sw/app/main.c @@ -62,13 +62,19 @@ struct xlni_ioctl_ifreq { #define HAVE_ADDR 0x01 #define HAVE_VALUE 0x02 #define HAVE_IFACE 0x04 +#define HAVE_DEBUG 0x08 static void usage(const char *progname) { - - printf("Usage: %s -a [-w ] [-i ]\n", + struct xlni_ioctl_ifreq sifr; + struct ifreq ifr; + printf("Usage: %s -a [-d] [-w ] [-i ]\n", progname); + printf("NFDP_IOCTL_CMD_WRITE_REG is %0d\n", NFDP_IOCTL_CMD_WRITE_REG); + printf("NFDP_IOCTL_CMD_READ_REG is %0d\n", NFDP_IOCTL_CMD_READ_REG); + printf("Size of ifr is %lu \n",sizeof(ifr)); + printf("Size of sifr is %lu \n",sizeof(sifr)); _exit(1); } @@ -82,13 +88,14 @@ main(int argc, char *argv[]) unsigned long l; uint32_t addr, value; int fd, flags, rc, req; + int i; flags = 0x00; addr = 0;//NFPLUS_DEFAULT_TEST_ADDR; ifnam = "nf0";//NFPLUS_IFNAM_DEFAULT; req = NFDP_IOCTL_CMD_READ_REG; value = 0; - while ((rc = getopt(argc, argv, "+a:hi:w:")) != -1) { + while ((rc = getopt(argc, argv, "+a:dhi:w:")) != -1) { switch (rc) { case 'a': l = strtoul(optarg, NULL, 0); @@ -97,6 +104,9 @@ main(int argc, char *argv[]) addr = (uint32_t)l; flags |= HAVE_ADDR; break; + case 'd': + flags |= HAVE_DEBUG; + break; case 'i': ifnam = optarg; flags |= HAVE_IFACE; @@ -145,7 +155,19 @@ main(int argc, char *argv[]) memcpy(ifr.ifr_name, ifnam, ifnamlen); ifr.ifr_name[ifnamlen] = '\0'; ifr.ifr_data = (char *)&sifr; - + + if ((flags & HAVE_DEBUG) != 0) { + printf("IF: %s Addr: 0x%08x RD_IOCTL:%0d WR_IOCTL:%0d\n", + ifnam, addr, NFDP_IOCTL_CMD_READ_REG,NFDP_IOCTL_CMD_WRITE_REG ); + } + + printf("Addr of sifr is %llx\n",(unsigned long long)(&sifr)); + printf("ifr before call: 0x"); + for (i=0; i < sizeof(ifr); i++) { + printf("%02x ",(unsigned int)(((char *)&ifr)[i] & 0xff)); + } + printf("\n"); + rc = ioctl(fd, req, &ifr); if (rc == -1) err(1, "ioctl"); diff --git a/sw/app/pkt_send/Makefile b/sw/app/pkt_send/Makefile new file mode 100644 index 0000000..2fabd66 --- /dev/null +++ b/sw/app/pkt_send/Makefile @@ -0,0 +1,45 @@ +# +# Copyright (c) 2021 University of Cambridge +# All rights reserved. +# +# This software was developed by +# Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# +EXE := pkt_send + +SRC := $(wildcard *.c) +OBJ := $(SRC:%.c=%.o) +CFLAGS := -Wall # some warnings about bad code +LDFLAGS := -Llib # -L is a linker flag +LDLIBS := -lm # Left empty if no libs are needed + +all: $(EXE) + +$(EXE): $(OBJ) + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +clean: + rm -f $(EXE) $(OBJ) + +.phoney: all + diff --git a/sw/app/pkt_send/README.txt b/sw/app/pkt_send/README.txt new file mode 100644 index 0000000..8bc2b44 --- /dev/null +++ b/sw/app/pkt_send/README.txt @@ -0,0 +1,4 @@ +Files needed: + +nf_data_sink_regs_defines.h must match the hardware version of the nf_data_sink library module. +This can be created by going to $NFPLUS_FOLDER/hw/lib/std/nf_data_sink_v1_0_0/data and running regs_gen.py if the .h file is not already present. diff --git a/sw/app/pkt_send/do_ioctl.py b/sw/app/pkt_send/do_ioctl.py new file mode 100644 index 0000000..41c2f8e --- /dev/null +++ b/sw/app/pkt_send/do_ioctl.py @@ -0,0 +1,51 @@ +# +# This is an attempt to do a simple register read/write in Python. +# +# Even though the ifr and sifr structures appear to be identical to +# the same structures in C, this does not work. +# +# Might consider using ctypes instead? + +import socket +import fcntl +import array +import struct + +NFDP_IOCTL_CMD_WRITE_REG = 35313 +NFDP_IOCTL_CMD_READ_REG = 35314 +IFR_SIZE = 40 # struct ifreq +NAMESIZE = 16 # max file name size + +def rd_ioctl(ifname, addr): + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + sifr = struct.pack('II',addr,0) + print(f"Size of II object is {struct.calcsize('II')}") + print("before call, sifr is 0x%0x 0x%0x " % (sifr[0], sifr[1])) + + sifr_addr = id(sifr) + ifname16 = ifname + (chr(0) * (NAMESIZE -len(ifname))) + print("sifr is at 0x%0x" % sifr_addr) + + # ifr = struct.pack('40s',ifname40.encode('UTF-8')) + ifr = struct.pack('<16sQQQ',ifname16.encode('UTF-8'), sifr_addr, 0,0) + + print("Before call ifr is ",end='') + for b in ifr: print("%02x " % b,end='') + print('') + + r = fcntl.ioctl(s.fileno(), + NFDP_IOCTL_CMD_READ_REG, + ifr) + print(f"ioctl returned {r}\nAfter call ifr is ",end='') + for b in ifr: print("%0x " % b,end='') + print('') + print("after call, sifr is 0x%0x 0x%0x" % (sifr[0], sifr[1])) + return sifr + +#get_ip_address('nf0') + +# for a in [0x0, 0x10000, 0x20000, 0x30000, 0x40000]: +for a in [0x10000]: + sifr = rd_ioctl('nf0', a) + print("IOCTL to addr 0x%0x returned 0x%0x" % (a, sifr[1])) + diff --git a/sw/app/pkt_send/nf_data_sink_regs_defines.h b/sw/app/pkt_send/nf_data_sink_regs_defines.h new file mode 100644 index 0000000..055af40 --- /dev/null +++ b/sw/app/pkt_send/nf_data_sink_regs_defines.h @@ -0,0 +1,79 @@ +// +// Copyright (c) 2015 University of Cambridge +// All rights reserved. +// +// +// File: +// nf_data_sink_regs_defines.h +// +// Description: +// This file is automatically generated with header defines for the software +// +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory +// under National Science Foundation under Grant No. CNS-0855268, +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +// as part of the DARPA MRC research programme. +// +// @NETFPGA_LICENSE_HEADER_START@ +// +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +// license agreements. See the NOTICE file distributed with this work for +// additional information regarding copyright ownership. NetFPGA licenses this +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +// "License"); you may not use this file except in compliance with the +// License. You may obtain a copy of the License at: +// +// http://www.netfpga-cic.org +// +// Unless required by applicable law or agreed to in writing, Work distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// @NETFPGA_LICENSE_HEADER_END@ +// + + +#define SUME_NF_DATA_SINK_ID_0_OFFSET 0x0 +#define SUME_NF_DATA_SINK_ID_0_DEFAULT 0x0000DAD1 +#define SUME_NF_DATA_SINK_ID_0_WIDTH 32 +#define SUME_NF_DATA_SINK_VERSION_0_OFFSET 0x4 +#define SUME_NF_DATA_SINK_VERSION_0_DEFAULT 0x03071338 +#define SUME_NF_DATA_SINK_VERSION_0_WIDTH 32 +#define SUME_NF_DATA_SINK_RESET_0_OFFSET 0x8 +#define SUME_NF_DATA_SINK_RESET_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_RESET_0_WIDTH 32 +#define SUME_NF_DATA_SINK_FLIP_0_OFFSET 0xC +#define SUME_NF_DATA_SINK_FLIP_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_FLIP_0_WIDTH 32 +#define SUME_NF_DATA_SINK_DEBUG_0_OFFSET 0x10 +#define SUME_NF_DATA_SINK_DEBUG_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_DEBUG_0_WIDTH 32 +#define SUME_NF_DATA_SINK_ENABLE_0_OFFSET 0x14 +#define SUME_NF_DATA_SINK_ENABLE_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_ENABLE_0_WIDTH 32 +#define SUME_NF_DATA_SINK_PKTIN_0_OFFSET 0x18 +#define SUME_NF_DATA_SINK_PKTIN_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_PKTIN_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINLO_0_OFFSET 0x1c +#define SUME_NF_DATA_SINK_BYTESINLO_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINLO_0_WIDTH 32 +#define SUME_NF_DATA_SINK_BYTESINHI_0_OFFSET 0x20 +#define SUME_NF_DATA_SINK_BYTESINHI_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_BYTESINHI_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TIME_0_OFFSET 0x24 +#define SUME_NF_DATA_SINK_TIME_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TIME_0_WIDTH 32 +#define SUME_NF_DATA_SINK_AXI_CLK_0_OFFSET 0x28 +#define SUME_NF_DATA_SINK_AXI_CLK_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_AXI_CLK_0_WIDTH 32 +#define SUME_NF_DATA_SINK_AXIS_CLK_0_OFFSET 0x2c +#define SUME_NF_DATA_SINK_AXIS_CLK_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_AXIS_CLK_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_OFFSET 0x30 +#define SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_WIDTH 32 +#define SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_OFFSET 0x34 +#define SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_DEFAULT 0x0 +#define SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_WIDTH 32 diff --git a/sw/app/pkt_send/pkt_send.c b/sw/app/pkt_send/pkt_send.c new file mode 100644 index 0000000..c11f282 --- /dev/null +++ b/sw/app/pkt_send/pkt_send.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2024 Gregory Watson + * All rights reserved. + * + * File: + * pkt_send.c + * + * $Id:$ + * + * Author: + * Greg Watson + * + * Based on rwaxi app in NetFPGA-PLUS/sw/app + * + * @NETFPGA_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @NETFPGA_LICENSE_HEADER_END@ + * +*/ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "pkt_send_ioctl.h" +#include "pkt_send_lib.h" +#include "nf_data_sink_regs_defines.h" + +#define MODE_SEND_PACKETS 1 +#define MODE_GET_CLOCKS 2 +#define MODE_SIZE_RANGE_REPORT_NUM_PKTS 4 +#define MODE_SIZE_RANGE_REPORT_NUM_MBYTES 8 + +#define PERF_LOOPS 3 + +int debug; +int mode = MODE_SEND_PACKETS; + +static void +usage(const char *progname) +{ + printf("Usage: %s [-d] [-b ] [-i ] [-n ] [-r ] [-z] \n", progname); + printf("\t-d : debug mode on (prints additional information. Performance results invalid.)\n"); + printf("\t-b : Specify the number of bytes in packet (length) 60-1514. 4 bytes extra will be added as CRC.\n"); + printf("\t-i : Specify the interface. Default is 'nf0'. See ifconfig.\n"); + printf("\t-n : Specify the number of packets to send for each test.\n"); + printf("\t-R,-r : Report mode: measures performance over a range of packet sizes.\n"); + printf("\t -R : Specify number of Mbytes to send for each packet size.\n"); + printf("\t -r : Specify number of packets to send for each packet size.\n"); + printf("\t-z : Measure AXI and AXIS clocks and report their frequencies.\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + char *ifnam; + int rc; + uint32_t pkt_len; // without CRC + uint32_t num_to_send; + uint32_t mbytes_to_send; + ds_sample_t sampled_regs; + float axi_Hz, axis_Hz; + float perf_Mbps; + + pkt_len = 60; + num_to_send = 1; + ifnam = "nf0";//NFPLUS_IFNAM_DEFAULT; + while ((rc = getopt(argc, argv, "b:i:n:r:R:dhz")) != -1) { + switch (rc) { + case 'b': + pkt_len = strtoul(optarg, NULL, 0); + if (pkt_len < 60 || pkt_len > ETH_FRAME_LEN) + errx(1, "Invalid packet length. Must be 60-1514"); + break; + case 'd': + debug = 1; + printf("DEBUG set to 1\n"); + break; + case 'i': + ifnam = optarg; + break; + case 'R': // report performance over packet size range. COnst data + mode |= MODE_SIZE_RANGE_REPORT_NUM_MBYTES; + mode &= ~MODE_SEND_PACKETS; + mbytes_to_send = strtoul(optarg, NULL, 0); + if (mbytes_to_send < 1) + errx(1, "Invalid number of Mbytes to send - must be >= 1"); + break; + case 'r': // report performance over packet size range. Const num pkts + mode |= MODE_SIZE_RANGE_REPORT_NUM_PKTS; + mode &= ~MODE_SEND_PACKETS; + case 'n': + num_to_send = strtoul(optarg, NULL, 0); + if (num_to_send < 1) + errx(1, "Invalid number to send - must be >= 1"); + break; + case 'z': + mode |= MODE_GET_CLOCKS; + break; + case 'h': + case '?': + default: + usage(argv[0]); + /* NOT REACHED */ + } + } + + rc = ps_compute_freqs_Hz(ifnam, &axi_Hz, &axis_Hz); + if (debug) { + rc = ps_get_id_ds(ifnam); + printf("FPGA design reports Module ID value 0x%0x\n", rc); + } + + + if (mode & MODE_GET_CLOCKS) { + printf("AXI clock: %6.2f MHz\nAXIS clock: %6.2f MHz\n", axi_Hz/1000000.0, axis_Hz/1000000.0); + exit(0); + } + + + if (mode & (MODE_SIZE_RANGE_REPORT_NUM_PKTS | MODE_SIZE_RANGE_REPORT_NUM_MBYTES | MODE_SEND_PACKETS)) { + + // Enable collection + if ((rc = ps_enable_ds(ifnam))) err(rc, "Unable to enable datasink module"); + // Send packets + if ((rc = ps_send_pkt_socket(ifnam, pkt_len, num_to_send))) err(rc, "Error sending packets."); + // Sample registers + if ((rc = ps_sample_ds(ifnam ))) err(rc, "Unable to issue sample command to data_sink module."); + // Load shadow registers into sample structure + if ((rc = ps_get_sample_ds(ifnam, &sampled_regs))) err(rc, "Unable to read the sample shadow registers in data_sink module."); + + if (debug) { + printf("Num pkts: %d\n", sampled_regs.num_packets); + printf("Num bytes: %0lu\n", sampled_regs.num_bytes); + printf("Num clk periods of activity: %d\n", sampled_regs.num_ds_periods); + } + + perf_Mbps = ps_compute_performance_bps(axis_Hz, &sampled_regs)/1000000.0; + printf("Performance was %6.1f Mbps (%6.2f Gbps)\n", perf_Mbps, perf_Mbps/1000.0); + // Disable collection and reset counters (clean up) + if ((rc = ps_disable_ds(ifnam))) err(rc, "Unable to disable datasink module"); + } + + + if (mode & (MODE_SIZE_RANGE_REPORT_NUM_MBYTES|MODE_SIZE_RANGE_REPORT_NUM_PKTS)) { + + uint32_t pkt_len = 60; + + while (pkt_len <= ETH_FRAME_LEN) { + + perf_Mbps = 0.0; + + if (mode & MODE_SIZE_RANGE_REPORT_NUM_MBYTES) { + num_to_send = mbytes_to_send*1024*1024/pkt_len; + } + + for (int avg_loop = 0; avg_loop < PERF_LOOPS; avg_loop++) { + + // Enable collection + if ((rc = ps_enable_ds(ifnam))) err(rc, "Unable to enable datasink module"); + // Send packets + if ((rc = ps_send_pkt_socket(ifnam, pkt_len, num_to_send))) err(rc, "Error sending packets."); + // Sample registers + if ((rc = ps_sample_ds(ifnam ))) err(rc, "Unable to issue sample command to data_sink module."); + // Load shadow registers into sample structure + if ((rc = ps_get_sample_ds(ifnam, &sampled_regs))) err(rc, "Unable to read the sample shadow registers in data_sink module."); + + if (debug) { + printf("Num pkts: %d\n", sampled_regs.num_packets); + printf("Num bytes: %0lu\n", sampled_regs.num_bytes); + printf("Num clk periods of activity: %d\n", sampled_regs.num_ds_periods); + } + + perf_Mbps += ps_compute_performance_bps(axis_Hz, &sampled_regs)/1000000.0; + // Disable collection and reset counters (clean up) + if ((rc = ps_disable_ds(ifnam))) err(rc, "Unable to disable datasink module"); + } + perf_Mbps /= PERF_LOOPS; + printf("%0d, %6.2f\n", pkt_len, perf_Mbps/1000.0); + + if ((pkt_len < 128) || ((pkt_len % 64) == 0)) + pkt_len++; + else + pkt_len = (pkt_len + 16) & 0xfff0; + } + } + + exit(0); +} + + diff --git a/sw/app/pkt_send/pkt_send_ioctl.c b/sw/app/pkt_send/pkt_send_ioctl.c new file mode 100644 index 0000000..807f254 --- /dev/null +++ b/sw/app/pkt_send/pkt_send_ioctl.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024 Gregory Watson + * All rights reserved. + * + * File: + * pkt_send_ioctl.c + * + * $Id:$ + * + * Author: + * Greg Watson + * + * Based on rwaxi app in NetFPGA-PLUS/sw/app + * + * @NETFPGA_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @NETFPGA_LICENSE_HEADER_END@ + * +*/ + +#include "pkt_send_ioctl.h" + +extern int debug; + +int call_ioctl (uint32_t addr, uint32_t op, char *ifnam, uint32_t *rd_data, uint32_t wr_data) +{ + struct xlni_ioctl_ifreq sifr; + struct ifreq ifr; + size_t ifnamlen; + static int fd; + int rc, req; + + req = NFDP_IOCTL_CMD_READ_REG; // default to read + if (op == OP_IS_WRITE) req = NFDP_IOCTL_CMD_WRITE_REG; + + ifnamlen = strlen(ifnam); + if (ifnamlen >= sizeof(ifr.ifr_name)) + errx(1, "Interface name too long"); + + if (fd == 0) { + fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (fd == -1) { + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) + err(1, "socket failed for AF_INET6 and AF_INET"); + } + } + + memset(&sifr, 0, sizeof(sifr)); + sifr.addr = addr; + if (op == OP_IS_WRITE) { + sifr.val = wr_data; + req = NFDP_IOCTL_CMD_WRITE_REG; + } + + memset(&ifr, 0, sizeof(ifr)); + memcpy(ifr.ifr_name, ifnam, ifnamlen); + ifr.ifr_name[ifnamlen] = '\0'; + ifr.ifr_data = (char *)&sifr; + + rc = ioctl(fd, req, &ifr); + if (rc == -1) + err(1, "ioctl"); + + if (op == OP_IS_READ) *rd_data = sifr.val; + return (0); +} + +int +read_register (char *ifnam, uint32_t addr, uint32_t *rd_data) +{ + if (debug) printf("DEBUG: read_register: reading address 0x%0x.\n",addr); + return call_ioctl (addr, OP_IS_READ, ifnam, rd_data, addr/*unused*/); +} + +int +write_register (char *ifnam, uint32_t addr, uint32_t wr_data) +{ + if (debug) printf("DEBUG: write_register: Write value 0x%0x to address 0x%0x.\n", wr_data, addr); + return call_ioctl (addr, OP_IS_WRITE, ifnam, NULL, wr_data); +} + + + +/* end */ diff --git a/sw/app/pkt_send/pkt_send_ioctl.h b/sw/app/pkt_send/pkt_send_ioctl.h new file mode 100644 index 0000000..fb8a24d --- /dev/null +++ b/sw/app/pkt_send/pkt_send_ioctl.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Gregory Watson + * All rights reserved. + * + * File: + * pkt_send_ioctl.h + * + * $Id:$ + * + * Author: + * Greg Watson + * + * Based on rwaxi app in NetFPGA-PLUS/sw/app + * + * @NETFPGA_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @NETFPGA_LICENSE_HEADER_END@ + * +*/ + +#ifndef PKT_SEND_IOCTL_H +#define PKT_SEND_IOCTL_H + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct xlni_ioctl_ifreq { + uint32_t addr; + uint32_t val; +}; + +//#define NFPLUS_DEFAULT_TEST_ADDR 0x44020000 +#define NFDP_IOCTL_CMD_WRITE_REG (SIOCDEVPRIVATE+1) +#define NFDP_IOCTL_CMD_READ_REG (SIOCDEVPRIVATE+2) + +#define OP_IS_READ 0 +#define OP_IS_WRITE 1 + + +// Provide register address and interface name (e.g. 'nf0') +// If it's a reg read then provide addr of integer variable rd_wr_data. +// If it's a write then provide write data. + +int read_register (char *ifnam, uint32_t addr, uint32_t *rd_data); +int write_register (char *ifnam, uint32_t addr, uint32_t wr_data); + +#endif /* pkt_send_ioctl.h */ + diff --git a/sw/app/pkt_send/pkt_send_lib.c b/sw/app/pkt_send/pkt_send_lib.c new file mode 100644 index 0000000..0275751 --- /dev/null +++ b/sw/app/pkt_send/pkt_send_lib.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2024 Gregory Watson + * All rights reserved. + * + * File: + * pkt_send_lib.c + * + * $Id:$ + * + * Author: + * Greg Watson + * + * Function library for pkt_send. + * + * @NETFPGA_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @NETFPGA_LICENSE_HEADER_END@ + * +*/ + +// #include +#include +#include + + +#include +// #include +#include +#include +#include +#include +#include +#include + +#include "pkt_send_ioctl.h" +#include "pkt_send_lib.h" +#include "nf_data_sink_regs_defines.h" + +extern int debug; + +// Get the module ID value to check it is NF_DATA_SINK. +uint32_t ps_get_id_ds(char *ifnam) { + uint32_t id; + read_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ID_0_OFFSET), + &id + ); + if (id != SUME_NF_DATA_SINK_ID_0_DEFAULT) { + fprintf(stderr, "ERROR: ID register value does not match expected DATA_SINK value of 0x%0x. Saw 0x%0x.\n", + SUME_NF_DATA_SINK_ID_0_DEFAULT, id + ); + } + return id; +} + +// Enable DataSink module to start collecting data on packets sent via DMA. +int ps_enable_ds(char *ifnam) { + return + write_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ENABLE_0_OFFSET), + (uint32_t) NF_DATA_SINK_ENABLE_ACTIVATE + ); +} + +// Disable DataSink module. Resets all counters +int ps_disable_ds(char *ifnam) { + return + write_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ENABLE_0_OFFSET), + (uint32_t) NF_DATA_SINK_ENABLE_DEACTIVATE + ); +} + +// After packets have been sent, use this to make shadow copies of all registers. +// Data capture will continue. +int ps_sample_ds(char *ifnam) { + return + write_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_ENABLE_0_OFFSET), + (uint32_t) NF_DATA_SINK_ENABLE_SAMPLE | NF_DATA_SINK_ENABLE_ACTIVATE + ); +} + +// After registers have been sampled, read them. +int ps_get_sample_ds(char *ifnam, ds_sample_t *sample_data) { + int rc; + uint32_t i32; + rc = read_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_PKTIN_0_OFFSET), + &i32 + ); + sample_data->num_packets = i32; + if (rc == 0) { + rc |= read_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_BYTESINLO_0_OFFSET), + &i32 + ); + sample_data->num_bytes = (uint64_t) i32; + }; + if (rc == 0) { + rc = read_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_BYTESINHI_0_OFFSET), + &i32 + ); + sample_data->num_bytes |= ((uint64_t) i32) << 32; + }; + if (rc == 0) { + rc = read_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_TIME_0_OFFSET), + &i32 + ); + sample_data->num_ds_periods = i32; + }; + return rc; +} + +int ps_get_tkeep_ds(char *ifnam, uint64_t *tkeep) { + int rc; + uint32_t i32; + rc = read_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_TKEEP_LAST_LO_0_OFFSET), + &i32 + ); + *tkeep = (uint64_t) i32; + if (rc == 0) { + rc = read_register (ifnam, + (uint32_t)(NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_TKEEP_LAST_HI_0_OFFSET), + &i32 + ); + *tkeep |= ((uint64_t) i32) << 32; + }; + return rc; +} +int ps_compute_freqs_Hz(char *ifnam, float *axi_Hz, float *axis_Hz){ + uint32_t axi_clk_freq [2]; + uint32_t axis_clk_freq[2]; + int rc; + if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXI_CLK_0_OFFSET, &axi_clk_freq[0]))) + err(rc,"Unable to get axi clock count values from registers"); + if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXIS_CLK_0_OFFSET, &axis_clk_freq[0]))) + err(rc,"Unable to get axis clock count values from registers"); + sleep(1); + if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXI_CLK_0_OFFSET, &axi_clk_freq[1]))) + err(rc,"Unable to get axi clock count values from registers"); + if ((rc = read_register (ifnam, NF_DATA_SINK_BASE_ADDR+SUME_NF_DATA_SINK_AXIS_CLK_0_OFFSET, &axis_clk_freq[1]))) + err(rc,"Unable to get axis clock count values from registers"); + *axi_Hz = (float)(axi_clk_freq[1] -axi_clk_freq[0]); + *axis_Hz = (float)(axis_clk_freq[1]-axis_clk_freq[0]); + return 0; +}; + +// Create packet, populating DA, SA, Ethtype and data. +// Also populate socket_address though not used for raw. +int ps_build_raw_packet(char *ifnam, int sockfd, char *sendbuf, struct sockaddr_ll *socket_address, uint32_t num_bytes) { + struct ifreq if_idx; + struct ifreq if_mac; + int tx_len = 0; + + /* Get the index of the interface to send on */ + memset(&if_idx, 0, sizeof(struct ifreq)); + strncpy(if_idx.ifr_name, ifnam, IFNAMSIZ-1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) + perror("SIOCGIFINDEX"); + /* Get the MAC address of the interface to send on */ + memset(&if_mac, 0, sizeof(struct ifreq)); + strncpy(if_mac.ifr_name, ifnam, IFNAMSIZ-1); + if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) + perror("SIOCGIFHWADDR"); + + /* Construct the Ethernet header */ + memset(sendbuf, 0, BUFSIZ); + /* Ethernet header - DA */ + sendbuf[0] = 0; + sendbuf[1] = 1; + sendbuf[2] = 2; + sendbuf[3] = 3; + sendbuf[4] = 4; + sendbuf[5] = 0; + /* Ethernet header - SA */ + sendbuf[6] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0]; + sendbuf[7] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1]; + sendbuf[8] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2]; + sendbuf[9] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3]; + sendbuf[10] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4]; + sendbuf[11] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5]; + /* Ethertype field */ + sendbuf[12] = htons(ETH_P_IP) >> 8; + sendbuf[13] = htons(ETH_P_IP) & 0xff; + tx_len += 14; + + /* Packet data */ + sendbuf[tx_len++] = 0xde; + sendbuf[tx_len++] = 0xad; + sendbuf[tx_len++] = 0xbe; + sendbuf[tx_len++] = 0xef; + while (tx_len < num_bytes) sendbuf[tx_len++] = 0xdd; + + /* Index of the network device */ + socket_address->sll_ifindex = if_idx.ifr_ifindex; + /* Address length*/ + socket_address->sll_halen = ETH_ALEN; + /* Destination MAC - should be irrelevant as RAW should just send the sendbuf as raw packet*/ + socket_address->sll_addr[0] = 0; + socket_address->sll_addr[1] = 1; + socket_address->sll_addr[2] = 2; + socket_address->sll_addr[3] = 3; + socket_address->sll_addr[4] = 4; + socket_address->sll_addr[5] = 0; + + return 0; +} + + +// Send packets of size + 4 bytes. +// (4 bytes of CRC32 will be added to num_bytes user data.) +int ps_send_pkt_socket(char *ifnam, uint32_t num_bytes, uint32_t num_to_send) { + int sockfd; + char sendbuf[BUFSIZ]; + struct sockaddr_ll socket_address; + int rc; + + if (num_bytes < 60 || num_bytes > ETH_FRAME_LEN) { + fprintf(stderr,"ERROR: ps_send_pkt_socket: packet length must >= 60 and <= ETH_FRAME_LEN (1514)"); + return 1; + } + if (num_to_send < 1) { + fprintf(stderr,"ERROR: ps_send_pkt_socket: number of pkts to send must be 1 or more."); + return 1; + } + if (debug) fprintf(stderr,"INFO:ps_send_pkt_socket %s. pkt size: %0d bytes.\n", ifnam, num_bytes); + + /* Open RAW socket to send on */ + if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) { + perror("socket"); + } + + /* Build the raw packet that will be sent many times */ + if ((rc = ps_build_raw_packet(ifnam, sockfd, sendbuf, &socket_address, num_bytes))) + err(rc, "Error creating raw packet."); + + /* Send packets. sendto is blocking */ + for (uint32_t i=0; i < num_to_send; i++) + if (sendto(sockfd, sendbuf, num_bytes, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0) { + printf("Send failed\n"); + return 1; + } + + close(sockfd); + return 0; +} + +// Compute performance in bits per second +float ps_compute_performance_bps(float axis_Hz, ds_sample_t *sampled_regs) { + float time_secs; + float bits_sent; + time_secs = sampled_regs->num_ds_periods / axis_Hz; + bits_sent = (float)(sampled_regs->num_bytes * 8); + return bits_sent / time_secs; +} diff --git a/sw/app/pkt_send/pkt_send_lib.h b/sw/app/pkt_send/pkt_send_lib.h new file mode 100644 index 0000000..b20eec2 --- /dev/null +++ b/sw/app/pkt_send/pkt_send_lib.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Gregory Watson + * All rights reserved. + * + * File: + * pkt_send_lib.h + * + * $Id:$ + * + * Author: + * Greg Watson + * + * Function library for pkt_send. + * + * @NETFPGA_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @NETFPGA_LICENSE_HEADER_END@ + * +*/ +#ifndef PKT_SEND_LIB_H +#define PKT_SEND_LIB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Address space within the card in which nf_data_sink is located. +#define NF_DATA_SINK_BASE_ADDR 0x10000 + +#define NF_DATA_SINK_ENABLE_ACTIVATE 1 +#define NF_DATA_SINK_ENABLE_DEACTIVATE 0 +#define NF_DATA_SINK_ENABLE_SAMPLE (1<<1) + +#define NF_CLOCK_DIV 8 + +// Sampled data from the Datasink module +typedef struct { + uint32_t num_packets; // number of packets received + uint64_t num_bytes; // number of bytes received + uint32_t num_ds_periods; // number of clocks/NF_CLOCK_DIV from 1st to last byte. +} ds_sample_t; + +uint32_t ps_get_id_ds(char *ifnam); +int ps_enable_ds(char *ifnam); +int ps_disable_ds(char *ifnam); +int ps_sample_ds(char *ifnam); +int ps_get_sample_ds(char *ifnam, ds_sample_t *sample_data); +int ps_compute_freqs_Hz(char *ifnam, float *axi_Hz, float *axis_Hz); +int ps_build_raw_packet(char *ifnam, int sockfd, char *sendbuf, struct sockaddr_ll *socket_address, uint32_t num_bytes); +int ps_send_pkt_socket(char *ifnam, uint32_t num_bytes, uint32_t num_to_send); +int ps_get_tkeep_ds(char *ifnam, uint64_t *tkeep); +float ps_compute_performance_bps(float axis_Hz, ds_sample_t *sampled_regs); + + +#endif \ No newline at end of file diff --git a/sw/app/pkt_send/send_pkt.py b/sw/app/pkt_send/send_pkt.py new file mode 100644 index 0000000..97c1896 --- /dev/null +++ b/sw/app/pkt_send/send_pkt.py @@ -0,0 +1,7 @@ +from scapy.all import * + +# create a TCP SYN packet with IP and Ethernet layers +packet = Ether()/IP(dst="192.168.1.250")/TCP(dport=80, flags="S") + +# send the packet using the eth0 interface +sendp(packet, iface="nf0") diff --git a/sw/driver/Makefile b/sw/driver/Makefile index c2844a9..554acb2 100644 --- a/sw/driver/Makefile +++ b/sw/driver/Makefile @@ -45,3 +45,9 @@ driver: clean: $(MAKE) -C $(DRIVER_DIR) clean + +install: + $(MAKE) -C $(DRIVER_DIR) install + +uninstall: + $(MAKE) -C $(DRIVER_DIR) uninstall \ No newline at end of file diff --git a/tools/infrastructure/regs_template.txt b/tools/infrastructure/regs_template.txt new file mode 100644 index 0000000..d90222b --- /dev/null +++ b/tools/infrastructure/regs_template.txt @@ -0,0 +1,1787 @@ +# +# Copyright (c) 2015 Noa Zilberman, Jingyun Zhang, Salvator Galea +# All rights reserved. +# +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory +# under National Science Foundation under Grant No. CNS-0855268, +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"), +# as part of the DARPA MRC research programme. +# +# @NETFPGA_LICENSE_HEADER_START@ +# +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. NetFPGA licenses this +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at: +# +# http://www.netfpga-cic.org +# +# Unless required by applicable law or agreed to in writing, Work distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# @NETFPGA_LICENSE_HEADER_END@ +# + +################################################################## +# a function that writes the header of regs file +################################################################## +def write_regs_header(regsFile): + regsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') +#end of write_regs_headerdefault + +################################################################## +# a function that writes the header of regs defines file +################################################################## + +def write_defs_header(defsFile): + defsFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_cpu_regs_defines.v\n\ +//\n\ +// Module:\n\ +// '+module_name+'_cpu_regs_defines\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with the registers defintions towards the CPU/Software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_defs_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_tcl_header(tclFile): + tclFile.write('\ +#\n\ +# Copyright (c) 2015 University of Cambridge\n\ +# All rights reserved.\n\ +#\n\ +#\n\ +# File:\n\ +# '+module_name+'_regs_defines.tcl\n\ +#\n\ +# Description:\n\ +# This file is automatically generated with tcl defines for the software\n\ +#\n\ +# This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +# under National Science Foundation under Grant No. CNS-0855268,\n\ +# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +# as part of the DARPA MRC research programme.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_START@\n\ +#\n\ +# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +# license agreements. See the NOTICE file distributed with this work for\n\ +# additional information regarding copyright ownership. NetFPGA licenses this\n\ +# file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +# "License"); you may not use this file except in compliance with the\n\ +# License. You may obtain a copy of the License at:\n\ +#\n\ +# http://www.netfpga-cic.org\n\ +#\n\ +# Unless required by applicable law or agreed to in writing, Work distributed\n\ +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +# CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +# specific language governing permissions and limitations under the License.\n\ +#\n\ +# @NETFPGA_LICENSE_HEADER_END@\n\ +#\n\ +\n') + +#end of write_tcl_header + + +################################################################## +# a function that writes the header of regs tcl file +################################################################## + +def write_hFile_header(hFile): + hFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.h\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +#end of write_h_header + + +################################################################## +# a function that writes the header of regs table file +################################################################## +def write_tbFile_header(tbFile): + tbFile.write('\ +//\n\ +// Copyright (c) 2015 University of Cambridge\n\ +// All rights reserved.\n\ +//\n\ +//\n\ +// File:\n\ +// '+module_name+'_regs_defines.txt\n\ +//\n\ +// Description:\n\ +// This file is automatically generated with header defines for the software\n\ +//\n\ +// This software was developed by Stanford University and the University of Cambridge Computer Laboratory\n\ +// under National Science Foundation under Grant No. CNS-0855268,\n\ +// the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and\n\ +// by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),\n\ +// as part of the DARPA MRC research programme.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_START@\n\ +//\n\ +// Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor\n\ +// license agreements. See the NOTICE file distributed with this work for\n\ +// additional information regarding copyright ownership. NetFPGA licenses this\n\ +// file to you under the NetFPGA Hardware-Software License, Version 1.0 (the\n\ +// "License"); you may not use this file except in compliance with the\n\ +// License. You may obtain a copy of the License at:\n\ +//\n\ +// http://www.netfpga-cic.org\n\ +//\n\ +// Unless required by applicable law or agreed to in writing, Work distributed\n\ +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR\n\ +// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n\ +// specific language governing permissions and limitations under the License.\n\ +//\n\ +// @NETFPGA_LICENSE_HEADER_END@\n\ +//\n\ +\n') + +################################################################## +#A funtion that writes the ports of the regs moduledefault +################################################################## + +def write_regs_ports(regsFile,regsDict, memsDict): + + regsFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\ +module '+module_name+'_cpu_regs #\n\ +(\n\ +parameter C_BASE_ADDRESS = 32\'h00000000,\n\ +parameter C_S_AXI_DATA_WIDTH = 32,\n\ +parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +(\n\ + // General ports\n\ + input clk,\n\ + input resetn,\n\ + // Global Registers\n\ + input cpu_resetn_soft,\n\ + output reg resetn_soft,\n\ + output reg resetn_sync,\n\ +\n\ + // Register ports\n') + + for entry in regsDict: + if entry['type']=="RO" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="ROC" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + regsFile.write(' output reg '+entry['name']+'_reg_clear,\n') + if entry['type']=="RWS" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WO" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="WOE" : + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg,\n') + if entry['type']=="RWA" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + if entry['type']=="RWCR" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + if entry['type']=="RWCW" : + regsFile.write(' input [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg,\n') + regsFile.write(' output reg [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg,\n') + regsFile.write(' output reg cpu2ip_'+entry['name']+'_reg_clear,\n') + + for entry in memsDict: + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr,\n') + regsFile.write(' output reg [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data,\n') + regsFile.write(' output reg '+entry['name']+'_rd_wrn,\n') + regsFile.write(' output reg '+entry['name']+'_cmd_valid,\n') + regsFile.write(' input [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_reply,\n') + regsFile.write(' input '+entry['name']+'_reply_valid,\n') + + regsFile.write('\n\ + // AXI Lite ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +\n\ +);\n'); +#end of write_regs_ports + +################################################################## +#A funtion that writes the wires and regs of the registers module +################################################################## +def write_regs_wires(regsFile,regsDict,memsDict): + + regsFile.write('\n\ + // AXI4LITE signals\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;\n\ + reg axi_awready;\n\ + reg axi_wready;\n\ + reg [1 : 0] axi_bresp;\n\ + reg axi_bvalid;\n\ + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;\n\ + reg axi_arready;\n\ + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;\n\ + reg [1 : 0] axi_rresp;\n\ + reg axi_rvalid;\n\ +\n\ + reg resetn_sync_d;\n\ + wire reg_rden;\n\ + wire reg_wren;\n\ + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;\n\ + integer byte_index;\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + reg cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + reg '+entry['name']+'_reg_clear_d;\n') + + for entry in regsDict: + if entry['type']=="RWSI" or entry['type']=="ROI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write('\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n\ + reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg_internal;\n\ + reg '+entry['name']+'_reg_update;\n') + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\n\ + // assign default little endian\n'); + regsFile.write('\ + wire [C_S_AXI_DATA_WIDTH-1 : 0] reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + regsFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + regsFile.write('\n\ + // I/O Connections assignments\n\ + assign S_AXI_AWREADY = axi_awready;\n\ + assign S_AXI_WREADY = axi_wready;\n\ + assign S_AXI_BRESP = axi_bresp;\n\ + assign S_AXI_BVALID = axi_bvalid;\n\ + assign S_AXI_ARREADY = axi_arready;\n\ + assign S_AXI_RDATA = axi_rdata;\n\ + assign S_AXI_RRESP = axi_rresp;\n\ + assign S_AXI_RVALID = axi_rvalid;\n\ +\n'); + + +#end of write_regs_wires + + +################################################################## +#sync reset signal for better timing +################################################################## +def sync_reset(regsFile): + + regsFile.write('\n\ + //Sample reset (not mandatory, but good practice)\n\ + always @ (posedge clk) begin\n\ + if (~resetn) begin\n\ + resetn_sync_d <= 1\'b0;\n\ + resetn_sync <= 1\'b0;\n\ + end\n\ + else begin\n\ + resetn_sync_d <= resetn;\n\ + resetn_sync <= resetn_sync_d;\n\ + end\n\ + end\n\ +\n'); + +# for now, only global reset is supported, to demonstrate usage + regsFile.write('\n\ + //global registers, sampling\n\ + always @(posedge clk) resetn_soft <= #1 cpu_resetn_soft;\n'); + + +#end of sync_reset + +################################################################## +# a function that writes the logic behind the registers access +################################################################## +def write_logic(regsFile,regsDict): +# boolean first_item; + + +# axi protocol generation + + regsFile.write('\n\ + // Implement axi_awready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // slave is ready to accept write address when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_awready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_awready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_awaddr latching\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_awaddr <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)\n\ + begin\n\ + // Write Address latching\n\ + axi_awaddr <= S_AXI_AWADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_wready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)\n\ + begin\n\ + // slave is ready to accept write data when\n\ + // there is a valid write address and write data\n\ + // on the write address and data bus. This design\n\ + // expects no outstanding transactions.\n\ + axi_wready <= 1\'b1;\n\ + end\n\ + else\n\ + begin\n\ + axi_wready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement write response logic generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_bvalid <= 0;\n\ + axi_bresp <= 2\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)\n\ + begin\n\ + // indicates a valid write response is available\n\ + axi_bvalid <= 1\'b1;\n\ + axi_bresp <= 2\'b0; // OKAY response\n\ + end // work error responses in future\n\ + else\n\ + begin\n\ + if (S_AXI_BREADY && axi_bvalid)\n\ + //check if bready is asserted while bvalid is high)\n\ + //(there is a possibility that bready is always asserted high)\n\ + begin\n\ + axi_bvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ + end\n\ +\n\ + // Implement axi_arready generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + axi_araddr <= 32\'b0;\n\ + end\n\ + else\n\ + begin\n\ + if (~axi_arready && S_AXI_ARVALID)\n\ + begin\n\ + // indicates that the slave has acceped the valid read address\n\ + // Read address latching\n\ + axi_arready <= 1\'b1;\n\ + axi_araddr <= S_AXI_ARADDR ^ C_BASE_ADDRESS;\n\ + end\n\ + else\n\ + begin\n\ + axi_arready <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n\ + // Implement axi_rvalid generation\n\ +\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rvalid <= 0;\n\ + axi_rresp <= 0;\n\ + end\n\ + else\n\ + begin\n\ + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)\n\ + begin\n\ + // Valid read data is available at the read data bus\n\ + axi_rvalid <= 1\'b1;\n\ + axi_rresp <= 2\'b0; // OKAY response\n\ + end\n\ + else if (axi_rvalid && S_AXI_RREADY)\n\ + begin\n\ + // Read data is accepted by the master\n\ + axi_rvalid <= 1\'b0;\n\ + end\n\ + end\n\ + end\n\ +\n\ +\n'); + + + regsFile.write('\ + // Implement memory mapped register select and write logic generation\n\ +\n\ + assign reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;\n\ +\n\ +//////////////////////////////////////////////////////////////\n\ +// write registers\n\ +//////////////////////////////////////////////////////////////\n\ +\n'); + +#Handle write only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="WO" : + if first_item: + regsFile.write('\n\ +//Write only register, not cleared\n\ + //static\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + first_item=False; + + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin //write event\n\ + case (axi_awaddr)\n'); + + + for entry in regsDict: + if entry['type']=="WO" : + if entry['endian']=="little" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write(' //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n'); + + +#Handle write only event registers + + first_item=True; + + for entry in regsDict: + if entry['type']=="WOE" : + if first_item: + first_item= False; + regsFile.write('\n\ +//Write only register, clear on write (i.e. event)\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n\ + if (reg_wren) begin\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="WOE" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + +#Handle Read/write registers, not cleared + + first_item=True; + + for entry in regsDict: + if first_item and (entry['type']=="RWS" or entry['type']=="RWA"): + first_item = False; + regsFile.write('\n\ +//R/W register, not cleared\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + '+entry['name']+'_reg_internal <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren) //write event\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWS" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWSI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if entry['type']=="RWI" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8]; //static register;\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + '+entry['name']+'_reg_internal[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not (first_item): + regsFile.write('\ + default: begin\n\ + end\n\ +\n\ + endcase\n\ + end\n'); + + for entry in regsDict: + if entry['type']=="RWI" : + regsFile.write(' '+entry['name']+'_reg_update <= reg_wren && (axi_awaddr == `REG_'+entry['name'].upper()+'_ADDR);\n'); + + if not (first_item): + regsFile.write(' end\n'); + +#Handle Read/write registers, clear on read + + first_item=True; + + for entry in regsDict: + if entry['type']=="RWCR" : + if first_item: + first_item = False; + regsFile.write('\n\ +//R/W register, clear on read\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n\ +\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if not (first_item): + regsFile.write('\ + end\n\ + else begin\n\ + if (reg_wren)\n\ + case (axi_awaddr)\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + endcase\n\ + end\n\ + end\n\ +\n\ +\n\ +//clear assertions\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCR" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 reg_rden && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\n\ + end\n\ + end\n'); + + + +#Handle Read/write registers, clear on write + + first_item= True; + + for entry in regsDict: + if entry['type']=="RWCW" : + first_item = False; + regsFile.write('\n\ +//R/W register, clear on write, dynamic\n\ +// i.e. on write - write, next clock - write default value\n\ + always @(posedge clk) begin\n\ + if (!resetn_sync) begin\n'); + + if entry['endian']=="little" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear_d <= #1 1\'b0;\n\ + cpu2ip_'+entry['name']+'_reg_clear <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + regsFile.write('\ + cpu2ip_'+entry['name']+'_reg_clear <= cpu2ip_'+entry['name']+'_reg_clear_d;\n\ + cpu2ip_'+entry['name']+'_reg_clear_d <= reg_wren && (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write('\ + if (reg_wren) begin\n'); + + for entry in regsDict: + if entry['type']=="RWCW" : + if entry['endian']=="little" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for ( byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index+1 )\n\ + if ( S_AXI_WSTRB[byte_index] == 1 ) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[byte_index*8 +: 8];\n\ + end\n\ + end\n'); + if entry['endian']=="big" : + regsFile.write('\ + if (axi_awaddr==`REG_'+entry['name'].upper()+'_ADDR) begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + if (S_AXI_WSTRB[byte_index] == 1) begin\n\ + cpu2ip_'+entry['name']+'_reg[byte_index*8 +: 8] <= S_AXI_WDATA[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8]; //dynamic register;\n\ + end\n\ + end\n'); + + if not(first_item): + regsFile.write('\ + end\n\ + end\n\ + end\n'); + + regsFile.write('\ +\n\ +\n\ +\n\ +/////////////////////////\n\ +//// end of write\n\ +/////////////////////////\n'); + + regsFile.write('\n\ + // Implement memory mapped register select and read logic generation\n\ + // Slave register read enable is asserted when valid address is available\n\ + // and the slave is ready to accept the read address.\n\ +\n\ + // reg_rden control logic\n\ + // temperary no extra logic here\n\ + assign reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;\n'); + +#return read data + regsFile.write('\n\ + always @(*)\n\ + begin\n\ +\n\ + case ( axi_araddr /*S_AXI_ARADDR ^ C_BASE_ADDRESS*/)\n'); + + for entry in regsDict: + if entry['type']=="RO" or entry['type']=="ROC" or entry['type']=="RWS" or entry['type']=="RWI" or entry['type']=="RWSI" or entry['type']=="ROI": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = '+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = '+entry['name']+'_reg [(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width'])<32: + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + if entry['type']=="RWCW" or entry['type']=="RWA" or entry['type']=="RWCR": + if entry['endian']=="little" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + reg_data_out [`REG_'+entry['name'].upper()+'_BITS] = ip2cpu_'+entry['name']+'_reg;\n'); + + if entry['endian']=="big" : + regsFile.write('\ + //'+entry['name'].capitalize()+' Register\n\ + `REG_'+entry['name'].upper()+'_ADDR : begin\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + reg_data_out [byte_index*8 +: 8] = ip2cpu_'+entry['name']+'_reg[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if int(entry['width']) < 32 : + regsFile.write('\ + reg_data_out [31:`REG_'+entry['name'].upper()+'_WIDTH] = \'b0;\n'); + + regsFile.write('\ + end\n'); + + regsFile.write('\ + //Default return value\n\ + default: begin\n\ + reg_data_out [31:0] = 32\'hDEADBEEF;\n\ + end\n\ +\n\ + endcase\n\ +\n\ + end//end of assigning data to IP2Bus_Data bus\n'); + +#Handle read only registers + first_item=True; + + for entry in regsDict: + if entry['type']=="ROC" : + if first_item: + first_item=False; + regsFile.write('\n\ + //Read only registers, not cleared\n\ + //Nothing to do here....\n\ +\n\ +//Read only registers, cleared on read (e.g. counters)\n\ + always @(posedge clk)\n\ + if (!resetn_sync) begin\n'); + + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 1\'b0;\n\ + '+entry['name']+'_reg_clear_d <= #1 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\ + else begin\n'); + + for entry in regsDict: + if entry['type']=="ROC" : + regsFile.write('\ + '+entry['name']+'_reg_clear <= #1 '+entry['name']+'_reg_clear_d;\n\ + '+entry['name']+'_reg_clear_d <= #1(reg_rden && (axi_araddr==`REG_'+entry['name'].upper()+'_ADDR)) ? 1\'b1 : 1\'b0;\n'); + + if not(first_item): + regsFile.write(' end\n\n'); + + regsFile.write('\n\ +// Output register or memory read data\n\ + always @( posedge S_AXI_ACLK )\n\ + begin\n\ + if ( S_AXI_ARESETN == 1\'b0 )\n\ + begin\n\ + axi_rdata <= 0;\n\ + end\n\ + else\n\ + begin\n\ + // When there is a valid read address (S_AXI_ARVALID) with\n\ + // acceptance of read address by the slave (axi_arready),\n\ + // output the read dada\n\ + if (reg_rden)\n\ + begin\n\ + axi_rdata <= reg_data_out/*ip2bus_data*/; // register read data /* some new changes here */\n\ + end\n\ + end\n\ + end\n'); + +# end of write_logic + +################################################################## +# a function that writes the logic behind the indirect registers access +################################################################## +def write_indirect(regsFile,memsDict): + regsFile.write('\n\ + //////////////////////////////////\n\ + // Implement Indirect Access\n\ + //////////////////////////////////\n\ + \n'); + + regsFile.write('\n\ + //--------------------- Internal Parameters-------------------------\n\ + localparam NUM_INDIRECT_STATES = 6;\n\ + localparam IDLE_INDIRECT_STATE = 1;\n\ + localparam WRITE_INDIRECT_STATE = 2;\n\ + localparam WRITE_WAIT_INDIRECT_STATE = 4;\n\ + localparam READ_INDIRECT_STATE = 8;\n\ + localparam READ_WAIT_INDIRECT_STATE = 16;\n\ + localparam INDIRECT_DONE_STATE = 32;\n\ + localparam INDIRECT_WRITE = 0;\n\ + localparam INDIRECT_READ = 1;\n\ + localparam INDIRECT_WRITE_TA = 1;\n\ + localparam INDIRECT_WRITE_WS = 0;\n\ + //------------------------------------------------------------------\n\ + \n\ + reg [NUM_INDIRECT_STATES-1:0] indirect_state, indirect_state_next, indirect_state_last;\n\ + wire indirect_trigger;\n\ + wire indirect_type;\n\ + reg indirect_status, indirect_status_next;\n\ + wire [3:0] indirect_address_increment;\n\ + wire indirect_write_type;\n\ + wire [10:0] indirect_timeout;\n\ + wire [15:0] indirect_repeat_count;\n\ + reg [15:0] indirect_remaining,indirect_remaining_next;\n\ + reg [10:0] indirect_timeout_count, indirect_timeout_count_next;\n\ + reg indirect_reply_valid;\n\ + reg [31:0] indirect_address,indirect_address_next;\n\ + reg [3:0] indirect_memory_select,indirect_memory_select_next;\n\ + wire indirect_command_done;\n\ + \n\ + assign indirect_trigger = indirectcommand_reg[0];\n\ + assign indirect_type = indirectcommand_reg[4];\n\ + assign indirect_address_increment = indirectconfig_reg[3:0];\n\ + assign indirect_write_type = indirectconfig_reg[4];\n\ + assign indirect_timeout = indirectconfig_reg[15:5];\n\ + assign indirect_repeat_count = indirectconfig_reg[31:16];\n\ + \n\ + always @(*) begin\n\ + indirect_state_next = indirect_state;\n\ + indirect_status_next = indirect_status;\n\ + indirect_remaining_next = indirect_remaining;\n\ + indirect_timeout_count_next = indirect_timeout_count;\n\ + indirect_address_next = indirect_address;\n\ + indirect_memory_select_next = indirect_memory_select;\n\ + case(indirect_state)\n\ + IDLE_INDIRECT_STATE: begin\n\ + if(indirect_trigger) begin\n\ + indirect_state_next= (indirect_type == INDIRECT_WRITE) ? WRITE_INDIRECT_STATE : READ_INDIRECT_STATE;\n\ + indirect_remaining_next = (indirect_repeat_count == 0) ? 16\'h1 : indirect_repeat_count;\n\ + indirect_timeout_count_next = indirect_timeout;\n\ + indirect_address_next = indirectaddress_reg; //This is the address in the user register\n\ + indirect_memory_select_next = indirectaddress_reg[31:28];\n\ + end\n\ + end\n\ + \n\ + READ_INDIRECT_STATE: begin\n\ + indirect_state_next = READ_WAIT_INDIRECT_STATE;\n\ + end\n\ + READ_WAIT_INDIRECT_STATE: begin\n\ + if (indirect_reply_valid) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next =0;\n\ + end\n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count-1;\n\ + end\n\ + WRITE_INDIRECT_STATE: begin\n\ + indirect_state_next = WRITE_WAIT_INDIRECT_STATE;\n\ + end\n\ + WRITE_WAIT_INDIRECT_STATE: begin\n\ + if (((indirect_write_type == INDIRECT_WRITE_TA) && (indirect_reply_valid)) || ((indirect_write_type == INDIRECT_WRITE_WS) && (indirect_timeout_count==0))) begin\n\ + indirect_remaining_next = indirect_remaining - 1;\n\ + indirect_address_next = indirect_address+indirect_address_increment;\n\ + if (indirect_remaining==1) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + end\n\ + end\n\ + else \n\ + if (indirect_timeout_count==0) begin\n\ + indirect_state_next = INDIRECT_DONE_STATE;\n\ + indirect_status_next = 1; \n\ + end\n\ + indirect_timeout_count_next = indirect_timeout_count==0 ? 0 : indirect_timeout_count-1;\n\ + end\n\ + INDIRECT_DONE_STATE: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + default: begin\n\ + indirect_state_next= IDLE_INDIRECT_STATE;\n\ + end\n\ + endcase // case(state)\n\ + end // always @ (*)\n\ + \n\ + assign indirect_command_done = (indirect_state==INDIRECT_DONE_STATE);\n\ + \n\ + always @(posedge clk) begin\n\ + if(~resetn_sync) begin\n\ + indirect_state <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_state_last <= #1 IDLE_INDIRECT_STATE;\n\ + indirect_status <= #1 1\'b0;\n\ + indirect_remaining <= #1 0;\n\ + indirect_timeout_count <= #1 0;\n\ + indirect_address <= #1 0;\n\ + indirect_memory_select <= #1 0;\n\ + indirectcommand_reg <= #1 `REG_INDIRECTCOMMAND_DEFAULT;\n\ + end\n\ + else begin\n\ + indirect_state <= #1 indirect_state_next;\n\ + indirect_state_last <= #1 indirect_state;\n\ + indirect_status <= #1 indirect_status_next;\n\ + indirect_remaining <= #1 indirect_remaining_next;\n\ + indirect_timeout_count <= #1 indirect_timeout_count_next;\n\ + indirect_address <= #1 indirect_address_next;\n\ + indirect_memory_select <= #1 indirect_memory_select_next;\n\ + indirectcommand_reg <= #1 indirect_command_done ? {indirect_status,indirectcommand_reg[7:4],4\'h0} : \n\ + indirectcommand_reg_update ? indirectcommand_reg_internal: \n\ + indirectcommand_reg;\n\ + end\n\ + end \n\ + \n'); + + + for entry in memsDict: + regsFile.write('\n\ + \n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + '+entry['name']+'_addr <= #1 0;\n\ + '+entry['name']+'_data <= #1 0;\n\ + '+entry['name']+'_rd_wrn<= #1 0;\n\ + '+entry['name']+'_cmd_valid <= #1 0;\n\ + end \n\ + else begin\n\ + '+entry['name']+'_addr <= #1 indirect_address;\n\ + '+entry['name']+'_data <= #1 indirectwrdata_reg;\n\ + '+entry['name']+'_rd_wrn<= #1 indirect_type;\n\ + '+entry['name']+'_cmd_valid <= #1 ('+entry['address']+'==(indirect_memory_select<<28)) && ((indirect_state == WRITE_INDIRECT_STATE) || (indirect_state == READ_INDIRECT_STATE));\n\ + end \n\ + end\n'); + + regsFile.write('\n\ + always @(posedge clk) begin\n\ + if (~resetn_sync) begin\n\ + indirectreply_reg <= #1 0;\n\ + indirect_reply_valid <= #1 0; \n\ + end \n\ + else begin \n\ + indirectreply_reg <= #1 ' ); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply :'); + regsFile.write(' 0;\n\ + indirect_reply_valid <= #1 '); + for entry in memsDict: + regsFile.write(entry['address']+'==(indirect_memory_select<<28) ? '+entry['name']+'_reply_valid :'); + regsFile.write(' 0;\n\ + end \n\ + end\n\ + \n'); +# end of write_indirect + +################################################################## +#write all the defines to the defs module +################################################################## +def write_defines(defsFile,regsDict, memsDict): + + for entry in regsDict: + defsFile.write( '\n`define REG_'+entry['name'].upper()+'_BITS\t\t\t\t'+entry['bits']+ + '\n`define REG_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define REG_'+entry['name'].upper()+'_DEFAULT\t\t\t\t'+entry['default']+ + '\n`define REG_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['addr']+'\n'); + + for entry in memsDict: + defsFile.write( '\n`define MEM_'+entry['name'].upper()+'_DATA_BITS\t\t\t\t'+entry['data_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR_BITS\t\t\t\t'+entry['addr_bits']+ + '\n`define MEM_'+entry['name'].upper()+'_WIDTH\t\t\t\t'+entry['width']+ + '\n`define MEM_'+entry['name'].upper()+'_DEPTH\t\t\t\t'+str(2**(int(entry['addr_bits'].split(':')[0])+1))+ + '\n`define MEM_'+entry['name'].upper()+'_ADDR\t\t\t\t'+entry['address']+'\n'); + +#end of write_defines + + +################################################################## +#write all the register offsets to the h template (to be included) +################################################################## +def write_h(hFile,regsDict,memsDict): + + hFile.write('##########This text should be copied to the head file #############\n\ + #Registers offset definitions\n\n'); + + for entry in regsDict: + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + hFile.write('#define SUME_'+block_name+'_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + hFile.write('#define SUME_'+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + +#end of write_h + +################################################################## +#write all the register offsets to the tcl file +################################################################## +def write_tcl(tclFile,regsDict,memsDict): + + for entry in regsDict: + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_OFFSET 0x'+entry['addr'][4:]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tclFile.write('set '+block_name+'_REGS_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_WIDTH '+entry['width']+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tclFile.write('set '+block_name+'_MEM_'+entry['name'].upper()+'_0_ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); + + +#end of write_tcl + +################################################################## +#write all the register offsets to table +################################################################## + +def write_tb(tbFile,regsDict,memsDict): + for entry in regsDict: + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' OFFSET 0x'+entry['addr'][4:]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' DEFAULT 0x'+entry['default'].split("'h")[-1]+'\n'); + tbFile.write('#define SUME '+block_name+' '+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + + for entry in memsDict: + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' WIDTH '+entry['width']+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' DEPTH '+str(2**(int(entry['addr_bits'].split(':')[0])+1))+'\n'); + tbFile.write('#define SUME '+block_name+' MEM_'+entry['name'].upper()+' ADDRESS 0x'+entry['address'].split("'h")[-1]+'\n'); +#end of write_tb + +################################################################## +#write top module's template (i.e. include this in your module) +################################################################## +def write_module_template(moduleFile,regsDict,memsDict): + +#first write static inclusions.... + moduleFile.write('`include "'+module_name+'_cpu_regs_defines.v"\n\ +\n\ +//parameters to be added to the top module parameters\n\ +#(\n\ + // AXI Registers Data Width\n\ + parameter C_S_AXI_DATA_WIDTH = 32,\n\ + parameter C_S_AXI_ADDR_WIDTH = 32\n\ +)\n\ +//ports to be added to the top module ports\n\ +(\n\ +// Signals for AXI_IP and IF_REG (Added for debug purposes)\n\ + // Slave AXI Ports\n\ + input S_AXI_ACLK,\n\ + input S_AXI_ARESETN,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,\n\ + input S_AXI_AWVALID,\n\ + input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,\n\ + input [C_S_AXI_DATA_WIDTH/8-1 : 0] S_AXI_WSTRB,\n\ + input S_AXI_WVALID,\n\ + input S_AXI_BREADY,\n\ + input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,\n\ + input S_AXI_ARVALID,\n\ + input S_AXI_RREADY,\n\ + output S_AXI_ARREADY,\n\ + output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,\n\ + output [1 : 0] S_AXI_RRESP,\n\ + output S_AXI_RVALID,\n\ + output S_AXI_WREADY,\n\ + output [1 :0] S_AXI_BRESP,\n\ + output S_AXI_BVALID,\n\ + output S_AXI_AWREADY\n\ +)\n\n'); + + first_item = True; + for entry in regsDict: + if first_item and (entry['endian']=="big") : + first_item = False; + moduleFile.write('\n\ + // define and assign default little endian\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + wire reg_'+entry['name']+'_default_little;\n'); + + for entry in regsDict: + if entry['endian']=="big" : + moduleFile.write('\ + assign reg_'+entry['name']+'_default_little = `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + +#then add design specific wires/regs: + + moduleFile.write('\n\ + // define registers\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="ROC" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + moduleFile.write(' wire '+entry['name']+'_reg_clear;\n') + if entry['type']=="RWS" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WO" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="WOE" : + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] '+entry['name']+'_reg;\n') + if entry['type']=="RWA" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + if entry['type']=="RWCR" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + if entry['type']=="RWCW" : + moduleFile.write(' reg [`REG_'+(entry['name']).upper()+'_BITS] ip2cpu_'+entry['name']+'_reg;\n') + moduleFile.write(' wire [`REG_'+(entry['name']).upper()+'_BITS] cpu2ip_'+entry['name']+'_reg;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear;\n') + moduleFile.write(' wire cpu2ip_'+entry['name']+'_reg_clear_d;\n') + + for entry in memsDict: + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_ADDR_BITS] '+entry['name']+'_addr;\n') + moduleFile.write(' wire [`MEM_'+(entry['name']).upper()+'_DATA_BITS] '+entry['name']+'_data;\n') + moduleFile.write(' wire '+entry['name']+'_rd_wrn;\n') + moduleFile.write(' wire '+entry['name']+'_cmd_valid;\n') + moduleFile.write(' reg [`MEM_'+(entry['name']).upper()+'DATA_BITS] '+entry['name']+'_reply;\n') + moduleFile.write(' reg '+entry['name']+'_reply_valid;\n') + + +#instantiate registers module + moduleFile.write('\n//Registers section\n\ + '+module_name+'_cpu_regs\n\ + #(\n\ + .C_BASE_ADDRESS (C_BASEADDR ),\n\ + .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH),\n\ + .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH)\n\ + ) '+module_name+'_cpu_regs_inst\n\ + (\n\ + // General ports\n\ + .clk (axis_aclk),\n\ + .resetn (axis_resetn),\n\ + // AXI Lite ports\n\ + .S_AXI_ACLK (S_AXI_ACLK),\n\ + .S_AXI_ARESETN (S_AXI_ARESETN),\n\ + .S_AXI_AWADDR (S_AXI_AWADDR),\n\ + .S_AXI_AWVALID (S_AXI_AWVALID),\n\ + .S_AXI_WDATA (S_AXI_WDATA),\n\ + .S_AXI_WSTRB (S_AXI_WSTRB),\n\ + .S_AXI_WVALID (S_AXI_WVALID),\n\ + .S_AXI_BREADY (S_AXI_BREADY),\n\ + .S_AXI_ARADDR (S_AXI_ARADDR),\n\ + .S_AXI_ARVALID (S_AXI_ARVALID),\n\ + .S_AXI_RREADY (S_AXI_RREADY),\n\ + .S_AXI_ARREADY (S_AXI_ARREADY),\n\ + .S_AXI_RDATA (S_AXI_RDATA),\n\ + .S_AXI_RRESP (S_AXI_RRESP),\n\ + .S_AXI_RVALID (S_AXI_RVALID),\n\ + .S_AXI_WREADY (S_AXI_WREADY),\n\ + .S_AXI_BRESP (S_AXI_BRESP),\n\ + .S_AXI_BVALID (S_AXI_BVALID),\n\ + .S_AXI_AWREADY (S_AXI_AWREADY),\n\ +\n\ + // Register ports\n'); + + for entry in regsDict: + if entry['type']=="RO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="ROC" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + moduleFile.write(' .'+entry['name']+'_reg_clear ('+entry['name']+'_reg_clear),\n') + if entry['type']=="RWS" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WO" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="WOE" : + moduleFile.write(' .'+entry['name']+'_reg ('+entry['name']+'_reg),\n') + if entry['type']=="RWA" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + if entry['type']=="RWCR" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + if entry['type']=="RWCW" : + moduleFile.write(' .ip2cpu_'+entry['name']+'_reg (ip2cpu_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg (cpu2ip_'+entry['name']+'_reg),\n') + moduleFile.write(' .cpu2ip_'+entry['name']+'_reg_clear (cpu2ip_'+entry['name']+'_reg_clear),\n') + + for entry in memsDict: + moduleFile.write(' .'+entry['name']+'_addr ('+entry['name']+'_addr),\n') + moduleFile.write(' .'+entry['name']+'_data ('+entry['name']+'_data),\n') + moduleFile.write(' .'+entry['name']+'_rd_wrn ('+entry['name']+'_rd_wrn),\n') + moduleFile.write(' .'+entry['name']+'_cmd_valid ('+entry['name']+'_cmd_valid ),\n') + moduleFile.write(' .'+entry['name']+'_reply ('+entry['name']+'_reply),\n') + moduleFile.write(' .'+entry['name']+'_reply_valid ('+entry['name']+'_reply_valid),\n') + + + moduleFile.write(' // Global Registers - user can select if to use\n\ + .cpu_resetn_soft(),//software reset, after cpu module\n\ + .resetn_soft (),//software reset to cpu module (from central reset management)\n\ + .resetn_sync (resetn_sync)//synchronized reset, use for better timing\n\ +);\n\ +//registers logic, current logic is just a placeholder for initial compil, required to be changed by the user\n'); + +#registers logic + + moduleFile.write('always @(posedge axis_aclk)\n\ + if (~resetn_sync) begin\n'); + + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWA" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + ip2cpu_'+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 \'h0\n;') + + moduleFile.write(' end\n\ + else begin\n') + for entry in regsDict: + if entry['type']=="RO" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + if entry['type']=="ROC" : + if entry['endian']=="little": + moduleFile.write('\ + '+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + for (byte_index = 0; byte_index <= (`REG_'+entry['name'].upper()+'_WIDTH/8-1); byte_index = byte_index +1)\n\ + '+entry['name']+'_reg[byte_index*8 +: 8] <= reg_'+entry['name']+'_default_little[(C_S_AXI_DATA_WIDTH/8-byte_index-1)*8 +: 8];\n'); + + + if entry['type']=="RWA" : + moduleFile.write(' ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;\n') + + if entry['type']=="RWCR" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear == 1\'b1) \n\ + '+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + + if entry['type']=="RWCW" : + if entry['endian']=="little": + moduleFile.write('\ + ip2cpu_'+entry['name']+'_reg <= #1 '+entry['name']+'_reg_clear ? \'h0 : `REG_'+entry['name'].upper()+'_DEFAULT;\n'); + if entry['endian']=="big": + moduleFile.write('\ + if ('+entry['name']+'_reg_clear_d == 1\'b1) \n\ + ip2cpu_'+entry['name']+'_reg <= #1 \'h0;\n\ + else\n\ + ip2cpu_'+entry['name']+'_reg <= #1 cpu2ip_'+entry['name']+'_reg;'); + moduleFile.write(' cpu_'+entry['name']+'_reg_clear_d <= #1 cpu_'+entry['name']+'_reg_clear;\n') + + moduleFile.write('\ + end\n\n') + + + +#end of write_module_template + + +######################################################################################## +# +# Main function body +# +######################################################################################## + + +# List of files to be generated. +filename_regs=''+module_name+'_cpu_regs.v' +filename_defs=''+module_name+'_cpu_regs_defines.v' +filename_template=''+module_name+'_cpu_template.v' +filename_h=''+module_name+'_regs_defines.h' +filename_tcl=''+module_name+'_regs_defines.tcl' +filename_tb=''+module_name+'_regs_defines.txt' + + +# Open the files for writing +regsFile = open(filename_regs, 'w') +defsFile = open(filename_defs, 'w') +moduleFile = open(filename_template, 'w') +hFile = open(filename_h, 'w') +tclFile = open(filename_tcl, 'w') +tbFile = open(filename_tb, 'w') + +# Write the header of each file +write_regs_header(regsFile) +write_defs_header(defsFile) +write_tcl_header(tclFile) +write_hFile_header(hFile) +write_tbFile_header(tbFile) + +#Write the regs module +#first the ports... +regsDict=create_regs_list() +memsDict=create_mems_list() +write_regs_ports(regsFile,regsDict, memsDict) + + +#then the wires... +write_regs_wires(regsFile,regsDict, memsDict) + +#resets etc..... +sync_reset(regsFile) + + +#registers logic... +write_logic(regsFile,regsDict) + +#indirect access... +if memsDict: + write_indirect(regsFile,memsDict) + +#tables... + +#close module..... +regsFile.write('endmodule\n') + +#write the defs module +write_defines(defsFile,regsDict, memsDict) + +#write the tcl module +write_tcl(tclFile,regsDict, memsDict) + +#write the default text to be copied to the h module +write_h(hFile,regsDict, memsDict) + +#write the default text to table file +write_tb(tbFile,regsDict, memsDict) + +#writes the default text to be copied to the top module +write_module_template(moduleFile,regsDict, memsDict) + + +# Close the output files +regsFile.close() +defsFile.close() +tclFile.close() +moduleFile.close() +hFile.close() +tbFile.close() diff --git a/tools/scripts/nf_test.py b/tools/scripts/nf_test.py index 0435260..af87d18 100755 --- a/tools/scripts/nf_test.py +++ b/tools/scripts/nf_test.py @@ -215,108 +215,108 @@ def run_hw_test(): print('') def run_sim_test(): - verifyCI() - #set up test dirs - passed = []; failed = []; gui = [] - for td in tests: - if args.tx: - if args.gui: - if args.packet_length and args.packet_no: - charis = os.system("make simtxgui TESTNAME=sim_tx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) - elif args.packet_length: - charis = os.system("make simtxgui TESTNAME=sim_tx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) - elif args.packet_no: - charis = os.system("make simtxgui TESTNAME=sim_tx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) - else: - charis = os.system("make simtxgui TESTNAME=sim_tx_dma -C %s" % (designDIr + '/test/')) - else: - if args.packet_length and args.packet_no: - charis = os.system("make simtx TESTNAME=sim_tx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) - elif args.packet_length: - charis = os.system("make simtx TESTNAME=sim_tx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) - elif args.packet_no: - charis = os.system("make simtx TESTNAME=sim_tx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) - else: - charis = os.system("make simtx TESTNAME=sim_tx_dma -C %s" % (designDIr + '/test/')) - elif args.rx: - if args.gui: - if args.packet_length and args.packet_no: - charis = os.system("make simrxgui TESTNAME=sim_rx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) - elif args.packet_length: - charis = os.system("make simrxgui TESTNAME=sim_rx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) - elif args.packet_no: - charis = os.system("make simrxgui TESTNAME=sim_rx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) - else: - charis = os.system("make simrxgui TESTNAME=sim_rx_dma -C %s" % (designDIr + '/test/')) - else: - if args.packet_length and args.packet_no: - charis = os.system("make simrx TESTNAME=sim_rx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) - elif args.packet_length: - charis = os.system("make simrx TESTNAME=sim_rx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) - elif args.packet_no: - charis = os.system("make simrx TESTNAME=sim_rx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) - else: - charis = os.system("make simrx TESTNAME=sim_rx_dma -C %s" % (designDIr + '/test/')) - elif args.txrx: - if args.gui: - if args.packet_length and args.packet_no: - charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) - elif args.packet_length: - charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) - elif args.packet_no: - charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) - else: - charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma -C %s" % (designDIr + '/test/')) - else: - if args.packet_length and args.packet_no: - charis = os.system("make simtxrx TESTNAME=sim_txrx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) - elif args.packet_length: - charis = os.system("make simtxrx TESTNAME=sim_txrx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) - elif args.packet_no: - charis = os.system("make simtxrx TESTNAME=sim_txrx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) - else: - charis = os.system("make simtxrx TESTNAME=sim_txrx_dma -C %s" % (designDIr + '/test/')) - elif args.gui: - charis = os.system("make simgui TESTNAME=%s -C %s" % (td, designDIr + '/test/')) - else: - charis = os.system("make sim TESTNAME=%s -C %s" % (td, designDIr + '/test/')) - print(charis) - - if args.type == 'sim': - subprocess.call(['cp', '-r', '-p', designDIr + '/hw/Makefile', src_test_dir]) - - if not args.no_compile: - buildSim() - if args.compile_only: - sys.exit(0) - prepareTestWorkDir(td) - global_run = designDIr + '/test/' + td + '/run.py' - dst_dir = proj_test_dir + '/' + td - which_run = global_run - cmd = [which_run, '--sim'] - os.chdir(dst_dir) - if args.isim: - cmd.append('isim') - elif args.vcs: - cmd.append('vcs') - elif args.vsim: - cmd.append('vsim') - else: - cmd.append('xsim') - if args.dump: - cmd.append('--dump') - if args.gui: - cmd.append('--gui') - if args.ci: - cmd.append('--ci') - cmd.append(args.ci) - cmd.append('--citest') - cmd.append(args.citest) - - #run tests - print('=== Running test ' + dst_dir + ' ...', end = " ") - print('using cmd', cmd) - + verifyCI() + #set up test dirs + passed = []; failed = []; gui = [] + for td in tests: + if args.tx: + if args.gui: + if args.packet_length and args.packet_no: + charis = os.system("make simtxgui TESTNAME=sim_tx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) + elif args.packet_length: + charis = os.system("make simtxgui TESTNAME=sim_tx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) + elif args.packet_no: + charis = os.system("make simtxgui TESTNAME=sim_tx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) + else: + charis = os.system("make simtxgui TESTNAME=sim_tx_dma -C %s" % (designDIr + '/test/')) + else: + if args.packet_length and args.packet_no: + charis = os.system("make simtx TESTNAME=sim_tx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) + elif args.packet_length: + charis = os.system("make simtx TESTNAME=sim_tx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) + elif args.packet_no: + charis = os.system("make simtx TESTNAME=sim_tx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) + else: + charis = os.system("make simtx TESTNAME=sim_tx_dma -C %s" % (designDIr + '/test/')) + elif args.rx: + if args.gui: + if args.packet_length and args.packet_no: + charis = os.system("make simrxgui TESTNAME=sim_rx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) + elif args.packet_length: + charis = os.system("make simrxgui TESTNAME=sim_rx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) + elif args.packet_no: + charis = os.system("make simrxgui TESTNAME=sim_rx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) + else: + charis = os.system("make simrxgui TESTNAME=sim_rx_dma -C %s" % (designDIr + '/test/')) + else: + if args.packet_length and args.packet_no: + charis = os.system("make simrx TESTNAME=sim_rx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) + elif args.packet_length: + charis = os.system("make simrx TESTNAME=sim_rx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) + elif args.packet_no: + charis = os.system("make simrx TESTNAME=sim_rx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) + else: + charis = os.system("make simrx TESTNAME=sim_rx_dma -C %s" % (designDIr + '/test/')) + elif args.txrx: + if args.gui: + if args.packet_length and args.packet_no: + charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) + elif args.packet_length: + charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) + elif args.packet_no: + charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) + else: + charis = os.system("make simtxrxgui TESTNAME=sim_txrx_dma -C %s" % (designDIr + '/test/')) + else: + if args.packet_length and args.packet_no: + charis = os.system("make simtxrx TESTNAME=sim_txrx_dma PKTLEN=%d PKTNO=%d -C %s" % (length, number, designDIr + '/test/')) + elif args.packet_length: + charis = os.system("make simtxrx TESTNAME=sim_txrx_dma PKTLEN=%d -C %s" % (length, designDIr + '/test/')) + elif args.packet_no: + charis = os.system("make simtxrx TESTNAME=sim_txrx_dma PKTNO=%d -C %s" % (number, designDIr + '/test/')) + else: + charis = os.system("make simtxrx TESTNAME=sim_txrx_dma -C %s" % (designDIr + '/test/')) + elif args.gui: + charis = os.system("make simgui TESTNAME=%s -C %s" % (td, designDIr + '/test/')) + else: + charis = os.system("make sim TESTNAME=%s -C %s" % (td, designDIr + '/test/')) + print(charis) + + if args.type == 'sim': + subprocess.call(['cp', '-r', '-p', designDIr + '/hw/Makefile', src_test_dir]) + + if not args.no_compile: + buildSim() + if args.compile_only: + sys.exit(0) + prepareTestWorkDir(td) + global_run = designDIr + '/test/' + td + '/run.py' + dst_dir = proj_test_dir + '/' + td + which_run = global_run + cmd = [which_run, '--sim'] + os.chdir(dst_dir) + if args.isim: + cmd.append('isim') + elif args.vcs: + cmd.append('vcs') + elif args.vsim: + cmd.append('vsim') + else: + cmd.append('xsim') + if args.dump: + cmd.append('--dump') + if args.gui: + cmd.append('--gui') + if args.ci: + cmd.append('--ci') + cmd.append(args.ci) + cmd.append('--citest') + cmd.append(args.citest) + + #run tests + print('=== Running test ' + dst_dir + ' ...', end = " ") + print('using cmd', cmd) + def handleArgs(): parser = argparse.ArgumentParser() parser.add_argument('type', choices=['hw','sim'], help='Type of test to run: hw or sw') @@ -360,32 +360,35 @@ def handleArgs(): print('Error: --make_opt, --sim_opt, --dump, --vcs, --vsim --isim, and --gui are only compatible with simulation tests') sys.exit(1) -def printEnv(): - print("NetFPGA environment:") - print(" Root dir: " + rootDir) - print(" Project name: " + project) - print(" Project dir: " + projDir) - print(" Work dir: " + workDir) +def printEnv(dir_only = False): + print("NetFPGA environment:") + print(" Root dir: " + rootDir) + print(" Project name: " + project) + print(" Project dir: " + projDir) + print(" Work dir: " + workDir) + + if dir_only: + return - if args.type == 'sim': - subprocess.call(['cp', '-r', '-p', designDIr + '/hw/Makefile', src_test_dir]) - os.system("make reg -C %s" % (designDIr + '/test/')) - else: - os.system("make reg -C %s" % (designDIr + '/hw/')) + if args.type == 'sim': + subprocess.call(['cp', '-r', '-p', designDIr + '/hw/Makefile', src_test_dir]) + os.system("make reg -C %s" % (designDIr + '/test/')) + else: + os.system("make reg -C %s" % (designDIr + '/hw/')) # verify that NF_ROOT has been set and exists def identifyRoot(): - global rootDir; global projDir; global designDIr - try: - rootDir = os.path.abspath(os.environ['NFPLUS_FOLDER']) - designDIr = os.path.abspath(os.environ['NF_DESIGN_DIR']) - projDir = designDIr - - if not os.path.exists(rootDir): - print("NetFPGA directory " + rootDir + " as referenced by environment variable 'NFPLUS_FOLDER' does not exist") - except(KeyError): - print("Please set the environment variable 'NFPLUS_FOLDER' to point to the local NetFPGA source") - os.environ['NFPLUS_FOLDER'] = rootDir + global rootDir; global projDir; global designDIr + try: + rootDir = os.path.abspath(os.environ['NFPLUS_FOLDER']) + designDIr = os.path.abspath(os.environ['NF_DESIGN_DIR']) + projDir = designDIr + + if not os.path.exists(rootDir): + print("NetFPGA directory " + rootDir + " as referenced by environment variable 'NFPLUS_FOLDER' does not exist") + except(KeyError): + print("Please set the environment variable 'NFPLUS_FOLDER' to point to the local NetFPGA source") + os.environ['NFPLUS_FOLDER'] = rootDir def identifyWorkDir(): global workDir @@ -394,7 +397,7 @@ def identifyWorkDir(): except(KeyError): login = os.getlogin() workDir = '/tmp/' + login - + if not os.path.exists(workDir): try: os.mkdir(workDir) @@ -421,36 +424,36 @@ def identifyWorkDir(): src_test_dir = os.environ['NF_DESIGN_DIR'] + '/test' def identifyTests(): - test_name = ''; both_test_name = '' - global length - global number - if args.major: - both_test_name = 'both_' + args.major + '_' + args.minor - if args.type == 'sim': - test_name = 'sim_' + args.major + '_' + args.minor - else: - test_name = 'hw_' + args.major + '_' + args.minor - else: - both_test_name = 'both_' - if args.type == 'sim': - test_name = 'sim_' - else: - test_name = 'hw_' - - if args.packet_length: - length = args.packet_length - - if args.packet_no: - number = args.packet_no - - dirs = os.listdir(os.environ['NF_DESIGN_DIR'] + '/test') - global tests;tests = [] - for test in dirs: - if test.endswith(test_name) or test.endswith(both_test_name): - tests.append(test) - if len(tests) == 0: - print('=== Error: No tests match ' + test_name + ' - exiting') - sys.exit(0) + test_name = ''; both_test_name = '' + global length + global number + if args.major: + both_test_name = 'both_' + args.major + '_' + args.minor + if args.type == 'sim': + test_name = 'sim_' + args.major + '_' + args.minor + else: + test_name = 'hw_' + args.major + '_' + args.minor + else: + both_test_name = 'both_' + if args.type == 'sim': + test_name = 'sim_' + else: + test_name = 'hw_' + + if args.packet_length: + length = args.packet_length + + if args.packet_no: + number = args.packet_no + + dirs = os.listdir(os.environ['NF_DESIGN_DIR'] + '/test') + global tests;tests = [] + for test in dirs: + if test.endswith(test_name) or test.endswith(both_test_name): + tests.append(test) + if len(tests) == 0: + print('=== Error: No tests match ' + test_name + ' - exiting') + sys.exit(0) def prepareWorkDir(): global project; global projDir @@ -471,33 +474,33 @@ def prepareWorkDir(): subprocess.call(['cp', '-r', '-p', src_test_dir + '/connections', projDir]) def prepareTestWorkDir(testName): - dst_dir = proj_test_dir + '/' + testName - src_dir = src_test_dir + '/' + testName - # look for a test - if args.type == 'sim': - print('=== Setting up test in ' + dst_dir) - # check if exists, make if doesn't, error if fail - if not os.path.exists(dst_dir): - try: - os.mkdir(dst_dir) - except OSError as exc: - print('Error: Unable to create test directory ' + dst_dir) - print(exc.strerror, exc.filename) - sys.exit(1) - # cp files to dst_dir - if args.type == 'sim': - for file in glob.glob(src_dir + '/*'): - subprocess.call(['cp', '-r', '-p', file, dst_dir]) - for i in range(2): - subprocess.call(['cp', '-r', '-p', src_test_dir + '/nf_interface_%d_log.axi' %i, dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/nf_interface_%d_stim.axi' %i, dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/nf_interface_%d_expected.axi' %i, dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/dma_0_log.axi', dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/dma_0_expected.axi', dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/Makefile', dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/reg_stim.log', dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/reg_expect.axi', dst_dir]) - subprocess.call(['cp', '-r', '-p', src_test_dir + '/reg_stim.axi', dst_dir]) + dst_dir = proj_test_dir + '/' + testName + src_dir = src_test_dir + '/' + testName + # look for a test + if args.type == 'sim': + print('=== Setting up test in ' + dst_dir) + # check if exists, make if doesn't, error if fail + if not os.path.exists(dst_dir): + try: + os.mkdir(dst_dir) + except OSError as exc: + print('Error: Unable to create test directory ' + dst_dir) + print(exc.strerror, exc.filename) + sys.exit(1) + # cp files to dst_dir + if args.type == 'sim': + for file in glob.glob(src_dir + '/*'): + subprocess.call(['cp', '-r', '-p', file, dst_dir]) + for i in range(2): + subprocess.call(['cp', '-r', '-p', src_test_dir + '/nf_interface_%d_log.axi' %i, dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/nf_interface_%d_stim.axi' %i, dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/nf_interface_%d_expected.axi' %i, dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/dma_0_log.axi', dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/dma_0_expected.axi', dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/Makefile', dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/reg_stim.log', dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/reg_expect.axi', dst_dir]) + subprocess.call(['cp', '-r', '-p', src_test_dir + '/reg_stim.axi', dst_dir]) def buildSim(): project = os.path.basename(os.path.abspath(os.environ['NF_DESIGN_DIR'])) @@ -637,6 +640,7 @@ def printScriptOutput(result, output): else: run_hw_test() +printEnv(dir_only=True) diff --git a/tools/settings.sh b/tools/settings.sh index a852b42..0b21618 100644 --- a/tools/settings.sh +++ b/tools/settings.sh @@ -23,13 +23,14 @@ # @NETFPGA_LICENSE_HEADER_END@ # ### User defined -export NFPLUS_FOLDER=${HOME}/NetFPGA-PLUS +export NFPLUS_FOLDER=${HOME}/NetFPGA-PLUS-GW export BOARD_NAME=au250 -export NF_PROJECT_NAME=reference_switch +export NF_PROJECT_NAME=reference_dma export PYTHON_BNRY=/usr/bin/python3 ### Don't change -export VERSION=2023.2 + +export VERSION=2023.1 export PROJECTS=${NFPLUS_FOLDER}/projects export CONTRIB_PROJECTS=${NFPLUS_FOLDER}/contrib-projects export NF_DESIGN_DIR=${NFPLUS_FOLDER}/hw/projects/${NF_PROJECT_NAME} @@ -56,6 +57,7 @@ if [ ${BOARD_NAME} != "au280" -a \ return -1 else board_name=`echo "puts [get_board_parts -quiet -latest_file_version \"*:${BOARD_NAME}:*\"]" | vivado -nolog -nojournal -mode tcl | grep xilinx` + echo "**** GREG: BOARD_NAME is $BOARD_NAME and board_name is $board_name" if [ ${BOARD_NAME} = "au280" ] ; then device="xcu280-fsvh2892-2L-e" elif [ ${BOARD_NAME} = "au250" ] ; then @@ -74,7 +76,7 @@ if [ ! -d ${NF_DESIGN_DIR} ] ; then return -1 fi -echo "[ok] All parameters has been checked." +echo "[ok] All parameters have been checked." vivado_version=`echo $XILINX_VIVADO | awk -F "/" 'NF>1{print $NF}'` if [ -z ${vivado_version} ]; then