From 7d7cba08382c10f55bf132d5867cd69627bae288 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 19 Jul 2016 16:21:15 -0700 Subject: [PATCH 1/7] Add bus width checks --- tb/gmii_ep.py | 4 ++++ tb/xgmii_ep.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tb/gmii_ep.py b/tb/gmii_ep.py index 528be9ab..eccbeb39 100644 --- a/tb/gmii_ep.py +++ b/tb/gmii_ep.py @@ -88,6 +88,8 @@ def GMIISource(clk, rst, fifo=None, name=None): + assert len(txd) == 8 + @instance def logic(): frame = None @@ -141,6 +143,8 @@ def GMIISink(clk, rst, fifo=None, name=None): + assert len(rxd) == 8 + @instance def logic(): frame = None diff --git a/tb/xgmii_ep.py b/tb/xgmii_ep.py index 5f29af57..cca98fb6 100644 --- a/tb/xgmii_ep.py +++ b/tb/xgmii_ep.py @@ -109,6 +109,8 @@ def XGMIISource(clk, rst, fifo=None, name=None): + assert len(txd) == 64 + @instance def logic(): frame = None @@ -210,6 +212,8 @@ def XGMIISink(clk, rst, fifo=None, name=None): + assert len(rxd) == 64 + @instance def logic(): frame = None From c34a9c2197434be9640d021903161a9e92f3c11d Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 19 Jul 2016 19:59:47 -0700 Subject: [PATCH 2/7] Add 32 bit XGMII support --- tb/xgmii_ep.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/tb/xgmii_ep.py b/tb/xgmii_ep.py index cca98fb6..4a1c3ec6 100644 --- a/tb/xgmii_ep.py +++ b/tb/xgmii_ep.py @@ -109,7 +109,9 @@ def XGMIISource(clk, rst, fifo=None, name=None): - assert len(txd) == 64 + assert len(txd) in [32, 64] + + bw = int(len(txd)/8) @instance def logic(): @@ -125,23 +127,23 @@ def XGMIISource(clk, rst, if rst: frame = None - txd.next = 0x0707070707070707 - txc.next = 0xff + txd.next = 0x0707070707070707 if bw == 8 else 0x07070707 + txc.next = 0xff if bw == 8 else 0xf dl = [] cl = [] ifg_cnt = 0 deficit_idle_cnt = 0 nt = False else: - if ifg_cnt > 7: - ifg_cnt -= 8 - txd.next = 0x0707070707070707 - txc.next = 0xff + if ifg_cnt > bw-1: + ifg_cnt -= bw + txd.next = 0x0707070707070707 if bw == 8 else 0x07070707 + txc.next = 0xff if bw == 8 else 0xf elif len(dl) > 0 or nt: d = 0 c = 0 - for i in range(8): + for i in range(bw): if len(dl) > 0: d |= dl.pop(0) << (8*i) c |= cl.pop(0) << i @@ -150,7 +152,7 @@ def XGMIISource(clk, rst, if nt: d |= 0xfd << (8*i) nt = False - ifg_cnt = 12 - (8-i) + deficit_idle_cnt + ifg_cnt = 12 - (bw-i) + deficit_idle_cnt else: d |= 0x07 << (8*i) c |= 1 << i @@ -182,7 +184,7 @@ def XGMIISource(clk, rst, d = 0xfb07070707 c = 0x1f - for i in range(k,8): + for i in range(k,bw): if len(dl) > 0: d |= dl.pop(0) << (8*i) c |= cl.pop(0) << i @@ -200,8 +202,8 @@ def XGMIISource(clk, rst, else: ifg_cnt = 0 deficit_idle_cnt = 0 - txd.next = 0x0707070707070707 - txc.next = 0xff + txd.next = 0x0707070707070707 if bw == 8 else 0x07070707 + txc.next = 0xff if bw == 8 else 0xf return logic @@ -212,7 +214,9 @@ def XGMIISink(clk, rst, fifo=None, name=None): - assert len(rxd) == 64 + assert len(rxd) in [32, 64] + + bw = int(len(rxd)/8) @instance def logic(): @@ -234,10 +238,10 @@ def XGMIISink(clk, rst, frame = XGMIIFrame() d = [0x55] c = [0] - for i in range(1,8): + for i in range(1,bw): d.append((int(rxd) >> (8*i)) & 0xff) c.append((int(rxc) >> i) & 1) - elif (rxc >> 4) & 1 and (rxd >> 32) & 0xff == 0xfb: + elif bw == 8 and (rxc >> 4) & 1 and (rxd >> 32) & 0xff == 0xfb: # start in lane 4 frame = XGMIIFrame() d = [0x55] @@ -246,7 +250,7 @@ def XGMIISink(clk, rst, d.append((int(rxd) >> (8*i)) & 0xff) c.append((int(rxc) >> i) & 1) else: - for i in range(8): + for i in range(bw): if (rxc >> i) & 1 and (rxd >> (8*i)) & 0xff == 0xfd: # terminate frame.parse(d, c) From 52fc34d82eb5884b03d15bff0c61fa2410d3e1ee Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 20 Jul 2016 12:36:59 -0700 Subject: [PATCH 3/7] Assume first tkeep bit is always set --- rtl/axis_frame_length_adjust.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtl/axis_frame_length_adjust.v b/rtl/axis_frame_length_adjust.v index fa36f3ca..59c8d5f3 100644 --- a/rtl/axis_frame_length_adjust.v +++ b/rtl/axis_frame_length_adjust.v @@ -272,8 +272,8 @@ always @* begin if (input_axis_tready & input_axis_tvalid) begin // transfer through - word_cnt = 0; - for (i = 0; i <= KEEP_WIDTH; i = i + 1) begin + word_cnt = 1; + for (i = 1; i <= KEEP_WIDTH; i = i + 1) begin //bit_cnt = bit_cnt + monitor_axis_tkeep[i]; if (input_axis_tkeep == ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-i)) word_cnt = i; end From d023213fdac53e390e7d9f4e4953e569eaf983a4 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 24 Jul 2016 13:06:59 -0700 Subject: [PATCH 4/7] Support generating asymmetric crosspoints --- rtl/axis_crosspoint.py | 57 ++++++++++++++++++++++----------------- rtl/axis_crosspoint_64.py | 57 ++++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 50 deletions(-) diff --git a/rtl/axis_crosspoint.py b/rtl/axis_crosspoint.py index f1dd1832..260b2398 100755 --- a/rtl/axis_crosspoint.py +++ b/rtl/axis_crosspoint.py @@ -11,7 +11,7 @@ from jinja2 import Template def main(): parser = argparse.ArgumentParser(description=__doc__.strip()) - parser.add_argument('-p', '--ports', type=int, default=4, help="number of ports") + parser.add_argument('-p', '--ports', type=int, default=[4], nargs='+', help="number of ports") parser.add_argument('-n', '--name', type=str, help="module name") parser.add_argument('-o', '--output', type=str, help="output file name") @@ -24,8 +24,15 @@ def main(): exit(1) def generate(ports=4, name=None, output=None): + if type(ports) is int: + m = n = ports + elif len(ports) == 1: + m = n = ports[0] + else: + m, n = ports + if name is None: - name = "axis_crosspoint_{0}x{0}".format(ports) + name = "axis_crosspoint_{0}x{1}".format(m, n) if output is None: output = name + ".v" @@ -34,9 +41,9 @@ def generate(ports=4, name=None, output=None): output_file = open(output, 'w') - print("Generating {0} port AXI Stream crosspoint {1}...".format(ports, name)) + print("Generating {0}x{1} port AXI Stream crosspoint {2}...".format(m, n, name)) - select_width = int(math.ceil(math.log(ports, 2))) + select_width = int(math.ceil(math.log(m, 2))) t = Template(u"""/* @@ -67,7 +74,7 @@ THE SOFTWARE. `timescale 1ns / 1ps /* - * AXI4-Stream {{n}}x{{n}} crosspoint + * AXI4-Stream {{m}}x{{n}} crosspoint */ module {{name}} # ( @@ -80,7 +87,7 @@ module {{name}} # /* * AXI Stream inputs */ -{%- for p in ports %} +{%- for p in range(m) %} input wire [DATA_WIDTH-1:0] input_{{p}}_axis_tdata, input wire input_{{p}}_axis_tvalid, input wire input_{{p}}_axis_tlast, @@ -89,7 +96,7 @@ module {{name}} # /* * AXI Stream outputs */ -{%- for p in ports %} +{%- for p in range(n) %} output wire [DATA_WIDTH-1:0] output_{{p}}_axis_tdata, output wire output_{{p}}_axis_tvalid, output wire output_{{p}}_axis_tlast, @@ -98,28 +105,28 @@ module {{name}} # /* * Control */ -{%- for p in ports %} +{%- for p in range(n) %} input wire [{{w-1}}:0] output_{{p}}_select{% if not loop.last %},{% endif %} {%- endfor %} ); -{% for p in ports %} +{% for p in range(m) %} reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; reg input_{{p}}_axis_tvalid_reg = 1'b0; reg input_{{p}}_axis_tlast_reg = 1'b0; reg input_{{p}}_axis_tuser_reg = 1'b0; {% endfor %} -{%- for p in ports %} +{%- for p in range(n) %} reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; reg output_{{p}}_axis_tvalid_reg = 1'b0; reg output_{{p}}_axis_tlast_reg = 1'b0; reg output_{{p}}_axis_tuser_reg = 1'b0; {% endfor %} -{%- for p in ports %} +{%- for p in range(n) %} reg [{{w-1}}:0] output_{{p}}_select_reg = {{w}}'d0; {%- endfor %} -{% for p in ports %} +{% for p in range(n) %} assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg; assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg; assign output_{{p}}_axis_tlast = output_{{p}}_axis_tlast_reg; @@ -128,41 +135,41 @@ assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg; always @(posedge clk) begin if (rst) begin -{%- for p in ports %} +{%- for p in range(n) %} output_{{p}}_select_reg <= {{w}}'d0; {%- endfor %} -{% for p in ports %} +{% for p in range(m) %} input_{{p}}_axis_tvalid_reg <= 1'b0; {%- endfor %} -{% for p in ports %} +{% for p in range(n) %} output_{{p}}_axis_tvalid_reg <= 1'b0; {%- endfor %} end else begin -{%- for p in ports %} +{%- for p in range(m) %} input_{{p}}_axis_tvalid_reg <= input_{{p}}_axis_tvalid; {%- endfor %} -{% for p in ports %} +{% for p in range(n) %} output_{{p}}_select_reg <= output_{{p}}_select; {%- endfor %} -{%- for p in ports %} +{%- for p in range(n) %} case (output_{{p}}_select_reg) -{%- for q in ports %} +{%- for q in range(m) %} {{w}}'d{{q}}: output_{{p}}_axis_tvalid_reg <= input_{{q}}_axis_tvalid_reg; {%- endfor %} endcase {%- endfor %} end -{%- for p in ports %} +{%- for p in range(m) %} input_{{p}}_axis_tdata_reg <= input_{{p}}_axis_tdata; input_{{p}}_axis_tlast_reg <= input_{{p}}_axis_tlast; input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser; {%- endfor %} -{%- for p in ports %} +{%- for p in range(n) %} case (output_{{p}}_select_reg) -{%- for q in ports %} +{%- for q in range(m) %} {{w}}'d{{q}}: begin output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg; output_{{p}}_axis_tlast_reg <= input_{{q}}_axis_tlast_reg; @@ -178,10 +185,10 @@ endmodule """) output_file.write(t.render( - n=ports, + m=m, + n=n, w=select_width, - name=name, - ports=range(ports) + name=name )) print("Done") diff --git a/rtl/axis_crosspoint_64.py b/rtl/axis_crosspoint_64.py index 75ff0bba..25d2acde 100755 --- a/rtl/axis_crosspoint_64.py +++ b/rtl/axis_crosspoint_64.py @@ -11,7 +11,7 @@ from jinja2 import Template def main(): parser = argparse.ArgumentParser(description=__doc__.strip()) - parser.add_argument('-p', '--ports', type=int, default=4, help="number of ports") + parser.add_argument('-p', '--ports', type=int, default=[4], nargs='+', help="number of ports") parser.add_argument('-n', '--name', type=str, help="module name") parser.add_argument('-o', '--output', type=str, help="output file name") @@ -24,8 +24,15 @@ def main(): exit(1) def generate(ports=4, name=None, output=None): + if type(ports) is int: + m = n = ports + elif len(ports) == 1: + m = n = ports[0] + else: + m, n = ports + if name is None: - name = "axis_crosspoint_64_{0}x{0}".format(ports) + name = "axis_crosspoint_64_{0}x{1}".format(m, n) if output is None: output = name + ".v" @@ -34,9 +41,9 @@ def generate(ports=4, name=None, output=None): output_file = open(output, 'w') - print("Generating {0} port AXI Stream crosspoint {1}...".format(ports, name)) + print("Generating {0}x{1} port AXI Stream crosspoint {2}...".format(m, n, name)) - select_width = int(math.ceil(math.log(ports, 2))) + select_width = int(math.ceil(math.log(m, 2))) t = Template(u"""/* @@ -67,7 +74,7 @@ THE SOFTWARE. `timescale 1ns / 1ps /* - * AXI4-Stream {{n}}x{{n}} crosspoint (64 bit datapath) + * AXI4-Stream {{m}}x{{n}} crosspoint (64 bit datapath) */ module {{name}} # ( @@ -81,7 +88,7 @@ module {{name}} # /* * AXI Stream inputs */ -{%- for p in ports %} +{%- for p in range(m) %} input wire [DATA_WIDTH-1:0] input_{{p}}_axis_tdata, input wire [KEEP_WIDTH-1:0] input_{{p}}_axis_tkeep, input wire input_{{p}}_axis_tvalid, @@ -91,7 +98,7 @@ module {{name}} # /* * AXI Stream outputs */ -{%- for p in ports %} +{%- for p in range(n) %} output wire [DATA_WIDTH-1:0] output_{{p}}_axis_tdata, output wire [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep, output wire output_{{p}}_axis_tvalid, @@ -101,11 +108,11 @@ module {{name}} # /* * Control */ -{%- for p in ports %} +{%- for p in range(n) %} input wire [{{w-1}}:0] output_{{p}}_select{% if not loop.last %},{% endif %} {%- endfor %} ); -{% for p in ports %} +{% for p in range(m) %} reg [DATA_WIDTH-1:0] input_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; reg [KEEP_WIDTH-1:0] input_{{p}}_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; reg input_{{p}}_axis_tvalid_reg = 1'b0; @@ -113,7 +120,7 @@ reg input_{{p}}_axis_tlast_reg = 1'b0; reg input_{{p}}_axis_tuser_reg = 1'b0; {% endfor %} -{%- for p in ports %} +{%- for p in range(n) %} reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; reg [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; reg output_{{p}}_axis_tvalid_reg = 1'b0; @@ -121,10 +128,10 @@ reg output_{{p}}_axis_tlast_reg = 1'b0; reg output_{{p}}_axis_tuser_reg = 1'b0; {% endfor %} -{%- for p in ports %} +{%- for p in range(n) %} reg [{{w-1}}:0] output_{{p}}_select_reg = {{w}}'d0; {%- endfor %} -{% for p in ports %} +{% for p in range(n) %} assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg; assign output_{{p}}_axis_tkeep = output_{{p}}_axis_tkeep_reg; assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg; @@ -134,42 +141,42 @@ assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg; always @(posedge clk) begin if (rst) begin -{%- for p in ports %} +{%- for p in range(n) %} output_{{p}}_select_reg <= {{w}}'d0; {%- endfor %} -{% for p in ports %} +{% for p in range(m) %} input_{{p}}_axis_tvalid_reg <= 1'b0; {%- endfor %} -{% for p in ports %} +{% for p in range(n) %} output_{{p}}_axis_tvalid_reg <= 1'b0; {%- endfor %} end else begin -{%- for p in ports %} +{%- for p in range(m) %} input_{{p}}_axis_tvalid_reg <= input_{{p}}_axis_tvalid; {%- endfor %} -{% for p in ports %} +{% for p in range(n) %} output_{{p}}_select_reg <= output_{{p}}_select; {%- endfor %} -{%- for p in ports %} +{%- for p in range(n) %} case (output_{{p}}_select_reg) -{%- for q in ports %} +{%- for q in range(m) %} {{w}}'d{{q}}: output_{{p}}_axis_tvalid_reg <= input_{{q}}_axis_tvalid_reg; {%- endfor %} endcase {%- endfor %} end -{%- for p in ports %} +{%- for p in range(m) %} input_{{p}}_axis_tdata_reg <= input_{{p}}_axis_tdata; input_{{p}}_axis_tkeep_reg <= input_{{p}}_axis_tkeep; input_{{p}}_axis_tlast_reg <= input_{{p}}_axis_tlast; input_{{p}}_axis_tuser_reg <= input_{{p}}_axis_tuser; {%- endfor %} -{%- for p in ports %} +{%- for p in range(n) %} case (output_{{p}}_select_reg) -{%- for q in ports %} +{%- for q in range(m) %} {{w}}'d{{q}}: begin output_{{p}}_axis_tdata_reg <= input_{{q}}_axis_tdata_reg; output_{{p}}_axis_tkeep_reg <= input_{{q}}_axis_tkeep_reg; @@ -186,10 +193,10 @@ endmodule """) output_file.write(t.render( - n=ports, + m=m, + n=n, w=select_width, - name=name, - ports=range(ports) + name=name )) print("Done") From 5fe35a79d2917d89eeb2da568a879fc41bd0b7b1 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Mon, 25 Jul 2016 11:28:35 -0700 Subject: [PATCH 5/7] Add tdest support to axis_ep --- tb/axis_ep.py | 57 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/tb/axis_ep.py b/tb/axis_ep.py index 14983f29..9c7a36ea 100644 --- a/tb/axis_ep.py +++ b/tb/axis_ep.py @@ -27,17 +27,21 @@ from myhdl import * skip_asserts = False class AXIStreamFrame(object): - def __init__(self, data=b'', keep=None, user=None): + def __init__(self, data=b'', keep=None, dest=None, user=None): self.B = 0 self.N = 8 self.M = 1 self.WL = 8 self.data = b'' self.keep = None + self.dest = 0 self.user = None if type(data) is bytes or type(data) is bytearray: self.data = bytearray(data) + self.keep = keep + self.dest = dest + self.user = user elif type(data) is AXIStreamFrame: self.N = data.N self.WL = data.WL @@ -47,6 +51,11 @@ class AXIStreamFrame(object): self.data = list(data.data) if data.keep is not None: self.keep = list(data.keep) + if data.dest is not None: + if type(data.dest) is int: + self.dest = data.dest + else: + self.dest = list(data.dest) if data.user is not None: if type(data.user) is int or type(data.user) is bool: self.user = data.user @@ -54,6 +63,9 @@ class AXIStreamFrame(object): self.user = list(data.user) else: self.data = list(data) + self.keep = keep + self.dest = dest + self.user = user def build(self): if self.data is None: @@ -62,9 +74,15 @@ class AXIStreamFrame(object): f = list(self.data) tdata = [] tkeep = [] + tdest = [] tuser = [] i = 0 + dest = 0 + if type(self.dest) is int: + dest = self.dest + self.dest = None + assert_tuser = False if (type(self.user) is int or type(self.user) is bool) and self.user: assert_tuser = True @@ -83,6 +101,10 @@ class AXIStreamFrame(object): tkeep.append(keep) else: tkeep.append(self.keep[i]) + if self.dest is None: + tdest.append(dest) + else: + tdest.append(self.dest[i]) if self.user is None: tuser.append(0) else: @@ -94,6 +116,10 @@ class AXIStreamFrame(object): data = 0 tdata.append(f.pop(0)) tkeep.append(0) + if self.dest is None: + tdest.append(dest) + else: + tdest.append(self.dest[i]) if self.user is None: tuser.append(0) else: @@ -104,16 +130,20 @@ class AXIStreamFrame(object): tuser[-1] = 1 self.user = 1 - return tdata, tkeep, tuser + if self.dest == None: + self.dest = dest - def parse(self, tdata, tkeep, tuser): + return tdata, tkeep, tdest, tuser + + def parse(self, tdata, tkeep, tdest, tuser): if tdata is None or tkeep is None or tuser is None: return - if len(tdata) != len(tkeep) or len(tdata) != len(tuser): + if len(tdata) != len(tkeep) or len(tdata) != len(tdest) or len(tdata) != len(tuser): raise Exception("Invalid data") self.data = [] self.keep = [] + self.dest = [] self.user = [] if self.B == 0: @@ -124,11 +154,13 @@ class AXIStreamFrame(object): if tkeep[i] & (1 << j): self.data.append((tdata[i] >> (j*self.WL)) & mask) self.keep.append(tkeep[i]) + self.dest.append(tdest[i]) self.user.append(tuser[i]) else: for i in range(len(tdata)): self.data.append(tdata[i]) self.keep.append(tkeep[i]) + self.dest.append(tdest[i]) self.user.append(tuser[i]) if self.WL == 8: @@ -139,7 +171,7 @@ class AXIStreamFrame(object): return self.data == other.data def __repr__(self): - return 'AXIStreamFrame(data=%s, keep=%s, user=%s)' % (repr(self.data), repr(self.keep), repr(self.user)) + return 'AXIStreamFrame(data=%s, keep=%s, dest=%s, user=%s)' % (repr(self.data), repr(self.keep), repr(self.dest), repr(self.user)) def __iter__(self): return self.data.__iter__() @@ -150,6 +182,7 @@ def AXIStreamSource(clk, rst, tvalid=Signal(bool(False)), tready=Signal(bool(True)), tlast=Signal(bool(False)), + tdest=Signal(intbv(0)), tuser=Signal(bool(False)), fifo=None, pause=0, @@ -168,6 +201,7 @@ def AXIStreamSource(clk, rst, frame = AXIStreamFrame() data = [] keep = [] + dest = [] user = [] B = 0 N = len(tdata) @@ -191,6 +225,8 @@ def AXIStreamSource(clk, rst, else: tdata.next = 0 tkeep.next = 0 + tdest.next = 0 + tuser.next = False tvalid_int.next = False tlast.next = False else: @@ -203,6 +239,7 @@ def AXIStreamSource(clk, rst, else: tdata.next = data.pop(0) tkeep.next = keep.pop(0) + tdest.next = dest.pop(0) tuser.next = user.pop(0) tvalid_int.next = True tlast.next = len(data) == 0 @@ -217,7 +254,7 @@ def AXIStreamSource(clk, rst, frame.N = N frame.M = M frame.WL = WL - data, keep, user = frame.build() + data, keep, dest, user = frame.build() if name is not None: print("[%s] Sending frame %s" % (name, repr(frame))) if B > 0: @@ -227,6 +264,7 @@ def AXIStreamSource(clk, rst, else: tdata.next = data.pop(0) tkeep.next = keep.pop(0) + tdest.next = dest.pop(0) tuser.next = user.pop(0) tvalid_int.next = True tlast.next = len(data) == 0 @@ -240,6 +278,7 @@ def AXIStreamSink(clk, rst, tvalid=Signal(bool(True)), tready=Signal(bool(True)), tlast=Signal(bool(True)), + tdest=Signal(intbv(0)), tuser=Signal(bool(False)), fifo=None, pause=0, @@ -258,6 +297,7 @@ def AXIStreamSink(clk, rst, frame = AXIStreamFrame() data = [] keep = [] + dest = [] user = [] B = 0 N = len(tdata) @@ -280,6 +320,7 @@ def AXIStreamSink(clk, rst, frame = AXIStreamFrame() data = [] keep = [] + dest = [] user = [] first = True else: @@ -314,6 +355,7 @@ def AXIStreamSink(clk, rst, else: data.append(int(tdata)) keep.append(int(tkeep)) + dest.append(int(tdest)) user.append(int(tuser)) first = False if tlast: @@ -321,7 +363,7 @@ def AXIStreamSink(clk, rst, frame.N = N frame.M = M frame.WL = WL - frame.parse(data, keep, user) + frame.parse(data, keep, dest, user) if fifo is not None: fifo.put(frame) if name is not None: @@ -329,6 +371,7 @@ def AXIStreamSink(clk, rst, frame = AXIStreamFrame() data = [] keep = [] + dest = [] user = [] first = True From 06bfa1944c1f51ef7451284a4a79566fa8675658 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Mon, 25 Jul 2016 13:12:10 -0700 Subject: [PATCH 6/7] Add AXI stream switch module, generator script, and testbench --- rtl/axis_switch.py | 477 ++++++++++++ rtl/axis_switch_4x4.v | 1262 +++++++++++++++++++++++++++++++ rtl/axis_switch_64.py | 492 ++++++++++++ rtl/axis_switch_64_4x4.v | 1331 +++++++++++++++++++++++++++++++++ tb/test_axis_switch_4x4.py | 682 +++++++++++++++++ tb/test_axis_switch_4x4.v | 240 ++++++ tb/test_axis_switch_64_4x4.py | 723 ++++++++++++++++++ tb/test_axis_switch_64_4x4.v | 266 +++++++ 8 files changed, 5473 insertions(+) create mode 100755 rtl/axis_switch.py create mode 100644 rtl/axis_switch_4x4.v create mode 100755 rtl/axis_switch_64.py create mode 100644 rtl/axis_switch_64_4x4.v create mode 100755 tb/test_axis_switch_4x4.py create mode 100644 tb/test_axis_switch_4x4.v create mode 100755 tb/test_axis_switch_64_4x4.py create mode 100644 tb/test_axis_switch_64_4x4.v diff --git a/rtl/axis_switch.py b/rtl/axis_switch.py new file mode 100755 index 00000000..35be6317 --- /dev/null +++ b/rtl/axis_switch.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python +""" +Generates an AXI Stream switch with the specified number of ports +""" + +from __future__ import print_function + +import argparse +import math +from jinja2 import Template + +def main(): + parser = argparse.ArgumentParser(description=__doc__.strip()) + parser.add_argument('-p', '--ports', type=int, default=[4], nargs='+', help="number of ports") + parser.add_argument('-n', '--name', type=str, help="module name") + parser.add_argument('-o', '--output', type=str, help="output file name") + + args = parser.parse_args() + + try: + generate(**args.__dict__) + except IOError as ex: + print(ex) + exit(1) + +def generate(ports=4, name=None, output=None): + if type(ports) is int: + m = n = ports + elif len(ports) == 1: + m = n = ports[0] + else: + m, n = ports + + if name is None: + name = "axis_switch_{0}x{1}".format(m, n) + + if output is None: + output = name + ".v" + + print("Opening file '{0}'...".format(output)) + + output_file = open(output, 'w') + + print("Generating {0}x{1} port AXI Stream switch {2}...".format(m, n, name)) + + cm = int(math.ceil(math.log(m, 2))) + cn = int(math.ceil(math.log(n, 2))) + + t = Template(u"""/* + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4-Stream {{m}}x{{n}} switch + */ +module {{name}} # +( + parameter DATA_WIDTH = 8, + parameter DEST_WIDTH = {{cn}}, +{%- for p in range(n) %} + parameter OUT_{{p}}_BASE = {{p}}, + parameter OUT_{{p}}_TOP = {{p}}, + parameter OUT_{{p}}_CONNECT = {{m}}'b{% for p in range(m) %}1{% endfor %}, +{%- endfor %} + // arbitration type: "PRIORITY" or "ROUND_ROBIN" + parameter ARB_TYPE = "ROUND_ROBIN", + // LSB priority: "LOW", "HIGH" + parameter LSB_PRIORITY = "HIGH" +) +( + input wire clk, + input wire rst, + + /* + * AXI Stream inputs + */ +{%- for p in range(m) %} + input wire [DATA_WIDTH-1:0] input_{{p}}_axis_tdata, + input wire input_{{p}}_axis_tvalid, + output wire input_{{p}}_axis_tready, + input wire input_{{p}}_axis_tlast, + input wire [DEST_WIDTH-1:0] input_{{p}}_axis_tdest, + input wire input_{{p}}_axis_tuser, +{% endfor %} + /* + * AXI Stream outputs + */ +{%- for p in range(n) %} + output wire [DATA_WIDTH-1:0] output_{{p}}_axis_tdata, + output wire output_{{p}}_axis_tvalid, + input wire output_{{p}}_axis_tready, + output wire output_{{p}}_axis_tlast, + output wire [DEST_WIDTH-1:0] output_{{p}}_axis_tdest, + output wire output_{{p}}_axis_tuser{% if not loop.last %},{% endif %} +{% endfor -%} +); + +// check configuration +initial begin + if (2**DEST_WIDTH < {{n}}) begin + $error("Error: DEST_WIDTH too small for port count"); + $finish; + end + + if ({%- for p in range(n) %}(OUT_{{p}}_BASE & 2**DEST_WIDTH-1) != OUT_{{p}}_BASE || (OUT_{{p}}_TOP & 2**DEST_WIDTH-1) != OUT_{{p}}_TOP{% if not loop.last %} || + {% endif %}{% endfor -%}) begin + $error("Error: value out of range"); + $finish; + end + + if ({%- for p in range(n) %}OUT_{{p}}_BASE > OUT_{{p}}_TOP{% if not loop.last %} || + {% endif %}{% endfor -%}) begin + $error("Error: invalid range"); + $finish; + end + + if ({%- for p in range(n-1) %}{% set outer_loop = loop %}{%- for q in range(p+1,n) %}(OUT_{{p}}_BASE <= OUT_{{q}}_TOP && OUT_{{q}}_BASE <= OUT_{{p}}_TOP){% if not (loop.last and outer_loop.last) %} || + {% endif %}{% endfor -%}{% endfor -%}) begin + $error("Error: ranges overlap"); + $finish; + end +end +{%- for p in range(m) %} + +reg [{{n-1}}:0] input_{{p}}_request_reg = {{n}}'d0, input_{{p}}_request_next; +reg input_{{p}}_request_valid_reg = 1'b0, input_{{p}}_request_valid_next; +reg input_{{p}}_request_error_reg = 1'b0, input_{{p}}_request_error_next; +{%- endfor %} +{% for p in range(n) %} +reg [{{cm-1}}:0] select_{{p}}_reg = {{cm}}'d0, select_{{p}}_next; +{%- endfor %} +{% for p in range(n) %} +reg enable_{{p}}_reg = 1'b0, enable_{{p}}_next; +{%- endfor %} +{% for p in range(m) %} +reg input_{{p}}_axis_tready_reg = 1'b0, input_{{p}}_axis_tready_next; +{%- endfor %} + +// internal datapath +{%- for p in range(n) %} +reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_int; +reg output_{{p}}_axis_tvalid_int; +reg output_{{p}}_axis_tready_int_reg = 1'b0; +reg output_{{p}}_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_{{p}}_axis_tdest_int; +reg output_{{p}}_axis_tuser_int; +wire output_{{p}}_axis_tready_int_early; +{% endfor %} +{%- for p in range(m) %} +assign input_{{p}}_axis_tready = input_{{p}}_axis_tready_reg; +{%- endfor %} + +// mux for start of packet detection + +{%- for p in range(n) %} +reg selected_input_{{p}}_axis_tvalid; + +always @* begin + case (grant_encoded_{{p}}) +{%- for q in range(m) %} + {{cm}}'d{{q}}: selected_input_{{p}}_axis_tvalid = input_{{q}}_axis_tvalid; +{%- endfor %} + default: selected_input_{{p}}_axis_tvalid = 1'b0; + endcase +end +{% endfor %} +// mux for incoming packet +{% for p in range(n) %} +reg [DATA_WIDTH-1:0] current_input_{{p}}_axis_tdata; +reg current_input_{{p}}_axis_tvalid; +reg current_input_{{p}}_axis_tready; +reg current_input_{{p}}_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_{{p}}_axis_tdest; +reg current_input_{{p}}_axis_tuser; + +always @* begin + case (select_{{p}}_reg) +{%- for q in range(m) %} + {{cm}}'d{{q}}: begin + current_input_{{p}}_axis_tdata = input_{{q}}_axis_tdata; + current_input_{{p}}_axis_tvalid = input_{{q}}_axis_tvalid; + current_input_{{p}}_axis_tready = input_{{q}}_axis_tready; + current_input_{{p}}_axis_tlast = input_{{q}}_axis_tlast; + current_input_{{p}}_axis_tdest = input_{{q}}_axis_tdest; + current_input_{{p}}_axis_tuser = input_{{q}}_axis_tuser; + end +{%- endfor %} + default: begin + current_input_{{p}}_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_{{p}}_axis_tvalid = 1'b0; + current_input_{{p}}_axis_tready = 1'b0; + current_input_{{p}}_axis_tlast = 1'b0; + current_input_{{p}}_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_{{p}}_axis_tuser = 1'b0; + end + endcase +end +{% endfor %} +// arbiter instances +{% for p in range(n) %} +wire [{{m-1}}:0] request_{{p}}; +wire [{{m-1}}:0] acknowledge_{{p}}; +wire [{{m-1}}:0] grant_{{p}}; +wire grant_valid_{{p}}; +wire [{{cm-1}}:0] grant_encoded_{{p}}; +{% endfor %} + +{%- for p in range(n) %} +arbiter #( + .PORTS({{m}}), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_{{p}}_inst ( + .clk(clk), + .rst(rst), + .request(request_{{p}}), + .acknowledge(acknowledge_{{p}}), + .grant(grant_{{p}}), + .grant_valid(grant_valid_{{p}}), + .grant_encoded(grant_encoded_{{p}}) +); +{% endfor %} +// request generation +{%- for p in range(n) %} +{%- for q in range(m) %} +assign request_{{p}}[{{q}}] = input_{{q}}_request_reg[{{p}}] & ~acknowledge_{{p}}[{{q}}]; +{%- endfor %} +{% endfor %} +// acknowledge generation +{%- for p in range(n) %} +{%- for q in range(m) %} +assign acknowledge_{{p}}[{{q}}] = grant_{{p}}[{{q}}] & input_{{q}}_axis_tvalid & input_{{q}}_axis_tready & input_{{q}}_axis_tlast; +{%- endfor %} +{% endfor %} +always @* begin +{%- for p in range(n) %} + select_{{p}}_next = select_{{p}}_reg; +{%- endfor %} +{% for p in range(n) %} + enable_{{p}}_next = enable_{{p}}_reg; +{%- endfor %} +{% for p in range(m) %} + input_{{p}}_request_next = input_{{p}}_request_reg; + input_{{p}}_request_valid_next = input_{{p}}_request_valid_reg; + input_{{p}}_request_error_next = input_{{p}}_request_error_reg; +{% endfor %} +{%- for p in range(m) %} + input_{{p}}_axis_tready_next = 1'b0; +{%- endfor %} +{% for p in range(n) %} + output_{{p}}_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_{{p}}_axis_tvalid_int = 1'b0; + output_{{p}}_axis_tlast_int = 1'b0; + output_{{p}}_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_{{p}}_axis_tuser_int = 1'b0; +{% endfor %} + // input decoding +{% for p in range(m) %} + if (input_{{p}}_request_valid_reg | input_{{p}}_request_error_reg) begin + if (input_{{p}}_axis_tvalid & input_{{p}}_axis_tready & input_{{p}}_axis_tlast) begin + input_{{p}}_request_next = {DEST_WIDTH{1'b0}}; + input_{{p}}_request_valid_next = 1'b0; + input_{{p}}_request_error_next = 1'b0; + end + end else if (input_{{p}}_axis_tvalid) begin +{%- for q in range(n) %} + input_{{p}}_request_next[{{q}}] = (input_{{p}}_axis_tdest >= OUT_{{q}}_BASE) & (input_{{p}}_axis_tdest <= OUT_{{q}}_TOP) & OUT_{{q}}_CONNECT[{{p}}]; +{%- endfor %} + + if (input_{{p}}_request_next) begin + input_{{p}}_request_valid_next = 1'b1; + end else begin + input_{{p}}_request_error_next = 1'b1; + end + end +{% endfor %} + // output control +{% for p in range(n) %} + if (enable_{{p}}_reg) begin + if (current_input_{{p}}_axis_tvalid & current_input_{{p}}_axis_tready) begin + enable_{{p}}_next = ~current_input_{{p}}_axis_tlast; + end + end else if (grant_valid_{{p}} & selected_input_{{p}}_axis_tvalid) begin + enable_{{p}}_next = 1'b1; + select_{{p}}_next = grant_encoded_{{p}}; + end +{% endfor %} + // generate ready signal on selected port +{% for p in range(n) %} + if (enable_{{p}}_next) begin + case (select_{{p}}_next) +{%- for q in range(m) %} + {{cm}}'d{{q}}: input_{{q}}_axis_tready_next = output_{{p}}_axis_tready_int_early; +{%- endfor %} + endcase + end +{% endfor %} + +{%- for p in range(m) %} + if (input_{{p}}_request_error_next) + input_{{p}}_axis_tready_next = 1'b1; +{%- endfor %} + + // pass through selected packet data +{% for p in range(n) %} + output_{{p}}_axis_tdata_int = current_input_{{p}}_axis_tdata; + output_{{p}}_axis_tvalid_int = current_input_{{p}}_axis_tvalid & current_input_{{p}}_axis_tready & enable_{{p}}_reg; + output_{{p}}_axis_tlast_int = current_input_{{p}}_axis_tlast; + output_{{p}}_axis_tdest_int = current_input_{{p}}_axis_tdest; + output_{{p}}_axis_tuser_int = current_input_{{p}}_axis_tuser; +{% endfor -%} +end + +always @(posedge clk) begin + if (rst) begin +{%- for p in range(m) %} + input_{{p}}_request_reg <= {{n}}'d0; + input_{{p}}_request_valid_reg <= 1'b0; + input_{{p}}_request_error_reg <= 1'b0; +{%- endfor %} +{%- for p in range(n) %} + select_{{p}}_reg <= 2'd0; +{%- endfor %} +{%- for p in range(n) %} + enable_{{p}}_reg <= 1'b0; +{%- endfor %} +{%- for p in range(m) %} + input_{{p}}_axis_tready_reg <= 1'b0; +{%- endfor %} + end else begin +{%- for p in range(m) %} + input_{{p}}_request_reg <= input_{{p}}_request_next; + input_{{p}}_request_valid_reg <= input_{{p}}_request_valid_next; + input_{{p}}_request_error_reg <= input_{{p}}_request_error_next; +{%- endfor %} +{%- for p in range(n) %} + select_{{p}}_reg <= select_{{p}}_next; +{%- endfor %} +{%- for p in range(n) %} + enable_{{p}}_reg <= enable_{{p}}_next; +{%- endfor %} +{%- for p in range(m) %} + input_{{p}}_axis_tready_reg <= input_{{p}}_axis_tready_next; +{%- endfor %} + end +end +{% for p in range(n) %} +// output {{p}} datapath logic +reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg output_{{p}}_axis_tvalid_reg = 1'b0, output_{{p}}_axis_tvalid_next; +reg output_{{p}}_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_{{p}}_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_{{p}}_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg temp_{{p}}_axis_tvalid_reg = 1'b0, temp_{{p}}_axis_tvalid_next; +reg temp_{{p}}_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_{{p}}_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_{{p}}_axis_tuser_reg = 1'b0; + +// datapath control +reg store_{{p}}_axis_int_to_output; +reg store_{{p}}_axis_int_to_temp; +reg store_{{p}}_axis_temp_to_output; + +assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg; +assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg; +assign output_{{p}}_axis_tlast = output_{{p}}_axis_tlast_reg; +assign output_{{p}}_axis_tdest = output_{{p}}_axis_tdest_reg; +assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_{{p}}_axis_tready_int_early = output_{{p}}_axis_tready | (~temp_{{p}}_axis_tvalid_reg & (~output_{{p}}_axis_tvalid_reg | ~output_{{p}}_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_reg; + temp_{{p}}_axis_tvalid_next = temp_{{p}}_axis_tvalid_reg; + + store_{{p}}_axis_int_to_output = 1'b0; + store_{{p}}_axis_int_to_temp = 1'b0; + store_{{p}}_axis_temp_to_output = 1'b0; + + if (output_{{p}}_axis_tready_int_reg) begin + // input is ready + if (output_{{p}}_axis_tready | ~output_{{p}}_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_int; + store_{{p}}_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_int; + store_{{p}}_axis_int_to_temp = 1'b1; + end + end else if (output_{{p}}_axis_tready) begin + // input is not ready, but output is ready + output_{{p}}_axis_tvalid_next = temp_{{p}}_axis_tvalid_reg; + temp_{{p}}_axis_tvalid_next = 1'b0; + store_{{p}}_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_{{p}}_axis_tvalid_reg <= 1'b0; + output_{{p}}_axis_tready_int_reg <= 1'b0; + temp_{{p}}_axis_tvalid_reg <= 1'b0; + end else begin + output_{{p}}_axis_tvalid_reg <= output_{{p}}_axis_tvalid_next; + output_{{p}}_axis_tready_int_reg <= output_{{p}}_axis_tready_int_early; + temp_{{p}}_axis_tvalid_reg <= temp_{{p}}_axis_tvalid_next; + end + + // datapath + if (store_{{p}}_axis_int_to_output) begin + output_{{p}}_axis_tdata_reg <= output_{{p}}_axis_tdata_int; + output_{{p}}_axis_tlast_reg <= output_{{p}}_axis_tlast_int; + output_{{p}}_axis_tdest_reg <= output_{{p}}_axis_tdest_int; + output_{{p}}_axis_tuser_reg <= output_{{p}}_axis_tuser_int; + end else if (store_{{p}}_axis_temp_to_output) begin + output_{{p}}_axis_tdata_reg <= temp_{{p}}_axis_tdata_reg; + output_{{p}}_axis_tlast_reg <= temp_{{p}}_axis_tlast_reg; + output_{{p}}_axis_tdest_reg <= temp_{{p}}_axis_tdest_reg; + output_{{p}}_axis_tuser_reg <= temp_{{p}}_axis_tuser_reg; + end + + if (store_{{p}}_axis_int_to_temp) begin + temp_{{p}}_axis_tdata_reg <= output_{{p}}_axis_tdata_int; + temp_{{p}}_axis_tlast_reg <= output_{{p}}_axis_tlast_int; + temp_{{p}}_axis_tdest_reg <= output_{{p}}_axis_tdest_int; + temp_{{p}}_axis_tuser_reg <= output_{{p}}_axis_tuser_int; + end +end +{% endfor %} +endmodule + +""") + + output_file.write(t.render( + m=m, + n=n, + cm=cm, + cn=cn, + name=name + )) + + print("Done") + +if __name__ == "__main__": + main() + diff --git a/rtl/axis_switch_4x4.v b/rtl/axis_switch_4x4.v new file mode 100644 index 00000000..0aaf3497 --- /dev/null +++ b/rtl/axis_switch_4x4.v @@ -0,0 +1,1262 @@ +/* + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4-Stream 4x4 switch + */ +module axis_switch_4x4 # +( + parameter DATA_WIDTH = 8, + parameter DEST_WIDTH = 2, + parameter OUT_0_BASE = 0, + parameter OUT_0_TOP = 0, + parameter OUT_0_CONNECT = 4'b1111, + parameter OUT_1_BASE = 1, + parameter OUT_1_TOP = 1, + parameter OUT_1_CONNECT = 4'b1111, + parameter OUT_2_BASE = 2, + parameter OUT_2_TOP = 2, + parameter OUT_2_CONNECT = 4'b1111, + parameter OUT_3_BASE = 3, + parameter OUT_3_TOP = 3, + parameter OUT_3_CONNECT = 4'b1111, + // arbitration type: "PRIORITY" or "ROUND_ROBIN" + parameter ARB_TYPE = "ROUND_ROBIN", + // LSB priority: "LOW", "HIGH" + parameter LSB_PRIORITY = "HIGH" +) +( + input wire clk, + input wire rst, + + /* + * AXI Stream inputs + */ + input wire [DATA_WIDTH-1:0] input_0_axis_tdata, + input wire input_0_axis_tvalid, + output wire input_0_axis_tready, + input wire input_0_axis_tlast, + input wire [DEST_WIDTH-1:0] input_0_axis_tdest, + input wire input_0_axis_tuser, + + input wire [DATA_WIDTH-1:0] input_1_axis_tdata, + input wire input_1_axis_tvalid, + output wire input_1_axis_tready, + input wire input_1_axis_tlast, + input wire [DEST_WIDTH-1:0] input_1_axis_tdest, + input wire input_1_axis_tuser, + + input wire [DATA_WIDTH-1:0] input_2_axis_tdata, + input wire input_2_axis_tvalid, + output wire input_2_axis_tready, + input wire input_2_axis_tlast, + input wire [DEST_WIDTH-1:0] input_2_axis_tdest, + input wire input_2_axis_tuser, + + input wire [DATA_WIDTH-1:0] input_3_axis_tdata, + input wire input_3_axis_tvalid, + output wire input_3_axis_tready, + input wire input_3_axis_tlast, + input wire [DEST_WIDTH-1:0] input_3_axis_tdest, + input wire input_3_axis_tuser, + + /* + * AXI Stream outputs + */ + output wire [DATA_WIDTH-1:0] output_0_axis_tdata, + output wire output_0_axis_tvalid, + input wire output_0_axis_tready, + output wire output_0_axis_tlast, + output wire [DEST_WIDTH-1:0] output_0_axis_tdest, + output wire output_0_axis_tuser, + + output wire [DATA_WIDTH-1:0] output_1_axis_tdata, + output wire output_1_axis_tvalid, + input wire output_1_axis_tready, + output wire output_1_axis_tlast, + output wire [DEST_WIDTH-1:0] output_1_axis_tdest, + output wire output_1_axis_tuser, + + output wire [DATA_WIDTH-1:0] output_2_axis_tdata, + output wire output_2_axis_tvalid, + input wire output_2_axis_tready, + output wire output_2_axis_tlast, + output wire [DEST_WIDTH-1:0] output_2_axis_tdest, + output wire output_2_axis_tuser, + + output wire [DATA_WIDTH-1:0] output_3_axis_tdata, + output wire output_3_axis_tvalid, + input wire output_3_axis_tready, + output wire output_3_axis_tlast, + output wire [DEST_WIDTH-1:0] output_3_axis_tdest, + output wire output_3_axis_tuser +); + +// check configuration +initial begin + if (2**DEST_WIDTH < 4) begin + $error("Error: DEST_WIDTH too small for port count"); + $finish; + end + + if ((OUT_0_BASE & 2**DEST_WIDTH-1) != OUT_0_BASE || (OUT_0_TOP & 2**DEST_WIDTH-1) != OUT_0_TOP || + (OUT_1_BASE & 2**DEST_WIDTH-1) != OUT_1_BASE || (OUT_1_TOP & 2**DEST_WIDTH-1) != OUT_1_TOP || + (OUT_2_BASE & 2**DEST_WIDTH-1) != OUT_2_BASE || (OUT_2_TOP & 2**DEST_WIDTH-1) != OUT_2_TOP || + (OUT_3_BASE & 2**DEST_WIDTH-1) != OUT_3_BASE || (OUT_3_TOP & 2**DEST_WIDTH-1) != OUT_3_TOP) begin + $error("Error: value out of range"); + $finish; + end + + if (OUT_0_BASE > OUT_0_TOP || + OUT_1_BASE > OUT_1_TOP || + OUT_2_BASE > OUT_2_TOP || + OUT_3_BASE > OUT_3_TOP) begin + $error("Error: invalid range"); + $finish; + end + + if ((OUT_0_BASE <= OUT_1_TOP && OUT_1_BASE <= OUT_0_TOP) || + (OUT_0_BASE <= OUT_2_TOP && OUT_2_BASE <= OUT_0_TOP) || + (OUT_0_BASE <= OUT_3_TOP && OUT_3_BASE <= OUT_0_TOP) || + (OUT_1_BASE <= OUT_2_TOP && OUT_2_BASE <= OUT_1_TOP) || + (OUT_1_BASE <= OUT_3_TOP && OUT_3_BASE <= OUT_1_TOP) || + (OUT_2_BASE <= OUT_3_TOP && OUT_3_BASE <= OUT_2_TOP)) begin + $error("Error: ranges overlap"); + $finish; + end +end + +reg [3:0] input_0_request_reg = 4'd0, input_0_request_next; +reg input_0_request_valid_reg = 1'b0, input_0_request_valid_next; +reg input_0_request_error_reg = 1'b0, input_0_request_error_next; + +reg [3:0] input_1_request_reg = 4'd0, input_1_request_next; +reg input_1_request_valid_reg = 1'b0, input_1_request_valid_next; +reg input_1_request_error_reg = 1'b0, input_1_request_error_next; + +reg [3:0] input_2_request_reg = 4'd0, input_2_request_next; +reg input_2_request_valid_reg = 1'b0, input_2_request_valid_next; +reg input_2_request_error_reg = 1'b0, input_2_request_error_next; + +reg [3:0] input_3_request_reg = 4'd0, input_3_request_next; +reg input_3_request_valid_reg = 1'b0, input_3_request_valid_next; +reg input_3_request_error_reg = 1'b0, input_3_request_error_next; + +reg [1:0] select_0_reg = 2'd0, select_0_next; +reg [1:0] select_1_reg = 2'd0, select_1_next; +reg [1:0] select_2_reg = 2'd0, select_2_next; +reg [1:0] select_3_reg = 2'd0, select_3_next; + +reg enable_0_reg = 1'b0, enable_0_next; +reg enable_1_reg = 1'b0, enable_1_next; +reg enable_2_reg = 1'b0, enable_2_next; +reg enable_3_reg = 1'b0, enable_3_next; + +reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next; +reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next; +reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next; +reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next; + +// internal datapath +reg [DATA_WIDTH-1:0] output_0_axis_tdata_int; +reg output_0_axis_tvalid_int; +reg output_0_axis_tready_int_reg = 1'b0; +reg output_0_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_0_axis_tdest_int; +reg output_0_axis_tuser_int; +wire output_0_axis_tready_int_early; + +reg [DATA_WIDTH-1:0] output_1_axis_tdata_int; +reg output_1_axis_tvalid_int; +reg output_1_axis_tready_int_reg = 1'b0; +reg output_1_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_1_axis_tdest_int; +reg output_1_axis_tuser_int; +wire output_1_axis_tready_int_early; + +reg [DATA_WIDTH-1:0] output_2_axis_tdata_int; +reg output_2_axis_tvalid_int; +reg output_2_axis_tready_int_reg = 1'b0; +reg output_2_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_2_axis_tdest_int; +reg output_2_axis_tuser_int; +wire output_2_axis_tready_int_early; + +reg [DATA_WIDTH-1:0] output_3_axis_tdata_int; +reg output_3_axis_tvalid_int; +reg output_3_axis_tready_int_reg = 1'b0; +reg output_3_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_3_axis_tdest_int; +reg output_3_axis_tuser_int; +wire output_3_axis_tready_int_early; + +assign input_0_axis_tready = input_0_axis_tready_reg; +assign input_1_axis_tready = input_1_axis_tready_reg; +assign input_2_axis_tready = input_2_axis_tready_reg; +assign input_3_axis_tready = input_3_axis_tready_reg; + +// mux for start of packet detection +reg selected_input_0_axis_tvalid; + +always @* begin + case (grant_encoded_0) + 2'd0: selected_input_0_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_0_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_0_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_0_axis_tvalid = input_3_axis_tvalid; + default: selected_input_0_axis_tvalid = 1'b0; + endcase +end + +reg selected_input_1_axis_tvalid; + +always @* begin + case (grant_encoded_1) + 2'd0: selected_input_1_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_1_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_1_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_1_axis_tvalid = input_3_axis_tvalid; + default: selected_input_1_axis_tvalid = 1'b0; + endcase +end + +reg selected_input_2_axis_tvalid; + +always @* begin + case (grant_encoded_2) + 2'd0: selected_input_2_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_2_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_2_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_2_axis_tvalid = input_3_axis_tvalid; + default: selected_input_2_axis_tvalid = 1'b0; + endcase +end + +reg selected_input_3_axis_tvalid; + +always @* begin + case (grant_encoded_3) + 2'd0: selected_input_3_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_3_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_3_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_3_axis_tvalid = input_3_axis_tvalid; + default: selected_input_3_axis_tvalid = 1'b0; + endcase +end + +// mux for incoming packet + +reg [DATA_WIDTH-1:0] current_input_0_axis_tdata; +reg current_input_0_axis_tvalid; +reg current_input_0_axis_tready; +reg current_input_0_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_0_axis_tdest; +reg current_input_0_axis_tuser; + +always @* begin + case (select_0_reg) + 2'd0: begin + current_input_0_axis_tdata = input_0_axis_tdata; + current_input_0_axis_tvalid = input_0_axis_tvalid; + current_input_0_axis_tready = input_0_axis_tready; + current_input_0_axis_tlast = input_0_axis_tlast; + current_input_0_axis_tdest = input_0_axis_tdest; + current_input_0_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_0_axis_tdata = input_1_axis_tdata; + current_input_0_axis_tvalid = input_1_axis_tvalid; + current_input_0_axis_tready = input_1_axis_tready; + current_input_0_axis_tlast = input_1_axis_tlast; + current_input_0_axis_tdest = input_1_axis_tdest; + current_input_0_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_0_axis_tdata = input_2_axis_tdata; + current_input_0_axis_tvalid = input_2_axis_tvalid; + current_input_0_axis_tready = input_2_axis_tready; + current_input_0_axis_tlast = input_2_axis_tlast; + current_input_0_axis_tdest = input_2_axis_tdest; + current_input_0_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_0_axis_tdata = input_3_axis_tdata; + current_input_0_axis_tvalid = input_3_axis_tvalid; + current_input_0_axis_tready = input_3_axis_tready; + current_input_0_axis_tlast = input_3_axis_tlast; + current_input_0_axis_tdest = input_3_axis_tdest; + current_input_0_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_0_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_0_axis_tvalid = 1'b0; + current_input_0_axis_tready = 1'b0; + current_input_0_axis_tlast = 1'b0; + current_input_0_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_0_axis_tuser = 1'b0; + end + endcase +end + +reg [DATA_WIDTH-1:0] current_input_1_axis_tdata; +reg current_input_1_axis_tvalid; +reg current_input_1_axis_tready; +reg current_input_1_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_1_axis_tdest; +reg current_input_1_axis_tuser; + +always @* begin + case (select_1_reg) + 2'd0: begin + current_input_1_axis_tdata = input_0_axis_tdata; + current_input_1_axis_tvalid = input_0_axis_tvalid; + current_input_1_axis_tready = input_0_axis_tready; + current_input_1_axis_tlast = input_0_axis_tlast; + current_input_1_axis_tdest = input_0_axis_tdest; + current_input_1_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_1_axis_tdata = input_1_axis_tdata; + current_input_1_axis_tvalid = input_1_axis_tvalid; + current_input_1_axis_tready = input_1_axis_tready; + current_input_1_axis_tlast = input_1_axis_tlast; + current_input_1_axis_tdest = input_1_axis_tdest; + current_input_1_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_1_axis_tdata = input_2_axis_tdata; + current_input_1_axis_tvalid = input_2_axis_tvalid; + current_input_1_axis_tready = input_2_axis_tready; + current_input_1_axis_tlast = input_2_axis_tlast; + current_input_1_axis_tdest = input_2_axis_tdest; + current_input_1_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_1_axis_tdata = input_3_axis_tdata; + current_input_1_axis_tvalid = input_3_axis_tvalid; + current_input_1_axis_tready = input_3_axis_tready; + current_input_1_axis_tlast = input_3_axis_tlast; + current_input_1_axis_tdest = input_3_axis_tdest; + current_input_1_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_1_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_1_axis_tvalid = 1'b0; + current_input_1_axis_tready = 1'b0; + current_input_1_axis_tlast = 1'b0; + current_input_1_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_1_axis_tuser = 1'b0; + end + endcase +end + +reg [DATA_WIDTH-1:0] current_input_2_axis_tdata; +reg current_input_2_axis_tvalid; +reg current_input_2_axis_tready; +reg current_input_2_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_2_axis_tdest; +reg current_input_2_axis_tuser; + +always @* begin + case (select_2_reg) + 2'd0: begin + current_input_2_axis_tdata = input_0_axis_tdata; + current_input_2_axis_tvalid = input_0_axis_tvalid; + current_input_2_axis_tready = input_0_axis_tready; + current_input_2_axis_tlast = input_0_axis_tlast; + current_input_2_axis_tdest = input_0_axis_tdest; + current_input_2_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_2_axis_tdata = input_1_axis_tdata; + current_input_2_axis_tvalid = input_1_axis_tvalid; + current_input_2_axis_tready = input_1_axis_tready; + current_input_2_axis_tlast = input_1_axis_tlast; + current_input_2_axis_tdest = input_1_axis_tdest; + current_input_2_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_2_axis_tdata = input_2_axis_tdata; + current_input_2_axis_tvalid = input_2_axis_tvalid; + current_input_2_axis_tready = input_2_axis_tready; + current_input_2_axis_tlast = input_2_axis_tlast; + current_input_2_axis_tdest = input_2_axis_tdest; + current_input_2_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_2_axis_tdata = input_3_axis_tdata; + current_input_2_axis_tvalid = input_3_axis_tvalid; + current_input_2_axis_tready = input_3_axis_tready; + current_input_2_axis_tlast = input_3_axis_tlast; + current_input_2_axis_tdest = input_3_axis_tdest; + current_input_2_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_2_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_2_axis_tvalid = 1'b0; + current_input_2_axis_tready = 1'b0; + current_input_2_axis_tlast = 1'b0; + current_input_2_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_2_axis_tuser = 1'b0; + end + endcase +end + +reg [DATA_WIDTH-1:0] current_input_3_axis_tdata; +reg current_input_3_axis_tvalid; +reg current_input_3_axis_tready; +reg current_input_3_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_3_axis_tdest; +reg current_input_3_axis_tuser; + +always @* begin + case (select_3_reg) + 2'd0: begin + current_input_3_axis_tdata = input_0_axis_tdata; + current_input_3_axis_tvalid = input_0_axis_tvalid; + current_input_3_axis_tready = input_0_axis_tready; + current_input_3_axis_tlast = input_0_axis_tlast; + current_input_3_axis_tdest = input_0_axis_tdest; + current_input_3_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_3_axis_tdata = input_1_axis_tdata; + current_input_3_axis_tvalid = input_1_axis_tvalid; + current_input_3_axis_tready = input_1_axis_tready; + current_input_3_axis_tlast = input_1_axis_tlast; + current_input_3_axis_tdest = input_1_axis_tdest; + current_input_3_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_3_axis_tdata = input_2_axis_tdata; + current_input_3_axis_tvalid = input_2_axis_tvalid; + current_input_3_axis_tready = input_2_axis_tready; + current_input_3_axis_tlast = input_2_axis_tlast; + current_input_3_axis_tdest = input_2_axis_tdest; + current_input_3_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_3_axis_tdata = input_3_axis_tdata; + current_input_3_axis_tvalid = input_3_axis_tvalid; + current_input_3_axis_tready = input_3_axis_tready; + current_input_3_axis_tlast = input_3_axis_tlast; + current_input_3_axis_tdest = input_3_axis_tdest; + current_input_3_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_3_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_3_axis_tvalid = 1'b0; + current_input_3_axis_tready = 1'b0; + current_input_3_axis_tlast = 1'b0; + current_input_3_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_3_axis_tuser = 1'b0; + end + endcase +end + +// arbiter instances + +wire [3:0] request_0; +wire [3:0] acknowledge_0; +wire [3:0] grant_0; +wire grant_valid_0; +wire [1:0] grant_encoded_0; + +wire [3:0] request_1; +wire [3:0] acknowledge_1; +wire [3:0] grant_1; +wire grant_valid_1; +wire [1:0] grant_encoded_1; + +wire [3:0] request_2; +wire [3:0] acknowledge_2; +wire [3:0] grant_2; +wire grant_valid_2; +wire [1:0] grant_encoded_2; + +wire [3:0] request_3; +wire [3:0] acknowledge_3; +wire [3:0] grant_3; +wire grant_valid_3; +wire [1:0] grant_encoded_3; + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_0_inst ( + .clk(clk), + .rst(rst), + .request(request_0), + .acknowledge(acknowledge_0), + .grant(grant_0), + .grant_valid(grant_valid_0), + .grant_encoded(grant_encoded_0) +); + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_1_inst ( + .clk(clk), + .rst(rst), + .request(request_1), + .acknowledge(acknowledge_1), + .grant(grant_1), + .grant_valid(grant_valid_1), + .grant_encoded(grant_encoded_1) +); + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_2_inst ( + .clk(clk), + .rst(rst), + .request(request_2), + .acknowledge(acknowledge_2), + .grant(grant_2), + .grant_valid(grant_valid_2), + .grant_encoded(grant_encoded_2) +); + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_3_inst ( + .clk(clk), + .rst(rst), + .request(request_3), + .acknowledge(acknowledge_3), + .grant(grant_3), + .grant_valid(grant_valid_3), + .grant_encoded(grant_encoded_3) +); + +// request generation +assign request_0[0] = input_0_request_reg[0] & ~acknowledge_0[0]; +assign request_0[1] = input_1_request_reg[0] & ~acknowledge_0[1]; +assign request_0[2] = input_2_request_reg[0] & ~acknowledge_0[2]; +assign request_0[3] = input_3_request_reg[0] & ~acknowledge_0[3]; + +assign request_1[0] = input_0_request_reg[1] & ~acknowledge_1[0]; +assign request_1[1] = input_1_request_reg[1] & ~acknowledge_1[1]; +assign request_1[2] = input_2_request_reg[1] & ~acknowledge_1[2]; +assign request_1[3] = input_3_request_reg[1] & ~acknowledge_1[3]; + +assign request_2[0] = input_0_request_reg[2] & ~acknowledge_2[0]; +assign request_2[1] = input_1_request_reg[2] & ~acknowledge_2[1]; +assign request_2[2] = input_2_request_reg[2] & ~acknowledge_2[2]; +assign request_2[3] = input_3_request_reg[2] & ~acknowledge_2[3]; + +assign request_3[0] = input_0_request_reg[3] & ~acknowledge_3[0]; +assign request_3[1] = input_1_request_reg[3] & ~acknowledge_3[1]; +assign request_3[2] = input_2_request_reg[3] & ~acknowledge_3[2]; +assign request_3[3] = input_3_request_reg[3] & ~acknowledge_3[3]; + +// acknowledge generation +assign acknowledge_0[0] = grant_0[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_0[1] = grant_0[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_0[2] = grant_0[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_0[3] = grant_0[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +assign acknowledge_1[0] = grant_1[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_1[1] = grant_1[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_1[2] = grant_1[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_1[3] = grant_1[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +assign acknowledge_2[0] = grant_2[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_2[1] = grant_2[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_2[2] = grant_2[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_2[3] = grant_2[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +assign acknowledge_3[0] = grant_3[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_3[1] = grant_3[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_3[2] = grant_3[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_3[3] = grant_3[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +always @* begin + select_0_next = select_0_reg; + select_1_next = select_1_reg; + select_2_next = select_2_reg; + select_3_next = select_3_reg; + + enable_0_next = enable_0_reg; + enable_1_next = enable_1_reg; + enable_2_next = enable_2_reg; + enable_3_next = enable_3_reg; + + input_0_request_next = input_0_request_reg; + input_0_request_valid_next = input_0_request_valid_reg; + input_0_request_error_next = input_0_request_error_reg; + + input_1_request_next = input_1_request_reg; + input_1_request_valid_next = input_1_request_valid_reg; + input_1_request_error_next = input_1_request_error_reg; + + input_2_request_next = input_2_request_reg; + input_2_request_valid_next = input_2_request_valid_reg; + input_2_request_error_next = input_2_request_error_reg; + + input_3_request_next = input_3_request_reg; + input_3_request_valid_next = input_3_request_valid_reg; + input_3_request_error_next = input_3_request_error_reg; + + input_0_axis_tready_next = 1'b0; + input_1_axis_tready_next = 1'b0; + input_2_axis_tready_next = 1'b0; + input_3_axis_tready_next = 1'b0; + + output_0_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_0_axis_tvalid_int = 1'b0; + output_0_axis_tlast_int = 1'b0; + output_0_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_0_axis_tuser_int = 1'b0; + + output_1_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_1_axis_tvalid_int = 1'b0; + output_1_axis_tlast_int = 1'b0; + output_1_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_1_axis_tuser_int = 1'b0; + + output_2_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_2_axis_tvalid_int = 1'b0; + output_2_axis_tlast_int = 1'b0; + output_2_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_2_axis_tuser_int = 1'b0; + + output_3_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_3_axis_tvalid_int = 1'b0; + output_3_axis_tlast_int = 1'b0; + output_3_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_3_axis_tuser_int = 1'b0; + + // input decoding + + if (input_0_request_valid_reg | input_0_request_error_reg) begin + if (input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast) begin + input_0_request_next = {DEST_WIDTH{1'b0}}; + input_0_request_valid_next = 1'b0; + input_0_request_error_next = 1'b0; + end + end else if (input_0_axis_tvalid) begin + input_0_request_next[0] = (input_0_axis_tdest >= OUT_0_BASE) & (input_0_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[0]; + input_0_request_next[1] = (input_0_axis_tdest >= OUT_1_BASE) & (input_0_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[0]; + input_0_request_next[2] = (input_0_axis_tdest >= OUT_2_BASE) & (input_0_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[0]; + input_0_request_next[3] = (input_0_axis_tdest >= OUT_3_BASE) & (input_0_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[0]; + + if (input_0_request_next) begin + input_0_request_valid_next = 1'b1; + end else begin + input_0_request_error_next = 1'b1; + end + end + + if (input_1_request_valid_reg | input_1_request_error_reg) begin + if (input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast) begin + input_1_request_next = {DEST_WIDTH{1'b0}}; + input_1_request_valid_next = 1'b0; + input_1_request_error_next = 1'b0; + end + end else if (input_1_axis_tvalid) begin + input_1_request_next[0] = (input_1_axis_tdest >= OUT_0_BASE) & (input_1_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[1]; + input_1_request_next[1] = (input_1_axis_tdest >= OUT_1_BASE) & (input_1_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[1]; + input_1_request_next[2] = (input_1_axis_tdest >= OUT_2_BASE) & (input_1_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[1]; + input_1_request_next[3] = (input_1_axis_tdest >= OUT_3_BASE) & (input_1_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[1]; + + if (input_1_request_next) begin + input_1_request_valid_next = 1'b1; + end else begin + input_1_request_error_next = 1'b1; + end + end + + if (input_2_request_valid_reg | input_2_request_error_reg) begin + if (input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast) begin + input_2_request_next = {DEST_WIDTH{1'b0}}; + input_2_request_valid_next = 1'b0; + input_2_request_error_next = 1'b0; + end + end else if (input_2_axis_tvalid) begin + input_2_request_next[0] = (input_2_axis_tdest >= OUT_0_BASE) & (input_2_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[2]; + input_2_request_next[1] = (input_2_axis_tdest >= OUT_1_BASE) & (input_2_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[2]; + input_2_request_next[2] = (input_2_axis_tdest >= OUT_2_BASE) & (input_2_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[2]; + input_2_request_next[3] = (input_2_axis_tdest >= OUT_3_BASE) & (input_2_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[2]; + + if (input_2_request_next) begin + input_2_request_valid_next = 1'b1; + end else begin + input_2_request_error_next = 1'b1; + end + end + + if (input_3_request_valid_reg | input_3_request_error_reg) begin + if (input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast) begin + input_3_request_next = {DEST_WIDTH{1'b0}}; + input_3_request_valid_next = 1'b0; + input_3_request_error_next = 1'b0; + end + end else if (input_3_axis_tvalid) begin + input_3_request_next[0] = (input_3_axis_tdest >= OUT_0_BASE) & (input_3_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[3]; + input_3_request_next[1] = (input_3_axis_tdest >= OUT_1_BASE) & (input_3_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[3]; + input_3_request_next[2] = (input_3_axis_tdest >= OUT_2_BASE) & (input_3_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[3]; + input_3_request_next[3] = (input_3_axis_tdest >= OUT_3_BASE) & (input_3_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[3]; + + if (input_3_request_next) begin + input_3_request_valid_next = 1'b1; + end else begin + input_3_request_error_next = 1'b1; + end + end + + // output control + + if (enable_0_reg) begin + if (current_input_0_axis_tvalid & current_input_0_axis_tready) begin + enable_0_next = ~current_input_0_axis_tlast; + end + end else if (grant_valid_0 & selected_input_0_axis_tvalid) begin + enable_0_next = 1'b1; + select_0_next = grant_encoded_0; + end + + if (enable_1_reg) begin + if (current_input_1_axis_tvalid & current_input_1_axis_tready) begin + enable_1_next = ~current_input_1_axis_tlast; + end + end else if (grant_valid_1 & selected_input_1_axis_tvalid) begin + enable_1_next = 1'b1; + select_1_next = grant_encoded_1; + end + + if (enable_2_reg) begin + if (current_input_2_axis_tvalid & current_input_2_axis_tready) begin + enable_2_next = ~current_input_2_axis_tlast; + end + end else if (grant_valid_2 & selected_input_2_axis_tvalid) begin + enable_2_next = 1'b1; + select_2_next = grant_encoded_2; + end + + if (enable_3_reg) begin + if (current_input_3_axis_tvalid & current_input_3_axis_tready) begin + enable_3_next = ~current_input_3_axis_tlast; + end + end else if (grant_valid_3 & selected_input_3_axis_tvalid) begin + enable_3_next = 1'b1; + select_3_next = grant_encoded_3; + end + + // generate ready signal on selected port + + if (enable_0_next) begin + case (select_0_next) + 2'd0: input_0_axis_tready_next = output_0_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_0_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_0_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_0_axis_tready_int_early; + endcase + end + + if (enable_1_next) begin + case (select_1_next) + 2'd0: input_0_axis_tready_next = output_1_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_1_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_1_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_1_axis_tready_int_early; + endcase + end + + if (enable_2_next) begin + case (select_2_next) + 2'd0: input_0_axis_tready_next = output_2_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_2_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_2_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_2_axis_tready_int_early; + endcase + end + + if (enable_3_next) begin + case (select_3_next) + 2'd0: input_0_axis_tready_next = output_3_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_3_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_3_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_3_axis_tready_int_early; + endcase + end + + if (input_0_request_error_next) + input_0_axis_tready_next = 1'b1; + if (input_1_request_error_next) + input_1_axis_tready_next = 1'b1; + if (input_2_request_error_next) + input_2_axis_tready_next = 1'b1; + if (input_3_request_error_next) + input_3_axis_tready_next = 1'b1; + + // pass through selected packet data + + output_0_axis_tdata_int = current_input_0_axis_tdata; + output_0_axis_tvalid_int = current_input_0_axis_tvalid & current_input_0_axis_tready & enable_0_reg; + output_0_axis_tlast_int = current_input_0_axis_tlast; + output_0_axis_tdest_int = current_input_0_axis_tdest; + output_0_axis_tuser_int = current_input_0_axis_tuser; + + output_1_axis_tdata_int = current_input_1_axis_tdata; + output_1_axis_tvalid_int = current_input_1_axis_tvalid & current_input_1_axis_tready & enable_1_reg; + output_1_axis_tlast_int = current_input_1_axis_tlast; + output_1_axis_tdest_int = current_input_1_axis_tdest; + output_1_axis_tuser_int = current_input_1_axis_tuser; + + output_2_axis_tdata_int = current_input_2_axis_tdata; + output_2_axis_tvalid_int = current_input_2_axis_tvalid & current_input_2_axis_tready & enable_2_reg; + output_2_axis_tlast_int = current_input_2_axis_tlast; + output_2_axis_tdest_int = current_input_2_axis_tdest; + output_2_axis_tuser_int = current_input_2_axis_tuser; + + output_3_axis_tdata_int = current_input_3_axis_tdata; + output_3_axis_tvalid_int = current_input_3_axis_tvalid & current_input_3_axis_tready & enable_3_reg; + output_3_axis_tlast_int = current_input_3_axis_tlast; + output_3_axis_tdest_int = current_input_3_axis_tdest; + output_3_axis_tuser_int = current_input_3_axis_tuser; +end + +always @(posedge clk) begin + if (rst) begin + input_0_request_reg <= 4'd0; + input_0_request_valid_reg <= 1'b0; + input_0_request_error_reg <= 1'b0; + input_1_request_reg <= 4'd0; + input_1_request_valid_reg <= 1'b0; + input_1_request_error_reg <= 1'b0; + input_2_request_reg <= 4'd0; + input_2_request_valid_reg <= 1'b0; + input_2_request_error_reg <= 1'b0; + input_3_request_reg <= 4'd0; + input_3_request_valid_reg <= 1'b0; + input_3_request_error_reg <= 1'b0; + select_0_reg <= 2'd0; + select_1_reg <= 2'd0; + select_2_reg <= 2'd0; + select_3_reg <= 2'd0; + enable_0_reg <= 1'b0; + enable_1_reg <= 1'b0; + enable_2_reg <= 1'b0; + enable_3_reg <= 1'b0; + input_0_axis_tready_reg <= 1'b0; + input_1_axis_tready_reg <= 1'b0; + input_2_axis_tready_reg <= 1'b0; + input_3_axis_tready_reg <= 1'b0; + end else begin + input_0_request_reg <= input_0_request_next; + input_0_request_valid_reg <= input_0_request_valid_next; + input_0_request_error_reg <= input_0_request_error_next; + input_1_request_reg <= input_1_request_next; + input_1_request_valid_reg <= input_1_request_valid_next; + input_1_request_error_reg <= input_1_request_error_next; + input_2_request_reg <= input_2_request_next; + input_2_request_valid_reg <= input_2_request_valid_next; + input_2_request_error_reg <= input_2_request_error_next; + input_3_request_reg <= input_3_request_next; + input_3_request_valid_reg <= input_3_request_valid_next; + input_3_request_error_reg <= input_3_request_error_next; + select_0_reg <= select_0_next; + select_1_reg <= select_1_next; + select_2_reg <= select_2_next; + select_3_reg <= select_3_next; + enable_0_reg <= enable_0_next; + enable_1_reg <= enable_1_next; + enable_2_reg <= enable_2_next; + enable_3_reg <= enable_3_next; + input_0_axis_tready_reg <= input_0_axis_tready_next; + input_1_axis_tready_reg <= input_1_axis_tready_next; + input_2_axis_tready_reg <= input_2_axis_tready_next; + input_3_axis_tready_reg <= input_3_axis_tready_next; + end +end + +// output 0 datapath logic +reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg output_0_axis_tvalid_reg = 1'b0, output_0_axis_tvalid_next; +reg output_0_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_0_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_0_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_0_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg temp_0_axis_tvalid_reg = 1'b0, temp_0_axis_tvalid_next; +reg temp_0_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_0_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_0_axis_tuser_reg = 1'b0; + +// datapath control +reg store_0_axis_int_to_output; +reg store_0_axis_int_to_temp; +reg store_0_axis_temp_to_output; + +assign output_0_axis_tdata = output_0_axis_tdata_reg; +assign output_0_axis_tvalid = output_0_axis_tvalid_reg; +assign output_0_axis_tlast = output_0_axis_tlast_reg; +assign output_0_axis_tdest = output_0_axis_tdest_reg; +assign output_0_axis_tuser = output_0_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_0_axis_tready_int_early = output_0_axis_tready | (~temp_0_axis_tvalid_reg & (~output_0_axis_tvalid_reg | ~output_0_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_0_axis_tvalid_next = output_0_axis_tvalid_reg; + temp_0_axis_tvalid_next = temp_0_axis_tvalid_reg; + + store_0_axis_int_to_output = 1'b0; + store_0_axis_int_to_temp = 1'b0; + store_0_axis_temp_to_output = 1'b0; + + if (output_0_axis_tready_int_reg) begin + // input is ready + if (output_0_axis_tready | ~output_0_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_0_axis_tvalid_next = output_0_axis_tvalid_int; + store_0_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_0_axis_tvalid_next = output_0_axis_tvalid_int; + store_0_axis_int_to_temp = 1'b1; + end + end else if (output_0_axis_tready) begin + // input is not ready, but output is ready + output_0_axis_tvalid_next = temp_0_axis_tvalid_reg; + temp_0_axis_tvalid_next = 1'b0; + store_0_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_0_axis_tvalid_reg <= 1'b0; + output_0_axis_tready_int_reg <= 1'b0; + temp_0_axis_tvalid_reg <= 1'b0; + end else begin + output_0_axis_tvalid_reg <= output_0_axis_tvalid_next; + output_0_axis_tready_int_reg <= output_0_axis_tready_int_early; + temp_0_axis_tvalid_reg <= temp_0_axis_tvalid_next; + end + + // datapath + if (store_0_axis_int_to_output) begin + output_0_axis_tdata_reg <= output_0_axis_tdata_int; + output_0_axis_tlast_reg <= output_0_axis_tlast_int; + output_0_axis_tdest_reg <= output_0_axis_tdest_int; + output_0_axis_tuser_reg <= output_0_axis_tuser_int; + end else if (store_0_axis_temp_to_output) begin + output_0_axis_tdata_reg <= temp_0_axis_tdata_reg; + output_0_axis_tlast_reg <= temp_0_axis_tlast_reg; + output_0_axis_tdest_reg <= temp_0_axis_tdest_reg; + output_0_axis_tuser_reg <= temp_0_axis_tuser_reg; + end + + if (store_0_axis_int_to_temp) begin + temp_0_axis_tdata_reg <= output_0_axis_tdata_int; + temp_0_axis_tlast_reg <= output_0_axis_tlast_int; + temp_0_axis_tdest_reg <= output_0_axis_tdest_int; + temp_0_axis_tuser_reg <= output_0_axis_tuser_int; + end +end + +// output 1 datapath logic +reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg output_1_axis_tvalid_reg = 1'b0, output_1_axis_tvalid_next; +reg output_1_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_1_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_1_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_1_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg temp_1_axis_tvalid_reg = 1'b0, temp_1_axis_tvalid_next; +reg temp_1_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_1_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_1_axis_tuser_reg = 1'b0; + +// datapath control +reg store_1_axis_int_to_output; +reg store_1_axis_int_to_temp; +reg store_1_axis_temp_to_output; + +assign output_1_axis_tdata = output_1_axis_tdata_reg; +assign output_1_axis_tvalid = output_1_axis_tvalid_reg; +assign output_1_axis_tlast = output_1_axis_tlast_reg; +assign output_1_axis_tdest = output_1_axis_tdest_reg; +assign output_1_axis_tuser = output_1_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_1_axis_tready_int_early = output_1_axis_tready | (~temp_1_axis_tvalid_reg & (~output_1_axis_tvalid_reg | ~output_1_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_1_axis_tvalid_next = output_1_axis_tvalid_reg; + temp_1_axis_tvalid_next = temp_1_axis_tvalid_reg; + + store_1_axis_int_to_output = 1'b0; + store_1_axis_int_to_temp = 1'b0; + store_1_axis_temp_to_output = 1'b0; + + if (output_1_axis_tready_int_reg) begin + // input is ready + if (output_1_axis_tready | ~output_1_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_1_axis_tvalid_next = output_1_axis_tvalid_int; + store_1_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_1_axis_tvalid_next = output_1_axis_tvalid_int; + store_1_axis_int_to_temp = 1'b1; + end + end else if (output_1_axis_tready) begin + // input is not ready, but output is ready + output_1_axis_tvalid_next = temp_1_axis_tvalid_reg; + temp_1_axis_tvalid_next = 1'b0; + store_1_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_1_axis_tvalid_reg <= 1'b0; + output_1_axis_tready_int_reg <= 1'b0; + temp_1_axis_tvalid_reg <= 1'b0; + end else begin + output_1_axis_tvalid_reg <= output_1_axis_tvalid_next; + output_1_axis_tready_int_reg <= output_1_axis_tready_int_early; + temp_1_axis_tvalid_reg <= temp_1_axis_tvalid_next; + end + + // datapath + if (store_1_axis_int_to_output) begin + output_1_axis_tdata_reg <= output_1_axis_tdata_int; + output_1_axis_tlast_reg <= output_1_axis_tlast_int; + output_1_axis_tdest_reg <= output_1_axis_tdest_int; + output_1_axis_tuser_reg <= output_1_axis_tuser_int; + end else if (store_1_axis_temp_to_output) begin + output_1_axis_tdata_reg <= temp_1_axis_tdata_reg; + output_1_axis_tlast_reg <= temp_1_axis_tlast_reg; + output_1_axis_tdest_reg <= temp_1_axis_tdest_reg; + output_1_axis_tuser_reg <= temp_1_axis_tuser_reg; + end + + if (store_1_axis_int_to_temp) begin + temp_1_axis_tdata_reg <= output_1_axis_tdata_int; + temp_1_axis_tlast_reg <= output_1_axis_tlast_int; + temp_1_axis_tdest_reg <= output_1_axis_tdest_int; + temp_1_axis_tuser_reg <= output_1_axis_tuser_int; + end +end + +// output 2 datapath logic +reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg output_2_axis_tvalid_reg = 1'b0, output_2_axis_tvalid_next; +reg output_2_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_2_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_2_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_2_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg temp_2_axis_tvalid_reg = 1'b0, temp_2_axis_tvalid_next; +reg temp_2_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_2_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_2_axis_tuser_reg = 1'b0; + +// datapath control +reg store_2_axis_int_to_output; +reg store_2_axis_int_to_temp; +reg store_2_axis_temp_to_output; + +assign output_2_axis_tdata = output_2_axis_tdata_reg; +assign output_2_axis_tvalid = output_2_axis_tvalid_reg; +assign output_2_axis_tlast = output_2_axis_tlast_reg; +assign output_2_axis_tdest = output_2_axis_tdest_reg; +assign output_2_axis_tuser = output_2_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_2_axis_tready_int_early = output_2_axis_tready | (~temp_2_axis_tvalid_reg & (~output_2_axis_tvalid_reg | ~output_2_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_2_axis_tvalid_next = output_2_axis_tvalid_reg; + temp_2_axis_tvalid_next = temp_2_axis_tvalid_reg; + + store_2_axis_int_to_output = 1'b0; + store_2_axis_int_to_temp = 1'b0; + store_2_axis_temp_to_output = 1'b0; + + if (output_2_axis_tready_int_reg) begin + // input is ready + if (output_2_axis_tready | ~output_2_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_2_axis_tvalid_next = output_2_axis_tvalid_int; + store_2_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_2_axis_tvalid_next = output_2_axis_tvalid_int; + store_2_axis_int_to_temp = 1'b1; + end + end else if (output_2_axis_tready) begin + // input is not ready, but output is ready + output_2_axis_tvalid_next = temp_2_axis_tvalid_reg; + temp_2_axis_tvalid_next = 1'b0; + store_2_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_2_axis_tvalid_reg <= 1'b0; + output_2_axis_tready_int_reg <= 1'b0; + temp_2_axis_tvalid_reg <= 1'b0; + end else begin + output_2_axis_tvalid_reg <= output_2_axis_tvalid_next; + output_2_axis_tready_int_reg <= output_2_axis_tready_int_early; + temp_2_axis_tvalid_reg <= temp_2_axis_tvalid_next; + end + + // datapath + if (store_2_axis_int_to_output) begin + output_2_axis_tdata_reg <= output_2_axis_tdata_int; + output_2_axis_tlast_reg <= output_2_axis_tlast_int; + output_2_axis_tdest_reg <= output_2_axis_tdest_int; + output_2_axis_tuser_reg <= output_2_axis_tuser_int; + end else if (store_2_axis_temp_to_output) begin + output_2_axis_tdata_reg <= temp_2_axis_tdata_reg; + output_2_axis_tlast_reg <= temp_2_axis_tlast_reg; + output_2_axis_tdest_reg <= temp_2_axis_tdest_reg; + output_2_axis_tuser_reg <= temp_2_axis_tuser_reg; + end + + if (store_2_axis_int_to_temp) begin + temp_2_axis_tdata_reg <= output_2_axis_tdata_int; + temp_2_axis_tlast_reg <= output_2_axis_tlast_int; + temp_2_axis_tdest_reg <= output_2_axis_tdest_int; + temp_2_axis_tuser_reg <= output_2_axis_tuser_int; + end +end + +// output 3 datapath logic +reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg output_3_axis_tvalid_reg = 1'b0, output_3_axis_tvalid_next; +reg output_3_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_3_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_3_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_3_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg temp_3_axis_tvalid_reg = 1'b0, temp_3_axis_tvalid_next; +reg temp_3_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_3_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_3_axis_tuser_reg = 1'b0; + +// datapath control +reg store_3_axis_int_to_output; +reg store_3_axis_int_to_temp; +reg store_3_axis_temp_to_output; + +assign output_3_axis_tdata = output_3_axis_tdata_reg; +assign output_3_axis_tvalid = output_3_axis_tvalid_reg; +assign output_3_axis_tlast = output_3_axis_tlast_reg; +assign output_3_axis_tdest = output_3_axis_tdest_reg; +assign output_3_axis_tuser = output_3_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_3_axis_tready_int_early = output_3_axis_tready | (~temp_3_axis_tvalid_reg & (~output_3_axis_tvalid_reg | ~output_3_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_3_axis_tvalid_next = output_3_axis_tvalid_reg; + temp_3_axis_tvalid_next = temp_3_axis_tvalid_reg; + + store_3_axis_int_to_output = 1'b0; + store_3_axis_int_to_temp = 1'b0; + store_3_axis_temp_to_output = 1'b0; + + if (output_3_axis_tready_int_reg) begin + // input is ready + if (output_3_axis_tready | ~output_3_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_3_axis_tvalid_next = output_3_axis_tvalid_int; + store_3_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_3_axis_tvalid_next = output_3_axis_tvalid_int; + store_3_axis_int_to_temp = 1'b1; + end + end else if (output_3_axis_tready) begin + // input is not ready, but output is ready + output_3_axis_tvalid_next = temp_3_axis_tvalid_reg; + temp_3_axis_tvalid_next = 1'b0; + store_3_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_3_axis_tvalid_reg <= 1'b0; + output_3_axis_tready_int_reg <= 1'b0; + temp_3_axis_tvalid_reg <= 1'b0; + end else begin + output_3_axis_tvalid_reg <= output_3_axis_tvalid_next; + output_3_axis_tready_int_reg <= output_3_axis_tready_int_early; + temp_3_axis_tvalid_reg <= temp_3_axis_tvalid_next; + end + + // datapath + if (store_3_axis_int_to_output) begin + output_3_axis_tdata_reg <= output_3_axis_tdata_int; + output_3_axis_tlast_reg <= output_3_axis_tlast_int; + output_3_axis_tdest_reg <= output_3_axis_tdest_int; + output_3_axis_tuser_reg <= output_3_axis_tuser_int; + end else if (store_3_axis_temp_to_output) begin + output_3_axis_tdata_reg <= temp_3_axis_tdata_reg; + output_3_axis_tlast_reg <= temp_3_axis_tlast_reg; + output_3_axis_tdest_reg <= temp_3_axis_tdest_reg; + output_3_axis_tuser_reg <= temp_3_axis_tuser_reg; + end + + if (store_3_axis_int_to_temp) begin + temp_3_axis_tdata_reg <= output_3_axis_tdata_int; + temp_3_axis_tlast_reg <= output_3_axis_tlast_int; + temp_3_axis_tdest_reg <= output_3_axis_tdest_int; + temp_3_axis_tuser_reg <= output_3_axis_tuser_int; + end +end + +endmodule diff --git a/rtl/axis_switch_64.py b/rtl/axis_switch_64.py new file mode 100755 index 00000000..3eebdbdf --- /dev/null +++ b/rtl/axis_switch_64.py @@ -0,0 +1,492 @@ +#!/usr/bin/env python +""" +Generates an AXI Stream switch with the specified number of ports +""" + +from __future__ import print_function + +import argparse +import math +from jinja2 import Template + +def main(): + parser = argparse.ArgumentParser(description=__doc__.strip()) + parser.add_argument('-p', '--ports', type=int, default=[4], nargs='+', help="number of ports") + parser.add_argument('-n', '--name', type=str, help="module name") + parser.add_argument('-o', '--output', type=str, help="output file name") + + args = parser.parse_args() + + try: + generate(**args.__dict__) + except IOError as ex: + print(ex) + exit(1) + +def generate(ports=4, name=None, output=None): + if type(ports) is int: + m = n = ports + elif len(ports) == 1: + m = n = ports[0] + else: + m, n = ports + + if name is None: + name = "axis_switch_64_{0}x{1}".format(m, n) + + if output is None: + output = name + ".v" + + print("Opening file '{0}'...".format(output)) + + output_file = open(output, 'w') + + print("Generating {0}x{1} port AXI Stream switch {2}...".format(m, n, name)) + + cm = int(math.ceil(math.log(m, 2))) + cn = int(math.ceil(math.log(n, 2))) + + t = Template(u"""/* + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4-Stream {{m}}x{{n}} switch (64 bit datapath) + */ +module {{name}} # +( + parameter DATA_WIDTH = 64, + parameter KEEP_WIDTH = (DATA_WIDTH/8), + parameter DEST_WIDTH = {{cn}}, +{%- for p in range(n) %} + parameter OUT_{{p}}_BASE = {{p}}, + parameter OUT_{{p}}_TOP = {{p}}, + parameter OUT_{{p}}_CONNECT = {{m}}'b{% for p in range(m) %}1{% endfor %}, +{%- endfor %} + // arbitration type: "PRIORITY" or "ROUND_ROBIN" + parameter ARB_TYPE = "ROUND_ROBIN", + // LSB priority: "LOW", "HIGH" + parameter LSB_PRIORITY = "HIGH" +) +( + input wire clk, + input wire rst, + + /* + * AXI Stream inputs + */ +{%- for p in range(m) %} + input wire [DATA_WIDTH-1:0] input_{{p}}_axis_tdata, + input wire [KEEP_WIDTH-1:0] input_{{p}}_axis_tkeep, + input wire input_{{p}}_axis_tvalid, + output wire input_{{p}}_axis_tready, + input wire input_{{p}}_axis_tlast, + input wire [DEST_WIDTH-1:0] input_{{p}}_axis_tdest, + input wire input_{{p}}_axis_tuser, +{% endfor %} + /* + * AXI Stream outputs + */ +{%- for p in range(n) %} + output wire [DATA_WIDTH-1:0] output_{{p}}_axis_tdata, + output wire [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep, + output wire output_{{p}}_axis_tvalid, + input wire output_{{p}}_axis_tready, + output wire output_{{p}}_axis_tlast, + output wire [DEST_WIDTH-1:0] output_{{p}}_axis_tdest, + output wire output_{{p}}_axis_tuser{% if not loop.last %},{% endif %} +{% endfor -%} +); + +// check configuration +initial begin + if (2**DEST_WIDTH < {{n}}) begin + $error("Error: DEST_WIDTH too small for port count"); + $finish; + end + + if ({%- for p in range(n) %}(OUT_{{p}}_BASE & 2**DEST_WIDTH-1) != OUT_{{p}}_BASE || (OUT_{{p}}_TOP & 2**DEST_WIDTH-1) != OUT_{{p}}_TOP{% if not loop.last %} || + {% endif %}{% endfor -%}) begin + $error("Error: value out of range"); + $finish; + end + + if ({%- for p in range(n) %}OUT_{{p}}_BASE > OUT_{{p}}_TOP{% if not loop.last %} || + {% endif %}{% endfor -%}) begin + $error("Error: invalid range"); + $finish; + end + + if ({%- for p in range(n-1) %}{% set outer_loop = loop %}{%- for q in range(p+1,n) %}(OUT_{{p}}_BASE <= OUT_{{q}}_TOP && OUT_{{q}}_BASE <= OUT_{{p}}_TOP){% if not (loop.last and outer_loop.last) %} || + {% endif %}{% endfor -%}{% endfor -%}) begin + $error("Error: ranges overlap"); + $finish; + end +end +{%- for p in range(m) %} + +reg [{{n-1}}:0] input_{{p}}_request_reg = {{n}}'d0, input_{{p}}_request_next; +reg input_{{p}}_request_valid_reg = 1'b0, input_{{p}}_request_valid_next; +reg input_{{p}}_request_error_reg = 1'b0, input_{{p}}_request_error_next; +{%- endfor %} +{% for p in range(n) %} +reg [{{cm-1}}:0] select_{{p}}_reg = {{cm}}'d0, select_{{p}}_next; +{%- endfor %} +{% for p in range(n) %} +reg enable_{{p}}_reg = 1'b0, enable_{{p}}_next; +{%- endfor %} +{% for p in range(m) %} +reg input_{{p}}_axis_tready_reg = 1'b0, input_{{p}}_axis_tready_next; +{%- endfor %} + +// internal datapath +{%- for p in range(n) %} +reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_int; +reg [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep_int; +reg output_{{p}}_axis_tvalid_int; +reg output_{{p}}_axis_tready_int_reg = 1'b0; +reg output_{{p}}_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_{{p}}_axis_tdest_int; +reg output_{{p}}_axis_tuser_int; +wire output_{{p}}_axis_tready_int_early; +{% endfor %} +{%- for p in range(m) %} +assign input_{{p}}_axis_tready = input_{{p}}_axis_tready_reg; +{%- endfor %} + +// mux for start of packet detection + +{%- for p in range(n) %} +reg selected_input_{{p}}_axis_tvalid; + +always @* begin + case (grant_encoded_{{p}}) +{%- for q in range(m) %} + {{cm}}'d{{q}}: selected_input_{{p}}_axis_tvalid = input_{{q}}_axis_tvalid; +{%- endfor %} + default: selected_input_{{p}}_axis_tvalid = 1'b0; + endcase +end +{% endfor %} +// mux for incoming packet +{% for p in range(n) %} +reg [DATA_WIDTH-1:0] current_input_{{p}}_axis_tdata; +reg [KEEP_WIDTH-1:0] current_input_{{p}}_axis_tkeep; +reg current_input_{{p}}_axis_tvalid; +reg current_input_{{p}}_axis_tready; +reg current_input_{{p}}_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_{{p}}_axis_tdest; +reg current_input_{{p}}_axis_tuser; + +always @* begin + case (select_{{p}}_reg) +{%- for q in range(m) %} + {{cm}}'d{{q}}: begin + current_input_{{p}}_axis_tdata = input_{{q}}_axis_tdata; + current_input_{{p}}_axis_tkeep = input_{{q}}_axis_tkeep; + current_input_{{p}}_axis_tvalid = input_{{q}}_axis_tvalid; + current_input_{{p}}_axis_tready = input_{{q}}_axis_tready; + current_input_{{p}}_axis_tlast = input_{{q}}_axis_tlast; + current_input_{{p}}_axis_tdest = input_{{q}}_axis_tdest; + current_input_{{p}}_axis_tuser = input_{{q}}_axis_tuser; + end +{%- endfor %} + default: begin + current_input_{{p}}_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_{{p}}_axis_tkeep = {KEEP_WIDTH{1'b0}}; + current_input_{{p}}_axis_tvalid = 1'b0; + current_input_{{p}}_axis_tready = 1'b0; + current_input_{{p}}_axis_tlast = 1'b0; + current_input_{{p}}_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_{{p}}_axis_tuser = 1'b0; + end + endcase +end +{% endfor %} +// arbiter instances +{% for p in range(n) %} +wire [{{m-1}}:0] request_{{p}}; +wire [{{m-1}}:0] acknowledge_{{p}}; +wire [{{m-1}}:0] grant_{{p}}; +wire grant_valid_{{p}}; +wire [{{cm-1}}:0] grant_encoded_{{p}}; +{% endfor %} + +{%- for p in range(n) %} +arbiter #( + .PORTS({{m}}), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_{{p}}_inst ( + .clk(clk), + .rst(rst), + .request(request_{{p}}), + .acknowledge(acknowledge_{{p}}), + .grant(grant_{{p}}), + .grant_valid(grant_valid_{{p}}), + .grant_encoded(grant_encoded_{{p}}) +); +{% endfor %} +// request generation +{%- for p in range(n) %} +{%- for q in range(m) %} +assign request_{{p}}[{{q}}] = input_{{q}}_request_reg[{{p}}] & ~acknowledge_{{p}}[{{q}}]; +{%- endfor %} +{% endfor %} +// acknowledge generation +{%- for p in range(n) %} +{%- for q in range(m) %} +assign acknowledge_{{p}}[{{q}}] = grant_{{p}}[{{q}}] & input_{{q}}_axis_tvalid & input_{{q}}_axis_tready & input_{{q}}_axis_tlast; +{%- endfor %} +{% endfor %} +always @* begin +{%- for p in range(n) %} + select_{{p}}_next = select_{{p}}_reg; +{%- endfor %} +{% for p in range(n) %} + enable_{{p}}_next = enable_{{p}}_reg; +{%- endfor %} +{% for p in range(m) %} + input_{{p}}_request_next = input_{{p}}_request_reg; + input_{{p}}_request_valid_next = input_{{p}}_request_valid_reg; + input_{{p}}_request_error_next = input_{{p}}_request_error_reg; +{% endfor %} +{%- for p in range(m) %} + input_{{p}}_axis_tready_next = 1'b0; +{%- endfor %} +{% for p in range(n) %} + output_{{p}}_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_{{p}}_axis_tkeep_int = {DATA_WIDTH{1'b0}}; + output_{{p}}_axis_tvalid_int = 1'b0; + output_{{p}}_axis_tlast_int = 1'b0; + output_{{p}}_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_{{p}}_axis_tuser_int = 1'b0; +{% endfor %} + // input decoding +{% for p in range(m) %} + if (input_{{p}}_request_valid_reg | input_{{p}}_request_error_reg) begin + if (input_{{p}}_axis_tvalid & input_{{p}}_axis_tready & input_{{p}}_axis_tlast) begin + input_{{p}}_request_next = {DEST_WIDTH{1'b0}}; + input_{{p}}_request_valid_next = 1'b0; + input_{{p}}_request_error_next = 1'b0; + end + end else if (input_{{p}}_axis_tvalid) begin +{%- for q in range(n) %} + input_{{p}}_request_next[{{q}}] = (input_{{p}}_axis_tdest >= OUT_{{q}}_BASE) & (input_{{p}}_axis_tdest <= OUT_{{q}}_TOP) & OUT_{{q}}_CONNECT[{{p}}]; +{%- endfor %} + + if (input_{{p}}_request_next) begin + input_{{p}}_request_valid_next = 1'b1; + end else begin + input_{{p}}_request_error_next = 1'b1; + end + end +{% endfor %} + // output control +{% for p in range(n) %} + if (enable_{{p}}_reg) begin + if (current_input_{{p}}_axis_tvalid & current_input_{{p}}_axis_tready) begin + enable_{{p}}_next = ~current_input_{{p}}_axis_tlast; + end + end else if (grant_valid_{{p}} & selected_input_{{p}}_axis_tvalid) begin + enable_{{p}}_next = 1'b1; + select_{{p}}_next = grant_encoded_{{p}}; + end +{% endfor %} + // generate ready signal on selected port +{% for p in range(n) %} + if (enable_{{p}}_next) begin + case (select_{{p}}_next) +{%- for q in range(m) %} + {{cm}}'d{{q}}: input_{{q}}_axis_tready_next = output_{{p}}_axis_tready_int_early; +{%- endfor %} + endcase + end +{% endfor %} + +{%- for p in range(m) %} + if (input_{{p}}_request_error_next) + input_{{p}}_axis_tready_next = 1'b1; +{%- endfor %} + + // pass through selected packet data +{% for p in range(n) %} + output_{{p}}_axis_tdata_int = current_input_{{p}}_axis_tdata; + output_{{p}}_axis_tkeep_int = current_input_{{p}}_axis_tkeep; + output_{{p}}_axis_tvalid_int = current_input_{{p}}_axis_tvalid & current_input_{{p}}_axis_tready & enable_{{p}}_reg; + output_{{p}}_axis_tlast_int = current_input_{{p}}_axis_tlast; + output_{{p}}_axis_tdest_int = current_input_{{p}}_axis_tdest; + output_{{p}}_axis_tuser_int = current_input_{{p}}_axis_tuser; +{% endfor -%} +end + +always @(posedge clk) begin + if (rst) begin +{%- for p in range(m) %} + input_{{p}}_request_reg <= {{n}}'d0; + input_{{p}}_request_valid_reg <= 1'b0; + input_{{p}}_request_error_reg <= 1'b0; +{%- endfor %} +{%- for p in range(n) %} + select_{{p}}_reg <= 2'd0; +{%- endfor %} +{%- for p in range(n) %} + enable_{{p}}_reg <= 1'b0; +{%- endfor %} +{%- for p in range(m) %} + input_{{p}}_axis_tready_reg <= 1'b0; +{%- endfor %} + end else begin +{%- for p in range(m) %} + input_{{p}}_request_reg <= input_{{p}}_request_next; + input_{{p}}_request_valid_reg <= input_{{p}}_request_valid_next; + input_{{p}}_request_error_reg <= input_{{p}}_request_error_next; +{%- endfor %} +{%- for p in range(n) %} + select_{{p}}_reg <= select_{{p}}_next; +{%- endfor %} +{%- for p in range(n) %} + enable_{{p}}_reg <= enable_{{p}}_next; +{%- endfor %} +{%- for p in range(m) %} + input_{{p}}_axis_tready_reg <= input_{{p}}_axis_tready_next; +{%- endfor %} + end +end +{% for p in range(n) %} +// output {{p}} datapath logic +reg [DATA_WIDTH-1:0] output_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg output_{{p}}_axis_tvalid_reg = 1'b0, output_{{p}}_axis_tvalid_next; +reg output_{{p}}_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_{{p}}_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_{{p}}_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_{{p}}_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] temp_{{p}}_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg temp_{{p}}_axis_tvalid_reg = 1'b0, temp_{{p}}_axis_tvalid_next; +reg temp_{{p}}_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_{{p}}_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_{{p}}_axis_tuser_reg = 1'b0; + +// datapath control +reg store_{{p}}_axis_int_to_output; +reg store_{{p}}_axis_int_to_temp; +reg store_{{p}}_axis_temp_to_output; + +assign output_{{p}}_axis_tdata = output_{{p}}_axis_tdata_reg; +assign output_{{p}}_axis_tkeep = output_{{p}}_axis_tkeep_reg; +assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg; +assign output_{{p}}_axis_tlast = output_{{p}}_axis_tlast_reg; +assign output_{{p}}_axis_tdest = output_{{p}}_axis_tdest_reg; +assign output_{{p}}_axis_tuser = output_{{p}}_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_{{p}}_axis_tready_int_early = output_{{p}}_axis_tready | (~temp_{{p}}_axis_tvalid_reg & (~output_{{p}}_axis_tvalid_reg | ~output_{{p}}_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_reg; + temp_{{p}}_axis_tvalid_next = temp_{{p}}_axis_tvalid_reg; + + store_{{p}}_axis_int_to_output = 1'b0; + store_{{p}}_axis_int_to_temp = 1'b0; + store_{{p}}_axis_temp_to_output = 1'b0; + + if (output_{{p}}_axis_tready_int_reg) begin + // input is ready + if (output_{{p}}_axis_tready | ~output_{{p}}_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_int; + store_{{p}}_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_int; + store_{{p}}_axis_int_to_temp = 1'b1; + end + end else if (output_{{p}}_axis_tready) begin + // input is not ready, but output is ready + output_{{p}}_axis_tvalid_next = temp_{{p}}_axis_tvalid_reg; + temp_{{p}}_axis_tvalid_next = 1'b0; + store_{{p}}_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_{{p}}_axis_tvalid_reg <= 1'b0; + output_{{p}}_axis_tready_int_reg <= 1'b0; + temp_{{p}}_axis_tvalid_reg <= 1'b0; + end else begin + output_{{p}}_axis_tvalid_reg <= output_{{p}}_axis_tvalid_next; + output_{{p}}_axis_tready_int_reg <= output_{{p}}_axis_tready_int_early; + temp_{{p}}_axis_tvalid_reg <= temp_{{p}}_axis_tvalid_next; + end + + // datapath + if (store_{{p}}_axis_int_to_output) begin + output_{{p}}_axis_tdata_reg <= output_{{p}}_axis_tdata_int; + output_{{p}}_axis_tkeep_reg <= output_{{p}}_axis_tkeep_int; + output_{{p}}_axis_tlast_reg <= output_{{p}}_axis_tlast_int; + output_{{p}}_axis_tdest_reg <= output_{{p}}_axis_tdest_int; + output_{{p}}_axis_tuser_reg <= output_{{p}}_axis_tuser_int; + end else if (store_{{p}}_axis_temp_to_output) begin + output_{{p}}_axis_tdata_reg <= temp_{{p}}_axis_tdata_reg; + output_{{p}}_axis_tkeep_reg <= temp_{{p}}_axis_tkeep_reg; + output_{{p}}_axis_tlast_reg <= temp_{{p}}_axis_tlast_reg; + output_{{p}}_axis_tdest_reg <= temp_{{p}}_axis_tdest_reg; + output_{{p}}_axis_tuser_reg <= temp_{{p}}_axis_tuser_reg; + end + + if (store_{{p}}_axis_int_to_temp) begin + temp_{{p}}_axis_tdata_reg <= output_{{p}}_axis_tdata_int; + temp_{{p}}_axis_tkeep_reg <= output_{{p}}_axis_tkeep_int; + temp_{{p}}_axis_tlast_reg <= output_{{p}}_axis_tlast_int; + temp_{{p}}_axis_tdest_reg <= output_{{p}}_axis_tdest_int; + temp_{{p}}_axis_tuser_reg <= output_{{p}}_axis_tuser_int; + end +end +{% endfor %} +endmodule + +""") + + output_file.write(t.render( + m=m, + n=n, + cm=cm, + cn=cn, + name=name + )) + + print("Done") + +if __name__ == "__main__": + main() + diff --git a/rtl/axis_switch_64_4x4.v b/rtl/axis_switch_64_4x4.v new file mode 100644 index 00000000..6370a1f4 --- /dev/null +++ b/rtl/axis_switch_64_4x4.v @@ -0,0 +1,1331 @@ +/* + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4-Stream 4x4 switch (64 bit datapath) + */ +module axis_switch_64_4x4 # +( + parameter DATA_WIDTH = 64, + parameter KEEP_WIDTH = (DATA_WIDTH/8), + parameter DEST_WIDTH = 2, + parameter OUT_0_BASE = 0, + parameter OUT_0_TOP = 0, + parameter OUT_0_CONNECT = 4'b1111, + parameter OUT_1_BASE = 1, + parameter OUT_1_TOP = 1, + parameter OUT_1_CONNECT = 4'b1111, + parameter OUT_2_BASE = 2, + parameter OUT_2_TOP = 2, + parameter OUT_2_CONNECT = 4'b1111, + parameter OUT_3_BASE = 3, + parameter OUT_3_TOP = 3, + parameter OUT_3_CONNECT = 4'b1111, + // arbitration type: "PRIORITY" or "ROUND_ROBIN" + parameter ARB_TYPE = "ROUND_ROBIN", + // LSB priority: "LOW", "HIGH" + parameter LSB_PRIORITY = "HIGH" +) +( + input wire clk, + input wire rst, + + /* + * AXI Stream inputs + */ + input wire [DATA_WIDTH-1:0] input_0_axis_tdata, + input wire [KEEP_WIDTH-1:0] input_0_axis_tkeep, + input wire input_0_axis_tvalid, + output wire input_0_axis_tready, + input wire input_0_axis_tlast, + input wire [DEST_WIDTH-1:0] input_0_axis_tdest, + input wire input_0_axis_tuser, + + input wire [DATA_WIDTH-1:0] input_1_axis_tdata, + input wire [KEEP_WIDTH-1:0] input_1_axis_tkeep, + input wire input_1_axis_tvalid, + output wire input_1_axis_tready, + input wire input_1_axis_tlast, + input wire [DEST_WIDTH-1:0] input_1_axis_tdest, + input wire input_1_axis_tuser, + + input wire [DATA_WIDTH-1:0] input_2_axis_tdata, + input wire [KEEP_WIDTH-1:0] input_2_axis_tkeep, + input wire input_2_axis_tvalid, + output wire input_2_axis_tready, + input wire input_2_axis_tlast, + input wire [DEST_WIDTH-1:0] input_2_axis_tdest, + input wire input_2_axis_tuser, + + input wire [DATA_WIDTH-1:0] input_3_axis_tdata, + input wire [KEEP_WIDTH-1:0] input_3_axis_tkeep, + input wire input_3_axis_tvalid, + output wire input_3_axis_tready, + input wire input_3_axis_tlast, + input wire [DEST_WIDTH-1:0] input_3_axis_tdest, + input wire input_3_axis_tuser, + + /* + * AXI Stream outputs + */ + output wire [DATA_WIDTH-1:0] output_0_axis_tdata, + output wire [KEEP_WIDTH-1:0] output_0_axis_tkeep, + output wire output_0_axis_tvalid, + input wire output_0_axis_tready, + output wire output_0_axis_tlast, + output wire [DEST_WIDTH-1:0] output_0_axis_tdest, + output wire output_0_axis_tuser, + + output wire [DATA_WIDTH-1:0] output_1_axis_tdata, + output wire [KEEP_WIDTH-1:0] output_1_axis_tkeep, + output wire output_1_axis_tvalid, + input wire output_1_axis_tready, + output wire output_1_axis_tlast, + output wire [DEST_WIDTH-1:0] output_1_axis_tdest, + output wire output_1_axis_tuser, + + output wire [DATA_WIDTH-1:0] output_2_axis_tdata, + output wire [KEEP_WIDTH-1:0] output_2_axis_tkeep, + output wire output_2_axis_tvalid, + input wire output_2_axis_tready, + output wire output_2_axis_tlast, + output wire [DEST_WIDTH-1:0] output_2_axis_tdest, + output wire output_2_axis_tuser, + + output wire [DATA_WIDTH-1:0] output_3_axis_tdata, + output wire [KEEP_WIDTH-1:0] output_3_axis_tkeep, + output wire output_3_axis_tvalid, + input wire output_3_axis_tready, + output wire output_3_axis_tlast, + output wire [DEST_WIDTH-1:0] output_3_axis_tdest, + output wire output_3_axis_tuser +); + +// check configuration +initial begin + if (2**DEST_WIDTH < 4) begin + $error("Error: DEST_WIDTH too small for port count"); + $finish; + end + + if ((OUT_0_BASE & 2**DEST_WIDTH-1) != OUT_0_BASE || (OUT_0_TOP & 2**DEST_WIDTH-1) != OUT_0_TOP || + (OUT_1_BASE & 2**DEST_WIDTH-1) != OUT_1_BASE || (OUT_1_TOP & 2**DEST_WIDTH-1) != OUT_1_TOP || + (OUT_2_BASE & 2**DEST_WIDTH-1) != OUT_2_BASE || (OUT_2_TOP & 2**DEST_WIDTH-1) != OUT_2_TOP || + (OUT_3_BASE & 2**DEST_WIDTH-1) != OUT_3_BASE || (OUT_3_TOP & 2**DEST_WIDTH-1) != OUT_3_TOP) begin + $error("Error: value out of range"); + $finish; + end + + if (OUT_0_BASE > OUT_0_TOP || + OUT_1_BASE > OUT_1_TOP || + OUT_2_BASE > OUT_2_TOP || + OUT_3_BASE > OUT_3_TOP) begin + $error("Error: invalid range"); + $finish; + end + + if ((OUT_0_BASE <= OUT_1_TOP && OUT_1_BASE <= OUT_0_TOP) || + (OUT_0_BASE <= OUT_2_TOP && OUT_2_BASE <= OUT_0_TOP) || + (OUT_0_BASE <= OUT_3_TOP && OUT_3_BASE <= OUT_0_TOP) || + (OUT_1_BASE <= OUT_2_TOP && OUT_2_BASE <= OUT_1_TOP) || + (OUT_1_BASE <= OUT_3_TOP && OUT_3_BASE <= OUT_1_TOP) || + (OUT_2_BASE <= OUT_3_TOP && OUT_3_BASE <= OUT_2_TOP)) begin + $error("Error: ranges overlap"); + $finish; + end +end + +reg [3:0] input_0_request_reg = 4'd0, input_0_request_next; +reg input_0_request_valid_reg = 1'b0, input_0_request_valid_next; +reg input_0_request_error_reg = 1'b0, input_0_request_error_next; + +reg [3:0] input_1_request_reg = 4'd0, input_1_request_next; +reg input_1_request_valid_reg = 1'b0, input_1_request_valid_next; +reg input_1_request_error_reg = 1'b0, input_1_request_error_next; + +reg [3:0] input_2_request_reg = 4'd0, input_2_request_next; +reg input_2_request_valid_reg = 1'b0, input_2_request_valid_next; +reg input_2_request_error_reg = 1'b0, input_2_request_error_next; + +reg [3:0] input_3_request_reg = 4'd0, input_3_request_next; +reg input_3_request_valid_reg = 1'b0, input_3_request_valid_next; +reg input_3_request_error_reg = 1'b0, input_3_request_error_next; + +reg [1:0] select_0_reg = 2'd0, select_0_next; +reg [1:0] select_1_reg = 2'd0, select_1_next; +reg [1:0] select_2_reg = 2'd0, select_2_next; +reg [1:0] select_3_reg = 2'd0, select_3_next; + +reg enable_0_reg = 1'b0, enable_0_next; +reg enable_1_reg = 1'b0, enable_1_next; +reg enable_2_reg = 1'b0, enable_2_next; +reg enable_3_reg = 1'b0, enable_3_next; + +reg input_0_axis_tready_reg = 1'b0, input_0_axis_tready_next; +reg input_1_axis_tready_reg = 1'b0, input_1_axis_tready_next; +reg input_2_axis_tready_reg = 1'b0, input_2_axis_tready_next; +reg input_3_axis_tready_reg = 1'b0, input_3_axis_tready_next; + +// internal datapath +reg [DATA_WIDTH-1:0] output_0_axis_tdata_int; +reg [KEEP_WIDTH-1:0] output_0_axis_tkeep_int; +reg output_0_axis_tvalid_int; +reg output_0_axis_tready_int_reg = 1'b0; +reg output_0_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_0_axis_tdest_int; +reg output_0_axis_tuser_int; +wire output_0_axis_tready_int_early; + +reg [DATA_WIDTH-1:0] output_1_axis_tdata_int; +reg [KEEP_WIDTH-1:0] output_1_axis_tkeep_int; +reg output_1_axis_tvalid_int; +reg output_1_axis_tready_int_reg = 1'b0; +reg output_1_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_1_axis_tdest_int; +reg output_1_axis_tuser_int; +wire output_1_axis_tready_int_early; + +reg [DATA_WIDTH-1:0] output_2_axis_tdata_int; +reg [KEEP_WIDTH-1:0] output_2_axis_tkeep_int; +reg output_2_axis_tvalid_int; +reg output_2_axis_tready_int_reg = 1'b0; +reg output_2_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_2_axis_tdest_int; +reg output_2_axis_tuser_int; +wire output_2_axis_tready_int_early; + +reg [DATA_WIDTH-1:0] output_3_axis_tdata_int; +reg [KEEP_WIDTH-1:0] output_3_axis_tkeep_int; +reg output_3_axis_tvalid_int; +reg output_3_axis_tready_int_reg = 1'b0; +reg output_3_axis_tlast_int; +reg [DEST_WIDTH-1:0] output_3_axis_tdest_int; +reg output_3_axis_tuser_int; +wire output_3_axis_tready_int_early; + +assign input_0_axis_tready = input_0_axis_tready_reg; +assign input_1_axis_tready = input_1_axis_tready_reg; +assign input_2_axis_tready = input_2_axis_tready_reg; +assign input_3_axis_tready = input_3_axis_tready_reg; + +// mux for start of packet detection +reg selected_input_0_axis_tvalid; + +always @* begin + case (grant_encoded_0) + 2'd0: selected_input_0_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_0_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_0_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_0_axis_tvalid = input_3_axis_tvalid; + default: selected_input_0_axis_tvalid = 1'b0; + endcase +end + +reg selected_input_1_axis_tvalid; + +always @* begin + case (grant_encoded_1) + 2'd0: selected_input_1_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_1_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_1_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_1_axis_tvalid = input_3_axis_tvalid; + default: selected_input_1_axis_tvalid = 1'b0; + endcase +end + +reg selected_input_2_axis_tvalid; + +always @* begin + case (grant_encoded_2) + 2'd0: selected_input_2_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_2_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_2_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_2_axis_tvalid = input_3_axis_tvalid; + default: selected_input_2_axis_tvalid = 1'b0; + endcase +end + +reg selected_input_3_axis_tvalid; + +always @* begin + case (grant_encoded_3) + 2'd0: selected_input_3_axis_tvalid = input_0_axis_tvalid; + 2'd1: selected_input_3_axis_tvalid = input_1_axis_tvalid; + 2'd2: selected_input_3_axis_tvalid = input_2_axis_tvalid; + 2'd3: selected_input_3_axis_tvalid = input_3_axis_tvalid; + default: selected_input_3_axis_tvalid = 1'b0; + endcase +end + +// mux for incoming packet + +reg [DATA_WIDTH-1:0] current_input_0_axis_tdata; +reg [KEEP_WIDTH-1:0] current_input_0_axis_tkeep; +reg current_input_0_axis_tvalid; +reg current_input_0_axis_tready; +reg current_input_0_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_0_axis_tdest; +reg current_input_0_axis_tuser; + +always @* begin + case (select_0_reg) + 2'd0: begin + current_input_0_axis_tdata = input_0_axis_tdata; + current_input_0_axis_tkeep = input_0_axis_tkeep; + current_input_0_axis_tvalid = input_0_axis_tvalid; + current_input_0_axis_tready = input_0_axis_tready; + current_input_0_axis_tlast = input_0_axis_tlast; + current_input_0_axis_tdest = input_0_axis_tdest; + current_input_0_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_0_axis_tdata = input_1_axis_tdata; + current_input_0_axis_tkeep = input_1_axis_tkeep; + current_input_0_axis_tvalid = input_1_axis_tvalid; + current_input_0_axis_tready = input_1_axis_tready; + current_input_0_axis_tlast = input_1_axis_tlast; + current_input_0_axis_tdest = input_1_axis_tdest; + current_input_0_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_0_axis_tdata = input_2_axis_tdata; + current_input_0_axis_tkeep = input_2_axis_tkeep; + current_input_0_axis_tvalid = input_2_axis_tvalid; + current_input_0_axis_tready = input_2_axis_tready; + current_input_0_axis_tlast = input_2_axis_tlast; + current_input_0_axis_tdest = input_2_axis_tdest; + current_input_0_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_0_axis_tdata = input_3_axis_tdata; + current_input_0_axis_tkeep = input_3_axis_tkeep; + current_input_0_axis_tvalid = input_3_axis_tvalid; + current_input_0_axis_tready = input_3_axis_tready; + current_input_0_axis_tlast = input_3_axis_tlast; + current_input_0_axis_tdest = input_3_axis_tdest; + current_input_0_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_0_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_0_axis_tkeep = {KEEP_WIDTH{1'b0}}; + current_input_0_axis_tvalid = 1'b0; + current_input_0_axis_tready = 1'b0; + current_input_0_axis_tlast = 1'b0; + current_input_0_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_0_axis_tuser = 1'b0; + end + endcase +end + +reg [DATA_WIDTH-1:0] current_input_1_axis_tdata; +reg [KEEP_WIDTH-1:0] current_input_1_axis_tkeep; +reg current_input_1_axis_tvalid; +reg current_input_1_axis_tready; +reg current_input_1_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_1_axis_tdest; +reg current_input_1_axis_tuser; + +always @* begin + case (select_1_reg) + 2'd0: begin + current_input_1_axis_tdata = input_0_axis_tdata; + current_input_1_axis_tkeep = input_0_axis_tkeep; + current_input_1_axis_tvalid = input_0_axis_tvalid; + current_input_1_axis_tready = input_0_axis_tready; + current_input_1_axis_tlast = input_0_axis_tlast; + current_input_1_axis_tdest = input_0_axis_tdest; + current_input_1_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_1_axis_tdata = input_1_axis_tdata; + current_input_1_axis_tkeep = input_1_axis_tkeep; + current_input_1_axis_tvalid = input_1_axis_tvalid; + current_input_1_axis_tready = input_1_axis_tready; + current_input_1_axis_tlast = input_1_axis_tlast; + current_input_1_axis_tdest = input_1_axis_tdest; + current_input_1_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_1_axis_tdata = input_2_axis_tdata; + current_input_1_axis_tkeep = input_2_axis_tkeep; + current_input_1_axis_tvalid = input_2_axis_tvalid; + current_input_1_axis_tready = input_2_axis_tready; + current_input_1_axis_tlast = input_2_axis_tlast; + current_input_1_axis_tdest = input_2_axis_tdest; + current_input_1_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_1_axis_tdata = input_3_axis_tdata; + current_input_1_axis_tkeep = input_3_axis_tkeep; + current_input_1_axis_tvalid = input_3_axis_tvalid; + current_input_1_axis_tready = input_3_axis_tready; + current_input_1_axis_tlast = input_3_axis_tlast; + current_input_1_axis_tdest = input_3_axis_tdest; + current_input_1_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_1_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_1_axis_tkeep = {KEEP_WIDTH{1'b0}}; + current_input_1_axis_tvalid = 1'b0; + current_input_1_axis_tready = 1'b0; + current_input_1_axis_tlast = 1'b0; + current_input_1_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_1_axis_tuser = 1'b0; + end + endcase +end + +reg [DATA_WIDTH-1:0] current_input_2_axis_tdata; +reg [KEEP_WIDTH-1:0] current_input_2_axis_tkeep; +reg current_input_2_axis_tvalid; +reg current_input_2_axis_tready; +reg current_input_2_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_2_axis_tdest; +reg current_input_2_axis_tuser; + +always @* begin + case (select_2_reg) + 2'd0: begin + current_input_2_axis_tdata = input_0_axis_tdata; + current_input_2_axis_tkeep = input_0_axis_tkeep; + current_input_2_axis_tvalid = input_0_axis_tvalid; + current_input_2_axis_tready = input_0_axis_tready; + current_input_2_axis_tlast = input_0_axis_tlast; + current_input_2_axis_tdest = input_0_axis_tdest; + current_input_2_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_2_axis_tdata = input_1_axis_tdata; + current_input_2_axis_tkeep = input_1_axis_tkeep; + current_input_2_axis_tvalid = input_1_axis_tvalid; + current_input_2_axis_tready = input_1_axis_tready; + current_input_2_axis_tlast = input_1_axis_tlast; + current_input_2_axis_tdest = input_1_axis_tdest; + current_input_2_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_2_axis_tdata = input_2_axis_tdata; + current_input_2_axis_tkeep = input_2_axis_tkeep; + current_input_2_axis_tvalid = input_2_axis_tvalid; + current_input_2_axis_tready = input_2_axis_tready; + current_input_2_axis_tlast = input_2_axis_tlast; + current_input_2_axis_tdest = input_2_axis_tdest; + current_input_2_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_2_axis_tdata = input_3_axis_tdata; + current_input_2_axis_tkeep = input_3_axis_tkeep; + current_input_2_axis_tvalid = input_3_axis_tvalid; + current_input_2_axis_tready = input_3_axis_tready; + current_input_2_axis_tlast = input_3_axis_tlast; + current_input_2_axis_tdest = input_3_axis_tdest; + current_input_2_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_2_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_2_axis_tkeep = {KEEP_WIDTH{1'b0}}; + current_input_2_axis_tvalid = 1'b0; + current_input_2_axis_tready = 1'b0; + current_input_2_axis_tlast = 1'b0; + current_input_2_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_2_axis_tuser = 1'b0; + end + endcase +end + +reg [DATA_WIDTH-1:0] current_input_3_axis_tdata; +reg [KEEP_WIDTH-1:0] current_input_3_axis_tkeep; +reg current_input_3_axis_tvalid; +reg current_input_3_axis_tready; +reg current_input_3_axis_tlast; +reg [DEST_WIDTH-1:0] current_input_3_axis_tdest; +reg current_input_3_axis_tuser; + +always @* begin + case (select_3_reg) + 2'd0: begin + current_input_3_axis_tdata = input_0_axis_tdata; + current_input_3_axis_tkeep = input_0_axis_tkeep; + current_input_3_axis_tvalid = input_0_axis_tvalid; + current_input_3_axis_tready = input_0_axis_tready; + current_input_3_axis_tlast = input_0_axis_tlast; + current_input_3_axis_tdest = input_0_axis_tdest; + current_input_3_axis_tuser = input_0_axis_tuser; + end + 2'd1: begin + current_input_3_axis_tdata = input_1_axis_tdata; + current_input_3_axis_tkeep = input_1_axis_tkeep; + current_input_3_axis_tvalid = input_1_axis_tvalid; + current_input_3_axis_tready = input_1_axis_tready; + current_input_3_axis_tlast = input_1_axis_tlast; + current_input_3_axis_tdest = input_1_axis_tdest; + current_input_3_axis_tuser = input_1_axis_tuser; + end + 2'd2: begin + current_input_3_axis_tdata = input_2_axis_tdata; + current_input_3_axis_tkeep = input_2_axis_tkeep; + current_input_3_axis_tvalid = input_2_axis_tvalid; + current_input_3_axis_tready = input_2_axis_tready; + current_input_3_axis_tlast = input_2_axis_tlast; + current_input_3_axis_tdest = input_2_axis_tdest; + current_input_3_axis_tuser = input_2_axis_tuser; + end + 2'd3: begin + current_input_3_axis_tdata = input_3_axis_tdata; + current_input_3_axis_tkeep = input_3_axis_tkeep; + current_input_3_axis_tvalid = input_3_axis_tvalid; + current_input_3_axis_tready = input_3_axis_tready; + current_input_3_axis_tlast = input_3_axis_tlast; + current_input_3_axis_tdest = input_3_axis_tdest; + current_input_3_axis_tuser = input_3_axis_tuser; + end + default: begin + current_input_3_axis_tdata = {DATA_WIDTH{1'b0}}; + current_input_3_axis_tkeep = {KEEP_WIDTH{1'b0}}; + current_input_3_axis_tvalid = 1'b0; + current_input_3_axis_tready = 1'b0; + current_input_3_axis_tlast = 1'b0; + current_input_3_axis_tdest = {DEST_WIDTH{1'b0}}; + current_input_3_axis_tuser = 1'b0; + end + endcase +end + +// arbiter instances + +wire [3:0] request_0; +wire [3:0] acknowledge_0; +wire [3:0] grant_0; +wire grant_valid_0; +wire [1:0] grant_encoded_0; + +wire [3:0] request_1; +wire [3:0] acknowledge_1; +wire [3:0] grant_1; +wire grant_valid_1; +wire [1:0] grant_encoded_1; + +wire [3:0] request_2; +wire [3:0] acknowledge_2; +wire [3:0] grant_2; +wire grant_valid_2; +wire [1:0] grant_encoded_2; + +wire [3:0] request_3; +wire [3:0] acknowledge_3; +wire [3:0] grant_3; +wire grant_valid_3; +wire [1:0] grant_encoded_3; + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_0_inst ( + .clk(clk), + .rst(rst), + .request(request_0), + .acknowledge(acknowledge_0), + .grant(grant_0), + .grant_valid(grant_valid_0), + .grant_encoded(grant_encoded_0) +); + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_1_inst ( + .clk(clk), + .rst(rst), + .request(request_1), + .acknowledge(acknowledge_1), + .grant(grant_1), + .grant_valid(grant_valid_1), + .grant_encoded(grant_encoded_1) +); + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_2_inst ( + .clk(clk), + .rst(rst), + .request(request_2), + .acknowledge(acknowledge_2), + .grant(grant_2), + .grant_valid(grant_valid_2), + .grant_encoded(grant_encoded_2) +); + +arbiter #( + .PORTS(4), + .TYPE(ARB_TYPE), + .BLOCK("ACKNOWLEDGE"), + .LSB_PRIORITY(LSB_PRIORITY) +) +arb_3_inst ( + .clk(clk), + .rst(rst), + .request(request_3), + .acknowledge(acknowledge_3), + .grant(grant_3), + .grant_valid(grant_valid_3), + .grant_encoded(grant_encoded_3) +); + +// request generation +assign request_0[0] = input_0_request_reg[0] & ~acknowledge_0[0]; +assign request_0[1] = input_1_request_reg[0] & ~acknowledge_0[1]; +assign request_0[2] = input_2_request_reg[0] & ~acknowledge_0[2]; +assign request_0[3] = input_3_request_reg[0] & ~acknowledge_0[3]; + +assign request_1[0] = input_0_request_reg[1] & ~acknowledge_1[0]; +assign request_1[1] = input_1_request_reg[1] & ~acknowledge_1[1]; +assign request_1[2] = input_2_request_reg[1] & ~acknowledge_1[2]; +assign request_1[3] = input_3_request_reg[1] & ~acknowledge_1[3]; + +assign request_2[0] = input_0_request_reg[2] & ~acknowledge_2[0]; +assign request_2[1] = input_1_request_reg[2] & ~acknowledge_2[1]; +assign request_2[2] = input_2_request_reg[2] & ~acknowledge_2[2]; +assign request_2[3] = input_3_request_reg[2] & ~acknowledge_2[3]; + +assign request_3[0] = input_0_request_reg[3] & ~acknowledge_3[0]; +assign request_3[1] = input_1_request_reg[3] & ~acknowledge_3[1]; +assign request_3[2] = input_2_request_reg[3] & ~acknowledge_3[2]; +assign request_3[3] = input_3_request_reg[3] & ~acknowledge_3[3]; + +// acknowledge generation +assign acknowledge_0[0] = grant_0[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_0[1] = grant_0[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_0[2] = grant_0[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_0[3] = grant_0[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +assign acknowledge_1[0] = grant_1[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_1[1] = grant_1[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_1[2] = grant_1[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_1[3] = grant_1[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +assign acknowledge_2[0] = grant_2[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_2[1] = grant_2[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_2[2] = grant_2[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_2[3] = grant_2[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +assign acknowledge_3[0] = grant_3[0] & input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast; +assign acknowledge_3[1] = grant_3[1] & input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast; +assign acknowledge_3[2] = grant_3[2] & input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast; +assign acknowledge_3[3] = grant_3[3] & input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast; + +always @* begin + select_0_next = select_0_reg; + select_1_next = select_1_reg; + select_2_next = select_2_reg; + select_3_next = select_3_reg; + + enable_0_next = enable_0_reg; + enable_1_next = enable_1_reg; + enable_2_next = enable_2_reg; + enable_3_next = enable_3_reg; + + input_0_request_next = input_0_request_reg; + input_0_request_valid_next = input_0_request_valid_reg; + input_0_request_error_next = input_0_request_error_reg; + + input_1_request_next = input_1_request_reg; + input_1_request_valid_next = input_1_request_valid_reg; + input_1_request_error_next = input_1_request_error_reg; + + input_2_request_next = input_2_request_reg; + input_2_request_valid_next = input_2_request_valid_reg; + input_2_request_error_next = input_2_request_error_reg; + + input_3_request_next = input_3_request_reg; + input_3_request_valid_next = input_3_request_valid_reg; + input_3_request_error_next = input_3_request_error_reg; + + input_0_axis_tready_next = 1'b0; + input_1_axis_tready_next = 1'b0; + input_2_axis_tready_next = 1'b0; + input_3_axis_tready_next = 1'b0; + + output_0_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_0_axis_tkeep_int = {DATA_WIDTH{1'b0}}; + output_0_axis_tvalid_int = 1'b0; + output_0_axis_tlast_int = 1'b0; + output_0_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_0_axis_tuser_int = 1'b0; + + output_1_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_1_axis_tkeep_int = {DATA_WIDTH{1'b0}}; + output_1_axis_tvalid_int = 1'b0; + output_1_axis_tlast_int = 1'b0; + output_1_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_1_axis_tuser_int = 1'b0; + + output_2_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_2_axis_tkeep_int = {DATA_WIDTH{1'b0}}; + output_2_axis_tvalid_int = 1'b0; + output_2_axis_tlast_int = 1'b0; + output_2_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_2_axis_tuser_int = 1'b0; + + output_3_axis_tdata_int = {DATA_WIDTH{1'b0}}; + output_3_axis_tkeep_int = {DATA_WIDTH{1'b0}}; + output_3_axis_tvalid_int = 1'b0; + output_3_axis_tlast_int = 1'b0; + output_3_axis_tdest_int = {DEST_WIDTH{1'b0}}; + output_3_axis_tuser_int = 1'b0; + + // input decoding + + if (input_0_request_valid_reg | input_0_request_error_reg) begin + if (input_0_axis_tvalid & input_0_axis_tready & input_0_axis_tlast) begin + input_0_request_next = {DEST_WIDTH{1'b0}}; + input_0_request_valid_next = 1'b0; + input_0_request_error_next = 1'b0; + end + end else if (input_0_axis_tvalid) begin + input_0_request_next[0] = (input_0_axis_tdest >= OUT_0_BASE) & (input_0_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[0]; + input_0_request_next[1] = (input_0_axis_tdest >= OUT_1_BASE) & (input_0_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[0]; + input_0_request_next[2] = (input_0_axis_tdest >= OUT_2_BASE) & (input_0_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[0]; + input_0_request_next[3] = (input_0_axis_tdest >= OUT_3_BASE) & (input_0_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[0]; + + if (input_0_request_next) begin + input_0_request_valid_next = 1'b1; + end else begin + input_0_request_error_next = 1'b1; + end + end + + if (input_1_request_valid_reg | input_1_request_error_reg) begin + if (input_1_axis_tvalid & input_1_axis_tready & input_1_axis_tlast) begin + input_1_request_next = {DEST_WIDTH{1'b0}}; + input_1_request_valid_next = 1'b0; + input_1_request_error_next = 1'b0; + end + end else if (input_1_axis_tvalid) begin + input_1_request_next[0] = (input_1_axis_tdest >= OUT_0_BASE) & (input_1_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[1]; + input_1_request_next[1] = (input_1_axis_tdest >= OUT_1_BASE) & (input_1_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[1]; + input_1_request_next[2] = (input_1_axis_tdest >= OUT_2_BASE) & (input_1_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[1]; + input_1_request_next[3] = (input_1_axis_tdest >= OUT_3_BASE) & (input_1_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[1]; + + if (input_1_request_next) begin + input_1_request_valid_next = 1'b1; + end else begin + input_1_request_error_next = 1'b1; + end + end + + if (input_2_request_valid_reg | input_2_request_error_reg) begin + if (input_2_axis_tvalid & input_2_axis_tready & input_2_axis_tlast) begin + input_2_request_next = {DEST_WIDTH{1'b0}}; + input_2_request_valid_next = 1'b0; + input_2_request_error_next = 1'b0; + end + end else if (input_2_axis_tvalid) begin + input_2_request_next[0] = (input_2_axis_tdest >= OUT_0_BASE) & (input_2_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[2]; + input_2_request_next[1] = (input_2_axis_tdest >= OUT_1_BASE) & (input_2_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[2]; + input_2_request_next[2] = (input_2_axis_tdest >= OUT_2_BASE) & (input_2_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[2]; + input_2_request_next[3] = (input_2_axis_tdest >= OUT_3_BASE) & (input_2_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[2]; + + if (input_2_request_next) begin + input_2_request_valid_next = 1'b1; + end else begin + input_2_request_error_next = 1'b1; + end + end + + if (input_3_request_valid_reg | input_3_request_error_reg) begin + if (input_3_axis_tvalid & input_3_axis_tready & input_3_axis_tlast) begin + input_3_request_next = {DEST_WIDTH{1'b0}}; + input_3_request_valid_next = 1'b0; + input_3_request_error_next = 1'b0; + end + end else if (input_3_axis_tvalid) begin + input_3_request_next[0] = (input_3_axis_tdest >= OUT_0_BASE) & (input_3_axis_tdest <= OUT_0_TOP) & OUT_0_CONNECT[3]; + input_3_request_next[1] = (input_3_axis_tdest >= OUT_1_BASE) & (input_3_axis_tdest <= OUT_1_TOP) & OUT_1_CONNECT[3]; + input_3_request_next[2] = (input_3_axis_tdest >= OUT_2_BASE) & (input_3_axis_tdest <= OUT_2_TOP) & OUT_2_CONNECT[3]; + input_3_request_next[3] = (input_3_axis_tdest >= OUT_3_BASE) & (input_3_axis_tdest <= OUT_3_TOP) & OUT_3_CONNECT[3]; + + if (input_3_request_next) begin + input_3_request_valid_next = 1'b1; + end else begin + input_3_request_error_next = 1'b1; + end + end + + // output control + + if (enable_0_reg) begin + if (current_input_0_axis_tvalid & current_input_0_axis_tready) begin + enable_0_next = ~current_input_0_axis_tlast; + end + end else if (grant_valid_0 & selected_input_0_axis_tvalid) begin + enable_0_next = 1'b1; + select_0_next = grant_encoded_0; + end + + if (enable_1_reg) begin + if (current_input_1_axis_tvalid & current_input_1_axis_tready) begin + enable_1_next = ~current_input_1_axis_tlast; + end + end else if (grant_valid_1 & selected_input_1_axis_tvalid) begin + enable_1_next = 1'b1; + select_1_next = grant_encoded_1; + end + + if (enable_2_reg) begin + if (current_input_2_axis_tvalid & current_input_2_axis_tready) begin + enable_2_next = ~current_input_2_axis_tlast; + end + end else if (grant_valid_2 & selected_input_2_axis_tvalid) begin + enable_2_next = 1'b1; + select_2_next = grant_encoded_2; + end + + if (enable_3_reg) begin + if (current_input_3_axis_tvalid & current_input_3_axis_tready) begin + enable_3_next = ~current_input_3_axis_tlast; + end + end else if (grant_valid_3 & selected_input_3_axis_tvalid) begin + enable_3_next = 1'b1; + select_3_next = grant_encoded_3; + end + + // generate ready signal on selected port + + if (enable_0_next) begin + case (select_0_next) + 2'd0: input_0_axis_tready_next = output_0_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_0_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_0_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_0_axis_tready_int_early; + endcase + end + + if (enable_1_next) begin + case (select_1_next) + 2'd0: input_0_axis_tready_next = output_1_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_1_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_1_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_1_axis_tready_int_early; + endcase + end + + if (enable_2_next) begin + case (select_2_next) + 2'd0: input_0_axis_tready_next = output_2_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_2_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_2_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_2_axis_tready_int_early; + endcase + end + + if (enable_3_next) begin + case (select_3_next) + 2'd0: input_0_axis_tready_next = output_3_axis_tready_int_early; + 2'd1: input_1_axis_tready_next = output_3_axis_tready_int_early; + 2'd2: input_2_axis_tready_next = output_3_axis_tready_int_early; + 2'd3: input_3_axis_tready_next = output_3_axis_tready_int_early; + endcase + end + + if (input_0_request_error_next) + input_0_axis_tready_next = 1'b1; + if (input_1_request_error_next) + input_1_axis_tready_next = 1'b1; + if (input_2_request_error_next) + input_2_axis_tready_next = 1'b1; + if (input_3_request_error_next) + input_3_axis_tready_next = 1'b1; + + // pass through selected packet data + + output_0_axis_tdata_int = current_input_0_axis_tdata; + output_0_axis_tkeep_int = current_input_0_axis_tkeep; + output_0_axis_tvalid_int = current_input_0_axis_tvalid & current_input_0_axis_tready & enable_0_reg; + output_0_axis_tlast_int = current_input_0_axis_tlast; + output_0_axis_tdest_int = current_input_0_axis_tdest; + output_0_axis_tuser_int = current_input_0_axis_tuser; + + output_1_axis_tdata_int = current_input_1_axis_tdata; + output_1_axis_tkeep_int = current_input_1_axis_tkeep; + output_1_axis_tvalid_int = current_input_1_axis_tvalid & current_input_1_axis_tready & enable_1_reg; + output_1_axis_tlast_int = current_input_1_axis_tlast; + output_1_axis_tdest_int = current_input_1_axis_tdest; + output_1_axis_tuser_int = current_input_1_axis_tuser; + + output_2_axis_tdata_int = current_input_2_axis_tdata; + output_2_axis_tkeep_int = current_input_2_axis_tkeep; + output_2_axis_tvalid_int = current_input_2_axis_tvalid & current_input_2_axis_tready & enable_2_reg; + output_2_axis_tlast_int = current_input_2_axis_tlast; + output_2_axis_tdest_int = current_input_2_axis_tdest; + output_2_axis_tuser_int = current_input_2_axis_tuser; + + output_3_axis_tdata_int = current_input_3_axis_tdata; + output_3_axis_tkeep_int = current_input_3_axis_tkeep; + output_3_axis_tvalid_int = current_input_3_axis_tvalid & current_input_3_axis_tready & enable_3_reg; + output_3_axis_tlast_int = current_input_3_axis_tlast; + output_3_axis_tdest_int = current_input_3_axis_tdest; + output_3_axis_tuser_int = current_input_3_axis_tuser; +end + +always @(posedge clk) begin + if (rst) begin + input_0_request_reg <= 4'd0; + input_0_request_valid_reg <= 1'b0; + input_0_request_error_reg <= 1'b0; + input_1_request_reg <= 4'd0; + input_1_request_valid_reg <= 1'b0; + input_1_request_error_reg <= 1'b0; + input_2_request_reg <= 4'd0; + input_2_request_valid_reg <= 1'b0; + input_2_request_error_reg <= 1'b0; + input_3_request_reg <= 4'd0; + input_3_request_valid_reg <= 1'b0; + input_3_request_error_reg <= 1'b0; + select_0_reg <= 2'd0; + select_1_reg <= 2'd0; + select_2_reg <= 2'd0; + select_3_reg <= 2'd0; + enable_0_reg <= 1'b0; + enable_1_reg <= 1'b0; + enable_2_reg <= 1'b0; + enable_3_reg <= 1'b0; + input_0_axis_tready_reg <= 1'b0; + input_1_axis_tready_reg <= 1'b0; + input_2_axis_tready_reg <= 1'b0; + input_3_axis_tready_reg <= 1'b0; + end else begin + input_0_request_reg <= input_0_request_next; + input_0_request_valid_reg <= input_0_request_valid_next; + input_0_request_error_reg <= input_0_request_error_next; + input_1_request_reg <= input_1_request_next; + input_1_request_valid_reg <= input_1_request_valid_next; + input_1_request_error_reg <= input_1_request_error_next; + input_2_request_reg <= input_2_request_next; + input_2_request_valid_reg <= input_2_request_valid_next; + input_2_request_error_reg <= input_2_request_error_next; + input_3_request_reg <= input_3_request_next; + input_3_request_valid_reg <= input_3_request_valid_next; + input_3_request_error_reg <= input_3_request_error_next; + select_0_reg <= select_0_next; + select_1_reg <= select_1_next; + select_2_reg <= select_2_next; + select_3_reg <= select_3_next; + enable_0_reg <= enable_0_next; + enable_1_reg <= enable_1_next; + enable_2_reg <= enable_2_next; + enable_3_reg <= enable_3_next; + input_0_axis_tready_reg <= input_0_axis_tready_next; + input_1_axis_tready_reg <= input_1_axis_tready_next; + input_2_axis_tready_reg <= input_2_axis_tready_next; + input_3_axis_tready_reg <= input_3_axis_tready_next; + end +end + +// output 0 datapath logic +reg [DATA_WIDTH-1:0] output_0_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] output_0_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg output_0_axis_tvalid_reg = 1'b0, output_0_axis_tvalid_next; +reg output_0_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_0_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_0_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_0_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] temp_0_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg temp_0_axis_tvalid_reg = 1'b0, temp_0_axis_tvalid_next; +reg temp_0_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_0_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_0_axis_tuser_reg = 1'b0; + +// datapath control +reg store_0_axis_int_to_output; +reg store_0_axis_int_to_temp; +reg store_0_axis_temp_to_output; + +assign output_0_axis_tdata = output_0_axis_tdata_reg; +assign output_0_axis_tkeep = output_0_axis_tkeep_reg; +assign output_0_axis_tvalid = output_0_axis_tvalid_reg; +assign output_0_axis_tlast = output_0_axis_tlast_reg; +assign output_0_axis_tdest = output_0_axis_tdest_reg; +assign output_0_axis_tuser = output_0_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_0_axis_tready_int_early = output_0_axis_tready | (~temp_0_axis_tvalid_reg & (~output_0_axis_tvalid_reg | ~output_0_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_0_axis_tvalid_next = output_0_axis_tvalid_reg; + temp_0_axis_tvalid_next = temp_0_axis_tvalid_reg; + + store_0_axis_int_to_output = 1'b0; + store_0_axis_int_to_temp = 1'b0; + store_0_axis_temp_to_output = 1'b0; + + if (output_0_axis_tready_int_reg) begin + // input is ready + if (output_0_axis_tready | ~output_0_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_0_axis_tvalid_next = output_0_axis_tvalid_int; + store_0_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_0_axis_tvalid_next = output_0_axis_tvalid_int; + store_0_axis_int_to_temp = 1'b1; + end + end else if (output_0_axis_tready) begin + // input is not ready, but output is ready + output_0_axis_tvalid_next = temp_0_axis_tvalid_reg; + temp_0_axis_tvalid_next = 1'b0; + store_0_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_0_axis_tvalid_reg <= 1'b0; + output_0_axis_tready_int_reg <= 1'b0; + temp_0_axis_tvalid_reg <= 1'b0; + end else begin + output_0_axis_tvalid_reg <= output_0_axis_tvalid_next; + output_0_axis_tready_int_reg <= output_0_axis_tready_int_early; + temp_0_axis_tvalid_reg <= temp_0_axis_tvalid_next; + end + + // datapath + if (store_0_axis_int_to_output) begin + output_0_axis_tdata_reg <= output_0_axis_tdata_int; + output_0_axis_tkeep_reg <= output_0_axis_tkeep_int; + output_0_axis_tlast_reg <= output_0_axis_tlast_int; + output_0_axis_tdest_reg <= output_0_axis_tdest_int; + output_0_axis_tuser_reg <= output_0_axis_tuser_int; + end else if (store_0_axis_temp_to_output) begin + output_0_axis_tdata_reg <= temp_0_axis_tdata_reg; + output_0_axis_tkeep_reg <= temp_0_axis_tkeep_reg; + output_0_axis_tlast_reg <= temp_0_axis_tlast_reg; + output_0_axis_tdest_reg <= temp_0_axis_tdest_reg; + output_0_axis_tuser_reg <= temp_0_axis_tuser_reg; + end + + if (store_0_axis_int_to_temp) begin + temp_0_axis_tdata_reg <= output_0_axis_tdata_int; + temp_0_axis_tkeep_reg <= output_0_axis_tkeep_int; + temp_0_axis_tlast_reg <= output_0_axis_tlast_int; + temp_0_axis_tdest_reg <= output_0_axis_tdest_int; + temp_0_axis_tuser_reg <= output_0_axis_tuser_int; + end +end + +// output 1 datapath logic +reg [DATA_WIDTH-1:0] output_1_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] output_1_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg output_1_axis_tvalid_reg = 1'b0, output_1_axis_tvalid_next; +reg output_1_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_1_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_1_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_1_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] temp_1_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg temp_1_axis_tvalid_reg = 1'b0, temp_1_axis_tvalid_next; +reg temp_1_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_1_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_1_axis_tuser_reg = 1'b0; + +// datapath control +reg store_1_axis_int_to_output; +reg store_1_axis_int_to_temp; +reg store_1_axis_temp_to_output; + +assign output_1_axis_tdata = output_1_axis_tdata_reg; +assign output_1_axis_tkeep = output_1_axis_tkeep_reg; +assign output_1_axis_tvalid = output_1_axis_tvalid_reg; +assign output_1_axis_tlast = output_1_axis_tlast_reg; +assign output_1_axis_tdest = output_1_axis_tdest_reg; +assign output_1_axis_tuser = output_1_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_1_axis_tready_int_early = output_1_axis_tready | (~temp_1_axis_tvalid_reg & (~output_1_axis_tvalid_reg | ~output_1_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_1_axis_tvalid_next = output_1_axis_tvalid_reg; + temp_1_axis_tvalid_next = temp_1_axis_tvalid_reg; + + store_1_axis_int_to_output = 1'b0; + store_1_axis_int_to_temp = 1'b0; + store_1_axis_temp_to_output = 1'b0; + + if (output_1_axis_tready_int_reg) begin + // input is ready + if (output_1_axis_tready | ~output_1_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_1_axis_tvalid_next = output_1_axis_tvalid_int; + store_1_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_1_axis_tvalid_next = output_1_axis_tvalid_int; + store_1_axis_int_to_temp = 1'b1; + end + end else if (output_1_axis_tready) begin + // input is not ready, but output is ready + output_1_axis_tvalid_next = temp_1_axis_tvalid_reg; + temp_1_axis_tvalid_next = 1'b0; + store_1_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_1_axis_tvalid_reg <= 1'b0; + output_1_axis_tready_int_reg <= 1'b0; + temp_1_axis_tvalid_reg <= 1'b0; + end else begin + output_1_axis_tvalid_reg <= output_1_axis_tvalid_next; + output_1_axis_tready_int_reg <= output_1_axis_tready_int_early; + temp_1_axis_tvalid_reg <= temp_1_axis_tvalid_next; + end + + // datapath + if (store_1_axis_int_to_output) begin + output_1_axis_tdata_reg <= output_1_axis_tdata_int; + output_1_axis_tkeep_reg <= output_1_axis_tkeep_int; + output_1_axis_tlast_reg <= output_1_axis_tlast_int; + output_1_axis_tdest_reg <= output_1_axis_tdest_int; + output_1_axis_tuser_reg <= output_1_axis_tuser_int; + end else if (store_1_axis_temp_to_output) begin + output_1_axis_tdata_reg <= temp_1_axis_tdata_reg; + output_1_axis_tkeep_reg <= temp_1_axis_tkeep_reg; + output_1_axis_tlast_reg <= temp_1_axis_tlast_reg; + output_1_axis_tdest_reg <= temp_1_axis_tdest_reg; + output_1_axis_tuser_reg <= temp_1_axis_tuser_reg; + end + + if (store_1_axis_int_to_temp) begin + temp_1_axis_tdata_reg <= output_1_axis_tdata_int; + temp_1_axis_tkeep_reg <= output_1_axis_tkeep_int; + temp_1_axis_tlast_reg <= output_1_axis_tlast_int; + temp_1_axis_tdest_reg <= output_1_axis_tdest_int; + temp_1_axis_tuser_reg <= output_1_axis_tuser_int; + end +end + +// output 2 datapath logic +reg [DATA_WIDTH-1:0] output_2_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] output_2_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg output_2_axis_tvalid_reg = 1'b0, output_2_axis_tvalid_next; +reg output_2_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_2_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_2_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_2_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] temp_2_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg temp_2_axis_tvalid_reg = 1'b0, temp_2_axis_tvalid_next; +reg temp_2_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_2_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_2_axis_tuser_reg = 1'b0; + +// datapath control +reg store_2_axis_int_to_output; +reg store_2_axis_int_to_temp; +reg store_2_axis_temp_to_output; + +assign output_2_axis_tdata = output_2_axis_tdata_reg; +assign output_2_axis_tkeep = output_2_axis_tkeep_reg; +assign output_2_axis_tvalid = output_2_axis_tvalid_reg; +assign output_2_axis_tlast = output_2_axis_tlast_reg; +assign output_2_axis_tdest = output_2_axis_tdest_reg; +assign output_2_axis_tuser = output_2_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_2_axis_tready_int_early = output_2_axis_tready | (~temp_2_axis_tvalid_reg & (~output_2_axis_tvalid_reg | ~output_2_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_2_axis_tvalid_next = output_2_axis_tvalid_reg; + temp_2_axis_tvalid_next = temp_2_axis_tvalid_reg; + + store_2_axis_int_to_output = 1'b0; + store_2_axis_int_to_temp = 1'b0; + store_2_axis_temp_to_output = 1'b0; + + if (output_2_axis_tready_int_reg) begin + // input is ready + if (output_2_axis_tready | ~output_2_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_2_axis_tvalid_next = output_2_axis_tvalid_int; + store_2_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_2_axis_tvalid_next = output_2_axis_tvalid_int; + store_2_axis_int_to_temp = 1'b1; + end + end else if (output_2_axis_tready) begin + // input is not ready, but output is ready + output_2_axis_tvalid_next = temp_2_axis_tvalid_reg; + temp_2_axis_tvalid_next = 1'b0; + store_2_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_2_axis_tvalid_reg <= 1'b0; + output_2_axis_tready_int_reg <= 1'b0; + temp_2_axis_tvalid_reg <= 1'b0; + end else begin + output_2_axis_tvalid_reg <= output_2_axis_tvalid_next; + output_2_axis_tready_int_reg <= output_2_axis_tready_int_early; + temp_2_axis_tvalid_reg <= temp_2_axis_tvalid_next; + end + + // datapath + if (store_2_axis_int_to_output) begin + output_2_axis_tdata_reg <= output_2_axis_tdata_int; + output_2_axis_tkeep_reg <= output_2_axis_tkeep_int; + output_2_axis_tlast_reg <= output_2_axis_tlast_int; + output_2_axis_tdest_reg <= output_2_axis_tdest_int; + output_2_axis_tuser_reg <= output_2_axis_tuser_int; + end else if (store_2_axis_temp_to_output) begin + output_2_axis_tdata_reg <= temp_2_axis_tdata_reg; + output_2_axis_tkeep_reg <= temp_2_axis_tkeep_reg; + output_2_axis_tlast_reg <= temp_2_axis_tlast_reg; + output_2_axis_tdest_reg <= temp_2_axis_tdest_reg; + output_2_axis_tuser_reg <= temp_2_axis_tuser_reg; + end + + if (store_2_axis_int_to_temp) begin + temp_2_axis_tdata_reg <= output_2_axis_tdata_int; + temp_2_axis_tkeep_reg <= output_2_axis_tkeep_int; + temp_2_axis_tlast_reg <= output_2_axis_tlast_int; + temp_2_axis_tdest_reg <= output_2_axis_tdest_int; + temp_2_axis_tuser_reg <= output_2_axis_tuser_int; + end +end + +// output 3 datapath logic +reg [DATA_WIDTH-1:0] output_3_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] output_3_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg output_3_axis_tvalid_reg = 1'b0, output_3_axis_tvalid_next; +reg output_3_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] output_3_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg output_3_axis_tuser_reg = 1'b0; + +reg [DATA_WIDTH-1:0] temp_3_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] temp_3_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg temp_3_axis_tvalid_reg = 1'b0, temp_3_axis_tvalid_next; +reg temp_3_axis_tlast_reg = 1'b0; +reg [DEST_WIDTH-1:0] temp_3_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg temp_3_axis_tuser_reg = 1'b0; + +// datapath control +reg store_3_axis_int_to_output; +reg store_3_axis_int_to_temp; +reg store_3_axis_temp_to_output; + +assign output_3_axis_tdata = output_3_axis_tdata_reg; +assign output_3_axis_tkeep = output_3_axis_tkeep_reg; +assign output_3_axis_tvalid = output_3_axis_tvalid_reg; +assign output_3_axis_tlast = output_3_axis_tlast_reg; +assign output_3_axis_tdest = output_3_axis_tdest_reg; +assign output_3_axis_tuser = output_3_axis_tuser_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign output_3_axis_tready_int_early = output_3_axis_tready | (~temp_3_axis_tvalid_reg & (~output_3_axis_tvalid_reg | ~output_3_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + output_3_axis_tvalid_next = output_3_axis_tvalid_reg; + temp_3_axis_tvalid_next = temp_3_axis_tvalid_reg; + + store_3_axis_int_to_output = 1'b0; + store_3_axis_int_to_temp = 1'b0; + store_3_axis_temp_to_output = 1'b0; + + if (output_3_axis_tready_int_reg) begin + // input is ready + if (output_3_axis_tready | ~output_3_axis_tvalid_reg) begin + // output is ready or currently not valid, transfer data to output + output_3_axis_tvalid_next = output_3_axis_tvalid_int; + store_3_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_3_axis_tvalid_next = output_3_axis_tvalid_int; + store_3_axis_int_to_temp = 1'b1; + end + end else if (output_3_axis_tready) begin + // input is not ready, but output is ready + output_3_axis_tvalid_next = temp_3_axis_tvalid_reg; + temp_3_axis_tvalid_next = 1'b0; + store_3_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + output_3_axis_tvalid_reg <= 1'b0; + output_3_axis_tready_int_reg <= 1'b0; + temp_3_axis_tvalid_reg <= 1'b0; + end else begin + output_3_axis_tvalid_reg <= output_3_axis_tvalid_next; + output_3_axis_tready_int_reg <= output_3_axis_tready_int_early; + temp_3_axis_tvalid_reg <= temp_3_axis_tvalid_next; + end + + // datapath + if (store_3_axis_int_to_output) begin + output_3_axis_tdata_reg <= output_3_axis_tdata_int; + output_3_axis_tkeep_reg <= output_3_axis_tkeep_int; + output_3_axis_tlast_reg <= output_3_axis_tlast_int; + output_3_axis_tdest_reg <= output_3_axis_tdest_int; + output_3_axis_tuser_reg <= output_3_axis_tuser_int; + end else if (store_3_axis_temp_to_output) begin + output_3_axis_tdata_reg <= temp_3_axis_tdata_reg; + output_3_axis_tkeep_reg <= temp_3_axis_tkeep_reg; + output_3_axis_tlast_reg <= temp_3_axis_tlast_reg; + output_3_axis_tdest_reg <= temp_3_axis_tdest_reg; + output_3_axis_tuser_reg <= temp_3_axis_tuser_reg; + end + + if (store_3_axis_int_to_temp) begin + temp_3_axis_tdata_reg <= output_3_axis_tdata_int; + temp_3_axis_tkeep_reg <= output_3_axis_tkeep_int; + temp_3_axis_tlast_reg <= output_3_axis_tlast_int; + temp_3_axis_tdest_reg <= output_3_axis_tdest_int; + temp_3_axis_tuser_reg <= output_3_axis_tuser_int; + end +end + +endmodule diff --git a/tb/test_axis_switch_4x4.py b/tb/test_axis_switch_4x4.py new file mode 100755 index 00000000..8d2d9dce --- /dev/null +++ b/tb/test_axis_switch_4x4.py @@ -0,0 +1,682 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from myhdl import * +import os + +try: + from queue import Queue +except ImportError: + from Queue import Queue + +import axis_ep + +module = 'axis_switch_4x4' +testbench = 'test_axis_switch_4x4' + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/arbiter.v") +srcs.append("../rtl/priority_encoder.v") +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def dut_axis_switch_4x4(clk, + rst, + current_test, + + input_0_axis_tdata, + input_0_axis_tvalid, + input_0_axis_tready, + input_0_axis_tlast, + input_0_axis_tdest, + input_0_axis_tuser, + input_1_axis_tdata, + input_1_axis_tvalid, + input_1_axis_tready, + input_1_axis_tlast, + input_1_axis_tdest, + input_1_axis_tuser, + input_2_axis_tdata, + input_2_axis_tvalid, + input_2_axis_tready, + input_2_axis_tlast, + input_2_axis_tdest, + input_2_axis_tuser, + input_3_axis_tdata, + input_3_axis_tvalid, + input_3_axis_tready, + input_3_axis_tlast, + input_3_axis_tdest, + input_3_axis_tuser, + + output_0_axis_tdata, + output_0_axis_tvalid, + output_0_axis_tready, + output_0_axis_tlast, + output_0_axis_tdest, + output_0_axis_tuser, + output_1_axis_tdata, + output_1_axis_tvalid, + output_1_axis_tready, + output_1_axis_tlast, + output_1_axis_tdest, + output_1_axis_tuser, + output_2_axis_tdata, + output_2_axis_tvalid, + output_2_axis_tready, + output_2_axis_tlast, + output_2_axis_tdest, + output_2_axis_tuser, + output_3_axis_tdata, + output_3_axis_tvalid, + output_3_axis_tready, + output_3_axis_tlast, + output_3_axis_tdest, + output_3_axis_tuser): + + if os.system(build_cmd): + raise Exception("Error running build command") + return Cosimulation("vvp -m myhdl %s.vvp -lxt2" % testbench, + clk=clk, + rst=rst, + current_test=current_test, + + input_0_axis_tdata=input_0_axis_tdata, + input_0_axis_tvalid=input_0_axis_tvalid, + input_0_axis_tready=input_0_axis_tready, + input_0_axis_tlast=input_0_axis_tlast, + input_0_axis_tdest=input_0_axis_tdest, + input_0_axis_tuser=input_0_axis_tuser, + input_1_axis_tdata=input_1_axis_tdata, + input_1_axis_tvalid=input_1_axis_tvalid, + input_1_axis_tready=input_1_axis_tready, + input_1_axis_tlast=input_1_axis_tlast, + input_1_axis_tdest=input_1_axis_tdest, + input_1_axis_tuser=input_1_axis_tuser, + input_2_axis_tdata=input_2_axis_tdata, + input_2_axis_tvalid=input_2_axis_tvalid, + input_2_axis_tready=input_2_axis_tready, + input_2_axis_tlast=input_2_axis_tlast, + input_2_axis_tdest=input_2_axis_tdest, + input_2_axis_tuser=input_2_axis_tuser, + input_3_axis_tdata=input_3_axis_tdata, + input_3_axis_tvalid=input_3_axis_tvalid, + input_3_axis_tready=input_3_axis_tready, + input_3_axis_tlast=input_3_axis_tlast, + input_3_axis_tdest=input_3_axis_tdest, + input_3_axis_tuser=input_3_axis_tuser, + + output_0_axis_tdata=output_0_axis_tdata, + output_0_axis_tvalid=output_0_axis_tvalid, + output_0_axis_tready=output_0_axis_tready, + output_0_axis_tlast=output_0_axis_tlast, + output_0_axis_tdest=output_0_axis_tdest, + output_0_axis_tuser=output_0_axis_tuser, + output_1_axis_tdata=output_1_axis_tdata, + output_1_axis_tvalid=output_1_axis_tvalid, + output_1_axis_tready=output_1_axis_tready, + output_1_axis_tlast=output_1_axis_tlast, + output_1_axis_tdest=output_1_axis_tdest, + output_1_axis_tuser=output_1_axis_tuser, + output_2_axis_tdata=output_2_axis_tdata, + output_2_axis_tvalid=output_2_axis_tvalid, + output_2_axis_tready=output_2_axis_tready, + output_2_axis_tlast=output_2_axis_tlast, + output_2_axis_tdest=output_2_axis_tdest, + output_2_axis_tuser=output_2_axis_tuser, + output_3_axis_tdata=output_3_axis_tdata, + output_3_axis_tvalid=output_3_axis_tvalid, + output_3_axis_tready=output_3_axis_tready, + output_3_axis_tlast=output_3_axis_tlast, + output_3_axis_tdest=output_3_axis_tdest, + output_3_axis_tuser=output_3_axis_tuser) + +def bench(): + + # Parameters + DATA_WIDTH = 8 + DEST_WIDTH = 3 + OUT_0_BASE = 0 + OUT_0_TOP = 0 + OUT_0_CONNECT = 0xf + OUT_1_BASE = 1 + OUT_1_TOP = 1 + OUT_1_CONNECT = 0xf + OUT_2_BASE = 2 + OUT_2_TOP = 2 + OUT_2_CONNECT = 0xf + OUT_3_BASE = 3 + OUT_3_TOP = 3 + OUT_3_CONNECT = 0xf + ARB_TYPE = "ROUND_ROBIN" + LSB_PRIORITY = "HIGH" + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + input_0_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_0_axis_tvalid = Signal(bool(0)) + input_0_axis_tlast = Signal(bool(0)) + input_0_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_0_axis_tuser = Signal(bool(0)) + input_1_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_1_axis_tvalid = Signal(bool(0)) + input_1_axis_tlast = Signal(bool(0)) + input_1_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_1_axis_tuser = Signal(bool(0)) + input_2_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_2_axis_tvalid = Signal(bool(0)) + input_2_axis_tlast = Signal(bool(0)) + input_2_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_2_axis_tuser = Signal(bool(0)) + input_3_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_3_axis_tvalid = Signal(bool(0)) + input_3_axis_tlast = Signal(bool(0)) + input_3_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_3_axis_tuser = Signal(bool(0)) + output_0_axis_tready = Signal(bool(0)) + output_1_axis_tready = Signal(bool(0)) + output_2_axis_tready = Signal(bool(0)) + output_3_axis_tready = Signal(bool(0)) + + # Outputs + input_0_axis_tready = Signal(bool(0)) + input_1_axis_tready = Signal(bool(0)) + input_2_axis_tready = Signal(bool(0)) + input_3_axis_tready = Signal(bool(0)) + output_0_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_0_axis_tvalid = Signal(bool(0)) + output_0_axis_tlast = Signal(bool(0)) + output_0_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_0_axis_tuser = Signal(bool(0)) + output_1_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_1_axis_tvalid = Signal(bool(0)) + output_1_axis_tlast = Signal(bool(0)) + output_1_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_1_axis_tuser = Signal(bool(0)) + output_2_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_2_axis_tvalid = Signal(bool(0)) + output_2_axis_tlast = Signal(bool(0)) + output_2_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_2_axis_tuser = Signal(bool(0)) + output_3_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_3_axis_tvalid = Signal(bool(0)) + output_3_axis_tlast = Signal(bool(0)) + output_3_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_3_axis_tuser = Signal(bool(0)) + + # sources and sinks + source_0_queue = Queue() + source_0_pause = Signal(bool(0)) + source_1_queue = Queue() + source_1_pause = Signal(bool(0)) + source_2_queue = Queue() + source_2_pause = Signal(bool(0)) + source_3_queue = Queue() + source_3_pause = Signal(bool(0)) + sink_0_queue = Queue() + sink_0_pause = Signal(bool(0)) + sink_1_queue = Queue() + sink_1_pause = Signal(bool(0)) + sink_2_queue = Queue() + sink_2_pause = Signal(bool(0)) + sink_3_queue = Queue() + sink_3_pause = Signal(bool(0)) + + source_0 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_0_axis_tdata, + tvalid=input_0_axis_tvalid, + tready=input_0_axis_tready, + tlast=input_0_axis_tlast, + tdest=input_0_axis_tdest, + tuser=input_0_axis_tuser, + fifo=source_0_queue, + pause=source_0_pause, + name='source0') + source_1 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_1_axis_tdata, + tvalid=input_1_axis_tvalid, + tready=input_1_axis_tready, + tlast=input_1_axis_tlast, + tdest=input_1_axis_tdest, + tuser=input_1_axis_tuser, + fifo=source_1_queue, + pause=source_1_pause, + name='source1') + source_2 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_2_axis_tdata, + tvalid=input_2_axis_tvalid, + tready=input_2_axis_tready, + tlast=input_2_axis_tlast, + tdest=input_2_axis_tdest, + tuser=input_2_axis_tuser, + fifo=source_2_queue, + pause=source_2_pause, + name='source2') + source_3 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_3_axis_tdata, + tvalid=input_3_axis_tvalid, + tready=input_3_axis_tready, + tlast=input_3_axis_tlast, + tdest=input_3_axis_tdest, + tuser=input_3_axis_tuser, + fifo=source_3_queue, + pause=source_3_pause, + name='source3') + + sink_0 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_0_axis_tdata, + tvalid=output_0_axis_tvalid, + tready=output_0_axis_tready, + tlast=output_0_axis_tlast, + tdest=output_0_axis_tdest, + tuser=output_0_axis_tuser, + fifo=sink_0_queue, + pause=sink_0_pause, + name='sink0') + sink_1 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_1_axis_tdata, + tvalid=output_1_axis_tvalid, + tready=output_1_axis_tready, + tlast=output_1_axis_tlast, + tdest=output_1_axis_tdest, + tuser=output_1_axis_tuser, + fifo=sink_1_queue, + pause=sink_1_pause, + name='sink1') + sink_2 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_2_axis_tdata, + tvalid=output_2_axis_tvalid, + tready=output_2_axis_tready, + tlast=output_2_axis_tlast, + tdest=output_2_axis_tdest, + tuser=output_2_axis_tuser, + fifo=sink_2_queue, + pause=sink_2_pause, + name='sink2') + sink_3 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_3_axis_tdata, + tvalid=output_3_axis_tvalid, + tready=output_3_axis_tready, + tlast=output_3_axis_tlast, + tdest=output_3_axis_tdest, + tuser=output_3_axis_tuser, + fifo=sink_3_queue, + pause=sink_3_pause, + name='sink3') + + # DUT + dut = dut_axis_switch_4x4(clk, + rst, + current_test, + input_0_axis_tdata, + input_0_axis_tvalid, + input_0_axis_tready, + input_0_axis_tlast, + input_0_axis_tdest, + input_0_axis_tuser, + input_1_axis_tdata, + input_1_axis_tvalid, + input_1_axis_tready, + input_1_axis_tlast, + input_1_axis_tdest, + input_1_axis_tuser, + input_2_axis_tdata, + input_2_axis_tvalid, + input_2_axis_tready, + input_2_axis_tlast, + input_2_axis_tdest, + input_2_axis_tuser, + input_3_axis_tdata, + input_3_axis_tvalid, + input_3_axis_tready, + input_3_axis_tlast, + input_3_axis_tdest, + input_3_axis_tuser, + output_0_axis_tdata, + output_0_axis_tvalid, + output_0_axis_tready, + output_0_axis_tlast, + output_0_axis_tdest, + output_0_axis_tuser, + output_1_axis_tdata, + output_1_axis_tvalid, + output_1_axis_tready, + output_1_axis_tlast, + output_1_axis_tdest, + output_1_axis_tuser, + output_2_axis_tdata, + output_2_axis_tvalid, + output_2_axis_tready, + output_2_axis_tlast, + output_2_axis_tdest, + output_2_axis_tuser, + output_3_axis_tdata, + output_3_axis_tvalid, + output_3_axis_tready, + output_3_axis_tlast, + output_3_axis_tdest, + output_3_axis_tuser) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + def wait_normal(): + while input_0_axis_tvalid or input_1_axis_tvalid or input_2_axis_tvalid or input_3_axis_tvalid: + yield clk.posedge + + def wait_pause_source(): + while input_0_axis_tvalid or input_1_axis_tvalid or input_2_axis_tvalid or input_3_axis_tvalid: + source_0_pause.next = True + source_1_pause.next = True + source_2_pause.next = True + source_3_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + source_0_pause.next = False + source_1_pause.next = False + source_2_pause.next = False + source_3_pause.next = False + yield clk.posedge + + def wait_pause_sink(): + while input_0_axis_tvalid or input_1_axis_tvalid or input_2_axis_tvalid or input_3_axis_tvalid: + sink_0_pause.next = True + sink_1_pause.next = True + sink_2_pause.next = True + sink_3_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + sink_0_pause.next = False + sink_1_pause.next = False + sink_2_pause.next = False + sink_3_pause.next = False + yield clk.posedge + + @instance + def check(): + yield delay(100) + yield clk.posedge + rst.next = 1 + yield clk.posedge + rst.next = 0 + yield clk.posedge + yield delay(100) + yield clk.posedge + + # testbench stimulus + + yield clk.posedge + print("test 1: 0123 -> 0123") + current_test.next = 1 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x01\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x01\x01\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame2 = axis_ep.AXIStreamFrame(b'\x01\x02\x02\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=2) + test_frame3 = axis_ep.AXIStreamFrame(b'\x01\x03\x03\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=3) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame1 + + rx_frame2 = None + if not sink_2_queue.empty(): + rx_frame2 = sink_2_queue.get() + + assert rx_frame2 == test_frame2 + + rx_frame3 = None + if not sink_3_queue.empty(): + rx_frame3 = sink_3_queue.get() + + assert rx_frame3 == test_frame3 + + yield delay(100) + + yield clk.posedge + print("test 2: 0123 -> 3210") + current_test.next = 2 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x02\x00\x03\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=3) + test_frame1 = axis_ep.AXIStreamFrame(b'\x02\x01\x02\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=2) + test_frame2 = axis_ep.AXIStreamFrame(b'\x02\x02\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame3 = axis_ep.AXIStreamFrame(b'\x02\x03\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame3 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame2 + + rx_frame2 = None + if not sink_2_queue.empty(): + rx_frame2 = sink_2_queue.get() + + assert rx_frame2 == test_frame1 + + rx_frame3 = None + if not sink_3_queue.empty(): + rx_frame3 = sink_3_queue.get() + + assert rx_frame3 == test_frame0 + + yield delay(100) + + yield clk.posedge + print("test 3: 0000 -> 0123") + current_test.next = 3 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x02\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x02\x00\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame2 = axis_ep.AXIStreamFrame(b'\x02\x00\x02\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=2) + test_frame3 = axis_ep.AXIStreamFrame(b'\x02\x00\x03\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=3) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_0_queue.put(test_frame1) + source_0_queue.put(test_frame2) + source_0_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame1 + + rx_frame2 = None + if not sink_2_queue.empty(): + rx_frame2 = sink_2_queue.get() + + assert rx_frame2 == test_frame2 + + rx_frame3 = None + if not sink_3_queue.empty(): + rx_frame3 = sink_3_queue.get() + + assert rx_frame3 == test_frame3 + + yield delay(100) + + yield clk.posedge + print("test 4: 0123 -> 0000") + current_test.next = 4 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x02\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x02\x01\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame2 = axis_ep.AXIStreamFrame(b'\x02\x02\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame3 = axis_ep.AXIStreamFrame(b'\x02\x03\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + yield clk.posedge + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_0_queue.empty(): + rx_frame1 = sink_0_queue.get() + + assert rx_frame1 == test_frame1 + + rx_frame2 = None + if not sink_0_queue.empty(): + rx_frame2 = sink_0_queue.get() + + assert rx_frame2 == test_frame2 + + rx_frame3 = None + if not sink_0_queue.empty(): + rx_frame3 = sink_0_queue.get() + + assert rx_frame3 == test_frame3 + + yield delay(100) + + yield clk.posedge + print("test 1: bad decoding") + current_test.next = 1 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x01\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x01\x01\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame2 = axis_ep.AXIStreamFrame(b'\x01\x02\x04\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=4) + test_frame3 = axis_ep.AXIStreamFrame(b'\x01\x03\x05\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=5) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame1 + + yield delay(100) + + raise StopSimulation + + return dut, source_0, source_1, source_2, source_3, sink_0, sink_1, sink_2, sink_3, clkgen, check + +def test_bench(): + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() diff --git a/tb/test_axis_switch_4x4.v b/tb/test_axis_switch_4x4.v new file mode 100644 index 00000000..0f3fb62b --- /dev/null +++ b/tb/test_axis_switch_4x4.v @@ -0,0 +1,240 @@ +/* + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Testbench for axis_switch_4x4 + */ +module test_axis_switch_4x4; + +// Parameters +parameter DATA_WIDTH = 8; +parameter DEST_WIDTH = 3; +parameter OUT_0_BASE = 0; +parameter OUT_0_TOP = 0; +parameter OUT_0_CONNECT = 4'b1111; +parameter OUT_1_BASE = 1; +parameter OUT_1_TOP = 1; +parameter OUT_1_CONNECT = 4'b1111; +parameter OUT_2_BASE = 2; +parameter OUT_2_TOP = 2; +parameter OUT_2_CONNECT = 4'b1111; +parameter OUT_3_BASE = 3; +parameter OUT_3_TOP = 3; +parameter OUT_3_CONNECT = 4'b1111; +parameter ARB_TYPE = "ROUND_ROBIN"; +parameter LSB_PRIORITY = "HIGH"; + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [DATA_WIDTH-1:0] input_0_axis_tdata = 0; +reg input_0_axis_tvalid = 0; +reg input_0_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_0_axis_tdest = 0; +reg input_0_axis_tuser = 0; +reg [DATA_WIDTH-1:0] input_1_axis_tdata = 0; +reg input_1_axis_tvalid = 0; +reg input_1_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_1_axis_tdest = 0; +reg input_1_axis_tuser = 0; +reg [DATA_WIDTH-1:0] input_2_axis_tdata = 0; +reg input_2_axis_tvalid = 0; +reg input_2_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_2_axis_tdest = 0; +reg input_2_axis_tuser = 0; +reg [DATA_WIDTH-1:0] input_3_axis_tdata = 0; +reg input_3_axis_tvalid = 0; +reg input_3_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_3_axis_tdest = 0; +reg input_3_axis_tuser = 0; +reg output_0_axis_tready = 0; +reg output_1_axis_tready = 0; +reg output_2_axis_tready = 0; +reg output_3_axis_tready = 0; + +// Outputs +wire input_0_axis_tready; +wire input_1_axis_tready; +wire input_2_axis_tready; +wire input_3_axis_tready; +wire [DATA_WIDTH-1:0] output_0_axis_tdata; +wire output_0_axis_tvalid; +wire output_0_axis_tlast; +wire [DEST_WIDTH-1:0] output_0_axis_tdest; +wire output_0_axis_tuser; +wire [DATA_WIDTH-1:0] output_1_axis_tdata; +wire output_1_axis_tvalid; +wire output_1_axis_tlast; +wire [DEST_WIDTH-1:0] output_1_axis_tdest; +wire output_1_axis_tuser; +wire [DATA_WIDTH-1:0] output_2_axis_tdata; +wire output_2_axis_tvalid; +wire output_2_axis_tlast; +wire [DEST_WIDTH-1:0] output_2_axis_tdest; +wire output_2_axis_tuser; +wire [DATA_WIDTH-1:0] output_3_axis_tdata; +wire output_3_axis_tvalid; +wire output_3_axis_tlast; +wire [DEST_WIDTH-1:0] output_3_axis_tdest; +wire output_3_axis_tuser; + +initial begin + // myhdl integration + $from_myhdl(clk, + rst, + current_test, + input_0_axis_tdata, + input_0_axis_tvalid, + input_0_axis_tlast, + input_0_axis_tdest, + input_0_axis_tuser, + input_1_axis_tdata, + input_1_axis_tvalid, + input_1_axis_tlast, + input_1_axis_tdest, + input_1_axis_tuser, + input_2_axis_tdata, + input_2_axis_tvalid, + input_2_axis_tlast, + input_2_axis_tdest, + input_2_axis_tuser, + input_3_axis_tdata, + input_3_axis_tvalid, + input_3_axis_tlast, + input_3_axis_tdest, + input_3_axis_tuser, + output_0_axis_tready, + output_1_axis_tready, + output_2_axis_tready, + output_3_axis_tready); + $to_myhdl(input_0_axis_tready, + input_1_axis_tready, + input_2_axis_tready, + input_3_axis_tready, + output_0_axis_tdata, + output_0_axis_tvalid, + output_0_axis_tlast, + output_0_axis_tdest, + output_0_axis_tuser, + output_1_axis_tdata, + output_1_axis_tvalid, + output_1_axis_tlast, + output_1_axis_tdest, + output_1_axis_tuser, + output_2_axis_tdata, + output_2_axis_tvalid, + output_2_axis_tlast, + output_2_axis_tdest, + output_2_axis_tuser, + output_3_axis_tdata, + output_3_axis_tvalid, + output_3_axis_tlast, + output_3_axis_tdest, + output_3_axis_tuser); + + // dump file + $dumpfile("test_axis_switch_4x4.lxt"); + $dumpvars(0, test_axis_switch_4x4); +end + +axis_switch_4x4 #( + .DATA_WIDTH(DATA_WIDTH), + .DEST_WIDTH(DEST_WIDTH), + .OUT_0_BASE(OUT_0_BASE), + .OUT_0_TOP(OUT_0_TOP), + .OUT_0_CONNECT(OUT_0_CONNECT), + .OUT_1_BASE(OUT_1_BASE), + .OUT_1_TOP(OUT_1_TOP), + .OUT_1_CONNECT(OUT_1_CONNECT), + .OUT_2_BASE(OUT_2_BASE), + .OUT_2_TOP(OUT_2_TOP), + .OUT_2_CONNECT(OUT_2_CONNECT), + .OUT_3_BASE(OUT_3_BASE), + .OUT_3_TOP(OUT_3_TOP), + .OUT_3_CONNECT(OUT_3_CONNECT), + .ARB_TYPE(ARB_TYPE), + .LSB_PRIORITY(LSB_PRIORITY) +) +UUT ( + .clk(clk), + .rst(rst), + // AXI inputs + .input_0_axis_tdata(input_0_axis_tdata), + .input_0_axis_tvalid(input_0_axis_tvalid), + .input_0_axis_tready(input_0_axis_tready), + .input_0_axis_tlast(input_0_axis_tlast), + .input_0_axis_tdest(input_0_axis_tdest), + .input_0_axis_tuser(input_0_axis_tuser), + .input_1_axis_tdata(input_1_axis_tdata), + .input_1_axis_tvalid(input_1_axis_tvalid), + .input_1_axis_tready(input_1_axis_tready), + .input_1_axis_tlast(input_1_axis_tlast), + .input_1_axis_tdest(input_1_axis_tdest), + .input_1_axis_tuser(input_1_axis_tuser), + .input_2_axis_tdata(input_2_axis_tdata), + .input_2_axis_tvalid(input_2_axis_tvalid), + .input_2_axis_tready(input_2_axis_tready), + .input_2_axis_tlast(input_2_axis_tlast), + .input_2_axis_tdest(input_2_axis_tdest), + .input_2_axis_tuser(input_2_axis_tuser), + .input_3_axis_tdata(input_3_axis_tdata), + .input_3_axis_tvalid(input_3_axis_tvalid), + .input_3_axis_tready(input_3_axis_tready), + .input_3_axis_tlast(input_3_axis_tlast), + .input_3_axis_tdest(input_3_axis_tdest), + .input_3_axis_tuser(input_3_axis_tuser), + // AXI outputs + .output_0_axis_tdata(output_0_axis_tdata), + .output_0_axis_tvalid(output_0_axis_tvalid), + .output_0_axis_tready(output_0_axis_tready), + .output_0_axis_tlast(output_0_axis_tlast), + .output_0_axis_tdest(output_0_axis_tdest), + .output_0_axis_tuser(output_0_axis_tuser), + .output_1_axis_tdata(output_1_axis_tdata), + .output_1_axis_tvalid(output_1_axis_tvalid), + .output_1_axis_tready(output_1_axis_tready), + .output_1_axis_tlast(output_1_axis_tlast), + .output_1_axis_tdest(output_1_axis_tdest), + .output_1_axis_tuser(output_1_axis_tuser), + .output_2_axis_tdata(output_2_axis_tdata), + .output_2_axis_tvalid(output_2_axis_tvalid), + .output_2_axis_tready(output_2_axis_tready), + .output_2_axis_tlast(output_2_axis_tlast), + .output_2_axis_tdest(output_2_axis_tdest), + .output_2_axis_tuser(output_2_axis_tuser), + .output_3_axis_tdata(output_3_axis_tdata), + .output_3_axis_tvalid(output_3_axis_tvalid), + .output_3_axis_tready(output_3_axis_tready), + .output_3_axis_tlast(output_3_axis_tlast), + .output_3_axis_tdest(output_3_axis_tdest), + .output_3_axis_tuser(output_3_axis_tuser) +); + +endmodule diff --git a/tb/test_axis_switch_64_4x4.py b/tb/test_axis_switch_64_4x4.py new file mode 100755 index 00000000..bde87e44 --- /dev/null +++ b/tb/test_axis_switch_64_4x4.py @@ -0,0 +1,723 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from myhdl import * +import os + +try: + from queue import Queue +except ImportError: + from Queue import Queue + +import axis_ep + +module = 'axis_switch_64_4x4' +testbench = 'test_axis_switch_64_4x4' + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/arbiter.v") +srcs.append("../rtl/priority_encoder.v") +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def dut_axis_switch_64_4x4(clk, + rst, + current_test, + + input_0_axis_tdata, + input_0_axis_tkeep, + input_0_axis_tvalid, + input_0_axis_tready, + input_0_axis_tlast, + input_0_axis_tdest, + input_0_axis_tuser, + input_1_axis_tdata, + input_1_axis_tkeep, + input_1_axis_tvalid, + input_1_axis_tready, + input_1_axis_tlast, + input_1_axis_tdest, + input_1_axis_tuser, + input_2_axis_tdata, + input_2_axis_tkeep, + input_2_axis_tvalid, + input_2_axis_tready, + input_2_axis_tlast, + input_2_axis_tdest, + input_2_axis_tuser, + input_3_axis_tdata, + input_3_axis_tkeep, + input_3_axis_tvalid, + input_3_axis_tready, + input_3_axis_tlast, + input_3_axis_tdest, + input_3_axis_tuser, + + output_0_axis_tdata, + output_0_axis_tkeep, + output_0_axis_tvalid, + output_0_axis_tready, + output_0_axis_tlast, + output_0_axis_tdest, + output_0_axis_tuser, + output_1_axis_tdata, + output_1_axis_tkeep, + output_1_axis_tvalid, + output_1_axis_tready, + output_1_axis_tlast, + output_1_axis_tdest, + output_1_axis_tuser, + output_2_axis_tdata, + output_2_axis_tkeep, + output_2_axis_tvalid, + output_2_axis_tready, + output_2_axis_tlast, + output_2_axis_tdest, + output_2_axis_tuser, + output_3_axis_tdata, + output_3_axis_tkeep, + output_3_axis_tvalid, + output_3_axis_tready, + output_3_axis_tlast, + output_3_axis_tdest, + output_3_axis_tuser): + + if os.system(build_cmd): + raise Exception("Error running build command") + return Cosimulation("vvp -m myhdl %s.vvp -lxt2" % testbench, + clk=clk, + rst=rst, + current_test=current_test, + + input_0_axis_tdata=input_0_axis_tdata, + input_0_axis_tkeep=input_0_axis_tkeep, + input_0_axis_tvalid=input_0_axis_tvalid, + input_0_axis_tready=input_0_axis_tready, + input_0_axis_tlast=input_0_axis_tlast, + input_0_axis_tdest=input_0_axis_tdest, + input_0_axis_tuser=input_0_axis_tuser, + input_1_axis_tdata=input_1_axis_tdata, + input_1_axis_tkeep=input_1_axis_tkeep, + input_1_axis_tvalid=input_1_axis_tvalid, + input_1_axis_tready=input_1_axis_tready, + input_1_axis_tlast=input_1_axis_tlast, + input_1_axis_tdest=input_1_axis_tdest, + input_1_axis_tuser=input_1_axis_tuser, + input_2_axis_tdata=input_2_axis_tdata, + input_2_axis_tkeep=input_2_axis_tkeep, + input_2_axis_tvalid=input_2_axis_tvalid, + input_2_axis_tready=input_2_axis_tready, + input_2_axis_tlast=input_2_axis_tlast, + input_2_axis_tdest=input_2_axis_tdest, + input_2_axis_tuser=input_2_axis_tuser, + input_3_axis_tdata=input_3_axis_tdata, + input_3_axis_tkeep=input_3_axis_tkeep, + input_3_axis_tvalid=input_3_axis_tvalid, + input_3_axis_tready=input_3_axis_tready, + input_3_axis_tlast=input_3_axis_tlast, + input_3_axis_tdest=input_3_axis_tdest, + input_3_axis_tuser=input_3_axis_tuser, + + output_0_axis_tdata=output_0_axis_tdata, + output_0_axis_tkeep=output_0_axis_tkeep, + output_0_axis_tvalid=output_0_axis_tvalid, + output_0_axis_tready=output_0_axis_tready, + output_0_axis_tlast=output_0_axis_tlast, + output_0_axis_tdest=output_0_axis_tdest, + output_0_axis_tuser=output_0_axis_tuser, + output_1_axis_tdata=output_1_axis_tdata, + output_1_axis_tkeep=output_1_axis_tkeep, + output_1_axis_tvalid=output_1_axis_tvalid, + output_1_axis_tready=output_1_axis_tready, + output_1_axis_tlast=output_1_axis_tlast, + output_1_axis_tdest=output_1_axis_tdest, + output_1_axis_tuser=output_1_axis_tuser, + output_2_axis_tdata=output_2_axis_tdata, + output_2_axis_tkeep=output_2_axis_tkeep, + output_2_axis_tvalid=output_2_axis_tvalid, + output_2_axis_tready=output_2_axis_tready, + output_2_axis_tlast=output_2_axis_tlast, + output_2_axis_tdest=output_2_axis_tdest, + output_2_axis_tuser=output_2_axis_tuser, + output_3_axis_tdata=output_3_axis_tdata, + output_3_axis_tkeep=output_3_axis_tkeep, + output_3_axis_tvalid=output_3_axis_tvalid, + output_3_axis_tready=output_3_axis_tready, + output_3_axis_tlast=output_3_axis_tlast, + output_3_axis_tdest=output_3_axis_tdest, + output_3_axis_tuser=output_3_axis_tuser) + +def bench(): + + # Parameters + DATA_WIDTH = 64 + KEEP_WIDTH = int(DATA_WIDTH/8) + DEST_WIDTH = 3 + OUT_0_BASE = 0 + OUT_0_TOP = 0 + OUT_0_CONNECT = 0xf + OUT_1_BASE = 1 + OUT_1_TOP = 1 + OUT_1_CONNECT = 0xf + OUT_2_BASE = 2 + OUT_2_TOP = 2 + OUT_2_CONNECT = 0xf + OUT_3_BASE = 3 + OUT_3_TOP = 3 + OUT_3_CONNECT = 0xf + ARB_TYPE = "ROUND_ROBIN" + LSB_PRIORITY = "HIGH" + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + input_0_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_0_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + input_0_axis_tvalid = Signal(bool(0)) + input_0_axis_tlast = Signal(bool(0)) + input_0_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_0_axis_tuser = Signal(bool(0)) + input_1_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_1_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + input_1_axis_tvalid = Signal(bool(0)) + input_1_axis_tlast = Signal(bool(0)) + input_1_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_1_axis_tuser = Signal(bool(0)) + input_2_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_2_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + input_2_axis_tvalid = Signal(bool(0)) + input_2_axis_tlast = Signal(bool(0)) + input_2_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_2_axis_tuser = Signal(bool(0)) + input_3_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + input_3_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + input_3_axis_tvalid = Signal(bool(0)) + input_3_axis_tlast = Signal(bool(0)) + input_3_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + input_3_axis_tuser = Signal(bool(0)) + output_0_axis_tready = Signal(bool(0)) + output_1_axis_tready = Signal(bool(0)) + output_2_axis_tready = Signal(bool(0)) + output_3_axis_tready = Signal(bool(0)) + + # Outputs + input_0_axis_tready = Signal(bool(0)) + input_1_axis_tready = Signal(bool(0)) + input_2_axis_tready = Signal(bool(0)) + input_3_axis_tready = Signal(bool(0)) + output_0_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_0_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + output_0_axis_tvalid = Signal(bool(0)) + output_0_axis_tlast = Signal(bool(0)) + output_0_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_0_axis_tuser = Signal(bool(0)) + output_1_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_1_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + output_1_axis_tvalid = Signal(bool(0)) + output_1_axis_tlast = Signal(bool(0)) + output_1_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_1_axis_tuser = Signal(bool(0)) + output_2_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_2_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + output_2_axis_tvalid = Signal(bool(0)) + output_2_axis_tlast = Signal(bool(0)) + output_2_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_2_axis_tuser = Signal(bool(0)) + output_3_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + output_3_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:]) + output_3_axis_tvalid = Signal(bool(0)) + output_3_axis_tlast = Signal(bool(0)) + output_3_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + output_3_axis_tuser = Signal(bool(0)) + + # sources and sinks + source_0_queue = Queue() + source_0_pause = Signal(bool(0)) + source_1_queue = Queue() + source_1_pause = Signal(bool(0)) + source_2_queue = Queue() + source_2_pause = Signal(bool(0)) + source_3_queue = Queue() + source_3_pause = Signal(bool(0)) + sink_0_queue = Queue() + sink_0_pause = Signal(bool(0)) + sink_1_queue = Queue() + sink_1_pause = Signal(bool(0)) + sink_2_queue = Queue() + sink_2_pause = Signal(bool(0)) + sink_3_queue = Queue() + sink_3_pause = Signal(bool(0)) + + source_0 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_0_axis_tdata, + tkeep=input_0_axis_tkeep, + tvalid=input_0_axis_tvalid, + tready=input_0_axis_tready, + tlast=input_0_axis_tlast, + tdest=input_0_axis_tdest, + tuser=input_0_axis_tuser, + fifo=source_0_queue, + pause=source_0_pause, + name='source0') + source_1 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_1_axis_tdata, + tkeep=input_1_axis_tkeep, + tvalid=input_1_axis_tvalid, + tready=input_1_axis_tready, + tlast=input_1_axis_tlast, + tdest=input_1_axis_tdest, + tuser=input_1_axis_tuser, + fifo=source_1_queue, + pause=source_1_pause, + name='source1') + source_2 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_2_axis_tdata, + tkeep=input_2_axis_tkeep, + tvalid=input_2_axis_tvalid, + tready=input_2_axis_tready, + tlast=input_2_axis_tlast, + tdest=input_2_axis_tdest, + tuser=input_2_axis_tuser, + fifo=source_2_queue, + pause=source_2_pause, + name='source2') + source_3 = axis_ep.AXIStreamSource(clk, + rst, + tdata=input_3_axis_tdata, + tkeep=input_3_axis_tkeep, + tvalid=input_3_axis_tvalid, + tready=input_3_axis_tready, + tlast=input_3_axis_tlast, + tdest=input_3_axis_tdest, + tuser=input_3_axis_tuser, + fifo=source_3_queue, + pause=source_3_pause, + name='source3') + + sink_0 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_0_axis_tdata, + tkeep=output_0_axis_tkeep, + tvalid=output_0_axis_tvalid, + tready=output_0_axis_tready, + tlast=output_0_axis_tlast, + tdest=output_0_axis_tdest, + tuser=output_0_axis_tuser, + fifo=sink_0_queue, + pause=sink_0_pause, + name='sink0') + sink_1 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_1_axis_tdata, + tkeep=output_1_axis_tkeep, + tvalid=output_1_axis_tvalid, + tready=output_1_axis_tready, + tlast=output_1_axis_tlast, + tdest=output_1_axis_tdest, + tuser=output_1_axis_tuser, + fifo=sink_1_queue, + pause=sink_1_pause, + name='sink1') + sink_2 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_2_axis_tdata, + tkeep=output_2_axis_tkeep, + tvalid=output_2_axis_tvalid, + tready=output_2_axis_tready, + tlast=output_2_axis_tlast, + tdest=output_2_axis_tdest, + tuser=output_2_axis_tuser, + fifo=sink_2_queue, + pause=sink_2_pause, + name='sink2') + sink_3 = axis_ep.AXIStreamSink(clk, + rst, + tdata=output_3_axis_tdata, + tkeep=output_3_axis_tkeep, + tvalid=output_3_axis_tvalid, + tready=output_3_axis_tready, + tlast=output_3_axis_tlast, + tdest=output_3_axis_tdest, + tuser=output_3_axis_tuser, + fifo=sink_3_queue, + pause=sink_3_pause, + name='sink3') + + # DUT + dut = dut_axis_switch_64_4x4(clk, + rst, + current_test, + input_0_axis_tdata, + input_0_axis_tkeep, + input_0_axis_tvalid, + input_0_axis_tready, + input_0_axis_tlast, + input_0_axis_tdest, + input_0_axis_tuser, + input_1_axis_tdata, + input_1_axis_tkeep, + input_1_axis_tvalid, + input_1_axis_tready, + input_1_axis_tlast, + input_1_axis_tdest, + input_1_axis_tuser, + input_2_axis_tdata, + input_2_axis_tkeep, + input_2_axis_tvalid, + input_2_axis_tready, + input_2_axis_tlast, + input_2_axis_tdest, + input_2_axis_tuser, + input_3_axis_tdata, + input_3_axis_tkeep, + input_3_axis_tvalid, + input_3_axis_tready, + input_3_axis_tlast, + input_3_axis_tdest, + input_3_axis_tuser, + output_0_axis_tdata, + output_0_axis_tkeep, + output_0_axis_tvalid, + output_0_axis_tready, + output_0_axis_tlast, + output_0_axis_tdest, + output_0_axis_tuser, + output_1_axis_tdata, + output_1_axis_tkeep, + output_1_axis_tvalid, + output_1_axis_tready, + output_1_axis_tlast, + output_1_axis_tdest, + output_1_axis_tuser, + output_2_axis_tdata, + output_2_axis_tkeep, + output_2_axis_tvalid, + output_2_axis_tready, + output_2_axis_tlast, + output_2_axis_tdest, + output_2_axis_tuser, + output_3_axis_tdata, + output_3_axis_tkeep, + output_3_axis_tvalid, + output_3_axis_tready, + output_3_axis_tlast, + output_3_axis_tdest, + output_3_axis_tuser) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + def wait_normal(): + while input_0_axis_tvalid or input_1_axis_tvalid or input_2_axis_tvalid or input_3_axis_tvalid: + yield clk.posedge + + def wait_pause_source(): + while input_0_axis_tvalid or input_1_axis_tvalid or input_2_axis_tvalid or input_3_axis_tvalid: + source_0_pause.next = True + source_1_pause.next = True + source_2_pause.next = True + source_3_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + source_0_pause.next = False + source_1_pause.next = False + source_2_pause.next = False + source_3_pause.next = False + yield clk.posedge + + def wait_pause_sink(): + while input_0_axis_tvalid or input_1_axis_tvalid or input_2_axis_tvalid or input_3_axis_tvalid: + sink_0_pause.next = True + sink_1_pause.next = True + sink_2_pause.next = True + sink_3_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + sink_0_pause.next = False + sink_1_pause.next = False + sink_2_pause.next = False + sink_3_pause.next = False + yield clk.posedge + + @instance + def check(): + yield delay(100) + yield clk.posedge + rst.next = 1 + yield clk.posedge + rst.next = 0 + yield clk.posedge + yield delay(100) + yield clk.posedge + + # testbench stimulus + + yield clk.posedge + print("test 1: 0123 -> 0123") + current_test.next = 1 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x01\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x01\x01\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame2 = axis_ep.AXIStreamFrame(b'\x01\x02\x02\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=2) + test_frame3 = axis_ep.AXIStreamFrame(b'\x01\x03\x03\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=3) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame1 + + rx_frame2 = None + if not sink_2_queue.empty(): + rx_frame2 = sink_2_queue.get() + + assert rx_frame2 == test_frame2 + + rx_frame3 = None + if not sink_3_queue.empty(): + rx_frame3 = sink_3_queue.get() + + assert rx_frame3 == test_frame3 + + yield delay(100) + + yield clk.posedge + print("test 2: 0123 -> 3210") + current_test.next = 2 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x02\x00\x03\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=3) + test_frame1 = axis_ep.AXIStreamFrame(b'\x02\x01\x02\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=2) + test_frame2 = axis_ep.AXIStreamFrame(b'\x02\x02\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame3 = axis_ep.AXIStreamFrame(b'\x02\x03\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame3 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame2 + + rx_frame2 = None + if not sink_2_queue.empty(): + rx_frame2 = sink_2_queue.get() + + assert rx_frame2 == test_frame1 + + rx_frame3 = None + if not sink_3_queue.empty(): + rx_frame3 = sink_3_queue.get() + + assert rx_frame3 == test_frame0 + + yield delay(100) + + yield clk.posedge + print("test 3: 0000 -> 0123") + current_test.next = 3 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x02\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x02\x00\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame2 = axis_ep.AXIStreamFrame(b'\x02\x00\x02\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=2) + test_frame3 = axis_ep.AXIStreamFrame(b'\x02\x00\x03\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=3) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_0_queue.put(test_frame1) + source_0_queue.put(test_frame2) + source_0_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame1 + + rx_frame2 = None + if not sink_2_queue.empty(): + rx_frame2 = sink_2_queue.get() + + assert rx_frame2 == test_frame2 + + rx_frame3 = None + if not sink_3_queue.empty(): + rx_frame3 = sink_3_queue.get() + + assert rx_frame3 == test_frame3 + + yield delay(100) + + yield clk.posedge + print("test 4: 0123 -> 0000") + current_test.next = 4 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x02\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x02\x01\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame2 = axis_ep.AXIStreamFrame(b'\x02\x02\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame3 = axis_ep.AXIStreamFrame(b'\x02\x03\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + yield clk.posedge + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_0_queue.empty(): + rx_frame1 = sink_0_queue.get() + + assert rx_frame1 == test_frame1 + + rx_frame2 = None + if not sink_0_queue.empty(): + rx_frame2 = sink_0_queue.get() + + assert rx_frame2 == test_frame2 + + rx_frame3 = None + if not sink_0_queue.empty(): + rx_frame3 = sink_0_queue.get() + + assert rx_frame3 == test_frame3 + + yield delay(100) + + yield clk.posedge + print("test 1: bad decoding") + current_test.next = 1 + + test_frame0 = axis_ep.AXIStreamFrame(b'\x01\x00\x00\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=0) + test_frame1 = axis_ep.AXIStreamFrame(b'\x01\x01\x01\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=1) + test_frame2 = axis_ep.AXIStreamFrame(b'\x01\x02\x04\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=4) + test_frame3 = axis_ep.AXIStreamFrame(b'\x01\x03\x05\xFF\x01\x02\x03\x04\x05\x06\x07\x08', dest=5) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source_0_queue.put(test_frame0) + source_1_queue.put(test_frame1) + source_2_queue.put(test_frame2) + source_3_queue.put(test_frame3) + yield clk.posedge + yield clk.posedge + + yield wait() + yield clk.posedge + yield clk.posedge + + rx_frame0 = None + if not sink_0_queue.empty(): + rx_frame0 = sink_0_queue.get() + + assert rx_frame0 == test_frame0 + + rx_frame1 = None + if not sink_1_queue.empty(): + rx_frame1 = sink_1_queue.get() + + assert rx_frame1 == test_frame1 + + yield delay(100) + + raise StopSimulation + + return dut, source_0, source_1, source_2, source_3, sink_0, sink_1, sink_2, sink_3, clkgen, check + +def test_bench(): + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() diff --git a/tb/test_axis_switch_64_4x4.v b/tb/test_axis_switch_64_4x4.v new file mode 100644 index 00000000..e5f939f8 --- /dev/null +++ b/tb/test_axis_switch_64_4x4.v @@ -0,0 +1,266 @@ +/* + +Copyright (c) 2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Testbench for axis_switch_64_4x4 + */ +module test_axis_switch_64_4x4; + +// Parameters +parameter DATA_WIDTH = 64; +parameter KEEP_WIDTH = (DATA_WIDTH/8); +parameter DEST_WIDTH = 3; +parameter OUT_0_BASE = 0; +parameter OUT_0_TOP = 0; +parameter OUT_0_CONNECT = 4'b1111; +parameter OUT_1_BASE = 1; +parameter OUT_1_TOP = 1; +parameter OUT_1_CONNECT = 4'b1111; +parameter OUT_2_BASE = 2; +parameter OUT_2_TOP = 2; +parameter OUT_2_CONNECT = 4'b1111; +parameter OUT_3_BASE = 3; +parameter OUT_3_TOP = 3; +parameter OUT_3_CONNECT = 4'b1111; +parameter ARB_TYPE = "ROUND_ROBIN"; +parameter LSB_PRIORITY = "HIGH"; + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [DATA_WIDTH-1:0] input_0_axis_tdata = 0; +reg [KEEP_WIDTH-1:0] input_0_axis_tkeep = 0; +reg input_0_axis_tvalid = 0; +reg input_0_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_0_axis_tdest = 0; +reg input_0_axis_tuser = 0; +reg [DATA_WIDTH-1:0] input_1_axis_tdata = 0; +reg [KEEP_WIDTH-1:0] input_1_axis_tkeep = 0; +reg input_1_axis_tvalid = 0; +reg input_1_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_1_axis_tdest = 0; +reg input_1_axis_tuser = 0; +reg [DATA_WIDTH-1:0] input_2_axis_tdata = 0; +reg [KEEP_WIDTH-1:0] input_2_axis_tkeep = 0; +reg input_2_axis_tvalid = 0; +reg input_2_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_2_axis_tdest = 0; +reg input_2_axis_tuser = 0; +reg [DATA_WIDTH-1:0] input_3_axis_tdata = 0; +reg [KEEP_WIDTH-1:0] input_3_axis_tkeep = 0; +reg input_3_axis_tvalid = 0; +reg input_3_axis_tlast = 0; +reg [DEST_WIDTH-1:0] input_3_axis_tdest = 0; +reg input_3_axis_tuser = 0; +reg output_0_axis_tready = 0; +reg output_1_axis_tready = 0; +reg output_2_axis_tready = 0; +reg output_3_axis_tready = 0; + +// Outputs +wire input_0_axis_tready; +wire input_1_axis_tready; +wire input_2_axis_tready; +wire input_3_axis_tready; +wire [DATA_WIDTH-1:0] output_0_axis_tdata; +wire [KEEP_WIDTH-1:0] output_0_axis_tkeep; +wire output_0_axis_tvalid; +wire output_0_axis_tlast; +wire [DEST_WIDTH-1:0] output_0_axis_tdest; +wire output_0_axis_tuser; +wire [DATA_WIDTH-1:0] output_1_axis_tdata; +wire [KEEP_WIDTH-1:0] output_1_axis_tkeep; +wire output_1_axis_tvalid; +wire output_1_axis_tlast; +wire [DEST_WIDTH-1:0] output_1_axis_tdest; +wire output_1_axis_tuser; +wire [DATA_WIDTH-1:0] output_2_axis_tdata; +wire [KEEP_WIDTH-1:0] output_2_axis_tkeep; +wire output_2_axis_tvalid; +wire output_2_axis_tlast; +wire [DEST_WIDTH-1:0] output_2_axis_tdest; +wire output_2_axis_tuser; +wire [DATA_WIDTH-1:0] output_3_axis_tdata; +wire [KEEP_WIDTH-1:0] output_3_axis_tkeep; +wire output_3_axis_tvalid; +wire output_3_axis_tlast; +wire [DEST_WIDTH-1:0] output_3_axis_tdest; +wire output_3_axis_tuser; + +initial begin + // myhdl integration + $from_myhdl(clk, + rst, + current_test, + input_0_axis_tdata, + input_0_axis_tkeep, + input_0_axis_tvalid, + input_0_axis_tlast, + input_0_axis_tdest, + input_0_axis_tuser, + input_1_axis_tdata, + input_1_axis_tkeep, + input_1_axis_tvalid, + input_1_axis_tlast, + input_1_axis_tdest, + input_1_axis_tuser, + input_2_axis_tdata, + input_2_axis_tkeep, + input_2_axis_tvalid, + input_2_axis_tlast, + input_2_axis_tdest, + input_2_axis_tuser, + input_3_axis_tdata, + input_3_axis_tkeep, + input_3_axis_tvalid, + input_3_axis_tlast, + input_3_axis_tdest, + input_3_axis_tuser, + output_0_axis_tready, + output_1_axis_tready, + output_2_axis_tready, + output_3_axis_tready); + $to_myhdl(input_0_axis_tready, + input_1_axis_tready, + input_2_axis_tready, + input_3_axis_tready, + output_0_axis_tdata, + output_0_axis_tkeep, + output_0_axis_tvalid, + output_0_axis_tlast, + output_0_axis_tdest, + output_0_axis_tuser, + output_1_axis_tdata, + output_1_axis_tkeep, + output_1_axis_tvalid, + output_1_axis_tlast, + output_1_axis_tdest, + output_1_axis_tuser, + output_2_axis_tdata, + output_2_axis_tkeep, + output_2_axis_tvalid, + output_2_axis_tlast, + output_2_axis_tdest, + output_2_axis_tuser, + output_3_axis_tdata, + output_3_axis_tkeep, + output_3_axis_tvalid, + output_3_axis_tlast, + output_3_axis_tdest, + output_3_axis_tuser); + + // dump file + $dumpfile("test_axis_switch_64_4x4.lxt"); + $dumpvars(0, test_axis_switch_64_4x4); +end + +axis_switch_64_4x4 #( + .DATA_WIDTH(DATA_WIDTH), + .KEEP_WIDTH(KEEP_WIDTH), + .DEST_WIDTH(DEST_WIDTH), + .OUT_0_BASE(OUT_0_BASE), + .OUT_0_TOP(OUT_0_TOP), + .OUT_0_CONNECT(OUT_0_CONNECT), + .OUT_1_BASE(OUT_1_BASE), + .OUT_1_TOP(OUT_1_TOP), + .OUT_1_CONNECT(OUT_1_CONNECT), + .OUT_2_BASE(OUT_2_BASE), + .OUT_2_TOP(OUT_2_TOP), + .OUT_2_CONNECT(OUT_2_CONNECT), + .OUT_3_BASE(OUT_3_BASE), + .OUT_3_TOP(OUT_3_TOP), + .OUT_3_CONNECT(OUT_3_CONNECT), + .ARB_TYPE(ARB_TYPE), + .LSB_PRIORITY(LSB_PRIORITY) +) +UUT ( + .clk(clk), + .rst(rst), + // AXI inputs + .input_0_axis_tdata(input_0_axis_tdata), + .input_0_axis_tkeep(input_0_axis_tkeep), + .input_0_axis_tvalid(input_0_axis_tvalid), + .input_0_axis_tready(input_0_axis_tready), + .input_0_axis_tlast(input_0_axis_tlast), + .input_0_axis_tdest(input_0_axis_tdest), + .input_0_axis_tuser(input_0_axis_tuser), + .input_1_axis_tdata(input_1_axis_tdata), + .input_1_axis_tkeep(input_1_axis_tkeep), + .input_1_axis_tvalid(input_1_axis_tvalid), + .input_1_axis_tready(input_1_axis_tready), + .input_1_axis_tlast(input_1_axis_tlast), + .input_1_axis_tdest(input_1_axis_tdest), + .input_1_axis_tuser(input_1_axis_tuser), + .input_2_axis_tdata(input_2_axis_tdata), + .input_2_axis_tkeep(input_2_axis_tkeep), + .input_2_axis_tvalid(input_2_axis_tvalid), + .input_2_axis_tready(input_2_axis_tready), + .input_2_axis_tlast(input_2_axis_tlast), + .input_2_axis_tdest(input_2_axis_tdest), + .input_2_axis_tuser(input_2_axis_tuser), + .input_3_axis_tdata(input_3_axis_tdata), + .input_3_axis_tkeep(input_3_axis_tkeep), + .input_3_axis_tvalid(input_3_axis_tvalid), + .input_3_axis_tready(input_3_axis_tready), + .input_3_axis_tlast(input_3_axis_tlast), + .input_3_axis_tdest(input_3_axis_tdest), + .input_3_axis_tuser(input_3_axis_tuser), + // AXI outputs + .output_0_axis_tdata(output_0_axis_tdata), + .output_0_axis_tkeep(output_0_axis_tkeep), + .output_0_axis_tvalid(output_0_axis_tvalid), + .output_0_axis_tready(output_0_axis_tready), + .output_0_axis_tlast(output_0_axis_tlast), + .output_0_axis_tdest(output_0_axis_tdest), + .output_0_axis_tuser(output_0_axis_tuser), + .output_1_axis_tdata(output_1_axis_tdata), + .output_1_axis_tkeep(output_1_axis_tkeep), + .output_1_axis_tvalid(output_1_axis_tvalid), + .output_1_axis_tready(output_1_axis_tready), + .output_1_axis_tlast(output_1_axis_tlast), + .output_1_axis_tdest(output_1_axis_tdest), + .output_1_axis_tuser(output_1_axis_tuser), + .output_2_axis_tdata(output_2_axis_tdata), + .output_2_axis_tkeep(output_2_axis_tkeep), + .output_2_axis_tvalid(output_2_axis_tvalid), + .output_2_axis_tready(output_2_axis_tready), + .output_2_axis_tlast(output_2_axis_tlast), + .output_2_axis_tdest(output_2_axis_tdest), + .output_2_axis_tuser(output_2_axis_tuser), + .output_3_axis_tdata(output_3_axis_tdata), + .output_3_axis_tkeep(output_3_axis_tkeep), + .output_3_axis_tvalid(output_3_axis_tvalid), + .output_3_axis_tready(output_3_axis_tready), + .output_3_axis_tlast(output_3_axis_tlast), + .output_3_axis_tdest(output_3_axis_tdest), + .output_3_axis_tuser(output_3_axis_tuser) +); + +endmodule From c27e74c7d47ff52de81d34b352550209859506dc Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Mon, 25 Jul 2016 13:15:59 -0700 Subject: [PATCH 7/7] Update readme --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index bc5d16d8..8dda8fb1 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,18 @@ AXI stream interface. Trigger signal used to reset and dump counts out of AXI interface, along with tag value. Use with axis_frame_join_N to form a single monolithic frame from multiple monitored points with the same trigger. +### axis_switch_NxN module + +Frame-aware AXI stream switch with parametrizable data width. + +Can be generated with arbitrary port counts with axis_switch.py. + +### axis_switch_64_NxN module + +Frame-aware AXI stream switch with tkeep signal and parametrizable data width. + +Can be generated with arbitrary port counts with axis_mux_64.py. + ### axis_tap module AXI stream tap module. Used to make a copy of an AXI stream bus without @@ -276,6 +288,10 @@ Parametrizable priority encoder. axis_srl_fifo_64.v : SRL-based FIFO (64 bit) axis_srl_register.v : SRL-based register axis_srl_register_64.v : SRL-based register (64 bit) + axis_switch.py : AXI stream switch generator + axis_switch_4x4.v : 4x4 port AXI stream switch + axis_switch_64.py : AXI stream switch generator (64 bit) + axis_switch_64_4x4.v : 4x4 port AXI stream switch (64 bit) axis_stat_counter.v : Statistics counter axis_tap.v : AXI stream tap axis_tap_64.v : AXI stream tap (64 bit)