diff options
Diffstat (limited to 'fpga/usrp3/lib/control/map/axis_muxed_kv_map.v')
| -rw-r--r-- | fpga/usrp3/lib/control/map/axis_muxed_kv_map.v | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/control/map/axis_muxed_kv_map.v b/fpga/usrp3/lib/control/map/axis_muxed_kv_map.v new file mode 100644 index 000000000..152cee8eb --- /dev/null +++ b/fpga/usrp3/lib/control/map/axis_muxed_kv_map.v @@ -0,0 +1,206 @@ +// +// Copyright 2018 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: axis_muxed_kv_map +// +// Description: +// +// This module implements a memory that stores key and value (KV) pairs such +// that the value can be looked up using the key (e.g., for a routing table). +// This implementation uses AXI stream for both inserting key-value pairs and +// for looking up a value by its key. It also supports multiple find/result +// AXI streams, which share the same KV map internally. +// +// Values are inserted into the KV map using the axis_insert_* AXI stream. A +// value can be looked up by its key using the axis_find_* AXI stream, in +// which case the resulting value is output on the axis_result_* AXI stream. +// +// Ports: +// +// axis_insert_tdest : Key to insert into the KV map +// axis_insert_tdata : Value to associate with the key in TDEST +// axis_insert_tvalid : Standard AXI stream TVALID +// axis_insert_tready : Standard AXI stream TREADY +// +// axis_find_tdata : Key to look up in the KV map +// axis_find_tvalid : Standard AXI stream TVALID +// axis_find_tready : Standard AXI stream TREADY +// +// axis_result_tdata : Value associated with key that was input on axis_find +// axis_result_tkeep : Indicates if TDATA contains a valid value (i.e., +// TKEEP is 0 if the lookup fails to find a match) +// axis_result_tvalid : Standard AXI stream TVALID +// axis_result_tready : Standard AXI stream TREADY +// +// Parameters: +// +// KEY_WIDTH : Width of the key (axis_insert_tdest, axis_find_tdata) +// VAL_WIDTH : Width of the value (axis_insert_tdata, axis_result_tdata) +// SIZE : Size of the KV map (i.e., 2**SIZE key-value pairs) +// NUM_PORTS : Number of AXI-Stream ports for the find and result interfaces +// + +module axis_muxed_kv_map #( + parameter KEY_WIDTH = 16, + parameter VAL_WIDTH = 32, + parameter SIZE = 6, + parameter NUM_PORTS = 4 +) ( + input wire clk, + input wire reset, + + input wire [KEY_WIDTH-1:0] axis_insert_tdest, + input wire [VAL_WIDTH-1:0] axis_insert_tdata, + input wire axis_insert_tvalid, + output wire axis_insert_tready, + + input wire [(KEY_WIDTH*NUM_PORTS)-1:0] axis_find_tdata, + input wire [NUM_PORTS-1:0] axis_find_tvalid, + output wire [NUM_PORTS-1:0] axis_find_tready, + + output wire [(VAL_WIDTH*NUM_PORTS)-1:0] axis_result_tdata, + output wire [NUM_PORTS-1:0] axis_result_tkeep, + output wire [NUM_PORTS-1:0] axis_result_tvalid, + input wire [NUM_PORTS-1:0] axis_result_tready +); + + localparam MUX_W = $clog2(NUM_PORTS) + KEY_WIDTH; + localparam DEMUX_W = $clog2(NUM_PORTS) + VAL_WIDTH + 1; + genvar i; + + localparam [1:0] ST_IDLE = 2'd0; + localparam [1:0] ST_REQUEST = 2'd1; + localparam [1:0] ST_PENDING = 2'd2; + + //--------------------------------------------------------- + // Demux find ports + //--------------------------------------------------------- + wire [KEY_WIDTH-1:0] find_key, find_key_reg; + wire find_key_stb; + wire [$clog2(NUM_PORTS)-1:0] find_dest, find_dest_reg; + wire find_key_valid, find_key_valid_reg; + wire find_ready; + reg find_in_progress = 1'b0; + wire insert_stb; + wire insert_busy; + wire find_res_stb; + wire [VAL_WIDTH-1:0] find_res_val; + wire find_res_match, find_res_ready; + + wire [(MUX_W*NUM_PORTS)-1:0] mux_tdata; + generate for (i = 0; i < NUM_PORTS; i = i + 1) begin : gen_mux_input + assign mux_tdata[(MUX_W*i)+KEY_WIDTH-1:MUX_W*i] = axis_find_tdata[(KEY_WIDTH*i)+:KEY_WIDTH]; + assign mux_tdata[(MUX_W*(i+1))-1:(MUX_W*i)+KEY_WIDTH] = i; + end endgenerate + + axi_mux #( + .WIDTH(KEY_WIDTH+$clog2(NUM_PORTS)), .SIZE(NUM_PORTS), + .PRE_FIFO_SIZE(0), .POST_FIFO_SIZE($clog2(NUM_PORTS)) + ) mux_i ( + .clk(clk), .reset(reset), .clear(1'b0), + .i_tdata(mux_tdata), .i_tlast({NUM_PORTS{1'b1}}), + .i_tvalid(axis_find_tvalid), .i_tready(axis_find_tready), + .o_tdata({find_dest_reg, find_key_reg}), .o_tlast(), + .o_tvalid(find_key_valid_reg), .o_tready(find_ready) + ); + + axi_fifo #( + .WIDTH(KEY_WIDTH+$clog2(NUM_PORTS)), .SIZE(1) + ) mux_reg_i ( + .clk(clk), .reset(reset), .clear(1'b0), + .i_tdata({find_dest_reg, find_key_reg}), + .i_tvalid(find_key_valid_reg), .i_tready(find_ready), + .o_tdata({find_dest, find_key}), + .o_tvalid(find_key_valid), .o_tready(find_res_stb), + .space(), .occupied() + ); + + always @(posedge clk) begin + if (reset) begin + find_in_progress <= 1'b0; + end else begin + if (find_key_stb) begin + find_in_progress <= 1'b1; + end else if (find_res_stb) begin + find_in_progress <= 1'b0; + end + end + end + + // find_key_stb indicates when to begin a new KV map lookup. We must wait + // until the output mux is ready before starting a lookup. + assign find_key_stb = find_key_valid & find_res_ready & ~find_in_progress; + + //--------------------------------------------------------- + // Insert logic + //--------------------------------------------------------- + reg [1:0] ins_state = ST_IDLE; + always @(posedge clk) begin + if (reset) begin + ins_state <= ST_IDLE; + end else begin + case (ins_state) + ST_IDLE: + if (axis_insert_tvalid & ~insert_busy) + ins_state <= ST_REQUEST; + ST_REQUEST: + ins_state <= ST_PENDING; + ST_PENDING: + if (~insert_busy) + ins_state <= ST_IDLE; + default: + ins_state <= ST_IDLE; + endcase + end + end + + assign axis_insert_tready = axis_insert_tvalid & (ins_state == ST_PENDING) & ~insert_busy; + assign insert_stb = axis_insert_tvalid & (ins_state == ST_REQUEST); + + //--------------------------------------------------------- + // KV map instantiation + //--------------------------------------------------------- + kv_map #( + .KEY_WIDTH (KEY_WIDTH), + .VAL_WIDTH (VAL_WIDTH), + .SIZE (SIZE) + ) map_i ( + .clk (clk), + .reset (reset), + .insert_stb (insert_stb), + .insert_key (axis_insert_tdest), + .insert_val (axis_insert_tdata), + .insert_busy (insert_busy), + .find_key_stb (find_key_stb), + .find_key (find_key), + .find_res_stb (find_res_stb), + .find_res_match (find_res_match), + .find_res_val (find_res_val), + .count (/* unused */) + ); + + //--------------------------------------------------------- + // Mux results port + //--------------------------------------------------------- + wire [(DEMUX_W*NUM_PORTS)-1:0] demux_tdata; + wire [DEMUX_W-1:0] hdr; + axi_demux #( + .WIDTH(DEMUX_W), .SIZE(NUM_PORTS), + .PRE_FIFO_SIZE(1), .POST_FIFO_SIZE(0) + ) demux_i ( + .clk(clk), .reset(reset), .clear(1'b0), + .header(hdr), .dest(hdr[DEMUX_W-1:VAL_WIDTH+1]), + .i_tdata({find_dest, find_res_match, find_res_val}), .i_tlast(1'b1), + .i_tvalid(find_res_stb), .i_tready(find_res_ready), + .o_tdata(demux_tdata), .o_tlast(), + .o_tvalid(axis_result_tvalid), .o_tready(axis_result_tready) + ); + + generate for (i = 0; i < NUM_PORTS; i = i + 1) begin : gen_result_output + assign axis_result_tdata[(VAL_WIDTH*i)+:VAL_WIDTH] = demux_tdata[(DEMUX_W*i)+VAL_WIDTH-1:DEMUX_W*i]; + assign axis_result_tkeep[i] = demux_tdata[(DEMUX_W*i)+VAL_WIDTH]; + end endgenerate + +endmodule |
