##// END OF EJS Templates
MiniSpartan6:...
MiniSpartan6: added ftdi chip config to switch between UART and Async FIFO. added few WIP designs with either spwlight core, FIFO_deom IP... Libs: added SpaceWire Light IP (Works really well!) started design of ahb_ftdi_fifo -> same protocol than AHBUART but over FTDI's Async FIFO interface. This might lead to much faster transfers UP to 12MB/s.

File last commit:

r681:9d85f9f8f05a default
r681:9d85f9f8f05a default
Show More
spwxmit_fast.vhd
721 lines | 28.2 KiB | text/x-vhdl | VhdlLexer
--
-- SpaceWire Transmitter
--
-- This entity translates outgoing characters and tokens into
-- data-strobe signalling.
--
-- The output stage is driven by a separate transmission clock "txclk" which
-- will typically be faster than the system clock. The actual transmission
-- rate is determined by dividing the transmission clock by an integer factor.
--
-- The code is tuned for implementation on Xilinx Spartan-3.
--
-- Concept
-- -------
--
-- Logic in the system clock domain generates a stream of tokens to be
-- transmitted. These tokens are encoded as instances of the token_type
-- record. Tokens are queued in a two-slot FIFO buffer (r.token0 and r.token1)
-- with a 1-bit pointer (r.tokmux) pointing to the head of the queue.
-- When a token is pushed into the buffer, a flag register is flipped
-- (r.sysflip0 and r.sysflip1) to indicate to the txclk domain that the
-- buffer slot has been refilled.
--
-- The txclk domain pulls tokens from the FIFO buffer, flipping flag
-- registers (rtx.txflip0 and rtx.txflip1) to indicate to the system clock
-- domain that a token has been pulled. When the system clock domain detects
-- that a token has been consumed, it refills the buffer slot with a new
-- token (assuming that there are tokens waiting to be transmitted).
-- Whenever the FIFO buffer is empty, the txclk domain sends NULLs instead.
-- This can happen either when there are no tokens to send, or when the
-- system clock domain is late to refill the buffer.
--
-- Details
-- -------
--
-- Logic in the system clock domain accepts transmission requests through
-- the external interface of the entity. Pending requests are translated
-- into a stream of tokens. The tokens are pushed to the txclk domain through
-- the FIFO buffer as described above.
--
-- The data path through the txclk domain is divided into stages B through F
-- in a half-hearted attempt to keep things simple.
--
-- 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
-- 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
-- skips a turn because stage C will already know what to do.
--
-- Stage C takes a token from stage B and translates it into a bit pattern.
-- Time codes and NULL tokens are broken into two separate tokens starting
-- with ESC. Stage C is triggered one clock after the shift buffer in
-- stage E drops to 3 tokens.
--
-- Stage D completes the task of translating tokens to bit patterns and
-- distinguishes between 10-bit and 4-bit tokens. It is not explicitly
-- triggered but simply follows stage C.
--
-- Stage E is the bit shift register. It shifts when "txclken" is high.
-- A one-hot counter keeps track of the number of bits remaining in
-- the register. When the register falls empty, it loads a new 10-bit or
-- 4-bit pattern as prepared by stage D. Stage E also computes parity.
--
-- Stage F performs data strobe encoding. When the transmitter is disabled,
-- the outputs of stage F fall to zero in a controlled way.
--
-- To generate the transmission bit clock, the txclk is divided by an
-- integer factor (divcnt+1) using an 8-bit down counter. The implementation
-- of this counter has become quite complicated in order to meet timing goals.
-- The counter consists of 4 blocks of two bits each (txclkcnt), with a
-- carry-save concept used between blocks (txclkcy). Detection of terminal
-- count (txclkdone) has a pipeline delay of two cycles. Therefore a separate
-- concept is used if the initial count is less than 2 (txdivnorm). This is
-- all glued together in the final assignment to txclken.
--
-- The initial count for txclk division (divcnt) comes from the system clock
-- domain and thus needs to be synchronized for use in the txclk domain.
-- To facilitate this, the system clock domain latches the value of divcnt
-- once every 6 sysclk cycles and sets a flag to indicate when the latched
-- value can safely be used by the txclk domain.
--
-- A tricky aspect of the design is the initial state of the txclk logic.
-- When the transmitter is enabled (txen goes high), the txclk logic starts
-- with the first ESC pattern already set up in stage D, and stage C ready
-- to produce the FCT part of the first NULL.
--
-- The following guidelines are used to get good timing for the txclk domain:
-- * The new value of a register depends on at most 4 inputs (single LUT),
-- or in a few cases on 5 inputs (two LUTs and F5MUX).
-- * Synchronous resets may be used, but only if the reset signal comes
-- directly from a register (no logic in set/reset path);
-- * Clock enables may be used, but only if the enable signal comes directly
-- from a register (no logic in clock enable path).
--
-- Synchronization issues
-- ----------------------
--
-- There is a two-slot FIFO buffer between the system and txclk domains.
-- After the txclk domain pulls a token from the buffer, the system clock
-- domain should ideally refill the buffer before the txclk domain again
-- tries to pull from the same buffer slot. If the refill occurs late,
-- the txclk domain needs to insert a NULL token which is inefficient
-- use of bandwidth.
--
-- Assuming the transmission consists of a stream of data characters,
-- 10 bits per character, there are exactly 2*10 bit periods between
-- successive reads from the same buffer slot by the txclk logic.
--
-- The time needed for the system clock logic to refill a buffer slot =
-- 1 txclk period (update of rtx.txflipN)
-- + 1 txclk period (routing delay between domains)
-- + 2 sysclk periods (synchronizer for txflipN)
-- + 1 sysclk period (refill buffer slot and update r.sysflipN)
-- + 1 txclk period (routing delay between domains)
-- + 2 txclk periods (synchronizer for sysflipN)
-- = 5 txclk periods + 3 sysclk periods
--
-- If for example txclk is 4 times as fast as sysclk, this amounts to
-- 5 txclk + 3 sysclk = 5 + 3*4 txclk = 17 txclk
-- is less than 20 bit periods even at maximum transmission rate, so
-- no problem there.
--
-- This is different when the data stream includes 4-bit tokens.
-- See the manual for further comments.
--
-- Implementation guidelines
-- -------------------------
--
-- To minimize clock skew, IOB flip-flops should be used to drive
-- spw_do and spw_so.
--
-- "txclk" must be at least as fast as the system clock;
-- "txclk" does not need to be phase-related to the system clock;
-- it is allowed for "txclk" to be equal to "clk".
--
-- The following timing constraints are needed:
-- * PERIOD constraint on the system clock;
-- * PERIOD constraint on "txclk";
-- * FROM-TO constraint from "txclk" to the system clock, equal to
-- one "txclk" period;
-- * FROM-TO constraint from the system clock to "txclk", equal to
-- one "txclk" period.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.spwpkg.all;
entity spwxmit_fast is
port (
-- System clock.
clk: in std_logic;
-- Transmit clock.
txclk: in std_logic;
-- Synchronous reset (active-high)
-- Used asynchronously by fast clock domain (must be glitch-free).
rst: in std_logic;
-- Scaling factor minus 1, used to scale the system clock into the
-- transmission bit rate. The system clock is divided by
-- (unsigned(divcnt) + 1). Changing this signal will immediately
-- change the transmission rate.
divcnt: in std_logic_vector(7 downto 0);
-- Input signals from spwlink.
xmiti: in spw_xmit_in_type;
-- Output signals to spwlink.
xmito: out spw_xmit_out_type;
-- Data Out signal to SpaceWire bus.
spw_do: out std_logic;
-- Strobe Out signal to SpaceWire bus.
spw_so: out std_logic
);
-- Turn off FSM extraction to avoid synchronization problems.
attribute FSM_EXTRACT: string;
attribute FSM_EXTRACT of spwxmit_fast: entity is "NO";
end entity spwxmit_fast;
architecture spwxmit_fast_arch of spwxmit_fast is
-- Convert boolean to std_logic.
type bool_to_logic_type is array(boolean) of std_ulogic;
constant bool_to_logic: bool_to_logic_type := (false => '0', true => '1');
-- Data records passed between clock domains.
type token_type is record
tick: std_ulogic; -- send time code
fct: std_ulogic; -- send FCT
fctpiggy: std_ulogic; -- send FCT and N-char
flag: std_ulogic; -- send EOP or EEP
char: std_logic_vector(7 downto 0); -- character or time code
end record;
-- Registers in txclk domain
type txregs_type is record
-- sync to system clock domain
txflip0: std_ulogic;
txflip1: std_ulogic;
-- stage B
b_update: std_ulogic;
b_mux: std_ulogic;
b_txflip: std_ulogic;
b_valid: std_ulogic;
b_token: token_type;
-- stage C
c_update: std_ulogic;
c_busy: std_ulogic;
c_esc: std_ulogic;
c_fct: std_ulogic;
c_bits: std_logic_vector(8 downto 0);
-- stage D
d_bits: std_logic_vector(8 downto 0);
d_cnt4: std_ulogic;
d_cnt10: std_ulogic;
-- stage E
e_valid: std_ulogic;
e_shift: std_logic_vector(9 downto 0);
e_count: std_logic_vector(9 downto 0);
e_parity: std_ulogic;
-- stage F
f_spwdo: std_ulogic;
f_spwso: std_ulogic;
-- tx clock enable logic
txclken: std_ulogic;
txclkpre: std_ulogic;
txclkcnt: std_logic_vector(7 downto 0);
txclkcy: std_logic_vector(2 downto 0);
txclkdone: std_logic_vector(1 downto 0);
txclkdiv: std_logic_vector(7 downto 0);
txdivnorm: std_ulogic;
end record;
-- Registers in system clock domain
type regs_type is record
-- sync status to txclk domain
txenreg: std_ulogic;
txdivreg: std_logic_vector(7 downto 0);
txdivnorm: std_ulogic;
txdivtmp: std_logic_vector(1 downto 0);
txdivsafe: std_ulogic;
-- data stream to txclk domain
sysflip0: std_ulogic;
sysflip1: std_ulogic;
token0: token_type;
token1: token_type;
tokmux: std_ulogic;
-- transmitter management
pend_fct: std_ulogic; -- '1' if an outgoing FCT 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_tick: std_ulogic; -- '1' if an outgoing time tick is pending
pend_time: std_logic_vector(7 downto 0); -- data bits of pending time tick
allow_fct: std_ulogic; -- '1' when allowed to send FCTs
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
end record;
-- 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 := (
txenreg => '0',
txdivreg => (others => '0'),
txdivnorm => '0',
txdivtmp => "00",
txdivsafe => '0',
sysflip0 => '0',
sysflip1 => '0',
token0 => token_reset,
token1 => token_reset,
tokmux => '0',
pend_fct => '0',
pend_char => '0',
pend_data => (others => '0'),
pend_tick => '0',
pend_time => (others => '0'),
allow_fct => '0',
allow_char => '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
signal rtx: txregs_type;
signal rtxin: txregs_type;
signal r: regs_type := regs_reset;
signal rin: regs_type;
-- Synchronized signals after crossing clock domains.
signal synctx: synctx_type;
signal syncsys: syncsys_type;
-- Output flip-flops
signal s_spwdo: std_logic;
signal s_spwso: std_logic;
-- Force use of IOB flip-flops
attribute IOB: string;
attribute IOB of s_spwdo: signal is "TRUE";
attribute IOB of s_spwso: signal is "TRUE";
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
spw_do <= s_spwdo;
spw_so <= s_spwso;
-- Combinatorial process
process (r, rtx, rst, divcnt, xmiti, synctx, syncsys) is
variable v: regs_type;
variable vtx: txregs_type;
variable v_needtoken: std_ulogic;
variable v_havetoken: std_ulogic;
variable v_token: token_type;
begin
v := r;
vtx := rtx;
v_needtoken := '0';
v_havetoken := '0';
v_token := token_reset;
-- ---- FAST CLOCK DOMAIN ----
-- Stage B: Multiplex tokens from system clock domain.
-- Update stage B three bit periods after updating 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
-- send a second token to complete its task.
vtx.b_update := rtx.txclken and rtx.e_count(0) and (not rtx.c_busy);
if rtx.b_mux = '0' then
vtx.b_txflip := rtx.txflip0;
else
vtx.b_txflip := rtx.txflip1;
end if;
if rtx.b_update = '1' then
if rtx.b_mux = '0' then
-- get token from slot 0
vtx.b_valid := synctx.sysflip0 xor rtx.b_txflip;
vtx.b_token := r.token0;
-- update mux flag if we got a valid token
vtx.b_mux := synctx.sysflip0 xor rtx.b_txflip;
vtx.txflip0 := synctx.sysflip0;
vtx.txflip1 := rtx.txflip1;
else
-- get token from slot 1
vtx.b_valid := synctx.sysflip1 xor rtx.b_txflip;
vtx.b_token := r.token1;
-- update mux flag if we got a valid token
vtx.b_mux := not (synctx.sysflip1 xor rtx.b_txflip);
vtx.txflip0 := rtx.txflip0;
vtx.txflip1 := synctx.sysflip1;
end if;
end if;
-- Stage C: Prepare to transmit EOP, EEP or a data character.
vtx.c_update := rtx.txclken and rtx.e_count(3);
if rtx.c_update = '1' then
-- 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
(not rtx.c_esc);
-- 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.char(0) = '0' then
-- prepare to send EOP
vtx.c_bits := "000000101"; -- EOP = P101
else
-- prepare to send EEP
vtx.c_bits := "000000011"; -- EEP = P110
end if;
else
-- prepare to send data char
vtx.c_bits := rtx.b_token.char & '0';
end if;
end if;
-- Stage D: Prepare to transmit FCT, ESC, or the stuff from stage C.
if rtx.c_esc = '1' then
-- prepare to send ESC
vtx.d_bits := "000000111"; -- ESC = P111
vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit
vtx.d_cnt10 := '0';
elsif rtx.c_fct = '1' then
-- prepare to send FCT
vtx.d_bits := "000000001"; -- FCT = P100
vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit
vtx.d_cnt10 := '0';
else
-- send the stuff from stage C.
vtx.d_bits := rtx.c_bits;
vtx.d_cnt4 := rtx.c_bits(0);
vtx.d_cnt10 := not rtx.c_bits(0);
end if;
-- Stage E: Shift register.
if rtx.txclken = '1' then
if rtx.e_count(0) = '1' then
-- reload shift register; output parity bit
vtx.e_valid := '1';
vtx.e_shift(vtx.e_shift'high downto 1) := rtx.d_bits;
vtx.e_shift(0) := not (rtx.e_parity xor rtx.d_bits(0));
vtx.e_count := rtx.d_cnt10 & "00000" & rtx.d_cnt4 & "000";
vtx.e_parity := rtx.d_bits(0);
else
-- shift bits to output; update parity bit
vtx.e_shift := '0' & rtx.e_shift(rtx.e_shift'high downto 1);
vtx.e_count := '0' & rtx.e_count(rtx.e_count'high downto 1);
vtx.e_parity := rtx.e_parity xor rtx.e_shift(1);
end if;
end if;
-- Stage F: Data/strobe encoding.
if rtx.txclken = '1' then
if rtx.e_valid = '1' then
-- output next data/strobe bits
vtx.f_spwdo := rtx.e_shift(0);
vtx.f_spwso := not (rtx.e_shift(0) xor rtx.f_spwdo xor rtx.f_spwso);
else
-- gentle reset of spacewire signals
vtx.f_spwdo := rtx.f_spwdo and rtx.f_spwso;
vtx.f_spwso := '0';
end if;
end if;
-- Generate tx clock enable
-- An 8-bit counter decrements on every clock. A txclken pulse is
-- produced 2 cycles after the counter reaches value 2. Counter reload
-- values of 0 and 1 are handled as special cases.
-- count down in blocks of two bits
vtx.txclkcnt(1 downto 0) := std_logic_vector(unsigned(rtx.txclkcnt(1 downto 0)) - 1);
vtx.txclkcnt(3 downto 2) := std_logic_vector(unsigned(rtx.txclkcnt(3 downto 2)) - unsigned(rtx.txclkcy(0 downto 0)));
vtx.txclkcnt(5 downto 4) := std_logic_vector(unsigned(rtx.txclkcnt(5 downto 4)) - unsigned(rtx.txclkcy(1 downto 1)));
vtx.txclkcnt(7 downto 6) := std_logic_vector(unsigned(rtx.txclkcnt(7 downto 6)) - unsigned(rtx.txclkcy(2 downto 2)));
-- propagate carry in blocks of two bits
vtx.txclkcy(0) := bool_to_logic(rtx.txclkcnt(1 downto 0) = "00");
vtx.txclkcy(1) := rtx.txclkcy(0) and bool_to_logic(rtx.txclkcnt(3 downto 2) = "00");
vtx.txclkcy(2) := rtx.txclkcy(1) and bool_to_logic(rtx.txclkcnt(5 downto 4) = "00");
-- detect value 2 in counter
vtx.txclkdone(0) := bool_to_logic(rtx.txclkcnt(3 downto 0) = "0010");
vtx.txclkdone(1) := bool_to_logic(rtx.txclkcnt(7 downto 4) = "0000");
-- trigger txclken
vtx.txclken := (rtx.txclkdone(0) and rtx.txclkdone(1)) or rtx.txclkpre;
vtx.txclkpre := (not rtx.txdivnorm) and ((not rtx.txclkpre) or (not rtx.txclkdiv(0)));
-- reload counter
if rtx.txclken = '1' then
vtx.txclkcnt := rtx.txclkdiv;
vtx.txclkcy := "000";
vtx.txclkdone := "00";
end if;
-- Synchronize txclkdiv
if synctx.txdivsafe = '1' then
vtx.txclkdiv := r.txdivreg;
vtx.txdivnorm := r.txdivnorm;
end if;
-- Transmitter disabled.
if synctx.txen = '0' then
vtx.txflip0 := '0';
vtx.txflip1 := '0';
vtx.b_update := '0';
vtx.b_mux := '0';
vtx.b_valid := '0';
vtx.c_update := '0';
vtx.c_busy := '1';
vtx.c_esc := '1'; -- need to send 2nd part of NULL
vtx.c_fct := '1';
vtx.d_bits := "000000111"; -- ESC = P111
vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit
vtx.d_cnt10 := '0';
vtx.e_valid := '0';
vtx.e_parity := '0';
vtx.e_count := (0 => '1', others => '0');
end if;
-- Reset.
if synctx.rstn = '0' then
vtx.f_spwdo := '0';
vtx.f_spwso := '0';
vtx.txclken := '0';
vtx.txclkpre := '1';
vtx.txclkcnt := (others => '0');
vtx.txclkdiv := (others => '0');
vtx.txdivnorm := '0';
end if;
-- ---- SYSTEM CLOCK DOMAIN ----
-- Hold divcnt and txen for use by txclk domain.
v.txdivtmp := std_logic_vector(unsigned(r.txdivtmp) - 1);
if r.txdivtmp = "00" then
if r.txdivsafe = '0' then
-- Latch the current value of divcnt and txen.
v.txdivsafe := '1';
v.txdivtmp := "01";
v.txdivreg := divcnt;
if unsigned(divcnt(divcnt'high downto 1)) = 0 then
v.txdivnorm := '0';
else
v.txdivnorm := '1';
end if;
v.txenreg := xmiti.txen;
else
-- Drop the txdivsafe flag but keep latched values.
v.txdivsafe := '0';
end if;
end if;
-- Pass falling edge of txen signal as soon as possible.
if xmiti.txen = '0' then
v.txenreg := '0';
end if;
-- Store requests for FCT transmission.
if xmiti.fct_in = '1' and r.allow_fct = '1' then
v.pend_fct := '1';
end if;
if xmiti.txen = '0' then
-- Transmitter disabled; reset state.
v.sysflip0 := '0';
v.sysflip1 := '0';
v.tokmux := '0';
v.pend_fct := '0';
v.pend_char := '0';
v.pend_tick := '0';
v.allow_fct := '0';
v.allow_char := '0';
v.sent_fct := '0';
else
-- Determine if a new token is needed.
if r.tokmux = '0' then
if r.sysflip0 = syncsys.txflip0 then
v_needtoken := '1';
end if;
else
if r.sysflip1 = syncsys.txflip1 then
v_needtoken := '1';
end if;
end if;
-- Prepare new token.
if r.allow_char = '1' and r.pend_tick = '1' then
-- prepare to send time code
v_token.tick := '1';
v_token.fct := '0';
v_token.fctpiggy := '0';
v_token.flag := '0';
v_token.char := r.pend_time;
v_havetoken := '1';
if v_needtoken = '1' then
v.pend_tick := '0';
end if;
else
if r.allow_fct = '1' and (xmiti.fct_in = '1' or r.pend_fct = '1') then
-- prepare to send FCT
v_token.fct := '1';
v_havetoken := '1';
if v_needtoken = '1' then
v.pend_fct := '0';
v.sent_fct := '1';
end if;
end if;
if r.allow_char = '1' and r.pend_char = '1' then
-- prepare to send N-Char
-- Note: it is possible to send an FCT and an N-Char
-- together by enabling the fctpiggy flag.
v_token.fctpiggy := v_token.fct;
v_token.flag := r.pend_data(8);
v_token.char := r.pend_data(7 downto 0);
v_havetoken := '1';
if v_needtoken = '1' then
v.pend_char := '0';
end if;
end if;
end if;
-- Put new token in slot.
if v_havetoken = '1' then
if r.tokmux = '0' then
if r.sysflip0 = syncsys.txflip0 then
v.sysflip0 := not r.sysflip0;
v.token0 := v_token;
v.tokmux := '1';
end if;
else
if r.sysflip1 = syncsys.txflip1 then
v.sysflip1 := not r.sysflip1;
v.token1 := v_token;
v.tokmux := '0';
end if;
end if;
end if;
-- Determine whether we are allowed to send FCTs and characters
v.allow_fct := not xmiti.stnull;
v.allow_char := (not xmiti.stnull) and (not xmiti.stfct) and r.sent_fct;
-- Store request for data transmission.
if xmiti.txwrite = '1' and r.allow_char = '1' and r.pend_char = '0' then
v.pend_char := '1';
v.pend_data := xmiti.txflag & xmiti.txdata;
end if;
-- Store requests for time tick transmission.
if xmiti.tick_in = '1' then
v.pend_tick := '1';
v.pend_time := xmiti.ctrl_in & xmiti.time_in;
end if;
end if;
-- Synchronous reset of system clock domain.
if rst = '1' then
v := regs_reset;
end if;
-- Drive outputs.
-- Note: the outputs are combinatorially dependent on certain inputs.
-- Set fctack high if (FCT requested) and (FCTs allowed) AND
-- (no FCT pending)
xmito.fctack <= xmiti.fct_in and xmiti.txen and r.allow_fct and
(not r.pend_fct);
-- Set txrdy high if (character requested) AND (characters allowed) AND
-- (no character pending)
xmito.txack <= xmiti.txwrite and xmiti.txen and r.allow_char and
(not r.pend_char);
-- Update registers.
rin <= v;
rtxin <= vtx;
end process;
-- Synchronous process in txclk domain
process (txclk) is
begin
if rising_edge(txclk) then
-- drive spacewire output signals
s_spwdo <= rtx.f_spwdo;
s_spwso <= rtx.f_spwso;
-- update registers
rtx <= rtxin;
end if;
end process;
-- Synchronous process in system clock domain
process (clk) is
begin
if rising_edge(clk) then
-- update registers
r <= rin;
end if;
end process;
end architecture spwxmit_fast_arch;