]> rtime.felk.cvut.cz Git - fpga/uart.git/commitdiff
Receiving capability added to the top component.
authorVladimir Burian <buriavl2@fel.cvut.cz>
Fri, 4 Feb 2011 13:06:14 +0000 (14:06 +0100)
committerVladimir Burian <buriavl2@fel.cvut.cz>
Fri, 4 Feb 2011 13:06:14 +0000 (14:06 +0100)
Now receiving and transmitting works and is usable. In the USTAT
register there are flags of TX and RX FIFOs states. In the UIE
register coresponding interrupts can be enabled.

tb/tb_uart.vhd
uart.vhd

index b4d1f2217b4138e98d1887965f2e82d4047d9976..f35be5e5a0dbc9b2de55346ee789fddb0a22aafe 100644 (file)
@@ -11,7 +11,8 @@ architecture testbench of tb_uart is
 
   component uart is
     generic (
-      output_fifo_width : integer
+      output_fifo_width : integer := 2;
+      input_fifo_width  : integer := 2
     );
     port (
       mclk        : in  std_logic;
@@ -20,10 +21,11 @@ architecture testbench of tb_uart is
       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_irq_acc : in  std_logic;
+      per_irq     : out std_logic;
       per_dout    : out std_logic_vector (15 downto 0);
 
+      rxd         : in  std_logic;
       txd         : out std_logic
     );
   end component;  
@@ -31,8 +33,8 @@ architecture testbench of tb_uart is
   signal clk   : std_logic;
   signal reset : std_logic;
   
-  constant period : time := 1 us;
-  constant offset : time := 2 us;
+  constant period : time := 200 ns;
+  constant offset : time := 2 * period;
 
 
   signal per_addr : std_logic_vector (7  downto 0);
@@ -40,40 +42,54 @@ architecture testbench of tb_uart is
   signal per_en   : std_logic;
   signal per_wen  : std_logic_vector (1  downto 0);
   signal per_dout : std_logic_vector (15 downto 0);
+  signal per_irq  : std_logic;
 
+  signal rxd      : std_logic;
   signal txd      : std_logic;
 
 
-  type test_record is record
-    we : std_logic;
+  type per_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;
+  type per_test_array is array (positive range <>) of per_test_record;
+  type rxd_test_array is array (positive range <>) of std_logic_vector (7 downto 0);
   
-  constant test_vectors : test_array := (
-    ('1','1',X"0002",X"0100"),
-    ('1','0',X"0065",X"0102")
+  constant addr_offset : std_logic_vector (15 downto 0) := X"0100";
+  
+  constant per_test_vectors : per_test_array := (
+    ('1','1',X"0002",X"0000"),
+    ('1','0',X"0065",X"0002")
+  );
+
+  constant rxd_test_vectors : rxd_test_array := (
+    "01000011",
+    "01000100"
   );
 
 --------------------------------------------------------------------------------
 
 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
+    mclk        => clk,
+    per_addr    => per_addr,
+    per_din     => per_din,
+    per_en      => per_en,
+    per_wen     => per_wen,
+    puc         => reset,
+    per_irq_acc => '0',
+    per_irq     => per_irq,
+    per_dout    => per_dout,
+    
+    rxd         => rxd,
+    txd         => txd
   );
 
-
+  
+  -- Clock generation
   process
   begin
     clk <= '0';
@@ -87,7 +103,8 @@ begin
     end loop;
   end process;
 
-
+  
+  -- Reset generation
   process
   begin
     reset <= '0';
@@ -98,9 +115,10 @@ begin
     wait;
   end process;
 
-
+  
+  -- Bus communication with UART peripherial (per_test_vector)
   process
-    variable vector : test_record;
+    variable vector : per_test_record;
   begin
     per_addr <= X"00";
     per_din  <= X"0000";
@@ -110,9 +128,10 @@ begin
     wait for 3.1 * period;
 
 
-    for i in test_vectors'range loop
-      vector := test_vectors(i);
-
+    for i in per_test_vectors'range loop
+      vector := per_test_vectors(i);
+      vector.addr := vector.addr + addr_offset;
+      
       per_addr <= vector.addr (8 downto 1);
       per_en <= '1';
     
@@ -140,6 +159,36 @@ begin
 
     wait;
   end process;
+
+
+  -- UART RXD signal generation (rxd_test_vector)
+  process
+    constant baud_period : time := 6 * period;
+    constant extra_wait  : time := 2 * baud_period;  -- waiting between frames
+    variable vector      : std_logic_vector (7 downto 0);
+  begin
+    rxd <= '1';
+
+    wait for 4.1 * period;
+
+    for i in rxd_test_vectors'range loop
+      vector := rxd_test_vectors (i);
+
+      rxd <= '0';
+      wait for baud_period;
+
+      for j in 7 downto 0 loop
+        rxd <= vector (j);
+        wait for baud_period;
+      end loop;
+
+      rxd <= '1';
+      wait for baud_period;
+      wait for extra_wait;
+    end loop;
+
+    wait;      
+  end process;
   
 end testbench;
 
index cddd6c86f23984958f5aa143d2861db09486ab44..11eb9b243eae781c3ff2992d55ed25dd411ab510 100644 (file)
--- a/uart.vhd
+++ b/uart.vhd
@@ -5,41 +5,25 @@ use ieee.std_logic_unsigned.all;
 
 entity uart is
   generic (
-    output_fifo_width : integer := 2
+    output_fifo_width : integer := 2;
+    input_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_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);  -- unused
-    puc         : in  std_logic;                       -- unused
-    --per_irq_acc : in  std_logic;                       -- unused
-    --per_irq     : out 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);
 
+    rxd         : in  std_logic;
     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
@@ -66,6 +50,34 @@ architecture dataflow of uart is
     );
   end component;
 
+  component rx_control is
+    port (
+      clk           : in  std_logic;
+      reset         : in  std_logic;
+      rx            : in  std_logic;
+      bad_start_bit : in  std_logic;
+      bad_stop_bit  : in  std_logic;
+      rx_ready      : in  std_logic;
+      rx_reset      : out std_logic;
+      rx_en         : out std_logic;
+      fifo_we       : out std_logic;
+      clk_en        : out std_logic
+    );
+  end component rx_control;
+
+  component receiver is
+    port (
+      clk           : in  std_logic;
+      reset         : in  std_logic;
+      en            : in  std_logic;
+      rx            : in  std_logic;
+      ready         : out std_logic;
+      bad_start_bit : out std_logic;
+      bad_stop_bit  : out std_logic;
+      data          : out std_logic_vector (7 downto 0)
+    );
+  end component receiver;
+  
   component fifo is
     generic (
       width : integer := 2
@@ -90,46 +102,80 @@ architecture dataflow of uart is
       clk      : in  std_logic;
       ce       : in  std_logic;
       reset    : in  std_logic;
-      scale    : in std_logic_vector (15 downto 0);
-      clk_baud : out  std_logic
+      scale    : in  std_logic_vector (15 downto 0);
+      clk_baud : out std_logic
     );
   end component;
 
 --------------------------------------------------------------------------------
 
+  alias per_din_low  : std_logic_vector (7 downto 0) is per_din (7 downto 0);
+  alias per_din_high : std_logic_vector (7 downto 0) is per_din (15 downto 8);
+  
   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;
+  constant UBAUD : integer := base_addr + 00;  -- 2B - Baud rate generator
+  constant UTX   : integer := base_addr + 02;  -- 1B - Transmit data
+  constant URX   : integer := base_addr + 04;  -- 1B - Read data
+  constant USTAT : integer := base_addr + 06;  -- 1B - Rx & Tx status
+  constant UIE   : integer := base_addr + 07;  -- 1B - Interrupt enable
 
