Line 120... |
Line 120... |
-- 5 txclk + 3 sysclk = 5 + 3*4 txclk = 17 txclk
|
-- 5 txclk + 3 sysclk = 5 + 3*4 txclk = 17 txclk
|
-- is less than 20 bit periods even at maximum transmission rate, so
|
-- is less than 20 bit periods even at maximum transmission rate, so
|
-- no problem there.
|
-- no problem there.
|
--
|
--
|
-- This is different when the data stream includes 4-bit tokens.
|
-- This is different when the data stream includes 4-bit tokens.
|
-- See the datasheet for an analysis of that case.
|
-- See the manual for further comments.
|
--
|
--
|
-- Implementation guidelines
|
-- Implementation guidelines
|
-- -------------------------
|
-- -------------------------
|
--
|
--
|
-- To minimize clock skew, IOB flip-flops should be used to drive
|
-- To minimize clock skew, IOB flip-flops should be used to drive
|
Line 198... |
Line 198... |
|
|
-- Data records passed between clock domains.
|
-- Data records passed between clock domains.
|
type token_type is record
|
type token_type is record
|
tick: std_ulogic; -- send time code
|
tick: std_ulogic; -- send time code
|
fct: std_ulogic; -- send FCT
|
fct: std_ulogic; -- send FCT
|
|
fctpiggy: std_ulogic; -- send FCT and N-char
|
flag: std_ulogic; -- send EOP or EEP
|
flag: std_ulogic; -- send EOP or EEP
|
char: std_logic_vector(7 downto 0); -- character or time code
|
char: std_logic_vector(7 downto 0); -- character or time code
|
end record;
|
end record;
|
|
|
-- Registers in txclk domain
|
-- Registers in txclk domain
|
Line 218... |
Line 219... |
b_txflip: std_ulogic;
|
b_txflip: std_ulogic;
|
b_valid: std_ulogic;
|
b_valid: std_ulogic;
|
b_token: token_type;
|
b_token: token_type;
|
-- stage C
|
-- stage C
|
c_update: std_ulogic;
|
c_update: std_ulogic;
|
|
c_busy: std_ulogic;
|
c_esc: std_ulogic;
|
c_esc: std_ulogic;
|
c_fct: std_ulogic;
|
c_fct: std_ulogic;
|
c_bits: std_logic_vector(8 downto 0);
|
c_bits: std_logic_vector(8 downto 0);
|
-- stage D
|
-- stage D
|
d_bits: std_logic_vector(8 downto 0);
|
d_bits: std_logic_vector(8 downto 0);
|
Line 275... |
Line 277... |
allow_char: std_ulogic; -- '1' when allowed to send data and time
|
allow_char: std_ulogic; -- '1' when allowed to send data and time
|
sent_fct: std_ulogic; -- '1' when at least one FCT token was sent
|
sent_fct: std_ulogic; -- '1' when at least one FCT token was sent
|
end record;
|
end record;
|
|
|
-- Initial state of system clock domain
|
-- Initial state of system clock domain
|
|
constant token_reset: token_type := (
|
|
tick => '0',
|
|
fct => '0',
|
|
fctpiggy => '0',
|
|
flag => '0',
|
|
char => (others => '0') );
|
constant regs_reset: regs_type := (
|
constant regs_reset: regs_type := (
|
txenreg => '0',
|
txenreg => '0',
|
txdivreg => (others => '0'),
|
txdivreg => (others => '0'),
|
txdivnorm => '0',
|
txdivnorm => '0',
|
txdivtmp => "00",
|
txdivtmp => "00",
|
txdivsafe => '0',
|
txdivsafe => '0',
|
sysflip0 => '0',
|
sysflip0 => '0',
|
sysflip1 => '0',
|
sysflip1 => '0',
|
token0 => ( tick => '0', fct => '0', flag => '0', char => (others => '0') ),
|
token0 => token_reset,
|
token1 => ( tick => '0', fct => '0', flag => '0', char => (others => '0') ),
|
token1 => token_reset,
|
tokmux => '0',
|
tokmux => '0',
|
txflip0 => "00",
|
txflip0 => "00",
|
txflip1 => "00",
|
txflip1 => "00",
|
pend_fct => '0',
|
pend_fct => '0',
|
pend_char => '0',
|
pend_char => '0',
|
Line 334... |
Line 342... |
begin
|
begin
|
v := r;
|
v := r;
|
vtx := rtx;
|
vtx := rtx;
|
v_needtoken := '0';
|
v_needtoken := '0';
|
v_havetoken := '0';
|
v_havetoken := '0';
|
v_token := ( tick => '0', fct => '0', flag => '0', char => (others => '0') );
|
v_token := token_reset;
|
|
|
-- ---- FAST CLOCK DOMAIN ----
|
-- ---- FAST CLOCK DOMAIN ----
|
|
|
-- Stage A: Synchronize token buffer counts from system clock domain.
|
-- Stage A: Synchronize token buffer counts from system clock domain.
|
vtx.a_sysflip0(0) := r.sysflip0;
|
vtx.a_sysflip0(0) := r.sysflip0;
|
Line 347... |
Line 355... |
vtx.a_sysflip1(1) := rtx.a_sysflip1(0);
|
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 the last token from stage C was ESC;
|
-- Do not update stage B if stage C is indicating that it needs to
|
-- stage C already knows what token to put after the ESC.
|
-- send a second token to complete its task.
|
vtx.b_update := rtx.txclken and rtx.e_count(0) and (not rtx.c_esc);
|
vtx.b_update := rtx.txclken and rtx.e_count(0) and (not rtx.c_busy);
|
if rtx.b_mux = '0' then
|
if rtx.b_mux = '0' then
|
vtx.b_txflip := rtx.txflip0;
|
vtx.b_txflip := rtx.txflip0;
|
else
|
else
|
vtx.b_txflip := rtx.txflip1;
|
vtx.b_txflip := rtx.txflip1;
|
end if;
|
end if;
|
Line 378... |
Line 386... |
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);
|
if rtx.c_update = '1' then
|
if rtx.c_update = '1' then
|
-- NULL is broken into two tokens: ESC + FCT
|
|
-- time codes are broken into two tokens: ESC + char
|
-- NULL is broken into two tokens: ESC + FCT.
|
|
-- Time-codes are broken into two tokens: ESC + char.
|
|
|
|
-- Enable c_esc on the first pass of a NULL or a time-code.
|
vtx.c_esc := (rtx.b_token.tick or (not rtx.b_valid)) and
|
vtx.c_esc := (rtx.b_token.tick or (not rtx.b_valid)) and
|
(not rtx.c_esc);
|
(not rtx.c_esc);
|
vtx.c_fct := rtx.b_token.fct or (not rtx.b_valid);
|
|
|
-- Enable c_fct on the first pass of an FCT and on
|
|
-- the second pass of a NULL (also the first pass, but c_esc
|
|
-- is stronger than c_fct).
|
|
vtx.c_fct := (rtx.b_token.fct and (not rtx.c_busy)) or
|
|
(not rtx.b_valid);
|
|
|
|
-- Enable c_busy on the first pass of a NULL or a time-code
|
|
-- or a piggy-backed FCT. This will tell stage B that we are
|
|
-- not done yet.
|
|
vtx.c_busy := (rtx.b_token.tick or (not rtx.b_valid) or
|
|
rtx.b_token.fctpiggy) and (not rtx.c_busy);
|
|
|
if rtx.b_token.flag = '1' then
|
if rtx.b_token.flag = '1' then
|
if rtx.b_token.char(0) = '0' then
|
if rtx.b_token.char(0) = '0' then
|
-- prepare to send EOP
|
-- prepare to send EOP
|
vtx.c_bits := "000000101"; -- EOP = P101
|
vtx.c_bits := "000000101"; -- EOP = P101
|
else
|
else
|
Line 491... |
Line 514... |
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';
|
vtx.c_update := '0';
|
vtx.c_update := '0';
|
|
vtx.c_busy := '1';
|
vtx.c_esc := '1'; -- need to send 2nd part of NULL
|
vtx.c_esc := '1'; -- need to send 2nd part of NULL
|
vtx.c_fct := '1';
|
vtx.c_fct := '1';
|
vtx.d_bits := "000000111"; -- ESC = P111
|
vtx.d_bits := "000000111"; -- ESC = P111
|
vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit
|
vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit
|
vtx.d_cnt10 := '0';
|
vtx.d_cnt10 := '0';
|
Line 582... |
Line 606... |
-- Prepare new token.
|
-- Prepare new token.
|
if r.allow_char = '1' and r.pend_tick = '1' then
|
if r.allow_char = '1' and r.pend_tick = '1' then
|
-- prepare to send time code
|
-- prepare to send time code
|
v_token.tick := '1';
|
v_token.tick := '1';
|
v_token.fct := '0';
|
v_token.fct := '0';
|
|
v_token.fctpiggy := '0';
|
v_token.flag := '0';
|
v_token.flag := '0';
|
v_token.char := r.pend_time;
|
v_token.char := r.pend_time;
|
v_havetoken := '1';
|
v_havetoken := '1';
|
if v_needtoken = '1' then
|
if v_needtoken = '1' then
|
v.pend_tick := '0';
|
v.pend_tick := '0';
|
end if;
|
end if;
|
elsif r.allow_fct = '1' and (xmiti.fct_in = '1' or r.pend_fct = '1') then
|
else
|
|
if r.allow_fct = '1' and (xmiti.fct_in = '1' or r.pend_fct = '1') then
|
-- prepare to send FCT
|
-- prepare to send FCT
|
v_token.tick := '0';
|
|
v_token.fct := '1';
|
v_token.fct := '1';
|
v_token.flag := '0';
|
|
v_havetoken := '1';
|
v_havetoken := '1';
|
if v_needtoken = '1' then
|
if v_needtoken = '1' then
|
v.pend_fct := '0';
|
v.pend_fct := '0';
|
v.sent_fct := '1';
|
v.sent_fct := '1';
|
end if;
|
end if;
|
elsif r.allow_char = '1' and r.pend_char = '1' then
|
end if;
|
|
if r.allow_char = '1' and r.pend_char = '1' then
|
-- prepare to send N-Char
|
-- prepare to send N-Char
|
v_token.tick := '0';
|
-- Note: it is possible to send an FCT and an N-Char
|
v_token.fct := '0';
|
-- together by enabling the fctpiggy flag.
|
|
v_token.fctpiggy := v_token.fct;
|
v_token.flag := r.pend_data(8);
|
v_token.flag := r.pend_data(8);
|
v_token.char := r.pend_data(7 downto 0);
|
v_token.char := r.pend_data(7 downto 0);
|
v_havetoken := '1';
|
v_havetoken := '1';
|
if v_needtoken = '1' then
|
if v_needtoken = '1' then
|
v.pend_char := '0';
|
v.pend_char := '0';
|
end if;
|
end if;
|
end if;
|
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 = r.txflip0(1) then
|