initial commit for open source NoC IP

This commit is contained in:
Zexin Fu
2023-11-26 14:59:34 +01:00
commit 6ba3d27334
122 changed files with 14907 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

59
doc/noc_intf.md Normal file
View File

@@ -0,0 +1,59 @@
# 1 NoC to local device and SoC intf
## 1.1 Ports
| Name | Direction | Type | Description |
| :------------------------------ | :-------- | :------------------------------------ | :------------------------------- |
| clk | in | wire logic | |
| rstn | in | wire logic | |
| rx_flit_pend_local_port_0 | in | wire [CHANNEL_NUM-1:0] logic | local port input |
| rx_flit_v_local_port_0 | in | wire [CHANNEL_NUM-1:0] logic | local port input |
| rx_flit_local_port_0 | in | wire [CHANNEL_NUM-1:0] flit_payload_t | local port input |
| rx_flit_send_ready_local_port_0 | out | [CHANNEL_NUM-1:0] logic | credit based flow control signal |
| tx_flit_pend_local_port_0 | out | [CHANNEL_NUM-1:0] logic | local port output |
| tx_flit_v_local_port_0 | out | [CHANNEL_NUM-1:0] logic | local port output |
| tx_flit_local_port_0 | out | [CHANNEL_NUM-1:0] flit_payload_t | local port output |
| tx_flit_rec_ready_local_port_0 | in | wire [CHANNEL_NUM-1:0] logic | credit based flow control signal |
| node_id_x_ths_hop_i | in | wire [NodeID_X_Width-1:0] logic | router position |
| node_id_y_ths_hop_i | in | wire [NodeID_Y_Width-1:0] logic | router position |
## 1.2 Diagram
![rrv64_router_intf](./image/rrv64_noc_intf_to_soc.svg)
# 2 NoC Router intf
## 2.1 Ports
| Name | Direction | Type | Description |
| :------------------------------ | :-------- | :-------------------------------------------------------------------------- | :------------------------------- |
| clk | in | wire logic | |
| rstn | in | wire logic | |
| rx_flit_pend_local_port_0 | in | wire [CHANNEL_NUM-1:0] logic | local port input |
| rx_flit_v_local_port_0 | in | wire [CHANNEL_NUM-1:0] logic | local port input |
| rx_flit_local_port_0 | in | wire [CHANNEL_NUM-1:0] flit_payload_t | local port input |
| rx_flit_send_ready_local_port_0 | out | [CHANNEL_NUM-1:0] logic | credit based flow control signal |
| tx_flit_pend_local_port_0 | out | [CHANNEL_NUM-1:0] logic | local port output |
| tx_flit_v_local_port_0 | out | [CHANNEL_NUM-1:0] logic | local port output |
| tx_flit_local_port_0 | out | [CHANNEL_NUM-1:0] flit_payload_t | local port output |
| tx_flit_rec_ready_local_port_0 | in | wire [CHANNEL_NUM-1:0] logic | credit based flow control signal |
| rx_flit_pend_i | in | wire [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] logic | router port input |
| rx_flit_v_i | in | wire [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] logic | router port input |
| rx_flit_i | in | wire [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] flit_payload_t | router port input |
| rx_flit_vc_id_i | in | wire [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] [VC_ID_NUM_MAX_W-1:0] logic | router port input |
| rx_flit_look_ahead_routing_i | in | wire [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] rvh_noc_pkg::io_port_t | router port input |
| tx_flit_pend_o | out | [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] logic | router port output |
| tx_flit_v_o | out | [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] logic | router port output |
| tx_flit_o | out | [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] flit_payload_t | router port output |
| tx_flit_vc_id_o | out | [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] [VC_ID_NUM_MAX_W-1:0] logic | router port output |
| tx_flit_look_ahead_routing_o | out | [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] rvh_noc_pkg::io_port_t | router port output |
| rx_lcrd_v_o | out | [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] logic | credit based flow control signal |
| rx_lcrd_id_o | out | [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] [VC_ID_NUM_MAX_W-1:0] logic | credit based flow control signal |
| tx_lcrd_v_i | in | wire [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] logic | credit based flow control signal |
| tx_lcrd_id_i | in | wire [CHANNEL_NUM-1:0] [ROUTER_PORT_NUMBER-1:0] [VC_ID_NUM_MAX_W-1:0] logic | credit based flow control signal |
| node_id_x_ths_hop_i | in | wire [NodeID_X_Width-1:0] logic | router position |
| node_id_y_ths_hop_i | in | wire [NodeID_Y_Width-1:0] logic | router position |
## 2.2 Diagram
![rrv64_noc_router_intf](./image/rrv64_noc_router_intf.svg)

538
doc/noc_spec.md Normal file
View File

