1// 2// Copyright 2018-2019 Ettus Research, A National Instruments Company 3// 4// SPDX-License-Identifier: LGPL-3.0-or-later 5// 6// Module: chdr_stream_input 7// Description: 8// Implements the CHDR input port for a stream endpoint. 9// The module accepts stream command and data packets and 10// emits stream status packets. Flow control and error state 11// is communicated using stream status packets. There are no 12// external config interfaces because all configuration is done 13// using stream command packets. 14// 15// Parameters: 16// - CHDR_W: Width of the CHDR bus in bits 17// - BUFF_SIZE: Buffer size in log2 of the number of words in the 18// ingress buffer for the stream 19// - FLUSH_TIMEOUT_W: log2 of the number of cycles to wait in order 20// to flush the input stream 21// - SIGNAL_ERRS: If set to 1 then all stream errors will be notified 22// upstream, otherwise ALL errors are ignored 23// 24// Signals: 25// - s_axis_chdr_* : Input CHDR stream (AXI-Stream) 26// - m_axis_chdr_* : Output flow-controlled CHDR stream (AXI-Stream) 27// - m_axis_strs_* : Output stream status (AXI-Stream) 28// - data_err_stb : If asserted, a data error notification is sent upstream 29// 30 31module chdr_stream_input #( 32 parameter CHDR_W = 256, 33 parameter BUFF_SIZE = 14, 34 parameter FLUSH_TIMEOUT_W = 14, 35 parameter MONITOR_EN = 1, 36 parameter SIGNAL_ERRS = 1 37)( 38 // Clock, reset and settings 39 input wire clk, 40 input wire rst, 41 // CHDR in (AXI-Stream) 42 input wire [CHDR_W-1:0] s_axis_chdr_tdata, 43 input wire s_axis_chdr_tlast, 44 input wire s_axis_chdr_tvalid, 45 output wire s_axis_chdr_tready, 46 // Flow controlled data out (AXI-Stream) 47 output wire [CHDR_W-1:0] m_axis_data_tdata, 48 output wire m_axis_data_tlast, 49 output wire m_axis_data_tvalid, 50 input wire m_axis_data_tready, 51 // Stream status out (AXI-Stream) 52 output reg [CHDR_W-1:0] m_axis_strs_tdata, 53 output wire m_axis_strs_tlast, 54 output wire m_axis_strs_tvalid, 55 input wire m_axis_strs_tready, 56 // External stream error signal 57 input wire data_err_stb 58); 59 60 // The buffer size depends on the BUFF_SIZE parameter 61 localparam [40:0] BUFF_SIZE_BYTES = ((41'h1 << BUFF_SIZE) * (CHDR_W / 8)) - 41'h1; 62 // This is a flit-buffer. No packet limits 63 localparam [23:0] BUFF_SIZE_PKTS = 24'hFFFFFF; 64 65 // --------------------------------------------------- 66 // RFNoC Includes 67 // --------------------------------------------------- 68 `include "rfnoc_chdr_utils.vh" 69 `include "rfnoc_chdr_internal_utils.vh" 70 71 // --------------------------------------------------- 72 // Ingress Buffer and Flow Control Logic 73 // --------------------------------------------------- 74 wire [CHDR_W-1:0] buff_tdata; 75 wire buff_tlast, buff_tvalid; 76 reg buff_tready; 77 wire [15:0] buff_info; 78 79 chdr_ingress_fifo #( 80 .WIDTH(CHDR_W), .SIZE(BUFF_SIZE) 81 ) ingress_fifo_i ( 82 .clk(clk), .reset(rst), .clear(1'b0), 83 .i_tdata(s_axis_chdr_tdata), .i_tlast(s_axis_chdr_tlast), 84 .i_tvalid(s_axis_chdr_tvalid), .i_tready(s_axis_chdr_tready), 85 .o_tdata(buff_tdata), .o_tlast(buff_tlast), 86 .o_tvalid(buff_tvalid), .o_tready(buff_tready) 87 ); 88 89 generate if (MONITOR_EN) begin 90 wire [BUFF_SIZE:0] occ_lines; 91 axis_fifo_monitor #( .COUNT_W(BUFF_SIZE+1) ) fifo_mon_i ( 92 .clk(clk), .reset(rst), 93 .i_tlast(s_axis_chdr_tlast), .i_tvalid(s_axis_chdr_tvalid), .i_tready(s_axis_chdr_tready), 94 .o_tlast(buff_tlast), .o_tvalid(buff_tvalid), .o_tready(buff_tready), 95 .i_sop(), .i_eop(), .o_sop(), .o_eop(), 96 .occupied(occ_lines), .occupied_pkts() 97 ); 98 // buff_info represents a fraction of the fullness of the buffer 99 // fullness percentage = (buff_info / 32768) * 100 100 if (BUFF_SIZE + 1 >= 16) 101 assign buff_info = occ_lines[BUFF_SIZE:(BUFF_SIZE-15)]; 102 else 103 assign buff_info = {occ_lines, {(15-BUFF_SIZE){1'b0}}}; 104 end else begin 105 assign buff_info = 16'd0; 106 end endgenerate 107 108 // Flow Control State 109 // xfer_cnt: Total transfer count since fc_enabled = 1 110 // accum: Transfer count since last FC response 111 // fc_freq: The threshold for sending an FC response 112 reg [63:0] xfer_cnt_bytes = 64'd0; 113 reg [39:0] xfer_cnt_pkts = 40'd0; 114 reg [63:0] accum_bytes = 64'd0; 115 reg [39:0] accum_pkts = 40'd0; 116 reg [63:0] fc_freq_bytes = 64'd0; 117 reg [39:0] fc_freq_pkts = 40'd0; 118 119 // State machine transition signals info 120 reg fc_enabled = 1'b0; // Is flow control enabled? 121 wire fc_ping; // A flow control response was requested 122 wire fc_first_resp; // Send the first flow control response 123 wire fc_refresh; // Refresh accumulated values 124 wire fc_override; // Override total xfer counts 125 reg fc_override_del = 1'b0; 126 reg [3:0] fc_due_shreg = 4'hF; // Is a response due? (shift register) 127 128 // Endpoint IDs of this endpoint and the stream source 129 reg [15:0] this_epid = 16'd0, return_epid = 16'd0; 130 131 // Cached values from a stream command 132 reg [63:0] strc_num_bytes; 133 reg [39:0] strc_num_pkts; 134 reg [3:0] strc_op_data; // Unused for now 135 reg [3:0] strc_op_code; 136 137 // Total transfer count updater 138 always @(posedge clk) begin 139 if (rst || !fc_enabled) begin 140 // Reset 141 xfer_cnt_bytes <= 64'd0; 142 xfer_cnt_pkts <= 40'd0; 143 end else if (fc_override) begin 144 // Override 145 xfer_cnt_bytes <= strc_num_bytes; 146 xfer_cnt_pkts <= strc_num_pkts; 147 end else if (buff_tvalid && buff_tready) begin 148 // Count 149 xfer_cnt_bytes <= xfer_cnt_bytes + (CHDR_W/8); 150 if (buff_tlast) 151 xfer_cnt_pkts <= xfer_cnt_pkts + 40'd1; 152 end 153 end 154 155 // Accumulated transfer count updater 156 always @(posedge clk) begin 157 if (rst || !fc_enabled || fc_refresh) begin 158 // Reset 159 accum_bytes <= 64'd0; 160 accum_pkts <= 40'd0; 161 end else if (buff_tvalid && buff_tready) begin 162 // Count 163 accum_bytes <= accum_bytes + (CHDR_W/8); 164 if (buff_tlast) 165 accum_pkts <= accum_pkts + 40'd1; 166 end 167 end 168 169 // Flow control trigger 170 // Why a shift-register here? 171 // 1. For edge detection 172 // 2. To allow the tools to re-time the wide comparators. 173 // We don't care about the latency here because stream 174 // status messages are asynchronous wrt the input. 175 always @(posedge clk) begin 176 if (rst || !fc_enabled) begin 177 // Reset to all ones so we don't send an extra stream status packet 178 // immediately after flow control is re-enabled. This also ensures we 179 // don't send an extra status packet when we get the first init command 180 // which has zero for num_bytes and num_pkts. 181 fc_due_shreg <= 4'hF; 182 end else begin 183 fc_due_shreg <= { 184 fc_due_shreg[2:0], 185 (accum_bytes >= fc_freq_bytes) || (accum_pkts >= fc_freq_pkts) 186 }; 187 end 188 end 189 wire fc_resp_due = fc_due_shreg[2] && !fc_due_shreg[3]; 190 191 // --------------------------------------------------- 192 // Stream Command Handler 193 // --------------------------------------------------- 194 localparam [2:0] ST_IN_HDR = 3'd0; // The CHDR header of an input pkt 195 localparam [2:0] ST_IN_DATA = 3'd1; // The CHDR body (incl. mdata) of an input pkt 196 localparam [2:0] ST_STRC_W0 = 3'd2; // The first word of a stream command 197 localparam [2:0] ST_STRC_W1 = 3'd3; // The second word of a stream command 198 localparam [2:0] ST_STRC_EXEC = 3'd4; // A stream command is executing 199 localparam [2:0] ST_FLUSH = 3'd5; // Input is flushing 200 localparam [2:0] ST_DROP = 3'd6; // Current packet is being dropped 201 202 reg [2:0] state = ST_IN_HDR; // State of the input state machine 203 reg pkt_too_long = 1'b0; // Error case. Packet is too long 204 reg is_first_data_pkt = 1'b1; // Is this the first data pkt after fc_enabled = 1? 205 reg is_first_strc_pkt = 1'b1; // Is this the strm cmd data pkt after fc_enabled = 1? 206 reg [15:0] exp_data_seq_num = 16'd0; // Expected sequence number for the next data pkt 207 reg [15:0] exp_strc_seq_num = 16'd0; // Expected sequence number for the next stream cmd pkt 208 reg [15:0] strc_dst_epid = 16'd0; // EPID in CHDR header of STRC packet 209 210 reg [FLUSH_TIMEOUT_W-1:0] flush_counter = {FLUSH_TIMEOUT_W{1'b0}}; 211 212 // Shortcuts 213 wire is_data_pkt = 214 chdr_get_pkt_type(buff_tdata[63:0]) == CHDR_PKT_TYPE_DATA || 215 chdr_get_pkt_type(buff_tdata[63:0]) == CHDR_PKT_TYPE_DATA_TS; 216 wire is_strc_pkt = 217 chdr_get_pkt_type(buff_tdata[63:0]) == CHDR_PKT_TYPE_STRC; 218 219 // Error Logic 220 wire data_seq_err_stb = (state == ST_IN_HDR) && is_data_pkt && !is_first_data_pkt && 221 (chdr_get_seq_num(buff_tdata[63:0]) != exp_data_seq_num); 222 wire strc_seq_err_stb = (state == ST_IN_HDR) && is_strc_pkt && !is_first_strc_pkt && 223 (chdr_get_seq_num(buff_tdata[63:0]) != exp_strc_seq_num); 224 wire seq_err_stb = (data_seq_err_stb || strc_seq_err_stb) && buff_tvalid && buff_tready; 225 226 wire route_err_stb = buff_tvalid && buff_tready && (state == ST_IN_HDR) && 227 (chdr_get_dst_epid(buff_tdata[63:0]) != this_epid); 228 229 // Break critical paths to response FIFO 230 reg [47:0] stream_err_info = 48'h0; 231 reg stream_err_stb = 1'b0; 232 reg [3:0] stream_err_status = CHDR_STRS_STATUS_OKAY; 233 234 always @(posedge clk) begin 235 if (rst || (SIGNAL_ERRS == 0)) begin 236 stream_err_stb <= 1'b0; 237 end else begin 238 stream_err_stb <= seq_err_stb | route_err_stb | data_err_stb; 239 if (seq_err_stb) begin 240 stream_err_status <= CHDR_STRS_STATUS_SEQERR; 241 // The extended info has the packet type (to detect which stream 242 // had an error), the expected and actual sequence number. 243 stream_err_info <= {13'h0, chdr_get_pkt_type(buff_tdata[63:0]), 244 data_seq_err_stb ? exp_data_seq_num : exp_strc_seq_num, 245 chdr_get_seq_num(buff_tdata[63:0])}; 246 end else if (route_err_stb) begin 247 stream_err_status <= CHDR_STRS_STATUS_RTERR; 248 // The extended info has the expected and actual destination EPID. 249 stream_err_info <= {16'd0, this_epid, chdr_get_dst_epid(buff_tdata[63:0])}; 250 end else begin 251 stream_err_status <= CHDR_STRS_STATUS_DATAERR; 252 // The extended info has the expected and actual destination EPID. 253 stream_err_info <= {16'd0, this_epid, chdr_get_dst_epid(buff_tdata[63:0])}; 254 end 255 end 256 end 257 258 // Input State Machine 259 // - Pass data packets forward 260 // - Consume stream cmd packets 261 always @(posedge clk) begin 262 if (rst) begin 263 state <= ST_IN_HDR; 264 pkt_too_long <= 1'b0; 265 fc_enabled <= 1'b0; 266 end else begin 267 case (state) 268 ST_IN_HDR: begin 269 if (buff_tvalid && buff_tready) begin 270 if (!buff_tlast) begin 271 // Classify packet and... 272 if (is_strc_pkt) begin 273 // ...consume if it is a stream command or... 274 state <= ST_STRC_W0; 275 end else if (is_data_pkt) begin 276 // ...pass to output if it is a data packet... 277 state <= ST_IN_DATA; 278 end else begin 279 // ... otherwise drop. 280 state <= ST_DROP; 281 end 282 end 283 // Update other state vars 284 pkt_too_long <= 1'b0; 285 if (is_strc_pkt) begin 286 is_first_strc_pkt <= 1'b0; 287 strc_dst_epid <= chdr_get_dst_epid(buff_tdata[63:0]); 288 exp_strc_seq_num <= chdr_get_seq_num(buff_tdata[63:0]) + 16'd1; 289 end else if (is_data_pkt) begin 290 is_first_data_pkt <= 1'b0; 291 exp_data_seq_num <= chdr_get_seq_num(buff_tdata[63:0]) + 16'd1; 292 end 293 end 294 end 295 ST_IN_DATA: begin 296 // Pass the data packet forward 297 if (buff_tvalid && buff_tready && buff_tlast) 298 state <= ST_IN_HDR; 299 end 300 ST_STRC_W0: begin 301 if (buff_tvalid && buff_tready) begin 302 // Consume the first word of a stream command packet 303 if (CHDR_W > 64) begin 304 strc_num_bytes <= chdr128_strc_get_num_bytes(buff_tdata[127:0]); 305 strc_num_pkts <= chdr128_strc_get_num_pkts (buff_tdata[127:0]); 306 strc_op_data <= chdr128_strc_get_op_data (buff_tdata[127:0]); 307 strc_op_code <= chdr128_strc_get_op_code (buff_tdata[127:0]); 308 return_epid <= chdr128_strs_get_src_epid (buff_tdata[127:0]); 309 state <= ST_STRC_EXEC; 310 pkt_too_long <= ~buff_tlast; 311 end else begin 312 strc_num_pkts <= chdr64_strc_get_num_pkts(buff_tdata[63:0]); 313 strc_op_data <= chdr64_strc_get_op_data (buff_tdata[63:0]); 314 strc_op_code <= chdr64_strc_get_op_code (buff_tdata[63:0]); 315 return_epid <= chdr64_strs_get_src_epid(buff_tdata[63:0]); 316 state <= ST_STRC_W1; 317 end 318 end 319 end 320 ST_STRC_W1: begin 321 if (buff_tvalid && buff_tready) begin 322 // Consume the second word of a stream command packet 323 strc_num_bytes <= chdr64_strc_get_num_bytes(buff_tdata[63:0]); 324 state <= ST_STRC_EXEC; 325 pkt_too_long <= ~buff_tlast; 326 end 327 end 328 ST_STRC_EXEC: begin 329 case (strc_op_code) 330 CHDR_STRC_OPCODE_INIT: begin 331 // Configure FC but disable it temporarily 332 fc_freq_bytes <= strc_num_bytes; 333 fc_freq_pkts <= strc_num_pkts; 334 this_epid <= strc_dst_epid; 335 fc_enabled <= 1'b0; 336 // Flush the input 337 state <= ST_FLUSH; 338 flush_counter <= {FLUSH_TIMEOUT_W{1'b1}}; 339 end 340 CHDR_STRC_OPCODE_PING: begin 341 // Ping can complete in 1 cycle 342 state <= pkt_too_long ? ST_DROP : ST_IN_HDR; 343 end 344 CHDR_STRC_OPCODE_RESYNC: begin 345 // Resync can complete in 1 cycle 346 state <= pkt_too_long ? ST_DROP : ST_IN_HDR; 347 end 348 default: begin 349 state <= pkt_too_long ? ST_DROP : ST_IN_HDR; 350 end 351 endcase 352 end 353 ST_FLUSH: begin 354 // Drop until the next packet arrives 355 if (buff_tvalid && buff_tready) begin 356 flush_counter <= {FLUSH_TIMEOUT_W{1'b1}}; 357 end else begin 358 flush_counter <= flush_counter - 'd1; 359 if (flush_counter == {FLUSH_TIMEOUT_W{1'b0}}) begin 360 // Done flushing. Re-arm flow control and reset packet 361 // sequence check info. 362 fc_enabled <= 1'b1; 363 is_first_data_pkt <= 1'b1; 364 is_first_strc_pkt <= 1'b1; 365 state <= ST_IN_HDR; 366 end 367 end 368 end 369 ST_DROP: begin 370 // Drop until the next packet arrives 371 if (buff_tvalid && buff_tready && buff_tlast) 372 state <= ST_IN_HDR; 373 end 374 default: begin 375 // We should never get here 376 state <= ST_IN_HDR; 377 end 378 endcase 379 end 380 end 381 382 always @(*) begin 383 case (state) 384 ST_IN_HDR: 385 buff_tready = m_axis_data_tready || !is_data_pkt; 386 ST_IN_DATA: 387 buff_tready = m_axis_data_tready; 388 ST_STRC_W0: 389 buff_tready = 1'b1; 390 ST_STRC_W1: 391 buff_tready = 1'b1; 392 ST_FLUSH: 393 buff_tready = 1'b1; 394 ST_DROP: 395 buff_tready = 1'b1; 396 default: 397 buff_tready = 1'b0; 398 endcase 399 end 400 401 // Logic to drive output port 402 assign m_axis_data_tdata = buff_tdata; 403 assign m_axis_data_tlast = buff_tlast; 404 assign m_axis_data_tvalid = buff_tvalid && 405 ((state == ST_IN_HDR && is_data_pkt) || state == ST_IN_DATA); 406 407 // Logic to drive triggers 408 assign fc_ping = (state == ST_STRC_EXEC) && (strc_op_code == CHDR_STRC_OPCODE_PING); 409 assign fc_first_resp = (state == ST_FLUSH) && (flush_counter == {FLUSH_TIMEOUT_W{1'b0}}); 410 assign fc_override = (state == ST_STRC_EXEC) && (strc_op_code == CHDR_STRC_OPCODE_RESYNC); 411 always @(posedge clk) fc_override_del <= fc_override; 412 413 wire [51:0] resp_o_tdata; 414 wire resp_o_tvalid; 415 wire resp_o_tready; 416 reg [51:0] resp_i_tdata; 417 reg resp_i_tvalid = 1'b0; 418 419 // Send a stream status packet for the following cases: 420 // - Immediately after initialization 421 // - If a response is explicitly requested (ping) 422 // - If a response is due i.e. we have exceeded the frequency 423 // - If FC is resynchronized via a stream cmd 424 // - If an error is detected in the stream 425 always @(posedge clk) begin 426 if (rst) begin 427 resp_i_tvalid <= 1'b0; 428 resp_i_tdata <= 52'h0; 429 end else begin 430 resp_i_tvalid <= fc_first_resp || fc_ping || fc_resp_due || fc_override_del || stream_err_stb; 431 resp_i_tdata <= stream_err_stb ? {stream_err_info, stream_err_status} : {48'h0, CHDR_STRS_STATUS_OKAY}; 432 end 433 end 434 435 // --------------------------------------------------- 436 // Stream Status Responder 437 // --------------------------------------------------- 438 localparam [2:0] ST_STRS_IDLE = 3'd0; // Waiting for response to post 439 localparam [2:0] ST_STRS_HDR = 3'd1; // Sending response CHDR header 440 localparam [2:0] ST_STRS_W0 = 3'd2; // Sending first response word 441 localparam [2:0] ST_STRS_W1 = 3'd3; // Sending second response word 442 localparam [2:0] ST_STRS_W2 = 3'd4; // Sending third response word 443 localparam [2:0] ST_STRS_W3 = 3'd5; // Sending fourth response word 444 localparam [2:0] ST_STRS_DONE = 3'd6; // Consuming response 445 446 reg [2:0] resp_state = ST_STRS_IDLE; // State of the responder 447 reg [15:0] resp_seq_num = 16'd0; // Current sequence number of response 448 449 assign fc_refresh = (resp_state == ST_STRS_DONE); 450 451 assign resp_o_tready = (resp_state == ST_STRS_DONE || !fc_enabled); 452 453 // A FIFO that holds up to 32 posted responses and status information 454 // NOTE: This is a lossy FIFO. If the downstream response port is clogged 455 // then we will drop responses. That should never happen in a normal operating 456 // scenario. 457 axi_fifo #(.WIDTH(48 + 4), .SIZE(5)) resp_fifo_i ( 458 .clk(clk), .reset(rst), .clear(1'b0), 459 .i_tdata(resp_i_tdata), .i_tvalid(resp_i_tvalid), .i_tready(/* Lossy FIFO */), 460 .o_tdata(resp_o_tdata), .o_tvalid(resp_o_tvalid), .o_tready(resp_o_tready), 461 .space(), .occupied() 462 ); 463 464 // Responder State Machine 465 // - Wait for response to appear in FIFO 466 // - Output a full packet (different # of xfers depending on CHDR_W) 467 always @(posedge clk) begin 468 if (rst || !fc_enabled) begin 469 resp_state <= ST_STRS_IDLE; 470 resp_seq_num <= 16'd0; 471 end else begin 472 case (resp_state) 473 ST_STRS_IDLE: begin 474 if (resp_o_tvalid) 475 resp_state <= ST_STRS_HDR; 476 end 477 ST_STRS_HDR: begin 478 if (m_axis_strs_tready) 479 resp_state <= ST_STRS_W0; 480 end 481 ST_STRS_W0: begin 482 if (m_axis_strs_tready) 483 if (CHDR_W < 256) 484 resp_state <= ST_STRS_W1; 485 else 486 resp_state <= ST_STRS_DONE; 487 end 488 ST_STRS_W1: begin 489 if (m_axis_strs_tready) 490 if (CHDR_W < 128) 491 resp_state <= ST_STRS_W2; 492 else 493 resp_state <= ST_STRS_DONE; 494 end 495 ST_STRS_W2: begin 496 if (m_axis_strs_tready) 497 resp_state <= ST_STRS_W3; 498 end 499 ST_STRS_W3: begin 500 if (m_axis_strs_tready) 501 resp_state <= ST_STRS_DONE; 502 end 503 ST_STRS_DONE: begin 504 resp_state <= ST_STRS_IDLE; 505 resp_seq_num <= resp_seq_num + 16'd1; 506 end 507 default: begin 508 // We should never get here 509 resp_state <= ST_STRS_IDLE; 510 end 511 endcase 512 end 513 end 514 515 // Output data. Header and Payload 516 wire [63:0] strs_header = chdr_build_header( 517 /*VC*/ 6'd0, /*eob*/ 1'b0, /*eov*/ 1'b0, CHDR_PKT_TYPE_STRS, CHDR_NO_MDATA, 518 resp_seq_num, 16'd32+(CHDR_W/8), return_epid); 519 wire [255:0] strs_payload = chdr256_strs_build( 520 /*statusinfo*/ resp_o_tdata[51:4], buff_info, 521 xfer_cnt_bytes, xfer_cnt_pkts, 522 BUFF_SIZE_PKTS[23:0], BUFF_SIZE_BYTES[39:0], 523 resp_o_tdata[3:0], this_epid); 524 525 // m_axis_strs_* signal values depend on CHDR_W 526 generate 527 if (CHDR_W == 64) begin 528 // Response spans 5 transfers (header + 4 words) 529 assign m_axis_strs_tlast = (resp_state == ST_STRS_W3); 530 always @(*) begin 531 case (resp_state) 532 ST_STRS_W0: 533 m_axis_strs_tdata = strs_payload[63:0]; 534 ST_STRS_W1: 535 m_axis_strs_tdata = strs_payload[127:64]; 536 ST_STRS_W2: 537 m_axis_strs_tdata = strs_payload[191:128]; 538 ST_STRS_W3: 539 m_axis_strs_tdata = strs_payload[255:192]; 540 default: 541 m_axis_strs_tdata = strs_header; 542 endcase 543 end 544 end else if (CHDR_W == 128) begin 545 // Response spans 3 transfers (header + 2 words) 546 assign m_axis_strs_tlast = (resp_state == ST_STRS_W1); 547 always @(*) begin 548 case (resp_state) 549 ST_STRS_W0: 550 m_axis_strs_tdata = strs_payload[127:0]; 551 ST_STRS_W1: 552 m_axis_strs_tdata = strs_payload[255:128]; 553 default: 554 m_axis_strs_tdata = {64'h0, strs_header}; 555 endcase 556 end 557 end else begin 558 // Response spans 2 transfers (header + word) 559 assign m_axis_strs_tlast = (resp_state == ST_STRS_W0); 560 always @(*) begin 561 case (resp_state) 562 ST_STRS_W0: 563 m_axis_strs_tdata[255:0] = strs_payload; 564 default: 565 m_axis_strs_tdata[255:0] = {192'h0, strs_header}; 566 endcase 567 if (CHDR_W > 256) begin 568 m_axis_strs_tdata[CHDR_W-1:256] = 'h0; 569 end 570 end 571 end 572 endgenerate 573 574 assign m_axis_strs_tvalid = (resp_state != ST_STRS_IDLE) && (resp_state != ST_STRS_DONE); 575 576endmodule // chdr_stream_input 577