📄 uart_simple_broken.vhd
字号:
--
-- uart_simple.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
--
-- A VERY simple uart without handshaking and fifos.
-- BUT THIS VERSION DOES NOT WORK!
--
-- 2005-01-14 adapted from uart.vhd
--
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
--
-- 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;
type uart_tdr_state_type is (s0, s1);
signal uart_tdr_state : uart_tdr_state_type;
signal tdr : std_logic_vector(7 downto 0); -- tx buffer
signal tdrf : std_logic; -- tdr has valid data
signal tdr_rd : std_logic; -- tdr was read
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;
type uart_rdr_state_type is (s0, s1);
signal uart_rdr_state : uart_rdr_state_type;
signal rdr : std_logic_vector(7 downto 0); -- rx buffer
signal rdre : std_logic; -- rdr is empty
signal rdr_wr : std_logic; -- rdr was written
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;
--
-- state machine for tdr
--
process(clk, reset)
begin
if (reset='1') then
uart_tdr_state <= s0;
tdrf <= '0';
tdr <= "00000000";
elsif rising_edge(clk) then
case uart_tdr_state is
when s0 =>
if (ua_wr='1') then
tdr <= din(7 downto 0);
tdrf <= '1';
uart_tdr_state <= s1;
end if;
when s1 =>
if (tdr_rd='1') then
tdrf <= '0';
uart_tdr_state <= s0;
end if;
end case;
end if;
end process;
tdre <= not tdrf;
--
-- 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";
tdr_rd <= '0';
elsif rising_edge(clk) then
case uart_tx_state is
when s0 =>
i := 0;
if tdrf='1' then
uart_tx_state <= s1;
tsr <= tdr & '0' & '1';
tdr_rd <= '1';
end if;
when s1 =>
tdr_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);
nrts <= ncts; -- no handshake
--
-- state machine for rdr
--
process(clk, reset)
begin
if (reset='1') then
uart_rdr_state <= s0;
rdre <= '1';
elsif rising_edge(clk) then
case uart_rdr_state is
when s0 =>
if (rdr_wr='1') then
rdre <= '0';
uart_rdr_state <= s1;
end if;
when s1 =>
if (ua_rd='1') then
rdre <= '1';
uart_rdr_state <= s0;
end if;
end case;
end if;
end process;
ua_dout <= rdr;
rdrf <= not rdre;
--
-- 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";
rdr_wr <= '0';
rx_clk_ena <= '0';
elsif rising_edge(clk) then
case uart_rx_state is
when s0 =>
i := 0;
rdr_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
rdr <= rsr(8 downto 1);
rdr_wr <= '1';
end if;
uart_rx_state <= s0;
end case;
end if;
end process;
end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -