File: command_uart.vhd

package info (click to toggle)
bladerf 0.2017.12~rc1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 14,620 kB
  • sloc: ansic: 50,123; vhdl: 12,873; python: 1,062; tcl: 1,060; xml: 1,017; makefile: 657; sh: 589; csh: 18; cpp: 9
file content (361 lines) | stat: -rw-r--r-- 13,876 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
-- Copyright (c) 2015 Nuand LLC
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.

library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;

entity command_uart is
  port (
    -- FPGA internal interface to the TX and RX FIFOs
    clock           :   in  std_logic ;
    reset           :   in  std_logic ;

    -- RS232 interface
    rs232_sout      :   out std_logic ;
    rs232_sin       :   in  std_logic ;

    -- Avalon-MM interface
    addr            :   in  std_logic_vector(4 downto 0) ;
    dout            :   out std_logic_vector(31 downto 0) ;
    din             :   in  std_logic_vector(31 downto 0) ;
    read            :   in  std_logic ;
    write           :   in  std_logic ;
    waitreq         :   out std_logic ;
    readack         :   out std_logic ;
    irq             :   out std_logic
  ) ;
end entity ; -- command_uart

architecture arch of command_uart is

    -- TODO: Make this a generic instead of a constant
    constant CLOCKS_PER_BIT :   natural := 20 ;

    -- Send and receive state machine definitions
    type send_fsm_t is (IDLE, SEND_START, SEND_DATA, SEND_STOP ) ;
    type receive_fsm_t is (WAIT_FOR_START, CENTER_START, SAMPLE_DATA, WAIT_FOR_STOP) ;

    -- FSM signals
    signal send_fsm     : send_fsm_t ;
    signal receive_fsm  : receive_fsm_t ;

    -- Synchronization signals for asynchronous input
    signal reg_sin      : std_logic ;
    signal sync_sin     : std_logic ;

    signal reg_response : std_logic_vector(127 downto 0) ;
    signal reg_request  : std_logic_vector(127 downto 0) ;

    signal sin_data     : std_logic_vector(7 downto 0) ;
    signal sin_we       : std_logic ;

    signal sout_data    : std_logic_vector(7 downto 0) ;
    signal sout_we      : std_logic ;

    signal ack : std_logic ;

    type magics_t is array(natural range <>) of std_logic_vector(7 downto 0) ;

    -- These are all the magic header characters
    constant magics : magics_t := (
        std_logic_vector(to_unsigned(character'pos('A'),8)),    -- 8x8
        std_logic_vector(to_unsigned(character'pos('B'),8)),    -- 8x16
        std_logic_vector(to_unsigned(character'pos('C'),8)),    -- 8x32
        std_logic_vector(to_unsigned(character'pos('D'),8)),    -- 8x64
        std_logic_vector(to_unsigned(character'pos('K'),8)),    -- 32x32
        std_logic_vector(to_unsigned(character'pos('N'),8)),    -- Legacy
        std_logic_vector(to_unsigned(character'pos('T'),8))     -- Retune
    ) ;

    signal command_in : std_logic ;

    signal control  :   std_logic_vector(7 downto 0) := (0 => '1', others =>'0') ;

    alias isr_enable is control(0) ;

begin

    readack <= ack ;
    waitreq <= not(ack or write) ;

    -- Avalon-MM interface for responses
    mm_writes : process(clock)
    begin
        if( rising_edge(clock) ) then
            command_in <= '0' ;
            if( write = '1' ) then
                case to_integer(unsigned(addr)) is
                    when  0| 1| 2| 3 => reg_response( 31 downto   0) <= din ; command_in <= '1' ;
                    when  4| 5| 6| 7 => reg_response( 63 downto  32) <= din ;
                    when  8| 9|10|11 => reg_response( 95 downto  64) <= din ;
                    when 12|13|14|15 => reg_response(127 downto  96) <= din ;
                    when others => control(7 downto 0) <= din(7 downto 0) ;
                end case ;
            end if ;
        end if ;
    end process ;

    send_command : process(clock, reset)
        type state_t is (WAITING_FOR_COMMAND, SEND_BYTE, WAITING_FOR_START, WAITING_FOR_DONE) ;
        variable state : state_t ;
        variable count : natural range 0 to 15 := 15 ;
    begin
        if( reset = '1' ) then
            state := WAITING_FOR_COMMAND ;
            sout_we <= '0' ;
        elsif( rising_edge(clock) ) then
            sout_we <= '0' ;
            sout_data <= reg_response(count*8+7 downto count*8) ;
            case state is
                when WAITING_FOR_COMMAND =>
                    if( command_in = '1' ) then
                        state := SEND_BYTE ;
                        count := 0 ;
                    end if ;

                when SEND_BYTE =>
                    sout_we <= '1' ;
                    state := WAITING_FOR_START ;

                when WAITING_FOR_START =>
                    if( send_fsm /= IDLE ) then
                        state := WAITING_FOR_DONE ;
                    end if ;

                when WAITING_FOR_DONE =>
                    if( send_fsm = IDLE ) then
                        if( count < 15 ) then
                            count := count + 1 ;
                            state := SEND_BYTE ;
                        else
                            state := WAITING_FOR_COMMAND ;
                        end if ;
                    end if ;
            end case ;
        end if ;
    end process ;

    -- Avanlon-MM interface for requests
    mm_reads : process(clock)
    begin
        if( rising_edge(clock) ) then
            ack <= read ;
            if( read = '1' ) then
                case to_integer(unsigned(addr)) is
                    when  0| 1| 2| 3 => dout <= reg_request( 31 downto  0) ;
                    when  4| 5| 6| 7 => dout <= reg_request( 63 downto 32) ;
                    when  8| 9|10|11 => dout <= reg_request( 95 downto 64) ;
                    when 12|13|14|15 => dout <= reg_request(127 downto 96) ;
                    when others => dout(7 downto 0) <= control ;
                end case ;
            end if ;
        end if ;
    end process ;

    receive_command : process(clock, reset)
        type state_t is (WAIT_FOR_MAGIC, CHECK_MAGIC, RECEIVE_COMMAND, INTERRUPT, WAIT_FOR_READ) ;
        variable state : state_t ;
        variable count : natural range 0 to 15 ;
    begin
        if( reset = '1' ) then
            state := WAIT_FOR_MAGIC ;
            count := 0 ;
            irq <= '0' ;
        elsif( rising_edge(clock) ) then
            if( sin_we = '1' ) then
                reg_request(count*8+7 downto count*8) <= sin_data ;
            end if ;
            case state is
                when WAIT_FOR_MAGIC =>
                    if( sin_we = '1' ) then
                        state := CHECK_MAGIC ;
                    end if ;

                when CHECK_MAGIC =>
                    for i in magics'range loop
                        if( magics(i) = reg_request(7 downto 0) ) then
                            state := RECEIVE_COMMAND ;
                            count := count + 1 ;
                        end if ;
                    end loop ;
                    if( count = 0 ) then
                        state := WAIT_FOR_MAGIC ;
                    end if ;

                when RECEIVE_COMMAND =>
                    if( sin_we = '1' ) then
                        if( count < 15 ) then
                            count := count + 1 ;
                        else
                            count := 0 ;
                            if( isr_enable = '1' ) then
                                state := INTERRUPT ;
                            else
                                state := WAIT_FOR_MAGIC ;
                            end if ;
                        end if ;
                    end if ;

                when INTERRUPT =>
                    irq <= '1' ;
                    state := WAIT_FOR_READ ;

                when WAIT_FOR_READ =>
                    if( read = '1' ) then
                        irq <= '0' ;
                        state := WAIT_FOR_MAGIC ;
                    end if ;
            end case ;
        end if ;
    end process ;

    -- Synchronize asynchronous inputs
    reg_sin <= rs232_sin when rising_edge( clock ) ;
    sync_sin <= reg_sin when rising_edge( clock ) ;

    -- Receive data from the UART and put it in the FIFO
    receive_from_uart : process(clock, reset)
        variable bits           :   std_logic_vector(7 downto 0) ;
        variable bit_count      :   natural range 0 to bits'length ;
        variable clock_count    :   natural range 0 to CLOCKS_PER_BIT ;
        variable sin_delay      :   std_logic ;
    begin
        if( reset = '1' ) then
            receive_fsm <= WAIT_FOR_START ;
            sin_we <= '0' ;
            sin_data <= (others =>'0') ;
            bits := (others =>'0') ;
            bit_count := 0 ;
            clock_count := 0 ;
            sin_delay := '0' ;
        elsif( rising_edge(clock) ) then
            sin_we <= '0' ;
            case receive_fsm is
                -- Wait for the start signal
                when WAIT_FOR_START =>
                    if( sync_sin = '0' and sin_delay = '1' ) then
                        receive_fsm <= CENTER_START ;
                        clock_count := CLOCKS_PER_BIT/2-1 ;
                    end if ;
                    sin_delay := sync_sin ;

                -- Center the start bit
                when CENTER_START =>
                    clock_count := clock_count - 1 ;
                    if( clock_count = 0 ) then
                        receive_fsm <= SAMPLE_DATA ;
                        clock_count := CLOCKS_PER_BIT ;
                        bit_count := bits'length ;
                    end if ;

                -- Sample the bits
                when SAMPLE_DATA =>
                    clock_count := clock_count - 1 ;
                    if( clock_count = 0 ) then
                        bits := sync_sin & bits(bits'high downto 1) ;
                        bit_count := bit_count - 1 ;
                        clock_count := CLOCKS_PER_BIT ;
                        if( bit_count = 0 ) then
                            receive_fsm <= WAIT_FOR_STOP ;
                            sin_data <= bits ;
                            sin_we <= '1' ;
                        end if ;
                    end if ;

                -- Wait for the stop bit
                when WAIT_FOR_STOP =>
                    clock_count := clock_count - 1 ;
                    if( clock_count = 0 ) then
                        receive_fsm <= WAIT_FOR_START ;
                        assert sync_sin = '1' report "STOP bit not found!" severity error ;
                    end if ;

                when others =>
            end case ;
        end if ;
    end process ;

    -- Send data to the UART from the FIFO
    send_to_uart : process(clock, reset)
        variable bits           : std_logic_vector(7 downto 0) ;
        variable bit_count      : natural range 0 to bits'length ;
        variable clock_count    : natural range 0 to CLOCKS_PER_BIT ;
    begin
        if( reset = '1' ) then
            send_fsm    <= IDLE ;
            rs232_sout  <= '1' ;
            bit_count   := 0 ;
            clock_count := 0 ;
            bits        := (others =>'0') ;
        elsif( rising_edge(clock) ) then
            case send_fsm is
                -- Wait until we have something to send
                when IDLE =>
                    rs232_sout <= '1' ;
                    if( sout_we = '1' ) then
                        send_fsm    <= SEND_START ;
                        bit_count   := bits'length ;
                        clock_count := CLOCKS_PER_BIT ;
                    end if ;

                -- Send the start bit
                when SEND_START =>
                    rs232_sout <= '0' ;
                    clock_count := clock_count - 1 ;
                    if( clock_count = 0 ) then
                        send_fsm    <= SEND_DATA ;
                        clock_count := CLOCKS_PER_BIT ;
                    elsif( clock_count = 9 ) then
                        bits := sout_data ;
                    end if ;
                -- Send the data
                when SEND_DATA =>
                    rs232_sout   <= bits(0) ;
                    clock_count := clock_count - 1 ;
                    if( clock_count = 0 ) then
                        bits        := '0' & bits(bits'high downto 1) ;
                        bit_count   := bit_count - 1 ;
                        clock_count := CLOCKS_PER_BIT ;
                        if( bit_count = 0 ) then
                            send_fsm <= SEND_STOP ;
                        end if ;
                    end if ;

                -- Send the stop bit
                when SEND_STOP =>
                    rs232_sout   <= '1' ;
                    clock_count := clock_count - 1 ;
                    if( clock_count = 0 ) then
                        send_fsm <= IDLE ;
                    end if ;

                -- Weird
                when others =>
                    send_fsm    <= IDLE ;
                    rs232_sout  <= '1' ;
                    bit_count   := 0 ;
                    clock_count := 0 ;
                    bits        := (others =>'0') ;
            end case ;
        end if ;
    end process ;

end architecture ; -- arch