Line 36... |
Line 36... |
-- Logic in the system clock domain accepts transmission requests through
|
-- Logic in the system clock domain accepts transmission requests through
|
-- the external interface of the entity. Pending requests are translated
|
-- the external interface of the entity. Pending requests are translated
|
-- into a stream of tokens. The tokens are pushed to the txclk domain through
|
-- into a stream of tokens. The tokens are pushed to the txclk domain through
|
-- the FIFO buffer as described above.
|
-- the FIFO buffer as described above.
|
--
|
--
|
-- The data path through the txclk domain is divided into stages A through F
|
-- The data path through the txclk domain is divided into stages B through F
|
-- in a half-hearted attempt to keep things simple. Stage A is just a
|
-- in a half-hearted attempt to keep things simple.
|
-- synchronizer for the buffer status flags from the system clock domain.
|
|
--
|
--
|
-- Stage B takes a token from the FIFO buffer and updates a buffer status
|
-- Stage B takes a token from the FIFO buffer and updates a buffer status
|
-- flag to indicate that the buffer slot needs to be refilled. If the FIFO
|
-- flag to indicate that the buffer slot needs to be refilled. If the FIFO
|
-- is empty, a NULL is inserted. Stage B is triggered one clock after
|
-- is empty, a NULL is inserted. Stage B is triggered one clock after
|
-- stage E switches to a new token. If the previous token was ESC, stage B
|
-- stage E switches to a new token. If the previous token was ESC, stage B
|
Line 182... |
Line 181... |
|
|
-- Turn off FSM extraction to avoid synchronization problems.
|
-- Turn off FSM extraction to avoid synchronization problems.
|
attribute FSM_EXTRACT: string;
|
attribute FSM_EXTRACT: string;
|
attribute FSM_EXTRACT of spwxmit_fast: entity is "NO";
|
attribute FSM_EXTRACT of spwxmit_fast: entity is "NO";
|
|
|
-- Turn off register duplication to avoid synchronization problems.
|
|
attribute REGISTER_DUPLICATION: string;
|
|
attribute REGISTER_DUPLICATION of spwxmit_fast: entity is "FALSE";
|
|
|
|
end entity spwxmit_fast;
|
end entity spwxmit_fast;
|
|
|
architecture spwxmit_fast_arch of spwxmit_fast is
|
architecture spwxmit_fast_arch of spwxmit_fast is
|
|
|
-- Convert boolean to std_logic.
|
-- Convert boolean to std_logic.
|
Line 208... |
Line 203... |
-- Registers in txclk domain
|
-- Registers in txclk domain
|
type txregs_type is record
|
type txregs_type is record
|
-- sync to system clock domain
|
-- sync to system clock domain
|
txflip0: std_ulogic;
|
txflip0: std_ulogic;
|
txflip1: std_ulogic;
|
txflip1: std_ulogic;
|
-- stage A
|
|
a_sysflip0: std_logic_vector(1 downto 0);
|
|
a_sysflip1: std_logic_vector(1 downto 0);
|
|
-- stage B
|
-- stage B
|
b_update: std_ulogic;
|
b_update: std_ulogic;
|
b_mux: std_ulogic;
|
b_mux: std_ulogic;
|
b_txflip: std_ulogic;
|
b_txflip: std_ulogic;
|
b_valid: std_ulogic;
|
b_valid: std_ulogic;
|
Line 243... |
Line 235... |
txclkcnt: std_logic_vector(7 downto 0);
|
txclkcnt: std_logic_vector(7 downto 0);
|
txclkcy: std_logic_vector(2 downto 0);
|
txclkcy: std_logic_vector(2 downto 0);
|
txclkdone: std_logic_vector(1 downto 0);
|
txclkdone: std_logic_vector(1 downto 0);
|
txclkdiv: std_logic_vector(7 downto 0);
|
txclkdiv: std_logic_vector(7 downto 0);
|
txdivnorm: std_ulogic;
|
txdivnorm: std_ulogic;
|
txdivsafe: std_logic_vector(1 downto 0);
|
|
-- tx enable logic
|
|
txensync: std_logic_vector(1 downto 0);
|
|
end record;
|
end record;
|
|
|
-- Registers in system clock domain
|
-- Registers in system clock domain
|
type regs_type is record
|
type regs_type is record
|
-- sync status to txclk domain
|
-- sync status to txclk domain
|
Line 262... |
Line 251... |
sysflip0: std_ulogic;
|
sysflip0: std_ulogic;
|
sysflip1: std_ulogic;
|
sysflip1: std_ulogic;
|
token0: token_type;
|
token0: token_type;
|
token1: token_type;
|
token1: token_type;
|
tokmux: std_ulogic;
|
tokmux: std_ulogic;
|
-- sync feedback from txclk domain
|
|
txflip0: std_logic_vector(1 downto 0);
|
|
txflip1: std_logic_vector(1 downto 0);
|
|
-- transmitter management
|
-- transmitter management
|
pend_fct: std_ulogic; -- '1' if an outgoing FCT is pending
|
pend_fct: std_ulogic; -- '1' if an outgoing FCT is pending
|
pend_char: std_ulogic; -- '1' if an outgoing N-Char is pending
|
pend_char: std_ulogic; -- '1' if an outgoing N-Char is pending
|
pend_data: std_logic_vector(8 downto 0); -- control flag and data bits of pending char
|
pend_data: std_logic_vector(8 downto 0); -- control flag and data bits of pending char
|
pend_tick: std_ulogic; -- '1' if an outgoing time tick is pending
|
pend_tick: std_ulogic; -- '1' if an outgoing time tick is pending
|
Line 294... |
Line 280... |
sysflip0 => '0',
|
sysflip0 => '0',
|
sysflip1 => '0',
|
sysflip1 => '0',
|
token0 => token_reset,
|
token0 => token_reset,
|
token1 => token_reset,
|
token1 => token_reset,
|
tokmux => '0',
|
tokmux => '0',
|
txflip0 => "00",
|
|
txflip1 => "00",
|
|
pend_fct => '0',
|
pend_fct => '0',
|
pend_char => '0',
|
pend_char => '0',
|
pend_data => (others => '0'),
|
pend_data => (others => '0'),
|
pend_tick => '0',
|
pend_tick => '0',
|
pend_time => (others => '0'),
|
pend_time => (others => '0'),
|
allow_fct => '0',
|
allow_fct => '0',
|
allow_char => '0',
|
allow_char => '0',
|
sent_fct => '0' );
|
sent_fct => '0' );
|
|
|
|
-- Signals that are re-synchronized from system clock to txclk domain.
|
|
type synctx_type is record
|
|
rstn: std_ulogic;
|
|
sysflip0: std_ulogic;
|
|
sysflip1: std_ulogic;
|
|
txen: std_ulogic;
|
|
txdivsafe: std_ulogic;
|
|
end record;
|
|
|
|
-- Signals that are re-synchronized from txclk to system clock domain.
|
|
type syncsys_type is record
|
|
txflip0: std_ulogic;
|
|
txflip1: std_ulogic;
|
|
end record;
|
|
|
-- Registers
|
-- Registers
|
signal rtx: txregs_type;
|
signal rtx: txregs_type;
|
signal rtxin: txregs_type;
|
signal rtxin: txregs_type;
|
signal r: regs_type := regs_reset;
|
signal r: regs_type := regs_reset;
|
signal rin: regs_type;
|
signal rin: regs_type;
|
|
|
-- Reset synchronizer for txclk domain
|
-- Synchronized signals after crossing clock domains.
|
signal s_tx_rst_sync: std_logic_vector(1 downto 0) := "11";
|
signal synctx: synctx_type;
|
signal s_tx_reset: std_ulogic := '1';
|
signal syncsys: syncsys_type;
|
|
|
-- Output flip-flops
|
-- Output flip-flops
|
signal s_spwdo: std_logic;
|
signal s_spwdo: std_logic;
|
signal s_spwso: std_logic;
|
signal s_spwso: std_logic;
|
|
|
Line 326... |
Line 325... |
attribute IOB of s_spwdo: signal is "TRUE";
|
attribute IOB of s_spwdo: signal is "TRUE";
|
attribute IOB of s_spwso: signal is "TRUE";
|
attribute IOB of s_spwso: signal is "TRUE";
|
|
|
begin
|
begin
|
|
|
|
-- Reset synchronizer for txclk domain.
|
|
synctx_rst: syncdff
|
|
port map ( clk => txclk, rst => rst, di => '1', do => synctx.rstn );
|
|
|
|
-- Synchronize signals from system clock domain to txclk domain.
|
|
synctx_sysflip0: syncdff
|
|
port map ( clk => txclk, rst => rst, di => r.sysflip0, do => synctx.sysflip0 );
|
|
synctx_sysflip1: syncdff
|
|
port map ( clk => txclk, rst => rst, di => r.sysflip1, do => synctx.sysflip1 );
|
|
synctx_txen: syncdff
|
|
port map ( clk => txclk, rst => rst, di => r.txenreg, do => synctx.txen );
|
|
synctx_txdivsafe: syncdff
|
|
port map ( clk => txclk, rst => rst, di => r.txdivsafe, do => synctx.txdivsafe );
|
|
|
|
-- Synchronize signals from txclk domain to system clock domain.
|
|
syncsys_txflip0: syncdff
|
|
port map ( clk => clk, rst => rst, di => rtx.txflip0, do => syncsys.txflip0 );
|
|
syncsys_txflip1: syncdff
|
|
port map ( clk => clk, rst => rst, di => rtx.txflip1, do => syncsys.txflip1 );
|
|
|
-- Drive SpaceWire output signals
|
-- Drive SpaceWire output signals
|
spw_do <= s_spwdo;
|
spw_do <= s_spwdo;
|
spw_so <= s_spwso;
|
spw_so <= s_spwso;
|
|
|
-- Combinatorial process
|
-- Combinatorial process
|
process (r, rtx, rst, divcnt, xmiti, s_tx_reset) is
|
process (r, rtx, rst, divcnt, xmiti, synctx, syncsys) is
|
variable v: regs_type;
|
variable v: regs_type;
|
variable vtx: txregs_type;
|
variable vtx: txregs_type;
|
variable v_needtoken: std_ulogic;
|
variable v_needtoken: std_ulogic;
|
variable v_havetoken: std_ulogic;
|
variable v_havetoken: std_ulogic;
|
variable v_token: token_type;
|
variable v_token: token_type;
|
Line 346... |
Line 365... |
v_havetoken := '0';
|
v_havetoken := '0';
|
v_token := token_reset;
|
v_token := token_reset;
|
|
|
-- ---- FAST CLOCK DOMAIN ----
|
-- ---- FAST CLOCK DOMAIN ----
|
|
|
-- Stage A: Synchronize token buffer counts from system clock domain.
|
|
vtx.a_sysflip0(0) := r.sysflip0;
|
|
vtx.a_sysflip0(1) := rtx.a_sysflip0(0);
|
|
vtx.a_sysflip1(0) := r.sysflip1;
|
|
vtx.a_sysflip1(1) := rtx.a_sysflip1(0);
|
|
|
|
-- Stage B: Multiplex tokens from system clock domain.
|
-- Stage B: Multiplex tokens from system clock domain.
|
-- Update stage B three bit periods after updating stage C
|
-- Update stage B three bit periods after updating stage C
|
-- (i.e. in time for the next update of stage C).
|
-- (i.e. in time for the next update of stage C).
|
-- Do not update stage B if stage C is indicating that it needs to
|
-- Do not update stage B if stage C is indicating that it needs to
|
-- send a second token to complete its task.
|
-- send a second token to complete its task.
|
Line 366... |
Line 379... |
vtx.b_txflip := rtx.txflip1;
|
vtx.b_txflip := rtx.txflip1;
|
end if;
|
end if;
|
if rtx.b_update = '1' then
|
if rtx.b_update = '1' then
|
if rtx.b_mux = '0' then
|
if rtx.b_mux = '0' then
|
-- get token from slot 0
|
-- get token from slot 0
|
vtx.b_valid := rtx.a_sysflip0(1) xor rtx.b_txflip;
|
vtx.b_valid := synctx.sysflip0 xor rtx.b_txflip;
|
vtx.b_token := r.token0;
|
vtx.b_token := r.token0;
|
-- update mux flag if we got a valid token
|
-- update mux flag if we got a valid token
|
vtx.b_mux := rtx.a_sysflip0(1) xor rtx.b_txflip;
|
vtx.b_mux := synctx.sysflip0 xor rtx.b_txflip;
|
vtx.txflip0 := rtx.a_sysflip0(1);
|
vtx.txflip0 := synctx.sysflip0;
|
vtx.txflip1 := rtx.txflip1;
|
vtx.txflip1 := rtx.txflip1;
|
else
|
else
|
-- get token from slot 1
|
-- get token from slot 1
|
vtx.b_valid := rtx.a_sysflip1(1) xor rtx.b_txflip;
|
vtx.b_valid := synctx.sysflip1 xor rtx.b_txflip;
|
vtx.b_token := r.token1;
|
vtx.b_token := r.token1;
|
-- update mux flag if we got a valid token
|
-- update mux flag if we got a valid token
|
vtx.b_mux := not (rtx.a_sysflip1(1) xor rtx.b_txflip);
|
vtx.b_mux := not (synctx.sysflip1 xor rtx.b_txflip);
|
vtx.txflip0 := rtx.txflip0;
|
vtx.txflip0 := rtx.txflip0;
|
vtx.txflip1 := rtx.a_sysflip1(1);
|
vtx.txflip1 := synctx.sysflip1;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
-- Stage C: Prepare to transmit EOP, EEP or a data character.
|
-- Stage C: Prepare to transmit EOP, EEP or a data character.
|
vtx.c_update := rtx.txclken and rtx.e_count(3);
|
vtx.c_update := rtx.txclken and rtx.e_count(3);
|
Line 495... |
Line 508... |
vtx.txclkcy := "000";
|
vtx.txclkcy := "000";
|
vtx.txclkdone := "00";
|
vtx.txclkdone := "00";
|
end if;
|
end if;
|
|
|
-- Synchronize txclkdiv
|
-- Synchronize txclkdiv
|
vtx.txdivsafe(0) := r.txdivsafe;
|
if synctx.txdivsafe = '1' then
|
vtx.txdivsafe(1) := rtx.txdivsafe(0);
|
|
if rtx.txdivsafe(1) = '1' then
|
|
vtx.txclkdiv := r.txdivreg;
|
vtx.txclkdiv := r.txdivreg;
|
vtx.txdivnorm := r.txdivnorm;
|
vtx.txdivnorm := r.txdivnorm;
|
end if;
|
end if;
|
|
|
-- Synchronize txen signal.
|
|
vtx.txensync(0) := r.txenreg;
|
|
vtx.txensync(1) := rtx.txensync(0);
|
|
|
|
-- Transmitter disabled.
|
-- Transmitter disabled.
|
if rtx.txensync(1) = '0' then
|
if synctx.txen = '0' then
|
vtx.txflip0 := '0';
|
vtx.txflip0 := '0';
|
vtx.txflip1 := '0';
|
vtx.txflip1 := '0';
|
vtx.b_update := '0';
|
vtx.b_update := '0';
|
vtx.b_mux := '0';
|
vtx.b_mux := '0';
|
vtx.b_valid := '0';
|
vtx.b_valid := '0';
|
Line 526... |
Line 533... |
vtx.e_parity := '0';
|
vtx.e_parity := '0';
|
vtx.e_count := (0 => '1', others => '0');
|
vtx.e_count := (0 => '1', others => '0');
|
end if;
|
end if;
|
|
|
-- Reset.
|
-- Reset.
|
if s_tx_reset = '1' then
|
if synctx.rstn = '0' then
|
vtx.f_spwdo := '0';
|
vtx.f_spwdo := '0';
|
vtx.f_spwso := '0';
|
vtx.f_spwso := '0';
|
vtx.txensync := "00";
|
|
vtx.txclken := '0';
|
vtx.txclken := '0';
|
vtx.txclkpre := '1';
|
vtx.txclkpre := '1';
|
vtx.txclkcnt := (others => '0');
|
vtx.txclkcnt := (others => '0');
|
vtx.txclkdiv := (others => '0');
|
vtx.txclkdiv := (others => '0');
|
vtx.txdivnorm := '0';
|
vtx.txdivnorm := '0';
|
Line 564... |
Line 570... |
-- Pass falling edge of txen signal as soon as possible.
|
-- Pass falling edge of txen signal as soon as possible.
|
if xmiti.txen = '0' then
|
if xmiti.txen = '0' then
|
v.txenreg := '0';
|
v.txenreg := '0';
|
end if;
|
end if;
|
|
|
-- Synchronize feedback from txclk domain.
|
|
v.txflip0(0) := rtx.txflip0;
|
|
v.txflip0(1) := r.txflip0(0);
|
|
v.txflip1(0) := rtx.txflip1;
|
|
v.txflip1(1) := r.txflip1(0);
|
|
|
|
-- Store requests for FCT transmission.
|
-- Store requests for FCT transmission.
|
if xmiti.fct_in = '1' and r.allow_fct = '1' then
|
if xmiti.fct_in = '1' and r.allow_fct = '1' then
|
v.pend_fct := '1';
|
v.pend_fct := '1';
|
end if;
|
end if;
|
|
|
Line 592... |
Line 592... |
|
|
else
|
else
|
|
|
-- Determine if a new token is needed.
|
-- Determine if a new token is needed.
|
if r.tokmux = '0' then
|
if r.tokmux = '0' then
|
if r.sysflip0 = r.txflip0(1) then
|
if r.sysflip0 = syncsys.txflip0 then
|
v_needtoken := '1';
|
v_needtoken := '1';
|
end if;
|
end if;
|
else
|
else
|
if r.sysflip1 = r.txflip1(1) then
|
if r.sysflip1 = syncsys.txflip1 then
|
v_needtoken := '1';
|
v_needtoken := '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
-- Prepare new token.
|
-- Prepare new token.
|
Line 640... |
Line 640... |
end if;
|
end if;
|
|
|
-- Put new token in slot.
|
-- Put new token in slot.
|
if v_havetoken = '1' then
|
if v_havetoken = '1' then
|
if r.tokmux = '0' then
|
if r.tokmux = '0' then
|
if r.sysflip0 = r.txflip0(1) then
|
if r.sysflip0 = syncsys.txflip0 then
|
v.sysflip0 := not r.sysflip0;
|
v.sysflip0 := not r.sysflip0;
|
v.token0 := v_token;
|
v.token0 := v_token;
|
v.tokmux := '1';
|
v.tokmux := '1';
|
end if;
|
end if;
|
else
|
else
|
if r.sysflip1 = r.txflip1(1) then
|
if r.sysflip1 = syncsys.txflip1 then
|
v.sysflip1 := not r.sysflip1;
|
v.sysflip1 := not r.sysflip1;
|
v.token1 := v_token;
|
v.token1 := v_token;
|
v.tokmux := '0';
|
v.tokmux := '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
Line 716... |
Line 716... |
-- update registers
|
-- update registers
|
r <= rin;
|
r <= rin;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Reset synchronizer for txclk domain
|
|
process (txclk, rst) is
|
|
begin
|
|
if rst = '1' then
|
|
s_tx_rst_sync <= "11";
|
|
s_tx_reset <= '1';
|
|
elsif rising_edge(txclk) then
|
|
s_tx_rst_sync <= s_tx_rst_sync(0 downto 0) & "0";
|
|
s_tx_reset <= s_tx_rst_sync(1);
|
|
end if;
|
|
end process;
|
|
|
|
end architecture spwxmit_fast_arch;
|
end architecture spwxmit_fast_arch;
|
|
|
No newline at end of file
|
No newline at end of file
|