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

Subversion Repositories open8_urisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /open8_urisc/trunk/VHDL
    from Rev 191 to Rev 192
    Reverse comparison

Rev 191 → Rev 192

/o8_sdlc_if.vhd
0,0 → 1,324
-- 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.
--
-- 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_1110" (0x1FE) RX Buffer END
-- "1_1111_1111" (0x1FF) RX Length / Status
--
-- * Address 0xFE reports the SDLC bit clock status and updates on changes. If
-- the bit clock goes away (BClk_Okay = '0'), the field will report 0x00.
-- otherwise it will report 0xFF. Note that the CPU can overwrite this
-- location, at which point the status will be invalid.
--
-- ** This location serves as the control/status register for the interface
-- 1) Writing 0x00 will reset the clock status flag in 0xFE without
-- triggering an interrupt.
-- 2) Writing a value between 1 and 253 will trigger the transmit engine,
-- using the write value as the packet length.
-- 3) Writing 0xFE or 0xFF will be ignored by the engine.
-- 4) This value will change from the user written value to 0xFF once the
-- packet is transmitted.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
 
library work;
use work.open8_pkg.all;
 
library work;
use work.sdlc_serial_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_Freq : real := 500000.0;
Sys_Freq : real := 100000000.0;
Reset_Level : std_logic := '1';
Address : ADDRESS_TYPE
);
port(
Clock : in std_logic;
Reset : in std_logic;
--
Bus_Address : in ADDRESS_TYPE;
Wr_Enable : in std_logic;
Wr_Data : in DATA_TYPE;
Rd_Enable : in std_logic;
Rd_Data : out DATA_TYPE;
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
 
-- Connect the CPU to the dual-port memory
constant Base_Addr : std_logic_vector(15 downto 9)
:= Address(15 downto 9);
 
alias RAM_Upper_Addr is Bus_Address(15 downto 9);
alias RAM_Lower_Addr is Bus_Address(8 downto 0);
 
signal RAM_Addr_Match : std_logic := '0';
signal RAM_Wr_En : std_logic := '0';
signal RAM_Rd_En : std_logic := '0';
signal Rd_Data_i : DATA_TYPE := OPEN8_NULLBUS;
 
constant Reg_Sub_Addr : std_logic_vector(8 downto 0) :=
conv_std_logic_vector(255,9);
 
signal Reg_Addr : std_logic_vector(8 downto 0) := (others => '0');
signal Reg_Wr_En : std_logic := '0';
signal Reg_Updated : std_logic := '0';
-- Connect the serial engine to the dual-port memory
signal DP_Addr : std_logic_vector(8 downto 0) := (others => '0');
signal DP_Wr_Data : DATA_IN_TYPE := x"00";
signal DP_Wr_En : std_logic := '0';
signal DP_Rd_Data : DATA_IN_TYPE := x"00";
 
signal BClk_RE : std_logic := '0';
signal BClk_FE : std_logic := '0';
 
signal TX_Wr_En : std_logic := '0';
signal TX_Wr_Flag : std_logic := '0';
signal TX_Wr_Data : DATA_IN_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_OUT_TYPE := x"0000";
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_CRC_Valid : std_logic := '0';
 
signal RX_Valid : std_logic := '0';
signal RX_Flag : std_logic := '0';
signal RX_Data : DATA_IN_TYPE := x"00";
signal RX_Idle : std_logic := '0';
 
signal RX_CRC_Clr : std_logic := '0';
signal RX_CRC_En : std_logic := '0';
signal RX_CRC_Data : CRC_OUT_TYPE := x"0000";
signal RX_CRC_Valid : std_logic := '0';
 
signal BClk_Okay : std_logic := '0';
 
begin
 
-- This decode needs to happen immediately, to give the RAM a chance to
-- do the lookup before we have to set Rd_Data
RAM_Addr_Match <= '1' when Base_Addr = RAM_Upper_Addr else '0';
RAM_Wr_En <= RAM_Addr_Match and Wr_Enable;
 
CPU_RAM_proc: process( Reset, Clock )
begin
if( Reset = Reset_Level )then
Reg_Addr <= (others => '0');
Reg_Wr_En <= '0';
Reg_Updated <= '0';
RAM_Rd_En <= '0';
Rd_Data <= OPEN8_NULLBUS;
elsif( rising_edge(Clock) )then
Reg_Addr <= RAM_Lower_Addr;
Reg_Wr_En <= RAM_Addr_Match and Wr_Enable;
 
Reg_Updated <= '0';
if( Reg_Addr = Reg_Sub_Addr )then
Reg_Updated <= Reg_Wr_En;
end if;
 
RAM_Rd_En <= RAM_Addr_Match and Rd_Enable;
Rd_Data <= OPEN8_NULLBUS;
if( RAM_Rd_En = '1' )then
Rd_Data <= Rd_Data_i;
end if;
end if;
end process;
 
U_RAM : entity work.ram_dp512b_core
port map(
clock => Clock,
address_a => RAM_Lower_Addr,
address_b => DP_Addr,
data_a => Wr_Data,
data_b => DP_Wr_Data,
wren_a => RAM_Wr_En,
wren_b => DP_Wr_En,
q_a => Rd_Data_i,
q_b => DP_Rd_Data
);
 
U_BCLK : entity work.sdlc_serial_clk
generic map(
Set_As_Master => Set_As_Master,
BitClock_Freq => BitClock_Freq,
Reset_Level => Reset_Level,
Sys_Freq => Sys_Freq
)
port map(
Clock => Clock,
Reset => Reset,
--
BClk_In => SDLC_SClk,
BClk_Out => SDLC_MClk,
BClk_FE => BClk_FE,
BClk_RE => BClk_RE,
BClk_Okay => BClk_Okay
);
 
U_CTRL : entity work.sdlc_serial_ctrl
generic map(
Reset_Level => Reset_Level
)
port map(
Clock => Clock,
Reset => Reset,
--
BClk_Okay => BClk_Okay,
--
Reg_Updated => Reg_Updated,
--
DP_Addr => DP_Addr,
DP_Wr_Data => DP_Wr_Data,
DP_Wr_En => DP_Wr_En,
DP_Rd_Data => DP_Rd_Data,
--
TX_Wr_En => TX_Wr_En,
TX_Wr_Flag => TX_Wr_Flag,
TX_Wr_Data => TX_Wr_Data,
TX_Req_Next => TX_Req_Next,
--
TX_CRC_Clr => TX_CRC_Clr,
TX_CRC_En => TX_CRC_En,
TX_CRC_Data => TX_CRC_Data,
TX_CRC_Valid => TX_CRC_Valid,
--
RX_Valid => RX_Valid,
RX_Flag => RX_Flag,
RX_Data => RX_Data,
RX_Idle => RX_Idle,
--
RX_CRC_Clr => RX_CRC_Clr,
RX_CRC_En => RX_CRC_En,
RX_CRC_Data => RX_CRC_Data,
RX_CRC_Valid => RX_CRC_Valid,
--
Interrupt => Interrupt
);
 
U_TX_SER : entity work.sdlc_serial_tx
generic map(
Reset_Level => Reset_Level
)
port map(
Clock => Clock,
Reset => Reset,
--
BClk_FE => BClk_FE,
BClk_RE => BClk_RE,
BClk_Okay => BClk_Okay,
--
TX_En => TX_Wr_En,
TX_FSS_Flag => TX_Wr_Flag,
TX_Data => TX_Wr_Data,
TX_Req_Next => TX_Req_Next,
--
Serial_Out => SDLC_Out
);
 
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_Data => TX_Wr_Data,
Wr_En => TX_CRC_En,
--
CRC16_Out => TX_CRC_Data,
CRC16_Valid => TX_CRC_Valid
);
 
U_RX_SER : entity work.sdlc_serial_rx
generic map(
Set_As_Master => Set_As_Master,
Clock_Offset => Clock_Offset,
Reset_Level => Reset_Level
)
port map(
Clock => Clock,
Reset => Reset,
--
BClk_RE => BClk_RE,
BClk_Okay => BClk_Okay,
--
Serial_In => SDLC_In,
--
RX_Valid => RX_Valid,
RX_Flag => RX_Flag,
RX_Data => RX_Data,
RX_Idle => RX_Idle
);
 
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_CRC_Clr,
Wr_Data => RX_Data,
Wr_En => RX_CRC_En,
--
CRC16_Out => RX_CRC_Data,
CRC16_Valid => RX_CRC_Valid
);
 
end architecture;
/sdlc_serial_clk.vhd
0,0 → 1,185
-- 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 : sdlc_serial_clk
-- Description:
-- Implements the serial clock output as well as rising/falling edge pulses
-- for use by the serial transmitter and receiver. Accepts the synchronous
-- serial bit rate as a real (BitClock_Freq). Note that the clock is free-
-- running rather than gated.
--
 
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.sdlc_serial_pkg.all;
 
entity sdlc_serial_clk is
generic(
Set_As_Master : boolean := true;
BitClock_Freq : real := 500000.0;
Reset_Level : std_logic;
Sys_Freq : real := 50000000.0
);
port(
Clock : in std_logic;
Reset : in std_logic;
BClk_In : in std_logic := '0';
BClk_Out : out std_logic;
BClk_FE : out std_logic;
BClk_RE : out std_logic;
BClk_Okay : out std_logic
);
end entity;
 
architecture behave of sdlc_serial_clk is
 
constant DLY_VAL : integer := integer(Sys_Freq / (2.0 * BitClock_Freq) );
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);
 
 
signal BClk_SR : std_logic_vector(2 downto 0) := (others => '0');
 
constant CLK_RATIO_R : real := Sys_Freq / (1.0 * BitClock_Freq);
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';
 
begin
 
Clock_Master: if( Set_As_Master )generate
 
SDLC_Clk_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_Out <= '0';
BClk_RE <= '0';
BClk_FE <= '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_Out <= BClk_Div;
BClk_RE <= (not BClk_Div) and BClk_Adv;
BClk_FE <= BClk_Div and BClk_Adv;
end if;
end process;
 
BClk_Okay <= BClk_Okay_SR(3);
 
end generate;
 
Clock_Slave: if( not Set_As_Master )generate
 
SDLC_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) & BClk_In;
BClk_FE <= BClk_SR(2) and (not BClk_SR(1));
BClk_RE <= (not BClk_SR(2)) and BClk_SR(1);
end if;
end process;
 
BClk_Out <= '0';
 
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) & BClk_In;
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;
 
end architecture;
/sdlc_serial_ctrl.vhd
0,0 → 1,598
-- 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 : sdlc_serial_ctrl
-- Description: Handles the high-level control of the SDLC engine by
-- providing arbitrated access to the internal side of the dual
-- port memory, perodically checking for new messages, adding/
-- checking CRC sums, and interrupting the processor when new
-- packets are received.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
 
library work;
use work.sdlc_serial_pkg.all;
 
entity sdlc_serial_ctrl is
generic(
Reset_Level : std_logic := '1'
);
port(
Clock : in std_logic;
Reset : in std_logic;
--
BClk_Okay : in std_logic;
--
Reg_Updated : in std_logic;
--
DP_Addr : out std_logic_vector(8 downto 0);
DP_Wr_Data : out DATA_IN_TYPE;
DP_Wr_En : out std_logic;
DP_Rd_Data : in DATA_IN_TYPE;
--
TX_Wr_En : out std_logic;
TX_Wr_Flag : out std_logic;
TX_Wr_Data : out DATA_IN_TYPE;
TX_Req_Next : in std_logic;
--
TX_CRC_Clr : out std_logic;
TX_CRC_En : out std_logic;
TX_CRC_Data : in CRC_OUT_TYPE;
TX_CRC_Valid : in std_logic;
--
RX_Valid : in std_logic;
RX_Flag : in std_logic;
RX_Data : in DATA_IN_TYPE;
RX_Idle : in std_logic;
 
RX_CRC_Clr : out std_logic;
RX_CRC_En : out std_logic;
RX_CRC_Data : in CRC_OUT_TYPE;
RX_CRC_Valid : in std_logic;
--
Interrupt : out std_logic
);
end entity;
 
architecture behave of sdlc_serial_ctrl is
 
signal RAM_Updated : std_logic;
 
-- RAM Arbitration logic
type DP_ARB_STATES is (IDLE,
PORT0_AD, PORT0_WR, PORT0_RD0, PORT0_RD1, PORT0_RD2,
PORT1_AD, PORT1_WR, PORT1_RD0, PORT1_RD1, PORT1_RD2 );
signal DP_Arb_State : DP_ARB_STATES := IDLE;
signal DP_Last_Port : std_logic := '0';
 
signal DP_Port0_Addr : DATA_IN_TYPE := x"00";
signal DP_Port0_RWn : std_logic := '0';
signal DP_Port0_WrData : DATA_IN_TYPE := x"00";
signal DP_Port0_RdData : DATA_IN_TYPE := x"00";
signal DP_Port0_Req : std_logic := '0';
signal DP_Port0_Ack : std_logic := '0';
 
signal DP_Port1_Addr : DATA_IN_TYPE := x"00";
signal DP_Port1_RWn : std_logic := '0';
signal DP_Port1_WrData : DATA_IN_TYPE := x"00";
signal DP_Port1_RdData : DATA_IN_TYPE := x"00";
signal DP_Port1_Req : std_logic := '0';
signal DP_Port1_Ack : std_logic := '0';
 
type TX_FSM_STATES is ( WR_CLOCK_STATE, WAIT_FOR_CLOCK, 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_CRC_LB_WAIT,
TX_CRC_UB_WR, TX_CRC_UB_WAIT,
TX_STOP_FLAG, TX_WAIT_STOP_FLAG, TX_DONE,
SET_FLAG );
 
signal TX_State : TX_FSM_STATES := WR_CLOCK_STATE;
signal TX_Length : DATA_IN_TYPE := x"00";
 
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 BClk_q1, BClk_CoS : std_logic := '0';
signal TX_Int_pend : std_logic := '0';
signal TX_Interrupt : std_logic := '0';
 
-- Packet Detection
type PACKET_STATES is (IDLE, FRAME_START, FRAME_DATA, FRAME_END, FRAME_ABORT);
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_IN_TYPE := x"00";
 
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, CHK_CRC,
RX_WR_COUNT, RX_TERM );
 
signal RX_State : RX_FSM_STATES := WAIT_FOR_CLOCK;
 
signal RX_Length : DATA_IN_TYPE := x"00";
 
type CRC_HISTORY is array(0 to 2) of CRC_OUT_TYPE;
signal RX_CRC_Hist : CRC_HISTORY;
alias RX_CRC_Calc is RX_CRC_Hist(2);
 
signal RX_CRC_Rcvd : CRC_OUT_TYPE;
alias RX_CRC_Rcvd_LB is RX_CRC_Rcvd(7 downto 0);
alias RX_CRC_Rcvd_UB is RX_CRC_Rcvd(15 downto 8);
 
signal RX_Interrupt : std_logic;
 
begin
 
RAM_Arb_proc: process( Clock, Reset )
begin
if( Reset = Reset_Level )then
DP_Arb_State <= IDLE;
DP_Last_Port <= '0';
DP_Addr <= (others => '0');
DP_Wr_Data <= x"00";
DP_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';
 
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_Addr <= '0' & DP_Port0_Addr;
DP_Wr_Data <= DP_Port0_WrData;
DP_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_Arb_State <= PORT0_RD2;
 
when PORT0_RD2 =>
DP_Port0_Ack <= '1';
DP_Port0_RdData <= DP_Rd_Data;
DP_Arb_State <= IDLE;
 
when PORT1_AD =>
DP_Last_Port <= '1';
DP_Addr <= '1' & DP_Port1_Addr;
DP_Wr_Data <= DP_Port1_WrData;
DP_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_Arb_State <= PORT1_RD2;
 
when PORT1_RD2 =>
DP_Port1_Ack <= '1';
DP_Port1_RdData <= DP_Rd_Data;
DP_Arb_State <= IDLE;
 
when others => null;
 
end case;
end if;
end process;
 
TX_Ctrl_proc: process( Reset, Clock )
begin
if( Reset = Reset_Level )then
TX_State <= WR_CLOCK_STATE;
 
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_State )is
 
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_State <= WAIT_FOR_CLOCK;
end if;
 
when WAIT_FOR_CLOCK =>
if( BClk_Okay = '1' )then
TX_State <= WAIT_FOR_UPDATE;
end if;
 
when WAIT_FOR_UPDATE =>
if( Reg_Updated = '1' )then
TX_State <= RD_TX_REGISTER;
end if;
 
when RD_TX_REGISTER =>
DP_Port0_Addr <= CR_REGISTER;
DP_Port0_Req <= '1';
if( DP_Port0_Ack = '1' )then
DP_Port0_Req <= '0';
TX_Length <= DP_Port0_RdData;
TX_State <= TX_INIT;
end if;
 
when TX_INIT =>
TX_State <= WR_CLOCK_STATE;
if( TX_Length > TX_RESERVED_LOW and
TX_Length < TX_RESERVED_HIGH )then
TX_CRC_Clr <= '1';
TX_State <= TX_START_FLAG;
end if;
 
when TX_START_FLAG =>
TX_Wr_En <= '1';
TX_Wr_Flag <= '1';
TX_Wr_Data <= SDLC_FLAG;
TX_State <= TX_WAIT_START_FLAG;
 
when TX_WAIT_START_FLAG =>
if( TX_Req_Next = '1' )then
DP_Port0_Addr <= x"00";
TX_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_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_State <= TX_WAIT_MESG_DATA;
 
when TX_WAIT_MESG_DATA =>
if( TX_Req_Next = '1' )then
TX_State <= TX_ADV_ADDR;
if( TX_Length = 0 )then
TX_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_State <= TX_CRC_LB_WAIT;
 
when TX_CRC_LB_WAIT =>
if( TX_Req_Next = '1' )then
TX_State <= TX_CRC_UB_WR;
end if;
 
when TX_CRC_UB_WR =>
TX_Wr_En <= '1';
TX_Wr_Data <= TX_CRC_Data_UB;
TX_State <= TX_CRC_UB_WAIT;
 
when TX_CRC_UB_WAIT =>
if( TX_Req_Next = '1' )then
TX_State <= TX_STOP_FLAG;
end if;
 
when TX_STOP_FLAG =>
TX_Wr_En <= '1';
TX_Wr_Flag <= '1';
TX_Wr_Data <= SDLC_FLAG;
TX_State <= TX_WAIT_STOP_FLAG;
 
when TX_WAIT_STOP_FLAG =>
if( TX_Req_Next = '1' )then
TX_State <= TX_DONE;
end if;
 
when TX_DONE =>
DP_Port0_Addr <= CR_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_State <= RD_TX_REGISTER;
end if;
 
when others => null;
end case;
 
if( BClk_CoS = '1' )then
TX_Int_pend <= '1';
TX_State <= WR_CLOCK_STATE;
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_END;
end if;
 
when FRAME_END =>
RX_Frame_Stop <= '1';
Pkt_State <= IDLE;
 
when others => null;
end case;
 
if( RX_Idle = '1' and Pkt_State /= IDLE )then
Pkt_State <= FRAME_END;
end if;
 
end if;
end process;
 
RX_Ctrl_proc: process( Reset, Clock )
begin
if( Reset = Reset_Level )then
RX_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_CRC_Clr <= '0';
RX_CRC_En <= '0';
 
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_CRC_Clr <= '0';
RX_CRC_En <= '0';
 
 
RX_Interrupt <= '0';
 
case( RX_State )is
 
when WAIT_FOR_CLOCK =>
RX_State <= WAIT_FOR_FLAG;
 
