OpenCores
URL https://opencores.org/ocsvn/spacewire_light/spacewire_light/trunk

Subversion Repositories spacewire_light

[/] [spacewire_light/] [trunk/] [rtl/] [vhdl/] [spwxmit_fast.vhd] - Blame information for rev 5

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jorisvr
--
2
--  SpaceWire Transmitter
3
--
4
--  This entity translates outgoing characters and tokens into
5
--  data-strobe signalling.
6
--
7
--  The output stage is driven by a separate transmission clock "txclk" which
8
--  will typically be faster than the system clock. The actual transmission
9
--  rate is determined by dividing the transmission clock by an integer factor.
10
--
11
--  The code is tuned for implementation on Xilinx Spartan-3.
12
--
13
--  Concept
14
--  -------
15
--
16
--  Logic in the system clock domain generates a stream of tokens to be
17
--  transmitted. These tokens are encoded as instances of the token_type
18
--  record. Tokens are queued in a two-slot FIFO buffer (r.token0 and r.token1)
19
--  with a 1-bit pointer (r.tokmux) pointing to the head of the queue.
20
--  When a token is pushed into the buffer, a flag register is flipped
21
--  (r.sysflip0 and r.sysflip1) to indicate to the txclk domain that the
22
--  buffer slot has been refilled.
23
--
24
--  The txclk domain pulls tokens from the FIFO buffer, flipping flag
25
--  registers (rtx.txflip0 and rtx.txflip1) to indicate to the system clock
26
--  domain that a token has been pulled. When the system clock domain detects
27
--  that a token has been consumed, it refills the buffer slot with a new
28
--  token (assuming that there are tokens waiting to be transmitted).
29
--  Whenever the FIFO buffer is empty, the txclk domain sends NULLs instead.
30
--  This can happen either when there are no tokens to send, or when the
31
--  system clock domain is late to refill the buffer.
32
--
33
--  Details
34
--  -------
35
--
36
--  Logic in the system clock domain accepts transmission requests through
37
--  the external interface of the entity. Pending requests are translated
38
--  into a stream of tokens. The tokens are pushed to the txclk domain through
39
--  the FIFO buffer as described above.
40
--
41
--  The data path through the txclk domain is divided into stages A through F
42
--  in a half-hearted attempt to keep things simple. Stage A is just a
43
--  synchronizer for the buffer status flags from the system clock domain.
44
--
45
--  Stage B takes a token from the FIFO buffer and updates a buffer status
46
--  flag to indicate that the buffer slot needs to be refilled. If the FIFO
47
--  is empty, a NULL is inserted. Stage B is triggered one clock after
48
--  stage E switches to a new token. If the previous token was ESC, stage B
49
--  skips a turn because stage C will already know what to do.
50
--
51
--  Stage C takes a token from stage B and translates it into a bit pattern.
52
--  Time codes and NULL tokens are broken into two separate tokens starting
53
--  with ESC. Stage C is triggered one clock after the shift buffer in
54
--  stage E drops to 3 tokens.
55
--
56
--  Stage D completes the task of translating tokens to bit patterns and
57
--  distinguishes between 10-bit and 4-bit tokens. It is not explicitly
58
--  triggered but simply follows stage C.
59
--
60
--  Stage E is the bit shift register. It shifts when "txclken" is high.
61
--  A one-hot counter keeps track of the number of bits remaining in
62
--  the register. When the register falls empty, it loads a new 10-bit or
63
--  4-bit pattern as prepared by stage D. Stage E also computes parity.
64
--
65
--  Stage F performs data strobe encoding. When the transmitter is disabled,
66
--  the outputs of stage F fall to zero in a controlled way.
67
-- 
68
--  To generate the transmission bit clock, the txclk is divided by an
69
--  integer factor (divcnt+1) using an 8-bit down counter. The implementation
70
--  of this counter has become quite complicated in order to meet timing goals.
71
--  The counter consists of 4 blocks of two bits each (txclkcnt), with a
72
--  carry-save concept used between blocks (txclkcy). Detection of terminal
73
--  count (txclkdone) has a pipeline delay of two cycles. Therefore a separate
74
--  concept is used if the initial count is less than 2 (txdivnorm). This is
75
--  all glued together in the final assignment to txclken.
76
--
77
--  The initial count for txclk division (divcnt) comes from the system clock
78
--  domain and thus needs to be synchronized for use in the txclk domain.
79
--  To facilitate this, the system clock domain latches the value of divcnt
80
--  once every 6 sysclk cycles and sets a flag to indicate when the latched
81
--  value can safely be used by the txclk domain.
82
--
83
--  A tricky aspect of the design is the initial state of the txclk logic.
84
--  When the transmitter is enabled (txen goes high), the txclk logic starts
85
--  with the first ESC pattern already set up in stage D, and stage C ready
86
--  to produce the FCT part of the first NULL.
87
--
88
--  The following guidelines are used to get good timing for the txclk domain:
89
--   * The new value of a register depends on at most 4 inputs (single LUT),
90
--     or in a few cases on 5 inputs (two LUTs and F5MUX).
91
--   * Synchronous resets may be used, but only if the reset signal comes
92
--     directly from a register (no logic in set/reset path);
93
--   * Clock enables may be used, but only if the enable signal comes directly
94
--     from a register (no logic in clock enable path).
95
--
96
--  Synchronization issues
97
--  ----------------------
98
--
99
--  There is a two-slot FIFO buffer between the system and txclk domains.
100
--  After the txclk domain pulls a token from the buffer, the system clock
101
--  domain should ideally refill the buffer before the txclk domain again
102
--  tries to pull from the same buffer slot. If the refill occurs late,
103
--  the txclk domain needs to insert a NULL token which is inefficient
104
--  use of bandwidth.
105
--
106
--  Assuming the transmission consists of a stream of data characters,
107
--  10 bits per character, there are exactly 2*10 bit periods between
108
--  successive reads from the same buffer slot by the txclk logic.
109
--
110
--  The time needed for the system clock logic to refill a buffer slot =
111
--     1 txclk period   (update of rtx.txflipN)
112
--   + 1 txclk period   (routing delay between domains)
113
--   + 2 sysclk periods (synchronizer for txflipN)
114
--   + 1 sysclk period  (refill buffer slot and update r.sysflipN)
115
--   + 1 txclk period   (routing delay between domains)
116
--   + 2 txclk periods  (synchronizer for sysflipN)
117
--   = 5 txclk periods + 3 sysclk periods
118
--
119
--  If for example txclk is 4 times as fast as sysclk, this amounts to
120
--   5 txclk + 3 sysclk = 5 + 3*4 txclk = 17 txclk
121
--  is less than 20 bit periods even at maximum transmission rate, so
122
--  no problem there.
123
--
124
--  This is different when the data stream includes 4-bit tokens.
125 3 jorisvr
--  See the manual for further comments.
126 2 jorisvr
--
127
--  Implementation guidelines
128
--  -------------------------
129
--
130
--  To minimize clock skew, IOB flip-flops should be used to drive
131
--  spw_do and spw_so.
132
--
133
--  "txclk" must be at least as fast as the system clock;
134
--  "txclk" does not need to be phase-related to the system clock;
135
--  it is allowed for "txclk" to be equal to "clk".
136
--
137
--  The following timing constraints are needed:
138
--   * PERIOD constraint on the system clock;
139
--   * PERIOD constraint on "txclk";
140
--   * FROM-TO constraint from "txclk" to the system clock, equal to
141
--     one "txclk" period;
142
--   * FROM-TO constraint from the system clock to "txclk", equal to
143
--     one "txclk" period.
144
--
145
 
