📄 uarts.vhd
字号:
-- ----------------------------------------------------
-- UART module
-- ----------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
-- ----------------------------------------------------
Entity UARTS is
-- ----------------------------------------------------
Port ( CLK : In std_logic;
RST : In std_logic;
Baud : In std_logic_vector (2 downto 0);
Rx : In std_logic;
LD : In std_logic;
Din : In std_logic_vector (7 downto 0);
Tx : Out std_logic;
TxBusy : Out std_logic;
RxRDY : Out std_logic;
RxErr : Out std_logic;
Dout : Out std_logic_vector (7 downto 0)
);
end UARTS;
Architecture RTL of UARTS is
type State_Rx_Type is (Idle, Start_Rx, Edge_Rx, Shift_Rx, Stop_Rx, RxOVF);
signal RxFSM : State_Rx_Type;
type State_Tx_Type is (Idle, Load_Tx, Shift_Tx, Stop_Tx);
signal TxFSM : State_Tx_Type;
signal parity : boolean;
signal Divisor : integer range 0 to 383;
signal Top16 : std_logic;
signal TopTx : std_logic;
signal TopRx : std_logic;
signal ClrDiv : std_logic;
signal RxRdyi : std_logic;
signal ClkDiv : unsigned (3 downto 0);
signal Div16 : integer range 0 to 383;
signal RxDiv : integer range 0 to 7;
signal TxBitCnt : integer range 0 to 15;
signal RxBitCnt : integer range 0 to 15;
constant NDBits : integer := 9;
signal RegDin : std_logic_vector (7 downto 0);
signal Tx_Reg : std_logic_vector (9 downto 0);
signal Rx_Reg : std_logic_vector (7 downto 0);
begin
-- --------------------------
-- Baud rate selection
-- --------------------------
process (RST, CLK)
begin
if RST='1' then
Divisor <= 0;
elsif rising_edge(CLK) then
case Baud is
when "000" => Divisor <= 0; -- 921.600
when "001" => Divisor <= 7; -- 115.200
when "010" => Divisor <= 15; -- 57.600
when "011" => Divisor <= 23; -- 38.400
when "100" => Divisor <= 47; -- 19.200
when "101" => Divisor <= 95; -- 9.600
when "110" => Divisor <= 191; -- 4.800
when "111" => Divisor <= 383; -- 2.400
when others => Divisor <= 0; -- n.u.
end case;
end if;
end process;
-- --------------------------
-- Clk16 Clock Generation
-- --------------------------
process (RST, CLK)
begin
if RST='1' then
Top16 <= '0';
Div16 <= 0;
elsif rising_edge(CLK) then
Top16 <= '0';
if Div16 = Divisor then
Div16 <= 0;
Top16 <= '1';
else
Div16 <= Div16 + 1;
end if;
end if;
end process;
-- --------------------------
-- Tx Clock Generation
-- --------------------------
process (RST, CLK)
begin
if RST='1' then
TopTx <= '0';
ClkDiv <= (others=>'0');
elsif rising_edge(CLK) then
TopTx <= '0';
if Top16='1' then
ClkDiv <= ClkDiv + 1;
if ClkDiv = 15 then
TopTx <= '1';
end if;
end if;
end if;
end process;
-- ------------------------------
-- Rx Sampling Clock Generation
-- ------------------------------
process (RST, CLK)
begin
if RST='1' then
TopRx <= '0';
RxDiv <= 0;
elsif rising_edge(CLK) then
TopRx <= '0';
if ClrDiv='1' then
RxDiv <= 0;
elsif Top16='1' then
if RxDiv = 7 then
RxDiv <= 0;
TopRx <= '1';
else
RxDiv <= RxDiv + 1;
end if;
end if;
end if;
end process;
-- --------------------------
-- Transmit State Machine
-- --------------------------
parity <= FALSE;
Tx <= Tx_Reg(0);
Tx_FSM: process (RST, CLK)
begin
if RST='1' then
Tx_Reg <= (others => '1');
TxBitCnt <= 0;
TxFSM <= Idle;
TxBusy <= '0';
RegDin <= (others=>'0');
elsif rising_edge(CLK) then
TxBusy <= '1'; -- except when explicitly '0'
case TxFSM is
when Idle =>
if LD='1' then
-- latch the input data immediately.
RegDin <= Din;
TxBusy <= '1';
TxFSM <= Load_Tx;
else
TxBusy <= '0';
end if;
when Load_Tx =>
if TopTx='1' then
TxFSM <= Shift_Tx;
if parity then
-- start + data + parity
TxBitCnt <= (NDBits + 2);
--Tx_Reg <= make_parity(RegDin,even) & Din & '0';
else
TxBitCnt <= (NDBits + 1); -- start + data
Tx_reg <= '1' & RegDin & '0';
end if;
end if;
when Shift_Tx =>
if TopTx='1' then
TxBitCnt <= TxBitCnt - 1;
Tx_reg <= '1' & Tx_reg (Tx_reg'high downto 1);
if TxBitCnt=1 then
TxFSM <= Stop_Tx;
end if;
end if;
when Stop_Tx =>
if TopTx='1' then
TxFSM <= Idle;
end if;
when others =>
TxFSM <= Idle;
end case;
end if;
end process;
-- ------------------------
-- RECEIVE State Machine
-- ------------------------
Rx_FSM: process (RST, CLK)
begin
if RST='1' then
Rx_Reg <= (others => '0');
Dout <= (others => '0');
RxBitCnt <= 0;
RxFSM <= Idle;
RxRdyi <= '0';
ClrDiv <= '0';
RxErr <= '0';
elsif rising_edge(CLK) then
ClrDiv <= '0'; -- default value
-- reset error when a word has been received Ok:
if RxRdyi='1' then
RxErr <= '0';
RxRdyi <= '0';
end if;
case RxFSM is
when Idle => -- wait on start bit
RxBitCnt <= 0;
if Top16='1' then
if Rx='0' then
RxFSM <= Start_Rx;
ClrDiv <='1'; -- Synchronize the divisor
end if; -- else false start, stay in Idle
end if;
when Start_Rx => -- wait on first data bit
if TopRx = '1' then
if Rx='1' then -- framing error
RxFSM <= RxOVF;
report "Start bit error." severity note;
else
RxFSM <= Edge_Rx;
end if;
end if;
when Edge_Rx => -- should be near Rx edge
if TopRx = '1' then
RxFSM <= Shift_Rx;
if RxBitCnt = NDbits then
RxFSM <= Stop_Rx;
else
RxFSM <= Shift_Rx;
end if;
end if;
when Shift_Rx => -- Sample data !
if TopRx = '1' then
RxBitCnt <= RxBitCnt + 1;
-- shift right :
Rx_Reg <= Rx & Rx_Reg (Rx_Reg'high downto 1);
RxFSM <= Edge_Rx;
end if;
when Stop_Rx => -- during Stop bit
if TopRx = '1' then
Dout <= Rx_reg;
RxRdyi <='1';
RxFSM <= Idle;
--assert (debug < 1)
--report "Character received in decimal is : " & integer'image(to_integer(unsigned(Rx_Reg)))
--severity note;
end if;
when RxOVF => -- Overflow / Error
RxErr <= '1';
if Rx='1' then
RxFSM <= Idle;
end if;
end case;
RxRDY <= RxRDYi;
end if;
end process;
end RTL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -