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