146
library ieee;
147
use ieee.std_logic_1164.all;
148
use ieee.numeric_std.all;
149
use work.spwpkg.all;
150
 
151
entity spwxmit_fast is
152
 
153
    port (
154
        -- System clock.
155
        clk:        in  std_logic;
156
 
157
        -- Transmit clock.
158
        txclk:      in  std_logic;
159
 
160
        -- Synchronous reset (active-high)
161
        -- Used asynchronously by fast clock domain (must be glitch-free).
162
        rst:        in  std_logic;
163
 
164
        -- Scaling factor minus 1, used to scale the system clock into the
165
        -- transmission bit rate. The system clock is divided by
166
        -- (unsigned(divcnt) + 1). Changing this signal will immediately
167
        -- change the transmission rate.
168
        divcnt:     in  std_logic_vector(7 downto 0);
169
 
170
        -- Input signals from spwlink.
171
        xmiti:      in  spw_xmit_in_type;
172
 
173
        -- Output signals to spwlink.
174
        xmito:      out spw_xmit_out_type;
175
 
176
        -- Data Out signal to SpaceWire bus.
177
        spw_do:     out std_logic;
178
 
179
        -- Strobe Out signal to SpaceWire bus.
180
        spw_so:     out std_logic
181
    );
182
 
183
    -- Turn off FSM extraction to avoid synchronization problems.