-  signal reg_we : std_logic_vector (511 downto 0);
-  signal reg_re : boolean_vector (511 downto 0);
+  signal reg_we   : std_logic_vector (511 downto 0);
+  signal reg_re   : std_logic_vector (511 downto 0);
+  signal reg_re_b : boolean_vector (512 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 reg_baud : std_logic_vector (15 downto 0) := "0000000000000010";
+  signal reg_stat : std_logic_vector (7 downto 0);
+  signal reg_ie   : std_logic_vector (7 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_full  : std_logic;
+  signal tx_fifo_hfull : std_logic;
   signal tx_fifo_empty : std_logic;
-  signal tx_fifo_re : std_logic;
-  signal tx_fifo_we : std_logic;
+  signal tx_fifo_re    : std_logic;
 
+  signal rx_clk           : std_logic;
+  signal rx_clk_en        : std_logic;
+  signal rx_en            : std_logic;
+  signal rx_ready         : std_logic;
+  signal rx_reset         : std_logic;
+  signal rx_data          : std_logic_vector (7 downto 0);
+  signal rx_bad_start_bit : std_logic;
+  signal rx_bad_stop_bit  : std_logic;
+  signal rx_fifo_we       : std_logic;
+  signal rx_fifo_out      : std_logic_vector (7 downto 0);
+  signal rx_fifo_full     : std_logic;
+  signal rx_fifo_hfull    : std_logic;
+  signal rx_fifo_empty    : std_logic;
+  signal rx_fifo_ow       : std_logic;
+  signal rx_fifo_ow_clear : std_logic;
+  
 --------------------------------------------------------------------------------
 
 begin
 
+  -- Address decoder
   process (per_addr, per_wen, per_en)
   begin
     for i in reg_re'range loop
-      reg_re (i) <= false;
-      reg_we (i) <= '0';
+      reg_re_b (i) <= false;
+      reg_re (i)   <= '0';
+      reg_we (i)   <= '0';
       
       if (per_en = '1' and per_addr = i/2) then
-        reg_re (i) <= true;
+        -- Register of the corresponding address is always read, so
+        -- read-modify-write operation in one cycle is possible.
+        reg_re_b (i) <= true;
+        reg_re (i)   <= '1';
         
         if (per_wen (i mod 2) = '1') then
           reg_we (i) <= '1';
@@ -138,6 +184,9 @@ begin
     end loop;
   end process;
   
+--------------------------------------------------------------------------------
+-- TX MODULE
+--------------------------------------------------------------------------------
 
   tx_control_0 : tx_control port map (
     clk        => mclk,
@@ -148,7 +197,7 @@ begin
     fifo_pop   => tx_fifo_re
   );
 
-  transmitter_0 : transmitter port map (
+  tx_transmitter_0 : transmitter port map (
     clk    => tx_clk,
     reset  => puc,
     data   => tx_data,
@@ -157,32 +206,125 @@ begin
     tx     => txd
   );
 
-  tx_fifo : fifo port map (
+  tx_fifo_0 : fifo port map (
     clk      => mclk,
     reset    => puc,
-    we       => tx_fifo_we,
+    we       => reg_we (UTX),
     re       => tx_fifo_re,
     clear_ow => '0',
     d_in     => per_din (7 downto 0),
     d_out    => tx_data,
-    full     => open,
-    hfull    => open,
+    full     => tx_fifo_full,
+    hfull    => tx_fifo_hfull,
     empty    => tx_fifo_empty,
     overflow => open
-  );
+    );
 
-  baud_gen_0 : baud_gen port map (
+  tx_baud_gen_0 : baud_gen port map (
     clk      => mclk,
     ce       => '1',
     reset    => puc,
-    scale    => "0000000000000000",
+    scale    => reg_baud,
     clk_baud => tx_clk
-  );
+    );
+
+--------------------------------------------------------------------------------
+-- RX MODULE
+--------------------------------------------------------------------------------
 
+  rx_control_0 : rx_control
+    port map (
+      clk           => mclk,
+      reset         => puc,
+      rx            => rxd,
+      bad_start_bit => rx_bad_start_bit,
+      bad_stop_bit  => rx_bad_stop_bit,
+      rx_ready      => rx_ready,
+      rx_reset      => rx_reset,
+      rx_en         => rx_en,
+      fifo_we       => rx_fifo_we,
+      clk_en        => rx_clk_en);
 
+  rx_receiver_0 : receiver
+    port map (
+      clk           => rx_clk,
+      reset         => puc,
+      en            => rx_en,
+      rx            => rxd,
+      ready         => rx_ready,
+      bad_start_bit => rx_bad_start_bit,
+      bad_stop_bit  => rx_bad_stop_bit,
+      data          => rx_data);
+
+  rx_fifo_0 : fifo
+    port map (
+      clk      => mclk,
+      reset    => puc,
+      we       => rx_fifo_we,
+      re       => reg_re (URX),
+      clear_ow => rx_fifo_ow_clear,
+      d_in     => rx_data,
+      d_out    => rx_fifo_out,
+      full     => rx_fifo_full,
+      hfull    => rx_fifo_hfull,
+      empty    => rx_fifo_empty,
+      overflow => rx_fifo_ow);
+
+  rx_baud_gen_0 : baud_gen
+    port map (
+      clk      => mclk,
+      ce       => rx_clk_en,
+      reset    => puc,
+      scale    => reg_baud,
+      clk_baud => rx_clk);
+  
 --------------------------------------------------------------------------------
+-- OTHER LOGIC
+--------------------------------------------------------------------------------
+  
+  process (mclk, puc) is
+  begin
+    if puc = '1' then
+      reg_baud <= (others => '0');
+      reg_ie   <= (others => '0');
+      
+    elsif mclk'event and mclk = '1' then
+      if reg_we (UBAUD) = '1' then
+        reg_baud (7 downto 0) <= per_din_low;
+      end if;
+
+      if reg_we (UBAUD+1) = '1' then
+        reg_baud (15 downto 8) <= per_din_high;
+      end if;
 
-  tx_fifo_we <= reg_we (UTX);
+      if reg_we (USTAT) = '1' then
+        reg_ie <= per_din_low;
+      end if;
+    end if;
+  end process;
+
+
+  reg_stat <= tx_fifo_empty &
+              tx_fifo_hfull &
+              tx_fifo_full &
+              not rx_fifo_empty &
+              rx_fifo_hfull &
+              rx_fifo_full &
+              rx_fifo_ow &
+              '0';
+
+  
+  per_irq <= '1' when (reg_stat and reg_ie and "10011100") /= "00000000" else '0' ;
+
+  per_dout <= reg_baud                 when reg_re_b (UBAUD) else
+              "00000000" & tx_data     when reg_re_b (UTX) else
+              "00000000" & rx_fifo_out when reg_re_b (URX) else
+              reg_ie & reg_stat        when reg_re_b (USTAT) else
+              (others => '0');
+  
+--------------------------------------------------------------------------------
+  
+  rx_fifo_ow_clear <= per_din (1) and reg_we (USTAT);
   
 end dataflow;