URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
[/] [open8_urisc/] [trunk/] [VHDL/] [o8_vector_rx.vhd] - Rev 308
Go to most recent revision | Compare with Previous | Blame | View Log
-- Copyright (c)2021 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 Entity: o8_vector_rx -- Description: Receives a 6-bit vector command and 16-bit argument from the -- vector_tx entity. Issues interrupt to the CPU on receipt of -- three bytes. -- -- Register Map: -- Offset Bitfield Description Read/Write -- 0x0 --AAAAAA Vector Select -- 0x1 AAAAAAAA Vector Argument LB -- 0x2 AAAAAAAA Vector Argument UB -- -- Revision History -- Author Date Change ------------------ -------- --------------------------------------------------- -- Seth Henry 04/15/20 Created from o8_epoch_timer due to requirement -- change. -- Seth Henry 04/16/20 Modified to make use of Open8 bus record -- Seth Henry 05/06/20 Modified to eliminate request line and detect idle -- conditions instead -- Seth Henry 05/23/20 Added the parallel interface -- Seth Henry 04/07/21 Added checksum to prevent glitching on serial noise -- Seth Henry 09/15/21 Removed parallel interface and increased checksum -- to 16-bits. Also made the magic number a generic. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use ieee.std_logic_misc.all; library work; use work.Open8_pkg.all; entity o8_vector_rx is generic( Magic_Num : DATA_TYPE; Bit_Rate : real; Enable_Parity : boolean; Parity_Odd_Even_n : std_logic; Clock_Frequency : real; Address : ADDRESS_TYPE ); port( Open8_Bus : in OPEN8_BUS_TYPE; Rd_Data : out DATA_TYPE; Interrupt : out std_logic; -- Serial Interface Rx_In : in std_logic; RX_FC : out std_logic ); end entity; architecture behave of o8_vector_rx is alias Clock is Open8_Bus.Clock; alias Reset is Open8_Bus.Reset; constant User_Addr : std_logic_vector(15 downto 2) := Address(15 downto 2); alias Comp_Addr is Open8_Bus.Address(15 downto 2); signal Addr_Match : std_logic := '0'; alias Reg_Sel_d is Open8_Bus.Address(1 downto 0); signal Reg_Sel_q : std_logic_vector(1 downto 0) := "00"; signal Wr_En_d : std_logic := '0'; signal Wr_En_q : std_logic := '0'; signal Rd_En_d : std_logic := '0'; signal Rd_En_q : std_logic := '0'; constant BAUD_RATE_DIV : integer := integer(Clock_Frequency / Bit_Rate); -- Period of each bit in sub-clocks (subtract one to account for zero) constant Full_Per_i : integer := BAUD_RATE_DIV - 1; constant Baud_Bits : integer := ceil_log2(Full_Per_i); constant FULL_PERIOD : std_logic_vector(Baud_Bits - 1 downto 0) := conv_std_logic_vector(Full_Per_i, Baud_Bits); signal Rx_Baud_Cntr : std_logic_vector(Baud_Bits - 1 downto 0) := (others => '0'); signal Rx_Baud_Tick : std_logic := '0'; signal Vec_Rx_SR : std_logic_vector(2 downto 0) := "000"; alias Vec_Rx_MS is Vec_Rx_SR(2); signal Rx_Idle_Cntr : std_logic_vector(3 downto 0) := "0000"; signal Rx_Idle : std_logic := '0'; signal Rx_Data : DATA_TYPE := x"00"; signal Rx_Valid : std_logic; type VECTOR_RX_STATES is ( CHECKSUM_INIT, GET_VECTOR_CMD, GET_VECTOR_ARG_LB, GET_VECTOR_ARG_UB, GET_VECTOR_SUM_LB, GET_VECTOR_SUM_UB, SEND_INTERRUPT ); signal Vector_State : VECTOR_RX_STATES := GET_VECTOR_CMD; signal Vec_Req_SR : std_logic_vector(2 downto 0) := "000"; alias Vec_Req_MS is Vec_Req_SR(2); signal Vector_Index : DATA_TYPE := x"00"; signal Vector_Data : ADDRESS_TYPE := x"0000"; alias Vector_Data_LB is Vector_Data(7 downto 0); alias Vector_Data_UB is Vector_Data(15 downto 8); signal Vector_RX_Sum : ADDRESS_TYPE := x"0000"; alias Vector_RX_Sum_LB is Vector_RX_Sum(7 downto 0); alias Vector_RX_Sum_UB is Vector_RX_Sum(15 downto 8); signal Checksum : ADDRESS_TYPE := x"0000"; signal Interrupt_Req : std_logic := '0'; signal Interrupt_Pending : std_logic := '0'; begin Addr_Match <= '1' when Comp_Addr = User_Addr else '0'; Wr_En_d <= Addr_Match and Open8_Bus.Wr_En; Rd_En_d <= Addr_Match and Open8_Bus.Rd_En; io_reg: process( Clock, Reset ) begin if( Reset = Reset_Level )then Reg_Sel_q <= (others => '0'); Wr_En_q <= '0'; Rd_En_q <= '0'; Rd_Data <= OPEN8_NULLBUS; Interrupt <= '0'; Interrupt_Pending <= '0'; elsif( rising_edge( Clock ) )then Reg_Sel_q <= Reg_Sel_d; Wr_En_q <= Wr_En_d; Rd_Data <= OPEN8_NULLBUS; Rd_En_q <= Rd_En_d; if( Rd_En_q = '1' )then case( Reg_Sel_q )is when "00" => Rd_Data <= Vector_Index; when "01" => Rd_Data <= Vector_Data_LB; when "10" => Rd_Data <= Vector_Data_UB; when "11" => Rd_Data <= Interrupt_Pending & "0000000"; when others => null; end case; end if; Interrupt <= Interrupt_Req; if( Interrupt_Req = '1' )then Interrupt_Pending <= '1'; elsif( Wr_En_q = '1' )then Interrupt_Pending <= '0'; end if; RX_FC <= not Interrupt_Pending; end if; end process; RX_Idle_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then Rx_Baud_Cntr <= (others => '0'); Rx_Baud_Tick <= '0'; Vec_Rx_SR <= (others => '1'); Rx_Idle_Cntr <= (others => '0'); Rx_Idle <= '0'; elsif( rising_edge(Clock) )then Rx_Baud_Cntr <= Rx_Baud_Cntr - 1; Rx_Baud_Tick <= '0'; if( Rx_Baud_Cntr = 0 )then Rx_Baud_Cntr <= FULL_PERIOD; Rx_Baud_Tick <= '1'; end if; Vec_Rx_SR <= Vec_Rx_SR(1 downto 0) & Rx_In; Rx_Idle_Cntr <= Rx_Idle_Cntr - Rx_Baud_Tick; if( Vec_Rx_MS = '0' )then Rx_Idle_Cntr <= (others => '1'); elsif( Rx_Idle_Cntr = 0 )then Rx_Idle_Cntr <= (others => '0'); end if; Rx_Idle <= nor_reduce(Rx_Idle_Cntr); end if; end process; U_RX : entity work.async_ser_rx generic map( Reset_Level => Reset_Level, Enable_Parity => Enable_Parity, Parity_Odd_Even_n => Parity_Odd_Even_n, Clock_Divider => BAUD_RATE_DIV ) port map( Clock => Clock, Reset => Reset, -- RX_In => Rx_In, -- Rx_Data => RX_Data, Rx_Valid => RX_Valid, Rx_PErr => open ); Vector_RX_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then Vec_Req_SR <= (others => '0'); Vector_State <= CHECKSUM_INIT; Vector_Index <= x"00"; Vector_Data <= x"0000"; Checksum <= x"0000"; Interrupt_Req <= '0'; elsif( rising_edge(Clock) )then Interrupt_Req <= '0'; case( Vector_State )is when CHECKSUM_INIT => Checksum <= x"00" & Magic_Num; Vector_State <= GET_VECTOR_CMD; when GET_VECTOR_CMD => if( Rx_Valid = '1' )then Checksum <= Checksum + (x"00" & Rx_Data); Vector_Index <= Rx_Data; Vector_State <= GET_VECTOR_ARG_LB; end if; when GET_VECTOR_ARG_LB => if( Rx_Valid = '1' )then Checksum <= Checksum + (x"00" & Rx_Data); Vector_Data_LB <= Rx_Data; Vector_State <= GET_VECTOR_ARG_UB; end if; when GET_VECTOR_ARG_UB => if( Rx_Valid = '1' )then Checksum <= Checksum + (x"00" & Rx_Data); Vector_Data_UB <= Rx_Data; Vector_State <= GET_VECTOR_SUM_LB; end if; when GET_VECTOR_SUM_LB => if( Rx_Valid = '1' )then Vector_RX_Sum_LB <= Rx_Data; Vector_State <= GET_VECTOR_SUM_UB; end if; when GET_VECTOR_SUM_UB => if( Rx_Valid = '1' )then Vector_RX_Sum_UB <= Rx_Data; Vector_State <= SEND_INTERRUPT; end if; when SEND_INTERRUPT => if( Checksum = Vector_RX_Sum )then Interrupt_Req <= '1'; end if; Vector_State <= CHECKSUM_INIT; when others => null; end case; if( Rx_Idle = '1' or Interrupt_Pending = '1' )then Vector_State <= CHECKSUM_INIT; end if; end if; end process; end architecture;
Go to most recent revision | Compare with Previous | Blame | View Log