184
    attribute FSM_EXTRACT: string;
185
    attribute FSM_EXTRACT of spwxmit_fast: entity is "NO";
186
 
187
    -- Turn off register duplication to avoid synchronization problems.
188
    attribute REGISTER_DUPLICATION: string;
189
    attribute REGISTER_DUPLICATION of spwxmit_fast: entity is "FALSE";
190
 
191
end entity spwxmit_fast;
192
 
193
architecture spwxmit_fast_arch of spwxmit_fast is
194
 
195
    -- Convert boolean to std_logic.
196
    type bool_to_logic_type is array(boolean) of std_ulogic;
197
    constant bool_to_logic: bool_to_logic_type := (false => '0', true => '1');
198
 
199
    -- Data records passed between clock domains.
200
    type token_type is record
201
        tick:       std_ulogic;                     -- send time code
202
        fct:        std_ulogic;                     -- send FCT
203 3 jorisvr
        fctpiggy:   std_ulogic;                     -- send FCT and N-char
204 2 jorisvr
        flag:       std_ulogic;                     -- send EOP or EEP
205
        char:       std_logic_vector(7 downto 0);   -- character or time code
206
    end record;
207
 
208
    -- Registers in txclk domain
209
    type txregs_type is record
210
        -- sync to system clock domain
211
        txflip0:    std_ulogic;
212
        txflip1:    std_ulogic;
213
        -- stage A
214
        a_sysflip0: std_logic_vector(1 downto 0);
215
        a_sysflip1: std_logic_vector(1 downto 0);
216
        -- stage B
217
        b_update:   std_ulogic;
218
        b_mux:      std_ulogic;
219
        b_txflip:   std_ulogic;
220
        b_valid:    std_ulogic;
221
        b_token:    token_type;
222
        -- stage C
223
        c_update:   std_ulogic;
224 3 jorisvr
        c_busy:     std_ulogic;
225 2 jorisvr
        c_esc:      std_ulogic;
226
        c_fct:      std_ulogic;
227
        c_bits:     std_logic_vector(8 downto 0);
228
        -- stage D
229
        d_bits:     std_logic_vector(8 downto 0);
230
        d_cnt4:     std_ulogic;
231
        d_cnt10:    std_ulogic;
232
        -- stage E
233
        e_valid:    std_ulogic;
234
        e_shift:    std_logic_vector(9 downto 0);
235
        e_count:    std_logic_vector(9 downto 0);
236
        e_parity:   std_ulogic;
237
        -- stage F
238
        f_spwdo:    std_ulogic;
239
        f_spwso:    std_ulogic;
240
        -- tx clock enable logic
241
        txclken:    std_ulogic;
242
        txclkpre:   std_ulogic;
243
        txclkcnt:   std_logic_vector(7 downto 0);
244
        txclkcy:    std_logic_vector(2 downto 0);
245
        txclkdone:  std_logic_vector(1 downto 0);
246
        txclkdiv:   std_logic_vector(7 downto 0);
247
        txdivnorm:  std_ulogic;
248
        txdivsafe:  std_logic_vector(1 downto 0);
249
        -- tx enable logic
250
        txensync:   std_logic_vector(1 downto 0);
251
    end record;
252
 
253
    -- Registers in system clock domain
254
    type regs_type is record
255
        -- sync status to txclk domain
256
        txenreg:    std_ulogic;
257
        txdivreg:   std_logic_vector(7 downto 0);
258
        txdivnorm:  std_ulogic;
259
        txdivtmp:   std_logic_vector(1 downto 0);
260
        txdivsafe:  std_ulogic;
261
        -- data stream to txclk domain
262
        sysflip0:   std_ulogic;
263
        sysflip1:   std_ulogic;
264
        token0:     token_type;
265
        token1:     token_type;
266
        tokmux:     std_ulogic;
267
        -- sync feedback from txclk domain
268
        txflip0:    std_logic_vector(1 downto 0);
