From 056eaf77d76fb0f33b266f68b1ea7e1cd3d73f3f Mon Sep 17 00:00:00 2001 From: Ioannis Dingolis Date: Sun, 30 Mar 2025 19:35:15 +0300 Subject: [PATCH 1/4] Optimized sram module for FPGA synthesis. --- rtl/sram.sv | 85 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 37 deletions(-) mode change 100755 => 100644 rtl/sram.sv diff --git a/rtl/sram.sv b/rtl/sram.sv old mode 100755 new mode 100644 index ebee80b..e1a2fd1 --- a/rtl/sram.sv +++ b/rtl/sram.sv @@ -1,19 +1,31 @@ -/* -* @info SRAM Module -* -* @author VLSI Lab, EE dept., Democritus University of Thrace -* -* @brief An SRAM module with parameterized Read and Write Ports. -* Can also be configured to be resetable with initial value==0 -* -* @param SIZE : # of addressable entries (lines) in the array -* @param DATA_WIDTH : # of Data Bits -* @param RD_PORTS : # of Read Ports -* @param WR_PORTS : # of Write Ports -* @param RESETABLE : Indicates if the entries will be resetable -*/ -module sram - #(SIZE=1024,DATA_WIDTH=8, RD_PORTS=1, WR_PORTS=1, RESETABLE=0) ( +// Copyright (c) 2024-2025 Integrated Circuits Lab, Democritus University of Thrace, Greece. +// +// Copyright and related rights are licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. Unless required +// by applicable law or agreed to in writing, software, hardware and materials +// distributed under this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Ioannis Dingolis + +// A parametrizable memory module with asynchronous read ports and synchronous write ports. +// This memory module follows the RAM HDL Coding Guidelines (UG901) to be able to be +// synthesized using memory primitives (distributed RAM) in an FPGA environment whenever possible. + +module sram #( + // Quantity of memory entries + parameter int unsigned SIZE = 0, + // Width of each memory entry + parameter int unsigned DATA_WIDTH = 0, + // Number of asynchronous read ports + parameter int unsigned RD_PORTS = 0, + // Number of synchronous write ports + parameter int unsigned WR_PORTS = 0, + // Is the memory asynchronously resettable? + parameter bit RESETABLE = 0 +) ( input logic clk , input logic rst_n , //Write Port @@ -25,40 +37,39 @@ module sram output logic [RD_PORTS-1:0][ DATA_WIDTH-1:0] data_out ); - localparam SEL_BITS = $clog2(SIZE); - // #Internal Signals# - logic [SIZE-1:0][DATA_WIDTH-1:0] Memory_Array; + (* ram_style = "auto" *) logic [DATA_WIDTH-1:0] ram [SIZE-1:0]; - //Push the Data out - always_comb begin : DataOUT - for (int i = 0; i < RD_PORTS; i++) begin - data_out[i] = Memory_Array[read_address[i]]; + generate + always_comb begin : asynchronous_read + for (int i = 0; i < RD_PORTS; i++) begin + data_out[i] = ram[read_address[i]]; + end end - end + endgenerate generate - if(RESETABLE) begin - //Create Resetable SRAM - always_ff @(posedge clk or negedge rst_n) begin : Update - if(!rst_n) begin - for (int i = 0; i <= SIZE-1; i++) begin - Memory_Array[i]<='d0; + if (RESETABLE) begin + always_ff @( posedge clk or negedge rst_n ) begin : async_reset_sync_write + if (!rst_n) begin + for (int i = 0; i < SIZE; i++) begin + ram[i] <= '0; end end else begin for (int i = 0; i < WR_PORTS; i++) begin - if (wr_en[i]) Memory_Array[write_address[i]] <= new_data[i]; + if (wr_en[i]) begin + ram[write_address[i]] <= new_data[i]; + end end end end end else begin - //Create Non-Resetable SRAM - always_ff @(posedge clk) begin : Update + always_ff @( posedge clk ) begin : synchronous_write for (int i = 0; i < WR_PORTS; i++) begin - if (wr_en[i]) Memory_Array[write_address[i]] <= new_data[i]; + if (wr_en[i]) begin + ram[write_address[i]] <= new_data[i]; + end end end end endgenerate - - -endmodule \ No newline at end of file +endmodule From 313ff72e852d72291c9c11ef7b37e7e6286d2755 Mon Sep 17 00:00:00 2001 From: Ioannis Dingolis Date: Sun, 30 Mar 2025 19:40:51 +0300 Subject: [PATCH 2/4] Fix wait buffer overflow and compile optimization. --- rtl/wait_buffer.sv | 5 +++-- sim/compile.do | 5 ++--- svas/wait_buffer_sva.sv | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) mode change 100755 => 100644 rtl/wait_buffer.sv diff --git a/rtl/wait_buffer.sv b/rtl/wait_buffer.sv old mode 100755 new mode 100644 index 8395368..3a0090c --- a/rtl/wait_buffer.sv +++ b/rtl/wait_buffer.sv @@ -64,7 +64,8 @@ module wait_buffer #( logic [DEPTH-1:0] saved_is_store, saved_valid; // #Internal Signals# - logic [ DEPTH-1:0] head, tail, peek, tail_reversed, stat_counter, arb_priority ; + logic [ DEPTH:0] stat_counter; + logic [ DEPTH-1:0] head, tail, peek, tail_reversed, arb_priority ; logic [ DEPTH-1:0] matched_search_main, matched_search_sec, matched, match_picked, forward_matched; logic pop, one_found, multi_found, microop_ok; @@ -74,7 +75,7 @@ module wait_buffer #( buffer_mode mode; assign valid = ~stat_counter[0]; - assign ready = ~stat_counter[DEPTH-1]; + assign ready = ~(stat_counter[DEPTH-1] | stat_counter[DEPTH]); assign in_walk_mode = (mode==WALK); // Search in the Array diff --git a/sim/compile.do b/sim/compile.do index 420c1d2..54a67c8 100755 --- a/sim/compile.do +++ b/sim/compile.do @@ -5,9 +5,8 @@ vlib work vlog -f files_rtl.f -f files_sim.f +incdir+../rtl +incdir+../svas/ +define+INCLUDE_SVAS -#vsim -novopt work.tb -onfinish "stop" -# Option -novopt deprecated in newer versions -vsim -voptargs="+acc" tb -onfinish "stop" +vopt +acc tb -o tbopt +vsim tbopt -onfinish "stop" log -r /* do wave.do diff --git a/svas/wait_buffer_sva.sv b/svas/wait_buffer_sva.sv index 08827fd..5fa1b45 100755 --- a/svas/wait_buffer_sva.sv +++ b/svas/wait_buffer_sva.sv @@ -1 +1 @@ - assert property (@(posedge clk) disable iff(!rst_n) write_enable |-> ready) else $error("ERROR:WT Buffer: Push on Full"); + assert property (@(posedge clk) disable iff(!rst_n) write_enable |-> !stat_counter[DEPTH]) else $error("ERROR:WT Buffer: Push on Full"); From 6ad556d265a38da90317b162a74c1cce0422335c Mon Sep 17 00:00:00 2001 From: Ioannis Dingolis Date: Mon, 31 Mar 2025 21:23:29 +0300 Subject: [PATCH 3/4] Optimized cache_to_native for FPGA use. --- rtl/cache_to_native.sv | 96 ++++++++++++++++++++++-------------------- rtl/simple_fifo.sv | 90 +++++++++++++++++++++++++++++++++++++++ sim/files_rtl.f | 1 + 3 files changed, 141 insertions(+), 46 deletions(-) create mode 100644 rtl/simple_fifo.sv diff --git a/rtl/cache_to_native.sv b/rtl/cache_to_native.sv index b23a460..28668c2 100644 --- a/rtl/cache_to_native.sv +++ b/rtl/cache_to_native.sv @@ -57,33 +57,35 @@ always_ff @(posedge clk) begin end assign wf_pop = wf_valid & pri_flag; -fifo_duth # ( - .DW (DATA_WIDTH+ADDR_WIDTH), - .DEPTH(4) +simple_fifo #( + .DATA_WIDTH (DATA_WIDTH+ADDR_WIDTH), + .DEPTH (4) ) write_fifo ( - .clk (clk), - .rst (!resetn), - .push_data ({cache_write_addr, cache_write_data}), - .push (cache_write_valid), - .ready (wf_ready), - .pop_data (wf_data_out), - .valid (wf_valid), - .pop (wf_pop) + .clk_i (clk), + .rst_ni (resetn), + .data_i ({cache_write_addr, cache_write_data}), + .push_i (cache_write_valid), + .ready_o (wf_ready), + .data_o (wf_data_out), + .valid_o (wf_valid), + .pop_i (wf_pop), + .usage_o () ); assign rf_pop = rf_valid & ~pri_flag; -fifo_duth # ( - .DW (ADDR_WIDTH), - .DEPTH(4) +simple_fifo #( + .DATA_WIDTH (ADDR_WIDTH), + .DEPTH (4) ) read_fifo ( - .clk (clk), - .rst (!resetn), - .push_data (cache_read_addr), - .push (cache_read_valid), - .ready (rf_ready), - .pop_data (rf_data_out), - .valid (rf_valid), - .pop (rf_pop) + .clk_i (clk), + .rst_ni (resetn), + .data_i (cache_read_addr), + .push_i (cache_read_valid), + .ready_o (rf_ready), + .data_o (rf_data_out), + .valid_o (rf_valid), + .pop_i (rf_pop), + .usage_o () ); assign req_push = wf_pop | rf_pop; @@ -91,18 +93,19 @@ assign req_pop = nat_request_valid & nat_request_ready; assign req_data_in[DATA_WIDTH+ADDR_WIDTH] = (wf_pop) ? 1 : (rf_pop) ? 0 : 0; assign req_data_in[DATA_WIDTH+ADDR_WIDTH-1:DATA_WIDTH] = (wf_pop) ? wf_data_out[DATA_WIDTH+ADDR_WIDTH-1:DATA_WIDTH] : (rf_pop) ? rf_data_out : rf_data_out; assign req_data_in[DATA_WIDTH-1:0] = (wf_pop) ? wf_data_out[DATA_WIDTH-1:0] : (rf_pop) ? 0 : 0; -fifo_duth # ( - .DW (DATA_WIDTH+ADDR_WIDTH+1), - .DEPTH(4) - ) request_fifo ( - .clk (clk), - .rst (!resetn), - .push_data (req_data_in), - .push (req_push), - .ready (req_ready), - .pop_data (req_data_out), - .valid (req_valid), - .pop (req_pop) +simple_fifo #( + .DATA_WIDTH (DATA_WIDTH+ADDR_WIDTH+1), + .DEPTH (4) +) request_fifo ( + .clk_i (clk), + .rst_ni (resetn), + .data_i (req_data_in), + .push_i (req_push), + .ready_o (req_ready), + .data_o (req_data_out), + .valid_o (req_valid), + .pop_i (req_pop), + .usage_o () ); always_comb begin : axi @@ -137,18 +140,19 @@ assign upd_push = nat_update_valid & nat_update_ready; assign upd_pop = upd_valid; assign upd_data_in = {nat_update_data, address_keep}; -fifo_duth # ( - .DW (DATA_WIDTH+ADDR_WIDTH), - .DEPTH(4) -) return_fifo ( - .clk (clk), - .rst (!resetn), - .push_data (upd_data_in), - .push (upd_push), - .ready (upd_ready), - .pop_data (upd_data_out), - .valid (upd_valid), - .pop (upd_pop) +simple_fifo #( + .DATA_WIDTH (DATA_WIDTH+ADDR_WIDTH), + .DEPTH (4) +) return_fifo ( + .clk_i (clk), + .rst_ni (resetn), + .data_i (upd_data_in), + .push_i (upd_push), + .ready_o (upd_ready), + .data_o (upd_data_out), + .valid_o (upd_valid), + .pop_i (upd_pop), + .usage_o () ); assign nat_request_valid = req_valid & ~addr_keep_flag; diff --git a/rtl/simple_fifo.sv b/rtl/simple_fifo.sv new file mode 100644 index 0000000..f5e5d4f --- /dev/null +++ b/rtl/simple_fifo.sv @@ -0,0 +1,90 @@ +// Copyright (c) 2024-2025 Integrated Circuits Lab, Democritus University of Thrace, Greece. +// +// Copyright and related rights are licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. Unless required +// by applicable law or agreed to in writing, software, hardware and materials +// distributed under this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Authors: +// - Ioannis Dingolis + +// simple fifo with depth > 0 + +module simple_fifo #( + parameter int unsigned DEPTH = 0, + parameter int unsigned DATA_WIDTH = 0, + parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1 +) ( + input logic clk_i, + input logic rst_ni, + input logic [DATA_WIDTH-1:0] data_i, + input logic push_i, + input logic pop_i, + output logic [ADDR_DEPTH:0] usage_o, + output logic ready_o, + output logic valid_o, + output logic [DATA_WIDTH-1:0] data_o +); +/*==================< FIFO Logic >==================*/ + logic [ADDR_DEPTH-1:0] read_pointer, write_pointer; + logic [ADDR_DEPTH:0] status_counter; + assign usage_o = status_counter; + + (* ram_style = "auto" *) logic [DATA_WIDTH-1:0] ram [DEPTH-1:0]; + + always_ff @ ( posedge clk_i ) begin : synchronous_write + if (push_i && ready_o) ram[write_pointer] <= data_i; + end + + always_ff @( posedge clk_i or negedge rst_ni ) begin : fifo_seq + if (!rst_ni) begin + read_pointer <= '0; + write_pointer <= '0; + status_counter <= '0; + end else begin + if (push_i && ready_o) begin + status_counter <= status_counter + 1; + if (write_pointer == DEPTH - 1) begin // if DEPTH != 2^n then set zero manually + write_pointer <= '0; // otherwise overflow + end else begin + write_pointer <= write_pointer + 1; + end + end + if (pop_i && valid_o) begin + status_counter <= status_counter - 1; + if (read_pointer == DEPTH - 1) begin + read_pointer <= '0; + end else begin + read_pointer <= read_pointer + 1; + end + end + if (push_i && ready_o && pop_i && valid_o) begin + status_counter <= status_counter; // Don't change counter. + end + + end + end + + always_comb begin : fifo_comb + ready_o = !(status_counter == DEPTH); + valid_o = !(status_counter == 0); + data_o = ram[read_pointer]; + end + + + initial begin + assert (DEPTH > 0) else $fatal("DEPTH must be greater than zero in simple_fifo."); + end + + push_full: assert property( + @( posedge clk_i ) disable iff (!rst_ni) (!ready_o |-> !push_i)) + else $fatal ("Pushing new data in simple_fifo while it's full."); + + pop_empty: assert property( + @( posedge clk_i ) disable iff (!rst_ni) (!valid_o |-> !pop_i)) + else $fatal ("Popping data from simple_fifo while it's empty."); + + +endmodule \ No newline at end of file diff --git a/sim/files_rtl.f b/sim/files_rtl.f index 6b8ba8e..f8f0718 100755 --- a/sim/files_rtl.f +++ b/sim/files_rtl.f @@ -55,6 +55,7 @@ ../rtl/lrumore.sv ../rtl/main_memory.sv ../rtl/onehot_detect.sv +../rtl/simple_fifo.sv ../rtl/sram.sv ../rtl/vga_controller.sv ../rtl/wait_buffer.sv From 196f29a2529c75ed25d70fe6ddb48a512e04e083 Mon Sep 17 00:00:00 2001 From: Ioannis Dingolis Date: Tue, 8 Apr 2025 18:03:10 +0300 Subject: [PATCH 4/4] Added AXI4 Master CDC --- rtl/AXI4_master_cdc.sv | 368 +++++++++++++++++++++++++++ rtl/pulp/LICENSE | 176 +++++++++++++ rtl/pulp/binary_to_gray.sv | 22 ++ rtl/pulp/cdc_fifo_gray.sv | 295 +++++++++++++++++++++ rtl/pulp/gray_to_binary.sv | 23 ++ rtl/pulp/include/assertions.svh | 201 +++++++++++++++ rtl/pulp/include/registers.svh | 262 +++++++++++++++++++ rtl/pulp/rstgen.sv | 30 +++ rtl/pulp/rstgen_bypass.sv | 67 +++++ rtl/pulp/spill_register.sv | 46 ++++ rtl/pulp/spill_register_flushable.sv | 105 ++++++++ rtl/pulp/sync.sv | 37 +++ rtl/pulp/tc_clk.sv | 120 +++++++++ rtl/pulp/tc_clk_xilinx.sv | 96 +++++++ sim/compile.do | 3 + sim/files_pulp.f | 16 ++ 16 files changed, 1867 insertions(+) create mode 100644 rtl/AXI4_master_cdc.sv create mode 100644 rtl/pulp/LICENSE create mode 100644 rtl/pulp/binary_to_gray.sv create mode 100644 rtl/pulp/cdc_fifo_gray.sv create mode 100644 rtl/pulp/gray_to_binary.sv create mode 100644 rtl/pulp/include/assertions.svh create mode 100644 rtl/pulp/include/registers.svh create mode 100644 rtl/pulp/rstgen.sv create mode 100644 rtl/pulp/rstgen_bypass.sv create mode 100644 rtl/pulp/spill_register.sv create mode 100644 rtl/pulp/spill_register_flushable.sv create mode 100644 rtl/pulp/sync.sv create mode 100644 rtl/pulp/tc_clk.sv create mode 100644 rtl/pulp/tc_clk_xilinx.sv create mode 100644 sim/files_pulp.f diff --git a/rtl/AXI4_master_cdc.sv b/rtl/AXI4_master_cdc.sv new file mode 100644 index 0000000..ad5afac --- /dev/null +++ b/rtl/AXI4_master_cdc.sv @@ -0,0 +1,368 @@ +//! During a write transaction, the master holds the required signals with the information for the transaction. +//! When the AWVALID-AWREADY handshake happens, it starts sending the data until it sents the last transfer of the transaction. +//! After that, it waits for the BRESP signal that informs the master whether or not the transaction was successful. +//! This master has to wait until it gets a response for the latest write transaction to initialize another request. + +//! @title Simple valid.ready to AXI4 Master with CDC FIFOs +//! @author Giorgos Pelekidis +//! @author Ioannis Dingolis + +// Instructions on how to use CDC FIFOs: Read description from file cdc_fifo_gray.sv +// Reset mechanism for CDC FIFOs needs to be implemented correctly. +// Module rstgen.sv can be used as a proper reset mechanism. Because it's +// technology dependent use in simulation the file tc_clk.sv and on implementation with +// Xilinx FPGAs the file tc_clk_xilinx.sv. Furthermore, timing constraints need to be +// implemented. Check CDC FIFO's description on how to implement those (using dont_touch, +// keep_hierarchy, set_max_delay and set_false_path -hold for XDC equivalent constraints). + +`ifdef MODEL_TECH + `include "structs.sv" +`endif +module AXI4_master_cdc #( + parameter ID_SEL = 0, //! Master's ID + parameter ID_WIDTH = 4, //! Number of Transaction ID bits + parameter ADDR_WIDTH = 32, //! Number of Address bits + parameter DATA_WIDTH = 32, //! Number of AXI Data bits + parameter RESP_WIDTH = 2, //! Number of Response bits + parameter LS_DATA_WIDTH = 256, //! Number of Left-side Data bits + // local parameters + localparam NBYTES = DATA_WIDTH/8, //! Number of Bytes per word. + localparam NTRANSF = LS_DATA_WIDTH/DATA_WIDTH, //! Required number of transfers per transaction. + localparam LEN_W = (NTRANSF==1) ? 1 : $clog2(NTRANSF) //! Required number of bits for the write and read_index to count the number of transfers. +)( + input logic clk_intc_i, // Side A (interconnect) clock + input logic rst_intc_ni, // Side A reset. !! ASYNC assertion (1->0) & SYNC deassertion (0->1) to side A clk. + input logic clk_proc_i, // Side B (processor) clock + input logic rst_proc_ni, // Side B reset. !! ASYNC assertion (1->0) & SYNC deassertion (0->1) to side B clk. + + // Left side signals + //! @virtualbus Valid-Ready_Interface @dir in Simple Valid-Ready Request and Return channels + input logic [ADDR_WIDTH-1:0] ls_address, //! Memory Address for the transaction + input logic [1:0] ls_operation, //! Write, Read or No operation + + input logic [LS_DATA_WIDTH-1:0] ls_data_in, //! Write Data + input logic ls_valid_in, //! Valid Request signal + output logic ls_ready_out, //! Ready Request signal + + output logic [LS_DATA_WIDTH-1:0] ls_data_out, //! Read Data + output logic ls_valid_out, //! Valid Return signal + input logic ls_ready_in, //! Ready Return signal + //! @end + + //! @virtualbus AXI_Master @dir out AXI Write and Read channels + // write request channel + //! AWVALID is HIGH when the master holds valid request signals for a slave. + output logic AWVALID, + input logic AWREADY, //! AWREADY is HIGH when the slave can accept a request. + output logic [ADDR_WIDTH-1:0] AWADDR, //! Holds the address of the first transfer in a Write transaction. + output logic [1:0] AWBURST, //! Describes how the address increments between transfers in a transaction. In this case always Incrimental. + output logic [7:0] AWLEN, //! The total number of transfers in a transaction, encoded as: Length=AxLEN+1. In this case always 7. + output logic [2:0] AWSIZE, //! Indicates the maximum number of bytes in each data transfer within a transaction. In this case always 4. + output logic [ID_WIDTH-1:0] AWID, //! Transaction ID. In this case every master has a fixed ID selected by the ID_SEL parameter. + + // write data channel + + output logic WVALID, //! WVALID is HIGH when the master holds valid data signals for a slave. + input logic WREADY, //! WREADY is HIGH when the slave can accept a request. + output logic [DATA_WIDTH-1:0] WDATA, //! Write data. + output logic WLAST, //! Indicates the last write data transfer of a transaction. + output logic [NBYTES-1:0] WSTRB, //! Indicates which byte lanes of WDATA contain valid data in a write transaction. + + // write response channel + input logic [ID_WIDTH-1:0] BID, //! Write Response ID. + input logic [RESP_WIDTH-1:0] BRESP, //! Returns success or failure of the transaction. + input logic BVALID, //! BVALID is HIGH when a slave holds valid Response signals for the master. + output logic BREADY, //! BREADY is HIGH when the master can accept a Response. + + // read request channel + input logic ARREADY, //! ARREADY is HIGH when a slave can accept a request. + output logic ARVALID, //! ARVALID is HIGH when the master holds valid Request signals for a slave. + output logic [ADDR_WIDTH-1:0] ARADDR, //! Holds the address of the first transfer in a Read transaction. + output logic [1:0] ARBURST, //! Describes how the address increments between transfers in a transaction. In this case always Incrimental. + output logic [7:0] ARLEN, //! The total number of transfers in a transaction, encoded as: Length=AxLEN+1. In this case always 7. + output logic [2:0] ARSIZE, //! Indicates the maximum number of bytes in each data transfer within a transaction. In this case always 4. + output logic [ID_WIDTH-1:0] ARID, //! Transaction ID. In this case every master has a fixed ID selected by the ID_SEL parameter. + + // read data channel + input logic [DATA_WIDTH-1:0] RDATA, //! Read data. + input logic RLAST, //! Indicates the last read data transfer of a transaction. + input logic [ID_WIDTH-1:0] RID, //! Read Response ID. + input logic [RESP_WIDTH-1:0] RRESP, //! Returns success or failure of the transaction. + input logic RVALID, //! RVALID is HIGH when a slave holds valid Response signals for the master. + output logic RREADY //! RREADY is HIGH when the master can accept a Response. + //! @end +); + +// loop counters +integer i1, i2, i3; //! Loop counter. + +//////////////////////////// +// Signal definition // +//////////////////////////// + +//! AW-channel control signals. +logic awpending; +logic [ADDR_WIDTH-1:0] awaddr; +logic awvalid; +//! W-channel control signals. +logic [DATA_WIDTH-1:0] wdata ; +logic wvalid; +logic [NBYTES-1 :0] wstrb ; +//! AR-channel control signals. +logic arpending; +logic [ADDR_WIDTH-1:0] araddr; +logic arvalid; + +// AXI related signals +logic [1:0] burst; //! Shared Burst type-signal assigned to both AW-channel and AR-channel. +logic [2 :0] size; //! Shared transfer Size-type signal assigned to both AWSIZE and ARSIZE. +logic [7 :0] len; //! Shared transaction Length signal assigned to both AWLEN and ARLEN. +logic [ID_WIDTH-1 :0] id_sel; //! Stores a constant ID for each master depending on the ID_SEL parameter. + +// request fifo +logic req_ready; //! Request-fifo full. +logic req_valid; //! Request-fifo req_valid. +logic req_push; //! Request-fifo push. +logic req_pop; //! Request-fifo pop. +logic [LS_DATA_WIDTH+ADDR_WIDTH+1:0] req_fifo_in; //! Request-fifo data in. +logic [LS_DATA_WIDTH+ADDR_WIDTH+1:0] req_fifo_out; //! Request-fifo data out. + +// retrun fifo +logic ret_ready; //! Return-fifo full signal. +logic ret_valid; //! Return-fifo empty signal. +logic ret_push; //! Return-fifo push signal. +logic ret_pop; //! Return-fifo pop signal. +logic [LS_DATA_WIDTH-1:0] ret_data_in; //! Return-fifo data in. +logic [LS_DATA_WIDTH-1:0] ret_data_out; //! Return-fifo data out. + +// return fifo assist signals +logic [RESP_WIDTH-1:0] resp_keep; //! Holds the B or R response in case of a double push from both channels. (NOT IMPLEMENTED CORRECTLY) +logic ret_push_flag; //! Helps delay the push signal by one cycle. + +// word fussion and fission buffers and buffer indexing +logic [DATA_WIDTH-1:0] write_data_buffer [NTRANSF]; //! Stores the incoming 256-bit write data, that later get seperated to 32-bit words for the 8-transfer AXI transactions. +logic [DATA_WIDTH-1:0] read_data_buffer [NTRANSF]; //! Stores the 8 incoming 32-bit read words to a 256-bit line that gets sent out from the Left-side interface. +logic [LEN_W-1:0] write_index; //! Index that helps read the 32-bit words from the write_data_buffer. +logic [LEN_W-1:0] read_index; //! Index that helps store the 32-bit words to the read_data_buffer. + +//////////////////////////// +// Signal assignment // +//////////////////////////// + +// AXI related signals +assign len = NTRANSF-1; +assign size = $clog2(NBYTES); +assign burst = 2'b01; +assign id_sel = ID_SEL; + +// word fussion and fission buffers and buffer indexing +always_ff @( posedge clk_intc_i ) begin : Write_index_increment //! - When a WVALID-WREADY handshake takes place, the index is incremented by 1 to read the next word from the write_data_buffer. + if (!rst_intc_ni) write_index <= 0; + else if (WVALID && WREADY && WLAST) write_index <= 0; + else if (WVALID && WREADY) write_index <= write_index + 1; +end + +always_ff @( posedge clk_intc_i ) begin : Update_write_data_buffer //! - Checks if the next entry in the Request-fifo is a write request and then it updates the write_data_buffer. + if (!rst_intc_ni) + write_data_buffer <= '{default:0}; + else if (req_fifo_out[1:0] == 2'b10 && req_valid && !awpending) + for (i1=0; i1 + +/// A binary to gray code converter. +module binary_to_gray #( + parameter int N = -1 +)( + input logic [N-1:0] A, + output logic [N-1:0] Z +); + assign Z = A ^ (A >> 1); +endmodule diff --git a/rtl/pulp/cdc_fifo_gray.sv b/rtl/pulp/cdc_fifo_gray.sv new file mode 100644 index 0000000..b1e09a7 --- /dev/null +++ b/rtl/pulp/cdc_fifo_gray.sv @@ -0,0 +1,295 @@ +// Copyright 2018-2019 ETH Zurich and University of Bologna. +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Fabian Schuiki +// Florian Zaruba + +/// A clock domain crossing FIFO, using gray counters. +/// +/// # Architecture +/// +/// The design is split into two parts, each one being clocked and reset +/// separately. +/// 1. The data to be transferred over the clock domain boundary is +/// is stored in a FIFO. The corresponding write pointer is managed +/// (incremented) in the source clock domain. +/// 2. The entire FIFO content is exposed over the `async_data` port. +/// The destination clock domain increments its read pointer +/// in its destination clock domain. +/// +/// Read and write pointers are then gray coded, communicated +/// and synchronized using a classic multi-stage FF synchronizer +/// in the other clock domain. The gray coding ensures that only +/// one bit changes at each pointer increment, preventing the +/// synchronizer to accidentally latch an inconsistent state +/// on a multi-bit bus. +/// +/// The not full signal e.g. `src_ready_o` (on the sending side) +/// is generated using the local write pointer and the pessimistic +/// read pointer from the destination clock domain (pessimistic +/// because it is delayed at least two cycles because of the synchronizer +/// stages). This prevents the FIFO from overflowing. +/// +/// The not empty signal e.g. `dst_valid_o` is generated using +/// the pessimistic write pointer and the local read pointer in +/// the destination clock domain. This means the FIFO content +/// does not need to be synchronized as we are sure we are reading +/// data which has been written at least two cycles earlier. +/// Furthermore, the read select logic into the FIFO is completely +/// clocked by the destination clock domain which avoids +/// inefficient data synchronization. +/// +/// The FIFO size must be powers of two, which is why its depth is +/// given as 2**LOG_DEPTH. LOG_DEPTH must be at least 1. +/// +/// # Reset Behavior!! +/// +/// This module must not be used if warm reset capabily is a requirement. The +/// only execption is if you consistently use a reset controller that sequences +/// the resets while gating both clock domains (be very careful if you follow +/// this strategy!). If you need warm reset/clear/flush capabilities, use (AND +/// CAREFULLY READ THE DESCRIPTION) the cdc_fifo_gray_clearable module. +/// +/// After this disclaimer, here is how you connect the src_rst_ni and the +/// dst_rst_ni of this module for power-on-reset (POR). The src_rst_ni and +/// dst_rst_ni signal must be asserted SIMULTANEOUSLY (i.e. asynchronous +/// assertion). Othwerwise, spurious transactions could occur in the domain +/// where the reset arrives later than the other. The de-assertion of both reset +/// must be synchronized to their respective clock domain (i.e. src_rst_ni must +/// be deasserted synchronously to the src_clk_i and dst_rst_ni must be +/// deasserted synchronously to dst_clk_i.) You can use the rstgen cell in the +/// common_cells library to achieve this (synchronization of only the +/// de-assertion). However be carefull about reset domain crossings; If you +/// reset both domain asynchronously in their entirety (i.e. POR) you are fine. +/// However, if you use this strategy for warm resets (some parts of the circuit +/// are not reset) you might introduce metastability in this separate +/// reset-domain when you assert the reset (the deassertion synchronizer doen't +/// help here). +/// +/// # Constraints +/// +/// We need to make sure that the propagation delay of the +/// data, read and write pointer is bound to the minimum of +/// either the sending or receiving clock period to prevent +/// an inconsistent state to be latched (if for example the one +/// bit of the read/write pointer have an excessive delay). +/// Furthermore, we should deactivate setup and hold checks on +/// the asynchronous signals. +/// +/// ``` +/// set_ungroup [get_designs cdc_fifo_gray*] false +/// set_boundary_optimization [get_designs cdc_fifo_gray*] false +/// set_max_delay min(T_src, T_dst) \ +/// -through [get_pins -hierarchical -filter async] \ +/// -through [get_pins -hierarchical -filter async] +/// set_false_path -hold \ +/// -through [get_pins -hierarchical -filter async] \ +/// -through [get_pins -hierarchical -filter async] +/// ``` + +`include "registers.svh" + +(* no_ungroup *) +(* no_boundary_optimization *) +module cdc_fifo_gray #( + /// The width of the default logic type. + parameter int unsigned WIDTH = 1, + /// The data type of the payload transported by the FIFO. + parameter type T = logic [WIDTH-1:0], + /// The FIFO's depth given as 2**LOG_DEPTH. + parameter int LOG_DEPTH = 3, + /// The number of synchronization registers to insert on the async pointers. + parameter int SYNC_STAGES = 2 +) ( + input logic src_rst_ni, + input logic src_clk_i, + input T src_data_i, + input logic src_valid_i, + output logic src_ready_o, + + input logic dst_rst_ni, + input logic dst_clk_i, + output T dst_data_o, + output logic dst_valid_o, + input logic dst_ready_i +); + + T [2**LOG_DEPTH-1:0] async_data; + logic [LOG_DEPTH:0] async_wptr; + logic [LOG_DEPTH:0] async_rptr; + + cdc_fifo_gray_src #( + .T ( T ), + .LOG_DEPTH ( LOG_DEPTH ) + ) i_src ( + .src_rst_ni, + .src_clk_i, + .src_data_i, + .src_valid_i, + .src_ready_o, + + (* async *) .async_data_o ( async_data ), + (* async *) .async_wptr_o ( async_wptr ), + (* async *) .async_rptr_i ( async_rptr ) + ); + + cdc_fifo_gray_dst #( + .T ( T ), + .LOG_DEPTH ( LOG_DEPTH ) + ) i_dst ( + .dst_rst_ni, + .dst_clk_i, + .dst_data_o, + .dst_valid_o, + .dst_ready_i, + + (* async *) .async_data_i ( async_data ), + (* async *) .async_wptr_i ( async_wptr ), + (* async *) .async_rptr_o ( async_rptr ) + ); + + // Check the invariants. + `ifndef SYNTHESIS + `ifndef COMMON_CELLS_ASSERTS_OFF + initial assert(LOG_DEPTH > 0); + initial assert(SYNC_STAGES >= 2); + `endif + `endif + +endmodule + + +(* no_ungroup *) +(* no_boundary_optimization *) +module cdc_fifo_gray_src #( + parameter type T = logic, + parameter int LOG_DEPTH = 3, + parameter int SYNC_STAGES = 2 +)( + input logic src_rst_ni, + input logic src_clk_i, + input T src_data_i, + input logic src_valid_i, + output logic src_ready_o, + + output T [2**LOG_DEPTH-1:0] async_data_o, + output logic [LOG_DEPTH:0] async_wptr_o, + input logic [LOG_DEPTH:0] async_rptr_i +); + + localparam int PtrWidth = LOG_DEPTH+1; + localparam logic [PtrWidth-1:0] PtrFull = (1 << LOG_DEPTH); + + T [2**LOG_DEPTH-1:0] data_q; + logic [PtrWidth-1:0] wptr_q, wptr_d, wptr_bin, wptr_next, rptr, rptr_bin; + + // Data FIFO. + assign async_data_o = data_q; + for (genvar i = 0; i < 2**LOG_DEPTH; i++) begin : gen_word + `FFLNR(data_q[i], src_data_i, + src_valid_i & src_ready_o & (wptr_bin[LOG_DEPTH-1:0] == i), src_clk_i) + end + + // Read pointer. + for (genvar i = 0; i < PtrWidth; i++) begin : gen_sync + sync #(.STAGES(SYNC_STAGES)) i_sync ( + .clk_i ( src_clk_i ), + .rst_ni ( src_rst_ni ), + .serial_i ( async_rptr_i[i] ), + .serial_o ( rptr[i] ) + ); + end + gray_to_binary #(PtrWidth) i_rptr_g2b (.A(rptr), .Z(rptr_bin)); + + // Write pointer. + assign wptr_next = wptr_bin+1; + gray_to_binary #(PtrWidth) i_wptr_g2b (.A(wptr_q), .Z(wptr_bin)); + binary_to_gray #(PtrWidth) i_wptr_b2g (.A(wptr_next), .Z(wptr_d)); + `FFLARN(wptr_q, wptr_d, src_valid_i & src_ready_o, '0, src_clk_i, src_rst_ni) + assign async_wptr_o = wptr_q; + + // The pointers into the FIFO are one bit wider than the actual address into + // the FIFO. This makes detecting critical states very simple: if all but the + // topmost bit of rptr and wptr agree, the FIFO is in a critical state. If the + // topmost bit is equal, the FIFO is empty, otherwise it is full. + assign src_ready_o = ((wptr_bin ^ rptr_bin) != PtrFull); + +endmodule + + +(* keep_hierarchy = "true" *) +(* dont_touch = "true" *) +(* no_ungroup *) +(* no_boundary_optimization *) +module cdc_fifo_gray_dst #( + parameter type T = logic, + parameter int LOG_DEPTH = 3, + parameter int SYNC_STAGES = 2 +)( + input logic dst_rst_ni, + input logic dst_clk_i, + output T dst_data_o, + output logic dst_valid_o, + input logic dst_ready_i, + + input T [2**LOG_DEPTH-1:0] async_data_i, + input logic [LOG_DEPTH:0] async_wptr_i, + output logic [LOG_DEPTH:0] async_rptr_o +); + + localparam int PtrWidth = LOG_DEPTH+1; + localparam logic [PtrWidth-1:0] PtrEmpty = '0; + + T dst_data; + logic [PtrWidth-1:0] rptr_q, rptr_d, rptr_bin, rptr_bin_d, rptr_next, wptr, wptr_bin; + logic dst_valid, dst_ready; + // Data selector and register. + assign dst_data = async_data_i[rptr_bin[LOG_DEPTH-1:0]]; + + // Read pointer. + assign rptr_next = rptr_bin+1; + gray_to_binary #(PtrWidth) i_rptr_g2b (.A(rptr_q), .Z(rptr_bin)); + binary_to_gray #(PtrWidth) i_rptr_b2g (.A(rptr_next), .Z(rptr_d)); + `FFLARN(rptr_q, rptr_d, dst_valid & dst_ready, '0, dst_clk_i, dst_rst_ni) + assign async_rptr_o = rptr_q; + + // Write pointer. + for (genvar i = 0; i < PtrWidth; i++) begin : gen_sync + sync #(.STAGES(SYNC_STAGES)) i_sync ( + .clk_i ( dst_clk_i ), + .rst_ni ( dst_rst_ni ), + .serial_i ( async_wptr_i[i] ), + .serial_o ( wptr[i] ) + ); + end + gray_to_binary #(PtrWidth) i_wptr_g2b (.A(wptr), .Z(wptr_bin)); + + // The pointers into the FIFO are one bit wider than the actual address into + // the FIFO. This makes detecting critical states very simple: if all but the + // topmost bit of rptr and wptr agree, the FIFO is in a critical state. If the + // topmost bit is equal, the FIFO is empty, otherwise it is full. + assign dst_valid = ((wptr_bin ^ rptr_bin) != PtrEmpty); + + // Cut the combinatorial path with a spill register. + spill_register #( + .T ( T ) + ) i_spill_register ( + .clk_i ( dst_clk_i ), + .rst_ni ( dst_rst_ni ), + .valid_i ( dst_valid ), + .ready_o ( dst_ready ), + .data_i ( dst_data ), + .valid_o ( dst_valid_o ), + .ready_i ( dst_ready_i ), + .data_o ( dst_data_o ) + ); + +endmodule diff --git a/rtl/pulp/gray_to_binary.sv b/rtl/pulp/gray_to_binary.sv new file mode 100644 index 0000000..b1ad46f --- /dev/null +++ b/rtl/pulp/gray_to_binary.sv @@ -0,0 +1,23 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Fabian Schuiki + +/// A gray code to binary converter. +module gray_to_binary #( + parameter int N = -1 +)( + input logic [N-1:0] A, + output logic [N-1:0] Z +); + for (genvar i = 0; i < N; i++) + assign Z[i] = ^A[N-1:i]; +endmodule diff --git a/rtl/pulp/include/assertions.svh b/rtl/pulp/include/assertions.svh new file mode 100644 index 0000000..b6b4b73 --- /dev/null +++ b/rtl/pulp/include/assertions.svh @@ -0,0 +1,201 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Macros and helper code for using assertions. +// - Provides default clk and rst options to simplify code +// - Provides boiler plate template for common assertions + +`ifndef PRIM_ASSERT_SV +`define PRIM_ASSERT_SV + +`ifdef UVM + // report assertion error with UVM if compiled + package assert_rpt_pkg; + import uvm_pkg::*; + `include "uvm_macros.svh" + function void assert_rpt(string msg); + `uvm_error("ASSERT FAILED", msg) + endfunction + endpackage +`endif + +/////////////////// +// Helper macros // +/////////////////// + +// local helper macro to reduce code clutter. undefined at the end of this file +`ifndef VERILATOR +`ifndef SYNTHESIS +`ifndef XSIM +`define INC_ASSERT +`endif +`endif +`endif + +// Converts an arbitrary block of code into a Verilog string +`define PRIM_STRINGIFY(__x) `"__x`" + +// ASSERT_RPT is available to change the reporting mechanism when an assert fails +`define ASSERT_RPT(__name) \ +`ifdef UVM \ + assert_rpt_pkg::assert_rpt($sformatf("[%m] %s (%s:%0d)", \ + __name, `__FILE__, `__LINE__)); \ +`else \ + $error("[ASSERT FAILED] [%m] %s (%s:%0d)", __name, `__FILE__, `__LINE__); \ +`endif + +/////////////////////////////////////// +// Simple assertion and cover macros // +/////////////////////////////////////// + +// Default clk and reset signals used by assertion macros below. +`define ASSERT_DEFAULT_CLK clk_i +`define ASSERT_DEFAULT_RST !rst_ni + +// Immediate assertion +// Note that immediate assertions are sensitive to simulation glitches. +`define ASSERT_I(__name, __prop) \ +`ifdef INC_ASSERT \ + __name: assert (__prop) \ + else begin \ + `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + end \ +`endif + +// Assertion in initial block. Can be used for things like parameter checking. +`define ASSERT_INIT(__name, __prop) \ +`ifdef INC_ASSERT \ + initial begin \ + __name: assert (__prop) \ + else begin \ + `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + end \ + end \ +`endif + +// Assertion in final block. Can be used for things like queues being empty +// at end of sim, all credits returned at end of sim, state machines in idle +// at end of sim. +`define ASSERT_FINAL(__name, __prop) \ +`ifdef INC_ASSERT \ + final begin \ + __name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \ + else begin \ + `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + end \ + end \ +`endif + +// Assert a concurrent property directly. +// It can be called as a module (or interface) body item. +`define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ + else begin \ + `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + end \ +`endif +// Note: Above we use (__rst !== '0) in the disable iff statements instead of +// (__rst == '1). This properly disables the assertion in cases when reset is X at +// the beginning of a simulation. For that case, (reset == '1) does not disable the +// assertion. + +// Assert a concurrent property NEVER happens +`define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not (__prop)) \ + else begin \ + `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + end \ +`endif + +// Assert that signal has a known value (each bit is either '0' or '1') after reset. +// It can be called as a module (or interface) body item. +`define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + `ASSERT(__name, !$isunknown(__sig), __clk, __rst) \ +`endif + +// Cover a concurrent property +`define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + __name: cover property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)); \ +`endif + +////////////////////////////// +// Complex assertion macros // +////////////////////////////// + +// Assert that signal is an active-high pulse with pulse length of 1 clock cycle +`define ASSERT_PULSE(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + `ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) \ +`endif + +// Assert that a property is true only when an enable signal is set. It can be called as a module +// (or interface) body item. +`define ASSERT_IF(__name, __prop, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + `ASSERT(__name, (__enable) |-> (__prop), __clk, __rst) \ +`endif + +// Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is +// set. It can be called as a module (or interface) body item. +`define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + `ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst) \ + `ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) \ +`endif + +/////////////////////// +// Assumption macros // +/////////////////////// + +// Assume a concurrent property +`define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef INC_ASSERT \ + __name: assume property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ + else begin \ + `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + end \ +`endif + +// Assume an immediate property +`define ASSUME_I(__name, __prop) \ +`ifdef INC_ASSERT \ + __name: assume (__prop) \ + else begin \ + `ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ + end \ +`endif + +////////////////////////////////// +// For formal verification only // +////////////////////////////////// + +// Note that the existing set of ASSERT macros specified above shall be used for FPV, +// thereby ensuring that the assertions are evaluated during DV simulations as well. + +// ASSUME_FPV +// Assume a concurrent property during formal verification only. +`define ASSUME_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef FPV_ON \ + `ASSUME(__name, __prop, __clk, __rst) \ +`endif + +// ASSUME_I_FPV +// Assume a concurrent property during formal verification only. +`define ASSUME_I_FPV(__name, __prop) \ +`ifdef FPV_ON \ + `ASSUME_I(__name, __prop) \ +`endif + +// COVER_FPV +// Cover a concurrent property during formal verification +`define COVER_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef FPV_ON \ + `COVER(__name, __prop, __clk, __rst) \ +`endif + +`endif // PRIM_ASSERT_SV diff --git a/rtl/pulp/include/registers.svh b/rtl/pulp/include/registers.svh new file mode 100644 index 0000000..8ebb39c --- /dev/null +++ b/rtl/pulp/include/registers.svh @@ -0,0 +1,262 @@ +// Copyright 2018, 2021 ETH Zurich and University of Bologna. +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// SPDX-License-Identifier: SHL-0.51 +// +// Author: Stefan Mach +// Description: Common register defines for RTL designs + +`ifndef COMMON_CELLS_REGISTERS_SVH_ +`define COMMON_CELLS_REGISTERS_SVH_ + +// Abridged Summary of available FF macros: +// `FF: asynchronous active-low reset +// `FFAR: asynchronous active-high reset +// `FFARN: [deprecated] asynchronous active-low reset +// `FFSR: synchronous active-high reset +// `FFSRN: synchronous active-low reset +// `FFNR: without reset +// `FFL: load-enable and asynchronous active-low reset +// `FFLAR: load-enable and asynchronous active-high reset +// `FFLARN: [deprecated] load-enable and asynchronous active-low reset +// `FFLARNC: load-enable and asynchronous active-low reset and synchronous active-high clear +// `FFLSR: load-enable and synchronous active-high reset +// `FFLSRN: load-enable and synchronous active-low reset +// `FFLNR: load-enable without reset + +`ifdef VERILATOR +`define NO_SYNOPSYS_FF 1 +`endif + +`define REG_DFLT_CLK clk_i +`define REG_DFLT_RST rst_ni + +// Flip-Flop with asynchronous active-low reset +// __q: Q output of FF +// __d: D input of FF +// __reset_value: value assigned upon reset +// (__clk: clock input) +// (__arst_n: asynchronous reset, active-low) +`define FF(__q, __d, __reset_value, __clk = `REG_DFLT_CLK, __arst_n = `REG_DFLT_RST) \ + always_ff @(posedge (__clk) or negedge (__arst_n)) begin \ + if (!__arst_n) begin \ + __q <= (__reset_value); \ + end else begin \ + __q <= (__d); \ + end \ + end + +// Flip-Flop with asynchronous active-high reset +// __q: Q output of FF +// __d: D input of FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __arst: asynchronous reset, active-high +`define FFAR(__q, __d, __reset_value, __clk, __arst) \ + always_ff @(posedge (__clk) or posedge (__arst)) begin \ + if (__arst) begin \ + __q <= (__reset_value); \ + end else begin \ + __q <= (__d); \ + end \ + end + +// DEPRECATED - use `FF instead +// Flip-Flop with asynchronous active-low reset +// __q: Q output of FF +// __d: D input of FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __arst_n: asynchronous reset, active-low +`define FFARN(__q, __d, __reset_value, __clk, __arst_n) \ + `FF(__q, __d, __reset_value, __clk, __arst_n) + +// Flip-Flop with synchronous active-high reset +// __q: Q output of FF +// __d: D input of FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __reset_clk: reset input, active-high +`define FFSR(__q, __d, __reset_value, __clk, __reset_clk) \ + `ifndef NO_SYNOPSYS_FF \ + /``* synopsys sync_set_reset `"__reset_clk`" *``/ \ + `endif \ + always_ff @(posedge (__clk)) begin \ + __q <= (__reset_clk) ? (__reset_value) : (__d); \ + end + +// Flip-Flop with synchronous active-low reset +// __q: Q output of FF +// __d: D input of FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __reset_n_clk: reset input, active-low +`define FFSRN(__q, __d, __reset_value, __clk, __reset_n_clk) \ + `ifndef NO_SYNOPSYS_FF \ + /``* synopsys sync_set_reset `"__reset_n_clk`" *``/ \ + `endif \ + always_ff @(posedge (__clk)) begin \ + __q <= (!__reset_n_clk) ? (__reset_value) : (__d); \ + end + +// Always-enable Flip-Flop without reset +// __q: Q output of FF +// __d: D input of FF +// __clk: clock input +`define FFNR(__q, __d, __clk) \ + always_ff @(posedge (__clk)) begin \ + __q <= (__d); \ + end + +// Flip-Flop with load-enable and asynchronous active-low reset (implicit clock and reset) +// __q: Q output of FF +// __d: D input of FF +// __load: load d value into FF +// __reset_value: value assigned upon reset +// (__clk: clock input) +// (__arst_n: asynchronous reset, active-low) +`define FFL(__q, __d, __load, __reset_value, __clk = `REG_DFLT_CLK, __arst_n = `REG_DFLT_RST) \ + always_ff @(posedge (__clk) or negedge (__arst_n)) begin \ + if (!__arst_n) begin \ + __q <= (__reset_value); \ + end else begin \ + if (__load) begin \ + __q <= (__d); \ + end \ + end \ + end + +// Flip-Flop with load-enable and asynchronous active-high reset +// __q: Q output of FF +// __d: D input of FF +// __load: load d value into FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __arst: asynchronous reset, active-high +`define FFLAR(__q, __d, __load, __reset_value, __clk, __arst) \ + always_ff @(posedge (__clk) or posedge (__arst)) begin \ + if (__arst) begin \ + __q <= (__reset_value); \ + end else begin \ + if (__load) begin \ + __q <= (__d); \ + end \ + end \ + end + +// DEPRECATED - use `FFL instead +// Flip-Flop with load-enable and asynchronous active-low reset +// __q: Q output of FF +// __d: D input of FF +// __load: load d value into FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __arst_n: asynchronous reset, active-low +`define FFLARN(__q, __d, __load, __reset_value, __clk, __arst_n) \ + `FFL(__q, __d, __load, __reset_value, __clk, __arst_n) + +// Flip-Flop with load-enable and synchronous active-high reset +// __q: Q output of FF +// __d: D input of FF +// __load: load d value into FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __reset_clk: reset input, active-high +`define FFLSR(__q, __d, __load, __reset_value, __clk, __reset_clk) \ + `ifndef NO_SYNOPSYS_FF \ + /``* synopsys sync_set_reset `"__reset_clk`" *``/ \ + `endif \ + always_ff @(posedge (__clk)) begin \ + if (__reset_clk) begin \ + __q <= (__reset_value); \ + end else if (__load) begin \ + __q <= (__d); \ + end \ + end + +// Flip-Flop with load-enable and synchronous active-low reset +// __q: Q output of FF +// __d: D input of FF +// __load: load d value into FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __reset_n_clk: reset input, active-low +`define FFLSRN(__q, __d, __load, __reset_value, __clk, __reset_n_clk) \ + `ifndef NO_SYNOPSYS_FF \ + /``* synopsys sync_set_reset `"__reset_n_clk`" *``/ \ + `endif \ + always_ff @(posedge (__clk)) begin \ + if (!__reset_n_clk) begin \ + __q <= (__reset_value); \ + end else if (__load) begin \ + __q <= (__d); \ + end \ + end + +// Flip-Flop with load-enable and asynchronous active-low reset and synchronous clear +// __q: Q output of FF +// __d: D input of FF +// __load: load d value into FF +// __clear: assign reset value into FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __arst_n: asynchronous reset, active-low +`define FFLARNC(__q, __d, __load, __clear, __reset_value, __clk, __arst_n) \ + `ifndef NO_SYNOPSYS_FF \ + /``* synopsys sync_set_reset `"__clear`" *``/ \ + `endif \ + always_ff @(posedge (__clk) or negedge (__arst_n)) begin \ + if (!__arst_n) begin \ + __q <= (__reset_value); \ + end else begin \ + if (__clear) begin \ + __q <= (__reset_value); \ + end else if (__load) begin \ + __q <= (__d); \ + end \ + end \ + end + +// Flip-Flop with asynchronous active-low reset and synchronous clear +// __q: Q output of FF +// __d: D input of FF +// __clear: assign reset value into FF +// __reset_value: value assigned upon reset +// __clk: clock input +// __arst_n: asynchronous reset, active-low +`define FFARNC(__q, __d, __clear, __reset_value, __clk, __arst_n) \ + `ifndef NO_SYNOPSYS_FF \ + /``* synopsys sync_set_reset `"__clear`" *``/ \ + `endif \ + always_ff @(posedge (__clk) or negedge (__arst_n)) begin \ + if (!__arst_n) begin \ + __q <= (__reset_value); \ + end else begin \ + if (__clear) begin \ + __q <= (__reset_value); \ + end else begin \ + __q <= (__d); \ + end \ + end \ + end + +// Load-enable Flip-Flop without reset +// __q: Q output of FF +// __d: D input of FF +// __load: load d value into FF +// __clk: clock input +`define FFLNR(__q, __d, __load, __clk) \ + always_ff @(posedge (__clk)) begin \ + if (__load) begin \ + __q <= (__d); \ + end \ + end + +`endif diff --git a/rtl/pulp/rstgen.sv b/rtl/pulp/rstgen.sv new file mode 100644 index 0000000..a7dccc6 --- /dev/null +++ b/rtl/pulp/rstgen.sv @@ -0,0 +1,30 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Davide Rossi + +module rstgen ( + input logic clk_i, + input logic rst_ni, + input logic test_mode_i, + output logic rst_no, + output logic init_no +); + + rstgen_bypass i_rstgen_bypass ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .rst_test_mode_ni ( rst_ni ), + .test_mode_i ( test_mode_i ), + .rst_no ( rst_no ), + .init_no ( init_no ) + ); + +endmodule diff --git a/rtl/pulp/rstgen_bypass.sv b/rtl/pulp/rstgen_bypass.sv new file mode 100644 index 0000000..fbf0cc9 --- /dev/null +++ b/rtl/pulp/rstgen_bypass.sv @@ -0,0 +1,67 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Florian Zaruba +// Description: This module is a reset synchronizer with a dedicated reset bypass pin for testmode reset. +// Pro Tip: The wise Dr. Schaffner recommends at least 4 registers! + +module rstgen_bypass #( + parameter int unsigned NumRegs = 4 +) ( + input logic clk_i, + input logic rst_ni, + input logic rst_test_mode_ni, + input logic test_mode_i, + output logic rst_no, + output logic init_no +); + + // internal reset + logic rst_n; + + logic [NumRegs-1:0] synch_regs_q; + + // bypass mode: use (clock) multiplexers + tc_clk_mux2 i_tc_clk_mux2_rst_n ( + .clk0_i ( rst_ni ), + .clk1_i ( rst_test_mode_ni ), + .clk_sel_i ( test_mode_i ), + .clk_o ( rst_n ) + ); + + tc_clk_mux2 i_tc_clk_mux2_rst_no ( + .clk0_i ( synch_regs_q[NumRegs-1] ), + .clk1_i ( rst_test_mode_ni ), + .clk_sel_i ( test_mode_i ), + .clk_o ( rst_no ) + ); + + tc_clk_mux2 i_tc_clk_mux2_init_no ( + .clk0_i ( synch_regs_q[NumRegs-1] ), + .clk1_i ( 1'b1 ), + .clk_sel_i ( test_mode_i ), + .clk_o ( init_no ) + ); + + always @(posedge clk_i or negedge rst_n) begin + if (~rst_n) begin + synch_regs_q <= 0; + end else begin + synch_regs_q <= {synch_regs_q[NumRegs-2:0], 1'b1}; + end + end + `ifndef SYNTHESIS + `ifndef COMMON_CELLS_ASSERTS_OFF + initial begin : p_assertions + if (NumRegs < 1) $fatal(1, "At least one register is required."); + end + `endif + `endif +endmodule diff --git a/rtl/pulp/spill_register.sv b/rtl/pulp/spill_register.sv new file mode 100644 index 0000000..80ff37f --- /dev/null +++ b/rtl/pulp/spill_register.sv @@ -0,0 +1,46 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Fabian Schuiki + + +/// Wrapper around the flushable spill register to maintain back-ward +/// compatibility. +module spill_register #( + parameter type T = logic, + parameter bit Bypass = 1'b0 // make this spill register transparent +) ( + input logic clk_i , + input logic rst_ni , + input logic valid_i , + output logic ready_o , + input T data_i , + output logic valid_o , + input logic ready_i , + output T data_o +); + + spill_register_flushable #( + .T(T), + .Bypass(Bypass) + ) spill_register_flushable_i ( + .clk_i, + .rst_ni, + .valid_i, + .flush_i(1'b0), + .ready_o, + .data_i, + .valid_o, + .ready_i, + .data_o + ); + +endmodule diff --git a/rtl/pulp/spill_register_flushable.sv b/rtl/pulp/spill_register_flushable.sv new file mode 100644 index 0000000..cea3fc8 --- /dev/null +++ b/rtl/pulp/spill_register_flushable.sv @@ -0,0 +1,105 @@ +// Copyright 2021 ETH Zurich and University of Bologna. +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Fabian Schuiki + + +/// A register with handshakes that completely cuts any combinational paths +/// between the input and output. This spill register can be flushed. +module spill_register_flushable #( + parameter type T = logic, + parameter bit Bypass = 1'b0 // make this spill register transparent +) ( + input logic clk_i , + input logic rst_ni , + input logic valid_i , + input logic flush_i , + output logic ready_o , + input T data_i , + output logic valid_o , + input logic ready_i , + output T data_o +); + + if (Bypass) begin : gen_bypass + assign valid_o = valid_i; + assign ready_o = ready_i; + assign data_o = data_i; + end else begin : gen_spill_reg + // The A register. + T a_data_q; + logic a_full_q; + logic a_fill, a_drain; + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_data + if (!rst_ni) + a_data_q <= T'('0); + else if (a_fill) + a_data_q <= data_i; + end + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_full + if (!rst_ni) + a_full_q <= 0; + else if (a_fill || a_drain) + a_full_q <= a_fill; + end + + // The B register. + T b_data_q; + logic b_full_q; + logic b_fill, b_drain; + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_data + if (!rst_ni) + b_data_q <= T'('0); + else if (b_fill) + b_data_q <= a_data_q; + end + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_full + if (!rst_ni) + b_full_q <= 0; + else if (b_fill || b_drain) + b_full_q <= b_fill; + end + + // Fill the A register when the A or B register is empty. Drain the A register + // whenever it is full and being filled, or if a flush is requested. + assign a_fill = valid_i && ready_o && (!flush_i); + assign a_drain = (a_full_q && !b_full_q) || flush_i; + + // Fill the B register whenever the A register is drained, but the downstream + // circuit is not ready. Drain the B register whenever it is full and the + // downstream circuit is ready, or if a flush is requested. + assign b_fill = a_drain && (!ready_i) && (!flush_i); + assign b_drain = (b_full_q && ready_i) || flush_i; + + // We can accept input as long as register B is not full. + // Note: flush_i and valid_i must not be high at the same time, + // otherwise an invalid handshake may occur + assign ready_o = !a_full_q || !b_full_q; + + // The unit provides output as long as one of the registers is filled. + assign valid_o = a_full_q | b_full_q; + + // We empty the spill register before the slice register. + assign data_o = b_full_q ? b_data_q : a_data_q; + + `ifndef SYNTHESIS + `ifndef COMMON_CELLS_ASSERTS_OFF + flush_valid : assert property ( + @(posedge clk_i) disable iff (~rst_ni) (flush_i |-> ~valid_i)) else + $warning("Trying to flush and feed the spill register simultaneously. You will lose data!"); + `endif + `endif + end +endmodule diff --git a/rtl/pulp/sync.sv b/rtl/pulp/sync.sv new file mode 100644 index 0000000..b7bb781 --- /dev/null +++ b/rtl/pulp/sync.sv @@ -0,0 +1,37 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Antonio Pullini + +module sync #( + parameter int unsigned STAGES = 2, + parameter bit ResetValue = 1'b0 +) ( + input logic clk_i, + input logic rst_ni, + input logic serial_i, + output logic serial_o +); + + (* dont_touch = "true" *) + (* async_reg = "true" *) + logic [STAGES-1:0] reg_q; + + always_ff @(posedge clk_i, negedge rst_ni) begin + if (!rst_ni) begin + reg_q <= {STAGES{ResetValue}}; + end else begin + reg_q <= {reg_q[STAGES-2:0], serial_i}; + end + end + + assign serial_o = reg_q[STAGES-1]; + +endmodule diff --git a/rtl/pulp/tc_clk.sv b/rtl/pulp/tc_clk.sv new file mode 100644 index 0000000..3ab329e --- /dev/null +++ b/rtl/pulp/tc_clk.sv @@ -0,0 +1,120 @@ +// Copyright 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +module tc_clk_and2 ( + input logic clk0_i, + input logic clk1_i, + output logic clk_o +); + + assign clk_o = clk0_i & clk1_i; + +endmodule + +module tc_clk_buffer ( + input logic clk_i, + output logic clk_o +); + + assign clk_o = clk_i; + +endmodule + +// Description: Behavioral model of an integrated clock-gating cell (ICG) +module tc_clk_gating #( + /// This paramaeter is a hint for tool/technology specific mappings of this + /// tech_cell. It indicates wether this particular clk gate instance is + /// required for functional correctness or just instantiated for power + /// savings. If IS_FUNCTIONAL == 0, technology specific mappings might + /// replace this cell with a feedthrough connection without any gating. + parameter bit IS_FUNCTIONAL = 1'b1 +)( + input logic clk_i, + input logic en_i, + input logic test_en_i, + output logic clk_o +); + + logic clk_en; + + always_latch begin + if (clk_i == 1'b0) clk_en <= en_i | test_en_i; + end + + assign clk_o = clk_i & clk_en; + +endmodule + +module tc_clk_inverter ( + input logic clk_i, + output logic clk_o +); + + assign clk_o = ~clk_i; + +endmodule + +// Warning: Typical clock mux cells of a technologies std cell library ARE NOT +// GLITCH FREE!! The only difference to a regular multiplexer cell is that they +// feature balanced rise- and fall-times. In other words: SWITCHING FROM ONE +// CLOCK TO THE OTHER CAN INTRODUCE GLITCHES. ALSO, GLITCHES ON THE SELECT LINE +// DIRECTLY TRANSLATE TO GLITCHES ON THE OUTPUT CLOCK!! This cell is only +// intended to be used for quasi-static switching between clocks when one of the +// clocks is anyway inactive or if the downstream logic remains gated or in +// reset state during the transition phase. If you need dynamic switching +// between arbitrary input clocks without introducing glitches, have a look at +// the clk_mux_glitch_free cell in the pulp-platform/common_cells repository. +module tc_clk_mux2 ( + input logic clk0_i, + input logic clk1_i, + input logic clk_sel_i, + output logic clk_o +); + + assign clk_o = (clk_sel_i) ? clk1_i : clk0_i; + +endmodule + +module tc_clk_xor2 ( + input logic clk0_i, + input logic clk1_i, + output logic clk_o +); + + assign clk_o = clk0_i ^ clk1_i; + +endmodule + +module tc_clk_or2 ( + input logic clk0_i, + input logic clk1_i, + output logic clk_o +); + + assign clk_o = clk0_i | clk1_i; + +endmodule + +`ifndef SYNTHESIS +module tc_clk_delay #( + parameter int unsigned Delay = 300ps +) ( + input logic in_i, + output logic out_o +); + +// pragma translate_off +`ifndef VERILATOR + assign #(Delay) out_o = in_i; +`endif +// pragma translate_on + +endmodule +`endif diff --git a/rtl/pulp/tc_clk_xilinx.sv b/rtl/pulp/tc_clk_xilinx.sv new file mode 100644 index 0000000..e45885b --- /dev/null +++ b/rtl/pulp/tc_clk_xilinx.sv @@ -0,0 +1,96 @@ +// Copyright 2019 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Cells to be used for Xilinx FPGA mappings + +module tc_clk_and2 ( + input logic clk0_i, + input logic clk1_i, + output logic clk_o +); + + assign clk_o = clk0_i & clk1_i; + +endmodule + +module tc_clk_buffer ( + input logic clk_i, + output logic clk_o +); + + assign clk_o = clk_i; + +endmodule + +// Disable clock gating on FPGA as it behaves differently than expected +module tc_clk_gating #( + /// This paramaeter is a hint for tool/technology specific mappings of this + /// tech_cell. It indicates wether this particular clk gate instance is + /// required for functional correctness or just instantiated for power + /// savings. If IS_FUNCTIONAL == 0, technology specific mappings might + /// replace this cell with a feedthrough connection without any gating. + parameter bit IS_FUNCTIONAL = 1'b1 +)( + input logic clk_i, + input logic en_i, + input logic test_en_i, + output logic clk_o +); + + assign clk_o = clk_i; + +endmodule + +module tc_clk_inverter ( + input logic clk_i, + output logic clk_o +); + + assign clk_o = ~clk_i; + +endmodule + +module tc_clk_mux2 ( + input logic clk0_i, + input logic clk1_i, + input logic clk_sel_i, + output logic clk_o +); + + BUFGMUX i_BUFGMUX ( + .S ( clk_sel_i ), + .I0 ( clk0_i ), + .I1 ( clk1_i ), + .O ( clk_o ) + ); + +endmodule + +module tc_clk_xor2 ( + input logic clk0_i, + input logic clk1_i, + output logic clk_o +); + + assign clk_o = clk0_i ^ clk1_i; + +endmodule + +module tc_clk_or2 ( + input logic clk0_i, + input logic clk1_i, + output logic clk_o +); + + assign clk_o = clk0_i | clk1_i; + +endmodule + + diff --git a/sim/compile.do b/sim/compile.do index 54a67c8..0c27327 100755 --- a/sim/compile.do +++ b/sim/compile.do @@ -5,6 +5,9 @@ vlib work vlog -f files_rtl.f -f files_sim.f +incdir+../rtl +incdir+../svas/ +define+INCLUDE_SVAS +# In case of AXI4_master_cdc.sv use, uncomment the following line. +# vlog -f files_pulp.f +incdir+../rtl/pulp/include +incdir+../rtl + vopt +acc tb -o tbopt vsim tbopt -onfinish "stop" diff --git a/sim/files_pulp.f b/sim/files_pulp.f new file mode 100644 index 0000000..73cffdc --- /dev/null +++ b/sim/files_pulp.f @@ -0,0 +1,16 @@ +-sv + +../rtl/pulp/binary_to_gray.sv +../rtl/pulp/gray_to_binary.sv +../rtl/pulp/spill_register_flushable.sv +../rtl/pulp/spill_register.sv +# Only in Xilinx FPGA implementation replace +# tc_clk.sv with tc_clk_xilinx.sv +../rtl/pulp/tc_clk.sv + +../rtl/pulp/sync.sv +../rtl/pulp/rstgen_bypass.sv +../rtl/pulp/rstgen.sv +../rtl/pulp/cdc_fifo_gray.sv + +../rtl/AXI4_master_cdc.sv \ No newline at end of file