@@ -0,0 +1,538 @@
# NoC Spec
## 1 Interface
This NoC uses CHI compatible interface. It defines 4 channels for different kinds of messages. Each channel is implemented in a specific physical sub-networks, so the NoC has 4 sub-networks.
Each router can be configured to have 0~4 local port(s).
### 1.1 Channel
In this specification, the Link layer provides a set of channels for flit communication.
Each channel has a defined flit format that has multiple fields and some of the field widths have multiple possible values. In some cases, the defined flit format can be used on both an inbound and an outbound channel.
Table 1 shows the channels, and the mapping onto the Request Node, Home Node and Subordinate Node component channels.
| Channel | Description | Usage | RN Channel | HN Channel | SN Channel |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ---------- | ---------- | ---------- |
| REQ | The request channel transfers flits associated with request messages such as Read requests and Write requests. | Requests from RN to HN | TXREQ | RXREQ | - |
| | | Requests from RN to SN | TXREQ | - | RXREQ |
| | | Requests from HN to SN | - | TXREQ | RXREQ |
| RSP | The response channel transfers flits associated with response messages that do not have a data payload such as write completion messages. | Responses from SN to HN | - | RXRSP | TXRSP |
| | | Responses from SN to RN | RXRSP | | TXRSP |
| | | Responses from HN to RN | RXRSP | TXRSP | - |
| | | Snoop Response and Completion Acknowledge from snoopee RN to HN | TXRSP | RXRSP | - |
| SNP | The snoop channel transfers flits associated with Snoop Request messages. | Snoop Requests from HN to snoopee RN | RXSNP | TXSNP | - |
| DAT | The data channel transfers flits associated with protocol messages that have a data payload such as read completion and WriteData messages. | WriteData, and Snoop response data from an RN to HN | TXDAT | RXDAT | - |
| | | WriteData from an RN to SN | TXDAT | - | RXDAT |
| | | WriteData from an HN to SN | - | TXDAT | RXDAT |
| | | Read data from SN to RN | RXDAT | - | TXDAT |
| | | Read data from SN to HN | - | RXDAT | TXDAT |
| | | Read data from HN to RN | RXDAT | TXDAT | - |
Table 2 shows the channels of Request Node, Home Node and Subordinate Node component have.
| Component | TXREQ | RXREQ | TXRSP | RXRSP | TXSNP | RXSNP | TXDAT | RXDAT |
| --------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- |
| RN | Y | - | Y | Y | - | Y | Y | Y |
| HN | Y | Y | Y | Y | Y | - | Y | Y |
| SN | - | Y | Y | - | - | - | Y | Y |
// TODO: RN need RXREQ to receive core to core interrupt
### 1.2 Port
Table 3 shows the links of each router (and channel) port.
| Name | Direction | Type | Description |
| :--------------------------- | :-------- | :----------------------------------------------------- | :------------------------------------------------- |
| rx_flit_pend_i | in | wire [INPUT_PORT_NUM-1:0] logic | input from other router or local port // N,S,E,W,L |
| rx_flit_v_i | in | wire [INPUT_PORT_NUM-1:0] logic | |
| rx_flit_i | in | wire [INPUT_PORT_NUM-1:0] flit_payload_t | |
| rx_flit_vc_id_i | in | wire [INPUT_PORT_NUM-1:0] [VC_ID_NUM_MAX_W-1:0] logic | |
| rx_flit_look_ahead_routing_i | in | wire [INPUT_PORT_NUM-1:0] rvh_noc_pkg::io_port_t | |
| tx_flit_pend_o | out | [OUTPUT_PORT_NUM-1:0] logic | output to other router or local port // N,S,E,W,L |
| tx_flit_v_o | out | [OUTPUT_PORT_NUM-1:0] logic | |
| tx_flit_o | out | [OUTPUT_PORT_NUM-1:0] flit_payload_t | |
| tx_flit_vc_id_o | out | [OUTPUT_PORT_NUM-1:0] [VC_ID_NUM_MAX_W-1:0] logic | |
| tx_flit_look_ahead_routing_o | out | [OUTPUT_PORT_NUM-1:0] rvh_noc_pkg::io_port_t | |
| rx_lcrd_v_o | out | [INPUT_PORT_NUM-1:0] logic | free VC credit sent to sender |
| rx_lcrd_id_o | out | [INPUT_PORT_NUM-1:0] [VC_ID_NUM_MAX_W-1:0] logic | |
| tx_lcrd_v_i | in | wire [OUTPUT_PORT_NUM-1:0] logic | free VC credit received from receiver |
| tx_lcrd_id_i | in | wire [OUTPUT_PORT_NUM-1:0] [VC_ID_NUM_MAX_W-1:0] logic | |
| node_id_x_ths_hop_i | in | wire [NodeID_X_Width-1:0] logic | router addr |
| node_id_y_ths_hop_i | in | wire [NodeID_Y_Width-1:0] logic | |
| clk | in | wire logic | |
| rstn | in | wire logic | |
### 1.3 Flit packet definitions
Refer to IHI0050F_amba_chi_architecture_spec Flit packet definitions. This part illustrates the definition of the variable length portion of the CHI flit for this design.
#### 1.3.1 Request flit
| Field | Field width | Comment |
| ----------------------- | --------------------------------- | ----------------------------------------- |
| QoS | 4 | - |
| TgtID | 7 | Width determined by NodeID_Width |
| SrcID | 7 | Width determined by NodeID_Width |
| TxnID | 12 | - |
| ReturnNID or | 7 | Used for DMT |
| StashNID or | | Used in Stash transactions |
| {(NodeID_Width - 7)'b0, | | SBZ |
| SLCRepHint[6:0]} | | Used in cache line replacement algorithms |
| StashNIDValid | 1 | Used in Stash transactions |
| Endian | | Used in Atomic transactions |
| Deep | | Used in CleanSharedPersist* transactions |
| ReturnTxnID[11:0] | 12 | Used for DMT |
| {6'b0, | | SBZ |
| StashLPIDValid, | | Used in Stash transactions |
| StashLPID[4:0]} | | Used in Stash transactions |
| Opcode | 7 | - |
| Size | 3 | - |
| Addr | RAW = 44 to 52 | Width determined by Req_Addr_Width (RAW) |
| NS | 1 | - |
| NSE | 1 | - |
| LikelyShared | 1 | - |
| AllowRetry | 1 | - |
| Order | 2 | - |
| PCrdType | 4 | - |
| MemAttr | 4 | - |
| SnpAttr or | 1 | - |
| DoDWT | | Used for DWT |
| PGroupID[7:0] or | 8 | Used in Persistent CMO transactions |
| StashGroupID[7:0] or | | Used in the StashOnceSep transaction |
| TagGroupID[7:0] or | | Used for Memory Tagging |
| {3'b0, | | SBZ |
| LPID[4:0]} | | - |
| Excl | 1 | Used in Exclusive transactions |
| SnoopMe | | Used in Atomic transactions |
| CAH | | Used in CopyBack Write transactions |
| ExpCompAck | 1 | - |
| TagOp | 2 | - |
| TraceTag | 1 | - |
| MPAM | M = 0 | No MPAM bus |
| | M = 12 | - |
| PBHA | PB = 0 | No PBHA bus |
| | PB = 4 | - |
| RSVDC | Y = 0 | No RSVDC bus |
| | Y = 4, 8, 12, 16, 24, 32 | - |
| Total | R = (88 + RAW + Y + M + PB) = 132 | RAW = 44, Y = 0, M = 0, PB = 0 |
#### 1.3.2 Response flit
| Field | Field width | Comment |
| --------------------- | ----------- | ----------------------------------- |
| QoS | 4 | - |
| TgtID | 7 | Width determined by NodeID_Width |
| SrcID | 7 | Width determined by NodeID_Width |
| TxnID | 12 | - |
| Opcode | 5 | - |
| RespErr | 2 | - |
| Resp | 3 | - |
| FwdState[2:0] or | 3 | Used for DCT |
| DataPull[2:0] | | Used in Stash transactions |
| CBusy | 3 | - |
| DBID[11:0] or | 12 | - |
| {4'b0, | | SBZ |
| PGroupID[7:0]} or | | Used in Persistent CMO transactions |
| {4'b0, | | SBZ |
| StashGroupID[7:0]} or | | Used in Stash transactions |
| {4'b0, | | SBZ |
| TagGroupID[7:0]} | | Used for Memory Tagging |
| PCrdType | 4 | - |
| TagOp | 2 | - |
| TraceTag | 1 | - |
| Total | T = 65 | - |
#### 1.3.3 Snoop flit
| Field | Field width | Comment |
| ---------------------- | ----------------------- | -------------------------------- |
| QoS | 4 | - |
| SrcID | 7 | Width determined by NodeID_Width |
| TxnID | 12 | - |
| FwdNID or | 7 | Width determined by NodeID_Width |
| {(NodeID_Width - 4)'0, | | |
| PBHA[3:0]} | | |
| FwdTxnID[11:0] or | 12 | Used for DCT |
| {6'b0, | | SBZ |
| StashLPIDValid | | Used in Stash transactions |
| StashLPID[4:0]} or | | Used in Stash transactions |
| {4'b0, | | SBZ |
| VMIDExt[7:0]} | | Used in DVM transactions |
| Opcode | 5 | - |
| Addr | SAW = 41 to 49 | Req_Addr_Width - 3 |
| NS | 1 | - |
| NSE | 1 | - |
| DoNotGoToSD | 1 | - |
| RetToSrc | 1 | - |
| TraceTag | 1 | - |
| MPAM | M = 0 | No MPAM bus |
| | M = 11 | - |
| Total | S = (52 + SAW + M) = 93 | SAW = 41, M = 0 |
#### 1.3.4 Data flit
| Field | Field width | Comment |
| ----------------------- | ----------------------------- | ----------------------------------- |
| QoS | 4 | - |
| TgtID | 7 | Width determined by NodeID_Width |
| SrcID | 7 | Width determined by NodeID_Width |
| TxnID | 12 | - |
| HomeNID or | 7 | Width determined by NodeID_Width |
| {(NodeID_Width - 4)'b0, | | |
| PBHA[3:0]} | | |
| Opcode | 4 | - |
| RespErr | 2 | - |
| Resp | 3 | - |
| DataSource[4:0] or | 5 | Indicates Data source in a response |
| {2'b0, | | SBZ |
| FwdState[2:0]} or | | Used for DCT |
| {2'b0, | | SBZ |
| DataPull[2:0]} | | Used in Stash transactions |
| CBusy | 3 | - |
| DBID[11:0] | 12 | - |
| CCID | 2 | - |
| DataID | 2 | - |
| TagOp | 2 | - |
| Tag | DW/32 = 4, 8, 16 | - |
| TU | DW/128 = 1, 2, 4 | - |
| TraceTag | 1 | - |
| CAH | 1 | - |
| RSVDC | Y = 0 | No RSVDC bus |
| | Y = 4, 8, 12, 16, 24, 32 | - |
| BE | DW/8 = 16, 32, 64 | - |
| Data | DW = 128, 256, 512 | DW = Data bus width |
| DataCheck (DC) | 0 or DW/8 = 16, 32, 64 | - |
| Poison (P) | 0 or DW/64 = 2, 4, 8 | - |
| Total | D = (223 to 235) + Y + DC + P | DW = 128 bit Data |
| | D = (372 to 384) + Y + DC + P | DW = 256 bit Data |
| | D = (670 to 682) + Y + DC + P | DW = 512 bit Data |
| | D = 223 + Y + DC + P = 223 | DW = 128, Y = 0, DC = 0, P = 0 |
| | D = 372 + Y + DC + P = 372 | DW = 128, Y = 0, DC = 0, P = 0 |
## 2 Parameters and Configuations
There are some parameters and configuations to set.
### 2.1 NoC Configuations
Table 4 shows configuations for overall NoC.
| Name | Type | Default Value | Description |
| :----------------------------- | :----- | :------------ | :------------------------------------------------------------------------------------ |
| HAVE_LOCAL_PORT | define | defined | The router have local port(s) |
| LOCAL_PORT_NUM_2 | define | undefined | The router have >= 2 local ports |
| LOCAL_PORT_NUM_3 | define | undefined | The router have >= 3 local ports |
| LOCAL_PORT_NUM_4 | define | undefined | The router have 4 local ports |
| VC_DATA_USE_DUAL_PORT_RAM | define | undefined | Use unified dual-port ram per input port VC data buffer (default: separate dff fifo) |
| RETURN_CREDIT_AT_SA_STAGE | define | undefined | Reture credit to send at sa stage rather than st atage |
| ALLOW_SAME_ROUTER_L2L_TRANSFER | define | undefined | Allow local ports in same router transfer flit, at least 2 local ports |
| COMMON_QOS | define | undefined | QoS, no special VC, all VC head flits ranked by QoS value |
| COMMON_QOS_EXTRA_RT_VC | define | defined | QoS, add special VC for highest priority flits, all VC head flits ranked by QoS value |
### 2.2 NoC Parameters
Table 5 shows parameters for overall NoC.
| Name | Type | Default Value | Description |
| :------------------------ | :--- | :---------------------------------------------------------------------------------- | :------------------------------------------- |
| CHANNEL_NUM | int | 4 | 4 channels: req, resp, data, snp |
| NodeID_X_Width | int | 2 | |
| NodeID_Y_Width | int | 3 | |
| NodeID_Device_Port_Width | int | 2 | |
| NodeID_Device_Id_Width | int | 1 | |
| NodeID_Width | int | NodeID_X_Width + NodeID_Y_Width + NodeID_Device_Port_Width + NodeID_Device_Id_Width | |
| TxnID_Width | int | 12 | |
| QoS_Value_Width | int | 4 | |
| FLIT_LENGTH | int | 256 | per channel refer to flit definitation |
| INPUT_PORT_NUMBER | int | 5 | |
| INPUT_PORT_NUMBER_IDX_W | int | INPUT_PORT_NUMBER > 1 ? $clog2(INPUT_PORT_NUMBER) : 1 | |
| OUTPUT_PORT_NUMBER | int | 5 | |
| ROUTER_PORT_NUMBER | int | 4 | 4 ports connect to other routers: N, S, E, W |
| LOCAL_PORT_NUMBER | int | INPUT_PORT_NUMBER-4 | Ports connect to local device(s) |
| QOS_VC_NUM_PER_INPUT | int | 1 | |
| VC_ID_NUM_MAX | int | (CHANNEL_NUM-1)+LOCAL_PORT_NUMBER+QOS_VC_NUM_PER_INPUT | |
| VC_ID_NUM_MAX_W | int | VC_ID_NUM_MAX > 1 ? $clog2(VC_ID_NUM_MAX) : 1 | |
| SA_GLOBAL_INPUT_NUM_MAX | int | (CHANNEL_NUM-1)+LOCAL_PORT_NUMBER | |
| SA_GLOBAL_INPUT_NUM_MAX_W | int | SA_GLOBAL_INPUT_NUM_MAX > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_MAX) : 1 | |
| VC_DEPTH_MAX | int | 4 | |
| VC_DPRAM_DEPTH_MAX | int | VC_ID_NUM_MAX * VC_DEPTH_MAX | |
| VC_BUFFER_DEPTH_MAX_W | int | VC_DEPTH_MAX > 1 ? $clog2(VC_DEPTH_MAX) : 1 | |
| VC_DPRAM_DEPTH_MAX_W | int | VC_DPRAM_DEPTH_MAX > 1 ? $clog2(VC_DPRAM_DEPTH_MAX) : 1 | |
### 2.3 Router Parameters
Table 6 shows parameters for each router instance, the default values are likely to be overwrite by NoC parameters.
| Name | Type | Default Value | Description |
| :-------------------------- | :------------- | :------------------------------------------------------------ | :---------------------- |
| INPUT_PORT_NUM | int | 5 | |
| OUTPUT_PORT_NUM | int | 5 | |
| LOCAL_PORT_NUM | int | INPUT_PORT_NUM-4 | |
| flit_payload_t | flit_payload_t | logic[256-1:0] | |
| QOS_VC_NUM_PER_INPUT | int | 0 | |
| VC_NUM_INPUT_N | int | 1+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_INPUT_S | int | 1+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_INPUT_E | int | 3+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_INPUT_W | int | 3+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_INPUT_L | int | 4+LOCAL_PORT_NUM-1+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_INPUT_N_IDX_W | int | VC_NUM_INPUT_N > 1 ? $clog2(VC_NUM_INPUT_N) : 1 | |
| VC_NUM_INPUT_S_IDX_W | int | VC_NUM_INPUT_S > 1 ? $clog2(VC_NUM_INPUT_S) : 1 | |
| VC_NUM_INPUT_E_IDX_W | int | VC_NUM_INPUT_E > 1 ? $clog2(VC_NUM_INPUT_E) : 1 | |
| VC_NUM_INPUT_W_IDX_W | int | VC_NUM_INPUT_W > 1 ? $clog2(VC_NUM_INPUT_W) : 1 | |
| VC_NUM_INPUT_L_IDX_W | int | VC_NUM_INPUT_L > 1 ? $clog2(VC_NUM_INPUT_L) : 1 | |
| SA_GLOBAL_INPUT_NUM_N | int | 3+LOCAL_PORT_NUM | |
| SA_GLOBAL_INPUT_NUM_S | int | 3+LOCAL_PORT_NUM | |
| SA_GLOBAL_INPUT_NUM_E | int | 1+LOCAL_PORT_NUM | |
| SA_GLOBAL_INPUT_NUM_W | int | 1+LOCAL_PORT_NUM | |
| SA_GLOBAL_INPUT_NUM_L | int | 4+LOCAL_PORT_NUM-1 | |
| SA_GLOBAL_INPUT_NUM_N_IDX_W | int | SA_GLOBAL_INPUT_NUM_N > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_N) : 1 | |
| SA_GLOBAL_INPUT_NUM_S_IDX_W | int | SA_GLOBAL_INPUT_NUM_S > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_S) : 1 | |
| SA_GLOBAL_INPUT_NUM_E_IDX_W | int | SA_GLOBAL_INPUT_NUM_E > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_E) : 1 | |
| SA_GLOBAL_INPUT_NUM_W_IDX_W | int | SA_GLOBAL_INPUT_NUM_W > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_W) : 1 | |
| SA_GLOBAL_INPUT_NUM_L_IDX_W | int | SA_GLOBAL_INPUT_NUM_L > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_L) : 1 | |
| VC_NUM_OUTPUT_N | int | 1+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_OUTPUT_S | int | 1+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_OUTPUT_E | int | 3+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_OUTPUT_W | int | 3+LOCAL_PORT_NUM+QOS_VC_NUM_PER_INPUT | |
| VC_NUM_OUTPUT_L | int | 1 | VC number in local node |
| VC_NUM_OUTPUT_N_IDX_W | int | VC_NUM_OUTPUT_N > 1 ? $clog2(VC_NUM_OUTPUT_N) : 1 | |
| VC_NUM_OUTPUT_S_IDX_W | int | VC_NUM_OUTPUT_S > 1 ? $clog2(VC_NUM_OUTPUT_S) : 1 | |
| VC_NUM_OUTPUT_E_IDX_W | int | VC_NUM_OUTPUT_E > 1 ? $clog2(VC_NUM_OUTPUT_E) : 1 | |
| VC_NUM_OUTPUT_W_IDX_W | int | VC_NUM_OUTPUT_W > 1 ? $clog2(VC_NUM_OUTPUT_W) : 1 | |
| VC_NUM_OUTPUT_L_IDX_W | int | VC_NUM_OUTPUT_L > 1 ? $clog2(VC_NUM_OUTPUT_L) : 1 | |
| VC_DEPTH_INPUT_N | int | 2 | |
| VC_DEPTH_INPUT_S | int | 2 | |
| VC_DEPTH_INPUT_E | int | 2 | |
| VC_DEPTH_INPUT_W | int | 2 | |
| VC_DEPTH_INPUT_L | int | 2 | |
| VC_DEPTH_OUTPUT_N | int | VC_DEPTH_INPUT_N | |
| VC_DEPTH_OUTPUT_S | int | VC_DEPTH_INPUT_S | |
| VC_DEPTH_OUTPUT_E | int | VC_DEPTH_INPUT_E | |
| VC_DEPTH_OUTPUT_W | int | VC_DEPTH_INPUT_W | |
| VC_DEPTH_OUTPUT_L | int | VC_DEPTH_INPUT_L | |
| VC_DEPTH_OUTPUT_N_COUNTER_W | int | $clog2(VC_DEPTH_OUTPUT_N + 1) | |
| VC_DEPTH_OUTPUT_S_COUNTER_W | int | $clog2(VC_DEPTH_OUTPUT_S + 1) | |
| VC_DEPTH_OUTPUT_E_COUNTER_W | int | $clog2(VC_DEPTH_OUTPUT_E + 1) | |
| VC_DEPTH_OUTPUT_W_COUNTER_W | int | $clog2(VC_DEPTH_OUTPUT_W + 1) | |
| VC_DEPTH_OUTPUT_L_COUNTER_W | int | $clog2(VC_DEPTH_OUTPUT_L + 1) | |
## 3 Topology
Configurable 2D mesh topology, the default topology in `tb_mesh.sv` and `top_mesh_syn.sv` is a 3x3 2D mesh.
```
NoC Topology
(0,2) -- (1,2) -- (2,2)
| \ | \ | \
| rn5 | rn6 | rn7
(0,1) -- (1,1) -- (2,1)
| \ | \ | \
| rn2 | rn3 | rn4
(0,0) -- (1,0) -- (2,0)
\ \ \
rn0 hn0 rn1
```
## 4 Routing
Use X-Y routing:
Routing directions are referred to by the mesh port that the NoC routes the flit through. For
example, if the NoC routes the flit northwards, then the flit is sent through the north mesh port.
If there is a mismatch between the target NoC XID and the current NoC XID, then the NoC uses
the following rule to decide the routing direction:
* If target NoC XID > current NoC XID, then route eastwards
* Otherwise, route westwards
If the target NoC XID and the current NoC XID match, then the flit routing components are
compared against the YID of the NoC. If YIDs do not match, then the NoC uses the following rule
to decide the routing direction:
* If target NoC YID > current NoC YID, then route northwards
* Otherwise, route southwards
If the target NoC XID and YID match the current NoC XID and YID, then the flit has reached the
target NoC. At this point, the flit is downloaded to the target device.
## 5 Flow Control
A flow-control mechanism by which the transmitting device uses link layer credits to send
NoC flits one credit per flit. In turn, the receiving device sends these credits back to the
transmitting device, one at a time, when it is done processing each flit to allow for subsequent
flit transfers.
## 6 Router Microarchitecture
![alt router_microarchitecture](./image/router_microarchitecture.drawio.png)
Features:
* 2-stage pipeline.
* credited-based flow control.
* Vitrual channel(VC) for QoS and switch allocation efficiency.
* The allocation priority of VC is based on look-ahead routing result.
* 2-level switch allocation, based on fair round-robin algorithm.
* Look-ahead routing for next hop router for better timing and VC allocation.
* Decoupled VC selection from VC allocation for better timing.
### 6.1 Routing Algorithm
Use XY routing, the routing result is calculated one hop ahead, which is look-ahead routing
#### 6.1.1 XY Routing
Flits firstly go through X axis, then go though Y axis:
```
1st phase: Assign next address
2nd phase: Define new Next-port
```
#### 6.1.2 Look-ahead Routing
The routing result is calculated at last hop router or local onput port, to achieve better timing and VC allocation.
### 6.2 Input Port
#### 6.2.1 Input VC
1. Use Fixed VC Assignment with Dynamic VC Allocation (FVADA) [paper](https://sites.pitt.edu/~juy9/papers/Yi-HPCA10.pdf) VC allocation mechanism. The input VCs are associated with the flits' output port.
2. XY routing, so some of the output port are not used in some input ports.
* VC in each input port:
| input port | input port id | VC id | priority be assigned output port | output port id |
| ---------- | ------------- | ----- | -------------------------------- | -------------- |
| N | 0 | 0 | S | 1 |
| | | 1 | L | 4 |
| S | 1 | 0 | N | 0 |
| | | 1 | L | 4 |
| E | 2 | 0 | N | 0 |
| | | 1 | S | 1 |
| | | 2 | W | 3 |
| | | 3 | L | 4 |
| W | 3 | 0 | N | 0 |
| | | 1 | S | 1 |
| | | 2 | E | 2 |
| | | 3 | L | 4 |
| L | 4 | 0 | N | 0 |
| | | 1 | S | 1 |
| | | 2 | E | 2 |
| | | 3 | W | 3 |
### 6.3 Switch Allocation
Use two-stage input-port-first allocation.
#### 6.3.1 Local allocation
Use round-robin arbition. As XY routing, the local arbiters' input port number are not the same.
#### 6.3.2 Global allocation
Use round-robin arbition. As XY routing, the global arbiters' input port number are not the same.
* input output port mapping for each SA global arbiter:
| output port | global SA arbiter connected input ports | global SA arbiter connected input ports id | next hop input port |
| ----------- | --------------------------------------- | ------------------------------------------ | ------------------- |
| N | S | 1 | S |
| | E | 2 | |
| | W | 3 | |
| | L | 4 | |
| S | N | 0 | N |
| | E | 2 | |
| | W | 3 | |
| | L | 4 | |
| E | W | 3 | W |
| | L | 4 | |
| W | E | 2 | E |
| | L | 4 | |
| L | N | 0 | - |
| | S | 1 | |
| | E | 2 | |
| | W | 3 | |
## 7 QoS Support
Features:
1. Each flit supports a flit QoS value of 0-15, and the larger the value, the higher the priority.
2. Perform fair round robin arbitration on flits with the same priority.
3. If an input port is not sent out after several cycles by the flit selected by round robin, another flit with the same priority will participate in the arbitration, reducing head of line blocking and improving arbitration efficiency.
4. Support to put the flits that need the same router output port on the same virtual channel first, reduce head of line blocking, and improve arbitration efficiency.
5. Supports assigning a dedicated virtual channel to the flit with the highest QoS priority to ensure the lowest latency and can be used for real-time applications.
6. The QoS value of each flit is given by the request node when sending req. Currently it is a fixed value given according to the flit type. In the future, it is planned to support dynamic QoS value setting strategies based on transaction latency and requester throughput respectively.
### 7.1 Common QoS
No special VC, all VC head flits ranked by QoS value.
* no extra real-time VC;
* no bypass arbiter for real-time VC;
* all VC involve QoS value compare.
### 7.2 Common QoS + extra real-time VC QoS
Add special VC for highest priority flits, all VC head flits ranked by QoS value.
* have extra real-time VC;
* no bypass arbiter for real-time VC;
* the real-time VC always win the local sa, and the local sa rr point should not be updated
* the real-time VC join global sa as common QoS, as it has highest QoS value, it can beat flits with other QoS value;
* all VC involve QoS value compare.
## 8 System Memory Map (TODO)
### 8.1 Home Node to Memory Channel
#### 8.1.1 Range-based: non-hashed SN target ID
use reg to direct assign a range of memory address to specific memory channel or io device
#### 8.1.2 Range-based: hashed SN target ID
##### 8.1.2.1 UMA mode
use reg to assign a range of memory address, for 4 home node, 4 memory channel:
1. use PA[7:6] to interleave among memony channels (cache line interleave)
2. for unbalanced memory size among memory channels, use to smallest size channel to interleave, and other memory use direct assign
| PA bit num | msb | ... | 8 | 7 | 6 | 5 - 0 |
| ----------------- | --- | --- | --- | --- | --- | ----------- |
| Interleaving type | | | | CH | CH | line offest |
CH: Channel interleaving
##### 8.1.2.2 NUMA mode
use reg to assign a range of memory address, for 4 home node, 4 memory channel:
1. use PA[6] to interleave among memony channels (cache line interleave)
2. use PA[msb] to interleave among nodes
3. for unbalanced memory size among memory channels, use to smallest size channel to interleave, and other memory use direct assign
| PA bit num | msb | ... | 8 | 7 | 6 | 5 - 0 |
| ----------------- | --- | --- | --- | --- | --- | ----------- |
| Interleaving type | ND | | | CH | CH | line offest |
ND: Node interleaving, CH: Channel interleaving
### 8.2 Request Node to Home Node
#### 8.2.1 Non-hashed regions
A given memory partition is assigned to an individual targetID (non-hashed), for:
1. PLIC(highest priority);
2. IO space;
3. Directly assigned memory range
#### 8.2.2 Hashed memory region or non-hashed mode of hashed memory region
##### 8.2.2.1 NUCA mode
use reg to assign a range of memory address for one core/cluster to its nearest home node,
it can be configured at reset.

99
doc/router_spec.md Normal file
View File

@@ -0,0 +1,99 @@
# Router Spec
# 1 Routing Algorithm
Use XY routing, the routing result is calculated one hop ahead, which is look-ahead routing
## 1.1 XY Routing
Flits firstly go through X axis, then go though Y axis:
```
1st phase: Assign next address
2nd phase: Define new Next-port
```
## 1.2 Look-ahead Routing
# 2 Input Port
## 2.1 Input VC
1. Use Fixed VC Assignment with Dynamic VC Allocation (FVADA) [paper](https://sites.pitt.edu/~juy9/papers/Yi-HPCA10.pdf) vc allocation mechanism. The input VCs are associated with the flits' output port.
2. XY routing, so some of the output port are not used in some input ports.
* VC in each input port:
| input port | input port id | vc id | assigned output port | output port id |
| ---------- | ------------- | ----- | -------------------- | -------------- |
| N | 0 | 0 | S | 1 |
| | | 1 | L | 4 |
| S | 1 | 0 | N | 0 |
| | | 1 | L | 4 |
| E | 2 | 0 | N | 0 |
| | | 1 | S | 1 |
| | | 2 | W | 3 |
| | | 3 | L | 4 |
| W | 3 | 0 | N | 0 |
| | | 1 | S | 1 |
| | | 2 | E | 2 |
| | | 3 | L | 4 |
| L | 4 | 0 | N | 0 |
| | | 1 | S | 1 |
| | | 2 | E | 2 |
| | | 3 | W | 3 |
# 3 Switch Allocation
Use two-stage input-port-first allocation.
## 3.1 Local allocation
Use round robin arbition. As XY routing, the local arbiters' input port number are not the same.
## 3.2 Global allocation
Use round robin arbition. As XY routing, the global arbiters' input port number are not the same.
* input output port mapping for each SA global arbiter:
| output port | global SA arbiter connected input ports | global SA arbiter connected input ports id | next hop input port |
| ----------- | --------------------------------------- | ------------------------------------------ | ------------------- |
| N | S | 1 | S |
| | E | 2 | |
| | W | 3 | |
| | L | 4 | |
| S | N | 0 | N |
| | E | 2 | |
| | W | 3 | |
| | L | 4 | |
| E | W | 3 | W |
| | L | 4 | |
| W | E | 2 | E |
| | L | 4 | |
| L | N | 0 | - |
| | S | 1 | |
| | E | 2 | |
| | W | 3 | |
# 4 QoS
## 4.1 Common QoS
No special vc, all vc head flits ranked by QoS value.
* no extra real-time vc;
* no bypass arbiter for real-time vc;
* all vc involve QoS value compare.
## 4.2 Common QoS + extra real-time vc QoS
Add special vc for highest priority flits, all vc head flits ranked by QoS value.
* have extra real-time vc;
* no bypass arbiter for real-time vc;
* the real-time vc always win the local sa, and the local sa rr point should not be updated
* the real-time vc join global sa as common QoS, as it has highest QoS value, it can beat flits with other QoS value;
* all vc involve QoS value compare.
## 4.3 extra real-time vc QoS + bypass switch allocation + no common QoS
Add special vc for highest priority flits, other vc head flits have no QoS support.
* have extra real-time vc;
* have bypass arbiter for real-time vc;
* non-highest-priority vc have no QoS support.
* the real-time vc bypass local sa, and override common rr arbiter's result;
* the real-time vc from all possible inport use a separate rr arbiter at per global sa, and override common rr arbiter's result;
It can have the same real-time support as 4.2, but may have better timing.

50
doc/system_memory_map.md Normal file
View File

@@ -0,0 +1,50 @@
# System Memory Map
## 1 Home Node to Memory Channel
### 1.1 Range-based: non-hashed SN target ID
use reg to direct assign a range of memory address to specific memory channel or io device
### 1.2 Range-based: hashed SN target ID
#### 1.2.1 UMA mode
use reg to assign a range of memory address, for 4 home node, 4 memory channel:
1. use PA[7:6] to interleave among memony channels (cache line interleave)
2. for unbalanced memory size among memory channels, use to smallest size channel to interleave, and other memory use direct assign
| PA bit num | msb | ... | 8 | 7 | 6 | 5 - 0 |
| ----------------- | --- | --- | --- | --- | --- | ----------- |
| Interleaving type | | | | CH | CH | line offest |
CH: Channel interleaving
#### 1.2.2 NUMA mode
use reg to assign a range of memory address, for 4 home node, 4 memory channel:
1. use PA[6] to interleave among memony channels (cache line interleave)
2. use PA[msb] to interleave among nodes
3. for unbalanced memory size among memory channels, use to smallest size channel to interleave, and other memory use direct assign
| PA bit num | msb | ... | 8 | 7 | 6 | 5 - 0 |
| ----------------- | --- | --- | --- | --- | --- | ----------- |
| Interleaving type | ND | | | CH | CH | line offest |
ND: Node interleaving, CH: Channel interleaving
## 2 Request Node to Home Node
### 2.1 Non-hashed regions
A given memory partition is assigned to an individual targetID (non-hashed), for:
1. PLIC(highest priority);
2. IO space;
3. Directly assigned memory range
### 2.2 Hashed memory region or non-hashed mode of hashed memory region
#### 2.2.1 NUCA mode
use reg to assign a range of memory address for one core/cluster to its nearest home node,
it can be configured at reset.

7
env/sourceme vendored Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/sh
CURDIR=$(cd $(dirname ${BASH_SOURCE[0]}); pwd )
PROJ_ROOT=$CURDIR/..
export PROJ_ROOT

14
flow/lint/Makefile Executable file
View File

@@ -0,0 +1,14 @@
NAME := rvh_core
run-goals: run-goal-design_read run-goal-lint_lint_rtl
run-goal-design_read:
sg_shell -tcl spyglass-run-design_read.tcl
run-goal-lint_lint_rtl:
sg_shell -enable_pass_exit_codes -tcl spyglass-run-lint_lint_rtl.tcl
run-gui:
spyglass -project $(NAME).prj
clean:
@rm -rf rvh_core

25
flow/lint/rvh_core.prj Executable file
View File

@@ -0,0 +1,25 @@
#!SPYGLASS_PROJECT_FILE
#!VERSION 3.0
# -------------------------------------------------------------------
# This is a automatically generated project file by fusesoc.
# -------------------------------------------------------------------
set_option projectwdir .
set_option language_mode mixed
set_option designread_enable_synthesis yes
set_option designread_disable_flatten no
# Make no only FATAL messages return a non-zero exit code, but also ERRORs and
# WARNINGs
set_option enable_pass_exit_codes yes
read_file -type sourcelist ../../tb/flist_mesh.syn.f
set_option top top_mesh_syn
set_option enableSV09 yes
set_option active_methodology $SPYGLASS_HOME/GuideWare/latest/block/rtl_handoff
current_methodology $SPYGLASS_HOME/GuideWare/latest/block/rtl_handoff

View File

@@ -0,0 +1,21 @@
open_project rvh_core.prj
current_goal Design_Read
# Parameters which are not used/defined in a given goal/methodology raise
# a WARNING, which fails the lint process. That's a bit over the top, we hence
# disable this warning.
waive -rule {checkCMD_unknown}
set rc [run_goal]
close_project -force
set errorCode [lindex $rc 0]
set errorMsg [lindex $rc 1]
if { $errorCode } {
puts stderr "SpyGlass run failed: $errorMsg ($errorCode)"
}
# requires sg_shell to be called with -enable_pass_exit_codes, otherwise
# all non-fatal exit codes are mapped to 0
exit $errorCode

View File

@@ -0,0 +1,21 @@
open_project rvh_core.prj
current_goal lint/lint_rtl
# Parameters which are not used/defined in a given goal/methodology raise
# a WARNING, which fails the lint process. That's a bit over the top, we hence
# disable this warning.
waive -rule {checkCMD_unknown}
set rc [run_goal]
close_project -force
set errorCode [lindex $rc 0]
set errorMsg [lindex $rc 1]
if { $errorCode } {
puts stderr "SpyGlass run failed: $errorMsg ($errorCode)"
}
# requires sg_shell to be called with -enable_pass_exit_codes, otherwise
# all non-fatal exit codes are mapped to 0
exit $errorCode

33
flow/syn/Makefile Normal file
View File

@@ -0,0 +1,33 @@
## prefered path: proj_root/syn/dc/
export TIMESTAMP=$(shell date +%Y%m%d%H%M%S)
export DESIGN_NAME=rvh_noc
# T12/GF22
export SYN_PDK=T12
# SINGLE_ROUTER/MESH
export SYN_TOP=SINGLE_ROUTER
all:
export TIMESTAMP=$(shell date +%Y%m%d%H%M%S)
export DESIGN_NAME=rvh_noc
export SYN_PDK=T12
export SYN_TOP=SINGLE_ROUTER
mkdir ./$(TIMESTAMP)_$(SYN_PDK)_$(SYN_TOP)_run && cd ./$(TIMESTAMP)_$(SYN_PDK)_$(SYN_TOP)_run && mkdir rpt && mkdir output
/opt/cad/synopsys/installs/syn/Q-2019.12-SP5-1/bin/dc_shell-t -checkout DesignWare -f tcl_scripts/synth.tcl | tee $(TIMESTAMP)_$(SYN_PDK)_$(SYN_TOP)_run/$(SYN_PDK)_$(SYN_TOP).log
PHONY:
clean:
rm -rf *_run
rm *.log
# -topographical_mode means using physical constraints on your design, this will allow you to
# accurately predict post-layout timing, area, and power during synthesis without the need for
# timing approximations based on wire load models. It uses placement and optimization
# technologies to drive accurate timing prediction within synthesis and automatically performs
# leakage power optimization, ensuring better correlation with the final physical design.

View File

@@ -0,0 +1,53 @@
proc assert {cond {msg ""}} {
if {![uplevel 1 expr $cond]} {
return -code error "$msg\n assertion failed: $cond"
}
}
proc assert_is_file { fpath } {
global ours
if {![file isfile $fpath]} {
error "Error: file ($fpath) not found"
# if {$ours(tcl_check_only) == "false"} {
# uplevel suspend
# } else {
# error ""
# }
}
}
proc assert_is_dir { dpath } {
global ours
if {![file isdirectory $dpath]} {
error "Error: dir ($dpath) not found"
# if {$ours(tcl_check_only) == "false"} {
# uplevel suspend
# } else {
# error ""
# }
}
}
proc assert_exist { dpath } {
global ours
if {![file exists $dpath]} {
error "Error: dir ($dpath) not found"
# if {$ours(tcl_check_only) == "false"} {
# uplevel suspend
# } else {
# error ""
# }
}
}
proc assert_is_file_list { ls_fpath } {
foreach fpath $ls_fpath {
assert_is_file $fpath
}
}
proc assert_is_dir_list { ls_dpath } {
foreach dpath $ls_dpath {
assert_is_dir $dpath
}
}

View File

@@ -0,0 +1,315 @@
#**************************************************************
# Create Clock
#**************************************************************
set clk_period 1
# set clk_period 0.66
# set clk_uncertainty [expr $clk_period * 0.1]
set clk_uncertainty_setup [expr $clk_period * 0.2]
set clk_uncertainty_hold [expr $clk_period * 0.05]
set latency_input_transition [expr $clk_period * 0.04]
set latency_input_transition_clocks [expr $clk_period * 0.003]
#MARGIN 0.9/0.65/1.0
set MARGIN 0.9
set period_1000m [expr $MARGIN * $clk_period];
#**************************************************************
# List clk ports
#**************************************************************
set CLK_PORT_LIST_IN "clk"
set RST_PORT_LIST_IN "rst"
set main_clk [get_ports clk]
#**************************************************************
# Create Clock
#**************************************************************
#create_clock -period 0.500 -waveform {0.0 0.25} -name clk [get_ports clk]
set period_main_clock $period_1000m
#create_clock -name CLK -period $clk_period [get_ports clk]
create_clock -name clk -period $period_main_clock -waveform [list 0 [expr $period_main_clock *0.5]] $main_clk -add
# create_clock -name vir_main_clk -period $period_main_clock -waveform [list 0 [expr $period_main_clock *0.5]]
#**************************************************************
# Create Generated Clock
#**************************************************************
#derive_pll_clocks
#**************************************************************
# ScanEnable to be 0
#**************************************************************
# Please include vcore_fp_top.disable_scan_constraints.v
set DRC_data_max_transition 0.25
set DRC_clock_max_transition 0.15
#**************************************************************
# Power Pin
#**************************************************************
#set ours(iport,cfg_pwr) [get_ports {*/cfg_is_clk_gated */cfg_thread_cnt*} -filter "direction==in"]
#**************************************************************
# Set Clock Latency
#**************************************************************
#**************************************************************
# Set Clock Uncertainty
#**************************************************************
#derive_clock_uncertainty
#set_clock_uncertainty 0.125 [all_clocks]
# set_clock_uncertainty $clk_uncertainty [all_clocks]
set_clock_uncertainty -setup $clk_uncertainty_setup [all_clocks]
set_clock_uncertainty -hold $clk_uncertainty_hold [all_clocks]
#**************************************************************
# Set I/O Delay
#**************************************************************
# set_input_delay [expr 0.5 * $clk_period] -max -clock vir_main_clk [remove_from_collection [all_inputs] [get_ports clk]]
# set_input_delay [expr 0.0 * $clk_period] -min -clock vir_main_clk [remove_from_collection [all_inputs] [get_ports clk]]
# set_output_delay [expr 0.5 * $clk_period] -max -clock vir_main_clk [all_outputs]
# set_output_delay [expr 0.0 * $clk_period] -max -clock vir_main_clk [all_outputs]
set_input_delay [expr $clk_period * 0.4] -clock clk [remove_from_collection [all_inputs] {clk}]
set_output_delay [expr $clk_period * 0.4] -clock clk [all_outputs]
#**************************************************************
# Set ideal_network
#**************************************************************
if {[sizeof_collection [get_cells -quiet -hierarchical -filter "ref_name =~CKLNQD*"]]} {
set_ideal_network [get_pins -filter "pin_direction == out" -of_object [get_cells -hierarchical -filter "ref_name =~ *CKLNQD*"]]
}
if {[sizeof_collection [get_cells -quiet -hierarchical -filter "ref_name =~CKLHQD*"]]} {
set_ideal_network [get_pins -filter "pin_direction == out" -of_object [get_cells -hierarchical -filter "ref_name =~ *CKKHQD*"]]
}
set_ideal_network [get_ports -quiet "$CLK_PORT_LIST_IN "]
set_ideal_network [get_ports -quiet "$RST_PORT_LIST_IN "]
# set_ideal_network [get_attribute [get_clocks -filter "full_name !~ vir*"] source]
# set_dont_touch_network [get_clocks -filter "full_name !~ vir*"]
set_dont_touch_network [all_clocks]
set_ideal_network [all_fanout -flat -clock_tree]
#**************************************************************
# Set False Path
#**************************************************************
# false path to power switch control ack (use pre-placed and pre-routing in ICC2)
#set_false_path -from [get_ports */cfg_is_clk_gated] -to [get_ports */cfg_is_clk_gated]
#set_false_path -from [get_ports */cfg_thread_cnt* ] -to [get_ports */cfg_thread_cnt*]
# false path from SLP to Q in SRAM (SLP not valid in VCORE yet, only on top level)
#set ours(pin,sram_slp) [get_pins -of [get_cells * -hier -filter "ref_name=~TS*N28HPCP*"] -filter "full_name=~*/SLP"]
#set ours(pin,sram_q) [get_pins -of [get_cells * -hier -filter "ref_name=~TS*N28HPCP*"] -filter "full_name=~*/Q*"]
#set_false_path -th $ours(pin,sram_slp) -th $ours(pin,sram_q)
#**************************************************************
# Begin
#**************************************************************
set global_setup_uncertainty 0.09
set global_hold_uncertainty 0.08
set ENV_data_input_max_transition 0.25
set ENV_input_min_transition 0.010
set DRC_max_fanout_inner 40
set DRC_max_fanout_input 1
set_max_transition $DRC_data_max_transition [current_design]
set_max_transition $DRC_data_max_transition -data_path [all_clocks]
set_max_transition $DRC_clock_max_transition -clock_path [all_clocks]
set_max_fanout $DRC_max_fanout_inner [current_design];#40
set_max_fanout $DRC_max_fanout_input [all_inputs];#1
set inputs [remove_from_collection [all_inputs] $CLK_PORT_LIST_IN]
set_input_transition -max $ENV_data_input_max_transition $inputs
set_input_transition -min $ENV_input_min_transition $inputs
set_load -max 0.050 [all_outputs]
set_load -max 0.004 [all_outputs]
if {[info exists dft_clks]} {
set func_clocks [remove_from_collection [all_clocks] $dft_clks]
} else {
set func_clocks [all_clocks]
}
set_clock_uncertainty -setup $global_setup_uncertainty $func_clocks
set_clock_uncertainty -hold $global_hold_uncertainty [all_clocks]
#**************************************************************
# Set Multicycle Path
#**************************************************************
# set_multicycle_path 18 -setup -end \
# -through [get_pins div_u/ff_div_a_u/q[*]] \
# -through [get_pins div_u/ff_div_output_data_u/d[*]]
# set_multicycle_path 17 -hold -end \
# -through [get_pins div_u/ff_div_a_u/q[*]] \
# -through [get_pins div_u/ff_div_output_data_u/d[*]]
# set_multicycle_path 18 -setup -end \
# -through [get_pins div_u/ff_div_b_u/q[*]] \
# -through [get_pins div_u/ff_div_output_data_u/d[*]]
# set_multicycle_path 17 -hold -end \
# -through [get_pins div_u/ff_div_b_u/q[*]] \
# -through [get_pins div_u/ff_div_output_data_u/d[*]]
# set_multicycle_path -setup 2 -through [get_cells {btb_u/BTB_SET_*__btb_tag/*}] -to [get_cells { \
# npc_gen_u/* \
# icache_u/req_valid_s1_reg \
# instr_buffer/wr_ptr_reg* \
# kill_f1_reg \
# btq_u/target_ram_reg* \
# }]
# set_multicycle_path -setup 2 -through [get_pins {btb_u/BTB_SET_*__btb_tag/*}]
# set_multicycle_path -setup 8 -through [get_pins {EX/DIV/*}] -to [get_pins { \
# EX/DIV/DW_DIV_SEQ/* \
# EX/DIV/* \
# }]
# set_multicycle_path -setup 8 -through [get_pins {EX/DIV/*}]
# set_multicycle_path -hold 7 -through [get_pins {EX/DIV/*}]
# set_multicycle_path -setup 8 -through [get_pins {EX/DIV/*/*}]
# set_multicycle_path -hold 7 -through [get_pins {EX/DIV/*/*}]
# set_multicycle_path -setup 5 -through [get_pins {EX/MUL/*}]
# set_multicycle_path -hold 4 -through [get_pins {EX/MUL/*}]
# set_multicycle_path -hold 7 -through [get_cells {EX/DIV/*}] -to [get_cells { \
# EX/DIV/* \
# EX/DIV/DW_DIV_SEQ_part_rem_reg_reg_*_ \
# EX/DIV/DW_DIV_SEQ_shf_reg_reg_*__*_ \
# EX/DIV/DW_DIV_SEQ*reg* \
# EX/ex2ma_ff_reg** \
# ID/id2div_ff_reg* \
# ID/id2ex_ff_reg* \
# ID/id2ex_ff_reg* \
# ID/id2ex_fp_rs1* \
# ID/id2fp_add_d_ff_reg* \
# ID/id2fp_add_s_ff_reg* \
# ID/id2fp_div_d_ff_reg* \
# ID/id2fp_div_s_ff_reg* \
# ID/id2fp_mac_d_ff_reg* \
# ID/id2fp_mac_s_ff_reg* \
# ID/id2fp_misc_ff_reg* \
# ID/id2fp_sqrt_d_ff_reg* \
# ID/id2fp_sqrt_s_ff_reg* \
# ID/id2mul_ff_reg* \
# itlb_u/dff_sfence_req_reg* \
# }]
# set_multicycle_path -hold 7 -through [get_pins {EX/DIV/*}] -to [get_pins { \
# EX/DIV/DW_DIV_SEQ/* \
# EX/DIV/* \
# }]
# set_multicycle_path -setup 5 -through [get_cells {EX/MUL/*}] -to [get_cells { \
# EX/ex2ma_ff_reg* \
# EX/MUL/DW_MULT_SEQ*reg* \
# EX/MUL/* \
# ID/id2div_ff_reg* \
# ID/id2ex_ff_reg* \
# ID/id2ex_ff_reg* \
# ID/id2ex_fp_rs1_ff_reg* \
# ID/id2fp_add_d_ff_reg* \
# ID/id2fp_add_s_ff_reg* \
# ID/id2fp_div_d_ff_reg* \
# ID/id2fp_div_s_ff_reg* \
# ID/id2fp_mac_d_ff_reg* \
# ID/id2fp_mac_s_ff_reg* \
# ID/id2fp_misc_ff_reg* \
# ID/id2fp_sqrt_d_ff_reg* \
# ID/id2fp_sqrt_s_ff_reg* \
# ID/id2mul_ff_reg* \
# itlb_u/dff_sfence_req_reg* \
# }]
# set_multicycle_path -setup 5 -through [get_pins {EX/MUL/*}] -to [get_pins { \
# EX/MUL/DW_MULT_SEQ/* \
# EX/MUL/* \
# }]
# set_multicycle_path -hold 4 -through [get_cells {EX/MUL/*}] -to [get_cells { \
# EX/ex2ma_ff_reg* \
# EX/MUL/DW_MULT_SEQ*reg* \
# EX/MUL/* \
# ID/id2div_ff_reg* \
# ID/id2ex_ff_reg* \
# ID/id2ex_ff_reg* \
# ID/id2ex_fp_rs1_ff_reg* \
# ID/id2fp_add_d_ff_reg* \
# ID/id2fp_add_s_ff_reg* \
# ID/id2fp_div_d_ff_reg* \
# ID/id2fp_div_s_ff_reg* \
# ID/id2fp_mac_d_ff_reg* \
# ID/id2fp_mac_s_ff_reg* \
# ID/id2fp_misc_ff_reg* \
# ID/id2fp_sqrt_d_ff_reg* \
# ID/id2fp_sqrt_s_ff_reg* \
# ID/id2mul_ff_reg* \
# itlb_u/dff_sfence_req_reg* \
# }]
# set_multicycle_path -hold 4 -through [get_pins {EX/MUL/*}] -to [get_pins { \
# EX/MUL/DW_MULT_SEQ/* \
# EX/MUL/* \
# }]
# set ours(ff,fp) [get_cells -hier {id2ex_ctrl_ff_reg*fp_* id2fp_add_s_ff_reg* id2fp_add_d_ff_reg* id2fp_mac_s_ff_reg* id2fp_mac_d_ff_reg* id2fp_div_s_ff_reg* id2fp_div_d_ff_reg* id2fp_sqrt_s_ff_reg* id2fp_sqrt_d_ff_reg* id2fp_misc_ff_reg*}]
# set ours(ff,fpsqrt) [get_cells -hier {id2fp_sqrt_s_ff_reg*}]
# # multicycle for fp units
# set_multicycle_path -setup 32 -from $ours(ff,fp)
# set_multicycle_path -hold 31 -from $ours(ff,fp)
# set_multicycle_path -setup 33 -from $ours(ff,fpsqrt)
# set_multicycle_path -hold 32 -from $ours(ff,fpsqrt)
# set_multicycle_path -setup 10 -from [get_ports {*_pwr_on* *rst_pc*}]
# set_multicycle_path -hold 9 -from [get_ports {*_pwr_on* *rst_pc*}]
# ## END ORV64
# ## ORV64 <-> VP
# #set vcore(orv,vc) [get_cells -hier { *VCORE_DEC_U* *orv2vc* *vc2orv*}]
# ### set vcore(orv,vc) [get_pins -hier {*orv2vc* *vc2orv*}]
# ### set_multicycle_path -setup 6 -from $vcore(orv,vc)
# ### set_multicycle_path -hold 4 -from $vcore(orv,vc)
# ## END ORV64 <-> VP
# #
# #set_max_delay 1.0 -to _vector_core/u_FP__floatpoint/v_*___vector/regs__*__regs/regs_*__r/wq_reg/D
# #set_max_delay 1.0 -from _vector_core/u_FP__floatpoint/clk -to _vector_core/u_FP__floatpoint/v_*___vector/regs__*__regs/regs_*__r/wq_reg/D
# #**************************************************************
# # Set Maximum Delay
# #**************************************************************
# # assuming 14%
# set_input_delay [expr $clk_period * 0.5] -clock CLK [all_inputs]
# set_output_delay [expr $clk_period * 0.5] -clock CLK [all_outputs]
#**************************************************************
# Set Minimum Delay
#**************************************************************
#**************************************************************
# Set Input Transition
#**************************************************************
#set_driving_cell -lib_cell BUFFD12BWP35P140HVT [all_inputs]
#set_load [get_attr [get_lib_pin tcbn28hpcplusbwp35p140hvtssg0p81vm40c_ccs/BUFFD12BWP35P140HVT/I] pin_capacitance] [all_outputs]
#set_input_transition $latency_input_transition [all_inputs]
#set_input_transition $latency_input_transition_clocks [get_ports clk]
#**************************************************************
# Set Load
#**************************************************************
#set_load [expr $clk_period * 0.01] [all_outputs]

View File

@@ -0,0 +1,139 @@
#!/bin/env tclsh
source [file join [file dirname [file normalize [info script]]] "parse_arg.tcl"]
source [file join [file dirname [file normalize [info script]]] "assert.tcl"]
proc resolve_env path {
regsub -all {\$\{?([^\s\/\{\}]+)\}?} $path {$::env(\1)} path
eval "set resolved $path"
return $resolved
}
proc file_to_list args {
parse_arg "-fpath(path)() -col(int)(1) -prefix(string)(.) -suffix(string)(.)" $args
if {![file isfile $fpath]} {
error "Error: file ($fpath) is missing"
}
set ls [list]
set f [open $fpath "r"]
while {[gets $f line] >= 0} {
set line [string trim $line]
if {[string length $line] == 0 || [string index $line 0] == "#" || [string range $line 0 1] == "//"} {
continue
}
regsub -all {\s+} $line " " line
set ls_line [split $line " "]
set item [lindex $ls_line [expr $col-1]]
lappend ls $item
}
close $f
if {$prefix != "."} {
set ls_new [list]
foreach item $ls {
lappend ls_new "${prefix}${item}"
}
set ls $ls_new
}
if {$suffix != "."} {
set ls_new [list]
foreach item $ls {
lappend ls_new "${item}${suffix}"
}
set ls $ls_new
}
return $ls
}
proc file_list_remove_duplicate {ls_fpath} {
set ls_new [list]
foreach fpath $ls_fpath {
set fpath_norm [file normalize $fpath]
if {[lsearch -exact $ls_new $fpath_norm] == -1} {
lappend ls_new $fpath_norm
}
}
return $ls_new
}
proc expand_file_list {file_list_fpath} {
if {![file isfile $file_list_fpath]} {
error "Error: file ($file_list_fpath) is missing"
}
set file_list_dpath [file dirname $file_list_fpath]
set ls_file [list]
set f [open $file_list_fpath "r"]
while {[gets $f line] >= 0} {
set line [string trim $line]
if {[string length $line] == 0 || [string index $line 0] == "#" || [string range $line 0 1] == "//"} {
continue
}
if {[string match +* $line]} {
continue
}
regsub -all {\s+} $line " " line
set ls_item [split $line " "]
if {[llength $ls_item] == 1} {
# single item
set fpath [lindex $ls_item 0]
set fpath [resolve_env $fpath]
if {[string index $fpath 0] == "/"} {
# absolute path
} else {
# relative path
set fpath [file join $file_list_dpath $fpath]
}
assert_exist $fpath
lappend ls_file $fpath
} elseif {[llength $ls_item] == 2} {
if {[lindex $ls_item 0] == "-f"} {
set fpath [resolve_env [lindex $ls_item 1]]
set nested_file_list_fpath [file join $file_list_dpath $fpath]
set ls_file [concat $ls_file [expand_file_list $nested_file_list_fpath]]
} elseif {[lindex $ls_item 0] == "-v"} {
set fpath [lindex $ls_item 1]
set fpath [resolve_env $fpath]
if {[string index $fpath 0] == "/"} {
# absolute path
} else {
# relative path
set fpath [file join $file_list_dpath $fpath]
}
assert_exist $fpath
lappend ls_file $fpath
} elseif {[lindex $ls_item 0] == "-y"} {
set path [resolve_env [lindex $ls_item 1]]
set ls_file [concat $ls_file [glob -nocomplain -directory $path *.sv]]
set ls_file [concat $ls_file [glob -nocomplain -directory $path *.v]]
} else {
error "Error: line ($line) is not recognized"
}
} else {
error "Error: line ($line) is not recognized"
}
}
close $f
return [file_list_remove_duplicate $ls_file]
}
if {[info exists argv0]} {
if {[file tail $argv0] == [file tail [info script]]} {
foreach fpath [expand_file_list [lindex $argv 0]] {
puts $fpath
}
}
}

View File

@@ -0,0 +1,130 @@
#!/bin/env tclsh
################################################################
# prase_arg
# ls_arg_definition
# one expected argument = "-${arg_name}(type)(default_value)"
# arg_name will be defined in up-level proc.
# To match defined arguments, we support shortcuts like Synopsys DC/PT/ICC
# type = <int|float|string|path|bool>
# default is the default value if it's not given in ls_arg.
# if default is empty, then this is a must-have argument.
# ls_arg can be $args for a proc or $argv for command line script
################################################################
proc parse_arg { ls_arg_definition ls_arg } {
# parse ls_arg_definition
set arg(name) {}
set usage "usage:\n"
foreach arg_def $ls_arg_definition {
if {[regexp {^-([_0-9a-zA-Z]+)\(([a-z]+)\)\((.*)\)$} $arg_def match arg_name arg_type default_value]} {
if {$default_value == ""} {
set default_value "NULL"
set optional "Must-have"
} else {
set optional "Optional"
}
set arg(name) [lappend arg(name) $arg_name]
set arg($arg_name,arg_type) $arg_type
set arg($arg_name,value) $default_value
uplevel set $arg_name $arg($arg_name,value)
# usage
set usage "$usage -$arg_name ($optional) TYPE=$arg_type; DEFAULT=$default_value\n"
} else {
error "Error: arg_definition ($arg_def) is not recognized"
}
}
# parse ls_arg
if {$ls_arg == "-help"} {
puts $usage
uplevel exit
}
if {$ls_arg == ""} {
set expect_arg_name -1
} else {
set expect_arg_name 1
}
while {$expect_arg_name >= 0} {
set input [lindex $ls_arg 0]
set ls_arg [lrange $ls_arg 1 end]
if {$expect_arg_name} {
# parse arg name
if {[regexp {^-([_0-9a-zA-Z]+)$} $input match input_arg_name]} {
set num_match 0
set match_arg_name ""
foreach arg_name $arg(name) {
if {[string match "${input_arg_name}*" $arg_name]} {
incr num_match 1
set match_arg_name $arg_name
}
}
if {$num_match == 0} {
# no match found
error "Error: argument ($input_arg_name) is not defined in ($ls_arg_definition)."
} elseif {$num_match > 1} {
# multi matches found
error "Error: argument ($input_arg_name) is too ambiguouse. $num_match matches are found."
} else {
# 1 match found
if {$arg($match_arg_name,arg_type) == "bool"} {
set arg($match_arg_name,value) 1
set expect_arg_name 1
} else {
set arg($match_arg_name,value) "NULL"
set expect_arg_name 0
}
}
} else {
error "Error: expecting argument name at ($input)"
}
} else {
# parse arg value
if {($arg($match_arg_name,arg_type) == "int" && ![regexp {^[0-9]+$} $input]) \
|| ($arg($match_arg_name,arg_type) == "float" && ![regexp {^[0-9]+\.[0-9]+} $input]) \
} {
error "Error: argument type is wrong. Expecting $arg($match_arg_name,arg_type) for $match_arg_name at ($input)"
} elseif {$arg($match_arg_name,arg_type) == "string"} {
regsub -all {\$} $input {\\$} input
regsub -all "\n" $input "\\n" input
regsub -all "\t" $input "\\t" input
regsub -all "\"" $input "\\\"" input
set arg($match_arg_name,value) "\"$input\""
} else {
set arg($match_arg_name,value) $input
}
set expect_arg_name 1
}
if {[llength $ls_arg] == 0} {
break
}
}
foreach arg_name $arg(name) {
if {$arg($arg_name,value) == "NULL"} {
error "Error: argument ($arg_name) has no value defined"
}
uplevel set $arg_name $arg($arg_name,value)
}
}
# test
if {[info exists argv0]} {
if {[file tail $argv0] == [file tail [info script]]} {
proc test_parse_arg args {
parse_arg "-num(int)(100) -input_file(path)() -output_file(path)() -is_cool(bool)(0) -some_string(string)(.)" $args
puts $num
puts $input_file
puts $output_file
puts $is_cool
puts "($some_string)"
}
test_parse_arg -num 123 -in ./input -out ../output -is_cool
test_parse_arg -num 123 -in ./input -out ../output
}
}

View File

@@ -0,0 +1,257 @@
# choose pdk
# set SYN_PDK GF22
# set SYN_PDK T12
# choose synthesis top
# set SYN_TOP SINGLE_ROUTER
# set SYN_TOP MESH
# start
echo "RUN STARTED AT [date]"
if { $env(SYN_PDK)=="GF22" } {
# gf22n
source tcl_scripts/synth_init_lib.tcl
} elseif { $env(SYN_PDK)=="T12" } {
# t12n
source tcl_scripts/synth_init_library.t12.tcl
} else {
exit 1
}
#start from the path of Makefile rather than#
# set saving path of formality file
set DESIGN_NAME $env(DESIGN_NAME)
if { $env(SYN_TOP)=="MESH" } {
# mesh
set TOP_NAME top_mesh_syn
set FLIST_NAME flist_mesh.syn.f
} else {
# single_router
set TOP_NAME top_single_router_syn
set FLIST_NAME flist_single_router.syn.f
}
set_svf ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/${DESIGN_NAME}.synth.svf
# setup will be included in .synopsys_dc.setup file
source ./.synopsys_dc.setup
###################################################################
#------------------------Specify the libraries---------------------#
set_app_var search_path "$search_path ."
#license is needed#
if { $env(SYN_PDK)=="GF22" } {
# gf22n
set_app_var target_library [concat "$DB(ssg0p45v,m40c)"]
} elseif { $env(SYN_PDK)=="T12" } {
# t12n
set_app_var target_library [concat "$DB(ssg0p72v,125c)"]
} else {
exit 1
}
#.db, TODO: simplify the way of importing target libs#
#----designware setting-------#
set_app_var synthetic_library "dw_foundation.sldb"
set_dp_smartgen_options -hierarchy -smart_compare true -tp_oper_sel auto -tp_opt_tree auto -brent_kung_adder true -adder_radix auto -inv_out_adder_cell auto -mult_radix4 auto -sop2pos_transformation auto -mult_arch auto -optimize_for area,speed
#Analyzes DesignWare datapath extraction.#
set_app_var link_library "* $target_library $synthetic_library"
#all libs which might be used#
#------------------------- Read the design ------------------------#
#----------------------#
## read
### in dc_shell: read -format sverilog rtl.sv
### in tcl shell: read_verilog rtl.v; read_db lib.db
#---------------------#
## or analyze+elaborate+WORK dir(default)
define_design_lib WORK -path ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/WORK
#can be omitted#
source tcl_scripts/file_to_list.tcl
analyze -format sverilog [concat [expand_file_list "$env(PROJ_ROOT)/tb/${FLIST_NAME}"]]
#analyze HDL source code and save intermediate results named .syn in ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/work dir, which can be used by elaborate directly even without anlyzing; TODO: what does es1y_define.sv mean?#
elaborate ${TOP_NAME}
# write_file -hierarchy -format verilog -output output/rvh1.synth.elaborate.v
#for dbg#
current_design ${TOP_NAME}
link
#not necessary after anal. and elab.?, link lib has been defined before#
analyze_datapath_extraction -no_autoungroup
#-------------------- Define the design environment -------------------#
# set_load 2.2 sout
# set_load 1.5 cout
# set_driving_cell -lib_cell FD1 [all_inputs]
#---------------------- Set the design constraints --------------------#
## Design Rule constraints
# set_max_transistion
# set_max_fanout
# set_max_capacitance
#provided by foundary company, can be setted tightly in advance; TODO: get precise indicators#
## Set the optimization constraints
#----delay----#
#----area-----#
set_host_options -max_cores 16
source tcl_scripts/constraints.sdc
set_clock_transition 0.1 [all_clocks]
set_critical_range 10 [current_design]
group_path -weight 0.1 -name input_path -from [all_inputs]
group_path -weight 0.1 -name output_path -to [all_outputs]
group_path -weight 0.1 -name in2out -from [all_inputs] -to [all_outputs]
set_dynamic_optimization false
set_leakage_optimization false
set compile_timing_high_effort true
set placer_tns_driven true
set psynopt_tns_high_effort true
set compile_timing_high_effort_tns true
set_cost_priority -delay
puts "TIMESTAMP Pre-Compile [clock format [clock second ] -format %T] [expr [mem] /1024]M"
set compile_final_drc_fix all
set compile_automatic_clock_phase_inference relaxed
set compile_enable_constant_propagation_with_no_boundary_opt true
set compile_advanced_fix_multiple_port_nets true
set compile_rewire_multiple_port_nets true
set_fix_multiple_port_nets -all -buffer_constants [get_designs *]
set_auto_disable_drc_nets -clock true -constant true -on_clock_network true
#copied from original /script/vp_fp.03-05-2020_20.30.59.sdc, TODO: define accurate constraints and optimizations#
# write_sdc output/rvh1.synth.elaborate.sdc
# report_clock_tree -structure > rpt/clock_tree_structure.rpt
#for dbg#
#--------------------- Define clock gating -------------------------#
set_clock_gating_style -sequential_cell latch -positive_edge_logic {integrated} -negative_edge_logic {integrated} \
-control_point before -control_signal scan_enable \
-minimum_bitwidth 4 -observation_point false \
-max_fanout 16
set_clock_latency 0 [all_clocks]
set_clock_gate_latency -overwrite -stage 0 -fanout_latency {1-inf 0}
set_clock_gate_latency -overwrite -stage 1 -fanout_latency {1-inf -0.05}
set_clock_gate_latency -overwrite -stage 2 -fanout_latency {1-inf -0.1}
set_clock_gate_latency -overwrite -stage 3 -fanout_latency {1-inf -0.15}
set_clock_gate_latency -overwrite -stage 4 -fanout_latency {1-inf -0.2}
set_clock_gate_latency -overwrite -stage 5 -fanout_latency {1-inf -0.25}
set ALL_INPUTS [all_inputs]
foreach_in_collection INPUTS $ALL_INPUTS {
append_to_collection -unique INPUT_REG [ filter_collection [all_fanout -from $INPUTS -flat -endpoints_only] "full_name =~ */synch_toggle || full_name =~ */synch_preset || full_name =~ */synch_enable || full_name =~ */synch_clear || full_name =~ */next_state "]
}
set_clock_gating_objects -exclude [get_cells -of_object $INPUT_REG]
#--------------------- Select compile strategy -------------------------#
#--------------------- Synthesize and optimize the design ------------------------#
# echo [get_object_name [get_lib_cells */* -filter dont_use==true]] > rpt/dont_use_list.rpt
# check_design > rpt/check_design.precompile.rpt
#for dbg#
set_verification_top
#set_dynamic_optimization true
#run 2 times compile_ultra
compile_ultra -gate_clock -retime -no_autoungroup -no_boundary_optimization
compile_ultra -gate_clock -retime -no_autoungroup -no_boundary_optimization
#compile_ultra (of DC Ultra) provides concurrent optimization of timing, area, power, and test for high performance designs#
#it also provides advanced delay and arithmetic optimization, advanced timing analysis, automatic leakage power optimization, and register retiming#
#--------------------- Analyze and debug the design/resolve design problems --------------------#
analyze_datapath > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/datapath.compile.rpt
report_resources > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/resources.compile.rpt
write_file -hierarchy -format verilog -output ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/rvh1.synth.compile.v
write_sdc ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/rvh1.synth.compile.sdc
update_timing
report_timing -nosplit > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/timing.compile.rpt
report_area -nosplit -hier > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/area.hier.compile.rpt
check_design > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/check_design.preopt.rpt
optimize_netlist -area -no_boundary_optimization
check_design > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/check_design.postopt.rpt
define_name_rules preserve_struct_bus_rule -preserve_struct_ports
define_name_rules ours_verilog_name_rule -allowed "a-z A-Z 0-9 _" \
-check_internal_net_name \
-case_insensitive
change_names -rules preserve_struct_bus_rule -hierarchy -log_changes ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/struct_name_change.log
change_names -rules ours_verilog_name_rule -hierarchy -log_changes ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/legalize_name_change.log
write -format verilog -hierarchy -output ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/rvh1.synth.final.v
write -format ddc -hierarchy -output ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/rvh1.synth.final.ddc
write_sdc -nosplit ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/rvh1.synth.final.sdc
report_clock_gating > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/clock_gating.rpt
report_timing -tran -net -input -max_paths 500 -significant_digits 3 -nosplit > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.timing.rpt
report_timing -delay_type min -max_paths 500 -input_pins -nets -transition_time -capacitance -significant_digits 3 > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.min_delay.rpt
report_timing -delay_type max -max_paths 500 -input_pins -nets -transition_time -capacitance -significant_digits 3 > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.max_delay.rpt
report_constraint -all_violators -significant_digits 3 > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.all_viol_constraints.rpt
report_area -nosplit -hier > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.area.hier.rpt
report_resources -nosplit -hier > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.resources.rpt
report_timing_requirements > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.mulcycle.rpt
report_compile_options -nosplit > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/synth.compile_options.rpt
#report_timing -tran -net -input -max_paths 1000 > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/timing.rpt
report_clock_gating -nosplit -verbose -multi_stage > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/clock_gating.rpt
report_clock_gating -gated -nosplit -verbose > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/clock_gating_gated.rpt
report_clock_gating -ungated -nosplit -verbose > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/clock_ungating_gated.rpt
report_power -nosplit > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/power.rpt
report_qor > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/qor.rpt
#report_area -hierarchy > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/area.rpt
#report_constraint -all_violators -verbose -max_capacitance -max_transition > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/drc.rpt
report_clocks > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/clock.rpt
check_design -unmapped > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/check_design.rpt
#check_timing -include {clock_no_period data_check_no_clock generated_clock generic} ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/check_timing.rpt
report_dont_touch -nosplit -class cell > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/dont_touch.rpt
report_threshold_voltage_group > ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/rpt/threshold_voltage_group.rpt
#--------------------- Save the design database ---------------------#
write_file -format ddc -hierarchy -output ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/${DESIGN_NAME}.ddc
#.ddc is the whole project, can be modified and checked#
write_file -format verilog -hierarchy -output ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/${DESIGN_NAME}_netlist.v
#netlist.v for P&R and sim#
#write_sdf ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/${DESIGN_NAME}_sdf
#recording the latency of std cells, also useful for post-sim#
#write_parasitics -output ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/${DESIGN_NAME}_parasitics
#Writes parasitics in SPEF format or as a Tcl script that contains set_load and set_resistance commands.#
# write_sdc sdc_file_name
#Writes out a script in Synopsys Design Constraints (SDC) format.#
#This script contains commands that can be used with PrimeTime or with Design Compiler. SDC is also licensed by external vendors through the Tap-in program. SDC-formatted script files are read into PrimeTime or Design Compiler using the read_sdc command.#
# write_floorplan -all ./$env(TIMESTAMP)_$env(SYN_PDK)_$env(SYN_TOP)_run/output/${DESIGN_NAME}_phys_cstr_file_name.tcl
#writes a Tcl script file that contains floorplan information for the current or user-specified design. writes commands relative to the top of the design, regardless of the current instance.#
#-------------------------------------------------------------------#
echo "RUN ENDED AT [date]"

View File

@@ -0,0 +1,4 @@
set DB(ssg0p45v,m40c) {
/work/tech/GF22FDX/LIB/DesignWare_logic_libs/globalfoundaries22nhsda/36hd/edl/ulvt/4.00a/liberty/ccs/gf22nsdvlogl36edl116a_TT_0P80V_0P00V_0P00V_0P00V_25C.db \
/work/tech/GF22FDX/LIB/DesignWare_logic_libs/globalfoundaries22nhsda/24hd/edl/lvt/4.00a/liberty/ccs/gf22nsdllogl24edl116a_TT_0P80V_0P00V_0P00V_0P00V_25C.db \
}

View File

@@ -0,0 +1,57 @@
set DB(ssg0p72v,125c) {
/work/tech/t12nm/Mem/db/ts1n12ffcllsblvtd128x32m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllsblvtd640x34m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta1024x128m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta1024x64m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta1024x72m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta1024x76m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta1024x80m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta128x256m2swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta128x262m2swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta128x32m2swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta128x51m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta128x59m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta128x82m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta128x88m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta16384x30m16swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta16384x32m16swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta16384x39m16swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta16x88m2swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta2048x128m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta2048x66m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta2048x98m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta256x80m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta32x86m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta4096x32m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta4096x32m8swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta4096x64m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta512x78m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta64x84m4swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts1n12ffcllulvta8192x32m8swbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts3n12ffcllulvta1024x64m16bo_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvta1088x34m8fwbsho_150a_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvta288x68m2fwbsho_150a_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvta368x34m2fwbsho_150a_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvta544x67m4fwbsho_150a_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvta88x136m2fwbsho_150a_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb1024x32m4wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb148x136m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb16x112m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb16x120m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb16x128m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb16x152m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb16x154m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb16x244m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb20x64m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb256x10m2wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb288x68m2wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb32x138m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb40x64m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb560x33m4wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb64x256m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb64x64m2wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb8x256m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/Mem/db/ts6n12ffcllulvtb8x64m1wbsho_130b_ssgnp0p72v125c.db \
/work/tech/t12nm/STD/db/tcbn12ffcllbwp20p90cpdlvtssgnp0p72v125c.db
}

157
rtl/include/rvh_noc_pkg.sv Executable file
View File

@@ -0,0 +1,157 @@
`ifndef __RVH_NOC_PKG_SV__
`define __RVH_NOC_PKG_SV__
// ----------
// local port configuration
// ----------
`define HAVE_LOCAL_PORT
`define LOCAL_PORT_NUM_2 // local port num >= 2
// `define LOCAL_PORT_NUM_3 // local port num >= 3
// `define LOCAL_PORT_NUM_4 // local port num >= 4
`ifdef LOCAL_PORT_NUM_4
`ifndef LOCAL_PORT_NUM_3
`define LOCAL_PORT_NUM_3
`endif
`ifndef LOCAL_PORT_NUM_2
`define LOCAL_PORT_NUM_2
`endif
`endif
`ifdef LOCAL_PORT_NUM_3
`ifndef LOCAL_PORT_NUM_2
`define LOCAL_PORT_NUM_2
`endif
`endif
// ----------
// use unified dual-port ram per input port vc data buffer (default: dff)
// ----------
// `define VC_DATA_USE_DUAL_PORT_RAM
// ----------
// reture credit to send at sa stage rather than st atage
// ----------
// `define RETURN_CREDIT_AT_SA_STAGE
// ----------
// whether allow local ports in same router transfer flit, at least 2 local ports
// ----------
`define ALLOW_SAME_ROUTER_L2L_TRANSFER
// ----------
// QoS, at most one of follow macros can be defined
// ----------
// `define COMMON_QOS // No special vc, all vc head flits ranked by QoS value.
`define COMMON_QOS_EXTRA_RT_VC // Add special vc for highest priority flits, all vc head flits ranked by QoS value
// not implemented:
// `define RT_BYPASS_QOS_EXTRA_RT_VC // Add special vc for highest priority flits, other vc head flits have no QoS support
`ifdef COMMON_QOS
`define USE_QOS_VALUE
`endif
`ifdef COMMON_QOS_EXTRA_RT_VC
`define USE_QOS_VALUE
`endif
package rvh_noc_pkg;
localparam CHANNEL_NUM = 4; // 4 channels: req, resp, data, snp
// 4*4 nodes max
localparam NodeID_X_Width = 2;
localparam NodeID_Y_Width = 2;
localparam NodeID_Device_Port_Width = 2;
localparam NodeID_Device_Id_Width = 1;
localparam NodeID_Width = NodeID_X_Width + NodeID_Y_Width + NodeID_Device_Port_Width + NodeID_Device_Id_Width; // 7
localparam TxnID_Width = 12;
localparam QoS_Value_Width = 4;
localparam FLIT_LENGTH = 256;
localparam INPUT_PORT_NUMBER = 6; // N,S,E,W,L
localparam INPUT_PORT_NUMBER_IDX_W = INPUT_PORT_NUMBER > 1 ? $clog2(INPUT_PORT_NUMBER) : 1;
localparam OUTPUT_PORT_NUMBER = 6; // N,S,E,W,L
localparam ROUTER_PORT_NUMBER = 4;
localparam LOCAL_PORT_NUMBER = INPUT_PORT_NUMBER-ROUTER_PORT_NUMBER;
`ifdef COMMON_QOS_EXTRA_RT_VC
localparam QOS_VC_NUM_PER_INPUT = 1;
`else
localparam QOS_VC_NUM_PER_INPUT = 0;
`endif
localparam VC_ID_NUM_MAX = (CHANNEL_NUM-1)+LOCAL_PORT_NUMBER+QOS_VC_NUM_PER_INPUT;
localparam VC_ID_NUM_MAX_W = VC_ID_NUM_MAX > 1 ? $clog2(VC_ID_NUM_MAX) : 1;
localparam SA_GLOBAL_INPUT_NUM_MAX = (CHANNEL_NUM-1)+LOCAL_PORT_NUMBER;
localparam SA_GLOBAL_INPUT_NUM_MAX_W = SA_GLOBAL_INPUT_NUM_MAX > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_MAX) : 1;
localparam VC_DEPTH_MAX = 4;
`ifdef VC_DATA_USE_DUAL_PORT_RAM
`ifdef RETURN_CREDIT_AT_SA_STAGE
localparam VC_DPRAM_DEPTH_MAX = VC_ID_NUM_MAX * (VC_DEPTH_MAX+1);
localparam VC_BUFFER_DEPTH_MAX_W = (VC_DEPTH_MAX+1) > 1 ? $clog2(VC_DEPTH_MAX+1) : 1;
`else
localparam VC_DPRAM_DEPTH_MAX = VC_ID_NUM_MAX * VC_DEPTH_MAX;
localparam VC_BUFFER_DEPTH_MAX_W = VC_DEPTH_MAX > 1 ? $clog2(VC_DEPTH_MAX) : 1;
`endif
localparam VC_DPRAM_DEPTH_MAX_W = VC_DPRAM_DEPTH_MAX > 1 ? $clog2(VC_DPRAM_DEPTH_MAX) : 1;
`endif
typedef enum logic [2:0] {
N = 0,
S = 1,
E = 2,
W = 3,
L0 = 4,
L1 = 5,
L2 = 6,
L3 = 7
} io_port_t;
typedef struct packed {
logic [NodeID_X_Width-1:0] x_position;
logic [NodeID_Y_Width-1:0] y_position;
logic [NodeID_Device_Port_Width-1:0] device_port;
logic [1-1:0] device_id;
} node_id_t;
`ifdef VC_DATA_USE_DUAL_PORT_RAM
typedef struct packed {
logic [VC_DPRAM_DEPTH_MAX_W-1:0] dpram_idx; // == VC_BUFFER_DEPTH * vc_id + per_vc_idx
logic [VC_BUFFER_DEPTH_MAX_W-1:0] per_vc_idx;
} dpram_used_idx_t;
`endif
typedef struct packed {
node_id_t tgt_id; // target id
node_id_t src_id; // source id
logic [TxnID_Width-1:0] txn_id; // transaction id
io_port_t look_ahead_routing;
`ifdef USE_QOS_VALUE
logic [QoS_Value_Width-1:0] qos_value;
`endif
`ifdef VC_DATA_USE_DUAL_PORT_RAM
dpram_used_idx_t dpram_used_idx;
`endif
} flit_dec_t;
typedef struct packed {
logic common_vld;
logic rt_vld;
} vc_select_vld_t;
typedef struct packed {
logic [VC_ID_NUM_MAX_W-1:0] common_vc_id;
logic [VC_ID_NUM_MAX_W-1:0] rt_vc_id;
} vc_select_vc_id_t;
endpackage
`endif

138
rtl/input_port.sv Normal file
View File

@@ -0,0 +1,138 @@
module input_port
import rvh_noc_pkg::*;
#(
parameter type flit_payload_t = logic[256-1:0],
parameter VC_NUM = 1,
parameter VC_DEPTH = 1,
parameter VC_NUM_IDX_W =VC_NUM > 1 ? $clog2(VC_NUM) : 1,
parameter INPUT_PORT_NO = 0
)
(
// input from other router or local port
input logic rx_flit_pend_i,
input logic rx_flit_v_i,
input flit_payload_t rx_flit_i,
input logic [VC_NUM_IDX_W-1:0] rx_flit_vc_id_i,
input io_port_t rx_flit_look_ahead_routing_i,
// free vc credit sent to sender
output logic rx_lcrd_v_o,
output logic [VC_ID_NUM_MAX_W-1:0] rx_lcrd_id_o,
// output head flit ctrl info to SA & RC unit
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,
`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,
`ifndef SYNTHESIS
// router addr
input logic [NodeID_X_Width-1:0] node_id_x_ths_hop_i,
input logic [NodeID_Y_Width-1:0] node_id_y_ths_hop_i,
`endif
input logic clk,
input logic rstn
);
flit_dec_t flit_ctrl_info;
// 1 decode flit, get input vc and routing info
input_port_flit_decoder
#(
.flit_payload_t (flit_payload_t)
// .VC_NUM_IDX_W (VC_NUM_IDX_W)
)
input_port_flit_decoder_u
(
.flit_v_i (rx_flit_v_i ),
.flit_i (rx_flit_i ),
.flit_look_ahead_routing_i(rx_flit_look_ahead_routing_i),
.flit_dec_o (flit_ctrl_info )
);
// 2 input vc fifo
input_port_vc
#(
.flit_payload_t (flit_payload_t ),
.VC_NUM (VC_NUM ),
.VC_DEPTH (VC_DEPTH )
)
input_port_vc_u
(
// input from input port
.flit_v_i (rx_flit_v_i ),
.flit_i (rx_flit_i ),
.flit_dec_i (flit_ctrl_info ),
.flit_vc_id_i (rx_flit_vc_id_i),
// free vc credit sent to sender
.lcrd_v_o (rx_lcrd_v_o ),
.lcrd_id_o (rx_lcrd_id_o ),
// output ctrl to local allocate
.vc_ctrl_head_vld_o (vc_ctrl_head_vld_o),
.vc_ctrl_head_o (vc_ctrl_head_o ),
// output data to switch traversal
.vc_data_head_o (vc_data_head_o ),
// input pop flit ctrl fifo (comes from SA stage)
.inport_read_enable_sa_stage_i (inport_read_enable_sa_stage_i ),
.inport_read_vc_id_sa_stage_i (inport_read_vc_id_sa_stage_i ),
`ifdef VC_DATA_USE_DUAL_PORT_RAM
.inport_read_dpram_idx_i (inport_read_dpram_idx_i ),
`endif
// input pop flit ctrl fifo (comes from ST stage)
.inport_read_enable_st_stage_i (inport_read_enable_st_stage_i ),
.inport_read_vc_id_st_stage_i (inport_read_vc_id_st_stage_i ),
.clk (clk ),
.rstn (rstn )
);
`ifndef SYNTHESIS
`ifdef V_INPORT_PRINT_EN
// debug print
always_ff @(posedge clk) begin
if(rstn) begin
if(rx_flit_v_i) begin
$display("[%16d] info: receive flit: router:(%d,%d); inport: %1d(N0,S1,E2,W3,L4-7); vc_id: %1d; look_ahead_routing: %1d(N0,S1,E2,W3,L4-7), QoS = %d",
$time(),
node_id_x_ths_hop_i, node_id_y_ths_hop_i,
INPUT_PORT_NO,
rx_flit_vc_id_i,
flit_ctrl_info.look_ahead_routing,
rx_flit_i[QoS_Value_Width-1:0]);
$write(" ");
$display("txn_id: 0x%h, sender: (%d,%d), sender_local_port: %1d",
flit_ctrl_info.txn_id,
flit_ctrl_info.src_id.x_position, flit_ctrl_info.src_id.y_position,
flit_ctrl_info.src_id.device_port);
$write(" ");
$display("tgt_id: (%d,%d), tgt_local_port: %1d",
flit_ctrl_info.tgt_id.x_position, flit_ctrl_info.tgt_id.y_position, flit_ctrl_info.tgt_id.device_port);
end
end
end
`endif
`endif
endmodule