269
        txflip1:    std_logic_vector(1 downto 0);
270
        -- transmitter management
271
        pend_fct:   std_ulogic;                     -- '1' if an outgoing FCT is pending
272
        pend_char:  std_ulogic;                     -- '1' if an outgoing N-Char is pending
273
        pend_data:  std_logic_vector(8 downto 0);   -- control flag and data bits of pending char
274
        pend_tick:  std_ulogic;                     -- '1' if an outgoing time tick is pending
275
        pend_time:  std_logic_vector(7 downto 0);   -- data bits of pending time tick
276
        allow_fct:  std_ulogic;                     -- '1' when allowed to send FCTs
277
        allow_char: std_ulogic;                     -- '1' when allowed to send data and time
278
        sent_fct:   std_ulogic;                     -- '1' when at least one FCT token was sent
279
    end record;
280
 
281
    -- Initial state of system clock domain
282 3 jorisvr
    constant token_reset: token_type := (
283
        tick        => '0',
284
        fct         => '0',
285
        fctpiggy    => '0',
286
        flag        => '0',
287
        char        => (others => '0') );
288 2 jorisvr
    constant regs_reset: regs_type := (
289
        txenreg     => '0',
290
        txdivreg    => (others => '0'),
291
        txdivnorm   => '0',
292
        txdivtmp    => "00",
293
        txdivsafe   => '0',
294
        sysflip0    => '0',
295
        sysflip1    => '0',
296 3 jorisvr
        token0      => token_reset,
297
        token1      => token_reset,
298 2 jorisvr
        tokmux      => '0',
299
        txflip0     => "00",
300
        txflip1     => "00",
301
        pend_fct    => '0',
302
        pend_char   => '0',
303
        pend_data   => (others => '0'),
304
        pend_tick   => '0',
305
        pend_time   => (others => '0'),
306
        allow_fct   => '0',
307
        allow_char  => '0',
308
        sent_fct    => '0' );
309
 
310
    -- Registers
311
    signal rtx:     txregs_type;
312
    signal rtxin:   txregs_type;
313
    signal r:       regs_type := regs_reset;
314
    signal rin:     regs_type;
315
 
316
    -- Reset synchronizer for txclk domain
317
    signal s_tx_rst_sync: std_logic_vector(1 downto 0) := "11";
318
    signal s_tx_reset:    std_ulogic := '1';
319
 
320
    -- Output flip-flops
321
    signal s_spwdo: std_logic;
322
    signal s_spwso: std_logic;
323
 
324
    -- Force use of IOB flip-flops
325
    attribute IOB: string;
326
    attribute IOB of s_spwdo: signal is "TRUE";
327
    attribute IOB of s_spwso: signal is "TRUE";
328
 
329
begin
330
 
331
    -- Drive SpaceWire output signals
332
    spw_do      <= s_spwdo;
333
    spw_so      <= s_spwso;
334
 
335
    -- Combinatorial process
336
    process (r, rtx, rst, divcnt, xmiti, s_tx_reset) is
337
        variable v:         regs_type;
338
        variable vtx:       txregs_type;
339
        variable v_needtoken: std_ulogic;
340
        variable v_havetoken: std_ulogic;
341
        variable v_token:     token_type;
342
    begin
343
        v           := r;
344
        vtx         := rtx;
345
        v_needtoken := '0';
346
        v_havetoken := '0';
347 3 jorisvr
        v_token     := token_reset;
348 2 jorisvr
 
349
        -- ---- FAST CLOCK DOMAIN ----
350
 
351
        -- Stage A: Synchronize token buffer counts from system clock domain.
352
        vtx.a_sysflip0(0) := r.sysflip0;
353
        vtx.a_sysflip0(1) := rtx.a_sysflip0(0);
354
        vtx.a_sysflip1(0) := r.sysflip1;
355
        vtx.a_sysflip1(1) := rtx.a_sysflip1(0);
356
 
357
        -- Stage B: Multiplex tokens from system clock domain.
358
        -- Update stage B three bit periods after updating stage C
359
        -- (i.e. in time for the next update of stage C).
360 3 jorisvr
        -- Do not update stage B if stage C is indicating that it needs to
361
        -- send a second token to complete its task.
362
        vtx.b_update := rtx.txclken and rtx.e_count(0) and (not rtx.c_busy);
363 2 jorisvr
        if rtx.b_mux = '0' then
