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 10

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 7 jorisvr
--  The data path through the txclk domain is divided into stages B through F
42
--  in a half-hearted attempt to keep things simple.
43 2 jorisvr
--
44
--  Stage B takes a token from the FIFO buffer and updates a buffer status
45
--  flag to indicate that the buffer slot needs to be refilled. If the FIFO
46
--  is empty, a NULL is inserted. Stage B is triggered one clock after
47
--  stage E switches to a new token. If the previous token was ESC, stage B
48
--  skips a turn because stage C will already know what to do.
49
--
50
--  Stage C takes a token from stage B and translates it into a bit pattern.
51
--  Time codes and NULL tokens are broken into two separate tokens starting
52
--  with ESC. Stage C is triggered one clock after the shift buffer in
53
--  stage E drops to 3 tokens.
54
--
55
--  Stage D completes the task of translating tokens to bit patterns and
56
--  distinguishes between 10-bit and 4-bit tokens. It is not explicitly
57
--  triggered but simply follows stage C.
58
--
59
--  Stage E is the bit shift register. It shifts when "txclken" is high.
60
--  A one-hot counter keeps track of the number of bits remaining in
61
--  the register. When the register falls empty, it loads a new 10-bit or
62
--  4-bit pattern as prepared by stage D. Stage E also computes parity.
63
--
64
--  Stage F performs data strobe encoding. When the transmitter is disabled,
65
--  the outputs of stage F fall to zero in a controlled way.
66
-- 
67
--  To generate the transmission bit clock, the txclk is divided by an
68
--  integer factor (divcnt+1) using an 8-bit down counter. The implementation
69
--  of this counter has become quite complicated in order to meet timing goals.
70
--  The counter consists of 4 blocks of two bits each (txclkcnt), with a
71
--  carry-save concept used between blocks (txclkcy). Detection of terminal
72
--  count (txclkdone) has a pipeline delay of two cycles. Therefore a separate
73
--  concept is used if the initial count is less than 2 (txdivnorm). This is
74
--  all glued together in the final assignment to txclken.
75
--
76
--  The initial count for txclk division (divcnt) comes from the system clock
77
--  domain and thus needs to be synchronized for use in the txclk domain.
78
--  To facilitate this, the system clock domain latches the value of divcnt
79
--  once every 6 sysclk cycles and sets a flag to indicate when the latched
80
--  value can safely be used by the txclk domain.
81
--
82
--  A tricky aspect of the design is the initial state of the txclk logic.
83
--  When the transmitter is enabled (txen goes high), the txclk logic starts
84
--  with the first ESC pattern already set up in stage D, and stage C ready
85
--  to produce the FCT part of the first NULL.
86
--
87
--  The following guidelines are used to get good timing for the txclk domain:
88
--   * The new value of a register depends on at most 4 inputs (single LUT),
89
--     or in a few cases on 5 inputs (two LUTs and F5MUX).
90
--   * Synchronous resets may be used, but only if the reset signal comes
91
--     directly from a register (no logic in set/reset path);
92
--   * Clock enables may be used, but only if the enable signal comes directly
93
--     from a register (no logic in clock enable path).
94
--
95
--  Synchronization issues
96
--  ----------------------
97
--
98
--  There is a two-slot FIFO buffer between the system and txclk domains.
99
--  After the txclk domain pulls a token from the buffer, the system clock
100
--  domain should ideally refill the buffer before the txclk domain again
101
--  tries to pull from the same buffer slot. If the refill occurs late,
102
--  the txclk domain needs to insert a NULL token which is inefficient
103
--  use of bandwidth.
104
--
105
--  Assuming the transmission consists of a stream of data characters,
106
--  10 bits per character, there are exactly 2*10 bit periods between
107
--  successive reads from the same buffer slot by the txclk logic.
108
--
109
--  The time needed for the system clock logic to refill a buffer slot =
110
--     1 txclk period   (update of rtx.txflipN)
111
--   + 1 txclk period   (routing delay between domains)
112
--   + 2 sysclk periods (synchronizer for txflipN)
113
--   + 1 sysclk period  (refill buffer slot and update r.sysflipN)
114
--   + 1 txclk period   (routing delay between domains)
115
--   + 2 txclk periods  (synchronizer for sysflipN)
116
--   = 5 txclk periods + 3 sysclk periods
117
--
118
--  If for example txclk is 4 times as fast as sysclk, this amounts to
119
--   5 txclk + 3 sysclk = 5 + 3*4 txclk = 17 txclk
120
--  is less than 20 bit periods even at maximum transmission rate, so
121
--  no problem there.
122
--
123
--  This is different when the data stream includes 4-bit tokens.
124 3 jorisvr
--  See the manual for further comments.
125 2 jorisvr
--
126
--  Implementation guidelines
127
--  -------------------------
128
--
129
--  To minimize clock skew, IOB flip-flops should be used to drive
130
--  spw_do and spw_so.
131
--
132
--  "txclk" must be at least as fast as the system clock;
133
--  "txclk" does not need to be phase-related to the system clock;
134
--  it is allowed for "txclk" to be equal to "clk".
135
--
136
--  The following timing constraints are needed:
137
--   * PERIOD constraint on the system clock;
138
--   * PERIOD constraint on "txclk";
139
--   * FROM-TO constraint from "txclk" to the system clock, equal to
140
--     one "txclk" period;
141
--   * FROM-TO constraint from the system clock to "txclk", equal to
142
--     one "txclk" period.
143
--
144
 
145
library ieee;
146
use ieee.std_logic_1164.all;
147
use ieee.numeric_std.all;
148
use work.spwpkg.all;
149
 
150
entity spwxmit_fast is
151
 
152
    port (
153
        -- System clock.
154
        clk:        in  std_logic;
155
 
156
        -- Transmit clock.
157
        txclk:      in  std_logic;
158
 
159
        -- Synchronous reset (active-high)
160
        -- Used asynchronously by fast clock domain (must be glitch-free).
161
        rst:        in  std_logic;
162
 
163
        -- Scaling factor minus 1, used to scale the system clock into the
164
        -- transmission bit rate. The system clock is divided by
165
        -- (unsigned(divcnt) + 1). Changing this signal will immediately
166
        -- change the transmission rate.
167
        divcnt:     in  std_logic_vector(7 downto 0);
168
 
169
        -- Input signals from spwlink.
170
        xmiti:      in  spw_xmit_in_type;
171
 
172
        -- Output signals to spwlink.
173
        xmito:      out spw_xmit_out_type;
174
 
175
        -- Data Out signal to SpaceWire bus.
176
        spw_do:     out std_logic;
177
 
178
        -- Strobe Out signal to SpaceWire bus.
179
        spw_so:     out std_logic
180
    );
181
 
182
    -- Turn off FSM extraction to avoid synchronization problems.
183
    attribute FSM_EXTRACT: string;
184
    attribute FSM_EXTRACT of spwxmit_fast: entity is "NO";
185
 
186
end entity spwxmit_fast;
187
 
188
architecture spwxmit_fast_arch of spwxmit_fast is
189
 
190
    -- Convert boolean to std_logic.
191
    type bool_to_logic_type is array(boolean) of std_ulogic;
192
    constant bool_to_logic: bool_to_logic_type := (false => '0', true => '1');
193
 
194
    -- Data records passed between clock domains.
195
    type token_type is record
196
        tick:       std_ulogic;                     -- send time code
197
        fct:        std_ulogic;                     -- send FCT
198 3 jorisvr
        fctpiggy:   std_ulogic;                     -- send FCT and N-char
199 2 jorisvr
        flag:       std_ulogic;                     -- send EOP or EEP
200
        char:       std_logic_vector(7 downto 0);   -- character or time code
201
    end record;
202
 
203
    -- Registers in txclk domain
204
    type txregs_type is record
205
        -- sync to system clock domain
206
        txflip0:    std_ulogic;
207
        txflip1:    std_ulogic;
208
        -- stage B
209
        b_update:   std_ulogic;
210
        b_mux:      std_ulogic;
211
        b_txflip:   std_ulogic;
212
        b_valid:    std_ulogic;
213
        b_token:    token_type;
214
        -- stage C
215
        c_update:   std_ulogic;
216 3 jorisvr
        c_busy:     std_ulogic;
217 2 jorisvr
        c_esc:      std_ulogic;
218
        c_fct:      std_ulogic;
219
        c_bits:     std_logic_vector(8 downto 0);
220
        -- stage D
221
        d_bits:     std_logic_vector(8 downto 0);
222
        d_cnt4:     std_ulogic;
223
        d_cnt10:    std_ulogic;
224
        -- stage E
225
        e_valid:    std_ulogic;
226
        e_shift:    std_logic_vector(9 downto 0);
227
        e_count:    std_logic_vector(9 downto 0);
228
        e_parity:   std_ulogic;
229
        -- stage F
230
        f_spwdo:    std_ulogic;
231
        f_spwso:    std_ulogic;
232
        -- tx clock enable logic
233
        txclken:    std_ulogic;
234
        txclkpre:   std_ulogic;
235
        txclkcnt:   std_logic_vector(7 downto 0);
236
        txclkcy:    std_logic_vector(2 downto 0);
237
        txclkdone:  std_logic_vector(1 downto 0);
238
        txclkdiv:   std_logic_vector(7 downto 0);
239
        txdivnorm:  std_ulogic;
240
    end record;
241
 
242
    -- Registers in system clock domain
243
    type regs_type is record
244
        -- sync status to txclk domain
245
        txenreg:    std_ulogic;
246
        txdivreg:   std_logic_vector(7 downto 0);
247
        txdivnorm:  std_ulogic;
248
        txdivtmp:   std_logic_vector(1 downto 0);
249
        txdivsafe:  std_ulogic;
250
        -- data stream to txclk domain
251
        sysflip0:   std_ulogic;
252
        sysflip1:   std_ulogic;
253
        token0:     token_type;
254
        token1:     token_type;
255
        tokmux:     std_ulogic;
256
        -- transmitter management
257
        pend_fct:   std_ulogic;                     -- '1' if an outgoing FCT is pending
258
        pend_char:  std_ulogic;                     -- '1' if an outgoing N-Char is pending
259
        pend_data:  std_logic_vector(8 downto 0);   -- control flag and data bits of pending char
260
        pend_tick:  std_ulogic;                     -- '1' if an outgoing time tick is pending
261
        pend_time:  std_logic_vector(7 downto 0);   -- data bits of pending time tick
262
        allow_fct:  std_ulogic;                     -- '1' when allowed to send FCTs
263
        allow_char: std_ulogic;                     -- '1' when allowed to send data and time
264
        sent_fct:   std_ulogic;                     -- '1' when at least one FCT token was sent
265
    end record;
266
 
267
    -- Initial state of system clock domain
268 3 jorisvr
    constant token_reset: token_type := (
269
        tick        => '0',
270
        fct         => '0',
271
        fctpiggy    => '0',
272
        flag        => '0',
273
        char        => (others => '0') );
274 2 jorisvr
    constant regs_reset: regs_type := (
275
        txenreg     => '0',
276
        txdivreg    => (others => '0'),
277
        txdivnorm   => '0',
278
        txdivtmp    => "00",
279
        txdivsafe   => '0',
280
        sysflip0    => '0',
281
        sysflip1    => '0',
282 3 jorisvr
        token0      => token_reset,
283
        token1      => token_reset,
284 2 jorisvr
        tokmux      => '0',
285
        pend_fct    => '0',
286
        pend_char   => '0',
287
        pend_data   => (others => '0'),
288
        pend_tick   => '0',
289
        pend_time   => (others => '0'),
290
        allow_fct   => '0',
291
        allow_char  => '0',
292
        sent_fct    => '0' );
293
 
294 7 jorisvr
    -- Signals that are re-synchronized from system clock to txclk domain.
295
    type synctx_type is record
296
        rstn:       std_ulogic;
297
        sysflip0:   std_ulogic;
298
        sysflip1:   std_ulogic;
299
        txen:       std_ulogic;
300
        txdivsafe:  std_ulogic;
301
    end record;
302
 
303
    -- Signals that are re-synchronized from txclk to system clock domain.
304
    type syncsys_type is record
305
        txflip0:    std_ulogic;
306
        txflip1:    std_ulogic;
307
    end record;
308
 
309 2 jorisvr
    -- Registers
310
    signal rtx:     txregs_type;
311
    signal rtxin:   txregs_type;
312
    signal r:       regs_type := regs_reset;
313
    signal rin:     regs_type;
314
 
315 7 jorisvr
    -- Synchronized signals after crossing clock domains.
316
    signal synctx:  synctx_type;
317
    signal syncsys: syncsys_type;
318 2 jorisvr
 
319
    -- Output flip-flops
320
    signal s_spwdo: std_logic;
321
    signal s_spwso: std_logic;
322
 
323
    -- Force use of IOB flip-flops
324
    attribute IOB: string;
325
    attribute IOB of s_spwdo: signal is "TRUE";
326
    attribute IOB of s_spwso: signal is "TRUE";
327
 
328
begin
329
 
330 7 jorisvr
    -- Reset synchronizer for txclk domain.
331
    synctx_rst: syncdff
332
        port map ( clk => txclk, rst => rst, di => '1',         do => synctx.rstn );
333
 
334
    -- Synchronize signals from system clock domain to txclk domain.
335
    synctx_sysflip0: syncdff
336
        port map ( clk => txclk, rst => rst, di => r.sysflip0,  do => synctx.sysflip0 );
337
    synctx_sysflip1: syncdff
338
        port map ( clk => txclk, rst => rst, di => r.sysflip1,  do => synctx.sysflip1 );
339
    synctx_txen: syncdff
340
        port map ( clk => txclk, rst => rst, di => r.txenreg,   do => synctx.txen );
341
    synctx_txdivsafe: syncdff
342
        port map ( clk => txclk, rst => rst, di => r.txdivsafe, do => synctx.txdivsafe );
343
 
344
    -- Synchronize signals from txclk domain to system clock domain.
345
    syncsys_txflip0: syncdff
346
        port map ( clk => clk,   rst => rst, di => rtx.txflip0, do => syncsys.txflip0 );
347
    syncsys_txflip1: syncdff
348
        port map ( clk => clk,   rst => rst, di => rtx.txflip1, do => syncsys.txflip1 );
349
 
350 2 jorisvr
    -- Drive SpaceWire output signals
351
    spw_do      <= s_spwdo;
352
    spw_so      <= s_spwso;
353
 
354
    -- Combinatorial process
355 7 jorisvr
    process (r, rtx, rst, divcnt, xmiti, synctx, syncsys) is
356 2 jorisvr
        variable v:         regs_type;
357
        variable vtx:       txregs_type;
358
        variable v_needtoken: std_ulogic;
359
        variable v_havetoken: std_ulogic;
360
        variable v_token:     token_type;
361
    begin
362
        v           := r;
363
        vtx         := rtx;
364
        v_needtoken := '0';
365
        v_havetoken := '0';
366 3 jorisvr
        v_token     := token_reset;
367 2 jorisvr
 
368
        -- ---- FAST CLOCK DOMAIN ----
369
 
370
        -- Stage B: Multiplex tokens from system clock domain.
371
        -- Update stage B three bit periods after updating stage C
372
        -- (i.e. in time for the next update of stage C).
373 3 jorisvr
        -- Do not update stage B if stage C is indicating that it needs to
