From 8bd8dd6ce07fb8e247f651b3c61c94bb1f00895a Mon Sep 17 00:00:00 2001 From: Väinö Kauppila Date: Sun, 19 Apr 2026 00:33:08 +0300 Subject: starting files and example programs --- PIC/uart.vhd | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 PIC/uart.vhd (limited to 'PIC/uart.vhd') diff --git a/PIC/uart.vhd b/PIC/uart.vhd new file mode 100644 index 0000000..a0fad93 --- /dev/null +++ b/PIC/uart.vhd @@ -0,0 +1,195 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- TX: fire and forget (8E1) +-- RX: FIFO-backed (8E1), consumer reads via rd_en/rx_data/rx_empty + +entity uart is + generic ( + CLK_FREQ : positive := 50_000_000; + BAUD_RATE : positive := 115_200; + CLKS_PER_BIT : positive := CLK_FREQ / BAUD_RATE + ); + port ( + clk : in std_logic; + -- TX + tx_should_send : in std_logic; + byte_in : in std_logic_vector(7 downto 0); + tx_done : out std_logic; + baud_tick : out std_logic; + uart_tx : out std_logic; + -- RX + uart_rx : in std_logic; + rd_en : in std_logic; + rx_data : out std_logic_vector(7 downto 0); + rx_empty : out std_logic; + rx_full : out std_logic + ); +end entity uart; + +architecture rtl of uart is + + signal baud_counter : std_logic_vector(15 downto 0) + := (others => '0'); + signal baud_tick_i : std_logic := '0'; + + signal tx_out : std_logic := '1'; + signal current_byte : std_logic_vector(7 downto 0) := (others => '0'); + signal tx_byte_latch : std_logic_vector(7 downto 0) := (others => '0'); + + -- RX input synchronizer (2FF, idle state is '1') + signal uart_rx_meta : std_logic := '1'; + signal uart_rx_sync : std_logic := '1'; + + -- RX FIFO wiring + signal fifo_wr_en : std_logic := '0'; + signal fifo_din : std_logic_vector(7 downto 0) + := (others => '0'); + signal fifo_full : std_logic := '0'; + +begin + + uart_tx <= tx_out; + baud_tick <= baud_tick_i; + + rx_fifo : entity work.fifo + generic map (DEPTH => 64, ADDR_BITS => 6, WIDTH => 8) + port map ( + clk => clk, + wr_en => fifo_wr_en, + rd_en => rd_en, + din => fifo_din, + dout => rx_data, + full => fifo_full, + empty => rx_empty + ); + + rx_full <= fifo_full; + + uart_rx_synchronizer : process(clk) + begin + if rising_edge(clk) then + uart_rx_meta <= uart_rx; + uart_rx_sync <= uart_rx_meta; + end if; + end process uart_rx_synchronizer; + + uart_baud_timer : process(clk) + begin + if rising_edge(clk) then + if unsigned(baud_counter) = CLKS_PER_BIT - 1 then + baud_counter <= (others => '0'); + baud_tick_i <= '1'; + else + baud_counter <= std_logic_vector(unsigned(baud_counter) + 1); + baud_tick_i <= '0'; + end if; + end if; + end process uart_baud_timer; + + uart_transmit_byte : process(clk) + type t_state is (idle, start, data, parity, stop); + variable state : t_state := idle; + variable bit_index : unsigned(2 downto 0); + variable parity_value : std_logic; + begin + if rising_edge(clk) then + tx_done <= '0'; + if baud_tick_i = '1' then + case state is + when idle => + if tx_should_send = '1' then + tx_out <= '0'; -- start bit immediately + tx_byte_latch <= byte_in; -- latch byte now + parity_value := '0'; + bit_index := (others => '0'); + state := data; + end if; + when start => + null; -- unused, kept for completeness + when data => + tx_out <= tx_byte_latch(to_integer(bit_index)); + parity_value := parity_value xor tx_byte_latch(to_integer(bit_index)); + if bit_index = 7 then + state := parity; + else + state := data; + end if; + bit_index := bit_index + 1; + when parity => + tx_out <= parity_value; + state := stop; + when stop => + tx_out <= '1'; + tx_done <= '1'; + state := idle; + end case; + end if; + end if; + end process uart_transmit_byte; + + uart_receive_byte : process(clk) + type rx_state_t is (idle, start, data, parity, stop); + variable state : rx_state_t := idle; + variable bit_index : unsigned(2 downto 0); + variable rx_byte : std_logic_vector(7 downto 0); + variable parity_val : std_logic; + variable rx_counter : unsigned(15 downto 0); + begin + if rising_edge(clk) then + fifo_wr_en <= '0'; + case state is + when idle => + if uart_rx_sync = '0' then + rx_counter := to_unsigned(CLKS_PER_BIT / 2, 16); + state := start; + end if; + when start => + if rx_counter = 0 then + if uart_rx_sync = '0' then + rx_counter := to_unsigned(CLKS_PER_BIT - 1, 16); + bit_index := (others => '0'); + parity_val := '0'; + state := data; + else + state := idle; + end if; + else + rx_counter := rx_counter - 1; + end if; + when data => + if rx_counter = 0 then + rx_byte(to_integer(bit_index)) := uart_rx_sync; + parity_val := parity_val xor uart_rx_sync; + rx_counter := to_unsigned(CLKS_PER_BIT - 1, 16); + if bit_index = 7 then + state := parity; + else + bit_index := bit_index + 1; + end if; + else + rx_counter := rx_counter - 1; + end if; + when parity => + if rx_counter = 0 then + rx_counter := to_unsigned(CLKS_PER_BIT - 1, 16); + state := stop; + else + rx_counter := rx_counter - 1; + end if; + when stop => + if rx_counter = 0 then + if uart_rx_sync = '1' and fifo_full = '0' then + fifo_din <= rx_byte; + fifo_wr_en <= '1'; + end if; + state := idle; + else + rx_counter := rx_counter - 1; + end if; + end case; + end if; + end process uart_receive_byte; + +end architecture rtl; -- cgit v1.3