📄 uart.vhd
字号:
--
-- uart.vhd
--
-- 8-N-1 serial interface
--
-- wr, rd should be one cycle long => trde, rdrf goes 0 one cycle later
--
-- Author: Martin Schoeberl martin@good-ear.com
--
--
-- resources on ACEX1K30-3
--
-- 100 LCs, max 90 MHz
--
-- resetting rts with fifo_full-1 works with C program on pc
-- but not with javax.comm: sends some more bytes after deassert
-- of rts (16 byte blocks regardless of rts).
-- Try to stop with half full fifo.
--
-- todo:
--
--
-- 2000-12-02 first working version
-- 2002-01-06 changed tdr and rdr to fifos.
-- 2002-05-15 changed clkdiv calculation
-- 2002-11-01 don't wait if read fifo is full, just drop the byte
-- 2002-11-03 use threshold in fifo to reset rts
-- don't send if cts is '0'
-- 2002-11-08 rx fifo to 20 characters and stop after 4
-- 2003-07-05 new IO standard, change cts/rts to neg logic
-- 2003-09-19 sync ncts in!
-- 2004-03-23 two stop bits
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity uart is
generic (io_addr : integer; clk_freq : integer;
baud_rate : integer;
txf_depth : integer; txf_thres : integer;
rxf_depth : integer; rxf_thres : integer);
port (
clk : in std_logic;
reset : in std_logic;
addr : in std_logic_vector(3 downto 0);
din : in std_logic_vector(31 downto 0);
wr : in std_logic;
dout : out std_logic_vector(31 downto 0);
rd : in std_logic;
txd : out std_logic;
rxd : in std_logic;
ncts : in std_logic;
nrts : out std_logic
);
end uart ;
architecture rtl of uart is
component fifo is
generic (width : integer; depth : integer; thres : integer);
port (
clk : in std_logic;
reset : in std_logic;
din : in std_logic_vector(width-1 downto 0);
dout : out std_logic_vector(width-1 downto 0);
rd : in std_logic;
wr : in std_logic;
empty : out std_logic;
full : out std_logic;
half : out std_logic
);
end component;
--
-- signals for uart connection
--
signal ua_dout : std_logic_vector(7 downto 0);
signal ua_wr, tdre : std_logic;
signal ua_rd, rdrf : std_logic;
type uart_tx_state_type is (s0, s1);
signal uart_tx_state : uart_tx_state_type;
signal tf_dout : std_logic_vector(7 downto 0); -- fifo out
signal tf_rd : std_logic;
signal tf_empty : std_logic;
signal tf_full : std_logic;
signal tf_half : std_logic;
signal ncts_buf : std_logic_vector(2 downto 0); -- sync in
signal tsr : std_logic_vector(9 downto 0); -- tx shift register
signal tx_clk : std_logic;
type uart_rx_state_type is (s0, s1, s2);
signal uart_rx_state : uart_rx_state_type;
signal rf_wr : std_logic;
signal rf_empty : std_logic;
signal rf_full : std_logic;
signal rf_half : std_logic;
signal rx_buf : std_logic_vector(2 downto 0); -- sync in, filter
signal rx_d : std_logic; -- rx serial data
signal rsr : std_logic_vector(9 downto 0); -- rx shift register
signal rx_clk : std_logic;
signal rx_clk_ena : std_logic;
constant clk16_cnt : integer := (clk_freq/baud_rate+8)/16-1;
begin
--
-- io handling
--
process(addr, rd, ua_dout, rdrf, tdre)
begin
ua_rd <= '0';
if addr=std_logic_vector(to_unsigned(io_addr, 4)) then
dout <= std_logic_vector(to_unsigned(0, 30)) & rdrf & tdre;
elsif addr=std_logic_vector(to_unsigned(io_addr+1, 4)) then
dout <= std_logic_vector(to_unsigned(0, 24)) & ua_dout;
ua_rd <= rd;
else
dout <= (others => 'Z');
end if;
end process;
process(wr, addr)
begin
ua_wr <= '0';
if addr=std_logic_vector(to_unsigned(io_addr+1, 4))
and wr='1' then
ua_wr <= '1';
end if;
end process;
--
-- serial clock
--
process(clk, reset)
variable clk16 : integer range 0 to clk16_cnt;
variable clktx : unsigned(3 downto 0);
variable clkrx : unsigned(3 downto 0);
begin
if (reset='1') then
clk16 := 0;
clktx := "0000";
clkrx := "0000";
tx_clk <= '0';
rx_clk <= '0';
rx_buf <= "111";
elsif rising_edge(clk) then
if (clk16=clk16_cnt) then -- 16 x serial clock
clk16 := 0;
--
-- tx clock
--
clktx := clktx + 1;
if (clktx="0000") then
tx_clk <= '1';
else
tx_clk <= '0';
end if;
--
-- rx clock
--
if (rx_clk_ena='1') then
clkrx := clkrx + 1;
if (clkrx="1000") then
rx_clk <= '1';
else
rx_clk <= '0';
end if;
else
clkrx := "0000";
end if;
--
-- sync in filter buffer
--
rx_buf(0) <= rxd;
rx_buf(2 downto 1) <= rx_buf(1 downto 0);
else
clk16 := clk16 + 1;
tx_clk <= '0';
rx_clk <= '0';
end if;
end if;
end process;
--
-- transmit fifo
--
cmp_tf: fifo generic map (8, txf_depth, txf_thres)
port map (clk, reset, din(7 downto 0), tf_dout, tf_rd, ua_wr, tf_empty, tf_full, tf_half);
--
-- state machine for actual shift out
--
process(clk, reset)
variable i : integer range 0 to 11;
begin
if (reset='1') then
uart_tx_state <= s0;
tsr <= "1111111111";
tf_rd <= '0';
ncts_buf <= "111";
elsif rising_edge(clk) then
ncts_buf(0) <= ncts;
ncts_buf(2 downto 1) <= ncts_buf(1 downto 0);
case uart_tx_state is
when s0 =>
i := 0;
if (tf_empty='0' and ncts_buf(2)='0') then
uart_tx_state <= s1;
tsr <= tf_dout & '0' & '1';
tf_rd <= '1';
end if;
when s1 =>
tf_rd <= '0';
if (tx_clk='1') then
tsr(9) <= '1';
tsr(8 downto 0) <= tsr(9 downto 1);
i := i+1;
if (i=11) then -- two stop bits
uart_tx_state <= s0;
end if;
end if;
end case;
end if;
end process;
txd <= tsr(0);
tdre <= not tf_full;
--
-- receive fifo
--
cmp_rf: fifo generic map (8, rxf_depth, rxf_thres)
port map (clk, reset, rsr(8 downto 1), ua_dout, ua_rd, rf_wr, rf_empty, rf_full, rf_half);
rdrf <= not rf_empty;
nrts <= rf_half; -- glitches even on empty fifo!
--
-- filter rxd
--
with rx_buf select
rx_d <= '0' when "000",
'0' when "001",
'0' when "010",
'1' when "011",
'0' when "100",
'1' when "101",
'1' when "110",
'1' when "111",
'X' when others;
--
-- state machine for actual shift in
--
process(clk, reset)
variable i : integer range 0 to 10;
begin
if (reset='1') then
uart_rx_state <= s0;
rsr <= "0000000000";
rf_wr <= '0';
rx_clk_ena <= '0';
elsif rising_edge(clk) then
case uart_rx_state is
when s0 =>
i := 0;
rf_wr <= '0';
if (rx_d='0') then
rx_clk_ena <= '1';
uart_rx_state <= s1;
else
rx_clk_ena <= '0';
end if;
when s1 =>
if (rx_clk='1') then
rsr(9) <= rx_d;
rsr(8 downto 0) <= rsr(9 downto 1);
i := i+1;
if (i=10) then
uart_rx_state <= s2;
end if;
end if;
when s2 =>
rx_clk_ena <= '0';
if rsr(0)='0' and rsr(9)='1' then
if rf_full='0' then -- if full just drop it
rf_wr <= '1';
end if;
end if;
uart_rx_state <= s0;
end case;
end if;
end process;
end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -