-- -- Downlink Encoder -- -- A bit more of a non-optimal hack, as this one isn't for an ASIC -- -- Matt Warren Aug 2016 -- -- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library downlink; use downlink.lcb_pkg_globals.all; entity lcbtst_encoder is port( hccid_i : in std_logic_vector(4 downto 0); l0a_i : in std_logic; bcr_i : in std_logic; tag_i : in std_logic_vector(6 downto 0); cmd7_i : in std_logic_vector(6 downto 0); cmd7_ready_i : in std_logic; cmd7_start_i : in std_logic; cmd7_end_i : in std_logic; cmd7_ack_o : out std_logic; ------------------------------ frame_sync_o : out std_logic_vector(1 downto 0); par4_o : out std_logic_vector(3 downto 0); -- Infra --clk160 : in std_logic; clk40 : in std_logic; --40MHz BCO rst : in std_logic ); -- Declarations end lcbtst_encoder; --------------------------------------------------------------------------- architecture rtl of lcbtst_encoder is signal frame_sync : std_logic_vector(1 downto 0); signal bcr : std_logic; signal l0a_sr : std_logic_vector(3 downto 0); signal l0a_map : std_logic_vector(3 downto 0); signal tag : std_logic_vector(6 downto 0); signal tag0 : std_logic_vector(6 downto 0); signal data6b0_l0a : std_logic_vector(5 downto 0); signal data6b1_l0a : std_logic_vector(5 downto 0); signal ready_l0a : std_logic; signal lone_bcr : std_logic; signal dbg_bcr : std_logic; signal dbg_l0a_map : std_logic_vector(3 downto 0); signal dbg_tag : std_logic_vector(6 downto 0); signal data6b0_cmd : std_logic_vector(5 downto 0); signal data6b1_cmd : std_logic_vector(5 downto 0); signal ready_cmd : std_logic; signal cmd7_ack0 : std_logic; -- IDLE frame signal symb0_idle : std_logic_vector(7 downto 0); signal symb1_idle : std_logic_vector(7 downto 0); signal enc_in : std_logic_vector(5 downto 0); signal enc_out : std_logic_vector(7 downto 0); signal symbol_out : std_logic_vector(7 downto 0); signal symbol_out_q : std_logic_vector(7 downto 0); type states is (Symbol00, L0A0, CMDStart0, CMDReady0, CMDEnd0, Idle0, L0A1, CMDStart1, CMDReady1, CMDEnd1, Idle1 ); signal state, nstate : states; begin -- Generate frame sync prc_frame_sync_gen : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then frame_sync <= FSYNC_NIB0; else if (bcr_i = '1') then -- Using BCR to set the frame phase ... gets -- messy if BCR is sent at the wrong time frame_sync <= FSYNC_NIB0; -- BCR arrives in NIB3, so next NIB is 0 elsif (frame_sync = "11") then frame_sync <= "00"; else frame_sync <= frame_sync + '1'; end if; end if; end if; end process; frame_sync_o <= frame_sync; ----------------------------------------------- -- Shift L0A in l0a_sr(0) <= l0a_i; l0a_sr(3 downto 1) <= l0a_sr(2 downto 0) when rising_edge(clk40); -- next frame gen and store prc_frame_store : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then bcr <= '0'; l0a_map <= "0000"; tag <= "0000000"; else if (frame_sync = FSYNC_NIB0) then tag0 <= tag_i; -- sample tag at the begining -- to allow for auto incementing elsif (frame_sync = FSYNC_FRAME) then tag <= tag0; -- still need taq in phase with everything else bcr <= bcr_i; l0a_map <= l0a_sr; end if; end if; end if; end process; -- L0A frame lone_bcr <= '1' when (bcr = '1') and (l0a_map = "0000") else '0'; data6b0_l0a <= bcr & l0a_map & tag(6) when (lone_bcr = '0') else "100000"; data6b1_l0a <= tag(5 downto 0) when (lone_bcr = '0') else "000000"; ready_l0a <= '1' when (l0a_map /= "0000") or (bcr = '1') else '0'; -- Easy now, but may need to revert to more complicated latching dbg_bcr <= bcr; -- when rising_edge(symbol0_sync); dbg_l0a_map <= l0a_map; -- when rising_edge(symbol0_sync); dbg_tag(6) <= tag(6); -- when rising_edge(symbol0_sync); dbg_tag(5 downto 0) <= tag(5 downto 0); -- when rising_edge(symbol1_sync); -- CMD frame data6b0_cmd <= "00000" & cmd7_i(6); data6b1_cmd <= cmd7_i(5 downto 0); ready_cmd <= cmd7_ready_i; -- IDLE frame symb0_idle <= MAP_K_8B(0); symb1_idle <= MAP_K_8B(1); -- Encoder --------------------------------------------- enc_out <= MAP_6B_8B(conv_integer(enc_in)); prc_sm_sync_part : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then state <= Symbol00; else if (frame_sync = FSYNC_FRAME) then -- Next state symbol 0 state <= Symbol00; else state <= nstate; end if; end if; end if; end process; prc_frame_out : process (cmd7_end_i, cmd7_ready_i, cmd7_start_i, data6b0_cmd, data6b0_l0a, data6b1_cmd, data6b1_l0a, enc_out, frame_sync, hccid_i, ready_l0a, state, symb0_idle, symb1_idle) begin -- defaults cmd7_ack0 <= '0'; enc_in <= data6b0_l0a; symbol_out <= enc_out; case state is when Symbol00 => if (ready_l0a = '1') then enc_in <= data6b0_l0a; symbol_out <= enc_out; nstate <= L0A0; elsif (cmd7_start_i = '1') then symbol_out <= S6B8B_K2; nstate <= CMDStart0; elsif (cmd7_end_i = '1') then symbol_out <= S6B8B_K3; nstate <= CMDEnd0; elsif (cmd7_ready_i = '1') then enc_in <= data6b0_cmd; symbol_out <= enc_out; nstate <= CMDReady0; else symbol_out <= symb0_idle; nstate <= Idle0; end if; -- Symbol 0 nib 1 states ------------------------------------------------------ when L0A0 => enc_in <= data6b0_l0a; symbol_out <= enc_out; nstate <= L0A1; when CMDStart0 => symbol_out <= S6B8B_K2; nstate <= CMDStart1; when CMDEnd0 => symbol_out <= S6B8B_K3; nstate <= CMDEnd1; when CMDReady0 => enc_in <= data6b0_cmd; symbol_out <= enc_out; nstate <= CMDReady1; when Idle0 => symbol_out <= symb0_idle; nstate <= Idle1; -- symbol 1 states (stay here until sync part changes state) ----------------------------------------------------------- when L0A1 => enc_in <= data6b1_l0a; symbol_out <= enc_out; nstate <= L0A1; when CMDStart1 => cmd7_ack0 <= '1'; enc_in <= '0' & hccid_i; symbol_out <= enc_out; nstate <= CMDStart1; when CMDEnd1 => cmd7_ack0 <= '1'; symbol_out <= SYMB_CMD_END; nstate <= CMDEnd1; when CMDReady1 => cmd7_ack0 <= '1'; enc_in <= data6b1_cmd; symbol_out <= enc_out; nstate <= CMDReady1; when Idle1 => symbol_out <= symb1_idle; nstate <= Idle1; end case; end process; cmd7_ack_o <= cmd7_ack0 when (frame_sync = FSYNC_FRAME) else '0'; -- par4b symbol mux -- ----------------------------------------------------------------------- -- Not worried about latency here at the mo, so sync prc_par4_out : process (clk40) begin if rising_edge(clk40) then -- if (rst = '1') then -- par4_o <= "0000"; -- else symbol_out_q <= symbol_out; -- store symbol for later tx (well it's -- -- just the lower nibble really) -- if (frame_sync(0) = '1') then -- symbol sync -- par4_o <= symbol_out(7 downto 4); -- else -- par4_o <= symbol_out_q(3 downto 0); -- end if; -- end if; end if; end process; -- OR we just do it the easy way - to hell with sync in sim par4_o <= symbol_out(7 downto 4) when (frame_sync(0) = '1') else -- symbol sync symbol_out_q(3 downto 0); end rtl;