View File

@@ -0,0 +1,8 @@
for chi, the least significant bit represents:
| field | width | bits in flit | comments |
| ----- | --------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| QoS | 4 | [0:3] | ascending values of QoS indicate higher priority levels, not used, place holder |
| TgtID | NodeID_Width, 7 to 11 | [4:4+NodeID_Width-1] | node ID of the component to which the message is targeted |
| SrcID | NodeID_Width, 7 to 11 | [4+NodeID_Width:4+NodeID_Width+NodeID_Width-1] | node ID of the component from which the message is sent |
| TxnID | 12 | [4+NodeID_Width+NodeID_Width:4+NodeID_Width+NodeID_Width+12-1] | transaction identifier of the message |

View File

@@ -0,0 +1,24 @@
module input_port_flit_decoder
import rvh_noc_pkg::*;
#(
parameter type flit_payload_t = logic[256-1:0]
// parameter VC_NUM_IDX_W = 1
)
(
input logic flit_v_i,
input flit_payload_t flit_i,
input io_port_t flit_look_ahead_routing_i,
output flit_dec_t flit_dec_o
);
`ifdef USE_QOS_VALUE
assign flit_dec_o.qos_value = flit_i[QoS_Value_Width-1:0];
`endif
assign flit_dec_o.tgt_id = flit_i[QoS_Value_Width+NodeID_Width-1:QoS_Value_Width];
assign flit_dec_o.src_id = flit_i[QoS_Value_Width+NodeID_Width+NodeID_Width-1:QoS_Value_Width+NodeID_Width];
assign flit_dec_o.txn_id = flit_i[QoS_Value_Width+NodeID_Width+NodeID_Width+TxnID_Width-1:QoS_Value_Width+NodeID_Width+NodeID_Width];
assign flit_dec_o.look_ahead_routing = flit_look_ahead_routing_i;
endmodule

289
rtl/input_port_vc.sv Normal file
View File

@@ -0,0 +1,289 @@
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;
assign vc_ctrl_din.txn_id = flit_dec_i.txn_id;
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))
else $fatal("noc_input_vc: rt VC has flit with lower QoS value, txn_id: 0x%x", vc_ctrl_head[i].txn_id);
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))
else $fatal("noc_input_vc: common VC has flit with highest QoS value, txn_id: 0x%x", vc_ctrl_head[i].txn_id);
end
endgenerate
`endif
`endif
endmodule

516
rtl/input_to_output.sv Normal file
View File

@@ -0,0 +1,516 @@
// this module connects switch allocation stage to switch traversal stage
// NOTE: if change to sram as input buffer, the read should conduct right after local allocate
module input_to_output
import rvh_noc_pkg::*;
#(
parameter INPUT_PORT_NUM = 5,
parameter OUTPUT_PORT_NUM = 5,
parameter LOCAL_PORT_NUM = INPUT_PORT_NUM-4,
parameter SA_GLOBAL_INPUT_NUM_N = 4,
parameter SA_GLOBAL_INPUT_NUM_S = 4,
parameter SA_GLOBAL_INPUT_NUM_E = 2,
parameter SA_GLOBAL_INPUT_NUM_W = 2,
parameter SA_GLOBAL_INPUT_NUM_L = 4,
parameter SA_GLOBAL_INPUT_NUM_N_W = SA_GLOBAL_INPUT_NUM_N > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_N) : 1,
parameter SA_GLOBAL_INPUT_NUM_S_W = SA_GLOBAL_INPUT_NUM_S > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_S) : 1,
parameter SA_GLOBAL_INPUT_NUM_E_W = SA_GLOBAL_INPUT_NUM_E > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_E) : 1,
parameter SA_GLOBAL_INPUT_NUM_W_W = SA_GLOBAL_INPUT_NUM_W > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_W) : 1,
parameter SA_GLOBAL_INPUT_NUM_L_W = SA_GLOBAL_INPUT_NUM_L > 1 ? $clog2(SA_GLOBAL_INPUT_NUM_L) : 1
)
(
// input from sa global allocation
input logic [OUTPUT_PORT_NUM-1:0] sa_global_vld_i,
// input logic [OUTPUT_PORT_NUM-1:0][SA_GLOBAL_INPUT_NUM_MAX_W-1:0] sa_global_inport_id_i,
input logic [OUTPUT_PORT_NUM-1:0][SA_GLOBAL_INPUT_NUM_MAX-1:0] sa_global_inport_id_oh_i,
input logic [OUTPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] sa_global_inport_vc_id_i,
// input from vc allocation
input logic [OUTPUT_PORT_NUM-1:0] vc_assignment_vld_i,
input logic [OUTPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] vc_assignment_vc_id_i,
input io_port_t [OUTPUT_PORT_NUM-1:0] look_ahead_routing_sel_i,
// output to input port buffer to get selected flit
output logic [INPUT_PORT_NUM-1:0] inport_read_enable_o,
// output io_port_t [INPUT_PORT_NUM-1:0] inport_read_outport_id_o,
output logic [INPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] inport_read_vc_id_o,
// output io_port_t [INPUT_PORT_NUM-1:0] inport_look_ahead_routing_o,
// output to switch to let outport select inport
output logic [OUTPUT_PORT_NUM-1:0] outport_vld_o,
output io_port_t [OUTPUT_PORT_NUM-1:0] outport_select_inport_id_o,
output logic [OUTPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] outport_vc_id_o,
output io_port_t [OUTPUT_PORT_NUM-1:0] outport_look_ahead_routing_o,
// output to outport vc credit counter to consume one credit
output logic [OUTPUT_PORT_NUM-1:0] consume_vc_credit_vld_o,
output logic [OUTPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] consume_vc_credit_vc_id_o
);
genvar i, j, k;
io_port_t [OUTPUT_PORT_NUM-1:0] inport_id_per_outport;
logic [OUTPUT_PORT_NUM-1:0][INPUT_PORT_NUM-1:0] inport_id_oh_per_outport;
logic [INPUT_PORT_NUM-1:0][OUTPUT_PORT_NUM-1:0] outport_id_oh_per_inport;
// outports valid signal
generate
for(i = 0; i < OUTPUT_PORT_NUM; i++) begin: gen_consume_vc_credit
assign consume_vc_credit_vld_o [i] = sa_global_vld_i[i] & vc_assignment_vld_i[i];
assign consume_vc_credit_vc_id_o[i] = vc_assignment_vc_id_i[i];
end
endgenerate
assign outport_vld_o = consume_vc_credit_vld_o;
assign outport_select_inport_id_o = inport_id_per_outport;
assign outport_vc_id_o = vc_assignment_vc_id_i;
assign outport_look_ahead_routing_o = look_ahead_routing_sel_i;
// map outports to per inport
// inport_read_enable_o
generate
for(i = 0; i < INPUT_PORT_NUM; i++) begin
for(j = 0; j < OUTPUT_PORT_NUM; j++) begin
assign outport_id_oh_per_inport[i][j] = inport_id_oh_per_outport[j][i];
end
end
endgenerate
generate
for(i = 0; i < INPUT_PORT_NUM; i++) begin
assign inport_read_enable_o[i] = |(outport_id_oh_per_inport[i] & vc_assignment_vld_i);
end
endgenerate
// inport_read_vc_id_o
logic [OUTPUT_PORT_NUM-1:0][INPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] inport_vc_id_oh_per_outport;
logic [INPUT_PORT_NUM-1:0][OUTPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] outport_vc_id_oh_per_inport;
logic [INPUT_PORT_NUM*VC_ID_NUM_MAX_W-1:0][OUTPUT_PORT_NUM-1:0] outport_vc_id_oh_per_inport_mid1;
logic [INPUT_PORT_NUM*VC_ID_NUM_MAX_W-1:0] outport_vc_id_oh_per_inport_mid2;
generate
for(i = 0; i < OUTPUT_PORT_NUM; i++) begin
for(j = 0; j < INPUT_PORT_NUM; j++) begin
assign inport_vc_id_oh_per_outport[i][j] = {VC_ID_NUM_MAX_W{inport_id_oh_per_outport[i][j]}} & sa_global_inport_vc_id_i[i];
end
end
endgenerate
generate
for(i = 0; i < INPUT_PORT_NUM; i++) begin
for(j = 0; j < OUTPUT_PORT_NUM; j++) begin
assign outport_vc_id_oh_per_inport[i][j] = inport_vc_id_oh_per_outport[j][i];
end
end
endgenerate
generate
for(i = 0; i < INPUT_PORT_NUM; i++) begin
for(j = 0; j < OUTPUT_PORT_NUM; j++) begin
for(k = 0; k < VC_ID_NUM_MAX_W; k++) begin
assign outport_vc_id_oh_per_inport_mid1[i*VC_ID_NUM_MAX_W+k][j] = outport_vc_id_oh_per_inport[i][j][k];
end
end
end
endgenerate
generate
for(i = 0; i < INPUT_PORT_NUM*VC_ID_NUM_MAX_W; i++) begin
assign outport_vc_id_oh_per_inport_mid2[i] = |(outport_vc_id_oh_per_inport_mid1[i]);
end
endgenerate
generate
for(i = 0; i < INPUT_PORT_NUM; i++) begin
for(j = 0; j < VC_ID_NUM_MAX_W; j++) begin
assign inport_read_vc_id_o[i][j] = outport_vc_id_oh_per_inport_mid2[i*VC_ID_NUM_MAX_W+j];
end
end
endgenerate
// always_comb begin
// // inport_read_enable_o = '0;
// inport_read_vc_id_o = '0;
// for(int i = 0; i < INPUT_PORT_NUM; i++) begin
// for(int j = 0; j < OUTPUT_PORT_NUM; j++) begin
// if((inport_id_per_outport[j] == i[$bits(io_port_t)-1:0]) & consume_vc_credit_vld_o[j]) begin
// // inport_read_enable_o [i] = 1'b1;
// // inport_read_outport_id_o [i] = inport_id_per_outport[j];
// inport_read_vc_id_o [i] = sa_global_inport_vc_id_i[j];
// // inport_look_ahead_routing_o [i] = look_ahead_routing_sel_i[j];
// end
// end
// end
// end
// map sa global input no. to router inport no.
// to N
always_comb begin
inport_id_per_outport[0] = S;
inport_id_oh_per_outport[0] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[0][0]: begin
inport_id_per_outport[0] = S;
inport_id_oh_per_outport[0][1] = 1'b1;
end
sa_global_inport_id_oh_i[0][1]: begin
inport_id_per_outport[0] = E;
inport_id_oh_per_outport[0][2] = 1'b1;
end
sa_global_inport_id_oh_i[0][2]: begin
inport_id_per_outport[0] = W;
inport_id_oh_per_outport[0][3] = 1'b1;
end
sa_global_inport_id_oh_i[0][3]: begin
inport_id_per_outport[0] = L0;
inport_id_oh_per_outport[0][4] = 1'b1;
end
`ifdef LOCAL_PORT_NUM_2
sa_global_inport_id_oh_i[0][4]: begin
inport_id_per_outport[0] = L1;
inport_id_oh_per_outport[0][5] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_3
sa_global_inport_id_oh_i[0][5]: begin
inport_id_per_outport[0] = L2;
inport_id_oh_per_outport[0][6] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_4
sa_global_inport_id_oh_i[0][6]: begin
inport_id_per_outport[0] = L3;
inport_id_oh_per_outport[0][7] = 1'b1;
end
`endif
default: begin
end
endcase
end
// to S
always_comb begin
inport_id_per_outport[1] = N;
inport_id_oh_per_outport[1] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[1][0]: begin
inport_id_per_outport[1] = N;
inport_id_oh_per_outport[1][0] = 1'b1;
end
sa_global_inport_id_oh_i[1][1]: begin
inport_id_per_outport[1] = E;
inport_id_oh_per_outport[1][2] = 1'b1;
end
sa_global_inport_id_oh_i[1][2]: begin
inport_id_per_outport[1] = W;
inport_id_oh_per_outport[1][3] = 1'b1;
end
sa_global_inport_id_oh_i[1][3]: begin
inport_id_per_outport[1] = L0;
inport_id_oh_per_outport[1][4] = 1'b1;
end
`ifdef LOCAL_PORT_NUM_2
sa_global_inport_id_oh_i[1][4]: begin
inport_id_per_outport[1] = L1;
inport_id_oh_per_outport[1][5] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_3
sa_global_inport_id_oh_i[1][5]: begin
inport_id_per_outport[1] = L2;
inport_id_oh_per_outport[1][6] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_4
sa_global_inport_id_oh_i[1][6]: begin
inport_id_per_outport[1] = L3;
inport_id_oh_per_outport[1][7] = 1'b1;
end
`endif
default: begin
end
endcase
end
// to E
always_comb begin
inport_id_per_outport[2] = W;
inport_id_oh_per_outport[2] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[2][0]: begin
inport_id_per_outport[2] = W;
inport_id_oh_per_outport[2][3] = 1'b1;
end
sa_global_inport_id_oh_i[2][1]: begin
inport_id_per_outport[2] = L0;
inport_id_oh_per_outport[2][4] = 1'b1;
end
`ifdef LOCAL_PORT_NUM_2
sa_global_inport_id_oh_i[2][2]: begin
inport_id_per_outport[2] = L1;
inport_id_oh_per_outport[2][5] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_3
sa_global_inport_id_oh_i[2][3]: begin
inport_id_per_outport[2] = L2;
inport_id_oh_per_outport[2][6] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_4
sa_global_inport_id_oh_i[2][4]: begin
inport_id_per_outport[2] = L3;
inport_id_oh_per_outport[2][7] = 1'b1;
end
`endif
default: begin
end
endcase
end
// to W
always_comb begin
inport_id_per_outport[3] = E;
inport_id_oh_per_outport[3] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[3][0]: begin
inport_id_per_outport[3] = E;
inport_id_oh_per_outport[3][2] = 1'b1;
end
sa_global_inport_id_oh_i[3][1]: begin
inport_id_per_outport[3] = L0;
inport_id_oh_per_outport[3][4] = 1'b1;
end
`ifdef LOCAL_PORT_NUM_2
sa_global_inport_id_oh_i[3][2]: begin
inport_id_per_outport[3] = L1;
inport_id_oh_per_outport[3][5] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_3
sa_global_inport_id_oh_i[3][3]: begin
inport_id_per_outport[3] = L2;
inport_id_oh_per_outport[3][6] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_4
sa_global_inport_id_oh_i[3][4]: begin
inport_id_per_outport[3] = L3;
inport_id_oh_per_outport[3][7] = 1'b1;
end
`endif
default: begin
end
endcase
end
// to L
`ifdef ALLOW_SAME_ROUTER_L2L_TRANSFER // allow local to local transfer, at least 2 local ports per router
// to L0
always_comb begin
inport_id_per_outport[4+0] = N;
inport_id_oh_per_outport[4+0] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[4+0][0]: begin
inport_id_per_outport[4+0] = N;
inport_id_oh_per_outport[4+0][0] = 1'b1;
end
sa_global_inport_id_oh_i[4+0][1]: begin
inport_id_per_outport[4+0] = S;
inport_id_oh_per_outport[4+0][1] = 1'b1;
end
sa_global_inport_id_oh_i[4+0][2]: begin
inport_id_per_outport[4+0] = E;
inport_id_oh_per_outport[4+0][2] = 1'b1;
end
sa_global_inport_id_oh_i[4+0][3]: begin
inport_id_per_outport[4+0] = W;
inport_id_oh_per_outport[4+0][3] = 1'b1;
end
sa_global_inport_id_oh_i[4+0][4]: begin
inport_id_per_outport[4+0] = L1;
inport_id_oh_per_outport[4+0][5] = 1'b1;
end
`ifdef LOCAL_PORT_NUM_3
sa_global_inport_id_oh_i[4+0][5]: begin
inport_id_per_outport[4+0] = L2;
inport_id_oh_per_outport[4+0][6] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_4
sa_global_inport_id_oh_i[4+0][6]: begin
inport_id_per_outport[4+0] = L3;
inport_id_oh_per_outport[4+0][7] = 1'b1;
end
`endif
default: begin
end
endcase
end
// to L1
always_comb begin
inport_id_per_outport[4+1] = N;
inport_id_oh_per_outport[4+1] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[4+1][0]: begin
inport_id_per_outport[4+1] = N;
inport_id_oh_per_outport[4+1][0] = 1'b1;
end
sa_global_inport_id_oh_i[4+1][1]: begin
inport_id_per_outport[4+1] = S;
inport_id_oh_per_outport[4+1][1] = 1'b1;
end
sa_global_inport_id_oh_i[4+1][2]: begin
inport_id_per_outport[4+1] = E;
inport_id_oh_per_outport[4+1][2] = 1'b1;
end
sa_global_inport_id_oh_i[4+1][3]: begin
inport_id_per_outport[4+1] = W;
inport_id_oh_per_outport[4+1][3] = 1'b1;
end
sa_global_inport_id_oh_i[4+1][4]: begin
inport_id_per_outport[4+1] = L0;
inport_id_oh_per_outport[4+1][4] = 1'b1;
end
`ifdef LOCAL_PORT_NUM_3
sa_global_inport_id_oh_i[4+1][5]: begin
inport_id_per_outport[4+1] = L2;
inport_id_oh_per_outport[4+1][6] = 1'b1;
end
`endif
`ifdef LOCAL_PORT_NUM_4
sa_global_inport_id_oh_i[4+1][6]: begin
inport_id_per_outport[4+1] = L3;
inport_id_oh_per_outport[4+1][7] = 1'b1;
end
`endif
default: begin
end
endcase
end
`ifdef LOCAL_PORT_NUM_3
// to L2
always_comb begin
inport_id_per_outport[4+2] = N;
inport_id_oh_per_outport[4+2] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[4+2][0]: begin
inport_id_per_outport[4+2] = N;
inport_id_oh_per_outport[4+2][0] = 1'b1;
end
sa_global_inport_id_oh_i[4+2][1]: begin
inport_id_per_outport[4+2] = S;
inport_id_oh_per_outport[4+2][1] = 1'b1;
end
sa_global_inport_id_oh_i[4+2][2]: begin
inport_id_per_outport[4+2] = E;
inport_id_oh_per_outport[4+2][2] = 1'b1;
end
sa_global_inport_id_oh_i[4+2][3]: begin
inport_id_per_outport[4+2] = W;
inport_id_oh_per_outport[4+2][3] = 1'b1;
end
sa_global_inport_id_oh_i[4+2][4]: begin
inport_id_per_outport[4+2] = L0;
inport_id_oh_per_outport[4+2][4] = 1'b1;
end
sa_global_inport_id_oh_i[4+2][5]: begin
inport_id_per_outport[4+2] = L1;
inport_id_oh_per_outport[4+2][5] = 1'b1;
end
`ifdef LOCAL_PORT_NUM_4
sa_global_inport_id_oh_i[4+2][6]: begin
inport_id_per_outport[4+2] = L3;
inport_id_oh_per_outport[4+2][7] = 1'b1;
end
`endif
default: begin
end
endcase
end
`endif
`ifdef LOCAL_PORT_NUM_4
// to L3
always_comb begin
inport_id_per_outport[4+3] = N;
inport_id_oh_per_outport[4+3] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[4+3][0]: begin
inport_id_per_outport[4+3] = N;
inport_id_oh_per_outport[4+3][0] = 1'b1;
end
sa_global_inport_id_oh_i[4+3][1]: begin
inport_id_per_outport[4+3] = S;
inport_id_oh_per_outport[4+3][1] = 1'b1;
end
sa_global_inport_id_oh_i[4+3][2]: begin
inport_id_per_outport[4+3] = E;
inport_id_oh_per_outport[4+3][2] = 1'b1;
end
sa_global_inport_id_oh_i[4+3][3]: begin
inport_id_per_outport[4+3] = W;
inport_id_oh_per_outport[4+3][3] = 1'b1;
end
sa_global_inport_id_oh_i[4+3][4]: begin
inport_id_per_outport[4+3] = L0;
inport_id_oh_per_outport[4+3][4] = 1'b1;
end
sa_global_inport_id_oh_i[4+3][5]: begin
inport_id_per_outport[4+3] = L1;
inport_id_oh_per_outport[4+3][5] = 1'b1;
end
sa_global_inport_id_oh_i[4+3][6]: begin
inport_id_per_outport[4+3] = L2;
inport_id_oh_per_outport[4+3][6] = 1'b1;
end
default: begin
end
endcase
end
`endif
`else
generate
if(LOCAL_PORT_NUM > 0) begin: gen_have_multi_local_port
for(i = 0; i < LOCAL_PORT_NUM; i++) begin: gen_multi_local_port
always_comb begin
inport_id_per_outport[4+i] = N;
inport_id_oh_per_outport[4+i] = '0;
unique case(1'b1)
sa_global_inport_id_oh_i[4+i][0]: begin
inport_id_per_outport[4+i] = N;
inport_id_oh_per_outport[4+i][0] = 1'b1;
end
sa_global_inport_id_oh_i[4+i][1]: begin
inport_id_per_outport[4+i] = S;
inport_id_oh_per_outport[4+i][1] = 1'b1;
end
sa_global_inport_id_oh_i[4+i][2]: begin
inport_id_per_outport[4+i] = E;
inport_id_oh_per_outport[4+i][2] = 1'b1;
end
sa_global_inport_id_oh_i[4+i][3]: begin
inport_id_per_outport[4+i] = W;
inport_id_oh_per_outport[4+i][3] = 1'b1;
end
default: begin
end
endcase
end
end
end
endgenerate
`endif
endmodule

View File

@@ -0,0 +1,329 @@
// this module is at local device side, use to handle local device credit based flow control
module local_port_couple_module
import rvh_noc_pkg::*;
#(
parameter VC_NUM_OUTPORT = 2,
parameter VC_NUM_OUTPORT_IDX_W = VC_NUM_OUTPORT > 1 ? $clog2(VC_NUM_OUTPORT) : 1,
parameter VC_DEPTH_OUTPORT = 2,
parameter VC_DEPTH_OUTPORT_COUNTER_W = $clog2(VC_DEPTH_OUTPORT + 1),
// for local ports, always OUTPUT_TO_L
parameter OUTPUT_TO_N = 0,
parameter OUTPUT_TO_S = 0,
parameter OUTPUT_TO_E = 0,
parameter OUTPUT_TO_W = 0,
parameter OUTPUT_TO_L = 1
)
(
// input vc head to calculate next routing
input logic [NodeID_X_Width-1:0] node_id_x_tgt_i,
input logic [NodeID_Y_Width-1:0] node_id_y_tgt_i,
`ifdef ALLOW_SAME_ROUTER_L2L_TRANSFER
input logic [NodeID_Device_Port_Width-1:0] device_port_tgt_i,
`endif
// input this hop xy addr
input logic [NodeID_X_Width-1:0] node_id_x_src_i,
input logic [NodeID_Y_Width-1:0] node_id_y_src_i,
// output look ahead routing result
output io_port_t look_ahead_routing_o,
// free credit in from router
input logic tx_lcrd_v_i,
input logic [VC_ID_NUM_MAX_W-1:0] tx_lcrd_id_i,
// consume credit
input logic flit_vld_i,
input logic [QoS_Value_Width-1:0] flit_qos_value_i,
output logic free_credit_vld_o,
output logic [VC_NUM_OUTPORT_IDX_W-1:0] free_credit_vc_id_o,
input logic clk,
input logic rstn
);
logic [VC_NUM_OUTPORT-1:0][VC_DEPTH_OUTPORT_COUNTER_W-1:0] vc_credit_counter;
logic [VC_NUM_OUTPORT-1:0] vc_credit_counter_non_zero;
logic [VC_NUM_OUTPORT-QOS_VC_NUM_PER_INPUT-1:0] vc_allocate_common_vc_grt_oh;
logic [$clog2(VC_NUM_OUTPORT-QOS_VC_NUM_PER_INPUT)-1:0] vc_allocate_common_vc_grt_idx;
`ifdef COMMON_QOS_EXTRA_RT_VC
logic [QOS_VC_NUM_PER_INPUT-1:0] vc_allocate_rt_vc_grt_oh;
logic [$clog2(QOS_VC_NUM_PER_INPUT)-1:0] vc_allocate_rt_vc_grt_idx;
`else
logic [1-1:0] vc_allocate_rt_vc_grt_oh;
logic [$clog2(1)-1:0] vc_allocate_rt_vc_grt_idx;
`endif
logic [VC_NUM_OUTPORT_IDX_W-1:0] preferred_vc_id;
// to send flit buffer
logic flit_buffer_head_rt_vc_en;
logic free_credit_vld;
logic flit_buffer_dequeue_vld;
logic consume_vc_credit_vld;
logic [VC_NUM_OUTPORT_IDX_W-1:0] consume_vc_credit_vc_id;
// 1st phase: calculate look ahead routing
local_port_look_adead_routing
local_port_look_adead_routing_u
(
.node_id_x_tgt_i (node_id_x_tgt_i ),
.node_id_y_tgt_i (node_id_y_tgt_i ),
`ifdef ALLOW_SAME_ROUTER_L2L_TRANSFER
.device_port_tgt_i (device_port_tgt_i),
`endif
.node_id_x_src_i (node_id_x_src_i ),
.node_id_y_src_i (node_id_y_src_i ),
.look_ahead_routing_o ( look_ahead_routing_o)
);
// 2nd phase: choose input vc
assign flit_buffer_head_rt_vc_en = QOS_VC_NUM_PER_INPUT && (flit_qos_value_i == '1);
assign free_credit_vld = (
`ifdef COMMON_QOS_EXTRA_RT_VC
(flit_buffer_head_rt_vc_en & (|(vc_credit_counter_non_zero[QOS_VC_NUM_PER_INPUT-1:0]))) |
`endif
(~flit_buffer_head_rt_vc_en & (|(vc_credit_counter_non_zero[VC_NUM_OUTPORT-1:QOS_VC_NUM_PER_INPUT])))
);
assign free_credit_vld_o = free_credit_vld;
assign free_credit_vc_id_o = consume_vc_credit_vc_id;
assign flit_buffer_dequeue_vld = flit_vld_i & // head valid
free_credit_vld; // vc not empty
// rr for vc allocation
generate
for(genvar i = 0; i < VC_NUM_OUTPORT; i++) begin: gen_vc_credit_counter_non_zero
assign vc_credit_counter_non_zero[i] = ~(vc_credit_counter[i] == '0);
end
endgenerate
one_hot_rr_arb #(
.N_INPUT (VC_NUM_OUTPORT-QOS_VC_NUM_PER_INPUT)
)
vc_allocate_common_vc_rr_arb_u
(
.req_i (vc_credit_counter_non_zero[VC_NUM_OUTPORT-1:QOS_VC_NUM_PER_INPUT] ),
.update_i (|(vc_credit_counter_non_zero[VC_NUM_OUTPORT-1:QOS_VC_NUM_PER_INPUT])),
.grt_o (vc_allocate_common_vc_grt_oh ),
.grt_idx_o (vc_allocate_common_vc_grt_idx ),
.rstn (rstn ),
.clk (clk )
);
`ifdef COMMON_QOS_EXTRA_RT_VC
generate
if(QOS_VC_NUM_PER_INPUT > 1) begin: gen_vc_allocate_rt_vc_rr_arb_u
one_hot_rr_arb #(
.N_INPUT (QOS_VC_NUM_PER_INPUT)
)
vc_allocate_rt_vc_rr_arb_u
(
.req_i (vc_credit_counter_non_zero[QOS_VC_NUM_PER_INPUT-1:0] ),
.update_i (|(vc_credit_counter_non_zero[QOS_VC_NUM_PER_INPUT-1:0])),
.grt_o (vc_allocate_rt_vc_grt_oh ),
.grt_idx_o (vc_allocate_rt_vc_grt_idx ),
.rstn (rstn ),
.clk (clk )
);
end else begin
assign vc_allocate_rt_vc_grt_oh = vc_credit_counter_non_zero[0];
assign vc_allocate_rt_vc_grt_idx = '0;
end
endgenerate
`else
assign vc_allocate_rt_vc_grt_oh = '0;
assign vc_allocate_rt_vc_grt_idx = '0;
`endif
// credit counter
assign consume_vc_credit_vld = flit_buffer_dequeue_vld;
assign consume_vc_credit_vc_id = flit_buffer_head_rt_vc_en ? vc_allocate_rt_vc_grt_idx :
vc_credit_counter_non_zero[preferred_vc_id] ? preferred_vc_id :
vc_allocate_common_vc_grt_idx+QOS_VC_NUM_PER_INPUT;
output_port_vc_credit_counter
#(
.VC_NUM (VC_NUM_OUTPORT ),
.VC_DEPTH (VC_DEPTH_OUTPORT )
)
output_port_vc_credit_counter_u (
.free_vc_credit_vld_i (tx_lcrd_v_i ),
.free_vc_credit_vc_id_i (tx_lcrd_id_i ),
.consume_vc_credit_vld_i (consume_vc_credit_vld ),
.consume_vc_credit_vc_id_i (consume_vc_credit_vc_id ),
.vc_credit_counter_o (vc_credit_counter ),
.clk (clk ),
.rstn (rstn )
);
// select preferred vc id for different output ports
// to N vc:
// vc0
generate
if(OUTPUT_TO_N) begin: gen_output_to_n // output to N, next hop input is S
always_comb begin
preferred_vc_id = '0;
unique case(look_ahead_routing_o)
S: begin
preferred_vc_id = 0;
end
L0: begin
preferred_vc_id = 1;
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
preferred_vc_id = 2;
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
preferred_vc_id = 3;
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
preferred_vc_id = 4;
end
`endif
default: begin
end
endcase
preferred_vc_id = preferred_vc_id + QOS_VC_NUM_PER_INPUT;
end
end
if(OUTPUT_TO_S) begin: gen_output_to_s // output to S, next hop input is N
always_comb begin
preferred_vc_id = '0;
unique case(look_ahead_routing_o)
N: begin
preferred_vc_id = 0;
end
L0: begin
preferred_vc_id = 1;
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
preferred_vc_id = 2;
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
preferred_vc_id = 3;
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
preferred_vc_id = 4;
end
`endif
default: begin
end
endcase
preferred_vc_id = preferred_vc_id + QOS_VC_NUM_PER_INPUT;
end
end
if(OUTPUT_TO_E) begin: gen_output_to_e // output to E, next hop input is W
always_comb begin
preferred_vc_id = '0;
unique case(look_ahead_routing_o)
N: begin
preferred_vc_id = 0;
end
S: begin
preferred_vc_id = 1;
end
W: begin
preferred_vc_id = 2;
end
L0: begin
preferred_vc_id = 3;
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
preferred_vc_id = 4;
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
preferred_vc_id = 5;
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
preferred_vc_id = 6;
end
`endif
default: begin
end
endcase
preferred_vc_id = preferred_vc_id + QOS_VC_NUM_PER_INPUT;
end
end
if(OUTPUT_TO_W) begin: gen_output_to_w // output to W, next hop input is E
always_comb begin
preferred_vc_id = '0;
unique case(look_ahead_routing_o)
N: begin
preferred_vc_id = 0;
end
S: begin
preferred_vc_id = 1;
end
E: begin
preferred_vc_id = 2;
end
L0: begin
preferred_vc_id = 3;
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
preferred_vc_id = 4;
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
preferred_vc_id = 5;
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
preferred_vc_id = 6;
end
`endif
default: begin
end
endcase
preferred_vc_id = preferred_vc_id + QOS_VC_NUM_PER_INPUT;
end
end
if(OUTPUT_TO_L) begin: gen_output_to_l // output to L, no next hop
always_comb begin
preferred_vc_id = '0;
unique case(look_ahead_routing_o) // assume all local port have 1 vc
default: begin
preferred_vc_id = '0;
end
endcase
preferred_vc_id = preferred_vc_id + QOS_VC_NUM_PER_INPUT;
end
end
endgenerate
endmodule

View File

@@ -0,0 +1,93 @@
// implemented XY routing, for per local sa winnner flit
module local_port_look_adead_routing
import rvh_noc_pkg::*;
#(
)
(
// input vc head to calculate next routing
input logic [NodeID_X_Width-1:0] node_id_x_tgt_i,
input logic [NodeID_Y_Width-1:0] node_id_y_tgt_i,
`ifdef ALLOW_SAME_ROUTER_L2L_TRANSFER
input logic [NodeID_Device_Port_Width-1:0] device_port_tgt_i,
`endif
// input this hop xy addr
input logic [NodeID_X_Width-1:0] node_id_x_src_i,
input logic [NodeID_Y_Width-1:0] node_id_y_src_i,
// output look ahead routing result
output io_port_t look_ahead_routing_o
);
// 2nd phase: Define new Next-port
logic x_nxt_equal_x_dst;
logic x_nxt_less_x_dst;
`ifdef ALLOW_SAME_ROUTER_L2L_TRANSFER
logic y_nxt_equal_y_dst;
`endif
logic y_nxt_less_y_dst;
assign x_nxt_equal_x_dst = (node_id_x_src_i == node_id_x_tgt_i);
assign x_nxt_less_x_dst = (node_id_x_src_i < node_id_x_tgt_i);
`ifdef ALLOW_SAME_ROUTER_L2L_TRANSFER
assign y_nxt_equal_y_dst = (node_id_y_src_i == node_id_y_tgt_i);
`endif
assign y_nxt_less_y_dst = (node_id_y_src_i < node_id_y_tgt_i);
`ifdef ALLOW_SAME_ROUTER_L2L_TRANSFER
always_comb begin
if(x_nxt_equal_x_dst) begin
if(y_nxt_equal_y_dst) begin
unique case(device_port_tgt_i) // chooose which local port to route to
0: begin
look_ahead_routing_o = L0;
end
`ifdef LOCAL_PORT_NUM_2
1: begin
look_ahead_routing_o = L1;
end
`endif
`ifdef LOCAL_PORT_NUM_3
2: begin
look_ahead_routing_o = L2;
end
`endif
`ifdef LOCAL_PORT_NUM_4
3: begin
look_ahead_routing_o = L3;
end
`endif
default: begin
look_ahead_routing_o = L0;
end
endcase
end else if(y_nxt_less_y_dst) begin
look_ahead_routing_o = N;
end else begin
look_ahead_routing_o = S;
end
end else if(x_nxt_less_x_dst) begin
look_ahead_routing_o = E;
end else begin
look_ahead_routing_o = W;
end
end
`else
always_comb begin
if(x_nxt_equal_x_dst) begin
if(y_nxt_less_y_dst) begin
look_ahead_routing_o = N;
end else begin
look_ahead_routing_o = S;
end
end else if(x_nxt_less_x_dst) begin
look_ahead_routing_o = E;
end else begin
look_ahead_routing_o = W;
end
end
`endif
endmodule

96
rtl/look_adead_routing.sv Normal file
View File

@@ -0,0 +1,96 @@
// implemented XY routing, for per local sa winnner flit
module look_ahead_routing
import rvh_noc_pkg::*;
#(
)
(
// input vc head to calculate next routing
input logic vc_ctrl_head_vld_i,
input flit_dec_t vc_ctrl_head_i,
// input this hop xy addr
input logic [NodeID_X_Width-1:0] node_id_x_ths_hop_i,
input logic [NodeID_Y_Width-1:0] node_id_y_ths_hop_i,
// output look ahead routing result
output io_port_t look_ahead_routing_o
);
logic [NodeID_X_Width-1:0] node_id_x_nxt_hop, node_id_x_dst_hop;
logic [NodeID_Y_Width-1:0] node_id_y_nxt_hop, node_id_y_dst_hop;
assign node_id_x_dst_hop = vc_ctrl_head_i.tgt_id.x_position;
assign node_id_y_dst_hop = vc_ctrl_head_i.tgt_id.y_position;
// 1st phase: Assign next address
always_comb begin
node_id_x_nxt_hop = node_id_x_ths_hop_i;
node_id_y_nxt_hop = node_id_y_ths_hop_i;
unique case(vc_ctrl_head_i.look_ahead_routing)
N: begin
node_id_y_nxt_hop = node_id_y_ths_hop_i + 1;
end
S: begin
node_id_y_nxt_hop = node_id_y_ths_hop_i - 1;
end
E: begin
node_id_x_nxt_hop = node_id_x_ths_hop_i + 1;
end
W: begin
node_id_x_nxt_hop = node_id_x_ths_hop_i - 1;
end
default: begin
end
endcase
end
// 2nd phase: Define new Next-port
logic x_nxt_equal_x_dst;
logic x_nxt_less_x_dst;
logic y_nxt_equal_y_dst;
logic y_nxt_less_y_dst;
assign x_nxt_equal_x_dst = (node_id_x_nxt_hop == node_id_x_dst_hop);
assign x_nxt_less_x_dst = (node_id_x_nxt_hop < node_id_x_dst_hop);
assign y_nxt_equal_y_dst = (node_id_y_nxt_hop == node_id_y_dst_hop);
assign y_nxt_less_y_dst = (node_id_y_nxt_hop < node_id_y_dst_hop);
always_comb begin
if(x_nxt_equal_x_dst) begin
if(y_nxt_equal_y_dst) begin
unique case(vc_ctrl_head_i.tgt_id.device_port) // chooose which local port to route to
0: begin
look_ahead_routing_o = L0;
end
`ifdef LOCAL_PORT_NUM_2
1: begin
look_ahead_routing_o = L1;
end
`endif
`ifdef LOCAL_PORT_NUM_3
2: begin
look_ahead_routing_o = L2;
end
`endif
`ifdef LOCAL_PORT_NUM_4
3: begin
look_ahead_routing_o = L3;
end
`endif
default: begin
look_ahead_routing_o = L0;
end
endcase
end else if(y_nxt_less_y_dst) begin
look_ahead_routing_o = N;
end else begin
look_ahead_routing_o = S;
end
end else if(x_nxt_less_x_dst) begin
look_ahead_routing_o = E;
end else begin
look_ahead_routing_o = W;
end
end
endmodule

View File

@@ -0,0 +1,30 @@
module rrv64_cell_clkgate (
input wire clk_i,
input wire clk_enable_i,
input wire clk_senable_i,
output wire clk_gated_o
);
// CKGATE
// CKGATE_inst
// (
// .cko (clk_gated_o),
// .cki (clk_i ),
// .e (clk_enable_i),
// .te (clk_senable_i),
// );
wire clk_en;
reg clk_en_reg;
assign clk_en = clk_enable_i | clk_senable_i;
always @ (clk_i or clk_en) begin
if(clk_i == 1'b0) begin
clk_en_reg <= clk_en;
end
end
assign clk_gated_o = clk_i & clk_en_reg;
endmodule

27
rtl/model/cells/std_dff.sv Executable file
View File

@@ -0,0 +1,27 @@
//===============================================
//Name : STD_DFF
//Author : cuiluping
//Email : luping.cui@rivai-ic.com.cn
//Date : 2019-08-24
//Description : no reset no enable D flip flop
//-----------------------------------------------
//All Rights Reserved by rivai company
//===============================================
module std_dff
#(
parameter WIDTH = 8
)
(
input clk,
input [WIDTH-1:0] d,
output [WIDTH-1:0] q
);
logic [WIDTH-1:0] dff_q;
always_ff @(posedge clk) begin
dff_q <= d;
end
assign q = dff_q;
endmodule

31
rtl/model/cells/std_dffe.sv Executable file
View File

@@ -0,0 +1,31 @@
//===============================================
//Name : STD_DFFE
//Author : cuiluping
//Email : luping.cui@rivai-ic.com.cn
//Date : 2019-08-24
//Description : no reset ,with enable D flip flop
//-----------------------------------------------
//All Rights Reserved by rivai company
//===============================================
module std_dffe
#(
parameter WIDTH = 8
)
(
input clk,
input en,
input [WIDTH-1:0] d,
output [WIDTH-1:0] q
);
logic [WIDTH-1:0] dff_q;
always_ff @(posedge clk) begin
if(en) begin
dff_q <= d;
end
end
assign q = dff_q;
endmodule

