From 2ebabd4dbaa364e876a5edd9f393cb778829217c Mon Sep 17 00:00:00 2001 From: Vladimir Burian Date: Sat, 22 Jan 2011 22:53:46 +0100 Subject: [PATCH] First working prototype of HW UART - TX part. --- baud_gen.vhd | 49 ++++++++++++ fifo.vhd | 97 ++++++++++++++++++++++++ tb/Makefile | 30 ++++++++ tb/tb_baud_gen.vhd | 76 +++++++++++++++++++ tb/tb_fifo.vhd | 112 +++++++++++++++++++++++++++ tb/tb_tx.vhd | 93 +++++++++++++++++++++++ tb/tb_uart.vhd | 145 +++++++++++++++++++++++++++++++++++ tx.vhd | 65 ++++++++++++++++ tx_control.vhd | 83 ++++++++++++++++++++ uart.vhd | 184 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 934 insertions(+) create mode 100644 baud_gen.vhd create mode 100644 fifo.vhd create mode 100644 tb/Makefile create mode 100644 tb/tb_baud_gen.vhd create mode 100644 tb/tb_fifo.vhd create mode 100644 tb/tb_tx.vhd create mode 100644 tb/tb_uart.vhd create mode 100644 tx.vhd create mode 100644 tx_control.vhd create mode 100644 uart.vhd diff --git a/baud_gen.vhd b/baud_gen.vhd new file mode 100644 index 0000000..ebe6b38 --- /dev/null +++ b/baud_gen.vhd @@ -0,0 +1,49 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity baud_gen is + port ( + clk : in std_logic; + reset : in std_logic; + scale : in std_logic_vector (15 downto 0); + clk_baud : out std_logic + ); +end baud_gen; + +-------------------------------------------------------------------------------- + +architecture behavioral of baud_gen is + + signal counter : std_logic_vector (15 downto 0); + signal clk_baud_s : std_logic; + +-------------------------------------------------------------------------------- + +begin + + process (clk, reset) + begin + if (reset = '1') then + counter <= (others => '0'); + clk_baud_s <= '0'; + + elsif (rising_edge(clk)) then + if (counter = 0) then + counter <= scale; + clk_baud_s <= not clk_baud_s; + + else + counter <= counter - 1; + + end if; + end if; + end process; + +-------------------------------------------------------------------------------- + + clk_baud <= clk_baud_s; + +end behavioral; + diff --git a/fifo.vhd b/fifo.vhd new file mode 100644 index 0000000..99abce7 --- /dev/null +++ b/fifo.vhd @@ -0,0 +1,97 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity fifo is + generic ( + width : integer := 2 + ); + port ( + clk : in std_logic; + reset : in std_logic; + we : in std_logic; + re : in std_logic; + d_in : in std_logic_vector (7 downto 0); + d_out : out std_logic_vector (7 downto 0); + full : out std_logic; + hfull : out std_logic; + empty : out std_logic; + overflow : out std_logic + ); +end fifo; + +-------------------------------------------------------------------------------- + +architecture behavioral of fifo is + + subtype mem_addr_t is std_logic_vector (width-1 downto 0); + type mem_t is array (3 downto 0) of std_logic_vector (7 downto 0); + + signal memory : mem_t; + + signal read_addr : mem_addr_t; + signal write_addr : mem_addr_t; + + signal length : std_logic_vector (width downto 0); + + signal full_s : std_logic; + +-------------------------------------------------------------------------------- + +begin + + process (clk, reset) + begin + if (reset = '1') then + length <= (others => '0'); + overflow <= '0'; + + elsif (rising_edge(clk)) then + if ((re = '1') and (we = '0')) then + length <= length - 1; + elsif ((re = '0') and (we = '1')) then + if (full_s = '1') then + overflow <= '1'; + else + length <= length + 1; + end if; + end if; + end if; + end process; + + + process (clk, reset) + begin + if (reset = '1') then + read_addr <= (others => '0'); + write_addr <= (others => '0'); + + elsif (rising_edge(clk)) then + if (re = '1') then + read_addr <= read_addr + 1; + end if; + + if (we = '1') then + write_addr <= write_addr + 1; + memory (conv_integer(write_addr)) <= d_in; + + if (full_s = '1') then + read_addr <= read_addr + 1; + end if; + end if; + end if; + end process; + +-------------------------------------------------------------------------------- + + d_out <= memory (conv_integer(read_addr)); + + full_s <= '1' when (length >= 2**width) else '0'; + + full <= full_s; + hfull <= '1' when (length >= 2**(width-1)) else '0'; + empty <= '1' when (length = 0) else '0'; + +end behavioral; + diff --git a/tb/Makefile b/tb/Makefile new file mode 100644 index 0000000..351eb42 --- /dev/null +++ b/tb/Makefile @@ -0,0 +1,30 @@ +VHDL_MAIN = tb_uart +VHDL_ENTITIES = uart.o \ + tx.o \ + fifo.o \ + baud_gen.o \ + tx_control.o + +STOP_TIME = 50us + + +all: $(VHDL_MAIN) + +run: $(VHDL_MAIN) + ghdl -r $< --stop-time=$(STOP_TIME) --vcd=$<.vcd + +view: run + gtkwave $(VHDL_MAIN).vcd + +$(VHDL_MAIN): $(VHDL_MAIN).o $(VHDL_ENTITIES) + ghdl -e -fexplicit --ieee=synopsys $@ + +%.o: %.vhd + ghdl -a -fexplicit --ieee=synopsys $< + +%.o: ../%.vhd + ghdl -a -fexplicit --ieee=synopsys $< + +clean: + rm -Rf *.o *.vcd $(VHDL_MAIN) results.txt work-obj93.cf + diff --git a/tb/tb_baud_gen.vhd b/tb/tb_baud_gen.vhd new file mode 100644 index 0000000..7981c32 --- /dev/null +++ b/tb/tb_baud_gen.vhd @@ -0,0 +1,76 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity tb_baud_gen is +end tb_baud_gen; + + +architecture testbench of tb_baud_gen is + + component baud_gen is + port ( + clk : in std_logic; + reset : in std_logic; + scale : in std_logic_vector (15 downto 0); + clk_baud : out std_logic + ); + end component; + + signal clk : std_logic; + signal reset : std_logic; + + constant period : time := 2 us; + constant offset : time := 2 us; + + signal scale : std_logic_vector (15 downto 0); + signal clk_baud : std_logic; + +-------------------------------------------------------------------------------- + +begin + UUT : baud_gen port map ( + clk => clk, + reset => reset, + scale => scale, + clk_baud => clk_baud + ); + + process + begin + clk <= '0'; + wait for offset; + + loop + clk <= '1'; + wait for period/2; + clk <= '0'; + wait for period/2; + end loop; + end process; + + + process + begin + reset <= '0'; + wait for 1.2 * period; + reset <= '1'; + wait for 3 * period; + reset <= '0'; + wait; + end process; + + + process + begin + scale <= X"0000"; + + wait until reset = '0' and clk = '1'; + wait for 0.1 * period; + + wait; + end process; + +end testbench; + diff --git a/tb/tb_fifo.vhd b/tb/tb_fifo.vhd new file mode 100644 index 0000000..35f72de --- /dev/null +++ b/tb/tb_fifo.vhd @@ -0,0 +1,112 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity tb_fifo is +end tb_fifo; + + +architecture testbench of tb_fifo is + + component fifo is + generic ( + width : integer := 2 + ); + port ( + clk : in std_logic; + reset : in std_logic; + we : in std_logic; + re : in std_logic; + d_in : in std_logic_vector (7 downto 0); + d_out : out std_logic_vector (7 downto 0); + overflow : out std_logic + ); + end component; + + signal clk : std_logic; + signal reset : std_logic; + signal we : std_logic; + signal re : std_logic; + signal d_in : std_logic_vector (7 downto 0) := (others => '0'); + signal d_out : std_logic_vector (7 downto 0); + signal length : std_logic_vector (2 downto 0); + signal overflow : std_logic; + + constant period : time := 1 us; + constant offset : time := 2 us; + +begin + UUT : fifo port map ( + clk => clk, + reset => reset, + we => we, + re => re, + d_in => d_in, + d_out => d_out, + overflow => overflow + ); + + process + begin + clk <= '0'; + wait for offset; + + loop + clk <= '1'; + wait for period/2; + clk <= '0'; + wait for period/2; + end loop; + end process; + + + process + begin + reset <= '0'; + wait for period; + reset <= '1'; + wait for period; + reset <= '0'; + wait; + end process; + + + process + begin + we <= '0'; + re <= '0'; + d_in <= "00000000"; + + wait for 0.1 * period; + + wait for 2 * period; + d_in <= "01000001"; + we <= '1'; + + wait for period; + d_in <= "01000010"; + + wait for period; + d_in <= "01000011"; + + wait for period; + d_in <= "01000011"; + + wait for period; + d_in <= "01000101"; + + wait for period; + we <= '0'; + + wait for 2 * period; + re <= '1'; + + wait for period; + re <= '0'; + + wait; + end process; + +end testbench; + diff --git a/tb/tb_tx.vhd b/tb/tb_tx.vhd new file mode 100644 index 0000000..209facc --- /dev/null +++ b/tb/tb_tx.vhd @@ -0,0 +1,93 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity tb_tx is +end tb_tx; + + +architecture testbench of tb_tx is + + component transmitter is + port ( + clk : in std_logic; + reset : in std_logic; + data : in std_logic_vector (7 downto 0); + we : in std_logic; + ready : out std_logic; + tx : out std_logic + ); + end component; + + signal clk : std_logic; + signal reset : std_logic; + signal data : std_logic_vector (7 downto 0) := (others => '0'); + signal we : std_logic := '0'; + signal ready : std_logic; + signal tx : std_logic; + + constant period : time := 2 us; + constant offset : time := 2 us; + +begin + UUT : transmitter port map ( + clk => clk, + reset => reset, + data => data, + we => we, + ready => ready, + tx => tx + ); + + process + begin + clk <= '0'; + wait for offset; + + loop + clk <= '1'; + wait for period/2; + clk <= '0'; + wait for period/2; + end loop; + end process; + + + process + begin + reset <= '0'; + wait for 1.5 * period; + reset <= '1'; + wait for 1 * period; + reset <= '0'; + wait; + end process; + + + process + begin + wait until reset = '0'; + wait for 0.1 * period; + + wait until ready = '1'; + data <= "01000001"; + we <= '1'; + wait until ready = '0'; + data <= "00000000"; + we <= '0'; + + + wait until ready = '1'; + wait for 1.5 * period; + data <= "01000010"; + we <= '1'; + wait until ready = '0'; + data <= "00000000"; + we <= '0'; + + wait; + end process; + +end testbench; + diff --git a/tb/tb_uart.vhd b/tb/tb_uart.vhd new file mode 100644 index 0000000..b4d1f22 --- /dev/null +++ b/tb/tb_uart.vhd @@ -0,0 +1,145 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity tb_uart is +end tb_uart; + + +architecture testbench of tb_uart is + + component uart is + generic ( + output_fifo_width : integer + ); + port ( + mclk : in std_logic; + per_addr : in std_logic_vector (7 downto 0); + per_din : in std_logic_vector (15 downto 0); + per_en : in std_logic; + per_wen : in std_logic_vector (1 downto 0); + puc : in std_logic; + --per_irq_acc : in std_logic; + --per_irq : out std_logic; + per_dout : out std_logic_vector (15 downto 0); + + txd : out std_logic + ); + end component; + + signal clk : std_logic; + signal reset : std_logic; + + constant period : time := 1 us; + constant offset : time := 2 us; + + + signal per_addr : std_logic_vector (7 downto 0); + signal per_din : std_logic_vector (15 downto 0); + signal per_en : std_logic; + signal per_wen : std_logic_vector (1 downto 0); + signal per_dout : std_logic_vector (15 downto 0); + + signal txd : std_logic; + + + type test_record is record + we : std_logic; + word : std_logic; + data : std_logic_vector (15 downto 0); + addr : std_logic_vector (15 downto 0); + end record; + + type test_array is array (positive range <>) of test_record; + + constant test_vectors : test_array := ( + ('1','1',X"0002",X"0100"), + ('1','0',X"0065",X"0102") + ); + +-------------------------------------------------------------------------------- + +begin + UUT : uart port map ( + mclk => clk, + per_addr => per_addr, + per_din => per_din, + per_en => per_en, + per_wen => per_wen, + puc => reset, + per_dout => per_dout, + + txd => txd + ); + + + process + begin + clk <= '0'; + wait for offset; + + loop + clk <= '1'; + wait for period/2; + clk <= '0'; + wait for period/2; + end loop; + end process; + + + process + begin + reset <= '0'; + wait for period; + reset <= '1'; + wait for period; + reset <= '0'; + wait; + end process; + + + process + variable vector : test_record; + begin + per_addr <= X"00"; + per_din <= X"0000"; + per_en <= '0'; + per_wen <= "00"; + + wait for 3.1 * period; + + + for i in test_vectors'range loop + vector := test_vectors(i); + + per_addr <= vector.addr (8 downto 1); + per_en <= '1'; + + if (vector.word = '1') then + per_wen <= "11"; + per_din <= vector.data (15 downto 0); + + else + if (vector.addr(0) = '1') then + per_wen <= "10"; + per_din <= vector.data (7 downto 0) & "00000000"; + else + per_wen <= "01"; + per_din <= "00000000" & vector.data (7 downto 0); + end if; + end if; + + wait for period; + + per_addr <= X"00"; + per_din <= X"0000"; + per_en <= '0'; + per_wen <= "00"; + end loop; + + wait; + end process; + +end testbench; + diff --git a/tx.vhd b/tx.vhd new file mode 100644 index 0000000..aca961a --- /dev/null +++ b/tx.vhd @@ -0,0 +1,65 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity transmitter is + port ( + clk : in std_logic; + reset : in std_logic; + data : in std_logic_vector (7 downto 0); + we : in std_logic; + ready : out std_logic; + tx : out std_logic + ); +end transmitter; + +-------------------------------------------------------------------------------- + +architecture dataflow of transmitter is + + -- Output shift register (containing also start and stop bit). + signal tx_shift_reg : std_logic_vector (9 downto 0); + -- Register parallel to the output shift register where '1' shows the last + -- bit of the frame ('1' is in the place of stop bit). + signal tx_flag : std_logic_vector (9 downto 0); + -- Transmitting of new frame could be started with next tx_clk. + signal tx_ready : std_logic; + +-------------------------------------------------------------------------------- + +begin + + process (clk, reset) + begin + if (reset = '1') then + tx_shift_reg <= "1111111111"; + tx_flag <= "0000000000"; + tx_ready <= '1'; + + elsif (rising_edge(clk)) then + if (we = '1') then + tx_shift_reg <= '1' & data & '0'; + tx_flag <= "1000000000"; + tx_ready <= '0'; + + else + tx_shift_reg <= '1' & tx_shift_reg(9 downto 1); + tx_flag <= '0' & tx_flag(9 downto 1); + + if (tx_flag(1) = '1') then + tx_ready <= '1'; + end if; + + end if; + end if; + end process; + +-------------------------------------------------------------------------------- + + ready <= tx_ready; + + tx <= tx_shift_reg(0); + +end dataflow; + diff --git a/tx_control.vhd b/tx_control.vhd new file mode 100644 index 0000000..155605b --- /dev/null +++ b/tx_control.vhd @@ -0,0 +1,83 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity tx_control is + port ( + clk : in std_logic; + reset : in std_logic; + tx_ready : in std_logic; + fifo_empty : in std_logic; + tx_we : out std_logic; + fifo_pop : out std_logic + ); +end tx_control; + +-------------------------------------------------------------------------------- + +architecture behavioral of tx_control is + + type state_t is (waiting, next_frame, transmitting); + + signal state : state_t; + +-------------------------------------------------------------------------------- + +begin + + process (clk, reset) + begin + if (reset = '1') then + state <= waiting; + + elsif (rising_edge(clk)) then + case state is + when waiting => + if (fifo_empty = '0') then + state <= next_frame; + end if; + + when next_frame => + if (tx_ready = '0') then + state <= transmitting; + end if; + + when transmitting => + if (tx_ready = '1') then + if (fifo_empty = '0') then + state <= next_frame; + else + state <= waiting; + end if; + end if; + end case; + end if; + end process; + + + process (state, tx_ready) + begin + case state is + when waiting => + tx_we <= '0'; + fifo_pop <= '0'; + + when next_frame => + tx_we <= '1'; + if (tx_ready = '0') then + fifo_pop <= '1'; + else + fifo_pop <= '0'; + end if; + + when transmitting => + tx_we <= '0'; + fifo_pop <= '0'; + end case; + end process; + +-------------------------------------------------------------------------------- + +end behavioral; + diff --git a/uart.vhd b/uart.vhd new file mode 100644 index 0000000..fe5714f --- /dev/null +++ b/uart.vhd @@ -0,0 +1,184 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +entity uart is + generic ( + output_fifo_width : integer := 2 + ); + port ( + mclk : in std_logic; + per_addr : in std_logic_vector (7 downto 0); + per_din : in std_logic_vector (15 downto 0); -- unused + per_en : in std_logic; + per_wen : in std_logic_vector (1 downto 0); -- unused + puc : in std_logic; -- unused + --per_irq_acc : in std_logic; -- unused + --per_irq : out std_logic; + per_dout : out std_logic_vector (15 downto 0); + + txd : out std_logic + ); +end uart; + +-- Registers: +-- - Prescaler .16b +-- - Modulator .8b +-- - TX data .8b +-- - TX enable +-- - TX buffer full .1b +-- - TX buffer empty .1b +-- - TX buffer empty IE 1.b +-- - RX data .8b +-- - RX enable +-- - RX buffer empty .1b +-- - RX buffer half full .1b +-- - RX buffer full .1b +-- - RX buffer half full IE .1b +-- - RX buffer full IE .1b +-- - RX framing error .1b +-- - RX buffer overflow .1b + +-------------------------------------------------------------------------------- + +architecture dataflow of uart is + + component tx_control is + port ( + clk : in std_logic; + reset : in std_logic; + tx_ready : in std_logic; + fifo_empty : in std_logic; + tx_we : out std_logic; + fifo_pop : out std_logic + ); + end component; + + component transmitter is + port ( + clk : in std_logic; + reset : in std_logic; + data : in std_logic_vector (7 downto 0); + we : in std_logic; + ready : out std_logic; + tx : out std_logic + ); + end component; + + component fifo is + generic ( + width : integer := 2 + ); + port ( + clk : in std_logic; + reset : in std_logic; + we : in std_logic; + re : in std_logic; + d_in : in std_logic_vector (7 downto 0); + d_out : out std_logic_vector (7 downto 0); + full : out std_logic; + hfull : out std_logic; + empty : out std_logic; + overflow : out std_logic + ); + end component; + + component baud_gen is + port ( + clk : in std_logic; + reset : in std_logic; + scale : in std_logic_vector (15 downto 0); + clk_baud : out std_logic + ); + end component; + +-------------------------------------------------------------------------------- + + type boolean_vector is array (natural range <>) of boolean; + +-------------------------------------------------------------------------------- + + constant base_addr : integer := 16#0100#; + + constant UBAUD : integer := base_addr + 00; + constant UTX : integer := base_addr + 02; + + signal reg_we : std_logic_vector (511 downto 0); + signal reg_re : boolean_vector (511 downto 0); + + signal tx_clk : std_logic; + signal tx_data : std_logic_vector (7 downto 0); + signal tx_we : std_logic; + signal tx_ready : std_logic; + + signal tx_fifo_empty : std_logic; + signal tx_fifo_re : std_logic; + signal tx_fifo_we : std_logic; + +-------------------------------------------------------------------------------- + +begin + + process (per_addr, per_wen, per_en) + begin + for i in reg_re'range loop + reg_re (i) <= false; + reg_we (i) <= '0'; + + if (per_en = '1' and per_addr = i/2) then + reg_re (i) <= true; + + if (per_wen (i mod 2) = '1') then + reg_we (i) <= '1'; + end if; + end if; + end loop; + end process; + + + tx_control_0 : tx_control port map ( + clk => mclk, + reset => puc, + tx_ready => tx_ready, + fifo_empty => tx_fifo_empty, + tx_we => tx_we, + fifo_pop => tx_fifo_re + ); + + transmitter_0 : transmitter port map ( + clk => tx_clk, + reset => puc, + data => tx_data, + we => tx_we, + ready => tx_ready, + tx => txd + ); + + tx_fifo : fifo port map ( + clk => mclk, + reset => puc, + we => tx_fifo_we, + re => tx_fifo_re, + d_in => per_din (7 downto 0), + d_out => tx_data, + full => open, + hfull => open, + empty => tx_fifo_empty, + overflow => open + ); + + baud_gen_0 : baud_gen port map ( + clk => mclk, + reset => puc, + scale => "0000000000000000", + clk_baud => tx_clk + ); + + +-------------------------------------------------------------------------------- + + tx_fifo_we <= reg_we (UTX); + +end dataflow; + -- 2.39.2