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

Subversion Repositories spacewire_light

[/] [spacewire_light/] [trunk/] [rtl/] [vhdl/] [spwlink.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 Exchange Level Controller.
3
--
4
--  This entity implements exchange level aspects of the SpaceWire protocol.
5
--  It handles connection setup, error detection and flow control.
6
--
7
 
8
library ieee;
9
use ieee.std_logic_1164.all;
10
use ieee.numeric_std.all;
11
use work.spwpkg.all;
12
 
13
entity spwlink is
14
 
15
    generic (
16
        -- Reset time expressed in system clock cycles.
17
        -- Should be 6.4 us (5.82 us .. 7.2 us) according to the standard.
18
        reset_time:      integer
19
    );
20
 
21
    port (
22
        -- System clock.
23
        clk:        in  std_logic;
24
 
25
        -- Synchronous reset (active-high).
26
        -- Disconnects, resets error conditions, puts the link state machine
27
        -- in state ErrorReset.
28
        rst:        in  std_logic;
29
 
30
        -- Link level inputs.
31
        linki:      in  spw_link_in_type;
32
 
33
        -- Link level outputs.
34
        linko:      out spw_link_out_type;
35
 
36
        -- Receiver enable signal to spwrecv.
37
        rxen:       out std_logic;
38
 
39
        -- Output signals from spwrecv.
40
        recvo:      in  spw_recv_out_type;
41
 
42
        -- Input signals for spwxmit.
43
        xmiti:      out spw_xmit_in_type;
44
 
45
        -- Output signals from spwxmit.
46
        xmito:      in  spw_xmit_out_type
47
    );
48
 
49
end entity spwlink;
50
 
51
architecture spwlink_arch of spwlink is
52
 
53
    -- Convert boolean to std_logic.
54
    type bool_to_logic_type is array(boolean) of std_ulogic;
55
    constant bool_to_logic: bool_to_logic_type := (false => '0', true => '1');
56
 
57
    -- State machine.
58
    type state_type is (
59
      S_ErrorReset, S_ErrorWait, S_Ready, S_Started, S_Connecting, S_Run );
60
 
61
    -- Registers
62
    type regs_type is record
63
        -- state machine
64
        state:          state_type;
65
        -- credit accounting
66
        tx_credit:  unsigned(5 downto 0);
67
        rx_credit:  unsigned(5 downto 0);
68
        errcred:    std_ulogic;
69
        -- reset timer
70
        timercnt:   unsigned(10 downto 0);
71
        timerdone:  std_ulogic;
72
        -- signal to transmitter
73
        xmit_fct_in: std_ulogic;
74
    end record;
75
 
76
    -- Initial state
77
    constant regs_reset: regs_type := (
78
        state       => S_ErrorReset,
79
        tx_credit   => "000000",
80
        rx_credit   => "000000",
81
        errcred     => '0',
82
        timercnt    => to_unsigned(reset_time, 11),
83
        timerdone   => '0',
84
        xmit_fct_in => '0' );
85
 
86
    signal r:       regs_type := regs_reset;
87
    signal rin:     regs_type;
88
 
89
begin
90
 
91
    -- Combinatorial process
92
    process (r, rst, linki, recvo, xmito) is
93
        variable v: regs_type;
94
        variable v_timerrst: std_logic;
95
    begin
96
        v := r;
97
        v_timerrst := '0';
98
 
99
        -- State machine.
100
        case r.state is
101
 
102
            when S_ErrorReset =>
103
                -- Wait for timer.
104
                if r.timercnt = 0 then
105
                    v.state     := S_ErrorWait;
106
                    v_timerrst  := '1';
107
                end if;
108
                v.errcred   := '0';
109
                v.xmit_fct_in := '0';
110
 
111
            when S_ErrorWait =>
112
                -- Wait for 2 timer periods.
113
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
114
                   ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') then
115 4 jorisvr
                    -- Note: spwrecv will never issue errpar, erresc, gotfct,
116
                    -- tick_out or rxchar before the first NULL has been seen.
117
                    -- Therefore it's ok here to bail on those conditions
118
                    -- without explicitly testing got_null.
119 2 jorisvr
                    v.state     := S_ErrorReset;    -- error, go back to reset
120
                    v_timerrst  := '1';
121
                elsif r.timercnt = 0 then
122
                    if r.timerdone = '1' then
123
                        v.state     := S_Ready;
124
                        v_timerrst  := '1';
125
                    end if;
126
                end if;
127
 
128
            when S_Ready =>
129
                -- Wait for link start.
130
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
131
                   ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') then
132
                    v.state     := S_ErrorReset;    -- error, go back to reset
133
                    v_timerrst  := '1';
134
                elsif (linki.linkdis = '0') and (r.xmit_fct_in = '1') and
135
                      ((linki.linkstart or (linki.autostart and recvo.gotnull)) = '1') then
136
                    v.state     := S_Started;       -- link enabled; start sending NULL
137
                    v_timerrst  := '1';
138
                end if;
139
 
140
            when S_Started =>
141
                -- Wait for NULL.
142
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
143
                   ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') or
144
                   ((r.timercnt = 0) and r.timerdone = '1') then
145
                    v.state     := S_ErrorReset;    -- error, go back to reset
146
                    v_timerrst  := '1';
147
                elsif recvo.gotnull = '1' then
148
                    v.state     := S_Connecting;    -- received null, continue
149
                    v_timerrst  := '1';
150
                end if;
151
 
152
            when S_Connecting =>
153
                -- Wait for FCT.
154
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
155
                   ((recvo.tick_out or recvo.rxchar) = '1') or
156
                   ((r.timercnt = 0) and r.timerdone = '1') then
157
                    v.state     := S_ErrorReset;    -- error, go back to reset
158
                    v_timerrst  := '1';
159
                elsif recvo.gotfct = '1' then
160
                    v.state     := S_Run;           -- got FCT, init completed
161
                end if;
162
 
163
            when S_Run =>
164
                -- All is well.
165
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
166
                   (r.errcred = '1') or
167
                   (linki.linkdis = '1') then
168
                    v.state     := S_ErrorReset;    -- error, go back to reset
169
                    v_timerrst  := '1';
170
                end if;
171
 
172
            when others =>
173
                v.state     := S_ErrorReset;        -- recover from invalid state
174
                v_timerrst  := '1';
175
 
176
        end case;
177
 
178
        -- Update credit counters.
179
        if r.state = S_ErrorReset then
180
 
181
            -- reset credit
182
            v.tx_credit := to_unsigned(0, v.tx_credit'length);
183
            v.rx_credit := to_unsigned(0, v.rx_credit'length);
184
 
185
        else
186
 
187
            -- update TX credit
188
            if recvo.gotfct = '1' then
189
                -- just received a FCT token
190
                v.tx_credit := v.tx_credit + to_unsigned(8, v.tx_credit'length);
191
                if r.tx_credit > 48 then
192
                    -- received too many FCT tokens
193
                    v.errcred   := '1';
194
                end if;
195
            end if;
196
            if xmito.txack = '1' then
197
                -- just sent one byte
198
                v.tx_credit := v.tx_credit - to_unsigned(1, v.tx_credit'length);
199
            end if;
200
 
201
            -- update RX credit after sending FCT
202
            if xmito.fctack = '1' then
203
               -- just sent a FCT token
204
                v.rx_credit := v.rx_credit + to_unsigned(8, v.rx_credit'length);
205
            end if;
206
 
207
            -- decide about sending FCT tokens
208
            v.xmit_fct_in := bool_to_logic( (v.rx_credit <= 48) and
209
                                            (v.rx_credit + to_unsigned(8, v.rx_credit'length) <= unsigned(linki.rxroom)) );
210
 
211
            -- update RX credit after receiving character
212
            if recvo.rxchar = '1' then
213
                -- just received a character
214
                v.rx_credit := v.rx_credit - to_unsigned(1, v.rx_credit'length);
215
                if r.rx_credit = 0 then
216
                    -- remote transmitter violated its credit
217
                    v.errcred   := '1';
218
                end if;
219
            end if;
220
 
221
        end if;
222
 
223
        -- Update the initializaton reset timer.
224
        if v_timerrst = '1' then
225
            v.timercnt  := to_unsigned(reset_time, v.timercnt'length);
226
            v.timerdone := '0';
227
        else
228
            if r.timercnt = 0 then
229
                v.timercnt  := to_unsigned(reset_time, v.timercnt'length);
230
                v.timerdone := '1';
231
            else
232
                v.timercnt  := r.timercnt - 1;
233
            end if;
234
        end if;
235
 
236
        -- Reset
237
        if rst = '1' then
238
            v := regs_reset;
239
        end if;
240
 
241
        -- Drive link level outputs.
242
        linko.started   <= bool_to_logic(r.state = S_Started);
243
        linko.connecting <= bool_to_logic(r.state = S_Connecting);
244
        linko.running   <= bool_to_logic(r.state = S_Run);
245
        linko.errdisc   <= recvo.errdisc and bool_to_logic(r.state = S_Run);
246
        linko.errpar    <= recvo.errpar  and bool_to_logic(r.state = S_Run);
247
        linko.erresc    <= recvo.erresc  and bool_to_logic(r.state = S_Run);
248
        linko.errcred   <= r.errcred;
249
        linko.txack     <= xmito.txack;
250
        linko.tick_out  <= recvo.tick_out and bool_to_logic(r.state = S_Run);
251
        linko.ctrl_out  <= recvo.ctrl_out;
252
        linko.time_out  <= recvo.time_out;
253
        linko.rxchar    <= recvo.rxchar  and bool_to_logic(r.state = S_Run);
254
        linko.rxflag    <= recvo.rxflag;
255
        linko.rxdata    <= recvo.rxdata;
256
 
257
        -- Drive receiver inputs.
258
        rxen            <= bool_to_logic(r.state /= S_ErrorReset);
259
 
260
        -- Drive transmitter input signals.
261
        xmiti.txen      <= bool_to_logic(r.state = S_Started or
262
                                         r.state = S_Connecting or
263
                                         r.state = S_Run);
264
        xmiti.stnull    <= bool_to_logic(r.state = S_Started);
265
        xmiti.stfct     <= bool_to_logic(r.state = S_Connecting);
266
        xmiti.fct_in    <= r.xmit_fct_in;
267
        xmiti.tick_in   <= linki.tick_in and bool_to_logic(r.state = S_Run);
268
        xmiti.ctrl_in   <= linki.ctrl_in;
269
        xmiti.time_in   <= linki.time_in;
270
        xmiti.txwrite   <= linki.txwrite and bool_to_logic(r.tx_credit /= 0);
271
        xmiti.txflag    <= linki.txflag;
272
        xmiti.txdata    <= linki.txdata;
273
 
274
        -- Update registers.
275
        rin <= v;
276
    end process;
277
 
278
    -- Update registers.
279
    process (clk) is
280
    begin
281
        if rising_edge(clk) then
282
            r <= rin;
283
        end if;
284
    end process;
285
 
286
end architecture spwlink_arch;

powered by: WebSVN 2.1.0

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