Files
OpenExSys_NoC/rtl/input_port_vc.sv
2023-11-26 15:36:27 +01:00

300 lines
10 KiB
Systemverilog

module input_port_vc
import rvh_noc_pkg::*;
#(
parameter type flit_payload_t = logic[256-1:0],
parameter VC_NUM = 1,
parameter VC_NUM_IDX_W = VC_NUM > 1 ? $clog2(VC_NUM) : 1,
parameter VC_DEPTH = 1,
`ifdef RETURN_CREDIT_AT_SA_STAGE
parameter VC_BUFFER_DEPTH = VC_DEPTH + 1, // need one more slot to handle push and pop at the same cycle when the fifo is full
`else
parameter VC_BUFFER_DEPTH = VC_DEPTH,
`endif
parameter VC_BUFFER_DEPTH_IDX_W = VC_BUFFER_DEPTH > 1 ? $clog2(VC_BUFFER_DEPTH) : 1
`ifdef VC_DATA_USE_DUAL_PORT_RAM
,
parameter VC_DPRAM_DEPTH = VC_NUM * VC_BUFFER_DEPTH,
parameter VC_DPRAM_DEPTH_IDX_W = VC_DPRAM_DEPTH > 1 ? $clog2(VC_DPRAM_DEPTH) : 1
`endif
)
(
// input from input port
input logic flit_v_i,
input flit_payload_t flit_i,
input flit_dec_t flit_dec_i,
input logic [VC_NUM_IDX_W-1:0] flit_vc_id_i,
// free vc credit sent to sender
output logic lcrd_v_o,
output logic [VC_ID_NUM_MAX_W-1:0] lcrd_id_o,
// output ctrl to local allocate
output logic [VC_NUM-1:0] vc_ctrl_head_vld_o,
output flit_dec_t [VC_NUM-1:0] vc_ctrl_head_o,
// output data to switch traversal
output flit_payload_t [VC_NUM-1:0] vc_data_head_o,
// input pop flit ctrl fifo (comes from SA stage)
input logic inport_read_enable_sa_stage_i,
input logic [VC_NUM_IDX_W-1:0] inport_read_vc_id_sa_stage_i, // use local sa result instead of vc assignment
`ifdef VC_DATA_USE_DUAL_PORT_RAM
input dpram_used_idx_t inport_read_dpram_idx_i,
`endif
// input pop flit ctrl fifo (comes from ST stage)
input logic inport_read_enable_st_stage_i,
input logic [VC_NUM_IDX_W-1:0] inport_read_vc_id_st_stage_i,
input logic clk,
input logic rstn
);
genvar i;
logic [VC_NUM-1:0] vc_data_tail_we;
flit_payload_t vc_data_din;
logic [VC_NUM-1:0] vc_data_enqueue_rdy;
logic [VC_NUM-1:0] vc_ctrl_tail_we;
flit_dec_t vc_ctrl_din;
logic [VC_NUM-1:0] vc_ctrl_enqueue_rdy;
logic [VC_NUM-1:0] vc_data_head_vld;
flit_payload_t [VC_NUM-1:0] vc_data_head;
logic [VC_NUM-1:0] vc_data_head_dequeue_vld;
logic [VC_NUM-1:0] vc_ctrl_head_vld;
flit_dec_t [VC_NUM-1:0] vc_ctrl_head;
logic [VC_NUM-1:0] vc_ctrl_head_dequeue_vld;
`ifdef VC_DATA_USE_DUAL_PORT_RAM
logic [VC_NUM-1:0][VC_BUFFER_DEPTH_IDX_W-1:0] vc_data_freelist_deq_per_vc_idx;
logic [VC_BUFFER_DEPTH_IDX_W-1:0] vc_data_freelist_deq_per_vc_idx_sel;
logic [VC_NUM-1:0] vc_data_freelist_deq_rdy;
logic [VC_NUM-1:0][VC_DPRAM_DEPTH_IDX_W-1:0] vc_data_freelist_deq_dpram_idx;
logic [VC_DPRAM_DEPTH_IDX_W-1:0] vc_data_freelist_deq_dpram_idx_sel;
logic [VC_NUM-1:0] vc_data_freelist_deq_vld;
logic [VC_BUFFER_DEPTH_IDX_W-1:0] vc_data_freelist_enq_per_vc_idx;
`endif
// enqueue
always_comb begin
vc_data_tail_we = '0;
vc_ctrl_tail_we = '0;
if(flit_v_i) begin
vc_data_tail_we[flit_vc_id_i] = 1'b1;
vc_ctrl_tail_we[flit_vc_id_i] = 1'b1;
end
end
assign vc_data_din = flit_i;
assign vc_ctrl_din.tgt_id = flit_dec_i.tgt_id;
assign vc_ctrl_din.src_id = flit_dec_i.src_id;
`ifdef ENABLE_TXN_ID
assign vc_ctrl_din.txn_id = flit_dec_i.txn_id;
`endif
assign vc_ctrl_din.look_ahead_routing = flit_dec_i.look_ahead_routing;
`ifdef USE_QOS_VALUE
assign vc_ctrl_din.qos_value = flit_dec_i.qos_value;
`endif
`ifdef VC_DATA_USE_DUAL_PORT_RAM
assign vc_ctrl_din.dpram_used_idx.dpram_idx = {{(VC_DPRAM_DEPTH_MAX_W-VC_DPRAM_DEPTH_IDX_W){1'b0}}, vc_data_freelist_deq_dpram_idx_sel};
assign vc_ctrl_din.dpram_used_idx.per_vc_idx = {{(VC_BUFFER_DEPTH_MAX_W-VC_BUFFER_DEPTH_IDX_W){1'b0}}, vc_data_freelist_deq_per_vc_idx_sel};
`endif
// dequeue
// ctrl dequeue at SA stage
always_comb begin
vc_ctrl_head_dequeue_vld = '0;
vc_ctrl_head_dequeue_vld[inport_read_vc_id_sa_stage_i] = inport_read_enable_sa_stage_i;
end
// data dequeue at ST stage
always_comb begin
vc_data_head_dequeue_vld = '0;
vc_data_head_dequeue_vld[inport_read_vc_id_st_stage_i] = inport_read_enable_st_stage_i;
end
// fifo module
`ifdef VC_DATA_USE_DUAL_PORT_RAM
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_data_freelist_deq_dpram_idx
assign vc_data_freelist_deq_dpram_idx[i] = VC_BUFFER_DEPTH * i + vc_data_freelist_deq_per_vc_idx[i];
end
endgenerate
assign vc_data_freelist_deq_vld = vc_data_tail_we;
onehot_mux
#(
.SOURCE_COUNT(VC_NUM ),
.DATA_WIDTH (VC_DPRAM_DEPTH_IDX_W )
)
onehot_mux_vc_data_freelist_deq_dpram_idx_sel_u (
.sel_i (vc_data_tail_we ),
.data_i (vc_data_freelist_deq_dpram_idx ),
.data_o (vc_data_freelist_deq_dpram_idx_sel )
);
onehot_mux
#(
.SOURCE_COUNT(VC_NUM ),
.DATA_WIDTH (VC_BUFFER_DEPTH_IDX_W )
)
onehot_mux_vc_data_freelist_deq_per_vc_idx_sel_u (
.sel_i (vc_data_tail_we ),
.data_i (vc_data_freelist_deq_per_vc_idx ),
.data_o (vc_data_freelist_deq_per_vc_idx_sel )
);
assign vc_data_freelist_enq_per_vc_idx = inport_read_dpram_idx_i.per_vc_idx[VC_BUFFER_DEPTH_IDX_W-1:0];
// free list
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_data_freelist
freelist
#(
.ENTRY_COUNT (VC_BUFFER_DEPTH)
)
VC_DATA_FREELIST_U (
.enq_vld_i (vc_ctrl_head_dequeue_vld [i] ),
.enq_tag_i (vc_data_freelist_enq_per_vc_idx ),
.deq_vld_i (vc_data_freelist_deq_vld [i] ),
.deq_tag_o (vc_data_freelist_deq_per_vc_idx [i] ),
.deq_rdy_o (vc_data_freelist_deq_rdy [i] ),
.flush_i ('0 ),
.clk (clk ),
.rst (~rstn )
);
end
endgenerate
// dpram
simple_dual_one_clock
#(
.ADDR_BITS (VC_DPRAM_DEPTH_IDX_W),
.DATA_BITS ($bits(flit_payload_t))
)
VC_DATA_DPRAM_U (
.clk (clk ),
.ena (flit_v_i ), // in flit write
.enb (inport_read_enable_sa_stage_i ), // out flit read
.wea (flit_v_i ),
.addra (vc_data_freelist_deq_dpram_idx_sel ),
.addrb (inport_read_dpram_idx_i.dpram_idx[VC_DPRAM_DEPTH_IDX_W-1:0] ),
.dia (vc_data_din ),
.dob (vc_data_head_o [0] )
);
`else
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_data_fifo
mp_fifo
#(
.payload_t (flit_payload_t),
.ENQUEUE_WIDTH (1),
.DEQUEUE_WIDTH (1),
.DEPTH (VC_BUFFER_DEPTH),
.MUST_TAKEN_ALL (1)
)
VC_DATA_U
(
// Enqueue
.enqueue_vld_i (vc_data_tail_we [i] ),
.enqueue_payload_i (vc_data_din ),
.enqueue_rdy_o (vc_data_enqueue_rdy [i] ),
// Dequeue
.dequeue_vld_o (vc_data_head_vld [i] ),
.dequeue_payload_o (vc_data_head [i] ),
.dequeue_rdy_i (vc_data_head_dequeue_vld [i] ),
.flush_i (1'b0 ),
.clk (clk),
.rst (~rstn)
);
assign vc_data_head_o [i] = vc_data_head [i];
end
endgenerate
`endif
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_ctrl_fifo
mp_fifo
#(
.payload_t (flit_dec_t),
.ENQUEUE_WIDTH (1),
.DEQUEUE_WIDTH (1),
.DEPTH (VC_DEPTH),
.MUST_TAKEN_ALL (1)
)
VC_CTRL_U
(
// Enqueue
.enqueue_vld_i (vc_ctrl_tail_we [i] ),
.enqueue_payload_i (vc_ctrl_din ),
.enqueue_rdy_o (vc_ctrl_enqueue_rdy [i] ),
// Dequeue
.dequeue_vld_o (vc_ctrl_head_vld [i] ),
.dequeue_payload_o (vc_ctrl_head [i] ),
.dequeue_rdy_i (vc_ctrl_head_dequeue_vld [i] ),
.flush_i (1'b0 ),
.clk (clk),
.rst (~rstn)
);
assign vc_ctrl_head_vld_o [i] = vc_ctrl_head_vld[i];
assign vc_ctrl_head_o [i] = vc_ctrl_head [i];
end
endgenerate
// free vc credit sent to sender
`ifdef RETURN_CREDIT_AT_SA_STAGE
assign lcrd_v_o = inport_read_enable_sa_stage_i;
assign lcrd_id_o = {{(VC_ID_NUM_MAX_W-VC_NUM_IDX_W){1'b0}}, inport_read_vc_id_sa_stage_i};
`else
assign lcrd_v_o = inport_read_enable_st_stage_i;
assign lcrd_id_o = {{(VC_ID_NUM_MAX_W-VC_NUM_IDX_W){1'b0}}, inport_read_vc_id_st_stage_i};
`endif
`ifndef SYNTHESIS
`ifdef COMMON_QOS_EXTRA_RT_VC
// assert property(@(posedge clk)disable iff(~rstn) (flit_v_i == 1'b1) |-> (((flit_vc_id_i < QOS_VC_NUM_PER_INPUT) && (flit_dec_i.qos_value == 15))))
// else $error("noc_input_port: flit with highest QoS value goes into common VC, txn_id: 0x%x, vc_id: %d, flit_v_i=%d", flit_dec_i.txn_id, flit_vc_id_i, flit_v_i);
// assert property(@(posedge clk)disable iff(~rstn) (flit_v_i == 1'b1) |-> (((flit_vc_id_i >= QOS_VC_NUM_PER_INPUT) && (flit_dec_i.qos_value < 15))))
// else begin $display("noc_input_port: flit with lower QoS value goes into rt VC, txn_id: 0x%x, vc_id: %d, flit_v_i=%d", flit_dec_i.txn_id, flit_vc_id_i, flit_v_i); $fatal(); end
generate
for(i = 0; i < QOS_VC_NUM_PER_INPUT; i++) begin
assert property(@(posedge clk)disable iff(~rstn) (vc_ctrl_head_vld[i]) |-> (vc_ctrl_head[i].qos_value == 15))
`ifdef ENABLE_TXN_ID
else $fatal("noc_input_vc: rt VC has flit with lower QoS value, txn_id: 0x%x", vc_ctrl_head[i].txn_id);
`else
else $fatal("noc_input_vc: rt VC has flit with lower QoS value");
`endif
end
for(i = QOS_VC_NUM_PER_INPUT; i < VC_NUM; i++) begin
assert property(@(posedge clk)disable iff(~rstn) (vc_ctrl_head_vld[i]) |-> (vc_ctrl_head[i].qos_value != 15))
`ifdef ENABLE_TXN_ID
else $fatal("noc_input_vc: common VC has flit with highest QoS value, txn_id: 0x%x", vc_ctrl_head[i].txn_id);
`else
else $fatal("noc_input_vc: common VC has flit with highest QoS value");
`endif
end
endgenerate
`endif
`endif
endmodule