From 39c86c8ed49607b34d02d0df2de624ec77d222fd Mon Sep 17 00:00:00 2001
From: Tristan Gingold <tristan.gingold@cern.ch>
Date: Tue, 22 Jan 2019 14:27:11 +0100
Subject: [PATCH] Add gc_sync_word_wr module.

---
 modules/common/gc_sync_word_wr.vhd         | 134 +++++++++++++++++++++
 sim/gc_sync_word_wr/run.do                 |  15 +++
 sim/gc_sync_word_wr/tb_gc_sync_word_wr.vhd |  65 ++++++++++
 sim/gc_sync_word_wr/wave.do                |  33 +++++
 4 files changed, 247 insertions(+)
 create mode 100644 modules/common/gc_sync_word_wr.vhd
 create mode 100644 sim/gc_sync_word_wr/run.do
 create mode 100644 sim/gc_sync_word_wr/tb_gc_sync_word_wr.vhd
 create mode 100644 sim/gc_sync_word_wr/wave.do

diff --git a/modules/common/gc_sync_word_wr.vhd b/modules/common/gc_sync_word_wr.vhd
new file mode 100644
index 0000000..2434352
--- /dev/null
+++ b/modules/common/gc_sync_word_wr.vhd
@@ -0,0 +1,134 @@
+--------------------------------------------------------------------------------
+-- CERN BE-CO-HT
+-- General Cores Library
+-- https://www.ohwr.org/projects/general-cores
+--------------------------------------------------------------------------------
+--
+-- unit name:   gc_sync_word_wr
+--
+-- description: Synchronizer for writing a word with an ack.
+--   Used to transfer a word from the input clock domain to the output clock
+--   domain.  User provides the data and a pulse write signal to transfer the
+--   data.  When the data are transfered, a write pulse is generated on the
+--   output side along with the data, and an acknowledge is geenrated on the
+--   input side.  Once the user request a transfer, no new data should be
+--   requested for a transfer until the ack was received.
+--
+--------------------------------------------------------------------------------
+-- Copyright CERN 2019
+--------------------------------------------------------------------------------
+-- Copyright and related rights are licensed under the Solderpad Hardware
+-- License, Version 2.0 (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-2.0.
+-- 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.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity gc_sync_word_wr is
+  generic (
+    width : positive := 8);
+  port (
+    --  Input clock and reset
+    clk_in_i    : in  std_logic;
+    rst_in_n_i  : in  std_logic;
+    --  Output clock.
+    clk_out_i   : in  std_logic;
+    rst_out_n_i : in std_logic;
+    --  Input data
+    data_i      : in  std_logic_vector (width - 1 downto 0);
+    --  Input wr
+    wr_i        : in  std_logic;
+    ack_o       : out std_logic;
+    --  Output data
+    data_o      : out std_logic_vector (width - 1 downto 0);
+    wr_o        : out std_logic);
+end entity;
+
+architecture behav of gc_sync_word_wr is
+  signal data : std_logic_vector (width - 1 downto 0);
+  signal in_busy : std_logic;
+  signal in_progress : std_logic;
+
+  signal ack_start, ack_done : std_logic;
+
+  --  Synchronized extended wr_i signal.
+  signal wr_out   : std_logic;
+  --  Internal pulse for wr_o, active one cycle before wr_o.
+  signal wr_out_p : std_logic;
+begin
+  --  Handle incoming request.
+  process(clk_in_i)
+  begin
+    if rising_edge(clk_in_i) then
+      if rst_in_n_i = '0' then
+        in_progress <= '0';
+        in_busy <= '0';
+        data <= (others => '0');
+        ack_o <= '0';
+      else
+        ack_o <= '0';
+        if in_busy = '0' then
+          if wr_i = '1' then
+            in_progress <= '1';
+            in_busy <= '1';
+            data <= data_i;
+          end if;
+        else
+          assert wr_i = '0' report "request while previous one not completed"
+            severity error;
+          if ack_start = '1' then
+            in_progress <= '0';
+          end if;
+          if ack_done = '1' then
+            assert in_progress = '0';
+            in_busy <= '0';
+            ack_o <= '1';
+          end if;
+        end if;
+      end if;
+    end if;
+  end process;
+
+  cmp_wr_sync : entity work.gc_sync_ffs
+    port map (
+      clk_i => clk_out_i,
+      rst_n_i => rst_out_n_i,
+      data_i => in_progress,
+      synced_o => wr_out,
+      ppulse_o => wr_out_p);
+
+  --  Outputs.
+  process (clk_out_i)
+  begin
+    if rising_edge(clk_out_i) then
+      if rst_out_n_i = '0' then
+        data_o <= (others => '0');
+        wr_o <= '0';
+      else
+        if wr_out_p = '1' then
+          --  Data are stable.
+          data_o <= data;
+          wr_o <= '1';
+        else
+          wr_o <= '0';
+        end if;
+      end if;
+    end if;
+  end process;
+
+  --  Ack.
+  cmp_ack_sync : entity work.gc_sync_ffs
+    port map (
+      clk_i => clk_in_i,
+      rst_n_i => rst_in_n_i,
+      data_i => wr_out,
+      ppulse_o => ack_start,
+      npulse_o => ack_done);
+end behav;
diff --git a/sim/gc_sync_word_wr/run.do b/sim/gc_sync_word_wr/run.do
new file mode 100644
index 0000000..7dc98e4
--- /dev/null
+++ b/sim/gc_sync_word_wr/run.do
@@ -0,0 +1,15 @@
+vlib work
+
+vcom -explicit -93 "../../modules/common/gc_sync_ffs.vhd"
+vcom -explicit -93 "../../modules/common/gc_sync_word_wr.vhd"
+
+vcom -explicit -93 "tb_gc_sync_word_wr.vhd"
+
+vsim -t 1ps -voptargs="+acc" -lib work work.tb_gc_sync_word_wr
+
+radix -hexadecimal
+#add wave *
+do wave.do
+
+run 4 us
+wave zoomfull
diff --git a/sim/gc_sync_word_wr/tb_gc_sync_word_wr.vhd b/sim/gc_sync_word_wr/tb_gc_sync_word_wr.vhd
new file mode 100644
index 0000000..dea3bd8
--- /dev/null
+++ b/sim/gc_sync_word_wr/tb_gc_sync_word_wr.vhd
@@ -0,0 +1,65 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity tb_gc_sync_word_wr is
+end;
+
+architecture arch of tb_gc_sync_word_wr is
+  signal din, dout : std_logic_vector(7 downto 0);
+  signal clki, clko : std_logic := '0';
+  signal rsti, rsto : std_logic;
+  signal wri, wro : std_logic;
+  signal ack : std_logic;
+begin
+  clki <= not clki after 10 ns;
+  clko <= not clko after 7 ns;
+
+  rsti <= '0', '1' after 30 ns;
+  rsto <= '0', '1' after 25 ns;
+
+  cmp_tb : entity work.gc_sync_word_wr
+    generic map (
+      width => 8)
+    port map (
+      clk_in_i => clki,
+      rst_in_n_i => rsti,
+      clk_out_i => clko,
+      rst_out_n_i => rsto,
+      data_i => din,
+      wr_i => wri,
+      ack_o => ack,
+      data_o => dout,
+      wr_o => wro);
+
+  process
+    procedure send_value (dat : std_logic_vector(7 downto 0)) is
+    begin
+      din <= dat;
+      wait until rising_edge(clki);
+      wri <= '1';
+      wait until rising_edge(clki);
+      wri <= '0';
+    end send_value;
+
+    --  Wait until ack.
+    procedure wait_ack is
+    begin
+      loop
+        wait until rising_edge(clki);
+        exit when ack = '1';
+      end loop;
+    end wait_ack;
+  begin
+    wri <= '0';
+    wait until rsti = '1';
+    wait until rising_edge(clki);
+
+    send_value(x"a5");
+    wait_ack;
+
+    send_value(x"7b");
+    wait_ack;
+
+    wait;
+  end process;
+end arch;
diff --git a/sim/gc_sync_word_wr/wave.do b/sim/gc_sync_word_wr/wave.do
new file mode 100644
index 0000000..f4fea1a
--- /dev/null
+++ b/sim/gc_sync_word_wr/wave.do
@@ -0,0 +1,33 @@
+onerror {resume}
+quietly WaveActivateNextPane {} 0
+add wave -noupdate /tb_gc_sync_word_wr/din
+add wave -noupdate /tb_gc_sync_word_wr/dout
+add wave -noupdate /tb_gc_sync_word_wr/clki
+add wave -noupdate /tb_gc_sync_word_wr/clko
+add wave -noupdate /tb_gc_sync_word_wr/rsti
+add wave -noupdate /tb_gc_sync_word_wr/rsto
+add wave -noupdate /tb_gc_sync_word_wr/wri
+add wave -noupdate /tb_gc_sync_word_wr/wro
+add wave -noupdate /tb_gc_sync_word_wr/ack
+add wave -noupdate /tb_gc_sync_word_wr/cmp_tb/in_busy
+add wave -noupdate /tb_gc_sync_word_wr/cmp_tb/in_progress
+add wave -noupdate /tb_gc_sync_word_wr/cmp_tb/ack_start
+add wave -noupdate /tb_gc_sync_word_wr/cmp_tb/ack_done
+TreeUpdate [SetDefaultTree]
+WaveRestoreCursors {{Cursor 1} {0 ps} 0}
+quietly wave cursor active 0
+configure wave -namecolwidth 150
+configure wave -valuecolwidth 100
+configure wave -justifyvalue left
+configure wave -signalnamewidth 1
+configure wave -snapdistance 10
+configure wave -datasetprefix 0
+configure wave -rowmargin 4
+configure wave -childrowmargin 2
+configure wave -gridoffset 0
+configure wave -gridperiod 1
+configure wave -griddelta 40
+configure wave -timeline 0
+configure wave -timelineunits ps
+update
+WaveRestoreZoom {0 ps} {262500 ps}
-- 
GitLab