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

Subversion Repositories spacewire_light

[/] [spacewire_light/] [trunk/] [rtl/] [vhdl/] [spwrecv.vhd] - Rev 2

Go to most recent revision | Compare with Previous | Blame | View Log

--
--  SpaceWire Receiver
--
--  This entity decodes the sequence of incoming data bits into tokens.
--  Data bits are passed to this entity from the Receiver Front-end
--  in groups of rxchunk bits at a time.
--
--  The bitrate of the incoming SpaceWire signal must be strictly less
--  than rxchunk times the system clock frequency. 
--
 
library ieee;
use ieee.std_logic_1164.all, ieee.numeric_std.all;
use work.spwpkg.all;
 
entity spwrecv is
 
    generic (
        -- Disconnect timeout, expressed in system clock cycles.
        -- Should be 850 ns (727 ns .. 1000 ns) according to the standard.
        disconnect_time: integer range 1 to 255;
 
        -- Nr of bits sampled per system clock.
        rxchunk:        integer range 1 to 4
    );
 
    port (
        -- System clock.
	clk:        in  std_logic;
 
        -- High to enable receiver; low to disable and reset receiver.
        rxen:       in  std_logic;
 
        -- Output signals to spwlink.
        recvo:      out spw_recv_out_type;
 
        -- High if there has been recent activity on the input lines.
        inact:      in  std_logic;
 
        -- High if inbits contains a valid group of received bits.
        inbvalid:   in  std_logic;
 
        -- Received bits from receiver front-end.
        inbits:     in  std_logic_vector(rxchunk-1 downto 0)
    );
 
end entity spwrecv;
 
architecture spwrecv_arch of spwrecv is
 
    -- registers
    type regs_type is record
        -- receiver state
        bit_seen:   std_ulogic;         -- got a bit transition
        null_seen:  std_ulogic;         -- got a NULL token
        -- input shift register
        bitshift:   std_logic_vector(8 downto 0);
        bitcnt:     std_logic_vector(9 downto 0);   -- one-hot counter
        -- parity flag
        parity:     std_ulogic;
        -- decoding
        control:    std_ulogic;         -- next code is control code
        escaped:    std_ulogic;         -- last code was ESC
        -- output registers
        gotfct:     std_ulogic;
        tick_out:   std_ulogic;
        rxchar:     std_ulogic;
        rxflag:     std_ulogic;
        timereg:    std_logic_vector(7 downto 0);
        datareg:    std_logic_vector(7 downto 0);
        -- disconnect timer
        disccnt:    unsigned(7 downto 0);
        -- error flags
        errpar:     std_ulogic;
        erresc:     std_ulogic;
    end record;
 
    -- Initial state
    constant regs_reset: regs_type := (
        bit_seen    => '0',
        null_seen   => '0',
        bitshift    => (others => '1'),
        bitcnt      => (others => '0'),
        parity      => '0',
        control     => '0',
        escaped     => '0',
        gotfct      => '0',
        tick_out    => '0',
        rxchar      => '0',
        rxflag      => '0',
        timereg     => (others => '0'),
        datareg     => (others => '0'),
        disccnt     => "00000000",
        errpar      => '0',
        erresc      => '0' );
 
    -- registers
    signal r:       regs_type := regs_reset;
    signal rin:     regs_type;
 
begin
 
    -- combinatorial process
    process  (r, rxen, inact, inbvalid, inbits)
        variable v:         regs_type;
        variable v_inbit:   std_ulogic;
    begin
        v           := r;
        v_inbit     := '0';
 
        -- disconnect timer
        if inact = '1' then
            -- activity on input; reset timer
            v.disccnt   := to_unsigned(disconnect_time, v.disccnt'length);
        elsif r.disccnt /= 0 then
            -- count down
            v.disccnt   := r.disccnt - 1;
        end if;
 
        -- assume no new token
        v.gotfct    := '0';
        v.tick_out  := '0';
        v.rxchar    := '0';
 
        if inbvalid = '1' then
 
            -- process incoming bits
            for i in 0 to rxchunk-1 loop
                v_inbit     := inbits(i);
 
                -- got a bit transition
                v.bit_seen  := '1';
 
                if v.bitcnt(0) = '1' then
                    -- received new token
                    if (v.parity xor v_inbit) = '0' then
                        -- Parity check failed.
                        v.errpar    := '1';
                    else
                        if v.control = '1' then
                            -- received control code
                            case v.bitshift(7 downto 6) is
                                when "00" => -- FCT or NULL
                                    v.gotfct    := not r.escaped;
                                    v.escaped   := '0';
                                when "10" => -- EOP
                                    if r.escaped = '1' then
                                        v.erresc    := '1';
                                    end if;
                                    v.escaped   := '0';
                                    v.rxchar    := not r.escaped;
                                    v.rxflag    := '1';
                                    v.datareg   := "00000000";
                                when "01" => -- EEP
                                    if r.escaped = '1' then
                                        v.erresc    := '1';
                                    end if;
                                    v.escaped   := '0';
                                    v.rxchar    := not r.escaped;
                                    v.rxflag    := '1';
                                    v.datareg   := "00000001";
                                when others => -- ESC
                                    if r.escaped = '1' then
                                        v.erresc    := '1';
                                    end if;
                                    v.escaped   := '1';
                            end case;
                        else
                            -- received 8-bit character
                            if r.escaped = '1' then
                                -- received Time-Code
                                v.tick_out  := '1';
                                v.timereg   := v.bitshift(7 downto 0);
                            else
                                -- received data character
                                v.rxflag    := '0';
                                v.rxchar    := '1';
                                v.datareg   := v.bitshift(7 downto 0);
                            end if;
                            v.escaped   := '0';
                        end if;
                    end if;
                    -- prepare for next code
                    v.parity    := '0';
                    v.control   := v_inbit;
                    if v_inbit = '1' then
                        -- next word will be control code.
                        v.bitcnt    := (3 => '1', others => '0');
                    else
                        -- next word will be a data byte.
                        v.bitcnt    := (9 => '1', others => '0');
                    end if;
                else
                    -- wait until next code is completely received;
                    -- accumulate parity
                    v.bitcnt    := '0' & v.bitcnt(9 downto 1);
                    v.parity    := v.parity xor v_inbit;
                end if;
 
                -- detect first NULL
                if v.null_seen = '0' then
                    if v.bitshift = "000101110" then
                        -- got first NULL pattern
                        v.null_seen := '1';
                        v.control   := v_inbit; -- should always be '1'
                        v.parity    := '0';
                        v.bitcnt    := (3 => '1', others => '0');
                    end if;
                end if;
 
                -- shift new bit into register.
                v.bitshift  := v_inbit & v.bitshift(v.bitshift'high downto 1);
 
            end loop;
        end if;
 
        -- synchronous reset
        if rxen = '0' then
            v.bit_seen  := '0';
            v.null_seen := '0';
            v.bitshift  := "111111111";
            v.bitcnt    := (others => '0');
            v.gotfct    := '0';
            v.tick_out  := '0';
            v.rxchar    := '0';
            v.rxflag    := '0';
            v.escaped   := '0';
            v.timereg   := "00000000";
            v.datareg   := "00000000";
            v.disccnt   := to_unsigned(0, v.disccnt'length);
            v.errpar    := '0';
            v.erresc    := '0';
        end if;
 
        -- drive outputs
        recvo.gotbit    <= r.bit_seen;
        recvo.gotnull   <= r.null_seen;
        recvo.gotfct    <= r.gotfct;
        recvo.tick_out  <= r.tick_out;
        recvo.ctrl_out  <= r.timereg(7 downto 6);
        recvo.time_out  <= r.timereg(5 downto 0);
        recvo.rxchar    <= r.rxchar;
        recvo.rxflag    <= r.rxflag;
        recvo.rxdata    <= r.datareg;
        if r.bit_seen = '1' and r.disccnt = 0 then
            recvo.errdisc   <= '1';
        else
            recvo.errdisc   <= '0';
        end if;
        recvo.errpar    <= r.errpar;
        recvo.erresc    <= r.erresc;
 
        -- update registers
        rin         <= v;
 
    end process;
 
    -- update registers on rising edge of system clock
    process (clk) is
    begin
        if rising_edge(clk) then
            r <= rin;
        end if;
    end process;
 
end architecture spwrecv_arch;
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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