when WAIT_FOR_FLAG =>
if( RX_Frame_Start = '1' )then
RX_Length <= x"00";
RX_CRC_Clr <= '1';
RX_State <= RX_MESG_DATA;
end if;
 
when RX_MESG_DATA =>
if( RX_Frame_Stop = '1' )then
RX_State <= RX_CRC_UB_RD;
elsif( RX_Frame_Valid = '1' )then
RX_State <= RX_WR_DATA;
if( RX_Length > 254 )then
RX_Length <= ERR_LENGTH;
RX_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_CRC_En <= '1';
RX_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_State <= RX_CRC_LB_RD;
end if;
 
when RX_CRC_LB_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_LB <= DP_Port1_RdData;
RX_State <= RX_WR_COUNT;
end if;
 
when CHK_CRC =>
RX_State <= RX_WR_COUNT;
if( RX_CRC_Rcvd /= RX_CRC_Calc )then
RX_Length <= ERR_CHECKSUM;
end if;
 
when RX_WR_COUNT =>
DP_Port1_Addr <= CR_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_State <= WAIT_FOR_FLAG;
end if;
 
when others => null;
end case;
 
if( BClk_Okay = '0' )then
RX_State <= WAIT_FOR_FLAG;
end if;
 
end if;
end process;
 
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;
 
Interrupt_merge_proc: process( Clock, Reset )
begin
if( Reset = Reset_Level )then
Interrupt <= '0';
elsif( rising_edge(Clock) )then
Interrupt <= RX_Interrupt or TX_Interrupt;
end if;
end process;
 
end architecture;
/sdlc_serial_pkg.vhd
0,0 → 1,65
-- 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.
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
package sdlc_serial_pkg is
 
subtype DATA_IN_TYPE is std_logic_vector(7 downto 0);
subtype CRC_OUT_TYPE is std_logic_vector(15 downto 0);
 
constant SDLC_Flag : DATA_IN_TYPE := x"7E";
 
function ceil_log2 (x : in natural) return natural;
 
-- Internal definitions
constant CK_REGISTER : DATA_IN_TYPE := x"FE";
constant CR_REGISTER : DATA_IN_TYPE := x"FF";
 
constant TX_RESERVED_LOW : integer := 0;
constant TX_RESERVED_HIGH : integer := 254;
 
constant FLAG_DONE : DATA_IN_TYPE := x"FF";
 
constant ERR_LENGTH : DATA_IN_TYPE := x"00";
constant ERR_CHECKSUM : DATA_IN_TYPE := x"FF";
 
end package;
 
package body sdlc_serial_pkg is
 
-- The ceil_log2 function returns the minimum register width required to
-- hold the supplied integer.
function ceil_log2 (x : in natural) return natural is
variable retval : natural;
begin
retval := 1;
while ((2**retval) - 1) < x loop
retval := retval + 1;
end loop;
return retval;
end ceil_log2;
 
end package body;
/sdlc_serial_rx.vhd
0,0 → 1,248
-- 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 : sdlc_serial_rx
-- Description:
-- Implements a SDLC compliant serial receiver based on the SDLC
-- requirements in the ITU X.25 physical layer specification.
--
-- This entity will receive synchronously applied SDLC formatted serial data,
-- automatically rejecting bit-stuffed zeros and checking/detecting frame
-- start/stop flags automatically.
--
-- Also, the receiver will automatically idle itself between frames in the
-- event the frame state is lost by detecting 16 or more consecutive '1's.
-- (This assumes the transmitter continuously drives the clock).
--
-- Further, a second shift register listens for the SDLC Flag (0x7E) and will
-- reset the bit counter in the event that a flag is detected "early",
-- implying that the bitcounter is out of alignment with the data. This
-- event shouldn't occur in normal reception and is present as a backup.
--
-- This entity requires the bitclock rising edge pulses from the serial clock
-- generator. Receive data and flag signals are generated to higher-level
-- logic shortly after the rising edge of the bitclock on the "clock" clock
-- domain.
--
 
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.sdlc_serial_pkg.all;
 
