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 2

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
--  See the datasheet for an analysis of that case.
126
--
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
        flag:       std_ulogic;                     -- send EOP or EEP
204
        char:       std_logic_vector(7 downto 0);   -- character or time code
205
    end record;
206
 
207
    -- Registers in txclk domain
208
    type txregs_type is record
209
        -- sync to system clock domain
210
        txflip0:    std_ulogic;
211
        txflip1:    std_ulogic;
212
        -- stage A
213
        a_sysflip0: std_logic_vector(1 downto 0);
214
        a_sysflip1: std_logic_vector(1 downto 0);
215
        -- stage B
216
        b_update:   std_ulogic;
217
        b_mux:      std_ulogic;
218
        b_txflip:   std_ulogic;
219
        b_valid:    std_ulogic;
220
        b_token:    token_type;
221
        -- stage C
222
        c_update:   std_ulogic;
223
        c_esc:      std_ulogic;
224
        c_fct:      std_ulogic;
225
        c_bits:     std_logic_vector(8 downto 0);
226
        -- stage D
227
        d_bits:     std_logic_vector(8 downto 0);
228
        d_cnt4:     std_ulogic;
229
        d_cnt10:    std_ulogic;
230
        -- stage E
231
        e_valid:    std_ulogic;
232
        e_shift:    std_logic_vector(9 downto 0);
233
        e_count:    std_logic_vector(9 downto 0);
234
        e_parity:   std_ulogic;
235
        -- stage F
236
        f_spwdo:    std_ulogic;
237
        f_spwso:    std_ulogic;
238
        -- tx clock enable logic
239
        txclken:    std_ulogic;
240
        txclkpre:   std_ulogic;
241
        txclkcnt:   std_logic_vector(7 downto 0);
242
        txclkcy:    std_logic_vector(2 downto 0);
243
        txclkdone:  std_logic_vector(1 downto 0);
244
        txclkdiv:   std_logic_vector(7 downto 0);
245
        txdivnorm:  std_ulogic;
246
        txdivsafe:  std_logic_vector(1 downto 0);
247
        -- tx enable logic
248
        txensync:   std_logic_vector(1 downto 0);
249
    end record;
250
 
251
    -- Registers in system clock domain
252
    type regs_type is record
253
        -- sync status to txclk domain
254
        txenreg:    std_ulogic;
255
        txdivreg:   std_logic_vector(7 downto 0);
256
        txdivnorm:  std_ulogic;
257
        txdivtmp:   std_logic_vector(1 downto 0);
258
        txdivsafe:  std_ulogic;
259
        -- data stream to txclk domain
260
        sysflip0:   std_ulogic;
261
        sysflip1:   std_ulogic;
262
        token0:     token_type;
263
        token1:     token_type;
264
        tokmux:     std_ulogic;
265
        -- sync feedback from txclk domain
266
        txflip0:    std_logic_vector(1 downto 0);
267
        txflip1:    std_logic_vector(1 downto 0);
268
        -- transmitter management
269
        pend_fct:   std_ulogic;                     -- '1' if an outgoing FCT is pending
270
        pend_char:  std_ulogic;                     -- '1' if an outgoing N-Char is pending
271
        pend_data:  std_logic_vector(8 downto 0);   -- control flag and data bits of pending char
272
        pend_tick:  std_ulogic;                     -- '1' if an outgoing time tick is pending
273
        pend_time:  std_logic_vector(7 downto 0);   -- data bits of pending time tick
274
        allow_fct:  std_ulogic;                     -- '1' when allowed to send FCTs
275
        allow_char: std_ulogic;                     -- '1' when allowed to send data and time
276
        sent_fct:   std_ulogic;                     -- '1' when at least one FCT token was sent
277
    end record;
278
 
279
    -- Initial state of system clock domain
