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