URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
[/] [open8_urisc/] [trunk/] [VHDL/] [o8_sdlc_if.vhd] - Rev 283
Compare with Previous | Blame | View Log
-- Copyright (c)2020 Jeremy Seth Henry -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- * Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- * Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution, -- where applicable (as part of a user interface, debugging port, etc.) -- -- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY -- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- -- VHDL Units : o8_sdlc_if -- Description: Provides a full memory-mapped SDLC stack with automatic CRC16 -- Checksum insertion and integrity checking. Note that this -- entity ONLY provides packet framing and checksum calculation. -- -- Transmit Memory Map -- "0_0000_0000" (0x000) TX Buffer START -- "0_1111_1101" (0x0FD) TX Buffer END -- "0_1111_1110" (0x0FE) Clock Status* -- "0_1111_1111" (0x0FF) TX Length / Status** -- -- Receive Memory Map -- "1_0000_0000" (0x100) RX Buffer START -- "1_1111_1101" (0x1FD) RX Buffer END -- "1_1111_1110" (0x0FE) RX Checksum Status*** -- "1_1111_1111" (0x1FF) RX Length Status**** -- -- * Address 0xFE reports the SDLC bit clock status and updates on changes. -- 1) If BClk_Okay = '0' (Bitclock is NOT present), the field will report -- 0x00. Otherwise, it will report 0xFF if the bitclock is present. -- 2) Writing any value to the register will cause the controller to -- silently reset the clock status without causing an interrupt. -- -- ** This location serves as the control/status register for transmit -- 1) Writing a value between 1 and 253 will trigger the transmit engine, -- using the write value as the packet length. -- 2) Values 0x00, 0xFE, or 0xFF are invalid, and will be ignored. -- 3) This value will change from the user written value to 0xFF once the -- packet is transmitted to indicate the transmission is complete. -- -- *** This location serves as the status register for receive checksum test -- 1) A value of 0x00 indicates the CRC did NOT match, while a value -- of 0xFF indicates that the recieved CRC matches the calculated CRC. -- -- **** This location serves as the status register for the receive -- 1) This value is only updated on reception of a full frame, indicated -- by a start followed by a stop flag. Incomplete frames are ignored. -- 2) If too many bytes are received (buffer overflow), a value of -- ERR_LENGTH is written. -- -- Revision History -- Author Date Change ------------------ -------- --------------------------------------------------- -- Seth Henry 12/09/20 Created from merged sub-entities into flat file library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use ieee.std_logic_misc.all; library work; use work.open8_pkg.all; entity o8_sdlc_if is generic( Poly_Init : std_logic_vector(15 downto 0) := x"0000"; Set_As_Master : boolean := true; Clock_Offset : integer := 6; BitClock_Frequency : real := 500000.0; Clock_Frequency : real := 100000000.0; Address : ADDRESS_TYPE ); port( Open8_Bus : in OPEN8_BUS_TYPE; Write_Qual : in std_logic := '1'; Rd_Data : out DATA_TYPE; TX_Interrupt : out std_logic; RX_Interrupt : out std_logic; -- Serial IO SDLC_In : in std_logic; SDLC_SClk : in std_logic; SDLC_MClk : out std_logic; SDLC_Out : out std_logic ); end entity; architecture behave of o8_sdlc_if is -- convenient subtypes & constants subtype CRC_TYPE is std_logic_vector(15 downto 0); -- Bus interface alias Clock is Open8_Bus.Clock; alias Reset is Open8_Bus.Reset; constant Base_Addr : std_logic_vector(15 downto 9) := Address(15 downto 9); alias CPU_Upper_Addr is Open8_Bus.Address(15 downto 9); signal Base_Addr_Match : std_logic := '0'; alias DP_A_Addr is Open8_Bus.Address(8 downto 0); signal DP_A_Wr_En : std_logic := '0'; alias DP_A_Wr_Data is Open8_Bus.Wr_Data; signal DP_A_Rd_En_d : std_logic := '0'; signal DP_A_Rd_En_q : std_logic := '0'; signal DP_A_Rd_Data : DATA_TYPE := OPEN8_NULLBUS; constant Reg_Sub_Addr : std_logic_vector(8 downto 1) := x"7F"; alias Reg_Upper_Addr is Open8_Bus.Address(8 downto 1); alias Reg_Lower_Addr is Open8_Bus.Address(0); signal Reg_Addr : std_logic_vector(8 downto 1) := (others => '0'); signal Reg_Sel : std_logic := '0'; signal Reg_Wr_En_d : std_logic := '0'; signal Reg_Wr_En_q : std_logic := '0'; signal TX_Ctl_Clk : std_logic := '0'; signal TX_Ctl_Len : std_logic := '0'; -- Dual-port memory signal DP_B_Addr : std_logic_vector(8 downto 0) := (others => '0'); signal DP_B_Wr_Data : DATA_TYPE := x"00"; signal DP_B_Wr_En : std_logic := '0'; signal DP_B_Rd_Data : DATA_TYPE := x"00"; -- Internal definitions constant SDLC_Flag : DATA_TYPE := x"7E"; constant CK_REGISTER : DATA_TYPE := x"FE"; constant TX_REGISTER : DATA_TYPE := x"FF"; constant CS_REGISTER : DATA_TYPE := x"FE"; constant RX_REGISTER : DATA_TYPE := x"FF"; constant TX_RESERVED_LOW : integer := 0; constant TX_RESERVED_HIGH : integer := 254; constant FLAG_DONE : DATA_TYPE := x"FF"; constant ERR_LENGTH : DATA_TYPE := x"00"; -- RAM Arbitration logic type DP_ARB_STATES is (PAUSE, IDLE, PORT0_AD, PORT0_WR, PORT0_RD0, PORT0_RD1, PORT1_AD, PORT1_WR, PORT1_RD0, PORT1_RD1 ); signal DP_Arb_State : DP_ARB_STATES := IDLE; signal DP_Last_Port : std_logic := '0'; signal DP_Port0_Addr : DATA_TYPE := x"00"; signal DP_Port0_RWn : std_logic := '0'; signal DP_Port0_WrData : DATA_TYPE := x"00"; signal DP_Port0_RdData : DATA_TYPE := x"00"; signal DP_Port0_Req : std_logic := '0'; signal DP_Port0_Ack : std_logic := '0'; signal DP_Port1_Addr : DATA_TYPE := x"00"; signal DP_Port1_RWn : std_logic := '0'; signal DP_Port1_WrData : DATA_TYPE := x"00"; signal DP_Port1_RdData : DATA_TYPE := x"00"; signal DP_Port1_Req : std_logic := '0'; signal DP_Port1_Ack : std_logic := '0'; -- Clock generation constant DLY_VAL : integer := integer(Clock_Frequency / (2.0 * BitClock_Frequency) ); constant DLY_WDT : integer := ceil_log2(DLY_VAL - 1); constant DLY_VEC : std_logic_vector := conv_std_logic_vector( DLY_VAL - 1, DLY_WDT); signal BClk_Cntr : std_logic_vector( DLY_WDT - 1 downto 0 ) := (others => '0'); signal BClk_Adv : std_logic := '0'; signal BClk_Accum : std_logic_vector(31 downto 0) := (others => '0'); signal BClk_Div : std_logic := '0'; signal BClk_Okay_SR : std_logic_vector(3 downto 0) := (others => '0'); signal BClk_SR : std_logic_vector(2 downto 0) := (others => '0'); constant CLK_RATIO_R : real := Clock_Frequency / (1.0 * BitClock_Frequency); constant CLK_DEVIATION_5P : real := CLK_RATIO_R * 0.05; constant CLK_RATIO_ADJ_R : real := CLK_RATIO_R + CLK_DEVIATION_5P; constant CLK_RATIO_ADJ_I : integer := integer(CLK_RATIO_ADJ_R); constant Threshold_bits : integer := ceil_log2(CLK_RATIO_ADJ_I); constant THRESHOLD : std_logic_vector(Threshold_bits - 1 downto 0) := conv_std_logic_vector(CLK_RATIO_ADJ_I,Threshold_bits); signal RE_Threshold_Ctr : std_logic_vector(Threshold_Bits - 1 downto 0) := (others => '0'); signal FE_Threshold_Ctr : std_logic_vector(Threshold_Bits - 1 downto 0) := (others => '0'); signal Ref_In_SR : std_logic_vector(2 downto 0) := (others => '0'); alias Ref_In_q1 is Ref_In_SR(1); alias Ref_In_q2 is Ref_In_SR(2); signal Ref_In_RE : std_logic := '0'; signal Ref_In_FE : std_logic := '0'; signal BClk_RE : std_logic := '0'; signal BClk_FE : std_logic := '0'; signal BClk_Okay : std_logic := '0'; -- Packet Transmit state logic type TX_FSM_STATES is ( INIT_FLAG, WR_CLOCK_STATE, WAIT_FOR_UPDATE, RD_TX_REGISTER, TX_INIT, TX_START_FLAG, TX_WAIT_START_FLAG, TX_MESG_DATA, TX_ADV_ADDR, TX_WAIT_MESG_DATA, TX_CRC_LB_WR, TX_WAIT_CRC_LB, TX_CRC_UB_WR, TX_WAIT_CRC_UB, TX_STOP_FLAG, TX_WAIT_STOP_FLAG, TX_SET_FLAG ); signal TX_FSM_State : TX_FSM_STATES := WR_CLOCK_STATE; signal TX_Length : DATA_TYPE := x"00"; signal BClk_q1, BClk_CoS : std_logic := '0'; signal TX_Int_pend : std_logic := '0'; signal TX_Wr_En : std_logic := '0'; signal TX_Wr_Flag : std_logic := '0'; signal TX_Wr_Data : DATA_TYPE := x"00"; signal TX_Req_Next : std_logic := '0'; signal TX_CRC_Clr : std_logic := '0'; signal TX_CRC_En : std_logic := '0'; signal TX_CRC_Data : CRC_TYPE := x"0000"; signal TX_CRC_Valid : std_logic := '0'; alias TX_CRC_Data_LB is TX_CRC_Data(7 downto 0); alias TX_CRC_Data_UB is TX_CRC_Data(15 downto 8); signal TX_Arm : std_logic := '0'; signal TX_Flag : std_logic := '0'; signal TX_Buffer : std_logic_vector(8 downto 0) := (others => '0'); alias TX_Buffer_Flag is TX_Buffer(8); alias TX_Buffer_Data is TX_Buffer(7 downto 0); -- SDLC transmitter type TX_STATES is (INIT, IDLE, XMIT, SPACE, TERM, LD_NEXT); signal TX_State : TX_STATES := INIT; signal TX_ShftReg : DATA_TYPE := (others => '0'); signal TX_Next : std_logic := '0'; signal TX_BitStuff : std_logic_vector(4 downto 0) := (others => '0'); signal TX_BitCntr : std_logic_vector(3 downto 0) := (others => '0'); alias TX_BitSel is TX_BitCntr(2 downto 0); alias TX_Term is TX_BitCntr(3); -- SDLC receiver signal RX_LatchEn_SR : std_logic_vector(Clock_Offset downto 0) := (others => '0'); alias RX_LatchEn_M is RX_LatchEn_SR(Clock_Offset); alias RX_LatchEn_S is BClk_RE; signal RX_LatchEn : std_logic := '0'; signal RX_Serial_SR : std_logic_vector(1 downto 0) := (others => '0'); alias RX_Serial is RX_Serial_SR(1); type RX_STATES is (INIT, IDLE, RCV_DATA, SKIP_ZERO, WRITE_DATA); signal RX_State : RX_STATES := INIT; signal RX_Buffer : DATA_TYPE := x"00"; signal RX_BitStuff_SR : std_logic_vector(4 downto 0) := (others => '0'); signal RX_BitCntr : std_logic_vector(3 downto 0) := (others => '0'); alias RX_BitSel is RX_BitCntr(2 downto 0); alias RX_Term is RX_BitCntr(3); signal RX_Flag_SR : DATA_TYPE := x"00"; signal RX_Idle_Cntr : std_logic_vector(2 downto 0) := (others => '0'); signal RX_Valid : std_logic := '0'; signal RX_Flag : std_logic := '0'; signal RX_Data : DATA_TYPE := x"00"; signal RX_Idle : std_logic := '0'; -- Packet detection logic type PACKET_STATES is (IDLE, FRAME_START, FRAME_DATA, FRAME_STOP ); signal Pkt_State : PACKET_STATES := IDLE; signal First_Byte : std_logic := '0'; signal RX_Frame_Start : std_logic := '0'; signal RX_Frame_Stop : std_logic := '0'; signal RX_Frame_Valid : std_logic := '0'; signal RX_Frame_Data : DATA_TYPE := x"00"; -- Receive data CRC calculation signal RX_CRC_Valid : std_logic := '0'; signal RX_CRC_Data : CRC_TYPE := x"0000"; type CRC_HISTORY is array(0 to 2) of CRC_TYPE; signal RX_CRC_Hist : CRC_HISTORY := (x"0000",x"0000",x"0000"); alias RX_CRC_Calc is RX_CRC_Hist(2); signal RX_CRC_Rcvd : CRC_TYPE := x"0000"; alias RX_CRC_Rcvd_LB is RX_CRC_Rcvd(7 downto 0); alias RX_CRC_Rcvd_UB is RX_CRC_Rcvd(15 downto 8); -- Packet receive state logic type RX_FSM_STATES is ( WAIT_FOR_CLOCK, WAIT_FOR_FLAG, RX_MESG_DATA, RX_WR_DATA, RX_CRC_LB_RD, RX_CRC_UB_RD, RX_WR_CRC, RX_WR_COUNT ); signal RX_FSM_State : RX_FSM_STATES := WAIT_FOR_CLOCK; signal RX_Length : DATA_TYPE := x"00"; begin -- *************************************************************************** -- * Open8 Bus Interface and Control Register Detection * -- *************************************************************************** -- This decode needs to happen immediately, to give the RAM a chance to -- do the lookup before we have to set Rd_Data Base_Addr_Match <= '1' when Base_Addr = CPU_Upper_Addr else '0'; Reg_Wr_En_d <= Base_Addr_Match and Open8_Bus.Wr_En and Write_Qual; DP_A_Wr_En <= Base_Addr_Match and Open8_Bus.Wr_En and Write_Qual; DP_A_Rd_En_d <= Base_Addr_Match and Open8_Bus.Rd_En; CPU_IF_proc: process( Reset, Clock ) begin if( Reset = Reset_Level )then Reg_Addr <= (others => '0'); Reg_Wr_En_q <= '0'; TX_Ctl_Clk <= '0'; TX_Ctl_Len <= '0'; DP_A_Rd_En_q <= '0'; Rd_Data <= OPEN8_NULLBUS; elsif( rising_edge(Clock) )then Reg_Addr <= Reg_Upper_Addr; Reg_Sel <= Reg_Lower_Addr; Reg_Wr_En_q <= Reg_Wr_En_d; TX_Ctl_Clk <= '0'; TX_Ctl_Len <= '0'; if( Reg_Addr = Reg_Sub_Addr )then TX_Ctl_Clk <= Reg_Wr_En_q and not Reg_Sel; TX_Ctl_Len <= Reg_Wr_En_q and Reg_Sel; end if; DP_A_Rd_En_q <= DP_A_Rd_En_d; Rd_Data <= OPEN8_NULLBUS; if( DP_A_Rd_En_q = '1' )then Rd_Data <= DP_A_Rd_Data; end if; end if; end process; -- *************************************************************************** -- * Shared Dual-Port Memory * -- *************************************************************************** U_RAM : entity work.sdlc_dp512b_ram port map( clock => Clock, address_a => DP_A_Addr, address_b => DP_B_Addr, data_a => DP_A_Wr_Data, data_b => DP_B_Wr_Data, wren_a => DP_A_Wr_En, wren_b => DP_B_Wr_En, q_a => DP_A_Rd_Data, q_b => DP_B_Rd_Data ); -- *************************************************************************** -- * Memory Arbitration * -- *************************************************************************** RAM_Arbitration_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then DP_Arb_State <= IDLE; DP_Last_Port <= '0'; DP_B_Addr <= (others => '0'); DP_B_Wr_Data <= x"00"; DP_B_Wr_En <= '0'; DP_Port0_RdData <= x"00"; DP_Port0_Ack <= '0'; DP_Port1_RdData <= x"00"; DP_Port1_Ack <= '0'; elsif( rising_edge(Clock) )then DP_Port0_Ack <= '0'; DP_Port1_Ack <= '0'; DP_B_Wr_En <= '0'; case( DP_Arb_State )is when IDLE => if( DP_Port0_Req = '1' and (DP_Port1_Req = '0' or DP_Last_Port = '1') )then DP_Arb_State <= PORT0_AD; elsif( DP_Port1_Req = '1' and (DP_Port0_Req = '0' or DP_Last_Port = '0') )then DP_Arb_State <= PORT1_AD; end if; when PORT0_AD => DP_Last_Port <= '0'; DP_B_Addr <= '0' & DP_Port0_Addr; DP_B_Wr_Data <= DP_Port0_WrData; DP_B_Wr_En <= not DP_Port0_RWn; if( DP_Port0_RWn = '1' )then DP_Arb_State <= PORT0_RD0; else DP_Port0_Ack <= '1'; DP_Arb_State <= PORT0_WR; end if; when PORT0_WR => DP_Arb_State <= IDLE; when PORT0_RD0 => DP_Arb_State <= PORT0_RD1; when PORT0_RD1 => DP_Port0_Ack <= '1'; DP_Port0_RdData <= DP_B_Rd_Data; DP_Arb_State <= PAUSE; when PORT1_AD => DP_Last_Port <= '1'; DP_B_Addr <= '1' & DP_Port1_Addr; DP_B_Wr_Data <= DP_Port1_WrData; DP_B_Wr_En <= not DP_Port1_RWn; if( DP_Port0_RWn = '1' )then DP_Arb_State <= PORT1_RD0; else DP_Port1_Ack <= '1'; DP_Arb_State <= PORT1_WR; end if; when PORT1_WR => DP_Arb_State <= IDLE; when PORT1_RD0 => DP_Arb_State <= PORT1_RD1; when PORT1_RD1 => DP_Port1_Ack <= '1'; DP_Port1_RdData <= DP_B_Rd_Data; DP_Arb_State <= PAUSE; when PAUSE => DP_Arb_State <= IDLE; when others => null; end case; end if; end process; -- **************************************************************************** -- * Bit clock generation * -- **************************************************************************** Clock_Master: if( Set_As_Master )generate Clock_Gen_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then BClk_Cntr <= DLY_VEC; BClk_Adv <= '0'; BClk_Accum <= (others => '0'); BClk_Div <= '0'; BClk_Okay_SR <= (others => '0'); BClk_RE <= '0'; BClk_FE <= '0'; SDLC_MClk <= '0'; elsif( rising_edge( Clock ) )then BClk_Cntr <= BClk_Cntr - 1; BClk_Adv <= '0'; if( or_reduce(BClk_Cntr) = '0' )then BClk_Cntr <= DLY_VEC; BClk_Adv <= '1'; BClk_Okay_SR <= BClk_Okay_SR(2 downto 0) & '1'; end if; BClk_Accum <= BClk_Accum + BClk_Adv; BClk_Div <= BClk_Div xor BClk_Adv; BClk_RE <= (not BClk_Div) and BClk_Adv; BClk_FE <= BClk_Div and BClk_Adv; SDLC_MClk <= BClk_Div; end if; end process; BClk_Okay <= BClk_Okay_SR(3); end generate; Clock_Slave: if( not Set_As_Master )generate Clock_Edge_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then BClk_SR <= (others => '0'); BClk_FE <= '0'; BClk_RE <= '0'; elsif( rising_edge(Clock) )then BClk_SR <= BClk_SR(1 downto 0) & SDLC_SClk; BClk_FE <= BClk_SR(2) and (not BClk_SR(1)); BClk_RE <= (not BClk_SR(2)) and BClk_SR(1); end if; end process; SDLC_MClk <= '0'; Clock_Detect_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then Ref_In_SR <= (others => '0'); Ref_In_RE <= '0'; Ref_In_FE <= '0'; RE_Threshold_Ctr <= (others => '0'); FE_Threshold_Ctr <= (others => '0'); BClk_Okay <= '0'; elsif( rising_edge(Clock) )then Ref_In_SR <= Ref_In_SR(1 downto 0) & SDLC_SClk; Ref_In_RE <= Ref_In_q1 and (not Ref_In_q2); Ref_In_FE <= (not Ref_In_q1) and Ref_In_q2; RE_Threshold_Ctr <= RE_Threshold_Ctr - 1; if( Ref_In_RE = '1' )then RE_Threshold_Ctr <= THRESHOLD; elsif( or_reduce(RE_Threshold_Ctr) = '0' )then RE_Threshold_Ctr <= (others => '0'); end if; FE_Threshold_Ctr <= FE_Threshold_Ctr - 1; if( Ref_In_FE = '1' )then FE_Threshold_Ctr <= THRESHOLD; elsif( or_reduce(FE_Threshold_Ctr) = '0' )then FE_Threshold_Ctr <= (others => '0'); end if; BClk_Okay <= or_reduce(RE_Threshold_Ctr) and or_reduce(FE_Threshold_Ctr); end if; end process; end generate; -- *************************************************************************** -- * Serial Transmit Path * -- *************************************************************************** TX_Packet_RAM_proc: process( Reset, Clock ) begin if( Reset = Reset_Level )then TX_FSM_State <= INIT_FLAG; DP_Port0_Addr <= x"00"; DP_Port0_RWn <= '1'; DP_Port0_WrData <= x"00"; DP_Port0_Req <= '0'; TX_Length <= x"00"; TX_Wr_En <= '0'; TX_Wr_Flag <= '0'; TX_Wr_Data <= x"00"; TX_CRC_Clr <= '0'; TX_CRC_En <= '0'; BClk_q1 <= '0'; BClk_CoS <= '0'; TX_Int_pend <= '0'; TX_Interrupt <= '0'; elsif( rising_edge(Clock) )then DP_Port0_RWn <= '1'; DP_Port0_WrData <= x"00"; DP_Port0_Req <= '0'; TX_Wr_En <= '0'; TX_Wr_Flag <= '0'; TX_Wr_Data <= x"00"; TX_CRC_Clr <= '0'; TX_CRC_En <= '0'; BClk_q1 <= BClk_Okay; BClk_CoS <= BClk_q1 xor BClk_Okay; TX_Interrupt <= '0'; case( TX_FSM_State )is when INIT_FLAG => DP_Port0_Addr <= TX_REGISTER; DP_Port0_Req <= '1'; DP_Port0_WrData <= FLAG_DONE; DP_Port0_RWn <= '0'; if( DP_Port0_Ack = '1' )then DP_Port0_Req <= '0'; TX_FSM_State <= WR_CLOCK_STATE; end if; when WR_CLOCK_STATE => DP_Port0_Addr <= CK_REGISTER; DP_Port0_Req <= '1'; DP_Port0_WrData <= (others => BClk_Okay); DP_Port0_RWn <= '0'; if( DP_Port0_Ack = '1' )then TX_Interrupt <= TX_Int_pend; TX_Int_pend <= '0'; DP_Port0_Req <= '0'; TX_FSM_State <= WAIT_FOR_UPDATE; end if; when WAIT_FOR_UPDATE => if( TX_Ctl_Clk = '1' )then TX_FSM_State <= WR_CLOCK_STATE; end if; if( TX_Ctl_Len = '1' and BClk_Okay = '1' )then TX_FSM_State <= RD_TX_REGISTER; end if; when RD_TX_REGISTER => DP_Port0_Addr <= TX_REGISTER; DP_Port0_Req <= '1'; if( DP_Port0_Ack = '1' )then DP_Port0_Req <= '0'; TX_Length <= DP_Port0_RdData; TX_FSM_State <= TX_INIT; end if; when TX_INIT => TX_FSM_State <= WAIT_FOR_UPDATE; if( TX_Length > TX_RESERVED_LOW and TX_Length < TX_RESERVED_HIGH )then TX_CRC_Clr <= '1'; TX_FSM_State <= TX_START_FLAG; end if; when TX_START_FLAG => TX_Wr_En <= '1'; TX_Wr_Flag <= '1'; TX_Wr_Data <= SDLC_FLAG; TX_FSM_State <= TX_WAIT_START_FLAG; when TX_WAIT_START_FLAG => if( TX_Req_Next = '1' )then DP_Port0_Addr <= x"00"; TX_FSM_State <= TX_ADV_ADDR; end if; when TX_ADV_ADDR => DP_Port0_Req <= '1'; if( DP_Port0_Ack = '1' )then DP_Port0_Req <= '0'; DP_Port0_Addr <= DP_Port0_Addr + 1; TX_Length <= TX_Length - 1; TX_FSM_State <= TX_MESG_DATA; end if; when TX_MESG_DATA => TX_Wr_En <= '1'; TX_Wr_Data <= DP_Port0_RdData; TX_CRC_En <= '1'; TX_FSM_State <= TX_WAIT_MESG_DATA; when TX_WAIT_MESG_DATA => if( TX_Req_Next = '1' )then TX_FSM_State <= TX_ADV_ADDR; if( TX_Length = 0 )then TX_FSM_State <= TX_CRC_LB_WR; end if; end if; when TX_CRC_LB_WR => TX_Wr_En <= '1'; TX_Wr_Data <= TX_CRC_Data_LB; TX_FSM_State <= TX_WAIT_CRC_LB; when TX_WAIT_CRC_LB => if( TX_Req_Next = '1' )then TX_FSM_State <= TX_CRC_UB_WR; end if; when TX_CRC_UB_WR => TX_Wr_En <= '1'; TX_Wr_Data <= TX_CRC_Data_UB; TX_FSM_State <= TX_WAIT_CRC_UB; when TX_WAIT_CRC_UB => if( TX_Req_Next = '1' )then TX_FSM_State <= TX_STOP_FLAG; end if; when TX_STOP_FLAG => TX_Wr_En <= '1'; TX_Wr_Flag <= '1'; TX_Wr_Data <= SDLC_FLAG; TX_FSM_State <= TX_WAIT_STOP_FLAG; when TX_WAIT_STOP_FLAG => if( TX_Req_Next = '1' )then TX_FSM_State <= TX_SET_FLAG; end if; when TX_SET_FLAG => DP_Port0_Addr <= TX_REGISTER; DP_Port0_Req <= '1'; DP_Port0_WrData <= FLAG_DONE; DP_Port0_RWn <= '0'; if( DP_Port0_Ack = '1' )then DP_Port0_Req <= '0'; TX_FSM_State <= WAIT_FOR_UPDATE; end if; when others => null; end case; if( BClk_CoS = '1' )then TX_Int_pend <= '1'; TX_FSM_State <= WR_CLOCK_STATE; end if; end if; end process; U_TX_CRC : entity work.sdlc_crc16_ccitt generic map( Poly_Init => Poly_Init, Reset_Level => Reset_Level ) port map( Clock => Clock, Reset => Reset, -- Clear => TX_CRC_Clr, Wr_En => TX_CRC_En, Wr_Data => TX_Wr_Data, -- CRC16_Valid => TX_CRC_Valid, CRC16_Out => TX_CRC_Data ); TX_Serial_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then TX_State <= IDLE; SDLC_Out <= '1'; TX_Arm <= '0'; TX_Buffer <= (others => '0'); TX_Flag <= '0'; TX_ShftReg <= (others => '0'); TX_BitStuff <= (others => '0'); TX_BitCntr <= (others => '1'); TX_Req_Next <= '0'; elsif( rising_edge(Clock) )then if( TX_Wr_En = '1' and TX_Arm = '0')then TX_Arm <= '1'; TX_Buffer_Flag <= TX_Wr_Flag; TX_Buffer_Data <= TX_Wr_Data; end if; TX_Req_Next <= '0'; case( TX_State )is when INIT => SDLC_Out <= '1'; TX_State <= IDLE; when IDLE => SDLC_Out <= '1'; if( TX_Arm = '1' and BClk_FE = '1' )then TX_Arm <= '0'; TX_BitCntr <= (others => '0'); TX_BitStuff <= (others => '0'); TX_Flag <= TX_Buffer_Flag; TX_ShftReg <= TX_Buffer_Data; TX_Req_Next <= '1'; TX_State <= XMIT; end if; when XMIT => SDLC_Out <= TX_ShftReg(conv_integer(TX_BitSel)); TX_BitCntr <= TX_BitCntr + BClk_FE; if( BClk_RE = '1' )then TX_BitStuff <= TX_BitStuff(3 downto 0) & TX_ShftReg(conv_integer(TX_BitSel)); end if; if( BClk_FE = '1' )then if( TX_BitCntr >= 7 )then TX_State <= TERM; elsif( and_reduce(TX_BitStuff) = '1' and TX_Flag = '0' )then TX_BitStuff <= (others => '0'); TX_State <= SPACE; else TX_BitCntr <= TX_BitCntr + 1; end if; end if; when SPACE => SDLC_Out <= '0'; if( BClk_FE = '1' )then TX_State <= XMIT; end if; when TERM => if( TX_Arm = '1' )then TX_State <= LD_NEXT; else TX_State <= IDLE; end if; when LD_NEXT => TX_Arm <= '0'; TX_BitCntr <= (others => '0'); TX_Flag <= TX_Buffer_Flag; TX_ShftReg <= TX_Buffer_Data; TX_Req_Next <= '1'; TX_State <= XMIT; if( and_reduce(TX_BitStuff) = '1' and TX_Flag = '0' )then TX_BitStuff <= (others => '0'); TX_State <= SPACE; end if; when others => null; end case; if( BClk_Okay = '0' )then TX_State <= INIT; end if; end if; end process; -- *************************************************************************** -- * Serial Receive Path * -- *************************************************************************** IF_Is_Master: if( Set_As_Master )generate Input_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then RX_LatchEn_SR <= (others => '0'); RX_Serial_SR <= (others => '0'); elsif( rising_edge(Clock) )then RX_LatchEn_SR <= RX_LatchEn_SR(Clock_Offset - 1 downto 0) & BClk_RE; RX_Serial_SR <= RX_Serial_SR(0) & SDLC_In; end if; end process; RX_LatchEn <= RX_LatchEn_M; end generate; IF_Is_Slave: if( not Set_As_Master )generate Input_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then RX_Serial_SR <= (others => '0'); elsif( rising_edge(Clock) )then RX_Serial_SR <= RX_Serial_SR(0) & SDLC_In; end if; end process; RX_LatchEn <= RX_LatchEn_S; end generate; RX_Serial_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then RX_BitStuff_SR <= (others => '0'); RX_Flag_SR <= (others => '0'); RX_Idle_Cntr <= (others => '0'); RX_State <= IDLE; RX_Idle <= '0'; RX_Buffer <= (others => '0'); RX_BitCntr <= (others => '0'); RX_Valid <= '0'; RX_Flag <= '0'; RX_Data <= (others => '0'); elsif( rising_edge(Clock) )then if( RX_LatchEn = '1' )then RX_Flag_SR <= RX_Flag_SR(6 downto 0) & RX_Serial; if( RX_State = IDLE )then RX_Flag_SR <= (others => '0'); end if; RX_Idle_Cntr <= RX_Idle_Cntr + RX_Serial; if( and_reduce(RX_Idle_Cntr) = '1' )then RX_Idle_Cntr <= "111"; end if; end if; if( RX_Serial = '0' )then RX_Idle_Cntr <= (others => '0'); end if; RX_Valid <= '0'; RX_Flag <= '0'; RX_Idle <= '0'; case( RX_State )is when INIT => RX_Idle <= '1'; RX_State <= IDLE; when IDLE => RX_Idle <= '1'; RX_BitCntr <= (others => '0'); RX_BitStuff_SR <= (others => '0'); if( RX_Serial = '0' )then RX_State <= RCV_DATA; end if; when RCV_DATA => if( RX_Term = '1' )then RX_State <= WRITE_DATA; end if; if( RX_LatchEn = '1' )then RX_Buffer(conv_integer(RX_BitSel)) <= RX_Serial; RX_BitStuff_SR <= RX_BitStuff_SR(3 downto 0) & RX_Serial; RX_BitCntr <= RX_BitCntr + 1; if( and_reduce(RX_BitStuff_SR) = '1' )then RX_BitStuff_SR <= (others => '0'); if( RX_Serial = '0' )then RX_BitCntr <= RX_BitCntr; RX_State <= SKIP_ZERO; end if; end if; end if; when SKIP_ZERO => RX_State <= RCV_DATA; when WRITE_DATA => RX_BitCntr <= (others => '0'); RX_Valid <= '1'; RX_Data <= RX_Buffer; if( RX_Flag_SR = SDLC_Flag )then RX_Flag <= '1'; end if; RX_State <= RCV_DATA; when others => null; end case; -- If we just shifted in the flag character, and the bit counter isn't -- 0x0, then our bit counter is out of alignment. Reset it to zero so -- that the next word is clocked in correctly. if( RX_Flag_SR = SDLC_Flag and RX_BitCntr > 0 )then RX_BitCntr <= (others => '0'); end if; -- If the serial line goes idle (In the marking state for more than 7 -- bit times), and the FSM isn't already in IDLE, force it to IDLE. if( and_reduce(RX_Idle_Cntr) = '1' and RX_State /= IDLE )then RX_State <= IDLE; end if; -- If the bit clock is no longer valid, soft-reset to the INIT state. if( BClk_Okay = '0' )then RX_State <= INIT; end if; end if; end process; Packet_Marker_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then Pkt_State <= IDLE; First_Byte <= '0'; RX_Frame_Start <= '0'; RX_Frame_Stop <= '0'; RX_Frame_Valid <= '0'; RX_Frame_Data <= x"00"; elsif( rising_edge(Clock) )then RX_Frame_Start <= '0'; RX_Frame_Stop <= '0'; RX_Frame_Valid <= '0'; case( Pkt_State )is when IDLE => if( RX_Valid = '1' and RX_Flag = '1' )then Pkt_State <= FRAME_START; end if; when FRAME_START => if( RX_Valid = '1' and RX_Flag = '0' )then RX_Frame_Start <= '1'; First_Byte <= '1'; Pkt_State <= FRAME_DATA; end if; when FRAME_DATA => First_Byte <= '0'; if( (RX_Valid = '1' and RX_Flag = '0') or First_Byte = '1' )then RX_Frame_Valid <= '1'; RX_Frame_Data <= RX_Data; elsif( RX_Valid = '1' and RX_Flag = '1' )then Pkt_State <= FRAME_STOP; end if; when FRAME_STOP => RX_Frame_Stop <= not RX_Idle; Pkt_State <= IDLE; when others => null; end case; if( RX_Idle = '1' and Pkt_State /= IDLE )then Pkt_State <= FRAME_STOP; end if; end if; end process; U_RX_CRC : entity work.sdlc_crc16_ccitt generic map( Poly_Init => Poly_Init, Reset_Level => Reset_Level ) port map( Clock => Clock, Reset => Reset, -- Clear => RX_Frame_Start, Wr_En => RX_Frame_Valid, Wr_Data => RX_Frame_Data, -- CRC16_Valid => RX_CRC_Valid, CRC16_Out => RX_CRC_Data ); CRC_History_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then RX_CRC_Hist(0) <= x"0000"; RX_CRC_Hist(1) <= x"0000"; RX_CRC_Hist(2) <= x"0000"; elsif( rising_edge(Clock) )then if( RX_CRC_Valid = '1' )then RX_CRC_Hist(2) <= RX_CRC_Hist(1); RX_CRC_Hist(1) <= RX_CRC_Hist(0); RX_CRC_Hist(0) <= RX_CRC_Data; end if; end if; end process; RX_Packet_RAM_proc: process( Reset, Clock ) begin if( Reset = Reset_Level )then RX_FSM_State <= WAIT_FOR_CLOCK; DP_Port1_Addr <= x"00"; DP_Port1_RWn <= '1'; DP_Port1_WrData <= x"00"; DP_Port1_Req <= '0'; RX_Length <= x"00"; RX_CRC_Rcvd <= x"0000"; RX_Interrupt <= '0'; elsif( rising_edge(Clock) )then DP_Port1_Addr <= x"00"; DP_Port1_RWn <= '1'; DP_Port1_WrData <= x"00"; DP_Port1_Req <= '0'; RX_Interrupt <= '0'; case( RX_FSM_State )is when WAIT_FOR_CLOCK => RX_FSM_State <= WAIT_FOR_FLAG; when WAIT_FOR_FLAG => if( RX_Frame_Start = '1' )then RX_Length <= x"00"; RX_FSM_State <= RX_MESG_DATA; end if; when RX_MESG_DATA => if( RX_Frame_Stop = '1' )then RX_Length <= RX_Length - 1; RX_FSM_State <= RX_CRC_UB_RD; elsif( RX_Frame_Valid = '1' )then RX_FSM_State <= RX_WR_DATA; if( RX_Length > 254 )then RX_Length <= ERR_LENGTH; RX_FSM_State <= RX_WR_COUNT; end if; end if; when RX_WR_DATA => RX_Length <= RX_Length + DP_Port1_Ack; DP_Port1_Addr <= RX_Length; DP_Port1_WrData <= RX_Frame_Data; DP_Port1_RWn <= '0'; DP_Port1_Req <= '1'; if( DP_Port1_Ack = '1' )then DP_Port1_Req <= '0'; RX_FSM_State <= RX_MESG_DATA; end if; when RX_CRC_UB_RD => RX_Length <= RX_Length - DP_Port1_Ack; DP_Port1_Addr <= RX_Length; DP_Port1_Req <= '1'; if( DP_Port1_Ack = '1' )then DP_Port1_Req <= '0'; RX_CRC_Rcvd_UB <= DP_Port1_RdData; RX_FSM_State <= RX_CRC_LB_RD; end if; when RX_CRC_LB_RD => DP_Port1_Addr <= RX_Length; DP_Port1_Req <= '1'; if( DP_Port1_Ack = '1' )then DP_Port1_Req <= '0'; RX_CRC_Rcvd_LB <= DP_Port1_RdData; RX_FSM_State <= RX_WR_CRC; end if; when RX_WR_CRC => DP_Port1_Addr <= CS_REGISTER; DP_Port1_WrData <= x"FF"; if( RX_CRC_Rcvd /= RX_CRC_Calc )then DP_Port1_WrData <= x"00"; end if; DP_Port1_RWn <= '0'; DP_Port1_Req <= '1'; if( DP_Port1_Ack = '1' )then DP_Port1_Req <= '0'; RX_FSM_State <= RX_WR_COUNT; end if; when RX_WR_COUNT => DP_Port1_Addr <= RX_REGISTER; DP_Port1_WrData <= RX_Length; DP_Port1_RWn <= '0'; DP_Port1_Req <= '1'; if( DP_Port1_Ack = '1' )then DP_Port1_Req <= '0'; RX_Interrupt <= '1'; RX_FSM_State <= WAIT_FOR_FLAG; end if; when others => null; end case; if( BClk_Okay = '0' )then RX_FSM_State <= WAIT_FOR_FLAG; end if; end if; end process; end architecture;