34
rtl/model/cells/std_dffr.sv Executable file
View File

@@ -0,0 +1,34 @@
//===============================================
//Name : STD_DFFR
//Author : cuiluping
//Email : luping.cui@rivai-ic.com.cn
//Date : 2019-08-24
//Description : with reset ,no enable D flip flop
//-----------------------------------------------
//All Rights Reserved by rivai company
//===============================================
module std_dffr
#(
parameter WIDTH = 8
)
(
input clk,
input rstn,
input [WIDTH-1:0] d,
output [WIDTH-1:0] q
);
logic [WIDTH-1:0] dff_q;
always_ff @(posedge clk or negedge rstn) begin
if(~rstn)begin
dff_q <= {WIDTH{1'b0}};
end
else begin
dff_q <= d;
end
end
assign q = dff_q;
endmodule

36
rtl/model/cells/std_dffre.sv Executable file
View File

@@ -0,0 +1,36 @@
//===============================================
//Name : STD_DFFRE
//Author : cuiluping
//Email : luping.cui@rivai-ic.com.cn
//Date : 2019-08-24
//Description : with reset ,with enable D flip flop
//-----------------------------------------------
//All Rights Reserved by rivai company
//===============================================
module std_dffre
#(
parameter WIDTH = 8
)
(
input clk,
input rstn,
input en,
input [WIDTH-1:0] d,
output [WIDTH-1:0] q
);
logic [WIDTH-1:0] dff_q;
always_ff @(posedge clk or negedge rstn) begin
if(~rstn)begin
dff_q <= {WIDTH{1'b0}};
end
else if(en)begin
dff_q <= d;
end
end
assign q = dff_q;
endmodule

38
rtl/model/cells/std_dffrve.sv Executable file
View File

@@ -0,0 +1,38 @@
//===============================================
//Name : STD_DFFRVE
//Author : cuiluping
//Email : luping.cui@rivai-ic.com.cn
//Date : 2019-08-24
//Description : with reset ,with enable D flip flop,
// reset value can be configured
//-----------------------------------------------
//All Rights Reserved by rivai company
//===============================================
module std_dffrve
#(
parameter WIDTH = 8
)
(
input clk,
input rstn,
input [WIDTH-1:0] rst_val,
input en,
input [WIDTH-1:0] d,
output [WIDTH-1:0] q
);
logic [WIDTH-1:0] dff_q;
always_ff @(posedge clk or negedge rstn) begin
if(~rstn)begin
dff_q <= rst_val;
end
else if(en)begin
dff_q <= d;
end
end
assign q = dff_q;
endmodule

View File

@@ -0,0 +1,47 @@
// Simple Dual-Port Block RAM with One Clock
// reference: https://docs.xilinx.com/r/en-US/ug901-vivado-synthesis/Single-Port-Block-RAM-No-Change-Mode-Verilog
// File: simple_dual_one_clock.v
module simple_dual_one_clock
#(
parameter ADDR_BITS = 4,
parameter DATA_BITS = 8
// parameter RAM_LATENCY = 1,
// parameter WE_SIZE = 1,
)
(clk,ena,enb,wea,addra,addrb,dia,dob);
input clk,ena,enb,wea;
input [ADDR_BITS-1:0] addra,addrb;
input [DATA_BITS-1:0] dia;
output [DATA_BITS-1:0] dob;
reg [DATA_BITS-1:0] ram [(1'b1<<ADDR_BITS)-1:0];
reg [DATA_BITS-1:0] doa,dob;
always @(posedge clk) begin
if (ena) begin
if (wea)
ram[addra] <= dia;
end
end
always @(posedge clk) begin
if (enb)
dob <= ram[addrb];
end
endmodule

View File

@@ -0,0 +1,268 @@
// vc assignment per output port: assign the final allocated vc to the flit from global sa, use the vc selected at vc selection
module output_port_vc_assignment
import rvh_noc_pkg::*;
#(
parameter OUTPUT_VC_NUM = 4,
parameter OUTPUT_VC_NUM_IDX_W = OUTPUT_VC_NUM > 1 ? $clog2(OUTPUT_VC_NUM) : 1,
parameter SA_GLOBAL_INPUT_NUM = 4,
parameter SA_GLOBAL_INPUT_NUM_IDX_W = SA_GLOBAL_INPUT_NUM > 1 ? $clog2(SA_GLOBAL_INPUT_NUM) : 1,
parameter OUTPUT_TO_N = 0,
parameter OUTPUT_TO_S = 0,
parameter OUTPUT_TO_E = 0,
parameter OUTPUT_TO_W = 0,
parameter OUTPUT_TO_L = 0
)
(
// input from global sa
input logic sa_global_vld_i,
// input logic [SA_GLOBAL_INPUT_NUM_IDX_W-1:0] sa_global_inport_id_i,
`ifdef COMMON_QOS_EXTRA_RT_VC
input logic [QoS_Value_Width-1:0] sa_global_qos_value_i,
`endif
input logic [SA_GLOBAL_INPUT_NUM-1:0] sa_global_inport_id_oh_i,
// input from look-ahead-routing
input io_port_t [SA_GLOBAL_INPUT_NUM-1:0] look_ahead_routing_i, // NOTICE: not all routing results, only the ones connected to this global sa
// input from vc selection
input vc_select_vld_t [OUTPUT_VC_NUM-1:0] vc_select_vld_i,
input vc_select_vc_id_t [OUTPUT_VC_NUM-1:0] vc_select_vc_id_i,
// output
output logic vc_assignment_vld_o,
output logic [VC_ID_NUM_MAX_W-1:0] vc_assignment_vc_id_o,
output io_port_t look_ahead_routing_sel_o
);
genvar i;
// select the look-ahead routing of the flit which wins the global sa
io_port_t look_ahead_routing_sel;
// assign look_ahead_routing_sel = look_ahead_routing_i[sa_global_inport_id_i];
onehot_mux
#(
.SOURCE_COUNT(SA_GLOBAL_INPUT_NUM ),
.DATA_WIDTH ($bits(io_port_t) )
)
onehot_mux_look_ahead_routing_sel_u (
.sel_i (sa_global_inport_id_oh_i ),
.data_i (look_ahead_routing_i ),
.data_o (look_ahead_routing_sel)
);
assign look_ahead_routing_sel_o = look_ahead_routing_sel;
logic sa_global_sel_rt_vc_flit_en;
logic [OUTPUT_VC_NUM-QOS_VC_NUM_PER_INPUT-1:0] vc_select_vld; // if local port as outport, doesn't take rt vc into consideration
logic [OUTPUT_VC_NUM-QOS_VC_NUM_PER_INPUT-1:0][VC_ID_NUM_MAX_W-1:0] vc_select_vc_id; // if local port as outport, doesn't take rt vc into consideration
`ifdef COMMON_QOS_EXTRA_RT_VC
assign sa_global_sel_rt_vc_flit_en = &sa_global_qos_value_i; // rt vc has highest QoS value
`else
assign sa_global_sel_rt_vc_flit_en = '0;
`endif
// vc_select_vld
// for vc_select_vld_i, the [0:QOS_VC_NUM_PER_INPUT-1] is rt vc, [QOS_VC_NUM_PER_INPUT:OUTPUT_VC_NUM-1] is common vc
generate
for(i = 0; i < OUTPUT_VC_NUM-QOS_VC_NUM_PER_INPUT; i++) begin: gen_vc_select_vld
assign vc_select_vld[i] = sa_global_sel_rt_vc_flit_en ? vc_select_vld_i[0].rt_vld : vc_select_vld_i[i+QOS_VC_NUM_PER_INPUT].common_vld;
end
endgenerate
// vc_select_vc_id
generate
for(i = 0; i < OUTPUT_VC_NUM-QOS_VC_NUM_PER_INPUT; i++) begin: gen_vc_select_vc_id
assign vc_select_vc_id[i] = sa_global_sel_rt_vc_flit_en ? vc_select_vc_id_i[0].rt_vc_id : vc_select_vc_id_i[i+QOS_VC_NUM_PER_INPUT].common_vc_id;
end
endgenerate
// vc assignment for different output ports
// to N vc:
// vc0
generate
if(OUTPUT_TO_N) begin: gen_output_to_n // output to N, next hop input is S
always_comb begin
vc_assignment_vld_o = 1'b0;
vc_assignment_vc_id_o = '0;
unique case(look_ahead_routing_sel)
N: begin
vc_assignment_vld_o = vc_select_vld[0];
vc_assignment_vc_id_o = vc_select_vc_id[0];
end
L0: begin
vc_assignment_vld_o = vc_select_vld[1];
vc_assignment_vc_id_o = vc_select_vc_id[1];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
vc_assignment_vld_o = vc_select_vld[2];
vc_assignment_vc_id_o = vc_select_vc_id[2];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
vc_assignment_vld_o = vc_select_vld[3];
vc_assignment_vc_id_o = vc_select_vc_id[3];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
vc_assignment_vld_o = vc_select_vld[4];
vc_assignment_vc_id_o = vc_select_vc_id[4];
end
`endif
default: begin
end
endcase
end
end
if(OUTPUT_TO_S) begin: gen_output_to_s // output to S, next hop input is N
always_comb begin
vc_assignment_vld_o = 1'b0;
vc_assignment_vc_id_o = '0;
unique case(look_ahead_routing_sel)
S: begin
vc_assignment_vld_o = vc_select_vld[0];
vc_assignment_vc_id_o = vc_select_vc_id[0];
end
L0: begin
vc_assignment_vld_o = vc_select_vld[1];
vc_assignment_vc_id_o = vc_select_vc_id[1];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
vc_assignment_vld_o = vc_select_vld[2];
vc_assignment_vc_id_o = vc_select_vc_id[2];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
vc_assignment_vld_o = vc_select_vld[3];
vc_assignment_vc_id_o = vc_select_vc_id[3];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
vc_assignment_vld_o = vc_select_vld[4];
vc_assignment_vc_id_o = vc_select_vc_id[4];
end
`endif
default: begin
end
endcase
end
end
if(OUTPUT_TO_E) begin: gen_output_to_e // output to E, next hop input is W
always_comb begin
vc_assignment_vld_o = 1'b0;
vc_assignment_vc_id_o = '0;
unique case(look_ahead_routing_sel)
N: begin
vc_assignment_vld_o = vc_select_vld[0];
vc_assignment_vc_id_o = vc_select_vc_id[0];
end
S: begin
vc_assignment_vld_o = vc_select_vld[1];
vc_assignment_vc_id_o = vc_select_vc_id[1];
end
E: begin
vc_assignment_vld_o = vc_select_vld[2];
vc_assignment_vc_id_o = vc_select_vc_id[2];
end
L0: begin
vc_assignment_vld_o = vc_select_vld[3];
vc_assignment_vc_id_o = vc_select_vc_id[3];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
vc_assignment_vld_o = vc_select_vld[4];
vc_assignment_vc_id_o = vc_select_vc_id[4];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
vc_assignment_vld_o = vc_select_vld[5];
vc_assignment_vc_id_o = vc_select_vc_id[5];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
vc_assignment_vld_o = vc_select_vld[6];
vc_assignment_vc_id_o = vc_select_vc_id[6];
end
`endif
default: begin
end
endcase
end
end
if(OUTPUT_TO_W) begin: gen_output_to_w // output to W, next hop input is E
always_comb begin
vc_assignment_vld_o = 1'b0;
vc_assignment_vc_id_o = '0;
unique case(look_ahead_routing_sel)
N: begin
vc_assignment_vld_o = vc_select_vld[0];
vc_assignment_vc_id_o = vc_select_vc_id[0];
end
S: begin
vc_assignment_vld_o = vc_select_vld[1];
vc_assignment_vc_id_o = vc_select_vc_id[1];
end
W: begin
vc_assignment_vld_o = vc_select_vld[2];
vc_assignment_vc_id_o = vc_select_vc_id[2];
end
L0: begin
vc_assignment_vld_o = vc_select_vld[3];
vc_assignment_vc_id_o = vc_select_vc_id[3];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
vc_assignment_vld_o = vc_select_vld[4];
vc_assignment_vc_id_o = vc_select_vc_id[4];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
vc_assignment_vld_o = vc_select_vld[5];
vc_assignment_vc_id_o = vc_select_vc_id[5];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
vc_assignment_vld_o = vc_select_vld[6];
vc_assignment_vc_id_o = vc_select_vc_id[6];
end
`endif
default: begin
end
endcase
end
end
if(OUTPUT_TO_L) begin: gen_output_to_l // output to L, no next hop
always_comb begin
vc_assignment_vld_o = 1'b0;
vc_assignment_vc_id_o = '0;
unique case(look_ahead_routing_sel) // assume all local port have 1 vc
default: begin
vc_assignment_vld_o = vc_select_vld_i [0].common_vld;
vc_assignment_vc_id_o = vc_select_vc_id_i[0].common_vc_id;
end
endcase
end
end
endgenerate
endmodule

View File

@@ -0,0 +1,97 @@
// vc credit counter per out port port
module output_port_vc_credit_counter
import rvh_noc_pkg::*;
#(
parameter VC_NUM = 4,
parameter VC_NUM_IDX_W = VC_NUM > 1 ? $clog2(VC_NUM) : 1,
parameter VC_DEPTH = 1,
parameter VC_DEPTH_COUNTER_W = $clog2(VC_DEPTH+1)
)
(
// input new free vc credit
input logic free_vc_credit_vld_i,
input logic [VC_NUM_IDX_W-1:0] free_vc_credit_vc_id_i,
// input new consume vc credit
input logic consume_vc_credit_vld_i,
input logic [VC_NUM_IDX_W-1:0] consume_vc_credit_vc_id_i,
// output to vc selection
output logic [VC_NUM-1:0][VC_DEPTH_COUNTER_W-1:0] vc_credit_counter_o,
input logic clk,
input logic rstn
);
genvar i;
// credit counter
logic [VC_NUM-1:0][VC_DEPTH_COUNTER_W-1:0] vc_credit_counter_d, vc_credit_counter_q;
logic [VC_NUM-1:0][VC_DEPTH_COUNTER_W-1:0] vc_credit_counter_q_plus1, vc_credit_counter_q_minus1;
logic [VC_NUM-1:0] vc_credit_counter_ena;
// credit counter nxt
logic [VC_NUM-1:0] free_vc_credit_vc_id_hit;
logic [VC_NUM-1:0] consume_vc_credit_vc_id_hit;
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_credit_vc_id_hit
assign free_vc_credit_vc_id_hit [i] = free_vc_credit_vld_i & (free_vc_credit_vc_id_i == i[VC_NUM_IDX_W-1:0]);
assign consume_vc_credit_vc_id_hit[i] = consume_vc_credit_vld_i & (consume_vc_credit_vc_id_i == i[VC_NUM_IDX_W-1:0]);
end
endgenerate
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_credit_counter_q_plus1
assign vc_credit_counter_q_plus1[i] = vc_credit_counter_q[i] + 1;
end
endgenerate
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_credit_counter_q_minus1
assign vc_credit_counter_q_minus1[i] = vc_credit_counter_q[i] - 1;
end
endgenerate
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_credit_counter_d
always_comb begin
vc_credit_counter_d [i] = vc_credit_counter_q[i];
vc_credit_counter_ena [i] = 1'b0;
if(free_vc_credit_vc_id_hit[i] & ~consume_vc_credit_vc_id_hit[i]) begin
vc_credit_counter_d [i] = vc_credit_counter_q_plus1[i];
vc_credit_counter_ena [i] = 1'b1;
end else if(~free_vc_credit_vc_id_hit[i] & consume_vc_credit_vc_id_hit[i]) begin
vc_credit_counter_d [i] = vc_credit_counter_q_minus1[i];
vc_credit_counter_ena [i] = 1'b1;
end
end
end
endgenerate
// dff vc_credit_counter_q
generate
for(i = 0; i < VC_NUM; i++) begin: gen_vc_credit_counter_q
std_dffrve
#(.WIDTH(VC_DEPTH_COUNTER_W))
U_DAT_VC_CREDIT_CONTER_REG
(
.clk(clk),
.rstn(rstn),
.rst_val(VC_DEPTH[VC_DEPTH_COUNTER_W-1:0]),
.en(vc_credit_counter_ena[i]),
.d(vc_credit_counter_d[i]),
.q(vc_credit_counter_q[i])
);
`ifndef SYNTHESIS
assert property(@(posedge clk)disable iff(~rstn) ((vc_credit_counter_q[i]) <= VC_DEPTH))
else $fatal("output_port_vc_credit_counter: vc credit counter overflow");
`endif
end
endgenerate
// output to vc selection
assign vc_credit_counter_o = vc_credit_counter_q;
endmodule

View File

@@ -0,0 +1,108 @@
// vc selection per output port to pre-allocate every possible next hop output port for vc assignment
module output_port_vc_selection
import rvh_noc_pkg::*;
#(
parameter OUTPUT_VC_NUM = 4,
parameter OUTPUT_VC_NUM_IDX_W = OUTPUT_VC_NUM > 1 ? $clog2(OUTPUT_VC_NUM) : 1,
parameter OUTPUT_VC_DEPTH = 1,
parameter OUTPUT_VC_DEPTH_IDX_W = $clog2(OUTPUT_VC_DEPTH + 1),
parameter OUTPUT_TO_L = 0
)
(
// input from per output port vc credit counter
input logic [OUTPUT_VC_NUM-1:0][OUTPUT_VC_DEPTH_IDX_W-1:0] vc_credit_counter_i,
// output to vc assignment
output vc_select_vld_t [OUTPUT_VC_NUM-1:0] vc_select_vld_o,
output vc_select_vc_id_t [OUTPUT_VC_NUM-1:0] vc_select_vc_id_o
);
genvar i;
logic [OUTPUT_VC_NUM-1:0] vc_credit_counter_not_empty;
generate
for(i = 0; i < OUTPUT_VC_NUM; i++) begin
assign vc_credit_counter_not_empty[i] = |(vc_credit_counter_i[i]);
end
endgenerate
generate
if(!OUTPUT_TO_L) begin
always_comb begin: comb_common_vc_id
for(int i = QOS_VC_NUM_PER_INPUT; i < OUTPUT_VC_NUM; i++) begin
vc_select_vld_o [i].common_vld = '0;
vc_select_vc_id_o[i].common_vc_id = '0;
vc_select_vld_o [i].rt_vld = '0;
vc_select_vc_id_o[i].rt_vc_id = '0;
if(vc_credit_counter_not_empty[i]) begin // the priority output port vc has free credit, assign it to the flit
vc_select_vld_o [i].common_vld = 1'b1;
vc_select_vc_id_o [i].common_vc_id = i[VC_ID_NUM_MAX_W-1:0];
end else begin // the priority output port vc has no free credit, try other vc
for(int j = QOS_VC_NUM_PER_INPUT; j < OUTPUT_VC_NUM; j++) begin
if(j != i) begin
if(vc_credit_counter_not_empty[j]) begin
vc_select_vld_o [i].common_vld = 1'b1;
vc_select_vc_id_o [i].common_vc_id = j[VC_ID_NUM_MAX_W-1:0];
end
end
end
end
end
end
`ifdef COMMON_QOS_EXTRA_RT_VC
always_comb begin: comb_rt_vc_id
for(int i = 0; i < QOS_VC_NUM_PER_INPUT; i++) begin
vc_select_vld_o [i].common_vld = '0;
vc_select_vc_id_o[i].common_vc_id = '0;
vc_select_vld_o [i].rt_vld = '0;
vc_select_vc_id_o[i].rt_vc_id = '0;
if(vc_credit_counter_not_empty[i]) begin // the priority output port vc has free credit, assign it to the flit
vc_select_vld_o [i].rt_vld = 1'b1;
vc_select_vc_id_o [i].rt_vc_id = i[VC_ID_NUM_MAX_W-1:0];
end else begin // the priority output port vc has no free credit, try other vc
for(int j = 0; j < QOS_VC_NUM_PER_INPUT; j++) begin
if(j != i) begin
if(vc_credit_counter_not_empty[j]) begin
vc_select_vld_o [i].rt_vld = 1'b1;
vc_select_vc_id_o [i].rt_vc_id = j[VC_ID_NUM_MAX_W-1:0];
end
end
end
end
end
end
`endif
end else begin // it is output to L, just common vc
always_comb begin
for(int i = 0; i < OUTPUT_VC_NUM; i++) begin
vc_select_vld_o [i].common_vld = '0;
vc_select_vc_id_o[i].common_vc_id = '0;
vc_select_vld_o [i].rt_vld = '0;
vc_select_vc_id_o[i].rt_vc_id = '0;
if(vc_credit_counter_not_empty[i]) begin // the priority output port vc has free credit, assign it to the flit
vc_select_vld_o [i].common_vld = 1'b1;
vc_select_vc_id_o [i].common_vc_id = i[VC_ID_NUM_MAX_W-1:0];
end else begin // the priority output port vc has no free credit, try other vc
for(int j = 0; j < OUTPUT_VC_NUM; j++) begin
if(j != i) begin
if(vc_credit_counter_not_empty[j]) begin
vc_select_vld_o [i].common_vld = 1'b1;
vc_select_vc_id_o [i].common_vc_id = j[VC_ID_NUM_MAX_W-1:0];
end
end
end
end
end
end
end
endgenerate
endmodule

175
rtl/performance_monitor.sv Normal file
View File

@@ -0,0 +1,175 @@
// this module records many perforance counters
module performance_monitor
import rvh_noc_pkg::*;
#(
parameter INPUT_PORT_NUM = 5,
parameter OUTPUT_PORT_NUM = 5,
parameter LOCAL_PORT_NUM = INPUT_PORT_NUM-4,
parameter VC_NUM_INPUT_N = 1+LOCAL_PORT_NUM,
parameter VC_NUM_INPUT_S = 1+LOCAL_PORT_NUM,
parameter VC_NUM_INPUT_E = 3+LOCAL_PORT_NUM,
parameter VC_NUM_INPUT_W = 3+LOCAL_PORT_NUM,
parameter VC_NUM_INPUT_L = 4,
parameter VC_DEPTH_INPUT_N = 2,
parameter VC_DEPTH_INPUT_S = 2,
parameter VC_DEPTH_INPUT_E = 2,
parameter VC_DEPTH_INPUT_W = 2,
parameter VC_DEPTH_INPUT_L = 2,
parameter VC_DEPTH_INPUT_N_COUNTER_W = $clog2(VC_DEPTH_INPUT_N + 1),
parameter VC_DEPTH_INPUT_S_COUNTER_W = $clog2(VC_DEPTH_INPUT_S + 1),
parameter VC_DEPTH_INPUT_E_COUNTER_W = $clog2(VC_DEPTH_INPUT_E + 1),
parameter VC_DEPTH_INPUT_W_COUNTER_W = $clog2(VC_DEPTH_INPUT_W + 1),
parameter VC_DEPTH_INPUT_L_COUNTER_W = $clog2(VC_DEPTH_INPUT_L + 1)
)
(
// 1. sa global util
// input from sa local
input logic [INPUT_PORT_NUM-1:0] sa_local_vld_i,
// input from sa global
input logic [INPUT_PORT_NUM-1:0] sa_global_inport_read_vld_i,
// 2. outport credit util
input logic [VC_NUM_INPUT_N-1:0][VC_DEPTH_INPUT_N_COUNTER_W-1:0] vc_credit_counter_toN_i,
input logic [VC_NUM_INPUT_S-1:0][VC_DEPTH_INPUT_S_COUNTER_W-1:0] vc_credit_counter_toS_i,
input logic [VC_NUM_INPUT_E-1:0][VC_DEPTH_INPUT_E_COUNTER_W-1:0] vc_credit_counter_toE_i,
input logic [VC_NUM_INPUT_W-1:0][VC_DEPTH_INPUT_W_COUNTER_W-1:0] vc_credit_counter_toW_i,
`ifdef HAVE_LOCAL_PORT
input logic [LOCAL_PORT_NUM-1:0][VC_NUM_INPUT_L-1:0][VC_DEPTH_INPUT_L_COUNTER_W-1:0] vc_credit_counter_toL_i,
`endif
// router addr
input logic [NodeID_X_Width-1:0] node_id_x_ths_hop_i,
input logic [NodeID_Y_Width-1:0] node_id_y_ths_hop_i,
input logic clk,
input logic rstn
);
genvar i;
// global sa efficiency
logic [INPUT_PORT_NUM-1:0][64-1:0] sa_local_vld_counter_d, sa_local_vld_counter_q;
logic [INPUT_PORT_NUM-1:0] sa_local_vld_counter_ena;
logic [INPUT_PORT_NUM-1:0][64-1:0] sa_global_inport_read_vld_counter_d, sa_global_inport_read_vld_counter_q;
logic [INPUT_PORT_NUM-1:0] sa_global_inport_read_vld_counter_ena;
always_comb begin
sa_local_vld_counter_d = sa_local_vld_counter_q;
sa_local_vld_counter_ena = '0;
sa_global_inport_read_vld_counter_d = sa_global_inport_read_vld_counter_q;
sa_global_inport_read_vld_counter_ena = '0;
for(int i = 0; i < INPUT_PORT_NUM; i++) begin
if(sa_local_vld_i[i]) begin
sa_local_vld_counter_d[i] = sa_local_vld_counter_d[i] + 1;
sa_local_vld_counter_ena[i] = 1'b1;
end
if(sa_global_inport_read_vld_i[i]) begin
sa_global_inport_read_vld_counter_d [i] = sa_global_inport_read_vld_counter_d[i] + 1;
sa_global_inport_read_vld_counter_ena [i] = 1'b1;
end
end
end
generate
for(i = 0; i < INPUT_PORT_NUM; i++) begin
std_dffre
#(.WIDTH(64))
U_DAT_SA_LOCAL_VLD_COUNTER
(
.clk(clk),
.rstn(rstn),
.en(sa_local_vld_counter_ena[i]),
.d(sa_local_vld_counter_d[i]),
.q(sa_local_vld_counter_q[i])
);
std_dffre
#(.WIDTH(64))
U_DAT_SA_GLOBAL_INPORT_READ_VLD_COUNTER
(
.clk(clk),
.rstn(rstn),
.en(sa_global_inport_read_vld_counter_ena[i]),
.d(sa_global_inport_read_vld_counter_d[i]),
.q(sa_global_inport_read_vld_counter_q[i])
);
end
endgenerate
`ifdef V_ROUTER_PM_PRINT_EN
// display
// 1. sa global util
real sa_local_vld_counter [INPUT_PORT_NUM-1:0];
real sa_global_inport_read_vld_counter[INPUT_PORT_NUM-1:0];
real sa_local_vld_counter_all;
real sa_global_inport_read_vld_counter_all;
always_ff @(posedge clk) begin
if(~rstn) begin
end else begin
sa_local_vld_counter_all = 0;
sa_global_inport_read_vld_counter_all = 0;
for(int i = 0; i < INPUT_PORT_NUM; i++) begin
sa_local_vld_counter[i] = sa_local_vld_counter_q[i];
sa_global_inport_read_vld_counter[i] = sa_global_inport_read_vld_counter_q[i];
sa_local_vld_counter_all = sa_local_vld_counter_all + sa_local_vld_counter_q[i];
sa_global_inport_read_vld_counter_all = sa_global_inport_read_vld_counter_all + sa_global_inport_read_vld_counter_q[i];
$display("[%16d] info: (router %d,%d inport %2d) pm global sa efficiency (sa_global/sa_local): (%16d/%16d) = %f",
$time(), node_id_x_ths_hop_i, node_id_y_ths_hop_i, i,
sa_global_inport_read_vld_counter[i], sa_local_vld_counter[i],
sa_global_inport_read_vld_counter[i]/sa_local_vld_counter[i]);
end
$display("[%16d] info: pm (inportall) global sa efficiency (sa_global/sa_local): (%16d/%16d) = %f",
$time(),
sa_global_inport_read_vld_counter_all, sa_local_vld_counter_all,
sa_global_inport_read_vld_counter_all/sa_local_vld_counter_all);
end
end
// 2. outport credit util
always_ff @(posedge clk) begin
if(~rstn) begin
end else begin
for(int i = 0; i < VC_NUM_INPUT_N; i++) begin
$display("[%16d] info: (router %d,%d outport N vc id %d) pm credit count: %d",
$time(), node_id_x_ths_hop_i, node_id_y_ths_hop_i, i,
vc_credit_counter_toN_i[i]);
end
for(int i = 0; i < VC_NUM_INPUT_S; i++) begin
$display("[%16d] info: (router %d,%d outport S vc id %d) pm credit count: %d",
$time(), node_id_x_ths_hop_i, node_id_y_ths_hop_i, i,
vc_credit_counter_toS_i[i]);
end
for(int i = 0; i < VC_NUM_INPUT_E; i++) begin
$display("[%16d] info: (router %d,%d outport E vc id %d) pm credit count: %d",
$time(), node_id_x_ths_hop_i, node_id_y_ths_hop_i, i,
vc_credit_counter_toE_i[i]);
end
for(int i = 0; i < VC_NUM_INPUT_W; i++) begin
$display("[%16d] info: (router %d,%d outport W vc id %d) pm credit count: %d",
$time(), node_id_x_ths_hop_i, node_id_y_ths_hop_i, i,
vc_credit_counter_toW_i[i]);
end
`ifdef HAVE_LOCAL_PORT
for(int i = 0; i < LOCAL_PORT_NUM; i++) begin
for(int j = 0; j < VC_NUM_INPUT_L; j++) begin
$display("[%16d] info: (router %d,%d outport L%1d vc id %d) pm credit count: %d",
$time(), node_id_x_ths_hop_i, node_id_y_ths_hop_i, i, j,
vc_credit_counter_toL_i[i][j]);
end
end
`endif
end
end
`endif
endmodule

View File

@@ -0,0 +1,43 @@
// select req(s) with the highest priority from the req input vector
module priority_req_select
import rvh_noc_pkg::*;
#(
parameter INPUT_NUM = 4,
parameter INPUT_NUM_IDX_W = INPUT_NUM > 1 ? $clog2(INPUT_NUM) : 1,
parameter INPUT_PRIORITY_W = 4
)
(
input logic [INPUT_NUM-1:0] req_vld_i,
input logic [INPUT_NUM-1:0][INPUT_PRIORITY_W-1:0] req_priority_i,
output logic [INPUT_NUM-1:0] req_vld_o
);
genvar i,j;
// x >= y -> 1 else 0
// req_vld_i pri 3 9 2 8 & req_vld_o
// 1 3 1 1 1 0 0 0
// 0 9 0 0 0 0 0 0
// 1 2 0 1 1 0 0 0
// 1 8 1 1 1 1 1 1
logic [INPUT_NUM-1:0][INPUT_NUM-1:0] priority_compare_vector;
generate
for(i = 0; i < INPUT_NUM; i++) begin: gen_priority_compare_vector_i
for(j = 0; j < INPUT_NUM; j++) begin: gen_priority_compare_vector_j
if (i == j) begin: gen_diagonal
assign priority_compare_vector[i][j] = req_vld_i[i];
end else begin: gen_others
assign priority_compare_vector[i][j] = ~req_vld_i[j] | (req_priority_i[i] >= req_priority_i[j]);
end
end
end
endgenerate
generate
for(i = 0; i < INPUT_NUM; i++) begin: gen_req_vld_o
assign req_vld_o[i] = &(priority_compare_vector[i]);
end
endgenerate
endmodule

467
rtl/ruby/ut_lib.sv Executable file
View File

@@ -0,0 +1,467 @@
`define LFSR_HIGH_16BIT_ENABLE
module LFSR #(parameter NUM_BITS)
(
input i_Clk,
input i_Enable,
//Optional Seed Value
input i_Seed_DV,
input [NUM_BITS-1:0] i_Seed_Data,
output[NUM_BITS-1:0] o_LFSR_Data,
output o_LFSR_Done
);
reg [NUM_BITS:1] r_LFSR = 0;
reg r_XNOR;
always @(posedge i_Clk or negedge i_Enable)
begin
if(~i_Enable) begin
r_LFSR <= i_Seed_Data;
end else if (i_Seed_DV == 1'b1) begin
r_LFSR <= i_Seed_Data;
end else begin
r_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR};
end
end
// Linear Feedback Shift Register Taps refer to https://docs.xilinx.com/v/u/en-US/xapp052
// use same or becaure the default seed can be '0, and should not be '1
always @(*)
begin
case (NUM_BITS)
2: begin
r_XNOR = r_LFSR[2] ^ ~r_LFSR[1];
end
3: begin
r_XNOR = r_LFSR[3] ^ ~r_LFSR[2];
end
4: begin
r_XNOR = r_LFSR[4] ^ ~r_LFSR[3];
end
5: begin
r_XNOR = r_LFSR[5] ^ ~r_LFSR[3];
end
6: begin
r_XNOR = r_LFSR[6] ^ ~r_LFSR[5];
end
7: begin
r_XNOR = r_LFSR[7] ^ ~r_LFSR[6];
end
8: begin
r_XNOR = r_LFSR[8] ^ ~r_LFSR[6] ^ ~r_LFSR[5] ^ ~r_LFSR[4];
end
9: begin
r_XNOR = r_LFSR[9] ^ ~r_LFSR[5];
end
10: begin
r_XNOR = r_LFSR[10] ^ ~r_LFSR[7];
end
11: begin
r_XNOR = r_LFSR[11] ^ ~r_LFSR[9];
end
12: begin
r_XNOR = r_LFSR[12] ^ ~r_LFSR[6] ^ ~r_LFSR[4] ^ ~r_LFSR[1];
end
13: begin
r_XNOR = r_LFSR[13] ^ ~r_LFSR[4] ^ ~r_LFSR[3] ^ ~r_LFSR[1];
end
14: begin
r_XNOR = r_LFSR[14] ^ ~r_LFSR[5] ^ ~r_LFSR[3] ^ ~r_LFSR[1];
end
15: begin
r_XNOR = r_LFSR[15] ^ ~r_LFSR[14];
end
16: begin
r_XNOR = r_LFSR[16] ^ ~r_LFSR[15] ^ ~r_LFSR[13] ^ ~r_LFSR[4];
end
`ifdef LFSR_HIGH_16BIT_ENABLE
17: begin
r_XNOR = r_LFSR[17] ^ ~r_LFSR[14];
end
18: begin
r_XNOR = r_LFSR[18] ^ ~r_LFSR[11];
end
19: begin
r_XNOR = r_LFSR[19] ^ ~r_LFSR[6] ^ ~r_LFSR[2] ^ ~r_LFSR[1];
end
20: begin
r_XNOR = r_LFSR[20] ^ ~r_LFSR[17];
end
21: begin
r_XNOR = r_LFSR[21] ^ ~r_LFSR[19];
end
22: begin
r_XNOR = r_LFSR[22] ^ ~r_LFSR[21];
end
23: begin
r_XNOR = r_LFSR[23] ^ ~r_LFSR[18];
end
24: begin
r_XNOR = r_LFSR[24] ^ ~r_LFSR[23] ^ ~r_LFSR[22] ^ ~r_LFSR[17];
end
25: begin
r_XNOR = r_LFSR[25] ^ ~r_LFSR[22];
end
26: begin
r_XNOR = r_LFSR[26] ^ ~r_LFSR[6] ^ ~r_LFSR[2] ^ ~r_LFSR[1];
end
27: begin
r_XNOR = r_LFSR[27] ^ ~r_LFSR[5] ^ ~r_LFSR[2] ^ ~r_LFSR[1];
end
28: begin
r_XNOR = r_LFSR[28] ^ ~r_LFSR[25];
end
29: begin
r_XNOR = r_LFSR[29] ^ ~r_LFSR[27];
end
30: begin
r_XNOR = r_LFSR[30] ^ ~r_LFSR[6] ^ ~r_LFSR[4] ^ ~r_LFSR[1];
end
31: begin
r_XNOR = r_LFSR[31] ^ ~r_LFSR[28];
end
32: begin
r_XNOR = r_LFSR[32] ^ ~r_LFSR[22] ^ ~r_LFSR[2] ^ ~r_LFSR[1];
end
64: begin
r_XNOR = r_LFSR[64] ^ ~r_LFSR[63] ^ ~r_LFSR[61] ^ ~r_LFSR[60];
end
80: begin
r_XNOR = r_LFSR[80] ^ ~r_LFSR[79] ^ ~r_LFSR[43] ^ ~r_LFSR[42];
end
128: begin
r_XNOR = r_LFSR[128] ^ ~r_LFSR[126] ^ ~r_LFSR[101] ^ ~r_LFSR[99];
end
168: begin
r_XNOR = r_LFSR[168] ^ ~r_LFSR[166] ^ ~r_LFSR[153] ^ ~r_LFSR[151];
end
`endif
default: begin
r_XNOR = '0;
end
endcase
end
assign o_LFSR_Data = r_LFSR[NUM_BITS:1];
assign o_LFSR_Done = (r_LFSR[NUM_BITS:1] == i_Seed_Data) ? 1'b1 : 1'b0;
endmodule
module id_pool_2w1r
#( parameter depth=8,
parameter width=32,
parameter ptr_sz=$clog2(depth)
)
(
input logic clk,
input logic rst_n,
input logic [1:0] c_srdy,
output logic [1:0] c_drdy,
input logic [1:0][width-1:0] c_data,
output logic p_srdy,
input logic p_drdy,
output logic [width-1:0] p_data,
output logic [ptr_sz:0] usage
);
localparam depth_sub_1 = depth-1;
localparam depth_sub_2 = depth-2;
logic [ptr_sz-1:0] wr_addr_d;
logic [ptr_sz-1:0] rd_addr_d;
logic [ptr_sz-1:0] wr_addr_q;
logic [ptr_sz-1:0] rd_addr_q;
logic [depth-1:0][width-1:0] array_d;
logic [depth-1:0][width-1:0] array_q;
logic [ptr_sz:0] occupy_cnt_d;
logic [ptr_sz:0] occupy_cnt_q;
logic full;
logic empty;
logic wr_2_en;
logic wr_2_vld;
logic wr_en;
logic rd_en;
logic [ptr_sz-1:0] wr_addr_p1;
assign c_drdy = wr_2_vld ? 2'b11 : (occupy_cnt_q == depth_sub_1) ? ((c_srdy == 2'b10) ? 2'b10 : 2'b01) : '0;
assign p_srdy = ~empty;
assign p_data = array_q[rd_addr_q];
assign empty = (occupy_cnt_q == '0);
assign full = (occupy_cnt_q == depth[ptr_sz:0]);
assign rd_en = p_drdy & ~empty;
assign wr_en = (c_srdy[0] | c_srdy[1]) & ~full;
assign wr_2_vld = (occupy_cnt_q < depth_sub_1);
assign wr_2_en = (c_srdy == 2'b11) & wr_2_vld;
assign rd_addr_d = rd_en ? ((rd_addr_q == depth_sub_1) ? '0 : rd_addr_q+1) : rd_addr_q;
assign wr_addr_p1 = (wr_addr_q == depth_sub_1) ? '0 : wr_addr_q+1;
assign wr_addr_d = wr_2_en ? ((wr_addr_q == depth_sub_1) ? ptr_sz'('d1) : (wr_addr_q == depth_sub_2) ? '0 : wr_addr_q+2) : wr_en ? wr_addr_p1 : wr_addr_q;
always_comb begin
occupy_cnt_d = occupy_cnt_q;
case ({wr_2_en,wr_en,rd_en})
3'b110: begin
occupy_cnt_d = occupy_cnt_q+{{(ptr_sz-1){1'b0}},2'd2};
end
3'b111: begin
occupy_cnt_d = occupy_cnt_q+{{(ptr_sz){1'b0}},1'b1};
end
3'b010: begin
occupy_cnt_d = occupy_cnt_q+{{(ptr_sz){1'b0}},1'b1};
end
3'b001: begin
occupy_cnt_d = occupy_cnt_q-{{(ptr_sz){1'b0}},1'b1};
end
endcase
end
std_dffr #(ptr_sz) FF_WR_ADDR (.clk(clk) ,.rstn(rst_n),.d(wr_addr_d),.q(wr_addr_q));
std_dffr #(ptr_sz) FF_RD_ADDR (.clk(clk) ,.rstn(rst_n),.d(rd_addr_d),.q(rd_addr_q));
std_dffrve #(ptr_sz+1) FF_OCCUPY_CNT (.clk(clk),.rstn(rst_n),.rst_val(depth),.en(1'b1),.d(occupy_cnt_d),.q(occupy_cnt_q));
generate
for (genvar ii=0; ii<depth ;ii++) begin
assign array_d[ii] = ((wr_addr_q == ii[ptr_sz-1:0]) & wr_en) ? (c_srdy[0] ? c_data[0] : c_data[1]) :
((wr_addr_p1 == ii[ptr_sz-1:0]) & wr_2_en) ? c_data[1] :
array_q[ii];
std_dffrve #(width) FF_ARRAY (.clk(clk) ,.rstn(rst_n) ,.rst_val(ii) ,.en(1'b1) ,.d(array_d[ii]) ,.q(array_q[ii]));
end
endgenerate
assign usage = occupy_cnt_q;
endmodule
// module sd_id_pool
// #( parameter depth=8,
// parameter width=32,
// parameter ptr_sz=$clog2(depth)
// )
// (
// input clk,
// input rst,
// input c_srdy,
// output c_drdy,
// input[width-1:0] c_data,
// output p_srdy,
// input p_drdy,
// output[width-1:0] p_data,
// output[ptr_sz:0] usage
// );
// localparam depth_sub_1 = depth-1;
// logic wr_en;
// logic rd_en;
// logic [ptr_sz-1:0] wr_addr;
// logic [ptr_sz-1:0] rd_addr;
// logic [ptr_sz-1:0] nxt_wr_addr;
// logic [ptr_sz-1:0] nxt_rd_addr;
// logic [depth-1:0][width-1:0] array;
// logic [ptr_sz:0] occupy_cnt;
// logic [ptr_sz:0] nxt_occupy_cnt;
// logic full;
// logic empty;
// assign wr_en = c_srdy & ~full;
// assign rd_en = p_srdy & p_drdy;
// genvar ii;
// generate
// for(ii=0; ii<depth;ii=ii+1) begin: array_entry_ii
// always @(posedge clk) begin
// if (rst) begin
// array[ii] <= ii[width-1:0];
// end
// else begin
// if ((wr_addr==ii[ptr_sz-1:0]) & wr_en)
// array[ii] <= c_data;
// end
// end
// end
// endgenerate
// assign p_data = array[rd_addr];
// assign nxt_wr_addr = (wr_en) ? ((wr_addr==depth_sub_1[ptr_sz-1:0]) ? {ptr_sz{1'b0}} : wr_addr+1'b1) : wr_addr;
// always @(posedge clk) begin
// if (rst)
// wr_addr <= {ptr_sz{1'b0}};
// else
// wr_addr <= nxt_wr_addr;
// end
// assign nxt_rd_addr = (rd_en) ? ((rd_addr==depth_sub_1[ptr_sz-1:0]) ? {ptr_sz{1'b0}} : rd_addr+1'b1) : rd_addr;
// always @(posedge clk) begin
// if (rst)
// rd_addr <= {ptr_sz{1'b0}};
// else
// rd_addr <= nxt_rd_addr;
// end
// always @* begin
// case ({wr_en, rd_en})
// 2'b00: begin
// nxt_occupy_cnt = occupy_cnt;
// end
// 2'b01: begin
// nxt_occupy_cnt = occupy_cnt-1'b1;
// end
// 2'b10: begin
// nxt_occupy_cnt = occupy_cnt+1'b1;
// end
// 2'b11: begin
// nxt_occupy_cnt = occupy_cnt;
// end
// endcase
// end
// always @(posedge clk) begin
// if(rst) begin
// occupy_cnt <= depth[ptr_sz:0];
// end
// else begin
// occupy_cnt <= nxt_occupy_cnt;
// end
// end
// assign empty = (occupy_cnt == {(ptr_sz+1){1'b0}}) ? 1'b1 : 1'b0;
// assign full = (occupy_cnt == depth[ptr_sz:0]) ? 1'b1 : 1'b0;
// assign c_drdy = ~full;
// assign p_srdy = ~empty;
// assign usage = occupy_cnt;
// endmodule
// module rrv64_vld_rdy_rr_arb #(
// parameter BACKEND_DOMAIN = 0,
// parameter N_INPUT = 2
// )(
// input logic [N_INPUT-1:0] vld,
// input logic rdy,
// output logic [N_INPUT-1:0] grt,
// input logic rstn,clk
// );
// localparam N_INPUT_BITS = $clog2(N_INPUT);
// typedef enum logic {
// ST_PASS_THROUGH,
// ST_HOLD
// } vld_rdy_rr_arb_st_t;
// generate
// if(N_INPUT==1) begin
// assign grt = vld;
// end else begin
// vld_rdy_rr_arb_st_t rff_state, next_state;
// logic [N_INPUT_BITS-1:0] rrf_last_grt_id, grt_id;
// logic [N_INPUT-1:0] vld_with_priority;
// logic [N_INPUT-1:0] grt_with_priority, next_grt, rff_grt;
// logic do_save_grt;
// // vld_with_priority
// always_comb begin
// vld_with_priority = vld;
// if (rff_last_grt_id != N_INPUT_BITS'(N_INPUT-1)) begin
// for(int i = 0;i < N_INPUT; i++) begin
// if(i > rff_last_grt_id) begin
// vld_with_priority[i - rff_last_grt_id - 1'b1] = vld[i];
// end else begin
// vld_with_priority[N_INPUT - rff_last_grt_id - 1'b1 + i] = vld[i];
// end
// end
// end
// end
// //grt_with_priority
// always_comb begin
// grt_with_priority = {N_INPUT{1'b0}}:
// if (|vld_with_priority) begin
// for (int i = 0; i < N_INPUT; i++) begin
// if (vld_with_priority[i] == 1'b1) begin
// grt_with_priority[i] = 1'b1;
// break;
// end
// end
// end
// end
// // next_grt
// always_comb begin
// if(rff_last_grt_id == N_INPUT_BITS'(N_INPUT-1)) begin
// next_grt = grt_with_priority;
// end else begin
// for(int i = 0; i < N_INPUT;i++) begin
// if(i > rff_last_grt_id) begin
// next_grt[i] = grt_with_priority[i - rff_last_grt_id - 1'b1];
// end else begin
// next_grt[i] = grt_with_priority[N_INPUT - rff_last_grt_id - 1'b1 + i];
// end
// end
// end
// end
// // Grant Update
// always_ff @(posedge clk or negedge rstn) begin
// if (!rstn) begin
// rff_grt <= '0;
// end else begin
// if (do_save_grt) begin
// rff_grt <= grt;
// end
// end
// end
// always_ff @(posedge clk or negedge rstn ) begin
// if (!rstn) begin
// rff_last_grt_id <= N_INPUT_BITS'(N_INPUT-1);
// end else begin
// if ((|grt) & rdy) begin
// rff_last_grt_id <= grt_id;
// end
// end
// end
// always_ff @(posedge clk or negedge rstn) begin
// if(!rstn) begin
// rff_state <= ST_PASS_THROUGH;
// end else begin
// rff_state <= next_state;
// end
// end
// always_comb begin
// case (rff_state)
// ST_HOLD: begin
// do_save_grt = '0;
// if (rdy) begin
// next_state = ST_PASS_THROUGH;
// end else begin
// next_state = ST_HOLD;
// end
// end
// default: begin
// if((|grt) & ~rdy) begin
// do_save_grt = '1;
// next_state = ST_HOLD;
// end else begin
// do_save_grt = '0;
// next_state = ST_PASS_THROUGH;
// end
// end
// endcase
// end
// assign grt = (rff_state == ST_HOLD) ? rff_grt: next_grt;
// end
// endgenerate
//endmodule

101
rtl/sa_global.sv Normal file
View File

@@ -0,0 +1,101 @@
module sa_global
import rvh_noc_pkg::*;
#(
parameter INPUT_NUM = 4,
parameter INPUT_NUM_IDX_W = INPUT_NUM > 1 ? $clog2(INPUT_NUM) : 1
)
(
// input to allocate
input logic [INPUT_NUM-1:0] sa_local_vld_i,
input logic [INPUT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] sa_local_vc_id_i,
`ifdef USE_QOS_VALUE
input logic [INPUT_NUM-1:0][QoS_Value_Width-1:0] sa_local_qos_value_i,
`endif
// output to VC assignment
output logic sa_global_vld_o,
`ifdef COMMON_QOS_EXTRA_RT_VC
output logic [QoS_Value_Width-1:0] sa_global_qos_value_o,
`endif
output logic [INPUT_NUM-1:0] sa_global_inport_id_oh_o,
output logic [VC_ID_NUM_MAX_W-1:0] sa_global_inport_vc_id_o,
// input from vc assignment for rr arbiter update
input logic vc_assignment_vld_i,
input logic clk,
input logic rstn
);
logic [INPUT_NUM-1:0] sa_global_grt_oh;
logic [INPUT_NUM_IDX_W-1:0] sa_global_grt_idx;
logic [INPUT_NUM-1:0] sa_local_vld_join_arb; // for qos, if no qos, it is same as sa_local_vld_i
`ifdef USE_QOS_VALUE
priority_req_select
#(
.INPUT_NUM ( INPUT_NUM ),
.INPUT_PRIORITY_W ( QoS_Value_Width )
)
sa_local_priority_req_select_u (
.req_vld_i (sa_local_vld_i ),
.req_priority_i (sa_local_qos_value_i ),
.req_vld_o (sa_local_vld_join_arb )
);
`else
assign sa_local_vld_join_arb = sa_local_vld_i;
`endif
one_hot_rr_arb #(
.N_INPUT (INPUT_NUM),
.TIMEOUT_UPDATE_EN (1 ),
.TIMEOUT_UPDATE_CYCLE (10)
)
sa_global_rr_arb_u
(
.req_i (sa_local_vld_join_arb ),
.update_i (vc_assignment_vld_i ),
.grt_o (sa_global_grt_oh ),
.grt_idx_o (sa_global_grt_idx ),
.rstn (rstn ),
.clk (clk )
);
assign sa_global_vld_o = |sa_local_vld_join_arb;
assign sa_global_inport_id_oh_o = sa_global_grt_oh;
// assign sa_global_inport_vc_id_o = sa_local_vc_id_i[sa_global_grt_idx];
onehot_mux
#(
.SOURCE_COUNT(INPUT_NUM ),
.DATA_WIDTH (VC_ID_NUM_MAX_W )
)
onehot_mux_sa_global_inport_vc_id_o_u (
.sel_i (sa_global_grt_oh ),
.data_i (sa_local_vc_id_i ),
.data_o (sa_global_inport_vc_id_o)
);
`ifdef COMMON_QOS_EXTRA_RT_VC
onehot_mux
#(
.SOURCE_COUNT(INPUT_NUM ),
.DATA_WIDTH (QoS_Value_Width )
)
onehot_mux_sa_global_qos_value_o_u (
.sel_i (sa_global_grt_oh ),
.data_i (sa_local_qos_value_i ),
.data_o (sa_global_qos_value_o)
);
`endif
endmodule

142
rtl/sa_local.sv Normal file
View File

@@ -0,0 +1,142 @@
module sa_local
import rvh_noc_pkg::*;
#(
parameter INPUT_NUM = 4,
parameter INPUT_NUM_IDX_W = INPUT_NUM > 1 ? $clog2(INPUT_NUM) : 1
)
(
// input to allocate
input logic [INPUT_NUM-1:0] vc_ctrl_head_vld_i,
input flit_dec_t [INPUT_NUM-1:0] vc_ctrl_head_i,
// output to global allocate
output logic [OUTPUT_PORT_NUMBER-1:0] sa_local_vld_to_sa_global_o,
output logic sa_local_vld_o,
output logic [INPUT_NUM_IDX_W-1:0] sa_local_vc_id_o,
output logic [INPUT_NUM-1:0] sa_local_vc_id_oh_o,
`ifdef USE_QOS_VALUE
output logic [QoS_Value_Width-1:0] sa_local_qos_value_o,
`endif
`ifdef VC_DATA_USE_DUAL_PORT_RAM
output dpram_used_idx_t sa_local_dpram_idx_o,
`endif
// input pop flit ctrl fifo (comes from SA stage), use to update rr arbiter pointer
input logic inport_read_enable_sa_stage_i,
input logic clk,
input logic rstn
);
genvar i,j;
logic [INPUT_NUM-1:0] sa_local_grt_oh;
logic [INPUT_NUM_IDX_W-1:0] sa_local_grt_idx;
logic [INPUT_NUM-1:0] vc_ctrl_head_vld_join_arb; // for qos, if no qos, it is same as vc_ctrl_head_vld_i
io_port_t [INPUT_NUM-1:0] vc_ctrl_head_i_look_ahead_routing;
logic [INPUT_NUM-1:0][OUTPUT_PORT_NUMBER-1:0] vc_ctrl_head_i_look_ahead_routing_match;
`ifdef USE_QOS_VALUE
logic [QoS_Value_Width-1:0] vc_ctrl_head_i_qos_value_sel;
`endif
flit_dec_t vc_ctrl_head_sel;
`ifdef USE_QOS_VALUE
logic [INPUT_NUM-1:0][QoS_Value_Width-1:0] vc_ctrl_head_qos_value;
generate
for(i = 0; i < INPUT_NUM; i++) begin: gen_vc_ctrl_head_qos_value
assign vc_ctrl_head_qos_value [i] = vc_ctrl_head_i[i].qos_value;
end
endgenerate
priority_req_select
#(
.INPUT_NUM ( INPUT_NUM ),
.INPUT_PRIORITY_W ( QoS_Value_Width )
)
sa_local_priority_req_select_u (
.req_vld_i (vc_ctrl_head_vld_i ),
.req_priority_i (vc_ctrl_head_qos_value ),
.req_vld_o (vc_ctrl_head_vld_join_arb )
);
`else
assign vc_ctrl_head_vld_join_arb = vc_ctrl_head_vld_i;
`endif
one_hot_rr_arb #(
.N_INPUT (INPUT_NUM),
.TIMEOUT_UPDATE_EN (1 ),
.TIMEOUT_UPDATE_CYCLE (10)
)
sa_local_rr_arb_u
(
.req_i (vc_ctrl_head_vld_join_arb ),
.update_i (inport_read_enable_sa_stage_i), // use global arbiter result to update: if win the global arbiter update local rr arbiter, or may be no fair
.grt_o (sa_local_grt_oh ),
.grt_idx_o (sa_local_grt_idx ),
.rstn (rstn ),
.clk (clk )
);
assign sa_local_vc_id_o = sa_local_grt_idx;
assign sa_local_vc_id_oh_o = sa_local_grt_oh;
`ifdef USE_QOS_VALUE
assign sa_local_qos_value_o = vc_ctrl_head_sel.qos_value;
`endif
`ifdef VC_DATA_USE_DUAL_PORT_RAM
assign sa_local_dpram_idx_o.dpram_idx = vc_ctrl_head_sel.dpram_used_idx.dpram_idx;
assign sa_local_dpram_idx_o.per_vc_idx = vc_ctrl_head_sel.dpram_used_idx.per_vc_idx;
`endif
assign sa_local_vld_o = |vc_ctrl_head_vld_join_arb;
generate
for(i = 0; i < OUTPUT_PORT_NUMBER; i++) begin
assign sa_local_vld_to_sa_global_o[i] = vc_ctrl_head_vld_join_arb[sa_local_grt_idx] &
vc_ctrl_head_i_look_ahead_routing_match[sa_local_grt_idx][i];
end
endgenerate
generate
for(i = 0; i < INPUT_NUM; i++) begin
assign vc_ctrl_head_i_look_ahead_routing[i] = vc_ctrl_head_i[i].look_ahead_routing;
end
endgenerate
generate
for(i = 0; i < INPUT_NUM; i++) begin: gen_vc_ctrl_head_i_look_ahead_routing_match_i
for(j = 0; j < OUTPUT_PORT_NUMBER; j++) begin: gen_vc_ctrl_head_i_look_ahead_routing_match_j
assign vc_ctrl_head_i_look_ahead_routing_match[i][j] = vc_ctrl_head_i_look_ahead_routing[i] == j[$bits(io_port_t)-1:0];
end
end
endgenerate
onehot_mux
#(
.SOURCE_COUNT(INPUT_NUM ),
.DATA_WIDTH ($bits(flit_dec_t))
)
onehot_mux_qos_value_sel_u (
.sel_i (sa_local_grt_oh ),
.data_i (vc_ctrl_head_i ),
.data_o (vc_ctrl_head_sel)
);
endmodule

279
rtl/switch.sv Normal file
View File

@@ -0,0 +1,279 @@
module switch
import rvh_noc_pkg::*;
#(
parameter INPUT_PORT_NUM = 5,
parameter OUTPUT_PORT_NUM = 5,
parameter LOCAL_PORT_NUM = INPUT_PORT_NUM-4,
parameter type flit_payload_t = logic[256-1:0],
parameter VC_NUM_INPUT_N = 2,
parameter VC_NUM_INPUT_S = 2,
parameter VC_NUM_INPUT_E = 4,
parameter VC_NUM_INPUT_W = 4,
parameter VC_NUM_INPUT_L = 4,
parameter VC_NUM_INPUT_N_IDX_W = VC_NUM_INPUT_N > 1 ? $clog2(VC_NUM_INPUT_N) : 1,
parameter VC_NUM_INPUT_S_IDX_W = VC_NUM_INPUT_S > 1 ? $clog2(VC_NUM_INPUT_S) : 1,
parameter VC_NUM_INPUT_E_IDX_W = VC_NUM_INPUT_E > 1 ? $clog2(VC_NUM_INPUT_E) : 1,
parameter VC_NUM_INPUT_W_IDX_W = VC_NUM_INPUT_W > 1 ? $clog2(VC_NUM_INPUT_W) : 1,
parameter VC_NUM_INPUT_L_IDX_W = VC_NUM_INPUT_L > 1 ? $clog2(VC_NUM_INPUT_L) : 1
)
(
// input flit data from input port buffer
input flit_payload_t [VC_NUM_INPUT_N-1:0] vc_data_head_fromN_i,
input flit_payload_t [VC_NUM_INPUT_S-1:0] vc_data_head_fromS_i,
input flit_payload_t [VC_NUM_INPUT_E-1:0] vc_data_head_fromE_i,
input flit_payload_t [VC_NUM_INPUT_W-1:0] vc_data_head_fromW_i,
`ifdef HAVE_LOCAL_PORT
input flit_payload_t [LOCAL_PORT_NUM-1:0][VC_NUM_INPUT_L-1:0] vc_data_head_fromL_i,
`endif
// input switch ctrl from SA to ST stage reg
input logic [INPUT_PORT_NUM-1:0] inport_read_enable_st_stage_i,
// input io_port_t [INPUT_PORT_NUM-1:0] inport_read_outport_id_st_stage_i,
input logic [INPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] inport_read_vc_id_st_stage_i,
// input io_port_t [INPUT_PORT_NUM-1:0] inport_look_ahead_routing_st_stage_i,
input logic [OUTPUT_PORT_NUM-1:0] outport_vld_st_stage_i,
input io_port_t [OUTPUT_PORT_NUM-1:0] outport_select_inport_id_st_stage_i,
input logic [OUTPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] outport_vc_id_st_stage_i,
input io_port_t [OUTPUT_PORT_NUM-1:0] outport_look_ahead_routing_st_stage_i,
// output flit data and look ahead routing to outport
output logic [OUTPUT_PORT_NUM-1:0] tx_flit_pend_o,
output logic [OUTPUT_PORT_NUM-1:0] tx_flit_v_o,
output flit_payload_t [OUTPUT_PORT_NUM-1:0] tx_flit_o,
output logic [OUTPUT_PORT_NUM-1:0][VC_ID_NUM_MAX_W-1:0] tx_flit_vc_id_o,
output io_port_t [OUTPUT_PORT_NUM-1:0] tx_flit_look_ahead_routing_o
);
genvar i;
// link flit clk gating
assign tx_flit_pend_o = '1; // TODO: by now receiver assuming always expecting a new flit
// select the output flit from per inport
flit_payload_t [INPUT_PORT_NUM-1:0] vc_head_data;
`ifdef VC_DATA_USE_DUAL_PORT_RAM // for dpram, only one flit would be read from per input_port, and always assign it in slot 0
assign vc_head_data[0] = vc_data_head_fromN_i[0]; // from N
assign vc_head_data[1] = vc_data_head_fromS_i[0]; // from S
assign vc_head_data[2] = vc_data_head_fromE_i[0]; // from E
assign vc_head_data[3] = vc_data_head_fromW_i[0]; // from W
generate
if(LOCAL_PORT_NUM > 0) begin: gen_have_vc_data_head_fromL_i
for(i = 0; i < LOCAL_PORT_NUM; i++) begin: gen_vc_data_head_fromL_i
assign vc_head_data[4+i] = vc_data_head_fromL_i[i][0]; // from L
end
end
endgenerate
`else
assign vc_head_data[0] = vc_data_head_fromN_i[inport_read_vc_id_st_stage_i[0][VC_NUM_INPUT_N_IDX_W-1:0]]; // from N
assign vc_head_data[1] = vc_data_head_fromS_i[inport_read_vc_id_st_stage_i[1][VC_NUM_INPUT_S_IDX_W-1:0]]; // from S
assign vc_head_data[2] = vc_data_head_fromE_i[inport_read_vc_id_st_stage_i[2][VC_NUM_INPUT_E_IDX_W-1:0]]; // from E
assign vc_head_data[3] = vc_data_head_fromW_i[inport_read_vc_id_st_stage_i[3][VC_NUM_INPUT_W_IDX_W-1:0]]; // from W
generate
if(LOCAL_PORT_NUM > 0) begin: gen_have_vc_data_head_fromL_i
for(i = 0; i < LOCAL_PORT_NUM; i++) begin: gen_vc_data_head_fromL_i
assign vc_head_data[4+i] = vc_data_head_fromL_i[i][inport_read_vc_id_st_stage_i[4+i][VC_NUM_INPUT_L_IDX_W-1:0]]; // from L
end
end
endgenerate
`endif
// map per valid inport head flit to outport
// map vld
assign tx_flit_v_o = outport_vld_st_stage_i;
// map receiver vc id
assign tx_flit_vc_id_o = outport_vc_id_st_stage_i;
// map look ahead routing
assign tx_flit_look_ahead_routing_o = outport_look_ahead_routing_st_stage_i;
// map data
// to N
always_comb begin
unique case(outport_select_inport_id_st_stage_i[0])
S: begin
tx_flit_o[0] = vc_head_data[1];
end
E: begin
tx_flit_o[0] = vc_head_data[2];
end
W: begin
tx_flit_o[0] = vc_head_data[3];
end
L0: begin
tx_flit_o[0] = vc_head_data[4];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
tx_flit_o[0] = vc_head_data[5];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
tx_flit_o[0] = vc_head_data[6];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
tx_flit_o[0] = vc_head_data[7];
end
`endif
default: begin
tx_flit_o[0] = vc_head_data[1];
end
endcase
end
// to S
always_comb begin
unique case(outport_select_inport_id_st_stage_i[1])
N: begin
tx_flit_o[1] = vc_head_data[0];
end
E: begin
tx_flit_o[1] = vc_head_data[2];
end
W: begin
tx_flit_o[1] = vc_head_data[3];
end
L0: begin
tx_flit_o[1] = vc_head_data[4];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
tx_flit_o[1] = vc_head_data[5];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
tx_flit_o[1] = vc_head_data[6];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
tx_flit_o[1] = vc_head_data[7];
end
`endif
default: begin
tx_flit_o[1] = vc_head_data[0];
end
endcase
end
// to E
always_comb begin
unique case(outport_select_inport_id_st_stage_i[2])
W: begin
tx_flit_o[2] = vc_head_data[3];
end
L0: begin
tx_flit_o[2] = vc_head_data[4];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
tx_flit_o[2] = vc_head_data[5];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
tx_flit_o[2] = vc_head_data[6];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
tx_flit_o[2] = vc_head_data[7];
end
`endif
default: begin
tx_flit_o[2] = vc_head_data[3];
end
endcase
end
// to W
always_comb begin
unique case(outport_select_inport_id_st_stage_i[3])
E: begin
tx_flit_o[3] = vc_head_data[2];
end
L0: begin
tx_flit_o[3] = vc_head_data[4];
end
`ifdef LOCAL_PORT_NUM_2
L1: begin
tx_flit_o[3] = vc_head_data[5];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
tx_flit_o[3] = vc_head_data[6];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
tx_flit_o[3] = vc_head_data[7];
end
`endif
default: begin
tx_flit_o[3] = vc_head_data[2];
end
endcase
end
// to L
generate
if(LOCAL_PORT_NUM > 0) begin: gen_have_multi_local_port_in_switch
for(i = 0; i < LOCAL_PORT_NUM; i++) begin: gen_multi_local_port_in_switch
always_comb begin
unique case(outport_select_inport_id_st_stage_i[4+i])
N: begin
tx_flit_o[4+i] = vc_head_data[0];
end
S: begin
tx_flit_o[4+i] = vc_head_data[1];
end
E: begin
tx_flit_o[4+i] = vc_head_data[2];
end
W: begin
tx_flit_o[4+i] = vc_head_data[3];
end
`ifdef HAVE_LOCAL_PORT
L0: begin
tx_flit_o[4+i] = vc_head_data[4];
end
`endif
`ifdef LOCAL_PORT_NUM_2
L1: begin
tx_flit_o[4+i] = vc_head_data[5];
end
`endif
`ifdef LOCAL_PORT_NUM_3
L2: begin
tx_flit_o[4+i] = vc_head_data[6];
end
`endif
`ifdef LOCAL_PORT_NUM_4
L3: begin
tx_flit_o[4+i] = vc_head_data[7];
end
`endif
default: begin
tx_flit_o[4+i] = vc_head_data[0];
end
endcase
end
end
end
endgenerate
endmodule

143
rtl/util/age_order_selector.sv Executable file
View File

@@ -0,0 +1,143 @@
`ifndef __AGE_ORDER_SELECTOR_SV__
`define __AGE_ORDER_SELECTOR_SV__
/*
* Age Matrix
* | Dependency bit |
* |E| | 0 | 1 | 2 | 3 |
* |N| 0 | 1 | 1 | 1 | 1 |
* |T| 1 | 0 | 1 | 1 | 1 |
* |R| 2 | 0 | 0 | 1 | 1 |
* |Y| 3 | 0 | 0 | 0 | 1 |
*
* age_matrix_r[i][i] : valid signal for entry(i)
* age_matrix_r[i][j] : if entry(j) deponds on entry(i)
*
* */
module age_order_selector #(
parameter int unsigned ENTRY_COUNT = 4,
parameter int unsigned ENQ_WIDTH = 1,
parameter int unsigned DEQ_WIDTH = 1,
parameter int unsigned SEL_WIDTH = 1,
localparam int unsigned ENTRY_TAG = $clog2(ENTRY_COUNT)
) (
// Enqueue
input logic [ENQ_WIDTH-1:0] enq_vld_i,
input logic [ENQ_WIDTH-1:0][ENTRY_TAG-1:0] enq_tag_i,
// Dequeue
input logic [DEQ_WIDTH-1:0] deq_vld_i,
input logic [DEQ_WIDTH-1:0][ENTRY_TAG-1:0] deq_tag_i,
// Status
output logic [ENTRY_COUNT-1:0] vld_mask_o,
// Select Oldest
input logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_mask_i,
output logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask_o,
// Flush
input logic flush_i,
input clk,
input rst
);
logic [ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] age_matrix_r, age_matrix_n;
logic [ENTRY_COUNT-1:0] vld_mask;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] sel_age_matrix;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask;
logic clk_en;
assign clk_en = (|enq_vld_i) | (|deq_vld_i) | flush_i;
always_comb begin : get_vld_mask
for (int row = 0; row < ENTRY_COUNT; row++) begin
vld_mask[row] = age_matrix_r[row][row];
end
end
// Sel Oldest Logic
always_comb begin : gen_sel_matrix
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
if (row == col) begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col];
end else begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col] ? age_matrix_r[row][col] :
1'b1;
end
end
end
end
end
always_comb begin : gen_sel_oldest_mask
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
sel_oldest_mask[i][row] = &sel_age_matrix[i][row];
end
end
end
// Update Logic
always_comb begin : update_logic
age_matrix_n = age_matrix_r;
for (int i = 0; i < ENQ_WIDTH; i++) begin
if (enq_vld_i[i]) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[enq_tag_i[i]][col] = ~age_matrix_r[col][col]; // Set Dependency
for(int j = 0; j < i; j++) begin
if(enq_vld_i[j]) begin
age_matrix_n[enq_tag_i[i]][enq_tag_i[j]] = 1'b0;
end
end
end
end
end
for (int i = 0; i < DEQ_WIDTH; i++) begin
if (deq_vld_i[i]) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
age_matrix_n[row][deq_tag_i[i]] = deq_tag_i[i] !=
row[ENTRY_TAG-1:0]; // Clear Dependency
end
end
end
if (flush_i) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[row][col] = 1'b0;
end
end
end
end
always_ff @(posedge clk) begin : age_matrix_dff
if (rst) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_r[row][col] <= 1'b0;
end
end
end else begin
if (clk_en) begin
age_matrix_r <= age_matrix_n;
end
end
end
// Output
assign vld_mask_o = vld_mask;
assign sel_oldest_mask_o = sel_oldest_mask;
endmodule : age_order_selector
`endif

View File

@@ -0,0 +1,203 @@
`ifndef __AGE_ORDER_SELECTOR_WITH_HEAD_SV__
`define __AGE_ORDER_SELECTOR_WITH_HEAD_SV__
/*
* Age Matrix
* | Dependency bit |
* |E| | 0 | 1 | 2 | 3 |
* |N| 0 | 1 | 1 | 1 | 1 |
* |T| 1 | 0 | 1 | 1 | 1 |
* |R| 2 | 0 | 0 | 1 | 1 |
* |Y| 3 | 0 | 0 | 0 | 1 |
*
* age_matrix_r[i][i] : valid signal for entry(i)
* age_matrix_r[i][j] : if entry(j) deponds on entry(i)
*
* */
module age_order_selector_with_head #(
parameter int unsigned ENTRY_COUNT = 4,
parameter int unsigned ENQ_WIDTH = 1,
parameter int unsigned DEQ_WIDTH = 1,
parameter int unsigned SEL_WIDTH = 1,
parameter int unsigned HEAD_PTR_COUNT = 1,
localparam int unsigned ENTRY_TAG = $clog2(ENTRY_COUNT)
) (
// Enqueue
input logic [ENQ_WIDTH-1:0] enq_vld_i,
input logic [ENQ_WIDTH-1:0][ENTRY_TAG-1:0] enq_tag_i,
// Dequeue
input logic [DEQ_WIDTH-1:0] deq_vld_i,
input logic [DEQ_WIDTH-1:0][ENTRY_TAG-1:0] deq_tag_i,
// Status
output logic [ENTRY_COUNT-1:0] vld_mask_o,
output logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0] oldest_mask_o,
// Select Oldest
input logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_mask_i,
output logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask_o,
// Flush
input logic flush_i,
input clk,
input rst
);
logic [ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] age_matrix_r, age_matrix_n;
logic [ENTRY_COUNT-1:0] vld_mask;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] sel_age_matrix;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask;
logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0] oldest_mask_r, oldest_mask_n;
logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0] masked_vld_mask;
logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] head_masked_age_matrix;
logic clk_en;
assign clk_en = (|enq_vld_i) | (|deq_vld_i) | flush_i;
always_comb begin : get_vld_mask
for (int row = 0; row < ENTRY_COUNT; row++) begin
vld_mask[row] = age_matrix_r[row][row];
end
end
// Sel Oldest Logic
always_comb begin : gen_sel_matrix
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
if (row == col) begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col];
end else begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col] ? age_matrix_r[row][col] :
1'b1;
end
end
end
end
end
always_comb begin : gen_sel_oldest_mask
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
sel_oldest_mask[i][row] = &sel_age_matrix[i][row];
end
end
end
// Update Logic
always_comb begin : update_logic
age_matrix_n = age_matrix_r;
for(int i = 0; i < ENQ_WIDTH; i++) begin
if (enq_vld_i[i]) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[enq_tag_i[i]][col] = ~age_matrix_r[col][col]; // Set Dependency
for(int j = 0; j < i; j++) begin
if(enq_vld_i[j]) begin
age_matrix_n[enq_tag_i[i]][enq_tag_i[j]] = 1'b0;
end
end
end
end
end
for(int i = 0 ; i < DEQ_WIDTH; i++) begin
if (deq_vld_i[i]) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
age_matrix_n[row][deq_tag_i[i]] = deq_tag_i[i] != row[ENTRY_TAG-1:0]; // Clear Dependency
end
end
end
if (flush_i) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[row][col] = 1'b0;
end
end
end
end
always_ff @(posedge clk) begin : age_matrix_dff
if (rst) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_r[row][col] <= 1'b0;
end
end
end else begin
if (clk_en) begin
age_matrix_r <= age_matrix_n;
end
end
end
// n-head Logic
always_comb begin : gen_masked_vld_mask
for (int i = 0; i < HEAD_PTR_COUNT; i++) begin
if (i == 0) begin
masked_vld_mask[i] = vld_mask;
end else begin
masked_vld_mask[i] = masked_vld_mask[i-1] & ~oldest_mask_n[i-1];
end
end
end
always_comb begin : gen_head_masked_matrix
for (int i = 0; i < HEAD_PTR_COUNT; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
if (i == 0) begin
head_masked_age_matrix[i][row][col] = age_matrix_n[row][col];
end else begin
if (col == row) begin
head_masked_age_matrix[i][row][col] = masked_vld_mask[i][col];
end else begin
head_masked_age_matrix[i][row][col] = masked_vld_mask[i][col] ?
head_masked_age_matrix[i-1][row][col] : 1'b1;
end
end
end
end
end
end
always_comb begin : gen_n_head_mask
for (int i = 0; i < HEAD_PTR_COUNT; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
oldest_mask_n[i][row] = &head_masked_age_matrix[i][row];
end
if (flush_i) begin
oldest_mask_n = {HEAD_PTR_COUNT * ENTRY_COUNT{1'b0}};
end
end
end
always_ff @(posedge clk) begin : oldest_mask_dff
if (rst) begin
oldest_mask_r <= {HEAD_PTR_COUNT * ENTRY_COUNT{1'b0}};
end else begin
if (clk_en) begin
oldest_mask_r <= oldest_mask_n;
end
end
end
// Output
assign oldest_mask_o = oldest_mask_r;
assign vld_mask_o = vld_mask;
assign sel_oldest_mask_o = sel_oldest_mask;
endmodule : age_order_selector_with_head
`endif

3
rtl/util/commoncell/.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "tools/pico"]
path = tools/pico
url = git@gitlab.com:series-han/development/pico.git