280
    constant regs_reset: regs_type := (
281
        txenreg     => '0',
282
        txdivreg    => (others => '0'),
283
        txdivnorm   => '0',
284
        txdivtmp    => "00",
285
        txdivsafe   => '0',
286
        sysflip0    => '0',
287
        sysflip1    => '0',
288
        token0      => ( tick => '0', fct => '0', flag => '0', char => (others => '0') ),
289
        token1      => ( tick => '0', fct => '0', flag => '0', char => (others => '0') ),
290
        tokmux      => '0',
291
        txflip0     => "00",
292
        txflip1     => "00",
293
        pend_fct    => '0',
294
        pend_char   => '0',
295
        pend_data   => (others => '0'),
296
        pend_tick   => '0',
297
        pend_time   => (others => '0'),
298
        allow_fct   => '0',
299
        allow_char  => '0',
300
        sent_fct    => '0' );
301
 
302
    -- Registers
303
    signal rtx:     txregs_type;
304
    signal rtxin:   txregs_type;
305
    signal r:       regs_type := regs_reset;
306
    signal rin:     regs_type;
307
 
308
    -- Reset synchronizer for txclk domain
309
    signal s_tx_rst_sync: std_logic_vector(1 downto 0) := "11";
310
    signal s_tx_reset:    std_ulogic := '1';
311
 
312
    -- Output flip-flops
313
    signal s_spwdo: std_logic;
314
    signal s_spwso: std_logic;
315
 
316
    -- Force use of IOB flip-flops
317
    attribute IOB: string;
318
    attribute IOB of s_spwdo: signal is "TRUE";
319
    attribute IOB of s_spwso: signal is "TRUE";
320
 
321
begin
322
 
323
    -- Drive SpaceWire output signals
324
    spw_do      <= s_spwdo;
325
    spw_so      <= s_spwso;
326
 
327
    -- Combinatorial process
328
    process (r, rtx, rst, divcnt, xmiti, s_tx_reset) is
329
        variable v:         regs_type;
330
        variable vtx:       txregs_type;
331
        variable v_needtoken: std_ulogic;
332
        variable v_havetoken: std_ulogic;
333
        variable v_token:     token_type;
334
    begin
335
        v           := r;
336
        vtx         := rtx;
337
        v_needtoken := '0';
338
        v_havetoken := '0';
339
        v_token     := ( tick => '0', fct => '0', flag => '0', char => (others => '0') );
340
 
341
        -- ---- FAST CLOCK DOMAIN ----
342
 
343
        -- Stage A: Synchronize token buffer counts from system clock domain.
344
        vtx.a_sysflip0(0) := r.sysflip0;
345
        vtx.a_sysflip0(1) := rtx.a_sysflip0(0);
346
        vtx.a_sysflip1(0) := r.sysflip1;
347
        vtx.a_sysflip1(1) := rtx.a_sysflip1(0);
348
 
349
        -- Stage B: Multiplex tokens from system clock domain.
350
        -- Update stage B three bit periods after updating stage C
351
        -- (i.e. in time for the next update of stage C).
352
        -- Do not update stage B if the last token from stage C was ESC;
353
        -- stage C already knows what token to put after the ESC.
354
        vtx.b_update := rtx.txclken and rtx.e_count(0) and (not rtx.c_esc);
355
        if rtx.b_mux = '0' then
356
            vtx.b_txflip := rtx.txflip0;
357
        else
358
            vtx.b_txflip := rtx.txflip1;
359
        end if;
360
        if rtx.b_update = '1' then
361
            if rtx.b_mux = '0' then
362
                -- get token from slot 0
363
                vtx.b_valid := rtx.a_sysflip0(1) xor rtx.b_txflip;
364
                vtx.b_token := r.token0;
365
                -- update mux flag if we got a valid token
366
                vtx.b_mux   := rtx.a_sysflip0(1) xor rtx.b_txflip;
367
                vtx.txflip0 := rtx.a_sysflip0(1);
368
                vtx.txflip1 := rtx.txflip1;
369
            else
370
                -- get token from slot 1
371
                vtx.b_valid := rtx.a_sysflip1(1) xor rtx.b_txflip;
372
                vtx.b_token := r.token1;
373
                -- update mux flag if we got a valid token
374
                vtx.b_mux   := not (rtx.a_sysflip1(1) xor rtx.b_txflip);
375
                vtx.txflip0 := rtx.txflip0;
376
                vtx.txflip1 := rtx.a_sysflip1(1);
377
            end if;
378
        end if;
379
 
380
        -- Stage C: Prepare to transmit EOP, EEP or a data character.
381
        vtx.c_update := rtx.txclken and rtx.e_count(3);
382
        if rtx.c_update = '1' then
383
            -- NULL is broken into two tokens: ESC + FCT
384
            -- time codes are broken into two tokens: ESC + char
385
            vtx.c_esc   := (rtx.b_token.tick or (not rtx.b_valid)) and
386
                           (not rtx.c_esc);
387
            vtx.c_fct   := rtx.b_token.fct or (not rtx.b_valid);
388
            if rtx.b_token.flag = '1' then
389
                if rtx.b_token.char(0) = '0' then
390
                    -- prepare to send EOP
391
                    vtx.c_bits  := "000000101"; -- EOP = P101
392
                else
393
                    -- prepare to send EEP
394
                    vtx.c_bits  := "000000011"; -- EEP = P110
395
                end if;
396
            else
397
                -- prepare to send data char
398
                vtx.c_bits  := rtx.b_token.char & '0';
399
            end if;
400
        end if;
401
 
402
        -- Stage D: Prepare to transmit FCT, ESC, or the stuff from stage C.
403
        if rtx.c_esc = '1' then
404
            -- prepare to send ESC
405
            vtx.d_bits  := "000000111";     -- ESC = P111
406
            vtx.d_cnt4  := '1';             -- 3 bits + implicit parity bit
407
            vtx.d_cnt10 := '0';
408
        elsif rtx.c_fct = '1' then
409
            -- prepare to send FCT
410
            vtx.d_bits  := "000000001";     -- FCT = P100
411
            vtx.d_cnt4  := '1';             -- 3 bits + implicit parity bit
412
            vtx.d_cnt10 := '0';
413
        else
414
            -- send the stuff from stage C.
415
            vtx.d_bits  := rtx.c_bits;
416
            vtx.d_cnt4  := rtx.c_bits(0);
417
            vtx.d_cnt10 := not rtx.c_bits(0);
418
        end if;
419
 
420
        -- Stage E: Shift register.
421
        if rtx.txclken = '1' then
422
            if rtx.e_count(0) = '1' then
423
                -- reload shift register; output parity bit
424
                vtx.e_valid  := '1';
425
                vtx.e_shift(vtx.e_shift'high downto 1) := rtx.d_bits;
426
                vtx.e_shift(0) := not (rtx.e_parity xor rtx.d_bits(0));
427
                vtx.e_count  := rtx.d_cnt10 & "00000" & rtx.d_cnt4 & "000";
428
                vtx.e_parity := rtx.d_bits(0);
429
            else
430
                -- shift bits to output; update parity bit
431
                vtx.e_shift  := '0' & rtx.e_shift(rtx.e_shift'high downto 1);
432
                vtx.e_count  := '0' & rtx.e_count(rtx.e_count'high downto 1);
433
                vtx.e_parity := rtx.e_parity xor rtx.e_shift(1);
434
            end if;
435
        end if;
436
 
437
        -- Stage F: Data/strobe encoding.
438
        if rtx.txclken = '1' then
439
            if rtx.e_valid = '1' then
440
                -- output next data/strobe bits
441
                vtx.f_spwdo := rtx.e_shift(0);
442
                vtx.f_spwso := not (rtx.e_shift(0) xor rtx.f_spwdo xor rtx.f_spwso);
443
            else
444
                -- gentle reset of spacewire signals
445
                vtx.f_spwdo := rtx.f_spwdo and rtx.f_spwso;
446
                vtx.f_spwso := '0';
447
            end if;
448
        end if;
449
 
450
        -- Generate tx clock enable
451
        -- An 8-bit counter decrements on every clock. A txclken pulse is
452
        -- produced 2 cycles after the counter reaches value 2. Counter reload
453
        -- values of 0 and 1 are handled as special cases.
454
        -- count down in blocks of two bits
455
        vtx.txclkcnt(1 downto 0) := std_logic_vector(unsigned(rtx.txclkcnt(1 downto 0)) - 1);
456
        vtx.txclkcnt(3 downto 2) := std_logic_vector(unsigned(rtx.txclkcnt(3 downto 2)) - unsigned(rtx.txclkcy(0 downto 0)));
457
        vtx.txclkcnt(5 downto 4) := std_logic_vector(unsigned(rtx.txclkcnt(5 downto 4)) - unsigned(rtx.txclkcy(1 downto 1)));
458
        vtx.txclkcnt(7 downto 6) := std_logic_vector(unsigned(rtx.txclkcnt(7 downto 6)) - unsigned(rtx.txclkcy(2 downto 2)));
459
        -- propagate carry in blocks of two bits
460
        vtx.txclkcy(0) := bool_to_logic(rtx.txclkcnt(1 downto 0) = "00");
461
        vtx.txclkcy(1) := rtx.txclkcy(0) and bool_to_logic(rtx.txclkcnt(3 downto 2) = "00");
462
        vtx.txclkcy(2) := rtx.txclkcy(1) and bool_to_logic(rtx.txclkcnt(5 downto 4) = "00");
463
        -- detect value 2 in counter
464
        vtx.txclkdone(0) := bool_to_logic(rtx.txclkcnt(3 downto 0) = "0010");
465
        vtx.txclkdone(1) := bool_to_logic(rtx.txclkcnt(7 downto 4) = "0000");
466
        -- trigger txclken
467
        vtx.txclken  := (rtx.txclkdone(0) and rtx.txclkdone(1)) or rtx.txclkpre;
468
        vtx.txclkpre := (not rtx.txdivnorm) and ((not rtx.txclkpre) or (not rtx.txclkdiv(0)));
469
        -- reload counter
470
        if rtx.txclken = '1' then
471
            vtx.txclkcnt  := rtx.txclkdiv;
472
            vtx.txclkcy   := "000";
473
            vtx.txclkdone := "00";
474
        end if;
475
 
476
        -- Synchronize txclkdiv
477
        vtx.txdivsafe(0) := r.txdivsafe;
478
        vtx.txdivsafe(1) := rtx.txdivsafe(0);
479
        if rtx.txdivsafe(1) = '1' then
480
            vtx.txclkdiv  := r.txdivreg;
481
            vtx.txdivnorm := r.txdivnorm;
482
        end if;
483
 
484
        -- Synchronize txen signal.
485
        vtx.txensync(0) := r.txenreg;
486
        vtx.txensync(1) := rtx.txensync(0);
487
 
488
        -- Transmitter disabled.
489
        if rtx.txensync(1) = '0' then
490
            vtx.txflip0   := '0';
491
            vtx.txflip1   := '0';
492
            vtx.b_update  := '0';
493
            vtx.b_mux     := '0';
494
            vtx.b_valid   := '0';
495
            vtx.c_update  := '0';
496
            vtx.c_esc     := '1';           -- need to send 2nd part of NULL
497
            vtx.c_fct     := '1';
498
            vtx.d_bits    := "000000111";   -- ESC = P111
499
            vtx.d_cnt4    := '1';           -- 3 bits + implicit parity bit
500
            vtx.d_cnt10   := '0';
501
            vtx.e_valid   := '0';
502
            vtx.e_parity  := '0';
503
            vtx.e_count   := (0 => '1', others => '0');
504
        end if;
505
 
506
        -- Reset.
507
        if s_tx_reset = '1' then
508
            vtx.f_spwdo   := '0';
509
            vtx.f_spwso   := '0';
510
            vtx.txensync  := "00";
511
            vtx.txclken   := '0';
512
            vtx.txclkpre  := '1';
513
            vtx.txclkcnt  := (others => '0');
514
            vtx.txclkdiv  := (others => '0');
515
            vtx.txdivnorm := '0';
516
        end if;
517
 
518
        -- ---- SYSTEM CLOCK DOMAIN ----
519
 
520
        -- Hold divcnt and txen for use by txclk domain.
521
        v.txdivtmp  := std_logic_vector(unsigned(r.txdivtmp) - 1);
522
        if r.txdivtmp = "00" then
523
            if r.txdivsafe = '0' then
524
                -- Latch the current value of divcnt and txen.
525
                v.txdivsafe := '1';
526
                v.txdivtmp  := "01";
527
                v.txdivreg  := divcnt;
528
                if unsigned(divcnt(divcnt'high downto 1)) = 0 then
529
                    v.txdivnorm := '0';
530
                else
531
                    v.txdivnorm := '1';
532
                end if;
533
                v.txenreg   := xmiti.txen;
534
            else
535
                -- Drop the txdivsafe flag but keep latched values.
536
                v.txdivsafe := '0';
537
            end if;
538
        end if;
539
 
540
        -- Pass falling edge of txen signal as soon as possible.
541
        if xmiti.txen = '0' then
542
            v.txenreg   := '0';
543
        end if;
544
 
545
        -- Synchronize feedback from txclk domain.
546
        v.txflip0(0) := rtx.txflip0;
547
        v.txflip0(1) := r.txflip0(0);
548
        v.txflip1(0) := rtx.txflip1;
549
        v.txflip1(1) := r.txflip1(0);
550
 
551
        -- Store requests for FCT transmission.
552
        if xmiti.fct_in = '1' and r.allow_fct = '1' then
553
            v.pend_fct  := '1';
554
        end if;
555
 
556
        if xmiti.txen = '0' then
557
 
558
            -- Transmitter disabled; reset state.
559
            v.sysflip0    := '0';
560
            v.sysflip1    := '0';
561
            v.tokmux      := '0';
562
            v.pend_fct    := '0';
563
            v.pend_char   := '0';
564
            v.pend_tick   := '0';
565
            v.allow_fct   := '0';
566
            v.allow_char  := '0';
567
            v.sent_fct    := '0';
568
 
569
        else
570
 
571
            -- Determine if a new token is needed.
572
            if r.tokmux = '0' then
573
                if r.sysflip0 = r.txflip0(1) then
574
                    v_needtoken := '1';
575
                end if;
576
            else
577
                if r.sysflip1 = r.txflip1(1) then
578
                    v_needtoken := '1';
579
                end if;
580
            end if;
581
 
582
            -- Prepare new token.
583
            if r.allow_char = '1' and r.pend_tick = '1' then
584
                -- prepare to send time code
585
                v_token.tick  := '1';
586
                v_token.fct   := '0';
587
                v_token.flag  := '0';
588
                v_token.char  := r.pend_time;
589
                v_havetoken   := '1';
590
                if v_needtoken = '1' then
591
                    v.pend_tick := '0';
592
                end if;
593
            elsif r.allow_fct = '1' and (xmiti.fct_in = '1' or r.pend_fct = '1') then
594
                -- prepare to send FCT
595
                v_token.tick  := '0';
596
                v_token.fct   := '1';
597
                v_token.flag  := '0';
598
                v_havetoken   := '1';
599
                if v_needtoken = '1' then
600
                    v.pend_fct  := '0';
601
                    v.sent_fct  := '1';
602
                end if;
603
            elsif r.allow_char = '1' and r.pend_char = '1' then
604
                -- prepare to send N-Char
605
                v_token.tick  := '0';
606
                v_token.fct   := '0';
607
                v_token.flag  := r.pend_data(8);
608
                v_token.char  := r.pend_data(7 downto 0);
609
                v_havetoken   := '1';
610
                if v_needtoken = '1' then
611
                    v.pend_char := '0';
612
                end if;
613
            end if;
614
 
615
            -- Put new token in slot.
616
            if v_havetoken = '1' then
617
                if r.tokmux = '0' then
618
                    if r.sysflip0 = r.txflip0(1) then
619
                        v.sysflip0  := not r.sysflip0;
620
                        v.token0    := v_token;
621
                        v.tokmux    := '1';
622
                    end if;
623
                else
624
                    if r.sysflip1 = r.txflip1(1) then
625
                        v.sysflip1  := not r.sysflip1;
626
                        v.token1    := v_token;
627
                        v.tokmux    := '0';
628
                    end if;
629
                end if;
630
            end if;
631
 
632
            -- Determine whether we are allowed to send FCTs and characters
633
            v.allow_fct  := not xmiti.stnull;
634
            v.allow_char := (not xmiti.stnull) and (not xmiti.stfct) and r.sent_fct;
635
 
636
            -- Store request for data transmission.
637
            if xmiti.txwrite = '1' and r.allow_char = '1' and r.pend_char = '0' then
638
                v.pend_char  := '1';
639
                v.pend_data  := xmiti.txflag & xmiti.txdata;
640
            end if;
641
 
642
            -- Store requests for time tick transmission.
643
            if xmiti.tick_in = '1' then
644
                v.pend_tick := '1';
645
                v.pend_time := xmiti.ctrl_in & xmiti.time_in;
646
            end if;
647
 
648
        end if;
649
 
650
        -- Synchronous reset of system clock domain.
651
        if rst = '1' then
652
            v := regs_reset;
653
        end if;
654
 
655
        -- Drive outputs.
656
        -- Note: the outputs are combinatorially dependent on certain inputs.
657
 
658
        -- Set fctack high if (FCT requested) and (FCTs allowed) AND
659
        -- (no FCT pending)
660
        xmito.fctack <= xmiti.fct_in and xmiti.txen and r.allow_fct and
661
                        (not r.pend_fct);
662
 
663
        -- Set txrdy high if (character requested) AND (characters allowed) AND
664
        -- (no character pending)
665
        xmito.txack <= xmiti.txwrite and xmiti.txen and r.allow_char and
666
                       (not r.pend_char);
667
 
668
        -- Update registers.
669
        rin     <= v;
670
        rtxin   <= vtx;
671
    end process;
672
 
673
    -- Synchronous process in txclk domain
674
    process (txclk) is
675
    begin
676
        if rising_edge(txclk) then
677
            -- drive spacewire output signals
678
            s_spwdo <= rtx.f_spwdo;
679
            s_spwso <= rtx.f_spwso;
680
            -- update registers
681
            rtx <= rtxin;
682
        end if;
683
    end process;
684
 
685
    -- Synchronous process in system clock domain
686
    process (clk) is
687
    begin
688
        if rising_edge(clk) then
689
            -- update registers
690
            r <= rin;
691
        end if;
692
    end process;
693
 
694
    -- Reset synchronizer for txclk domain
695
    process (txclk, rst) is
696
    begin
697
        if rst = '1' then
698
            s_tx_rst_sync <= "11";
699
            s_tx_reset    <= '1';
700
        elsif rising_edge(txclk) then
701
            s_tx_rst_sync <= s_tx_rst_sync(0 downto 0) & "0";
702
            s_tx_reset    <= s_tx_rst_sync(1);
703
        end if;
704
    end process;
705
 
706
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.