entity sdlc_serial_rx is
generic(
Set_As_Master : boolean := true;
Clock_Offset : integer := 6;
Reset_Level : std_logic := '1'
);
port(
Clock : in std_logic;
Reset : in std_logic;
-- Bitclock rising edges
BClk_RE : in std_logic;
BClk_Okay : in std_logic;
-- Bit stream in
Serial_In : in std_logic;
-- Parallel + Flag out
RX_Valid : out std_logic;
RX_Flag : out std_logic;
RX_Data : out DATA_IN_TYPE;
RX_Idle : out std_logic
);
end entity;
 
architecture behave of sdlc_serial_rx is
 
signal RX_LatchEn_SR : std_logic_vector(Clock_Offset downto 0) := (others => '0');
alias RX_LatchEn_M is RX_LatchEn_SR(Clock_Offset);
 
signal RX_LatchEn_S : std_logic;
signal RX_LatchEn : std_logic;
 
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_IN_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_IN_TYPE := x"00";
 
signal RX_Idle_Cntr : std_logic_vector(2 downto 0) := (others => '0');
 
begin
 
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) & Serial_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_LatchEn_S <= '0';
RX_Serial_SR <= (others => '0');
elsif( rising_edge(Clock) )then
RX_LatchEn_S <= BClk_RE;
RX_Serial_SR <= RX_Serial_SR(0) & Serial_In;
end if;
end process;
 
RX_LatchEn <= RX_LatchEn_S;
 
end generate;
 
 
RX_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
 
RX_Valid <= '0';
 
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_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;
RX_Flag <= '0';
if( RX_Buffer = 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;
 
end architecture;
/sdlc_serial_tx.vhd
0,0 → 1,179
-- 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 : sdlc_serial_tx
-- Description:
-- Implements a SDLC compliant serial transmitter based on the SDLC
-- requirements in the ITU X.25 physical layer specification. Entity will
-- insert a zero after every 5 consecutive '1's unless the TX_FSS_Flag is
-- held high while TX_En is driven high. This will allow the SDLC frame
-- flag, 0x7E, to be transmitted unmodified. (FSS = Frame Start/Stop)
--
-- This entity requires the Bitclock rising and falling edge pulses from the
-- bitclock generator. Transmit data is updated on the falling edge, while
-- signals to higher-level logic (TX_Req_Next) are generated on the rising
-- edge.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_misc.all;
 
library work;
use work.sdlc_serial_pkg.all;
 
entity sdlc_serial_tx is
generic(
Reset_Level : std_logic := '1'
);
port(
Clock : in std_logic;
Reset : in std_logic;
-- Bitclock rising/falling edges
BClk_FE : in std_logic;
BClk_RE : in std_logic;
BClk_Okay : in std_logic;
-- Write port from higher-level logic
TX_En : in std_logic;
TX_FSS_Flag : in std_logic;
TX_Data : in DATA_IN_TYPE;
TX_Req_Next : out std_logic;
-- Bit stream
Serial_Out : out std_logic
);
end entity;
 
architecture behave of sdlc_serial_tx is
 
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);
 
type TX_STATES is (INIT, IDLE, XMIT, SPACE, TERM, LD_NEXT);
signal TX_State : TX_STATES := INIT;
 
signal TX_ShftReg : std_logic_vector(7 downto 0) := (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);
 
begin
 
TX_Proc: process( Clock, Reset )
begin
if( Reset = Reset_Level )then
TX_State <= IDLE;
Serial_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_En = '1' and TX_Arm = '0')then
TX_Arm <= '1';
TX_Buffer_Flag <= TX_FSS_Flag;
TX_Buffer_Data <= TX_Data;
end if;
 
TX_Req_Next <= '0';
 
case( TX_State )is
when INIT =>
Serial_Out <= '1';
TX_State <= IDLE;
 
when IDLE =>
Serial_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 =>
Serial_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 =>
Serial_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;
 
end architecture;

powered by: WebSVN 2.1.0

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