##// END OF EJS Templates
MiniSpartan6:...
MiniSpartan6: added ftdi chip config to switch between UART and Async FIFO. added few WIP designs with either spwlight core, FIFO_deom IP... Libs: added SpaceWire Light IP (Works really well!) started design of ahb_ftdi_fifo -> same protocol than AHBUART but over FTDI's Async FIFO interface. This might lead to much faster transfers UP to 12MB/s.

File last commit:

r681:9d85f9f8f05a default
r681:9d85f9f8f05a default
Show More
spwrecv.vhd
267 lines | 9.2 KiB | text/x-vhdl | VhdlLexer
MiniSpartan6:...
r681 --
-- 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
-- note that this will not happen before null_seen='1'
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;