View File

@@ -0,0 +1,5 @@
Name: CommonCell
Dependency:
- src/StdDFF/StdDFF.yaml
- src/Basic/Basic.yaml
- src/Queue/Queue.yaml

View File

@@ -0,0 +1,92 @@
# CommonCell
Common logic cell for RTL encoding.
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://gitlab.com/series-han/hardware/commoncell.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.com/series-han/hardware/commoncell/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

0
rtl/util/commoncell/doc/.gitignore vendored Normal file
View File

11
rtl/util/commoncell/env/sourceme vendored Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
CURDIR=$(cd $(dirname ${BASH_SOURCE[0]}); pwd )
PROJ_ROOT=$CURDIR/../
PICO_PATH=$PROJ_ROOT/tools/pico/
export PROJ_ROOT
export PATH=$PICO_PATH:$PATH

View File

@@ -0,0 +1,67 @@
Name: Basic
Dependency:
- ../StdDFF/StdDFF.yaml
Module:
- name: CountOne
description: CountOne
language: SystemVerilog
rtl:
- hw/CountOne.v
sim:
- dv/CountOne_tb.v
- name: MuxOH
description: One-hot Mux
language: SystemVerilog
rtl:
- hw/MuxOH.v
sim:
- dv/MuxOH_tb.v
- name: OH2UInt
description: One-hot to UInt
language: SystemVerilog
rtl:
- hw/OH2UInt.v
dependency:
- CountOne
- name: PriorityMux
description: Priority Mux
language: SystemVerilog
rtl:
- hw/PriorityMux.v
dependency:
- MuxOH
- name: SyncFIFO
description: Sync FIFO
language: SystemVerilog
rtl:
- hw/SyncFIFO.v
sim:
- dv/SyncFIFO_tb.v
dependency:
- StdDFF
- name: StreamFIFO
description: StreamFIFO
language: SystemVerilog
rtl:
- hw/StreamFIFO.v
sim:
- dv/StreamFIFO_tb.v
dependency:
- SyncFIFO
- name: PLRU
description: PLRU
language: SystemVerilog
rtl:
- hw/PLRUTree.v
- hw/PLRU.v
sim:
- dv/PLRU_tb.v
dependency:
- StdDFF

