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 2

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
                    v.state     := S_ErrorReset;    -- error, go back to reset
116
                    v_timerrst  := '1';
117
                elsif r.timercnt = 0 then
118
                    if r.timerdone = '1' then
119
                        v.state     := S_Ready;
120
                        v_timerrst  := '1';
121
                    end if;
122
                end if;
123
 
124
            when S_Ready =>
125
                -- Wait for link start.
126
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
127
                   ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') then
128
                    v.state     := S_ErrorReset;    -- error, go back to reset
129
                    v_timerrst  := '1';
130
                elsif (linki.linkdis = '0') and (r.xmit_fct_in = '1') and
131
                      ((linki.linkstart or (linki.autostart and recvo.gotnull)) = '1') then
132
                    v.state     := S_Started;       -- link enabled; start sending NULL
133
                    v_timerrst  := '1';
134
                end if;
135
 
136
            when S_Started =>
137
                -- Wait for NULL.
138
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
139
                   ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') or
140
                   ((r.timercnt = 0) and r.timerdone = '1') then
141
                    v.state     := S_ErrorReset;    -- error, go back to reset
142
                    v_timerrst  := '1';
143
                elsif recvo.gotnull = '1' then
144
                    v.state     := S_Connecting;    -- received null, continue
145
                    v_timerrst  := '1';
146
                end if;
147
 
148
            when S_Connecting =>
149
                -- Wait for FCT.
150
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
151
                   ((recvo.tick_out or recvo.rxchar) = '1') or
152
                   ((r.timercnt = 0) and r.timerdone = '1') then
153
                    v.state     := S_ErrorReset;    -- error, go back to reset
154
                    v_timerrst  := '1';
155
                elsif recvo.gotfct = '1' then
156
                    v.state     := S_Run;           -- got FCT, init completed
157
                end if;
158
 
159
            when S_Run =>
160
                -- All is well.
161
                if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or
162
                   (r.errcred = '1') or
163
                   (linki.linkdis = '1') then
164
                    v.state     := S_ErrorReset;    -- error, go back to reset
165
                    v_timerrst  := '1';
166
                end if;
167
 
168
            when others =>
169
                v.state     := S_ErrorReset;        -- recover from invalid state
170
                v_timerrst  := '1';
171
 
172
        end case;
173
 
174
        -- Update credit counters.
175
        if r.state = S_ErrorReset then
176
 
177
            -- reset credit
178
            v.tx_credit := to_unsigned(0, v.tx_credit'length);
179
            v.rx_credit := to_unsigned(0, v.rx_credit'length);
180
 
181
        else
182
 
183
            -- update TX credit
184
            if recvo.gotfct = '1' then
185
                -- just received a FCT token
186
                v.tx_credit := v.tx_credit + to_unsigned(8, v.tx_credit'length);
187
                if r.tx_credit > 48 then
188
                    -- received too many FCT tokens
189
                    v.errcred   := '1';
190
                end if;
191
            end if;
192
            if xmito.txack = '1' then
193
                -- just sent one byte
194
                v.tx_credit := v.tx_credit - to_unsigned(1, v.tx_credit'length);
195
            end if;
196
 
197
            -- update RX credit after sending FCT
198
            if xmito.fctack = '1' then
199
               -- just sent a FCT token
200
                v.rx_credit := v.rx_credit + to_unsigned(8, v.rx_credit'length);
201
            end if;
202
 
203
            -- decide about sending FCT tokens
204
            v.xmit_fct_in := bool_to_logic( (v.rx_credit <= 48) and
205
                                            (v.rx_credit + to_unsigned(8, v.rx_credit'length) <= unsigned(linki.rxroom)) );
206
 
207
            -- update RX credit after receiving character
208
            if recvo.rxchar = '1' then
209
                -- just received a character
210
                v.rx_credit := v.rx_credit - to_unsigned(1, v.rx_credit'length);
211
                if r.rx_credit = 0 then
212
                    -- remote transmitter violated its credit
213
                    v.errcred   := '1';
214
                end if;
215
            end if;
216
 
217
        end if;
218
 
219
        -- Update the initializaton reset timer.
220
        if v_timerrst = '1' then
221
            v.timercnt  := to_unsigned(reset_time, v.timercnt'length);
222
            v.timerdone := '0';
223
        else
224
            if r.timercnt = 0 then
225
                v.timercnt  := to_unsigned(reset_time, v.timercnt'length);
226
                v.timerdone := '1';
227
            else
228
                v.timercnt  := r.timercnt - 1;
229
            end if;
230
        end if;
231
 
232
        -- Reset
233
        if rst = '1' then
234
            v := regs_reset;
235
        end if;
236
 
237
        -- Drive link level outputs.
238
        linko.started   <= bool_to_logic(r.state = S_Started);
239
        linko.connecting <= bool_to_logic(r.state = S_Connecting);
240
        linko.running   <= bool_to_logic(r.state = S_Run);
241
        linko.errdisc   <= recvo.errdisc and bool_to_logic(r.state = S_Run);
242
        linko.errpar    <= recvo.errpar  and bool_to_logic(r.state = S_Run);
243
        linko.erresc    <= recvo.erresc  and bool_to_logic(r.state = S_Run);
244
        linko.errcred   <= r.errcred;
245
        linko.txack     <= xmito.txack;
246
        linko.tick_out  <= recvo.tick_out and bool_to_logic(r.state = S_Run);
247
        linko.ctrl_out  <= recvo.ctrl_out;
248
        linko.time_out  <= recvo.time_out;
249
        linko.rxchar    <= recvo.rxchar  and bool_to_logic(r.state = S_Run);
250
        linko.rxflag    <= recvo.rxflag;
251
        linko.rxdata    <= recvo.rxdata;
252
 
253
        -- Drive receiver inputs.
254
        rxen            <= bool_to_logic(r.state /= S_ErrorReset);
255
 
256
        -- Drive transmitter input signals.
257
        xmiti.txen      <= bool_to_logic(r.state = S_Started or
258
                                         r.state = S_Connecting or
259
                                         r.state = S_Run);
260
        xmiti.stnull    <= bool_to_logic(r.state = S_Started);
261
        xmiti.stfct     <= bool_to_logic(r.state = S_Connecting);
262
        xmiti.fct_in    <= r.xmit_fct_in;
263
        xmiti.tick_in   <= linki.tick_in and bool_to_logic(r.state = S_Run);
264
        xmiti.ctrl_in   <= linki.ctrl_in;
265
        xmiti.time_in   <= linki.time_in;
266
        xmiti.txwrite   <= linki.txwrite and bool_to_logic(r.tx_credit /= 0);
267
        xmiti.txflag    <= linki.txflag;
268
        xmiti.txdata    <= linki.txdata;
269
 
270
        -- Update registers.
271
        rin <= v;
272
    end process;
273
 
274
    -- Update registers.
275
    process (clk) is
276
    begin
277
        if rising_edge(clk) then
278
            r <= rin;
279
        end if;
280
    end process;
281
 
282
end architecture spwlink_arch;

powered by: WebSVN 2.1.0

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