364
            vtx.b_txflip := rtx.txflip0;
365
        else
366
            vtx.b_txflip := rtx.txflip1;
367
        end if;
368
        if rtx.b_update = '1' then
369
            if rtx.b_mux = '0' then
370
                -- get token from slot 0
371
                vtx.b_valid := rtx.a_sysflip0(1) xor rtx.b_txflip;
372
                vtx.b_token := r.token0;
373
                -- update mux flag if we got a valid token
374
                vtx.b_mux   := rtx.a_sysflip0(1) xor rtx.b_txflip;
375
                vtx.txflip0 := rtx.a_sysflip0(1);
376
                vtx.txflip1 := rtx.txflip1;
377
            else
378
                -- get token from slot 1
379
                vtx.b_valid := rtx.a_sysflip1(1) xor rtx.b_txflip;
380
                vtx.b_token := r.token1;
381
                -- update mux flag if we got a valid token
382
                vtx.b_mux   := not (rtx.a_sysflip1(1) xor rtx.b_txflip);
383
                vtx.txflip0 := rtx.txflip0;
384
                vtx.txflip1 := rtx.a_sysflip1(1);
385
            end if;
386
        end if;
387
 
388
        -- Stage C: Prepare to transmit EOP, EEP or a data character.
389
        vtx.c_update := rtx.txclken and rtx.e_count(3);
390
        if rtx.c_update = '1' then
391 3 jorisvr
 
392
            -- NULL is broken into two tokens: ESC + FCT.
393
            -- Time-codes are broken into two tokens: ESC + char.
394
 
395
            -- Enable c_esc on the first pass of a NULL or a time-code.
396 2 jorisvr
            vtx.c_esc   := (rtx.b_token.tick or (not rtx.b_valid)) and
397
                           (not rtx.c_esc);
398 3 jorisvr
 
399
            -- Enable c_fct on the first pass of an FCT and on
400
            -- the second pass of a NULL (also the first pass, but c_esc
401
            -- is stronger than c_fct).
402
            vtx.c_fct   := (rtx.b_token.fct and (not rtx.c_busy)) or
403
                           (not rtx.b_valid);
404
 
405
            -- Enable c_busy on the first pass of a NULL or a time-code
406
            -- or a piggy-backed FCT. This will tell stage B that we are
407
            -- not done yet.
408
            vtx.c_busy  := (rtx.b_token.tick or (not rtx.b_valid) or
409
                            rtx.b_token.fctpiggy) and (not rtx.c_busy);
410
 
411 2 jorisvr
            if rtx.b_token.flag = '1' then
412
                if rtx.b_token.char(0) = '0' then
413
                    -- prepare to send EOP
414
                    vtx.c_bits  := "000000101"; -- EOP = P101
415
                else
416
                    -- prepare to send EEP
417
                    vtx.c_bits  := "000000011"; -- EEP = P110
418
                end if;
419
            else
420
                -- prepare to send data char
421
                vtx.c_bits  := rtx.b_token.char & '0';
422
            end if;
423
        end if;
424
 
425
        -- Stage D: Prepare to transmit FCT, ESC, or the stuff from stage C.
426
        if rtx.c_esc = '1' then
427
            -- prepare to send ESC
428
            vtx.d_bits  := "000000111";     -- ESC = P111
429
            vtx.d_cnt4  := '1';             -- 3 bits + implicit parity bit
430
            vtx.d_cnt10 := '0';
431
        elsif rtx.c_fct = '1' then
432
            -- prepare to send FCT
433
            vtx.d_bits  := "000000001";     -- FCT = P100
434
            vtx.d_cnt4  := '1';             -- 3 bits + implicit parity bit
435
            vtx.d_cnt10 := '0';
436
        else
437
            -- send the stuff from stage C.
438
            vtx.d_bits  := rtx.c_bits;
439
            vtx.d_cnt4  := rtx.c_bits(0);
440
            vtx.d_cnt10 := not rtx.c_bits(0);
441
        end if;
442
 
443
        -- Stage E: Shift register.
444
        if rtx.txclken = '1' then
445
            if rtx.e_count(0) = '1' then
446
                -- reload shift register; output parity bit
447
                vtx.e_valid  := '1';
448
                vtx.e_shift(vtx.e_shift'high downto 1) := rtx.d_bits;
449
                vtx.e_shift(0) := not (rtx.e_parity xor rtx.d_bits(0));
450
                vtx.e_count  := rtx.d_cnt10 & "00000" & rtx.d_cnt4 & "000";
451
                vtx.e_parity := rtx.d_bits(0);
452
            else
453
                -- shift bits to output; update parity bit
454
                vtx.e_shift  := '0' & rtx.e_shift(rtx.e_shift'high downto 1);
455
                vtx.e_count  := '0' & rtx.e_count(rtx.e_count'high downto 1);
456
                vtx.e_parity := rtx.e_parity xor rtx.e_shift(1);
457
            end if;
458
        end if;
459
 
460
        -- Stage F: Data/strobe encoding.
461
        if rtx.txclken = '1' then
462
            if rtx.e_valid = '1' then
463
                -- output next data/strobe bits
464
                vtx.f_spwdo := rtx.e_shift(0);
465
                vtx.f_spwso := not (rtx.e_shift(0) xor rtx.f_spwdo xor rtx.f_spwso);
466
            else
467
                -- gentle reset of spacewire signals
468
                vtx.f_spwdo := rtx.f_spwdo and rtx.f_spwso;
469
                vtx.f_spwso := '0';
470
            end if;
471
        end if;
472
 
473
        -- Generate tx clock enable
474
        -- An 8-bit counter decrements on every clock. A txclken pulse is
475
        -- produced 2 cycles after the counter reaches value 2. Counter reload
476
        -- values of 0 and 1 are handled as special cases.
477
        -- count down in blocks of two bits
478
        vtx.txclkcnt(1 downto 0) := std_logic_vector(unsigned(rtx.txclkcnt(1 downto 0)) - 1);
479
        vtx.txclkcnt(3 downto 2) := std_logic_vector(unsigned(rtx.txclkcnt(3 downto 2)) - unsigned(rtx.txclkcy(0 downto 0)));
480
        vtx.txclkcnt(5 downto 4) := std_logic_vector(unsigned(rtx.txclkcnt(5 downto 4)) - unsigned(rtx.txclkcy(1 downto 1)));
481
        vtx.txclkcnt(7 downto 6) := std_logic_vector(unsigned(rtx.txclkcnt(7 downto 6)) - unsigned(rtx.txclkcy(2 downto 2)));
482
        -- propagate carry in blocks of two bits
483
        vtx.txclkcy(0) := bool_to_logic(rtx.txclkcnt(1 downto 0) = "00");
484
        vtx.txclkcy(1) := rtx.txclkcy(0) and bool_to_logic(rtx.txclkcnt(3 downto 2) = "00");
485
        vtx.txclkcy(2) := rtx.txclkcy(1) and bool_to_logic(rtx.txclkcnt(5 downto 4) = "00");
486
        -- detect value 2 in counter
487
        vtx.txclkdone(0) := bool_to_logic(rtx.txclkcnt(3 downto 0) = "0010");
488
        vtx.txclkdone(1) := bool_to_logic(rtx.txclkcnt(7 downto 4) = "0000");
489
        -- trigger txclken
490
        vtx.txclken  := (rtx.txclkdone(0) and rtx.txclkdone(1)) or rtx.txclkpre;
491
        vtx.txclkpre := (not rtx.txdivnorm) and ((not rtx.txclkpre) or (not rtx.txclkdiv(0)));
492
        -- reload counter
493
        if rtx.txclken = '1' then
494
            vtx.txclkcnt  := rtx.txclkdiv;
495
            vtx.txclkcy   := "000";
496
            vtx.txclkdone := "00";
497
        end if;
498
 
499
        -- Synchronize txclkdiv
500
        vtx.txdivsafe(0) := r.txdivsafe;
501
        vtx.txdivsafe(1) := rtx.txdivsafe(0);
502
        if rtx.txdivsafe(1) = '1' then
503
            vtx.txclkdiv  := r.txdivreg;
504
            vtx.txdivnorm := r.txdivnorm;
505
        end if;
506
 
507
        -- Synchronize txen signal.
508
        vtx.txensync(0) := r.txenreg;
509
        vtx.txensync(1) := rtx.txensync(0);
510
 
511
        -- Transmitter disabled.
512
        if rtx.txensync(1) = '0' then
513
            vtx.txflip0   := '0';
514
            vtx.txflip1   := '0';
515
            vtx.b_update  := '0';
516
            vtx.b_mux     := '0';
517
            vtx.b_valid   := '0';
518
            vtx.c_update  := '0';
519 3 jorisvr
            vtx.c_busy    := '1';
520 2 jorisvr
            vtx.c_esc     := '1';           -- need to send 2nd part of NULL
521
            vtx.c_fct     := '1';
522
            vtx.d_bits    := "000000111";   -- ESC = P111
523
            vtx.d_cnt4    := '1';           -- 3 bits + implicit parity bit
524
            vtx.d_cnt10   := '0';
525
            vtx.e_valid   := '0';
526
            vtx.e_parity  := '0';
527
            vtx.e_count   := (0 => '1', others => '0');
528
        end if;
529
 
530
        -- Reset.
531
        if s_tx_reset = '1' then
532
            vtx.f_spwdo   := '0';
533
            vtx.f_spwso   := '0';
534
            vtx.txensync  := "00";
535
            vtx.txclken   := '0';
536
            vtx.txclkpre  := '1';
537
            vtx.txclkcnt  := (others => '0');
538
            vtx.txclkdiv  := (others => '0');
539
            vtx.txdivnorm := '0';
540
        end if;
541
 
542
        -- ---- SYSTEM CLOCK DOMAIN ----
543
 
544
        -- Hold divcnt and txen for use by txclk domain.
545
        v.txdivtmp  := std_logic_vector(unsigned(r.txdivtmp) - 1);
546
        if r.txdivtmp = "00" then
547
            if r.txdivsafe = '0' then
548
                -- Latch the current value of divcnt and txen.
549
                v.txdivsafe := '1';
550
                v.txdivtmp  := "01";
551
                v.txdivreg  := divcnt;
552
                if unsigned(divcnt(divcnt'high downto 1)) = 0 then
553
                    v.txdivnorm := '0';
554
                else
555
                    v.txdivnorm := '1';
556
                end if;
557
                v.txenreg   := xmiti.txen;
558
            else
559
                -- Drop the txdivsafe flag but keep latched values.
560
                v.txdivsafe := '0';
561
            end if;
562
        end if;
563
 
564
        -- Pass falling edge of txen signal as soon as possible.
565
        if xmiti.txen = '0' then
566
            v.txenreg   := '0';
567
        end if;
568
 
569
        -- Synchronize feedback from txclk domain.
570
        v.txflip0(0) := rtx.txflip0;
571
        v.txflip0(1) := r.txflip0(0);
572
        v.txflip1(0) := rtx.txflip1;
573
        v.txflip1(1) := r.txflip1(0);
574
 
575
        -- Store requests for FCT transmission.
576
        if xmiti.fct_in = '1' and r.allow_fct = '1' then
577
            v.pend_fct  := '1';
578
        end if;
579
 
580
        if xmiti.txen = '0' then
581
 
582
            -- Transmitter disabled; reset state.
583
            v.sysflip0    := '0';
584
            v.sysflip1    := '0';
585
            v.tokmux      := '0';
586
            v.pend_fct    := '0';
587
            v.pend_char   := '0';
588
            v.pend_tick   := '0';
589
            v.allow_fct   := '0';
590
            v.allow_char  := '0';
591
            v.sent_fct    := '0';
592
 
593
        else
594
 
595
            -- Determine if a new token is needed.
596
            if r.tokmux = '0' then
597
                if r.sysflip0 = r.txflip0(1) then
598
                    v_needtoken := '1';
599
                end if;
600
            else
601
                if r.sysflip1 = r.txflip1(1) then
602
                    v_needtoken := '1';
603
                end if;
604
            end if;
605
 
606
            -- Prepare new token.
607
            if r.allow_char = '1' and r.pend_tick = '1' then
608
                -- prepare to send time code
609
                v_token.tick  := '1';
610
                v_token.fct   := '0';
611 3 jorisvr
                v_token.fctpiggy := '0';
612 2 jorisvr
                v_token.flag  := '0';
613
                v_token.char  := r.pend_time;
614
                v_havetoken   := '1';
615
                if v_needtoken = '1' then
616
                    v.pend_tick := '0';
617
                end if;
618 3 jorisvr
            else
619
                if r.allow_fct = '1' and (xmiti.fct_in = '1' or r.pend_fct = '1') then
620
                    -- prepare to send FCT
621
                    v_token.fct   := '1';
622
                    v_havetoken   := '1';
623
                    if v_needtoken = '1' then
624
                        v.pend_fct  := '0';
625
                        v.sent_fct  := '1';
626
                    end if;
627 2 jorisvr
                end if;
628 3 jorisvr
                if r.allow_char = '1' and r.pend_char = '1' then
629
                    -- prepare to send N-Char
630
                    -- Note: it is possible to send an FCT and an N-Char
631
                    -- together by enabling the fctpiggy flag.
632
                    v_token.fctpiggy := v_token.fct;
633
                    v_token.flag  := r.pend_data(8);
634
                    v_token.char  := r.pend_data(7 downto 0);
635
                    v_havetoken   := '1';
636
                    if v_needtoken = '1' then
637
                        v.pend_char := '0';
638
                    end if;
639 2 jorisvr
                end if;
640
            end if;
641
 
642
            -- Put new token in slot.
643
            if v_havetoken = '1' then
644
                if r.tokmux = '0' then
645
                    if r.sysflip0 = r.txflip0(1) then
646
                        v.sysflip0  := not r.sysflip0;
647
                        v.token0    := v_token;
648
                        v.tokmux    := '1';
649
                    end if;
650
                else
651
                    if r.sysflip1 = r.txflip1(1) then
652
                        v.sysflip1  := not r.sysflip1;
653
                        v.token1    := v_token;
654
                        v.tokmux    := '0';
655
                    end if;
656
                end if;
657
            end if;
658
 
659
            -- Determine whether we are allowed to send FCTs and characters
660
            v.allow_fct  := not xmiti.stnull;
661
            v.allow_char := (not xmiti.stnull) and (not xmiti.stfct) and r.sent_fct;
662
 
663
            -- Store request for data transmission.
664
            if xmiti.txwrite = '1' and r.allow_char = '1' and r.pend_char = '0' then
665
                v.pend_char  := '1';
666
                v.pend_data  := xmiti.txflag & xmiti.txdata;
667
            end if;
668
 
669
            -- Store requests for time tick transmission.
670
            if xmiti.tick_in = '1' then
671
                v.pend_tick := '1';
672
                v.pend_time := xmiti.ctrl_in & xmiti.time_in;
673
            end if;
674
 
675
        end if;
676
 
677
        -- Synchronous reset of system clock domain.
678
        if rst = '1' then
679
            v := regs_reset;
680
        end if;
681
 
682
        -- Drive outputs.
683
        -- Note: the outputs are combinatorially dependent on certain inputs.
684
 
685
        -- Set fctack high if (FCT requested) and (FCTs allowed) AND
686
        -- (no FCT pending)
687
        xmito.fctack <= xmiti.fct_in and xmiti.txen and r.allow_fct and
688
                        (not r.pend_fct);
689
 
690
        -- Set txrdy high if (character requested) AND (characters allowed) AND
691
        -- (no character pending)
692
        xmito.txack <= xmiti.txwrite and xmiti.txen and r.allow_char and
693
                       (not r.pend_char);
694
 
695
        -- Update registers.
696
        rin     <= v;
697
        rtxin   <= vtx;
698
    end process;
699
 
700
    -- Synchronous process in txclk domain
701
    process (txclk) is
702
    begin
703
        if rising_edge(txclk) then
704
            -- drive spacewire output signals
705
            s_spwdo <= rtx.f_spwdo;
706
            s_spwso <= rtx.f_spwso;
707
            -- update registers
708
            rtx <= rtxin;
709
        end if;
710
    end process;
711
 
712
    -- Synchronous process in system clock domain
713
    process (clk) is
714
    begin
715
        if rising_edge(clk) then
716
            -- update registers
717
            r <= rin;
718
        end if;
719
    end process;
720
 
721
    -- Reset synchronizer for txclk domain
722
    process (txclk, rst) is
723
    begin
724
        if rst = '1' then
725
            s_tx_rst_sync <= "11";
726
            s_tx_reset    <= '1';
727
        elsif rising_edge(txclk) then
728
            s_tx_rst_sync <= s_tx_rst_sync(0 downto 0) & "0";
729
            s_tx_reset    <= s_tx_rst_sync(1);
730
        end if;
731
    end process;
732
 
733
end architecture spwxmit_fast_arch;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.