374
        -- send a second token to complete its task.
375
        vtx.b_update := rtx.txclken and rtx.e_count(0) and (not rtx.c_busy);
376 2 jorisvr
        if rtx.b_mux = '0' then
377
            vtx.b_txflip := rtx.txflip0;
378
        else
379
            vtx.b_txflip := rtx.txflip1;
380
        end if;
381
        if rtx.b_update = '1' then
382
            if rtx.b_mux = '0' then
383
                -- get token from slot 0
384 7 jorisvr
                vtx.b_valid := synctx.sysflip0 xor rtx.b_txflip;
385 2 jorisvr
                vtx.b_token := r.token0;
386
                -- update mux flag if we got a valid token
387 7 jorisvr
                vtx.b_mux   := synctx.sysflip0 xor rtx.b_txflip;
388
                vtx.txflip0 := synctx.sysflip0;
389 2 jorisvr
                vtx.txflip1 := rtx.txflip1;
390
            else
391
                -- get token from slot 1
392 7 jorisvr
                vtx.b_valid := synctx.sysflip1 xor rtx.b_txflip;
393 2 jorisvr
                vtx.b_token := r.token1;
394
                -- update mux flag if we got a valid token
395 7 jorisvr
                vtx.b_mux   := not (synctx.sysflip1 xor rtx.b_txflip);
396 2 jorisvr
                vtx.txflip0 := rtx.txflip0;
397 7 jorisvr
                vtx.txflip1 := synctx.sysflip1;
398 2 jorisvr
            end if;
399
        end if;
400
 
401
        -- Stage C: Prepare to transmit EOP, EEP or a data character.
402
        vtx.c_update := rtx.txclken and rtx.e_count(3);
403
        if rtx.c_update = '1' then
404 3 jorisvr
 
405
            -- NULL is broken into two tokens: ESC + FCT.
406
            -- Time-codes are broken into two tokens: ESC + char.
407
 
408
            -- Enable c_esc on the first pass of a NULL or a time-code.
409 2 jorisvr
            vtx.c_esc   := (rtx.b_token.tick or (not rtx.b_valid)) and
410
                           (not rtx.c_esc);
411 3 jorisvr
 
412
            -- Enable c_fct on the first pass of an FCT and on
413
            -- the second pass of a NULL (also the first pass, but c_esc
414
            -- is stronger than c_fct).
415
            vtx.c_fct   := (rtx.b_token.fct and (not rtx.c_busy)) or
416
                           (not rtx.b_valid);
417
 
418
            -- Enable c_busy on the first pass of a NULL or a time-code
419
            -- or a piggy-backed FCT. This will tell stage B that we are
420
            -- not done yet.
421
            vtx.c_busy  := (rtx.b_token.tick or (not rtx.b_valid) or
422
                            rtx.b_token.fctpiggy) and (not rtx.c_busy);
423
 
424 2 jorisvr
            if rtx.b_token.flag = '1' then
425
                if rtx.b_token.char(0) = '0' then
426
                    -- prepare to send EOP
427
                    vtx.c_bits  := "000000101"; -- EOP = P101
428
                else
429
                    -- prepare to send EEP
430
                    vtx.c_bits  := "000000011"; -- EEP = P110
431
                end if;
432
            else
433
                -- prepare to send data char
434
                vtx.c_bits  := rtx.b_token.char & '0';
435
            end if;
436
        end if;
437
 
438
        -- Stage D: Prepare to transmit FCT, ESC, or the stuff from stage C.
439
        if rtx.c_esc = '1' then
440
            -- prepare to send ESC
441
            vtx.d_bits  := "000000111";     -- ESC = P111
442
            vtx.d_cnt4  := '1';             -- 3 bits + implicit parity bit
443
            vtx.d_cnt10 := '0';
444
        elsif rtx.c_fct = '1' then
445
            -- prepare to send FCT
446
            vtx.d_bits  := "000000001";     -- FCT = P100
447
            vtx.d_cnt4  := '1';             -- 3 bits + implicit parity bit
448
            vtx.d_cnt10 := '0';
449
        else
450
            -- send the stuff from stage C.
451
            vtx.d_bits  := rtx.c_bits;
452
            vtx.d_cnt4  := rtx.c_bits(0);
453
            vtx.d_cnt10 := not rtx.c_bits(0);
454
        end if;
455
 
456
        -- Stage E: Shift register.
457
        if rtx.txclken = '1' then
458
            if rtx.e_count(0) = '1' then
459
                -- reload shift register; output parity bit
460
                vtx.e_valid  := '1';
461
                vtx.e_shift(vtx.e_shift'high downto 1) := rtx.d_bits;
462
                vtx.e_shift(0) := not (rtx.e_parity xor rtx.d_bits(0));
463
                vtx.e_count  := rtx.d_cnt10 & "00000" & rtx.d_cnt4 & "000";
464
                vtx.e_parity := rtx.d_bits(0);
465
            else
466
                -- shift bits to output; update parity bit
467
                vtx.e_shift  := '0' & rtx.e_shift(rtx.e_shift'high downto 1);
468
                vtx.e_count  := '0' & rtx.e_count(rtx.e_count'high downto 1);
469
                vtx.e_parity := rtx.e_parity xor rtx.e_shift(1);
470
            end if;
471
        end if;
472
 
473
        -- Stage F: Data/strobe encoding.
474
        if rtx.txclken = '1' then
475
            if rtx.e_valid = '1' then
476
                -- output next data/strobe bits
477
                vtx.f_spwdo := rtx.e_shift(0);
478
                vtx.f_spwso := not (rtx.e_shift(0) xor rtx.f_spwdo xor rtx.f_spwso);
479
            else
480
                -- gentle reset of spacewire signals
481
                vtx.f_spwdo := rtx.f_spwdo and rtx.f_spwso;
482
                vtx.f_spwso := '0';
483
            end if;
484
        end if;
485
 
486
        -- Generate tx clock enable
487
        -- An 8-bit counter decrements on every clock. A txclken pulse is
488
        -- produced 2 cycles after the counter reaches value 2. Counter reload
489
        -- values of 0 and 1 are handled as special cases.
490
        -- count down in blocks of two bits
491
        vtx.txclkcnt(1 downto 0) := std_logic_vector(unsigned(rtx.txclkcnt(1 downto 0)) - 1);
492
        vtx.txclkcnt(3 downto 2) := std_logic_vector(unsigned(rtx.txclkcnt(3 downto 2)) - unsigned(rtx.txclkcy(0 downto 0)));
493
        vtx.txclkcnt(5 downto 4) := std_logic_vector(unsigned(rtx.txclkcnt(5 downto 4)) - unsigned(rtx.txclkcy(1 downto 1)));
494
        vtx.txclkcnt(7 downto 6) := std_logic_vector(unsigned(rtx.txclkcnt(7 downto 6)) - unsigned(rtx.txclkcy(2 downto 2)));
495
        -- propagate carry in blocks of two bits
496
        vtx.txclkcy(0) := bool_to_logic(rtx.txclkcnt(1 downto 0) = "00");
497
        vtx.txclkcy(1) := rtx.txclkcy(0) and bool_to_logic(rtx.txclkcnt(3 downto 2) = "00");
498
        vtx.txclkcy(2) := rtx.txclkcy(1) and bool_to_logic(rtx.txclkcnt(5 downto 4) = "00");
499
        -- detect value 2 in counter
500
        vtx.txclkdone(0) := bool_to_logic(rtx.txclkcnt(3 downto 0) = "0010");
501
        vtx.txclkdone(1) := bool_to_logic(rtx.txclkcnt(7 downto 4) = "0000");
502
        -- trigger txclken
503
        vtx.txclken  := (rtx.txclkdone(0) and rtx.txclkdone(1)) or rtx.txclkpre;
504
        vtx.txclkpre := (not rtx.txdivnorm) and ((not rtx.txclkpre) or (not rtx.txclkdiv(0)));
505
        -- reload counter
506
        if rtx.txclken = '1' then
507
            vtx.txclkcnt  := rtx.txclkdiv;
508
            vtx.txclkcy   := "000";
509
            vtx.txclkdone := "00";
510
        end if;
511
 
512
        -- Synchronize txclkdiv
513 7 jorisvr
        if synctx.txdivsafe = '1' then
514 2 jorisvr
            vtx.txclkdiv  := r.txdivreg;
515
            vtx.txdivnorm := r.txdivnorm;
516
        end if;
517
 
518
        -- Transmitter disabled.
519 7 jorisvr
        if synctx.txen = '0' then
520 2 jorisvr
            vtx.txflip0   := '0';
521
            vtx.txflip1   := '0';
522
            vtx.b_update  := '0';
523
            vtx.b_mux     := '0';
524
            vtx.b_valid   := '0';
525
            vtx.c_update  := '0';
526 3 jorisvr
            vtx.c_busy    := '1';
527 2 jorisvr
            vtx.c_esc     := '1';           -- need to send 2nd part of NULL
528
            vtx.c_fct     := '1';
529
            vtx.d_bits    := "000000111";   -- ESC = P111
530
            vtx.d_cnt4    := '1';           -- 3 bits + implicit parity bit
531
            vtx.d_cnt10   := '0';
532
            vtx.e_valid   := '0';
533
            vtx.e_parity  := '0';
534
            vtx.e_count   := (0 => '1', others => '0');
535
        end if;
536
 
537
        -- Reset.
538 7 jorisvr
        if synctx.rstn = '0' then
539 2 jorisvr
            vtx.f_spwdo   := '0';
540
            vtx.f_spwso   := '0';
541
            vtx.txclken   := '0';
542
            vtx.txclkpre  := '1';
543
            vtx.txclkcnt  := (others => '0');
544
            vtx.txclkdiv  := (others => '0');
545
            vtx.txdivnorm := '0';
546
        end if;
547
 
548
        -- ---- SYSTEM CLOCK DOMAIN ----
549
 
550
        -- Hold divcnt and txen for use by txclk domain.
551
        v.txdivtmp  := std_logic_vector(unsigned(r.txdivtmp) - 1);
552
        if r.txdivtmp = "00" then
553
            if r.txdivsafe = '0' then
554
                -- Latch the current value of divcnt and txen.
555
                v.txdivsafe := '1';
556
                v.txdivtmp  := "01";
557
                v.txdivreg  := divcnt;
558
                if unsigned(divcnt(divcnt'high downto 1)) = 0 then
559
                    v.txdivnorm := '0';
560
                else
561
                    v.txdivnorm := '1';
562
                end if;
563
                v.txenreg   := xmiti.txen;
564
            else
565
                -- Drop the txdivsafe flag but keep latched values.
566
                v.txdivsafe := '0';
567
            end if;
568
        end if;
569
 
570
        -- Pass falling edge of txen signal as soon as possible.
571
        if xmiti.txen = '0' then
572
            v.txenreg   := '0';
573
        end if;
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 7 jorisvr
                if r.sysflip0 = syncsys.txflip0 then
598 2 jorisvr
                    v_needtoken := '1';
599
                end if;
600
            else
601 7 jorisvr
                if r.sysflip1 = syncsys.txflip1 then
602 2 jorisvr
                    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 7 jorisvr
                    if r.sysflip0 = syncsys.txflip0 then
646 2 jorisvr
                        v.sysflip0  := not r.sysflip0;
647
                        v.token0    := v_token;
648
                        v.tokmux    := '1';
649
                    end if;
650
                else
651 7 jorisvr
                    if r.sysflip1 = syncsys.txflip1 then
652 2 jorisvr
                        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
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.