View File

@@ -0,0 +1,59 @@
module CountOne_tb;
// Parameters
localparam int unsigned InputWidth = 8;
localparam int unsigned CountWidth = $clog2(InputWidth + 1);
// Ports
reg [InputWidth-1:0] bits_i;
wire [CountWidth-1:0] cnt_o;
CountOne #(
.InputWidth(InputWidth)
) u_CountOne (
.bits_i(bits_i),
.cnt_o (cnt_o)
);
function automatic [CountWidth-1:0] GlodenModel;
input bit [InputWidth-1:0] in;
bit [CountWidth-1:0] sum;
begin
sum = 0;
for (int i = 0; i < InputWidth; i++) begin
sum = sum + in[i];
end
GlodenModel = sum;
end
endfunction
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("CountOne_tb.fsdb");
$fsdbDumpvars(0, CountOne_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
initial begin : RANDOM_TEST
begin
repeat (10000) begin : GEN_CASE
bits_i = $urandom_range(0, InputWidth - 1);
#100;
NOT_EQUAL :
assert (cnt_o == GlodenModel(bits_i))
else begin
$error("Input[%b], Output[%d], Gloden[%d]\n", bits_i, cnt_o, GlodenModel(bits_i));
break;
end
end
#100;
$fatal("PASS\n");
$finish;
end
end
endmodule

View File

@@ -0,0 +1,66 @@
module MuxOH_tb;
// Parameters
localparam int unsigned InputWidth = 8;
localparam int unsigned DataWidth = 8;
// Ports
reg [InputWidth-1:0] sel_i;
reg [InputWidth-1:0][DataWidth-1:0] data_i;
wire [DataWidth-1:0] data_o;
MuxOH #(
.InputWidth(InputWidth),
.DataWidth (DataWidth)
) u_MuxOH (
.sel_i (sel_i),
.data_i(data_i),
.data_o(data_o)
);
function automatic [DataWidth-1:0] GlodenModel;
input bit [InputWidth-1:0] sel;
input bit [InputWidth-1:0][DataWidth-1:0] data;
bit [DataWidth-1:0] result;
begin
for (int i = 0; i < InputWidth; i++) begin
if (sel[i]) begin
result = data[i];
end
end
GlodenModel = result;
end
endfunction
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("MuxOH_tb.fsdb");
$fsdbDumpvars(0, MuxOH_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
initial begin
repeat (10000) begin : GEN_CASE
sel_i = 1 << $urandom_range(0, InputWidth - 1);
for (int i = 0; i < InputWidth; i++) begin
data_i[i] = $urandom();
end
#100;
NOT_EQUAL :
assert (data_o == GlodenModel(sel_i, data_i))
else begin
$fatal("Input[%b], Output[%d], Gloden[%d]\n", sel_i, data_o, GlodenModel(sel_i, data_i));
break;
end
end
#100;
$info("PASS\n");
$finish;
end
endmodule

View File

@@ -0,0 +1,49 @@
module PLRU_tb;
// Parameters
localparam ENTRY_COUNT = 4;
// Ports
reg [ENTRY_COUNT-1:0] access_mask_i;
wire [ENTRY_COUNT-1:0] least_used_mask_o;
reg clk = 0;
reg rstn = 0;
PLRU #(
.ENTRY_COUNT(ENTRY_COUNT)
) PLRU_dut (
.access_mask_i(access_mask_i),
.least_used_mask_o(least_used_mask_o),
.clk(clk),
.rstn(rstn)
);
initial begin
begin
#10 rstn = 1'b1;
repeat (10000) begin
@(negedge clk);
if (|access_mask_i) begin
$info("\n Access Entry[%d], PLRU Change to [%d]\n", $countones(access_mask_i-1), $countones(
least_used_mask_o - 1));
end
access_mask_i = 1 << $urandom_range(0, ENTRY_COUNT - 1);
@(posedge clk);
end
$finish;
end
end
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("PLRU_tb.fsdb");
$fsdbDumpvars(0, PLRU_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,83 @@
module StreamFIFO_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned WordWidth = 64;
// Ports
reg enq_vld_i = 0;
reg [WordWidth-1:0] enq_payload_i;
wire enq_rdy_o;
wire deq_vld_o;
wire [WordWidth-1:0] deq_payload_o;
reg deq_rdy_i = 0;
reg flush_i = 0;
reg clk = 0;
reg rstn = 0;
bit [WordWidth-1:0] golden_fifo[$];
bit [WordWidth-1:0] random_payload;
bit [WordWidth-1:0] golden_fifo_front;
int iter = 1000000;
initial begin
begin
#10 rstn = 1'b1;
repeat (iter) begin : random_test
@(negedge clk);
enq_vld_i = 1'b0;
deq_rdy_i = 1'b0;
if ($urandom_range(0, 1) && deq_vld_o) begin : test_deq
deq_rdy_i = 1'b1;
golden_fifo_front = golden_fifo.pop_front();
CHECK_EQUALATION :
assert (deq_payload_o == golden_fifo_front)
else begin
$fatal("\n Error: Fail when check equalation, ours[%x] -- gloden[%x]", deq_payload_o,
golden_fifo_front);
end
;
end
if ($urandom_range(0, 1) && enq_rdy_o) begin : test_push
random_payload = $urandom();
enq_vld_i = 1'b1;
enq_payload_i = random_payload;
golden_fifo.push_back(random_payload);
end
end
$info("\n PASS after %d iter \n", iter);
$finish;
end
end
StreamFIFO #(
.Depth(Depth),
.WordWidth(WordWidth)
) StreamFIFO_dut (
.enq_vld_i(enq_vld_i),
.enq_payload_i(enq_payload_i),
.enq_rdy_o(enq_rdy_o),
.deq_vld_o(deq_vld_o),
.deq_payload_o(deq_payload_o),
.deq_rdy_i(deq_rdy_i),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("StreamFIFO_tb.fsdb");
$fsdbDumpvars(0, StreamFIFO_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,83 @@
module SyncFIFO_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned WordWidth = 32;
// Ports
reg push_i = 0;
reg [WordWidth-1:0] push_payload_i;
reg pop_i = 0;
wire [WordWidth-1:0] pop_payload_o;
wire full_o;
wire empty_o;
reg flush_i = 0;
reg clk = 0;
reg rstn = 0;
bit [WordWidth-1:0] golden_fifo[$];
bit [WordWidth-1:0] random_payload;
bit [WordWidth-1:0] golden_fifo_front;
int iter = 1000000;
initial begin
begin
#10 rstn = 1'b1;
repeat (iter) begin : random_test
@(negedge clk);
pop_i = 1'b0;
push_i = 1'b0;
if ($urandom_range(0, 1) && ~empty_o) begin : test_pop
pop_i = 1'b1;
golden_fifo_front = golden_fifo.pop_front();
CHECK_EQUALATION :
assert (pop_payload_o == golden_fifo_front)
else begin
$fatal("\n Error: Fail when check equalation, ours[%x] -- gloden[%x]", pop_payload_o,
golden_fifo_front);
end
;
end
if ($urandom_range(0, 1) && ~full_o) begin : test_push
random_payload = $urandom();
push_i = 1'b1;
push_payload_i = random_payload;
golden_fifo.push_back(random_payload);
end
end
$info("\n PASS after %d iter \n", iter);
$finish;
end
end
SyncFIFO #(
.Depth(Depth),
.WordWidth(WordWidth)
) SyncFIFO_dut (
.push_i(push_i),
.push_payload_i(push_payload_i),
.pop_i(pop_i),
.pop_payload_o(pop_payload_o),
.full_o(full_o),
.empty_o(empty_o),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("SyncFIFO_tb.fsdb");
$fsdbDumpvars(0, SyncFIFO_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,42 @@
module CountOne #(
parameter int unsigned InputWidth = 8,
localparam int unsigned CountWidth = $clog2(InputWidth + 1)
) (
input wire [InputWidth-1:0] bits_i,
output wire [CountWidth-1:0] cnt_o
);
localparam int unsigned PaddedWidth = 1 << $clog2(InputWidth);
localparam int unsigned ChildCountWidth = PaddedWidth == 1 ? 1 : $clog2(PaddedWidth);
wire [ChildCountWidth-1:0] leftChildCount, rightChildCount;
generate
if (InputWidth == 1) begin : gen_single_node
assign leftChildCount = 1'b0;
assign rightChildCount = bits_i;
end else if (InputWidth == 2) begin : gen_leaf_node
assign leftChildCount = bits_i[0];
assign rightChildCount = bits_i[1];
end else begin : gen_non_leaf_node
wire [PaddedWidth-1:0] paddedBits;
// Zero pad the input bits to next power of two
assign paddedBits = {{PaddedWidth - InputWidth{1'b0}}, bits_i};
CountOne #(
.InputWidth(PaddedWidth / 2)
) u_leftChild (
.bits_i(paddedBits[PaddedWidth-1:PaddedWidth/2]),
.cnt_o (leftChildCount)
);
CountOne #(
.InputWidth(PaddedWidth / 2)
) u_rightChild (
.bits_i(paddedBits[PaddedWidth/2-1:0]),
.cnt_o (rightChildCount)
);
end
endgenerate
assign cnt_o = leftChildCount + rightChildCount;
endmodule

View File

@@ -0,0 +1,21 @@
module MuxOH #(
parameter int unsigned InputWidth = 8,
parameter int unsigned DataWidth = 8
) (
input wire [InputWidth-1:0] sel_i,
input wire [InputWidth-1:0][DataWidth-1:0] data_i,
output wire [DataWidth-1:0] data_o
);
wire [DataWidth-1:0][InputWidth-1:0] dataT;
generate
for (genvar i = 0; i < DataWidth; i++) begin : gen_row
for (genvar j = 0; j < InputWidth; j++) begin : gen_col
assign dataT[i][j] = data_i[j][i];
end
assign data_o[i] = |(dataT[i] & sel_i);
end
endgenerate
endmodule

View File

@@ -0,0 +1,25 @@
module OH2UInt #(
parameter int unsigned InputWidth = 8,
localparam int unsigned OutputWidth = InputWidth > 1 ? $clog2(InputWidth) : 1
) (
input wire [ InputWidth-1:0] oh_i,
output wire [OutputWidth-1:0] result_o
);
localparam int unsigned CountWidth = $clog2(InputWidth + 1);
wire [InputWidth-1:0] maskLow;
wire [CountWidth-1:0] count;
assign maskLow = oh_i - 1'b1;
assign result_o = count[OutputWidth-1:0];
CountOne #(
.InputWidth(InputWidth)
) CountOne_dut (
.bits_i(maskLow),
.cnt_o (count)
);
endmodule

View File

@@ -0,0 +1,48 @@
module PLRU #(
parameter ENTRY_COUNT = 4
) (
input [ENTRY_COUNT-1:0] access_mask_i,
output [ENTRY_COUNT-1:0] least_used_mask_o,
input clk,
input rstn
);
localparam PLRUTreeLvl = $clog2(ENTRY_COUNT);
localparam NodeCount = ENTRY_COUNT - 1;
generate
if (ENTRY_COUNT == 1) begin : gen_one_entry_case
assign least_used_mask_o = 1'b1;
end else begin : gen_normal_case
wire plru_nodes_clk_en;
wire [NodeCount-1:0] plru_nodes_d;
reg [NodeCount-1:0] plru_nodes_q;
assign plru_nodes_clk_en = |access_mask_i;
DFFRE #(
.Width(NodeCount)
) u_plru_nodes_DFFRE (
.CLK(clk),
.RSTN(rstn),
.DRST({NodeCount{1'b0}}),
.EN(plru_nodes_clk_en),
.D(plru_nodes_d),
.Q(plru_nodes_q)
);
PLRUTree #(
.TREE_LVL_COUNT(PLRUTreeLvl)
) u_PLRUTree (
.access_mask_i(access_mask_i),
.plru_old_node_i(plru_nodes_q),
.plru_new_node_o(plru_nodes_d),
.node_en_i(1'b1),
.least_used_mask_o(least_used_mask_o),
.clk(clk),
.rstn(rstn)
);
end
endgenerate
endmodule

View File

@@ -0,0 +1,64 @@
module PLRUTree #(
parameter TREE_LVL_COUNT = 3,
localparam ENTRY_COUNT = (1 << TREE_LVL_COUNT),
localparam NODE_COUNT = ENTRY_COUNT - 1
) (
input [ENTRY_COUNT-1:0] access_mask_i,
input [NODE_COUNT-1:0] plru_old_node_i,
output [NODE_COUNT-1:0] plru_new_node_o,
input node_en_i,
output [ENTRY_COUNT-1:0] least_used_mask_o,
input clk,
input rstn
);
wire node_toggle_en;
wire node;
wire left_child_node_en;
wire right_child_node_en;
wire access_left;
wire access_right;
assign node = plru_old_node_i[0];
assign node_toggle_en = (~node & access_left) | (node & access_right);
assign plru_new_node_o[0] = node_toggle_en ? ~node : node;
assign access_left = |access_mask_i[ENTRY_COUNT/2-1:0];
assign access_right = |access_mask_i[ENTRY_COUNT-1:ENTRY_COUNT/2];
assign left_child_node_en = node_en_i & ~node;
assign right_child_node_en = node_en_i & node;
generate
if (TREE_LVL_COUNT > 1) begin : gen_child_tree
PLRUTree #(
.TREE_LVL_COUNT(TREE_LVL_COUNT - 1)
) u_left_child_PLRUTree (
.access_mask_i(access_mask_i[ENTRY_COUNT/2-1:0]),
.plru_old_node_i(plru_old_node_i[(NODE_COUNT-1)/2:1]),
.plru_new_node_o(plru_new_node_o[(NODE_COUNT-1)/2:1]),
.node_en_i(left_child_node_en),
.least_used_mask_o(least_used_mask_o[ENTRY_COUNT/2-1:0]),
.clk(clk),
.rstn(rstn)
);
PLRUTree #(
.TREE_LVL_COUNT(TREE_LVL_COUNT - 1)
) u_right_child_PLRUTree (
.access_mask_i(access_mask_i[ENTRY_COUNT-1:ENTRY_COUNT/2]),
.plru_old_node_i(plru_old_node_i[NODE_COUNT-1:(NODE_COUNT+1)/2]),
.plru_new_node_o(plru_new_node_o[NODE_COUNT-1:(NODE_COUNT+1)/2]),
.node_en_i(right_child_node_en),
.least_used_mask_o(least_used_mask_o[ENTRY_COUNT-1:ENTRY_COUNT/2]),
.clk(clk),
.rstn(rstn)
);
end else begin : gen_leaf
assign least_used_mask_o[0] = left_child_node_en;
assign least_used_mask_o[1] = right_child_node_en;
end
endgenerate
endmodule

View File

@@ -0,0 +1,24 @@
module PriorityMux #(
parameter int unsigned InputWidth = 8,
parameter int unsigned DataWidth = 8
) (
input wire [InputWidth-1:0] sel_i,
input wire [InputWidth-1:0][DataWidth-1:0] data_i,
output wire [DataWidth-1:0] data_o
);
wire [InputWidth-1:0] sel_oh;
assign sel_oh = sel_i & (~(sel_i - 1));
MuxOH #(
.InputWidth(InputWidth),
.DataWidth (DataWidth)
) u_MuxOH (
.sel_i (sel_oh),
.data_i(data_i),
.data_o(data_o)
);
endmodule

View File

@@ -0,0 +1,52 @@
module StreamFIFO #(
parameter int unsigned Depth = 8,
parameter int unsigned WordWidth = 64
) (
input wire enq_vld_i,
input wire [WordWidth-1:0] enq_payload_i,
output wire enq_rdy_o,
output wire deq_vld_o,
output wire [WordWidth-1:0] deq_payload_o,
input wire deq_rdy_i,
input wire flush_i,
input wire clk,
input wire rstn
);
wire push;
wire [WordWidth-1:0] push_payload;
wire pop;
wire [WordWidth-1:0] pop_payload;
wire full;
wire empty;
wire enq_fire;
wire deq_fire;
assign enq_rdy_o = ~full;
assign enq_fire = enq_vld_i & enq_rdy_o;
assign push = enq_fire;
assign push_payload = enq_payload_i;
assign pop = deq_fire;
assign deq_vld_o = ~empty;
assign deq_fire = deq_vld_o & deq_rdy_i;
assign deq_payload_o = pop_payload;
SyncFIFO #(
.Depth(Depth),
.WordWidth(WordWidth)
) u_SyncFIFO (
.push_i(push),
.push_payload_i(push_payload),
.pop_i(pop),
.pop_payload_o(pop_payload),
.full_o(full),
.empty_o(empty),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
endmodule

View File

@@ -0,0 +1,129 @@
module SyncFIFO #(
parameter int unsigned Depth = 8,
parameter int unsigned WordWidth = 64
) (
input wire push_i,
input wire [WordWidth-1:0] push_payload_i,
input wire pop_i,
output wire [WordWidth-1:0] pop_payload_o,
output wire full_o,
output wire empty_o,
input wire flush_i,
input wire clk,
input wire rstn
);
localparam int unsigned PtrWidth = $clog2(Depth);
wire [Depth-1:0] payload_ram_clk_en;
wire [Depth-1:0][WordWidth-1:0] payload_ram_d, payload_ram_q;
wire head_clk_en;
reg head_flag_d, head_flag_q;
reg [PtrWidth-1:0] head_ptr_d, head_ptr_q;
wire tail_clk_en;
reg tail_flag_d, tail_flag_q;
reg [PtrWidth-1:0] tail_ptr_d, tail_ptr_q;
wire ptr_equal;
wire flag_equal;
assign head_clk_en = pop_i | flush_i;
assign tail_clk_en = push_i | flush_i;
generate
for (genvar i = 0; i < Depth; i++) begin : gen_payload_update_logic
assign payload_ram_clk_en[i] = (push_i & ~flush_i) & (tail_ptr_q == i);
assign payload_ram_d[i] = payload_ram_clk_en[i] ? push_payload_i : payload_ram_q[i];
end
endgenerate
always @(*) begin : tail_update_logic
{tail_flag_d, tail_ptr_d} = {tail_flag_q, tail_ptr_q};
if (push_i) begin
if (tail_ptr_q == Depth - 1) begin
{tail_flag_d, tail_ptr_d} = {~tail_flag_q, {PtrWidth{1'b0}}};
end else begin
tail_ptr_d = tail_ptr_q + 1'b1;
end
end
if (flush_i) begin
{tail_flag_d, tail_ptr_d} = {PtrWidth + 1{1'b0}};
end
end
always @(*) begin : head_update_logic
{head_flag_d, head_ptr_d} = {head_flag_q, head_ptr_q};
if (pop_i) begin
if (head_ptr_q == Depth - 1) begin
{head_flag_d, head_ptr_d} = {~head_flag_q, {PtrWidth{1'b0}}};
end else begin
head_ptr_d = head_ptr_q + 1'b1;
end
end
if (flush_i) begin
{head_flag_d, head_ptr_d} = {PtrWidth + 1{1'b0}};
end
end
assign flag_equal = head_flag_q == tail_flag_q;
assign ptr_equal = head_ptr_q == tail_ptr_q;
assign full_o = (~flag_equal & ptr_equal & ~pop_i);
assign empty_o = flag_equal & ptr_equal;
assign pop_payload_o = payload_ram_q[head_ptr_q];
DFFRE #(
.Width(PtrWidth + 1)
) u_head_dff (
.CLK(clk),
.RSTN(rstn),
.EN(head_clk_en),
.DRST({PtrWidth + 1{1'b0}}),
.D({head_flag_d, head_ptr_d}),
.Q({head_flag_q, head_ptr_q})
);
DFFRE #(
.Width(PtrWidth + 1)
) u_tail_dff (
.CLK(clk),
.RSTN(rstn),
.EN(tail_clk_en),
.DRST({PtrWidth + 1{1'b0}}),
.D({tail_flag_d, tail_ptr_d}),
.Q({tail_flag_q, tail_ptr_q})
);
generate
for (genvar i = 0; i < Depth; i++) begin : gen_payload_dff
DFFE #(
.Width(WordWidth)
) u_payload_dff (
.CLK(clk),
.EN (payload_ram_clk_en[i]),
.D (payload_ram_d[i]),
.Q (payload_ram_q[i])
);
end
endgenerate
`ifndef SYNTHESIS
default disable iff (~rstn); CHECK_POP_WHEN_EMPTY :
assert property (@(posedge clk) pop_i |-> ~empty_o)
else begin
$error("Pop when empty\n");
end
CHECK_PUSH_WHEN_FULL :
assert property (@(posedge clk) push_i |-> ~full_o)
else begin
$error("Push when full\n");
end
`endif
endmodule

View File

@@ -0,0 +1,58 @@
Name: Queue
Dependency:
- ../StdDFF/StdDFF.yaml
- ../Basic/Basic.yaml
Module:
- name: QueueManager
description: Queue Ptr Manager
language: SystemVerilog
rtl:
- hw/QueueManager.v
dependency:
- CountOne
- StdDFF
- name: StaticPrioritySelector
description: Static Priority Selector
language: SystemVerilog
rtl:
- hw/StaticPrioritySelector.v
sim:
- dv/StaticPrioritySelector_tb.v
- name: AgeMatrixSelector
description: Age Matrix selector to select in age order
language: SystemVerilog
rtl:
- hw/AgeMatrixSelector.v
# sim:
# - dv/AgeMatrixSelector_tb.v
dependency:
- MuxOH
- name: MultiPortStreamFIFO
description: MultiPortStream FIFO
language: SystemVerilog
rtl:
- hw/FIFO/MultiPortStreamFIFO.v
sim:
- dv/FIFO/MultiPortStreamFIFO_tb.v
dependency:
- QueueManager
- name: FIAOWithQueueManager
description: FIAOWithQueueManager
language: SystemVerilog
rtl:
- hw/FIAO/FIAOWithQueueManager.v
dependency:
- QueueManager
# - name: FIAOWithAgeMatrix
# description: FIAOWithAgeMatrix
# language: SystemVerilog
# rtl:
# - hw/FIAO/FIAOWithAgeMatrix.v
# dependency:
# - OH2UInt
# - AgeMatrixSelector

View File

@@ -0,0 +1,168 @@
// module AgeMatrixSelector_tb;
// // Parameters
// localparam int unsigned EntryCount = 4;
// localparam int unsigned EnqWidth = 2;
// localparam int unsigned SelWidth = 2;
// // Ports
// reg [EnqWidth-1:0] enq_fire_i;
// reg [EntryCount-1:0] enq_mask_i[EnqWidth];
// reg [EntryCount-1:0] sel_mask_i;
// wire [EntryCount-1:0] result_mask_o[SelWidth];
// reg [EntryCount-1:0] entry_vld_i;
// reg clk = 0;
// reg rstn = 0;
// bit [EntryCount-1:0][EntryCount-1:0] golden_age_matrix_d, golden_age_matrix_q;
// bit [EntryCount-1:0][EntryCount-1:0] golden_masked_age_matrix[SelWidth];
// bit [EntryCount-1:0] golden_selected_mask[SelWidth];
// bit [EntryCount-1:0] golden_sel_result[SelWidth];
// always @(posedge clk) begin
// if (~rstn) begin
// golden_age_matrix_q <= 0;
// end else begin
// for (int row = 0; row < EntryCount; row++) begin
// for (int col = 0; col < EntryCount; col++) begin
// if (row != col) begin
// golden_age_matrix_q[row][col] <= golden_age_matrix_d[row][col];
// end
// end
// end
// end
// end
// always @(*) begin
// for (int row = 0; row < EntryCount; row++) begin
// golden_age_matrix_q[row][row] <= entry_vld_i[row];
// end
// end
// always @(*) begin
// golden_age_matrix_d = golden_age_matrix_q;
// for (int i = 0; i < EnqWidth; i++) begin
// if (enq_fire_i[i]) begin
// for (int row = 0; row < EntryCount; row++) begin
// if (enq_mask_i[i][row]) begin
// for (int col = 0; col < EntryCount; col++) begin
// golden_age_matrix_d[row][col] = ~golden_age_matrix_d[col][col];
// end
// end
// end
// end
// end
// end
// always @(*) begin
// for (int i = 0; i < EntryCount; i++) begin
// if (i == 0) begin
// golden_selected_mask[i] = 0;
// end else begin
// golden_selected_mask[i] = golden_selected_mask[i-1] | golden_sel_result[i-1];
// end
// end
// end
// always @(*) begin
// for (int i = 0; i < SelWidth; i++) begin
// golden_masked_age_matrix[i] = golden_age_matrix_q;
// for (int col = 0; col < EntryCount; col++) begin
// if (golden_selected_mask[i][col] | ~sel_mask_i[col]) begin
// for (int row = 0; row < EntryCount; row++) begin
// golden_masked_age_matrix[i][row][col] = col != row;
// end
// end
// end
// end
// end
// always @(*) begin
// for (int i = 0; i < SelWidth; i++) begin
// for (int row = 0; row < EntryCount; row++) begin
// golden_sel_result[i][row] = &golden_masked_age_matrix[i][row];
// end
// end
// end
// default disable iff (~rstn);
// int iter = 10000;
// int random_ptr;
// CHECK_EQULATION :
// assert property (@(negedge clk) golden_age_matrix_q == AgeMatrixSelector_dut.age_matrix_q)
// else begin
// $fatal("\n Error : Age matrix is not equal to golden one \n");
// end
// initial begin
// #100 rstn = 1'b1;
// entry_vld_i = 0;
// enq_fire_i = 0;
// sel_mask_i = 0;
// repeat (iter) begin
// @(posedge clk);
// entry_vld_i = entry_vld_i & ~(entry_vld_i & $urandom_range(0, (1 << EntryCount) - 1));
// for (int i = 0; i < EnqWidth; i++) begin
// if (enq_fire_i[i]) begin
// entry_vld_i = entry_vld_i | enq_mask_i[i];
// end
// end
// sel_mask_i = $urandom_range(0, (1 << EntryCount) - 1) & entry_vld_i;
// @(negedge clk);
// for (int i = 0; i < EnqWidth; i++) begin
// enq_fire_i[i] = 0;
// enq_mask_i[i] = 0;
// random_ptr = $urandom_range(0, EntryCount - 1);
// if (~entry_vld_i[random_ptr]) begin
// enq_fire_i[i] = 1;
// enq_mask_i[i][random_ptr] = 1;
// end
// for(int j = 0 ; j < i; j++) begin
// if(enq_fire_i[j] && (enq_mask_i[j] == enq_mask_i[i])) begin
// enq_fire_i[i] = 0;
// end
// end
// end
// for (int i = 0; i < SelWidth; i++) begin
// assert (result_mask_o[i] == golden_sel_result[i])
// else begin
// $fatal("\n Error : Selection is not equal, golden[%b] our[%b] \n", golden_sel_result[i],
// result_mask_o[i]);
// end
// end
// end
// $info("\n PASS after %d iter \n",iter);
// $finish();
// end
// AgeMatrixSelector #(
// .EntryCount(EntryCount),
// .EnqWidth (EnqWidth),
// .SelWidth (SelWidth)
// ) AgeMatrixSelector_dut (
// .enq_fire_i(enq_fire_i),
// .enq_mask_i(enq_mask_i),
// .sel_mask_i(sel_mask_i),
// .result_mask_o(result_mask_o),
// .entry_vld_i(entry_vld_i),
// .clk(clk),
// .rstn(rstn)
// );
// `ifdef DUMPON
// initial begin : GEN_WAVEFORM
// $fsdbDumpfile("AgeMatrixSelector_tb.fsdb");
// $fsdbDumpvars(0, AgeMatrixSelector_tb);
// $fsdbDumpvars("+mda");
// $fsdbDumpvars("+all");
// $fsdbDumpon();
// end
// `endif
// always #20 clk = !clk;
// endmodule

View File

@@ -0,0 +1,111 @@
module MultiPortStreamFIFO_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned DataWidth = 32;
localparam int unsigned EnqWidth = 2;
localparam int unsigned DeqWidth = 2;
localparam int unsigned TakenAll = 0;
// Ports
reg [EnqWidth-1:0] enq_vld_i;
reg [EnqWidth-1:0][DataWidth-1:0] enq_payload_i;
wire [EnqWidth-1:0] enq_rdy_o;
wire [DeqWidth-1:0] deq_vld_o;
wire [DeqWidth-1:0][DataWidth-1:0] deq_payload_o;
reg [DeqWidth-1:0] deq_rdy_i;
reg flush_i = 0;
reg clk = 0;
reg rstn = 0;
bit [DataWidth-1:0] golden_fifo[$];
bit [DataWidth-1:0] golden_fifo_front;
int usage = 0;
int iter = 1000000;
always @(posedge clk) begin
for (int i = 0; i < DeqWidth; i++) begin : test_deq
if (deq_vld_o[i] & deq_rdy_i[i]) begin
usage = usage - 1;
golden_fifo_front = golden_fifo.pop_front();
assert (deq_payload_o[i] == golden_fifo_front)
else begin
$fatal("\n Error: Fail when check equalation, ours[%x] -- gloden[%x]", deq_payload_o[i],
golden_fifo_front);
end
end
end
for (int i = 0; i < EnqWidth; i++) begin : enq_test
if (enq_vld_i[i] & enq_rdy_o[i]) begin
usage = usage + 1;
golden_fifo.push_back(enq_payload_i[i]);
end
end
end
initial begin
#10 rstn = 1'b1;
repeat (iter) begin : random_test
@(negedge clk);
deq_rdy_i = {DeqWidth{1'b0}};
enq_vld_i = {EnqWidth{1'b0}};
for (int i = 0; i < DeqWidth; i++) begin : gen_deq_rdy
if ($urandom_range(0, 1)) begin
deq_rdy_i[i] = 1'b1;
end else begin
break;
end
end
for (int i = 0; i < EnqWidth; i++) begin : gen_enq_vld
if ($urandom_range(0, 1)) begin
enq_vld_i[i] = 1'b1;
enq_payload_i[i] = $urandom();
end else begin
break;
end
end
CHECK_USAGE :
assert (usage == MultiPortStreamFIFO_dut.u_QueueManager.usage)
else begin
$fatal("\n Error : Usage is not equal, which should never happen! ours[%d] gloden[%d] \n",
MultiPortStreamFIFO_dut.u_QueueManager.usage, usage);
end
end
$info("\n PASS after %d iter \n", iter);
$finish;
end
MultiPortStreamFIFO #(
.Depth(Depth),
.DataWidth(DataWidth),
.EnqWidth(EnqWidth),
.DeqWidth(DeqWidth),
.TakenAll(TakenAll)
) MultiPortStreamFIFO_dut (
.enq_vld_i(enq_vld_i),
.enq_payload_i(enq_payload_i),
.enq_rdy_o(enq_rdy_o),
.deq_vld_o(deq_vld_o),
.deq_payload_o(deq_payload_o),
.deq_rdy_i(deq_rdy_i),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("MultiPortStreamFIFO_tb.fsdb");
$fsdbDumpvars(0, MultiPortStreamFIFO_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,99 @@
module StaticPrioritySelector_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned EnqWidth = 2;
localparam int unsigned SelWidth = 2;
localparam int unsigned PtrWidth = $clog2(Depth);
// Ports
wire [EnqWidth-1:0][Depth-1:0] enq_mask_o;
reg [Depth-1:0] sel_mask_i;
wire [SelWidth-1:0][Depth-1:0] result_mask_o;
reg [Depth-1:0] entry_vld_i;
int iter = 100000;
bit [EnqWidth-1:0][Depth-1:0] golden_enq_mask;
bit [SelWidth-1:0][Depth-1:0] golden_result_mask;
int cnt;
initial begin
repeat (iter) begin
entry_vld_i = $urandom_range(0, ((1 << Depth) - 1));
sel_mask_i = $urandom_range(0, ((1 << Depth) - 1)) & entry_vld_i;
#100;
for (int i = 0; i < EnqWidth; i++) begin : init_golden_enq_mask
golden_enq_mask[i] = 0;
end
cnt = 0;
for (int i = 0; i < Depth; i++) begin : gen_golden_enq_mask
if (~entry_vld_i[i]) begin
golden_enq_mask[cnt][i] = 1'b1;
cnt = cnt + 1;
if (cnt == EnqWidth) begin
break;
end
end
end
for (int i = 0; i < SelWidth; i++) begin : init_golden_result_mask
golden_result_mask[i] = 0;
end
cnt = 0;
for (int i = 0; i < Depth; i++) begin : gen_golden_result_mask
if (sel_mask_i[i]) begin
golden_result_mask[cnt][i] = 1'b1;
cnt = cnt + 1;
if (cnt == SelWidth) begin
break;
end
end
end
CheckEnqEqual :
for (int i = 0; i < EnqWidth; i++) begin
assert (golden_enq_mask[i] == enq_mask_o[i])
else begin
$fatal("\n Masks are not equal, ours[%b] - golden[%b] \n", enq_mask_o[i],
golden_enq_mask[i]);
end
end
for (int i = 0; i < SelWidth; i++) begin
CheckSelEqual :
assert (golden_result_mask[i] == result_mask_o[i])
else begin
$fatal("\n Masks are not equal, ours[%b] - golden[%b] \n", result_mask_o[i],
golden_result_mask[i]);
end
end
end
#100;
$info("PASS\n");
$finish;
end
StaticPrioritySelector #(
.Depth(Depth),
.EnqWidth(EnqWidth),
.SelWidth(SelWidth)
) StaticPrioritySelector_dut (
.enq_mask_o(enq_mask_o),
.sel_mask_i(sel_mask_i),
.result_mask_o(result_mask_o),
.entry_vld_i(entry_vld_i)
);
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("StaticPrioritySelector_tb.fsdb");
$fsdbDumpvars(0, StaticPrioritySelector_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
endmodule

View File

@@ -0,0 +1,187 @@
module AgeMatrixSelector #(
parameter int unsigned EntryCount = 4,
parameter int unsigned EnqWidth = 2,
parameter int unsigned SelWidth = 2
) (
input wire [EnqWidth-1:0] enq_fire_i,
input wire [EnqWidth-1:0][EntryCount-1:0] enq_mask_i,
input wire deq_fire_i,
input wire [EntryCount-1:0] deq_mask_i,
input wire [EntryCount-1:0] sel_mask_i,
output wire [SelWidth-1:0][EntryCount-1:0] result_mask_o,
input wire [EntryCount-1:0] entry_vld_i,
input wire clk,
input wire rstn
);
wire [EntryCount-1:0] age_matrix_clk_en;
wire [EntryCount-1:0] enq_age_matrix_en;
wire [EntryCount-1:0] deq_age_matrix_en;
wire [EnqWidth-1:0][EntryCount-1:0] enq_dependency_vec;
wire [EntryCount-1:0][EnqWidth-1:0] enq_entry_sel_mask;
wire [EntryCount-1:0][EntryCount-1:0] enq_age_matrix;
wire [EntryCount-1:0][EntryCount-1:0] deq_age_matrix;
reg [EntryCount-1:0][EntryCount-1:0] age_matrix_d, age_matrix_q;
wire [SelWidth-1:0][EntryCount-1:0] selected_vec;
wire [SelWidth-1:0][EntryCount-1:0][EntryCount-1:0] masked_age_matrix;
// In age order select
generate
for (genvar i = 0; i < SelWidth; i++) begin : gen_selected_vec
if (i == 0) begin : gen_initial_one
assign selected_vec[i] = {EntryCount{1'b0}};
end else begin : gen_others
assign selected_vec[i] = selected_vec[i-1] | result_mask_o[i-1];
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_sel_matrix
for (genvar col = 0; col < EntryCount; col++) begin : gen_col
for (genvar row = 0; row < EntryCount; row++) begin : gen_row
if (col == row) begin : gen_masked_vld
assign masked_age_matrix[i][row][col] = sel_mask_i[col] & ~selected_vec[i][col];
end else begin : gen_masked_dependency
assign masked_age_matrix[i][row][col] = (sel_mask_i[col] & ~selected_vec[i][col]) ?
age_matrix_q[row][col] : 1'b1;
end
end
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_multi_result
for (genvar row = 0; row < EntryCount; row++) begin : gen_one
assign result_mask_o[i][row] = &masked_age_matrix[i][row];
end
end
endgenerate
// Enq -> Set dependency bits
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_enq_entry_en
assign enq_age_matrix_en[i] = |enq_entry_sel_mask[i];
end
endgenerate
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_dependency_vec
if (i == 0) begin : gen_init_vec
assign enq_dependency_vec[i] = deq_fire_i ? (~entry_vld_i | deq_mask_i) : ~entry_vld_i;
end else begin : gen_vec_with_inter_check
assign enq_dependency_vec[i] = enq_fire_i[i-1] ?
(enq_dependency_vec[i-1] & ~enq_mask_i[i-1]) : enq_dependency_vec[i-1];
end
end
endgenerate
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_enq_entry_sel_mask
for (genvar j = 0; j < EnqWidth; j++) begin : gen_sel
assign enq_entry_sel_mask[i][j] = enq_fire_i[j] & enq_mask_i[j][i];
end
end
endgenerate
// Deq -> Clear dependency bits
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_deq_entry_clk_en
assign deq_age_matrix[i] = age_matrix_q[i] | deq_mask_i;
end
endgenerate
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_deq_entry_en
assign deq_age_matrix_en[i] = deq_fire_i & entry_vld_i[i];
end
endgenerate
assign age_matrix_clk_en = enq_age_matrix_en | deq_age_matrix_en;
// Age matrix update
always @(*) begin : age_matrix_vld_dff
for (int i = 0; i < EntryCount; i++) begin
age_matrix_q[i][i] = entry_vld_i[i];
end
end
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_age_matrix_update_logic
MuxOH #(
.InputWidth(2),
.DataWidth (EntryCount)
) u_age_matrix_update_MuxOH (
.sel_i ({enq_age_matrix_en[i], deq_age_matrix_en[i]}),
.data_i({enq_age_matrix[i], deq_age_matrix[i]}),
.data_o(age_matrix_d[i])
);
end
endgenerate
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_entry_update_dependency_vec
MuxOH #(
.InputWidth(EnqWidth),
.DataWidth (EntryCount)
) u_depend_vec_MuxOH (
.sel_i (enq_entry_sel_mask[i]),
.data_i(enq_dependency_vec),
.data_o(enq_age_matrix[i])
);
end
endgenerate
always @(posedge clk or negedge rstn) begin : age_matrix_dependency_dff
if (~rstn) begin
for (int row = 0; row < EntryCount; row++) begin
for (int col = 0; col < EntryCount; col++) begin
if (row != col) begin
age_matrix_q[row][col] <= 1'b0;
end
end
end
end else begin
for (int row = 0; row < EntryCount; row++) begin
if (age_matrix_clk_en[row]) begin
for (int col = 0; col < EntryCount; col++) begin
if (row != col) begin
age_matrix_q[row][col] <= age_matrix_d[row][col];
end
end
end
end
end
end
`ifndef SYNTHESIS
default disable iff (~rstn);
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_checker
ENQ_VLD_ENTRY :
assert property (@(posedge clk) enq_fire_i[i] |-> ((enq_mask_i[i] & entry_vld_i) == 0))
else begin
$fatal("\n Error : Enqueueing a valid entry! enq_mask[%b]\n", enq_mask_i[i]);
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_sel_checker
SEL_INVLD_ENTRY :
assert property (@(negedge clk) |sel_mask_i |-> ((result_mask_o[i] & ~entry_vld_i) == 0))
else begin
$fatal("\n Error : Selecting a invalid entry! sel_mask[%b]\n",
(result_mask_o[i] & ~entry_vld_i));
end
RESULT_MASK_IS_ONEHOT :
assert property (@(negedge clk) |sel_mask_i |-> $onehot0(result_mask_o[i]))
else begin
$fatal("\n Error : Got multi-choice which should never happend! result_mask[%b]\n",
result_mask_o[i]);
end
end
endgenerate
`endif
endmodule

View File

@@ -0,0 +1,61 @@
// module FIAOWithAgeMatrix #(
// parameter int unsigned Depth = 8,
// parameter int unsigned EnqWidth = 2,
// parameter int unsigned SelWidth = 2,
// localparam int unsigned PtrWidth = $clog2(Depth)
// ) (
// // Enqueue Port
// input wire [EnqWidth-1:0] enq_fire_i,
// input wire [EnqWidth-1:0] enq_eval_i,
// output wire [Depth-1:0] enq_mask_o[EnqWidth],
// output wire [PtrWidth-1:0] enq_ptr_o[EnqWidth],
// // Select Port
// input wire [Depth-1:0] sel_mask_i,
// output wire [Depth-1:0] result_mask_o[SelWidth],
// // Status
// input wire [Depth-1:0] entry_vld_i,
// input wire clk,
// input wire rstn
// );
// wire [Depth-1:0] enq_rdy_mask[EnqWidth];
// generate
// for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_rdy_mask
// if (i == 0) begin : gen_initial_one
// assign enq_rdy_mask[i] = ~entry_vld_i;
// end else begin : gen_others
// assign enq_rdy_mask[i] = enq_eval_i[i-1] ?
// enq_rdy_mask[i-1] : (enq_rdy_mask[i-1] & ~enq_mask_o[i-1]);
// end
// end
// for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_mask
// assign enq_mask_o[i] = enq_rdy_mask[i] & ~(enq_rdy_mask[i] - 1'b1);
// OH2UInt #(
// .InputWidth(Depth)
// ) u_OH2UInt (
// .oh_i(enq_mask_o[i]),
// .result_o(enq_ptr_o[i])
// );
// end
// endgenerate
// AgeMatrixSelector #(
// .EntryCount(Depth),
// .EnqWidth (EnqWidth),
// .SelWidth (SelWidth)
// ) u_AgeMatrixSelector (
// .enq_fire_i(enq_fire_i),
// .enq_mask_i(enq_mask_o),
// .sel_mask_i(sel_mask_i),
// .result_mask_o(result_mask_o),
// .entry_vld_i(entry_vld_i),
// .clk(clk),
// .rstn(rstn)
// );
// endmodule

View File

@@ -0,0 +1,126 @@
module FIAOWithQueueManager #(
parameter int unsigned Depth = 8,
parameter int unsigned EnqWidth = 2,
parameter int unsigned DeqWidth = 2,
parameter int unsigned SelWidth = 2,
localparam int unsigned PtrWidth = $clog2(Depth)
) (
// Enqueue Port
input wire [EnqWidth-1:0] enq_fire_i,
input wire [EnqWidth-1:0] enq_eval_i,
output wire [EnqWidth-1:0][Depth-1:0] enq_mask_o,
output wire [EnqWidth-1:0][PtrWidth-1:0] enq_ptr_o,
// Select Port
input wire [Depth-1:0] sel_mask_i,
output wire [SelWidth-1:0][Depth-1:0] result_mask_o,
// Status
input wire [Depth-1:0] entry_vld_i,
input wire clk,
input wire rstn
);
localparam int unsigned TagWidth = PtrWidth + 1;
wire [EnqWidth-1:0][PtrWidth-1:0] enq_ptr;
wire [EnqWidth-1:0] enq_flag;
wire [EnqWidth-1:0][TagWidth-1:0] enq_tag;
wire [DeqWidth-1:0] enq_eval;
wire [DeqWidth-1:0] enq_fire;
wire [DeqWidth-1:0][PtrWidth-1:0] deq_ptr;
wire [DeqWidth-1:0] deq_flag;
wire [DeqWidth-1:0][TagWidth-1:0] deq_tag;
wire [DeqWidth-1:0] deq_eval;
wire [DeqWidth-1:0] deq_fire;
wire first_enq_flag;
wire [PtrWidth-1:0] first_enq_ptr;
wire first_deq_flag;
wire [PtrWidth-1:0] first_deq_ptr;
wire flag_equal;
wire [Depth-1:0] head_inv_mask;
wire [Depth-1:0] tail_inv_mask;
wire [Depth-1:0] head_side_sel_mask[SelWidth-1:0];
wire [Depth-1:0] tail_side_sel_mask[SelWidth-1:0];
wire [Depth-1:0] head_side_sel_result[SelWidth-1:0];
wire [Depth-1:0] tail_side_sel_result[SelWidth-1:0];
wire [Depth-1:0] selected_mask[SelWidth-1:0];
// Enqueue Logic
assign enq_eval = enq_eval_i;
assign enq_fire = enq_fire_i;
assign enq_ptr_o = enq_ptr;
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_logic
assign enq_ptr[i] = enq_tag[i][PtrWidth-1:0];
assign enq_flag[i] = enq_tag[i][TagWidth-1];
assign enq_mask_o[i] = {{Depth - 1{1'b0}}, 1'b1} << enq_ptr[i];
end
endgenerate
// Select Logic
assign first_enq_flag = enq_flag[0];
assign first_enq_ptr = enq_ptr[0];
assign first_deq_flag = deq_flag[0];
assign first_deq_ptr = deq_ptr[0];
assign flag_equal = ~(first_enq_flag ^ first_deq_flag);
assign head_inv_mask = (({{PtrWidth - 1{1'b0}}, {1'b1}} << first_deq_ptr) - 1'b1);
assign tail_inv_mask = ~(({{PtrWidth - 1{1'b0}}, {1'b1}} << first_enq_ptr) - 1'b1);
generate
for (genvar i = 0; i < SelWidth; i++) begin : gen_selected_mask
if (i == 0) begin : gen_initial_one
assign selected_mask[i] = {Depth{1'b0}};
end else begin : gen_others
assign selected_mask[i] = selected_mask[i-1] | result_mask_o[i-1];
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_side_sel_mask
assign head_side_sel_mask[i] = sel_mask_i & ~selected_mask[i] & ~head_inv_mask;
assign tail_side_sel_mask[i] = sel_mask_i & ~selected_mask[i] & ~tail_inv_mask;
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_priority_select_result
assign head_side_sel_result[i] = head_side_sel_mask[i] & ~(head_side_sel_mask[i] - 1'b1);
assign tail_side_sel_result[i] = tail_side_sel_mask[i] & ~(tail_side_sel_mask[i] - 1'b1);
assign result_mask_o[i] = flag_equal ? head_side_sel_result[i] :
(|head_side_sel_result[i] ? head_side_sel_result[i] : tail_side_sel_result[i]);
end
endgenerate
// Dequeue Logic
generate
for (genvar i = 0; i < DeqWidth; i++) begin : gen_deq_logic
assign deq_ptr[i] = deq_tag[i][PtrWidth-1:0];
assign deq_flag[i] = deq_tag[i][TagWidth-1];
assign deq_eval[i] = 1'b1;
assign deq_fire[i] = ~entry_vld_i[deq_tag[i]];
end
endgenerate
QueueManager #(
.Depth(Depth),
.EnqWidth(EnqWidth),
.DeqWidth(DeqWidth),
.FlagEnable(1),
.EnqCollapse(1),
.DeqCollapse(0),
.InitFull(0)
) u_QueueManager (
.enq_fire_i(enq_fire),
.enq_eval_i(enq_eval),
.enq_tag_o(enq_tag),
.deq_fire_i(deq_fire),
.deq_eval_i(deq_eval),
.deq_tag_o(deq_tag),
.flush_i(1'b0),
.clk(clk),
.rstn(rstn)
);
endmodule

View File

@@ -0,0 +1,124 @@
module MultiPortStreamFIFO #(
parameter int unsigned Depth = 8,
parameter int unsigned DataWidth = 32,
parameter int unsigned EnqWidth = 2,
parameter int unsigned DeqWidth = 2,
parameter int unsigned TakenAll = 0
) (
input wire [EnqWidth-1:0] enq_vld_i,
input wire [EnqWidth-1:0][DataWidth-1:0] enq_payload_i,
output wire [EnqWidth-1:0] enq_rdy_o,
output wire [DeqWidth-1:0] deq_vld_o,
output wire [DeqWidth-1:0][DataWidth-1:0] deq_payload_o,
input wire [DeqWidth-1:0] deq_rdy_i,
input wire flush_i,
input wire clk,
input wire rstn
);
localparam int unsigned PtrWidth = $clog2(Depth);
reg [Depth-1:0] payload_clk_en;
reg [Depth-1:0] vld_dff_d, vld_dff_q;
reg [Depth-1:0][DataWidth-1:0] payload_dff_d, payload_dff_q;
wire [EnqWidth-1:0][PtrWidth-1:0] enq_ptr;
wire [DeqWidth-1:0][PtrWidth-1:0] deq_ptr;
wire [EnqWidth-1:0] enq_rdy;
wire [EnqWidth-1:0] enq_fire;
wire [DeqWidth-1:0] deq_fire;
assign enq_fire = enq_vld_i & enq_rdy_o;
assign deq_fire = deq_vld_o & deq_rdy_i;
always @(*) begin : vld_dff_update_logic
vld_dff_d = vld_dff_q;
for (int i = 0; i < EnqWidth; i++) begin
if (enq_fire[i]) begin
vld_dff_d[enq_ptr[i]] = 1'b1;
end
end
for (int i = 0; i < DeqWidth; i++) begin
if (deq_fire[i]) begin
vld_dff_d[deq_ptr[i]] = 1'b0;
end
end
if (flush_i) begin
vld_dff_d = {Depth{1'b0}};
end
end
always @(*) begin : payload_update_logic
for (int i = 0; i < Depth; i++) begin : payload_init
payload_clk_en[i] = 1'b0;
payload_dff_d[i] = payload_dff_q[i];
end
for (int i = 0; i < EnqWidth; i++) begin : enq_update
if (enq_fire[i] & ~flush_i) begin
payload_clk_en[enq_ptr[i]] = 1'b1;
payload_dff_d[enq_ptr[i]] = enq_payload_i[i];
end
end
end
generate
if (TakenAll) begin : gen_rdy_if_need_taken_all
assign enq_rdy_o = {EnqWidth{&enq_rdy}};
end else begin : gen_normal_rdy
assign enq_rdy_o = enq_rdy;
end
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_rdy_logic
assign enq_rdy[i] = ~vld_dff_q[enq_ptr[i]];
end
for (genvar i = 0; i < DeqWidth; i++) begin : gen_deq_logic
assign deq_vld_o[i] = vld_dff_q[deq_ptr[i]];
assign deq_payload_o[i] = payload_dff_q[deq_ptr[i]];
end
endgenerate
DFFR #(
.Width(Depth)
) u_vld_dff (
.CLK(clk),
.RSTN(rstn),
.DRST({Depth{1'b0}}),
.D(vld_dff_d),
.Q(vld_dff_q)
);
generate
for (genvar i = 0; i < Depth; i++) begin : gen_payload_dff
DFFE #(
.Width(DataWidth)
) u_payload_dff (
.CLK(clk),
.EN (payload_clk_en[i]),
.D (payload_dff_d[i]),
.Q (payload_dff_q[i])
);
end
endgenerate
QueueManager #(
.Depth(Depth),
.EnqWidth(EnqWidth),
.DeqWidth(DeqWidth),
.FlagEnable(0),
.EnqCollapse(1),
.DeqCollapse(0),
.InitFull(0)
) u_QueueManager (
.enq_fire_i(enq_fire),
.enq_eval_i(enq_vld_i),
.enq_tag_o(enq_ptr),
.deq_fire_i(deq_fire),
.deq_eval_i(deq_vld_o),
.deq_tag_o(deq_ptr),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
endmodule

View File

@@ -0,0 +1,206 @@
module QueueManager #(
parameter int unsigned Depth = 8,
parameter int unsigned EnqWidth = 2,
parameter int unsigned DeqWidth = 2,
parameter bit FlagEnable = 0,
parameter bit EnqCollapse = 0,
parameter bit DeqCollapse = 0,
parameter bit InitFull = 0,
localparam int unsigned PtrWidth = $clog2(Depth),
localparam int unsigned CntWidth = $clog2(Depth + 1),
localparam int unsigned TagWidth = PtrWidth + FlagEnable
) (
input wire [EnqWidth-1:0] enq_fire_i,
input wire [EnqWidth-1:0] enq_eval_i,
output wire [EnqWidth-1:0][TagWidth-1:0] enq_tag_o,
input wire [DeqWidth-1:0] deq_fire_i,
input wire [DeqWidth-1:0] deq_eval_i,
output wire [DeqWidth-1:0][TagWidth-1:0] deq_tag_o,
input wire flush_i,
input wire clk,
input wire rstn
);
localparam int unsigned EnqCountWidth = $clog2(EnqWidth + 1);
localparam int unsigned DeqCountWidth = $clog2(DeqWidth + 1);
function automatic [TagWidth-1:0] tagPlusOne;
input [TagWidth-1:0] originalTag;
begin
if (FlagEnable) begin
if (originalTag[PtrWidth-1:0] == Depth - 1) begin
tagPlusOne = {~originalTag[TagWidth-1], {PtrWidth{1'b0}}};
end else begin
tagPlusOne = originalTag + 1'b1;
end
end else begin
if (originalTag[PtrWidth-1:0] == Depth - 1) begin
tagPlusOne = {PtrWidth{1'b0}};
end else begin
tagPlusOne = originalTag + 1'b1;
end
end
end
endfunction
function automatic [TagWidth-1:0] tagPlus;
input [TagWidth-1:0] originalTag;
input [PtrWidth-1:0] delta;
reg [PtrWidth:0] sum;
reg [PtrWidth:0] reverse_sum;
begin
if (2 ** $clog2(Depth) == Depth) begin
tagPlus = originalTag + delta;
end else begin
sum = $unsigned({1'b0, originalTag[PtrWidth-1:0]}) + $unsigned({{1'b0}, delta});
reverse_sum = $signed(sum) - $unsigned(Depth);
if ($signed(reverse_sum) >= 0) begin
if (FlagEnable) begin
tagPlus = {~originalTag[TagWidth-1], reverse_sum[PtrWidth-1:0]};
end else begin
tagPlus = reverse_sum[PtrWidth-1:0];
end
end else begin
if (FlagEnable) begin
tagPlus = {originalTag[TagWidth-1], sum[PtrWidth-1:0]};
end else begin
tagPlus = sum[PtrWidth-1:0];
end
end
end
end
endfunction
wire enq_tag_clk_en;
wire [EnqWidth-1:0] enq_rdy_mask, enq_collapse_rdy_mask;
wire [EnqCountWidth-1:0] enq_cnt;
wire [PtrWidth-1:0] enq_delta;
reg [TagWidth-1:0] enq_tag_d, enq_tag_q;
wire deq_tag_clk_en;
wire [DeqCountWidth-1:0] deq_cnt;
wire [PtrWidth-1:0] deq_delta;
reg [TagWidth-1:0] deq_tag_d, deq_tag_q;
assign enq_tag_clk_en = (|enq_fire_i);
assign deq_tag_clk_en = (|deq_fire_i);
assign enq_delta = {{PtrWidth - EnqCountWidth{1'b0}}, enq_cnt};
assign deq_delta = {{PtrWidth - DeqCountWidth{1'b0}}, deq_cnt};
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_ptr
if (i == 0) begin : gen_first_enq_ptr
assign enq_tag_o[i] = enq_tag_q;
end else begin : gen_next_enq_ptr
assign enq_tag_o[i] = (EnqCollapse & ~enq_eval_i[i-1]) ? enq_tag_o[i-1] : tagPlusOne(
enq_tag_o[i-1]
);
end
end
for (genvar i = 0; i < DeqWidth; i++) begin : gen_deq_ptr
if (i == 0) begin : gen_first_deq_ptr
assign deq_tag_o[i] = deq_tag_q;
end else begin : gen_next_deq_ptr
assign deq_tag_o[i] = (DeqCollapse & ~deq_eval_i[i-1]) ? deq_tag_o[i-1] : tagPlusOne(
deq_tag_o[i-1]
);
end
end
endgenerate
always @(*) begin : enq_tag_update_logic
enq_tag_d = enq_tag_q;
if (enq_tag_clk_en) begin
enq_tag_d = tagPlus(enq_tag_q, enq_delta);
end
if (flush_i) begin
if (InitFull & FlagEnable) begin
enq_tag_d = {~deq_tag_q[TagWidth-1], deq_tag_q[PtrWidth-1:0]};
end else begin
enq_tag_d = deq_tag_q;
end
end
end
always @(*) begin : deq_tag_update_logic
deq_tag_d = deq_tag_q;
if (deq_tag_clk_en) begin
deq_tag_d = tagPlus(deq_tag_q, deq_delta);
end
if (flush_i) begin
deq_tag_d = deq_tag_q;
end
end
CountOne #(
.InputWidth(EnqWidth)
) u_enqCounter (
.bits_i(enq_fire_i),
.cnt_o (enq_cnt)
);
CountOne #(
.InputWidth(DeqWidth)
) u_deqCounter (
.bits_i(deq_fire_i),
.cnt_o (deq_cnt)
);
DFFRE #(
.Width(TagWidth)
) u_enq_tag_dff (
.CLK(clk),
.RSTN(rstn),
.EN(enq_tag_clk_en | flush_i),
.DRST({(InitFull & FlagEnable), {TagWidth - 1{1'b0}}}),
.D(enq_tag_d),
.Q(enq_tag_q)
);
DFFRE #(
.Width(TagWidth)
) u_deq_tag_dff (
.CLK(clk),
.RSTN(rstn),
.EN(deq_tag_clk_en | flush_i),
.DRST({TagWidth{1'b0}}),
.D(deq_tag_d),
.Q(deq_tag_q)
);
`ifndef SYNTHESIS
default disable iff (~rstn);
int unsigned usage = 0;
always @(posedge clk) begin : gen_usage
if (~rstn) begin
usage = 0;
end else begin
if (flush_i) begin
usage = 0;
end else if (enq_tag_clk_en & deq_tag_clk_en) begin
usage = usage + enq_cnt - deq_cnt;
end else if (enq_tag_clk_en) begin
usage = usage + enq_cnt;
end else if (deq_tag_clk_en) begin
usage = usage - deq_cnt;
end
end
end
CHECK_ENQ_WHEN_FULL :
assert property (@(posedge clk) enq_tag_clk_en |-> (Depth - usage >= enq_cnt))
else begin
$fatal("\n Error : Enqueue count[%d] > Availible count[%d]\n", enq_cnt, Depth - usage);
end
CHECK_DEQ_WHEN_EMPTY :
assert property (@(posedge clk) deq_tag_clk_en |-> (usage >= deq_cnt))
else begin
$fatal("\n Error : Dequeue count[%d] > Availible count[%d]\n", deq_cnt, usage);
end
`endif
endmodule

View File

@@ -0,0 +1,52 @@
module StaticPrioritySelector #(
parameter int unsigned Depth = 8,
parameter int unsigned EnqWidth = 2,
parameter int unsigned SelWidth = 2
) (
// Enqueue Port
output wire [EnqWidth-1:0][Depth-1:0] enq_mask_o,
// Select Port
input wire [Depth-1:0] sel_mask_i,
output wire [SelWidth-1:0][Depth-1:0] result_mask_o,
// Status
input wire [Depth-1:0] entry_vld_i
);
wire [EnqWidth-1:0][Depth-1:0] enq_allocated_mask;
wire [EnqWidth-1:0][Depth-1:0] masked_enq_rdy;
wire [SelWidth-1:0][Depth-1:0] selected_mask;
wire [SelWidth-1:0][Depth-1:0] masked_sel_mask;
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_allocated_mask
if (i == 0) begin : gen_initial_one
assign enq_allocated_mask[i] = {Depth{1'b0}};
end else begin : gen_others
assign enq_allocated_mask[i] = enq_allocated_mask[i-1] | enq_mask_o[i-1];
end
assign masked_enq_rdy[i] = ~enq_allocated_mask[i] & ~entry_vld_i;
end
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_mask
assign enq_mask_o[i] = masked_enq_rdy[i] & ~(masked_enq_rdy[i] - 1);
end
endgenerate
generate
for (genvar i = 0; i < SelWidth; i++) begin : gen_masked_sel_mask
if (i == 0) begin : gen_initial_one
assign selected_mask[i] = {Depth{1'b0}};
end else begin : gen_others
assign selected_mask[i] = selected_mask[i-1] | result_mask_o[i-1];
end
assign masked_sel_mask[i] = ~selected_mask[i] & sel_mask_i;
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_sel_result
assign result_mask_o[i] = masked_sel_mask[i] & ~(masked_sel_mask[i] - 1);
end
endgenerate
endmodule

View File

@@ -0,0 +1,39 @@
Name : StdDFF
Module:
- name: DFFUncertainChecker
description: DFF uncertain checker
language: SystemVerilog
rtl:
- dv/DFFUncertainChecker.v
- name: DFF
description: Standard DFF
language: SystemVerilog
rtl:
- hw/DFF.v
dependency:
- DFFUncertainChecker
- name: DFFE
description: Standard DFF with EN port
language: SystemVerilog
rtl:
- hw/DFFE.v
dependency:
- DFFUncertainChecker
- name: DFFR
description: Standard DFF with RST port
language: SystemVerilog
rtl:
- hw/DFFR.v
dependency:
- DFFUncertainChecker
- name: DFFRE
description: Standard DFF with EN and RST port
language: SystemVerilog
rtl:
- hw/DFFRE.v
dependency:
- DFFUncertainChecker

View File

@@ -0,0 +1,17 @@
module DFFUncertainChecker #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire EN,
input reg [Width-1:0] Q
);
`ifndef SYNTHESIS
CHECK_UNCERTAIN :
assert property (@(posedge CLK) EN |=> (|Q !== 1'bx))
else begin
$fatal("\n Error : detected a X value which should never happen!\n");
end
`endif
endmodule

View File

@@ -0,0 +1,25 @@
module DFF #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK) begin : dff
Q <= D;
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (1'b1),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1,28 @@
module DFFE #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire EN,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK) begin : dff
if (EN) begin
Q <= D;
end
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (EN),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1,31 @@
module DFFR #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire RSTN,
input wire [Width-1:0] DRST,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK or negedge RSTN) begin : dff
if (~RSTN) begin
Q <= DRST;
end else begin
Q <= D;
end
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (1'b1),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1,35 @@
module DFFRE #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire RSTN,
input wire EN,
input wire [Width-1:0] DRST,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK or negedge RSTN) begin : dff
if (~RSTN) begin
Q <= DRST;
end else begin
if (EN) begin
Q <= D;
end
end
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (EN),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1 @@
__pycache__

View File

@@ -0,0 +1,132 @@
#!/usr/bin/python3
from distutils.log import error, fatal
from pathlib import Path
from sys import argv
import yaml
class Module:
def __init__(self, root: Path, moduleMeta: dict) -> None:
self.rtlPathList = []
self.simPathList = []
self.dependModuleList = []
if moduleMeta.get("dependency"):
for m in moduleMeta["dependency"]:
self.dependModuleList.append(m)
if moduleMeta.get("rtl"):
for m in moduleMeta["rtl"]:
self.rtlPathList.append(Path(root) / m)
if moduleMeta.get("sim"):
for m in moduleMeta["sim"]:
self.simPathList.append(Path(root) / m)
try:
self.name = moduleMeta["name"]
self.description = moduleMeta["description"]
self.language = moduleMeta["language"]
except yaml.YAMLError as e:
error(e)
class PackageParser:
def __init__(self, manifestPath: str):
with open(manifestPath) as f:
self.packageLocation = Path(manifestPath)
ROOT = self.packageLocation.parent
manifest = yaml.load(f, yaml.CLoader)
self.dependPackageDict = {}
self.ModuleDict = {}
if manifest.get("Dependency"):
for packagePath in manifest["Dependency"]:
filePath = Path(ROOT / packagePath)
package = PackageParser(filePath)
if not self.dependPackageDict.get(package.Name):
self.dependPackageDict[package.Name] = package
for (key, value) in package.ModuleDict.items():
if not self.ModuleDict.get(key):
self.ModuleDict[key] = value
if manifest.get("Module"):
for module in manifest["Module"]:
self.addModule(ROOT, module)
try:
self.Name = manifest["Name"]
self.addModule(ROOT, self.packModule())
except yaml.YAMLError as e:
error(e)
def packModule(self):
packedModule = {}
packedModule['name'] = self.Name
packedModule['language'] = None
packedModule['description'] = "package {}".format(self.Name)
packedModule['dependency'] = []
for module in self.ModuleDict:
packedModule['dependency'].append(module)
return packedModule
def addModule(self, root: Path, moduleMeta: dict) -> None:
self.ModuleDict[moduleMeta["name"]] = Module(root, moduleMeta)
if moduleMeta.get("sim"):
self.ModuleDict[moduleMeta["name"]+'_tb'] = Module(root, moduleMeta)
def genModuleFileList(self, top: str, sim: bool):
if self.ModuleDict.get(top):
module = self.ModuleDict[top]
filelist = []
for dependModule in module.dependModuleList:
for file in self.genModuleFileList(dependModule, False):
if file not in filelist:
filelist.append(file)
for file in module.rtlPathList:
absPath = str(file.absolute())
if absPath not in filelist:
filelist.append((absPath,module.language))
if sim:
for file in module.simPathList:
absPath = str(file.absolute())
if absPath not in filelist:
filelist.append((absPath,module.language))
return filelist
else:
fatal("Module {} doesn't exist".format(top))
def genPackageFileList(self, sim: bool):
filelist = []
for module in self.ModuleDict:
for file in self.genModuleFileList(module, sim):
if file not in filelist :
filelist.append(file)
return filelist
def genVcsFileList(self, sim: bool):
filelist = self.genPackageFileList(sim)
vcsfilelist = []
for file in filelist:
vcsfilelist.append(file[0])
return vcsfilelist
def genEDAlizeFile(self,top: str, sim: bool):
edalizeFileList = []
filelist = self.genModuleFileList(top,sim)
for (filePath,language) in filelist:
if language == "SystemVerilog" :
edalizeFileList.append(
{'name' : filePath, 'file_type' : 'systemVerilogSource'}
)
elif language == "Verilog" :
edalizeFileList.append(
{'name' : filePath, 'file_type' : 'verilogSource'}
)
elif language == "Vhdl":
edalizeFileList.append(
{'name' : filePath, 'file_type' : 'vhdlSource'}
)
return edalizeFileList
if __name__ == "__main__":
t = PackageParser(argv[1])
for file in t.genVcsFileList(False):
print(file)

View File

@@ -0,0 +1,2 @@
# pico
Pico is a hardware dependency manangement tool which integrate Edalize to support different cad flow

View File

@@ -0,0 +1,8 @@
vcs :
vcs_options : [-full64,-sverilog,+v2k,-debug_access+all,-kdb]
run_options : []
spyglass:
methodology : GuideWare/latest/block/rtl_handoff
goals : [ 'lint/lint_rtl' ]
spyglass_parameters : []
rule_parameters : []

View File

@@ -0,0 +1,127 @@
#!/usr/bin/python3
import argparse
from distutils.log import fatal
from genericpath import getmtime
import os
from pathlib import Path
from sys import argv
import yaml
from time import ctime, gmtime, strftime, time
from edalize import *
import edalize
from PackageParser import PackageParser
SIM_TOOL = [
'vcs', 'verilator'
]
TOOLS = [tool for tool in edalize.walk_tool_packages()]
def getTime():
return strftime("%m%d_%H_%M", gmtime())
class PicoArgsParser:
def __init__(self, argv) -> None:
argParser = argparse.ArgumentParser(usage='Pico.py [manifest] -top [topmodule] -tool [vcs/verilator/veriblelint .etc] -configure -build -run',prefix_chars="-+")
argParser.add_argument('manifest', type=str, help="Project manifest")
argParser.add_argument(
'+args', nargs='?', action='append', help="Compile arguments")
argParser.add_argument(
'-tool', type=str, choices=TOOLS, required=True, help="EDA tool")
argParser.add_argument(
'-top', type=str, required=True, help="Top module")
argParser.add_argument('-trace', action='store_true',
default=False, help="Enable Waveform")
argParser.add_argument(
'+define', nargs='?', action='append', type=str, help="Verilog defination")
argParser.add_argument('-workdir', type=str, help="Work space")
argParser.add_argument('-build', action='store_true',
default=False, help="Build Project")
argParser.add_argument('-run', action='store_true',
default=False, help="Run Project")
argParser.add_argument('+runtime', action='append', help="runtime args")
argParser.add_argument('-cov','-coverage', dest='coverage', action='store_true',help='Enable coverage')
self.config = argParser.parse_args(argv)
self.tool = self.config.tool
self.toplevel = self.config.top
self.build = self.config.build
self.run = self.config.run
self.tool_options = self.buildToolOptions()
self.parameters = self.buildDefination()
self.file = self.buildFlist()
self.edam = {
'files': self.file,
'name': self.toplevel,
'parameters': self.parameters,
'tool_options': self.tool_options,
'toplevel': self.toplevel
}
self.workSpace = self.getWorkSpace()
def getWorkSpace(self):
if self.config.workdir:
work_root = self.config.workdir
else:
work_root = self.tool + '_' + self.toplevel + '_' + getTime()
return work_root
def buildFlist(self):
manifestParser = PackageParser(self.config.manifest)
simulationEnable = self.tool in SIM_TOOL
return manifestParser.genEDAlizeFile(self.toplevel, simulationEnable)
def buildToolOptions(self):
config = self.config
tool_options = yaml.load(
open(Path(__file__).parent / "defaultToolOption.yaml"), yaml.CLoader)
if config.args:
if config.tool == 'vcs':
tool_options['vcs']['vcs_options'] += config.args
if config.runtime:
if config.tool == 'vcs':
tool_options['vcs']['run_options'] += config.runtime
if config.coverage:
if config.tool == 'vcs':
tool_options['vcs']['vcs_options'] += ['-cm line+cond+tgl+fsm+branch+assert']
tool_options['vcs']['run_options'] += ['-cm line+cond+tgl+fsm+branch+assert']
return tool_options
def buildDefination(self):
parameters = {}
config = self.config
if config.trace:
parameters["DUMPON"] = {
'datatype': 'bool',
'default': 1,
'paramtype': 'vlogdefine'
}
if config.define:
for define in config.define:
for item in define.split(','):
parameters[item] = {
'datatype': 'bool',
'default': 1,
'paramtype': 'vlogdefine'
}
return parameters
if __name__ == "__main__":
config = PicoArgsParser(argv[1:])
work_root = config.workSpace
backend = get_edatool(config.tool)(edam=config.edam, work_root=work_root)
if not os.path.exists(work_root):
os.makedirs(work_root)
if config.build:
backend.configure()
backend.build()
if config.run:
backend.run()

148
rtl/util/freelist.sv Executable file
View File

@@ -0,0 +1,148 @@
`ifndef __FREELIST_SV__
`define __FREELIST_SV__
module freelist
#(
parameter int unsigned ENTRY_COUNT = 4,
localparam int unsigned ENTRY_TAG_WIDTH = $clog2(ENTRY_COUNT),
localparam int unsigned IS_LOG2 = (2 ** ENTRY_TAG_WIDTH) == ENTRY_COUNT
)
(
// Enqueue
input logic enq_vld_i,
input logic[ENTRY_TAG_WIDTH-1:0] enq_tag_i,
// Dequeue
input logic deq_vld_i,
output logic[ENTRY_TAG_WIDTH-1:0] deq_tag_o,
output logic deq_rdy_o,
// Flush
input logic flush_i,
input clk,
input rst
);
logic [ENTRY_COUNT-1:0][ENTRY_TAG_WIDTH-1:0] ram_r,ram_n;
logic [ENTRY_COUNT-1:0] ram_clk_en;
logic [ENTRY_TAG_WIDTH-1:0] head_r,head_n;
logic head_flag_r,head_flag_n;
logic head_clk_en;
logic [ENTRY_TAG_WIDTH-1:0] tail_r,tail_n;
logic tail_flag_r,tail_flag_n;
logic tail_clk_en;
logic enq_fire;
logic deq_fire;
logic full,empty;
logic flag_equal,tag_equal;
assign enq_fire = enq_vld_i;
assign deq_fire = deq_rdy_o & deq_vld_i;
assign flag_equal = tail_flag_r == head_flag_r;
assign tag_equal = tail_r == head_r;
assign full = ~flag_equal & tag_equal;
assign empty = flag_equal & tag_equal;
// Output
assign deq_tag_o = ram_r[head_r];
always_comb begin : ram_update
ram_n = ram_r;
ram_n[tail_r] = enq_tag_i;
if(flush_i) begin
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
ram_n[i] = i[ENTRY_TAG_WIDTH-1:0];
end
end
end
always_comb begin : ram_clk_en_gen
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
ram_clk_en[i] = (enq_fire & (i == tail_r)) | flush_i;
end
end
always_comb begin : head_update
if(IS_LOG2) begin
{head_flag_n,head_n} = {head_flag_r,head_r} + 1'b1;
end else begin
if(head_r == ENTRY_COUNT-1) begin
head_n = {ENTRY_COUNT{1'b0}};
head_flag_n = ~head_flag_r;
end else begin
head_n = head_r + 1'b1;
head_flag_n = head_flag_r;
end
end
if(flush_i) begin
{head_flag_n,head_n} = {head_flag_r,head_r};
end
end
assign tail_clk_en = enq_fire | flush_i;
assign deq_rdy_o = ~empty;
always_comb begin : tail_update
if(IS_LOG2) begin
{tail_flag_n,tail_n} = {tail_flag_r,tail_r} + 1'b1;
end else begin
if(tail_r == ENTRY_COUNT-1) begin
tail_n = {ENTRY_TAG_WIDTH{1'b0}};
tail_flag_n = ~tail_flag_r;
end else begin
tail_n = tail_r + 1'b1;
tail_flag_n = tail_flag_r;
end
end
if(flush_i) begin
{tail_flag_n,tail_n} = {~head_flag_r,head_r};
end
end
assign head_clk_en = deq_fire | flush_i;
always_ff@(posedge clk) begin : head_dff
if(rst) begin
{head_flag_r,head_r} <= {(ENTRY_TAG_WIDTH+1){1'b0}};
end else begin
if(head_clk_en) begin
{head_flag_r,head_r} <= {head_flag_n,head_n};
end
end
end
always_ff@(posedge clk) begin : tail_dff
if(rst) begin
{tail_flag_r,tail_r} <= {1'b1,{(ENTRY_TAG_WIDTH){1'b0}}};
end else begin
if(tail_clk_en) begin
{tail_flag_r,tail_r} <= {tail_flag_n,tail_n};
end
end
end
always_ff@(posedge clk) begin : ram_dff
if(rst) begin
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
ram_r[i] <= i[ENTRY_TAG_WIDTH-1:0];
end
end else begin
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
if(ram_clk_en[i]) begin
ram_r[i] <= ram_n[i];
end
end
end
end
endmodule : freelist
`endif

View File

@@ -0,0 +1,67 @@
`ifndef __INORDER_ROUTER_SV__
`define __INORDER_ROUTER_SV__
module inorder_router
#(
parameter int unsigned SRC_COUNT = 4,
parameter int unsigned DES_COUNT = 4
) (
input logic[SRC_COUNT-1:0] src_vld_i,
input logic[SRC_COUNT-1:0][DES_COUNT-1:0] src_des_en_i,
output logic[SRC_COUNT-1:0] success_o,
output logic[DES_COUNT-1:0][SRC_COUNT-1:0] src_des_sel_o
);
logic[SRC_COUNT-1:0] success;
logic[SRC_COUNT-1:0][DES_COUNT-1:0] des_sel_mask;
logic[SRC_COUNT-1:0][DES_COUNT-1:0] des_disable_mask;
logic[SRC_COUNT-1:0][DES_COUNT-1:0] des_rdy_mask;
generate
for(genvar src = 0 ; src < SRC_COUNT; src++) begin : gen_des_disable_mask
if(src == 0) begin
assign des_disable_mask[src] = {DES_COUNT{1'b0}};
end else begin
assign des_disable_mask[src] = des_disable_mask[src-1] | des_sel_mask[src-1];
end
end
endgenerate
generate
for(genvar src = 0 ; src < SRC_COUNT ; src++) begin : gen_des_rdy_mask
if(src == 0) begin
assign des_rdy_mask[src] = {DES_COUNT{src_vld_i[src]}} & src_des_en_i[src];
end else begin
assign des_rdy_mask[src] = {DES_COUNT{src_vld_i[src]}} & src_des_en_i[src] & ~des_disable_mask[src] & {DES_COUNT{success[src-1]}};
end
end
endgenerate
generate
for(genvar src = 0 ; src < SRC_COUNT ; src++) begin : gen_success_vec
assign success[src] = |des_sel_mask[src];
end
endgenerate
always_comb begin : output_logic
success_o = success;
for(int src = 0 ; src < SRC_COUNT; src++) begin
for(int des = 0 ; des < DES_COUNT; des++) begin
src_des_sel_o[des][src] = des_sel_mask[src][des];
end
end
end
generate
for(genvar src = 0 ; src < SRC_COUNT ; src++) begin
one_hot_priority_encoder
#(
.SEL_WIDTH(DES_COUNT)
) u_routing_encoder (
.sel_i(des_rdy_mask[src]),
.sel_o(des_sel_mask[src])
);
end
endgenerate
endmodule
`endif

View File

@@ -0,0 +1,15 @@
module left_circular_rotate #(
parameter N_INPUT = 2,
localparam int unsigned N_INPUT_WIDTH = N_INPUT > 1 ? $clog2(N_INPUT) : 1
) (
input logic [N_INPUT-1:0] ori_vector_i,
input logic [N_INPUT_WIDTH-1:0] req_left_rotate_num_i,
output logic [N_INPUT-1:0] roteted_vector_o
);
logic [N_INPUT*2-1:0] ori_vector_mid;
assign ori_vector_mid = {ori_vector_i, ori_vector_i} << req_left_rotate_num_i;
assign roteted_vector_o = ori_vector_mid[N_INPUT*2-1-:N_INPUT];
endmodule

91
rtl/util/mp_fifo.sv Executable file
View File

@@ -0,0 +1,91 @@
`ifndef __MP_FIFO_SV__
`define __MP_FIFO_SV__
module mp_fifo
#(
parameter type payload_t = logic[3:0],
parameter int unsigned ENQUEUE_WIDTH = 4,
parameter int unsigned DEQUEUE_WIDTH = 4,
parameter int unsigned DEPTH = 16,
parameter int unsigned MUST_TAKEN_ALL = 1
)
(
// Enqueue
input logic[ENQUEUE_WIDTH-1:0] enqueue_vld_i,
input payload_t[ENQUEUE_WIDTH-1:0] enqueue_payload_i,
output logic[ENQUEUE_WIDTH-1:0] enqueue_rdy_o,
// Dequeue
output logic[DEQUEUE_WIDTH-1:0] dequeue_vld_o,
output payload_t[DEQUEUE_WIDTH-1:0] dequeue_payload_o,
input logic[DEQUEUE_WIDTH-1:0] dequeue_rdy_i,
input logic flush_i,
input clk,
input rst
);
localparam int unsigned ENTRY_PTR_WIDTH = $clog2(DEPTH);
localparam int unsigned ENTRY_CNT_WIDTH = $clog2(DEPTH+1);
logic[ENQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] enq_ptr;
logic[DEQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] deq_ptr;
logic[ENTRY_CNT_WIDTH-1:0] avail_cnt;
payload_t[DEPTH-1:0] payload_dff;
logic[ENQUEUE_WIDTH-1:0] enq_fire;
logic[DEQUEUE_WIDTH-1:0] deq_fire;
assign enq_fire = enqueue_vld_i & enqueue_rdy_o;
assign deq_fire = dequeue_vld_o & dequeue_rdy_i;
generate
for(genvar i = 0 ; i < DEQUEUE_WIDTH; i++) begin
assign dequeue_payload_o[i] = payload_dff[deq_ptr[i]];
assign dequeue_vld_o[i] = (DEPTH-avail_cnt) > i;
end
endgenerate
generate
if(MUST_TAKEN_ALL) begin
assign enqueue_rdy_o = {ENQUEUE_WIDTH{avail_cnt >= ENQUEUE_WIDTH}};
end else begin
for(genvar i = 0; i < ENQUEUE_WIDTH; i++) begin
assign enqueue_rdy_o[i] = avail_cnt > i;
end
end
endgenerate
always_ff@(posedge clk) begin : payload_dff_update
for(int i = 0; i < ENQUEUE_WIDTH; i++) begin
if(enq_fire[i]) begin
payload_dff[enq_ptr[i]] <= enqueue_payload_i[i];
end
end
end
usage_manager #(
.ENTRY_COUNT(DEPTH),
.ENQ_WIDTH(ENQUEUE_WIDTH),
.DEQ_WIDTH(DEQUEUE_WIDTH),
.FLAG_EN(0),
.INIT_IS_FULL(0),
.COMB_DEQ_EN(0),
.COMB_ENQ_EN(1)
) u_usage_manager (
.enq_fire_i(enq_fire),
.deq_fire_i(deq_fire),
.head_o(deq_ptr),
.tail_o(enq_ptr),
.avail_cnt_o(avail_cnt),
.flush_i(flush_i),
.clk(clk),
.rst(rst)
);
endmodule : mp_fifo
`endif

94
rtl/util/mp_fifo_ptr_output.sv Executable file
View File

@@ -0,0 +1,94 @@
module mp_fifo_ptr_output
#(
parameter type payload_t = logic[3:0],
parameter int unsigned ENQUEUE_WIDTH = 4,
parameter int unsigned DEQUEUE_WIDTH = 4,
parameter int unsigned DEPTH = 16,
parameter int unsigned MUST_TAKEN_ALL = 1,
localparam int unsigned ENTRY_PTR_WIDTH = $clog2(DEPTH),
localparam int unsigned ENTRY_CNT_WIDTH = $clog2(DEPTH+1)
)
(
// Enqueue
input logic[ENQUEUE_WIDTH-1:0] enqueue_vld_i,
input payload_t[ENQUEUE_WIDTH-1:0] enqueue_payload_i,
output logic[ENQUEUE_WIDTH-1:0] enqueue_rdy_o,
// Dequeue
output logic[DEQUEUE_WIDTH-1:0] dequeue_vld_o,
output payload_t[DEQUEUE_WIDTH-1:0] dequeue_payload_o,
input logic[DEQUEUE_WIDTH-1:0] dequeue_rdy_i,
// ptr output
output logic[ENQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] enq_ptr_o,
output logic[DEQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] deq_ptr_o,
input logic flush_i,
input clk,
input rst
);
logic[ENQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] enq_ptr;
logic[DEQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] deq_ptr;
logic[ENTRY_CNT_WIDTH-1:0] avail_cnt;
payload_t[DEPTH-1:0] payload_dff;
logic[ENQUEUE_WIDTH-1:0] enq_fire;
logic[DEQUEUE_WIDTH-1:0] deq_fire;
assign enq_ptr_o = enq_ptr;
assign deq_ptr_o = deq_ptr;
assign enq_fire = enqueue_vld_i & enqueue_rdy_o;
assign deq_fire = dequeue_vld_o & dequeue_rdy_i;
generate
for(genvar i = 0 ; i < DEQUEUE_WIDTH; i++) begin
assign dequeue_payload_o[i] = payload_dff[deq_ptr[i]];
assign dequeue_vld_o[i] = (DEPTH-avail_cnt) > i;
end
endgenerate
generate
if(MUST_TAKEN_ALL) begin
assign enqueue_rdy_o = {ENQUEUE_WIDTH{avail_cnt >= ENQUEUE_WIDTH}};
end else begin
for(genvar i = 0; i < ENQUEUE_WIDTH; i++) begin
assign enqueue_rdy_o[i] = avail_cnt > i;
end
end
endgenerate
always_ff@(posedge clk) begin : payload_dff_update
for(int i = 0; i < ENQUEUE_WIDTH; i++) begin
if(enq_fire[i]) begin
payload_dff[enq_ptr[i]] <= enqueue_payload_i[i];
end
end
end
usage_manager #(
.ENTRY_COUNT(DEPTH),
.ENQ_WIDTH(ENQUEUE_WIDTH),
.DEQ_WIDTH(DEQUEUE_WIDTH),
.FLAG_EN(0),
.INIT_IS_FULL(0),
.COMB_DEQ_EN(0),
.COMB_ENQ_EN(1)
) u_usage_manager (
.enq_fire_i(enq_fire),
.deq_fire_i(deq_fire),
.head_o(deq_ptr),
.tail_o(enq_ptr),
.avail_cnt_o(avail_cnt),
.flush_i(flush_i),
.clk(clk),
.rst(rst)
);
endmodule : mp_fifo_ptr_output

134
rtl/util/mp_freelist.sv Executable file
View File

@@ -0,0 +1,134 @@
`ifndef __MP_FREELIST_SV__
`define __MP_FREELIST_SV__
module mp_freelist #(
parameter int unsigned ENTRY_COUNT = 12,
parameter int unsigned ALLOC_WIDTH = 4,
parameter int unsigned DEALLOC_WIDTH = 4,
parameter bit MUST_TAKEN_ALL = 1,
localparam int unsigned TAG_WIDTH = $clog2(ENTRY_COUNT)
) (
// Enqueue
input logic [ALLOC_WIDTH-1:0] alloc_vld_i,
output logic [ALLOC_WIDTH-1:0][TAG_WIDTH-1:0] alloc_tag_o,
output logic [ALLOC_WIDTH-1:0] alloc_rdy_o,
// Dequeue
input logic [DEALLOC_WIDTH-1:0] dealloc_vld_i,
input logic [DEALLOC_WIDTH-1:0][TAG_WIDTH-1:0] dealloc_tag_i,
input logic flush_i,
input clk,
input rst
);
localparam int unsigned AVAIL_CNT_WIDTH = $clog2(ENTRY_COUNT + 1);
// Clk gate
logic [ENTRY_COUNT-1:0] ram_clk_en;
// Status
logic [DEALLOC_WIDTH-1:0][TAG_WIDTH-1:0] head;
logic [ALLOC_WIDTH-1:0][TAG_WIDTH-1:0] tail;
logic [AVAIL_CNT_WIDTH-1:0] usage;
logic [ENTRY_COUNT-1:0][TAG_WIDTH-1:0] ram_d, ram_q;
// Allocate
logic [ALLOC_WIDTH-1:0] alloc_fire;
logic [ALLOC_WIDTH-1:0][TAG_WIDTH-1:0] alloc_entry_ptr;
// Deallocate
logic [DEALLOC_WIDTH-1:0] dealloc_fire;
logic [DEALLOC_WIDTH-1:0][TAG_WIDTH-1:0] dealloc_entry_ptr;
always_comb begin : gen_alloc_rdy
if (MUST_TAKEN_ALL) begin
for (int i = 0; i < ALLOC_WIDTH; i++) begin
alloc_rdy_o[i] = (ENTRY_COUNT - usage) >= ALLOC_WIDTH;
end
end else begin
for (int i = 0; i < ALLOC_WIDTH; i++) begin
alloc_rdy_o[i] = (ENTRY_COUNT - usage) > i;
end
end
end
generate
for (genvar i = 0; i < ALLOC_WIDTH; i++) begin : gen_alloc_tag
assign alloc_tag_o[i] = ram_q[alloc_entry_ptr[i]];
end
endgenerate
assign alloc_fire = alloc_vld_i & alloc_rdy_o;
assign alloc_entry_ptr = head;
assign dealloc_fire = dealloc_vld_i;
assign dealloc_entry_ptr = tail;
always_comb begin : gen_ram_clk_en
ram_clk_en = {ENTRY_COUNT{flush_i}};
for (int i = 0; i < DEALLOC_WIDTH; i++) begin
if(dealloc_fire[i]) begin
ram_clk_en[dealloc_entry_ptr[i]] = 1'b1;
end
end
end
always_comb begin : ram_update
ram_d = ram_q;
for (int i = 0; i < DEALLOC_WIDTH; i++) begin
ram_d[dealloc_entry_ptr[i]] = dealloc_tag_i[i];
end
if (flush_i) begin
for (int i = 0; i < ENTRY_COUNT; i++) begin
ram_d[i] = i[TAG_WIDTH-1:0];
end
end
end
always_ff @(posedge clk) begin : ram_dff
if (rst) begin
for (int i = 0; i < ENTRY_COUNT; i++) begin
ram_q[i] <= i[TAG_WIDTH-1:0];
end
end else begin
for (int i = 0; i < ENTRY_COUNT; i++) begin
if (ram_clk_en[i]) begin
ram_q[i] <= ram_d[i];
end
end
end
end
usage_manager #(
.ENTRY_COUNT(ENTRY_COUNT),
.ENQ_WIDTH(DEALLOC_WIDTH),
.DEQ_WIDTH(ALLOC_WIDTH),
.FLAG_EN(0),
.INIT_IS_FULL(1),
.COMB_DEQ_EN(1),
.COMB_ENQ_EN(1)
) u_usage_manager (
.enq_fire_i(dealloc_fire),
.deq_fire_i(alloc_fire),
.head_o(head),
.tail_o(tail),
.avail_cnt_o(usage),
.flush_i(flush_i),
.clk(clk),
.rst(rst)
);
endmodule : mp_freelist
`endif

29
rtl/util/oh2idx.sv Normal file
View File

@@ -0,0 +1,29 @@
module oh2idx
#(
parameter int unsigned N_INPUT = 2,
localparam int unsigned N_INPUT_WIDTH = N_INPUT > 1 ? $clog2(N_INPUT) : 1
)
(
input [N_INPUT-1:0] oh_i,
output [N_INPUT_WIDTH-1:0] idx_o
);
genvar i, j;
logic [N_INPUT_WIDTH-1:0][N_INPUT-1:0] mask;
generate
for(i = 0; i < N_INPUT_WIDTH; i++) begin: gen_mask_i
for(j = 0; j < N_INPUT; j++) begin: gen_mask_j
assign mask[i][j] = (j/(2**i)) % 2;
end
end
endgenerate
generate
for(i = 0; i < N_INPUT_WIDTH; i++) begin: gen_idx_o
assign idx_o[i] = |(oh_i & mask[i]);
end
endgenerate
endmodule

50
rtl/util/one_counter.sv Executable file
View File

@@ -0,0 +1,50 @@
`ifndef __ONE_COUNTER_SV__
`define __ONE_COUNTER_SV__
module one_counter
#(
parameter int unsigned DATA_WIDTH = 8,
localparam int unsigned CNT_WIDTH = $clog2(DATA_WIDTH) + 1
)
(
input logic[DATA_WIDTH-1:0] data_i,
output logic[CNT_WIDTH-1:0] cnt_o
);
localparam int unsigned PADDED_DATA_WIDTH = 1 << $clog2(DATA_WIDTH);
logic [PADDED_DATA_WIDTH-1:0] padded_data;
always_comb begin
padded_data = {PADDED_DATA_WIDTH{1'b0}};
padded_data[DATA_WIDTH-1:0] = data_i;
end
if(DATA_WIDTH == 1) begin
assign cnt_o = data_i;
end else begin
logic [CNT_WIDTH-2:0] res_left,res_right;
assign cnt_o = res_left + res_right;
one_counter #(
.DATA_WIDTH(PADDED_DATA_WIDTH/2)
) one_counter_left_u (
.data_i(padded_data[PADDED_DATA_WIDTH-1:PADDED_DATA_WIDTH/2]),
.cnt_o(res_left)
);
one_counter #(
.DATA_WIDTH(PADDED_DATA_WIDTH/2)
) one_counter_right_u (
.data_i(padded_data[PADDED_DATA_WIDTH/2-1:0]),
.cnt_o(res_right)
);
end
endmodule : one_counter
`endif

View File

@@ -0,0 +1,28 @@
`ifndef __ONE_HOT_PRIORITY_ENCODER_SV__
`define __ONE_HOT_PRIORITY_ENCODER_SV__
module one_hot_priority_encoder
#(
parameter int unsigned SEL_WIDTH = 8
)
(
input logic[SEL_WIDTH-1:0] sel_i,
output logic[SEL_WIDTH-1:0] sel_o
);
localparam int unsigned SEL_ID_WIDHT = $clog2(SEL_WIDTH);
logic [SEL_WIDTH-1:0] sel_mask;
assign sel_mask = ((~sel_i + 1'b1) & sel_i);
assign sel_o = sel_mask;
endmodule : one_hot_priority_encoder
`endif

128
rtl/util/one_hot_rr_arb.sv Executable file
View File

@@ -0,0 +1,128 @@
module one_hot_rr_arb #(
parameter N_INPUT = 2,
localparam int unsigned N_INPUT_WIDTH = N_INPUT > 1 ? $clog2(N_INPUT) : 1,
localparam int unsigned IS_LOG2 = (2 ** N_INPUT_WIDTH) == N_INPUT,
parameter TIMEOUT_UPDATE_EN = 0,
parameter TIMEOUT_UPDATE_CYCLE = 10
) (
input logic [N_INPUT-1:0] req_i,
input logic update_i,
output logic [N_INPUT-1:0] grt_o,
output logic [N_INPUT_WIDTH-1:0] grt_idx_o,
input logic rstn, clk
);
logic [$clog2(TIMEOUT_UPDATE_CYCLE)-1:0] timeout_counter_q, timeout_counter_d;
logic timeout_counter_add, timeout_counter_clr;
logic timeout_counter_en;
logic timeout_en;
generate
if(N_INPUT == 1) begin: gen_one_hot_rr_arb_one_input
assign grt_o = req_i;
assign grt_idx_o = 0;
end else begin: gen_one_hot_rr_arb_common_input
logic req_vld;
logic [N_INPUT*2-1:0] reversed_dereordered_selected_req_pre_shift, reversed_dereordered_selected_req_shift;
logic [N_INPUT-1:0] reodered_req, reordered_selected_req;
logic [N_INPUT-1:0] dereordered_selected_req;
logic [N_INPUT-1:0] reversed_reordered_selected_req, reversed_dereordered_selected_req;
logic [N_INPUT_WIDTH-1:0] round_ptr_q, round_ptr_d;
logic [N_INPUT_WIDTH-1:0] round_ptr_q_comp;
logic [N_INPUT_WIDTH-1:0] oh_to_idx;
logic [N_INPUT_WIDTH-1:0] selected_req_idx;
assign req_vld = update_i | timeout_en;
always_ff @(posedge clk or negedge rstn) begin
if (~rstn) begin
round_ptr_q <= '0;
end else begin
if (req_vld) begin
round_ptr_q <= round_ptr_d;
end
end
end
assign round_ptr_q_comp = N_INPUT - round_ptr_q;
//7 6 5 4 3 2 1 0 // req_i
//2 1 0 7 6 5 4 3 // reodered_req
//7 6 5 4 3 2 1 0 // dereordered_selected_req
left_circular_rotate
#(
.N_INPUT(N_INPUT )
)
left_circular_rotate_reodered_req_u (
.ori_vector_i (req_i ),
.req_left_rotate_num_i (round_ptr_q ),
.roteted_vector_o ( reodered_req)
);
one_hot_priority_encoder
#(
.SEL_WIDTH (N_INPUT)
)
biased_one_hot_priority_encoder_u
(
.sel_i (reodered_req ),
.sel_o (reordered_selected_req )
);
left_circular_rotate
#(
.N_INPUT(N_INPUT )
)
left_circular_rotate_dereordered_selected_req_u (
.ori_vector_i (reordered_selected_req ),
.req_left_rotate_num_i (round_ptr_q_comp ),
.roteted_vector_o ( dereordered_selected_req)
);
oh2idx
#(
.N_INPUT(N_INPUT )
)
oh2idx_u (
.oh_i (dereordered_selected_req ),
.idx_o (oh_to_idx)
);
assign selected_req_idx = oh_to_idx[N_INPUT_WIDTH-1:0];
assign round_ptr_d = (selected_req_idx == '0) ? N_INPUT-1 :
(selected_req_idx == (N_INPUT-1)) ? '0 :
(N_INPUT-1) - selected_req_idx;
assign grt_o = dereordered_selected_req;
assign grt_idx_o = selected_req_idx;
// timeout update
if(TIMEOUT_UPDATE_EN) begin
assign timeout_counter_add = (|req_i) & ~req_vld;
assign timeout_counter_clr = req_vld;
assign timeout_counter_d = timeout_counter_clr ? '0 : timeout_counter_q + 1;
assign timeout_counter_en = timeout_counter_add | (timeout_counter_clr & (timeout_counter_q != '0));
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
timeout_counter_q <= '0;
end else begin
if (timeout_counter_en) begin
timeout_counter_q <= timeout_counter_d;
end
end
end
assign timeout_en = (timeout_counter_q == TIMEOUT_UPDATE_CYCLE);
end else begin
assign timeout_en = '0;
end
end
endgenerate
endmodule

37
rtl/util/onehot_mux.sv Executable file
View File

@@ -0,0 +1,37 @@
`ifndef __ONEHOT_MUX_SV__
`define __ONEHOT_MUX_SV__
module onehot_mux
#(
parameter int unsigned SOURCE_COUNT = 2,
parameter int unsigned DATA_WIDTH = 1
)
(
input logic[SOURCE_COUNT-1:0] sel_i,
input logic[SOURCE_COUNT-1:0][DATA_WIDTH-1:0] data_i,
output logic[DATA_WIDTH-1:0] data_o
);
logic[DATA_WIDTH-1:0][SOURCE_COUNT-1:0] trans_data;
logic[DATA_WIDTH-1:0][SOURCE_COUNT-1:0] select_mat;
generate
for(genvar i = 0 ; i < DATA_WIDTH; i++) begin
for(genvar j = 0 ; j < SOURCE_COUNT; j++) begin
assign trans_data[i][j] = data_i[j][i];
end
end
endgenerate
generate
for(genvar i = 0; i < DATA_WIDTH; i++) begin
assign select_mat[i] = trans_data[i] & sel_i;
assign data_o[i] = |select_mat[i];
end
endgenerate
endmodule
`endif

121
rtl/util/plru.sv Normal file
View File

@@ -0,0 +1,121 @@
`ifndef __PLRU_SV__
`define __PLRU_SV__
module plru
#(
parameter int unsigned N_WAYS = 2,
parameter int unsigned N_SETS = 2
)
(
input logic touch_valid_i,
input logic [$clog2(N_SETS)-1:0] touch_addr_i,
input logic [$clog2(N_WAYS)-1:0] touch_way_i,
output logic [$clog2(N_WAYS)-1:0] alloc_way_o,
input logic clk,
input logic rst
);
logic [N_SETS-1:0][N_WAYS-2:0] plru_regs;
generate
if(N_WAYS == 2) begin
assign alloc_way_o = plru_regs[touch_addr_i][0];
end
else if (N_WAYS == 4) begin
assign alloc_way_o = plru_regs[touch_addr_i][0] ?
{plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][2]} :
{plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][1]};
end
else if (N_WAYS == 8) begin
always_comb begin
if (plru_regs[touch_addr_i][0]) begin
if (plru_regs[touch_addr_i][2]) begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][2], plru_regs[touch_addr_i][6]};
end
else begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][2], plru_regs[touch_addr_i][5]};
end
end
else begin
if (plru_regs[touch_addr_i][1]) begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][1], plru_regs[touch_addr_i][4]};
end
else begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][1], plru_regs[touch_addr_i][3]};
end
end
end
end
endgenerate
generate
if(N_WAYS == 2) begin
always_ff @(posedge clk) begin
if (rst) begin
plru_regs <= 0;
end
else if (touch_valid_i) begin
if (touch_way_i == alloc_way_o) begin
plru_regs[touch_addr_i] <= ~plru_regs[touch_addr_i];
end
end
end
end
else if (N_WAYS == 4) begin
always_ff @(posedge clk) begin
if (rst) begin
plru_regs <= 0;
end
else if (touch_valid_i & (alloc_way_o == touch_way_i)) begin
if (plru_regs[touch_addr_i][0]) begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
end
else begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][1] <= ~plru_regs[touch_addr_i][1];
end
end
end
end
else if (N_WAYS == 8) begin
always_ff @(posedge clk) begin
if (rst) begin
plru_regs <= 0;
end
else if (touch_valid_i & (alloc_way_o == touch_way_i)) begin
if (plru_regs[touch_addr_i][0]) begin
if (plru_regs[touch_addr_i][2]) begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][6] <= ~plru_regs[touch_addr_i][6];
end
else begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][5] <= ~plru_regs[touch_addr_i][5];
end
end
else begin
if (plru_regs[touch_addr_i][1]) begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][4] <= ~plru_regs[touch_addr_i][4];
end
else begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][3] <= ~plru_regs[touch_addr_i][3];
end
end
end
end
end
endgenerate
endmodule
`endif

43
rtl/util/priority_encoder.sv Executable file
View File

@@ -0,0 +1,43 @@
`ifndef __PRIORITY_ENCODER_SV__
`define __PRIORITY_ENCODER_SV__
module priority_encoder
#(
parameter int unsigned SEL_WIDTH = 8,
localparam int unsigned SEL_ID_WIDHT = SEL_WIDTH > 1 ? $clog2(SEL_WIDTH) : 1
)
(
input logic[SEL_WIDTH-1:0] sel_i,
output logic id_vld_o,
output logic[SEL_ID_WIDHT-1:0] id_o
);
if(SEL_WIDTH == 1) begin
assign id_vld_o = sel_i;
assign id_o = 1'b0;
end
else begin
logic [SEL_WIDTH-1:0] sel_mask;
logic [SEL_ID_WIDHT+1-1:0] sel_result;
assign sel_mask = ((~sel_i + 1'b1) & sel_i) - 1'b1;
one_counter #(
.DATA_WIDTH(SEL_WIDTH)
) one_counter_u (
.data_i(sel_mask),
.cnt_o(sel_result)
);
assign id_o = sel_result[SEL_ID_WIDHT-1:0];
assign id_vld_o = |sel_i;
end
endmodule : priority_encoder
`endif

Some files were not shown because too many files have changed in this diff Show More