├── .gitignore ├── LICENSE ├── README.rst ├── simulation └── .gitignore ├── source ├── fpga_unit_tests.py ├── generic_fifo.vhd ├── loopback.vhd ├── tb_uart.vhd ├── top.vhd ├── uart.ucf ├── uart.vhd └── uart_unit_tests.py ├── synthesis └── .gitignore └── uart.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.cache 2 | __pycache__ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Peter Bennett 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | VHDL UART 2 | ========= 3 | 4 | Description 5 | ----------- 6 | 7 | A VHDL UART for communicating over a serial link with an FPGA. This example 8 | implements a loopback so that data received by the FPGA will be returned down 9 | the serial link. 10 | 11 | The default settings for the link are 115200 BAUD, 8 Data, 1 Stop, No parity. 12 | 13 | Source files 14 | ------------ 15 | 16 | The following source files can be found in the 'source' directory. 17 | 18 | +--------------------+--------+----------------------------------------------------+ 19 | | File | Type | Description | 20 | +====================+========+====================================================+ 21 | | uart.vhd | VHDL | UART implementation | 22 | +--------------------+--------+----------------------------------------------------+ 23 | | loopback.vhd | VHDL | Instance UART in loopback @ 115200 baud & 100MHz | 24 | +--------------------+--------+----------------------------------------------------+ 25 | | top.vhd | VHDL | Instance loopback in FPGA top level wrapper | 26 | +--------------------+--------+----------------------------------------------------+ 27 | | tb_uart.vhd | VHDL | Testbench for the UART component | 28 | +--------------------+--------+----------------------------------------------------+ 29 | | uart_unit_tests.py | Python | ChipTools unit test suite for tb_uart.vhd | 30 | +--------------------+--------+----------------------------------------------------+ 31 | | uart.ucf | UCF | Constraints for Spartan 6 LX9 Microboard (Avnet) | 32 | +--------------------+--------+----------------------------------------------------+ 33 | | fpga_unit_tests.py | Python | Hardware unit tests for the LX9 Microboard | 34 | +--------------------+--------+----------------------------------------------------+ 35 | 36 | The **uart.xml** file in the top level directory is a project file to allow you 37 | to build and test this design using the `ChipTools framework `_ 38 | 39 | Getting Started 40 | ---------------- 41 | 42 | The following instructions explain how to test and build the loopback example 43 | using the ChipTools framework. Simulation and hardware tests are included. 44 | 45 | Run the Unit Tests 46 | ~~~~~~~~~~~~~~~~~~ 47 | 48 | To run the unit tests invoke ChipTools in the top level directory: 49 | 50 | .. code-block:: bash 51 | 52 | $ chiptools 53 | 54 | Load the project and run the tests: 55 | 56 | .. code-block:: bash 57 | 58 | $ load_project uart.xml 59 | $ run_tests 60 | 61 | The default simulator is set to Modelsim, to run the tests using a different 62 | simulator supply either 'isim', 'ghdl' or 'vivado' to the **run_tests** 63 | command. 64 | 65 | The report file: **report.html** is saved in the **simulation** directory and 66 | contains the results of the simulation test suite. 67 | 68 | Synthesise the Design 69 | ~~~~~~~~~~~~~~~~~~~~~ 70 | 71 | A constraints file is provided to allow the design to be built for the 72 | **Spartan 6 LX9 Microboard**. To initiate a build perform the following in the 73 | top level directory: 74 | 75 | .. code-block:: bash 76 | 77 | $ chiptools 78 | $ load_project uart.xml 79 | $ synthesise lib_uart.top 80 | 81 | The synthesis flow is set to 'ise' as this is targeted at a Spartan6 FPGA. 82 | 83 | Build outputs will be automatically archived and stored in the **synthesis** 84 | directory. 85 | 86 | Run the Hardware Unit Tests 87 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 88 | 89 | A set of unit tests have been written to test the UART loopback example after 90 | it has been programmed onto a Spartan 6 LX9 Microboard. The unit tests check 91 | different transfer sizes of random data using the default BAUD rate of 115200. 92 | 93 | The tests require `PySerial `_ to allow 94 | Python to read and write to the serial port. Before running the tests the board 95 | should be programmed and connected to your PC and the serial port setting in 96 | the unit test should be edited to map to the serial port of the FPGA board. 97 | 98 | 99 | Further reading 100 | -------------------- 101 | 102 | Original release post 103 | ~~~~~~~~~~~~~~~~~~~~~ 104 | 105 | http://www.bytebash.com/2011/10/rs232-uart-vhdl/ 106 | 107 | ChipTools repository 108 | ~~~~~~~~~~~~~~~~~~~~~ 109 | 110 | http://github.com/pabennett/chiptools 111 | 112 | ChipTools documentation 113 | ~~~~~~~~~~~~~~~~~~~~~~~ 114 | 115 | http://chiptools.readthedocs.org/en/latest/index.html -------------------------------------------------------------------------------- /simulation/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /source/fpga_unit_tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | fpga_unit_tests.py 3 | The tests contained in this script are designed to test the UART loopback 4 | example when it is programmed on to an FPGA. To run the tests you must first 5 | have programmed an FPGA board with the loopback example and connected a serial 6 | cable to your PC. The PORT setting in this file, which defaults to 'COM4', must 7 | be edited to match the port address assigned to the FPGA board. These tests 8 | check the default configuration of 115200 BAUD. 9 | """ 10 | import serial 11 | import random 12 | import unittest 13 | import time 14 | from serial.tools import list_ports 15 | 16 | print(list(list_ports.comports())) 17 | 18 | 19 | class TestSerial(unittest.TestCase): 20 | 21 | def setUp(self): 22 | self.ser = serial.Serial( 23 | # Update this to match the device port for the FPGA board 24 | port='COM4', 25 | baudrate=115200, 26 | parity=serial.PARITY_NONE, 27 | stopbits=serial.STOPBITS_ONE, 28 | bytesize=serial.EIGHTBITS, 29 | ) 30 | self.assertTrue(self.ser.isOpen()) 31 | if self.ser.inWaiting() > 0: 32 | self.ser.read(self.ser.inWaiting()) 33 | 34 | def tearDown(self): 35 | self.ser.close() 36 | 37 | def test_single_byte(self): 38 | """ 39 | Send bytes 0-255 to the UART individually and ensure that they are 40 | returned. 41 | """ 42 | print('Testing single characters...') 43 | for i in range(256): 44 | print('Checking byte: ' + hex(i) + ' '*50, end='') 45 | self.ser.write([i]) 46 | time.sleep(0.1) 47 | self.assertEqual(self.ser.inWaiting(), 1) 48 | self.assertEqual(int(self.ser.read()[0]), i) 49 | print('\r', end='') 50 | print('') 51 | 52 | def test_static_sequences(self): 53 | """ 54 | This test transmits 256 blocks of 2**10 bytes using the blockId as the 55 | static character to send. 56 | """ 57 | print('Testing character sequences [0x00 0x01 ... 0xFF]...') 58 | self.burst_test( 59 | 2**10, 60 | 256, 61 | lambda charId, burstId: burstId 62 | ) 63 | 64 | def test_bit_flips_0xAA_0x55(self): 65 | """ 66 | This test transmits 20 blocks of 2**16 bits using an alternating byte 67 | pattern of 0xAA 0x55. 68 | """ 69 | print('Testing character sequences 0xAA 0x55...') 70 | self.burst_test( 71 | 2**16, 72 | 20, 73 | lambda charId, burstId: [0xAA, 0x55][charId % 2] 74 | ) 75 | 76 | def test_bit_flips_0xFF_0x00(self): 77 | """ 78 | This test transmits 20 blocks of 2**16 bits using an alternating byte 79 | pattern of 0xFF 0xFF. 80 | """ 81 | print('Testing character sequences 0xFF 0x00...') 82 | self.burst_test( 83 | 2**16, 84 | 20, 85 | lambda charId, burstId: [0xFF, 0x00][charId % 2] 86 | ) 87 | 88 | def test_endianness(self): 89 | """ 90 | This test transmits 20 blocks of 2**16 bits using an alternating byte 91 | pattern of 0x81 0x18. 92 | """ 93 | print('Testing character sequences 0x81 0x18...') 94 | self.burst_test( 95 | 2**16, 96 | 20, 97 | lambda charId, burstId: [0x81, 0x18][charId % 2] 98 | ) 99 | 100 | def test_random_byte_sequences(self): 101 | """ 102 | This test transmits 20 blocks of 2**16 random bytes to the UART and 103 | checks that the data is correctly returned. If data is not returned by 104 | the device or the data is incorrect this test will fail. 105 | """ 106 | print('Testing random character sequences...') 107 | self.burst_test( 108 | 2**16, 109 | 20, 110 | lambda charId, burstId: random.randint(0, 2**8-1) 111 | ) 112 | 113 | def burst_test(self, burst_size, num_bursts, data_fn): 114 | """ 115 | This test transmits 20 blocks of 2**16 random bytes to the UART and 116 | checks that the data is correctly returned. If data is not returned by 117 | the device or the data is incorrect this test will fail. 118 | """ 119 | for burstId in range(num_bursts): 120 | print( 121 | "Transferring block {0} of {1} (block size: {2})".format( 122 | burstId+1, 123 | num_bursts, 124 | burst_size 125 | ) + ''*50, 126 | end='' 127 | ) 128 | data_in = [data_fn(i, burstId) for i in range(burst_size)] 129 | self.ser.write(data_in) 130 | self.ser.flush() 131 | retries = 2 132 | while True: 133 | time.sleep(0.2) 134 | bytes_waiting = self.ser.inWaiting() 135 | if bytes_waiting < burst_size: 136 | if retries > 0: 137 | retries -= 1 138 | else: 139 | self.fail("Did not get data in time") 140 | else: 141 | break 142 | data_out = self.ser.read(self.ser.inWaiting()) 143 | data_out = [int(x) for x in data_out] 144 | self.assertListEqual(data_out, data_in) 145 | print('\r', end='') 146 | print('') 147 | 148 | if __name__ == '__main__': 149 | unittest.main() 150 | -------------------------------------------------------------------------------- /source/generic_fifo.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | use ieee.math_real.all; 5 | 6 | entity GENERIC_FIFO is 7 | generic ( 8 | FIFO_WIDTH : positive := 32; 9 | FIFO_DEPTH : positive := 1024 10 | ); 11 | port ( 12 | clock : in std_logic; 13 | reset : in std_logic; 14 | write_data : in std_logic_vector(FIFO_WIDTH-1 downto 0); 15 | read_data : out std_logic_vector(FIFO_WIDTH-1 downto 0); 16 | write_en : in std_logic; 17 | read_en : in std_logic; 18 | full : out std_logic; 19 | empty : out std_logic; 20 | level : out std_logic_vector( 21 | integer(ceil(log2(real(FIFO_DEPTH))))-1 downto 0 22 | ) 23 | ); 24 | end entity; 25 | 26 | architecture RTL of GENERIC_FIFO is 27 | --------------------------------------------------------------------------- 28 | -- Functions 29 | --------------------------------------------------------------------------- 30 | function get_fifo_level( 31 | write_pointer : unsigned; 32 | read_pointer : unsigned; 33 | depth : positive) return integer is 34 | begin 35 | if write_pointer > read_pointer then 36 | return to_integer(write_pointer - read_pointer); 37 | elsif write_pointer = read_pointer then 38 | return 0; 39 | else 40 | return ( 41 | ((depth) - to_integer(read_pointer)) + 42 | to_integer(write_pointer) 43 | ); 44 | end if; 45 | end function get_fifo_level; 46 | --------------------------------------------------------------------------- 47 | -- Types 48 | --------------------------------------------------------------------------- 49 | type memory is array (0 to FIFO_DEPTH-1) of std_logic_vector( 50 | FIFO_WIDTH-1 downto 0 51 | ); 52 | --------------------------------------------------------------------------- 53 | -- Signals 54 | --------------------------------------------------------------------------- 55 | signal fifo_memory : memory := (others => (others => '0')); 56 | signal read_pointer, write_pointer : unsigned( 57 | integer(ceil(log2(real(FIFO_DEPTH))))-1 downto 0 58 | ) := (others => '0'); 59 | signal fifo_empty : std_logic := '1'; 60 | signal fifo_full : std_logic := '0'; 61 | begin 62 | full <= fifo_full; 63 | empty <= fifo_empty; 64 | FIFO_FLAGS : process(write_pointer, read_pointer) is 65 | variable lev : integer range 0 to FIFO_DEPTH - 1; 66 | begin 67 | lev := get_fifo_level(write_pointer, read_pointer, FIFO_DEPTH); 68 | level <= std_logic_vector(to_unsigned(lev, level'length)); 69 | if lev = FIFO_DEPTH - 1 then 70 | fifo_full <= '1'; 71 | else 72 | fifo_full <= '0'; 73 | end if; 74 | if lev = 0 then 75 | fifo_empty <= '1'; 76 | else 77 | fifo_empty <= '0'; 78 | end if; 79 | end process; 80 | FIFO_LOGIC : process(clock) is 81 | begin 82 | if rising_edge(clock) then 83 | if reset = '1' then 84 | write_pointer <= (others => '0'); 85 | read_pointer <= (others => '0'); 86 | else 87 | -- FIFO WRITE 88 | if write_en = '1' and fifo_full = '0' then 89 | fifo_memory(to_integer(write_pointer)) <= write_data; 90 | if write_pointer < FIFO_DEPTH - 1 then 91 | write_pointer <= write_pointer + 1; 92 | else 93 | write_pointer <= (others => '0'); 94 | end if; 95 | end if; 96 | -- FIFO READ 97 | if read_en = '1' and fifo_empty = '0' then 98 | if read_pointer < FIFO_DEPTH - 1 then 99 | read_pointer <= read_pointer + 1; 100 | else 101 | read_pointer <= (others => '0'); 102 | end if; 103 | end if; 104 | end if; 105 | end if; 106 | end process; 107 | 108 | read_data <= fifo_memory(to_integer(read_pointer)); 109 | 110 | end RTL; -------------------------------------------------------------------------------- /source/loopback.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- UART 3 | -- Simple loopback 4 | ------------------------------------------------------------------------------- 5 | library ieee; 6 | use ieee.std_logic_1164.all; 7 | use ieee.numeric_std.all; 8 | use ieee.math_real.all; 9 | 10 | entity loopback is 11 | generic ( 12 | baud : positive; 13 | clock_frequency : positive 14 | ); 15 | port ( 16 | clock : in std_logic; 17 | reset : in std_logic; 18 | rx : in std_logic; 19 | tx : out std_logic 20 | ); 21 | end loopback; 22 | 23 | architecture rtl of loopback is 24 | --------------------------------------------------------------------------- 25 | -- Component declarations 26 | --------------------------------------------------------------------------- 27 | component uart is 28 | generic ( 29 | baud : positive; 30 | clock_frequency : positive 31 | ); 32 | port ( 33 | clock : in std_logic; 34 | reset : in std_logic; 35 | data_stream_in : in std_logic_vector(7 downto 0); 36 | data_stream_in_stb : in std_logic; 37 | data_stream_in_ack : out std_logic; 38 | data_stream_out : out std_logic_vector(7 downto 0); 39 | data_stream_out_stb : out std_logic; 40 | tx : out std_logic; 41 | rx : in std_logic 42 | ); 43 | end component uart; 44 | 45 | component generic_fifo is 46 | generic ( 47 | fifo_width : positive := 32; 48 | fifo_depth : positive := 1024 49 | ); 50 | port ( 51 | clock : in std_logic; 52 | reset : in std_logic; 53 | write_data : in std_logic_vector(FIFO_WIDTH-1 downto 0); 54 | read_data : out std_logic_vector(FIFO_WIDTH-1 downto 0); 55 | write_en : in std_logic; 56 | read_en : in std_logic; 57 | full : out std_logic; 58 | empty : out std_logic; 59 | level : out std_logic_vector( 60 | integer(ceil(log2(real(fifo_depth))))-1 downto 0 61 | ) 62 | ); 63 | end component; 64 | --------------------------------------------------------------------------- 65 | -- UART signals 66 | --------------------------------------------------------------------------- 67 | signal uart_data_in : std_logic_vector(7 downto 0); 68 | signal uart_data_out : std_logic_vector(7 downto 0); 69 | signal uart_data_in_stb : std_logic := '0'; 70 | signal uart_data_in_ack : std_logic := '0'; 71 | signal uart_data_out_stb : std_logic := '0'; 72 | -- Transmit buffer signals 73 | constant buffer_depth : integer := 1024; 74 | signal fifo_data_out : std_logic_vector(7 downto 0); 75 | signal fifo_data_in : std_logic_vector(7 downto 0); 76 | signal fifo_data_in_stb : std_logic; 77 | signal fifo_data_out_stb : std_logic; 78 | signal fifo_full : std_logic; 79 | signal fifO_empty : std_logic; 80 | begin 81 | --------------------------------------------------------------------------- 82 | -- UART instantiation 83 | --------------------------------------------------------------------------- 84 | uart_inst : uart 85 | generic map ( 86 | baud => baud, 87 | clock_frequency => clock_frequency 88 | ) 89 | port map ( 90 | -- general 91 | clock => clock, 92 | reset => reset, 93 | data_stream_in => uart_data_in, 94 | data_stream_in_stb => uart_data_in_stb, 95 | data_stream_in_ack => uart_data_in_ack, 96 | data_stream_out => uart_data_out, 97 | data_stream_out_stb => uart_data_out_stb, 98 | tx => tx, 99 | rx => rx 100 | ); 101 | 102 | -- Intermediate buffer for storing bytes received by the UART 103 | -- Bytes stored in this buffer are immediately retransmitted. 104 | receive_buffer : generic_fifo 105 | generic map( 106 | fifo_width => 8, 107 | fifo_depth => buffer_depth 108 | ) 109 | port map( 110 | clock => clock, 111 | reset => reset, 112 | write_data => fifo_data_in, 113 | read_data => fifo_data_out, 114 | write_en => fifo_data_in_stb, 115 | read_en => fifo_data_out_stb, 116 | full => fifo_full, 117 | empty => fifo_empty, 118 | level => open 119 | ); 120 | 121 | --------------------------------------------------------------------------- 122 | -- Simple loopback, retransmit any received data 123 | --------------------------------------------------------------------------- 124 | uart_loopback : process (clock) 125 | begin 126 | if rising_edge(clock) then 127 | if reset = '1' then 128 | uart_data_in_stb <= '0'; 129 | uart_data_in <= (others => '0'); 130 | fifo_data_out_stb <= '0'; 131 | fifo_data_in_stb <= '0'; 132 | else 133 | -- Acknowledge data receive strobes and set up a transmission 134 | -- request 135 | fifo_data_in_stb <= '0'; 136 | if uart_data_out_stb = '1' and fifo_full = '0' then 137 | fifo_data_in_stb <= '1'; 138 | fifo_data_in <= uart_data_out; 139 | end if; 140 | -- Clear transmission request strobe upon acknowledge. 141 | if uart_data_in_ack = '1' then 142 | uart_data_in_stb <= '0'; 143 | end if; 144 | -- Transmit any data in the buffer 145 | fifo_data_out_stb <= '0'; 146 | if fifo_empty = '0' then 147 | if uart_data_in_stb = '0' then 148 | uart_data_in_stb <= '1'; 149 | fifo_data_out_stb <= '1'; 150 | uart_data_in <= fifo_data_out; 151 | end if; 152 | end if; 153 | end if; 154 | end if; 155 | end process; 156 | end rtl; 157 | -------------------------------------------------------------------------------- /source/tb_uart.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- TB_UART 3 | -- This testbench instantiates the top level UART loopback example 4 | -- (referred to as the 'remote' UART) and a separate instance of the UART core, 5 | -- which is referred to as the 'local' UART. 6 | -- The local UART is given data to send from the input text file 'input.txt' 7 | -- which it then sends to the remote UART via a serial interface. 8 | -- The remote UART is configured in loopback mode so it 9 | -- will retransmit any data that it receives back to the local UART. 10 | -- The testbench will store any data received by the local UART into the output 11 | -- file 'output.txt'. 12 | -- Stimulus input and output checking is performed by the external Python 13 | -- unit test 'uart_unit_tests.py', which is designed to work with the ChipTools 14 | -- framework. This testbench allows the clock frequencies of the local and 15 | -- remote UARTs to be configured separately as well as their phase relationship 16 | -- and baud rates. A full suite of tests covering various configurations is 17 | -- provided in the unit test suite. 18 | ------------------------------------------------------------------------------- 19 | 20 | library ieee; 21 | use ieee.std_logic_1164.all; 22 | use ieee.numeric_std.all; 23 | use ieee.math_real.all; 24 | 25 | library std; 26 | use std.textio.all; 27 | 28 | library lib_uart; 29 | use lib_uart.all; 30 | 31 | entity tb_uart is 32 | generic ( 33 | -- Phase delay between local and remote comms links 34 | delay_ns : real := 0.75; 35 | -- Local and remote baud rates 36 | baud : positive := 115200; 37 | -- Remote clock frequency 38 | remote_clock_hz : positive := 100000000; 39 | -- Local clock frequency 40 | local_clock_hz : positive := 99999334 41 | ); 42 | end entity; 43 | 44 | architecture beh of tb_uart is 45 | component uart is 46 | generic ( 47 | baud : positive; 48 | clock_frequency : positive 49 | ); 50 | port ( 51 | -- general 52 | clock : in std_logic; 53 | reset : in std_logic; 54 | data_stream_in : in std_logic_vector(7 downto 0); 55 | data_stream_in_stb : in std_logic; 56 | data_stream_in_ack : out std_logic := '0'; 57 | data_stream_out : out std_logic_vector(7 downto 0); 58 | data_stream_out_stb : out std_logic; 59 | tx : out std_logic; 60 | rx : in std_logic 61 | ); 62 | end component; 63 | component top is 64 | generic ( 65 | baud : positive; 66 | clock_frequency : positive 67 | ); 68 | port ( 69 | clock_y3 : in std_logic; 70 | user_reset : in std_logic; 71 | usb_rs232_rxd : in std_logic; 72 | usb_rs232_txd : out std_logic 73 | ); 74 | end component; 75 | signal remote_clock : std_logic := '0'; 76 | signal remote_clock_int : std_logic := '0'; 77 | signal remote_data : std_logic_vector(7 downto 0); 78 | signal remote_data_in_stb : std_logic; 79 | signal remote_data_in_ack : std_logic; 80 | signal remote_data_out : std_logic_vector(7 downto 0); 81 | signal remote_data_out_stb : std_logic; 82 | signal remote_data_out_ack : std_logic; 83 | signal remote_tx : std_logic; 84 | signal remote_rx : std_logic; 85 | signal local_clock : std_logic := '0'; 86 | signal local_data : std_logic_vector(7 downto 0); 87 | signal local_data_in_stb : std_logic := '0'; 88 | signal local_data_in_ack : std_logic := '0'; 89 | signal local_data_out : std_logic_vector(7 downto 0); 90 | signal local_data_out_stb : std_logic; 91 | signal local_data_out_ack : std_logic; 92 | signal local_tx : std_logic; 93 | signal local_rx : std_logic; 94 | signal rx_count : integer := 0; 95 | signal tx_count : integer := 0; 96 | signal done : boolean := False; 97 | begin 98 | --------------------------------------------------------------------------- 99 | -- GENERATE LOCAL AND REMOTE CLOCKS 100 | --------------------------------------------------------------------------- 101 | local_clock_gen : process(local_clock) 102 | begin 103 | if not done then 104 | local_clock <= not local_clock after ( 105 | (1.0 / (2.0 * real(local_clock_hz))) * real(1e9) 106 | ) * 1 ns; 107 | end if; 108 | end process; 109 | remote_clock_gen : process(remote_clock_int) 110 | begin 111 | if not done then 112 | remote_clock_int <= not remote_clock_int after ( 113 | (1.0 / (2.0 * real(remote_clock_hz))) * real(1e9) 114 | ) * 1 ns; 115 | remote_clock <= transport remote_clock_int after delay_ns * 1 ns; 116 | end if; 117 | end process; 118 | --------------------------------------------------------------------------- 119 | -- READ/WRITE STIMULUS DATA FILES 120 | --------------------------------------------------------------------------- 121 | stim_parser : process 122 | constant input_path : string := "input.txt"; 123 | constant output_path : string := "output.txt"; 124 | file input_file : text; 125 | file output_file : text; 126 | variable data_line : line; 127 | variable output_line : line; 128 | variable status : file_open_status := status_error; 129 | variable data : bit_vector(7 downto 0); 130 | variable read_ok : boolean; 131 | variable first_call : boolean := false; 132 | begin 133 | if status /= open_ok then 134 | file_open(status, input_file, input_path, read_mode); 135 | assert (status = open_ok) 136 | report "Failed to open " & input_path 137 | severity failure; 138 | file_open(status, output_file, output_path, write_mode); 139 | assert (status = open_ok) 140 | report "Failed to open " & output_path 141 | severity failure; 142 | end if; 143 | 144 | if local_data_out_stb = '1' then 145 | write(output_line, to_bitvector(local_data_out)); 146 | writeline(output_file, output_line); 147 | rx_count <= rx_count + 1; 148 | end if; 149 | 150 | if not endfile(input_file) then 151 | if local_data_in_stb = '0' or local_data_in_ack = '1' then 152 | -- Get Data 153 | readline(input_file, data_line); 154 | read(data_line, data, read_ok); 155 | local_data <= to_stdlogicvector(data); 156 | local_data_in_stb <= '1'; 157 | tx_count <= tx_count + 1; 158 | end if; 159 | wait until rising_edge(local_clock); 160 | else 161 | if local_data_in_ack = '1' then 162 | local_data_in_stb <= '0'; 163 | end if; 164 | if rx_count = tx_count then 165 | report "Test complete, transmit " & integer'image(tx_count) & 166 | " byte(s) and received " & integer'image(rx_count) & 167 | " byte(s)"; 168 | done <= true; 169 | end if; 170 | wait until rising_edge(local_clock); 171 | end if; 172 | end process; 173 | -- If the test does not return data within a time limit then the system may 174 | -- not be functioning. Abort the test and report an error instead of 175 | -- continuing. 176 | watchdog : process(local_clock) 177 | constant timeout_reset : integer := 10e6; 178 | variable timeout : integer := timeout_reset; 179 | begin 180 | if rising_edge(local_clock) then 181 | if local_data_out_stb = '1' then 182 | timeout := timeout_reset; 183 | else 184 | timeout := timeout - 1; 185 | if timeout = 0 then 186 | report "Automatically aborting testbench because data" & 187 | " was not received for " & integer'image(timeout_reset) & 188 | " local clock cycles." severity failure; 189 | end if; 190 | end if; 191 | end if; 192 | end process; 193 | 194 | --------------------------------------------------------------------------- 195 | -- REMOTE UART 196 | --------------------------------------------------------------------------- 197 | remote_uart : top 198 | generic map( 199 | baud => baud, 200 | clock_frequency => remote_clock_hz 201 | ) 202 | port map( 203 | clock_y3 => remote_clock, 204 | user_reset => '0', 205 | usb_rs232_rxd => remote_rx, 206 | usb_rs232_txd => remote_tx 207 | ); 208 | --------------------------------------------------------------------------- 209 | -- LOCAL UART 210 | --------------------------------------------------------------------------- 211 | local_uart : uart 212 | generic map( 213 | baud => baud, 214 | clock_frequency => local_clock_hz 215 | ) 216 | port map( 217 | -- general 218 | clock => local_clock, 219 | reset => '0', 220 | data_stream_in => local_data, 221 | data_stream_in_stb => local_data_in_stb, 222 | data_stream_in_ack => local_data_in_ack, 223 | data_stream_out => local_data_out, 224 | data_stream_out_stb => local_data_out_stb, 225 | tx => local_tx, 226 | rx => local_rx 227 | ); 228 | -- Connect local and remote UART interfaces 229 | remote_rx <= local_tx; 230 | local_rx <= remote_tx; 231 | end beh; -------------------------------------------------------------------------------- /source/top.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- TOP 3 | -- This top level component is designed for the Spartan 6 LX9 Microboard 4 | ------------------------------------------------------------------------------- 5 | library ieee; 6 | use ieee.std_logic_1164.all; 7 | use ieee.numeric_std.all; 8 | 9 | entity top is 10 | generic ( 11 | baud : positive; 12 | clock_frequency : positive 13 | ); 14 | port ( 15 | clock_y3 : in std_logic; 16 | user_reset : in std_logic; 17 | usb_rs232_rxd : in std_logic; 18 | usb_rs232_txd : out std_logic 19 | ); 20 | end top; 21 | 22 | architecture rtl of top is 23 | component loopback is 24 | generic ( 25 | baud : positive; 26 | clock_frequency : positive 27 | ); 28 | port( 29 | clock : in std_logic; 30 | reset : in std_logic; 31 | rx : in std_logic; 32 | tx : out std_logic 33 | ); 34 | end component loopback; 35 | signal tx, rx, rx_sync, reset, reset_sync : std_logic; 36 | begin 37 | ---------------------------------------------------------------------------- 38 | -- Loopback instantiation 39 | ---------------------------------------------------------------------------- 40 | loopback_inst1 : loopback 41 | generic map ( 42 | baud => baud, 43 | clock_frequency => clock_frequency 44 | ) 45 | port map ( 46 | clock => clock_y3, 47 | reset => reset, 48 | rx => rx, 49 | tx => tx 50 | ); 51 | ---------------------------------------------------------------------------- 52 | -- Deglitch inputs 53 | ---------------------------------------------------------------------------- 54 | deglitch : process (clock_y3) 55 | begin 56 | if rising_edge(clock_y3) then 57 | rx_sync <= usb_rs232_rxd; 58 | rx <= rx_sync; 59 | reset_sync <= user_reset; 60 | reset <= reset_sync; 61 | usb_rs232_txd <= tx; 62 | end if; 63 | end process; 64 | end rtl; -------------------------------------------------------------------------------- /source/uart.ucf: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # This UCF file is designed for the Spartan 6 LX9 Microboard from Avnet 3 | ############################################################################### 4 | CONFIG VCCAUX=3.3; 5 | NET USB_RS232_RXD LOC = R7 | IOSTANDARD = LVCMOS33; # "USB_RS232_RXD" 6 | NET USB_RS232_TXD LOC = T7 | IOSTANDARD = LVCMOS33; # "USB_RS232_TXD" 7 | NET USER_RESET LOC = V4 | IOSTANDARD = LVCMOS33 | PULLDOWN; # "USER_RESET_N" 8 | NET USER_RESET TIG; 9 | NET CLOCK_Y3 LOC = C10 | IOSTANDARD = LVCMOS33; # "CLOCK_Y3" 10 | NET CLOCK_Y3 TNM_NET = CLOCK_Y3; 11 | TIMESPEC TS_CLOCK_Y3 = PERIOD CLOCK_Y3 100000 kHz; -------------------------------------------------------------------------------- /source/uart.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- UART 3 | -- Implements a universal asynchronous receiver transmitter 4 | ------------------------------------------------------------------------------- 5 | -- clock 6 | -- Input clock, must match frequency value given on clock_frequency 7 | -- generic input. 8 | -- reset 9 | -- Synchronous reset. 10 | -- data_stream_in 11 | -- Input data bus for bytes to transmit. 12 | -- data_stream_in_stb 13 | -- Input strobe to qualify the input data bus. 14 | -- data_stream_in_ack 15 | -- Output acknowledge to indicate the UART has begun sending the byte 16 | -- provided on the data_stream_in port. 17 | -- data_stream_out 18 | -- Data output port for received bytes. 19 | -- data_stream_out_stb 20 | -- Output strobe to qualify the received byte. Will be valid for one clock 21 | -- cycle only. 22 | -- tx 23 | -- Serial transmit. 24 | -- rx 25 | -- Serial receive 26 | ------------------------------------------------------------------------------- 27 | library ieee; 28 | use ieee.std_logic_1164.all; 29 | use ieee.numeric_std.all; 30 | use ieee.math_real.all; 31 | 32 | entity uart is 33 | generic ( 34 | baud : positive; 35 | clock_frequency : positive 36 | ); 37 | port ( 38 | clock : in std_logic; 39 | reset : in std_logic; 40 | data_stream_in : in std_logic_vector(7 downto 0); 41 | data_stream_in_stb : in std_logic; 42 | data_stream_in_ack : out std_logic; 43 | data_stream_out : out std_logic_vector(7 downto 0); 44 | data_stream_out_stb : out std_logic; 45 | tx : out std_logic; 46 | rx : in std_logic 47 | ); 48 | end uart; 49 | 50 | architecture rtl of uart is 51 | --------------------------------------------------------------------------- 52 | -- Baud generation constants 53 | --------------------------------------------------------------------------- 54 | constant c_tx_div : integer := clock_frequency / baud; 55 | constant c_rx_div : integer := clock_frequency / (baud * 16); 56 | constant c_tx_div_width : integer 57 | := integer(log2(real(c_tx_div))) + 1; 58 | constant c_rx_div_width : integer 59 | := integer(log2(real(c_rx_div))) + 1; 60 | --------------------------------------------------------------------------- 61 | -- Baud generation signals 62 | --------------------------------------------------------------------------- 63 | signal tx_baud_counter : unsigned(c_tx_div_width - 1 downto 0) 64 | := (others => '0'); 65 | signal tx_baud_tick : std_logic := '0'; 66 | signal rx_baud_counter : unsigned(c_rx_div_width - 1 downto 0) 67 | := (others => '0'); 68 | signal rx_baud_tick : std_logic := '0'; 69 | --------------------------------------------------------------------------- 70 | -- Transmitter signals 71 | --------------------------------------------------------------------------- 72 | type uart_tx_states is ( 73 | tx_send_start_bit, 74 | tx_send_data, 75 | tx_send_stop_bit 76 | ); 77 | signal uart_tx_state : uart_tx_states := tx_send_start_bit; 78 | signal uart_tx_data_vec : std_logic_vector(7 downto 0) := (others => '0'); 79 | signal uart_tx_data : std_logic := '1'; 80 | signal uart_tx_count : unsigned(2 downto 0) := (others => '0'); 81 | signal uart_rx_data_in_ack : std_logic := '0'; 82 | --------------------------------------------------------------------------- 83 | -- Receiver signals 84 | --------------------------------------------------------------------------- 85 | type uart_rx_states is ( 86 | rx_get_start_bit, 87 | rx_get_data, 88 | rx_get_stop_bit 89 | ); 90 | signal uart_rx_state : uart_rx_states := rx_get_start_bit; 91 | signal uart_rx_bit : std_logic := '1'; 92 | signal uart_rx_data_vec : std_logic_vector(7 downto 0) := (others => '0'); 93 | signal uart_rx_data_sr : std_logic_vector(1 downto 0) := (others => '1'); 94 | signal uart_rx_filter : unsigned(1 downto 0) := (others => '1'); 95 | signal uart_rx_count : unsigned(2 downto 0) := (others => '0'); 96 | signal uart_rx_data_out_stb : std_logic := '0'; 97 | signal uart_rx_bit_spacing : unsigned (3 downto 0) := (others => '0'); 98 | signal uart_rx_bit_tick : std_logic := '0'; 99 | begin 100 | -- Connect IO 101 | data_stream_in_ack <= uart_rx_data_in_ack; 102 | data_stream_out <= uart_rx_data_vec; 103 | data_stream_out_stb <= uart_rx_data_out_stb; 104 | tx <= uart_tx_data; 105 | --------------------------------------------------------------------------- 106 | -- OVERSAMPLE_CLOCK_DIVIDER 107 | -- generate an oversampled tick (baud * 16) 108 | --------------------------------------------------------------------------- 109 | oversample_clock_divider : process (clock) 110 | begin 111 | if rising_edge (clock) then 112 | if reset = '1' then 113 | rx_baud_counter <= (others => '0'); 114 | rx_baud_tick <= '0'; 115 | else 116 | if rx_baud_counter = c_rx_div then 117 | rx_baud_counter <= (others => '0'); 118 | rx_baud_tick <= '1'; 119 | else 120 | rx_baud_counter <= rx_baud_counter + 1; 121 | rx_baud_tick <= '0'; 122 | end if; 123 | end if; 124 | end if; 125 | end process oversample_clock_divider; 126 | --------------------------------------------------------------------------- 127 | -- RXD_SYNCHRONISE 128 | -- Synchronise rxd to the oversampled baud 129 | --------------------------------------------------------------------------- 130 | rxd_synchronise : process(clock) 131 | begin 132 | if rising_edge(clock) then 133 | if reset = '1' then 134 | uart_rx_data_sr <= (others => '1'); 135 | else 136 | if rx_baud_tick = '1' then 137 | uart_rx_data_sr(0) <= rx; 138 | uart_rx_data_sr(1) <= uart_rx_data_sr(0); 139 | end if; 140 | end if; 141 | end if; 142 | end process rxd_synchronise; 143 | --------------------------------------------------------------------------- 144 | -- RXD_FILTER 145 | -- Filter rxd with a 2 bit counter. 146 | --------------------------------------------------------------------------- 147 | rxd_filter : process(clock) 148 | begin 149 | if rising_edge(clock) then 150 | if reset = '1' then 151 | uart_rx_filter <= (others => '1'); 152 | uart_rx_bit <= '1'; 153 | else 154 | if rx_baud_tick = '1' then 155 | -- filter rxd. 156 | if uart_rx_data_sr(1) = '1' and uart_rx_filter < 3 then 157 | uart_rx_filter <= uart_rx_filter + 1; 158 | elsif uart_rx_data_sr(1) = '0' and uart_rx_filter > 0 then 159 | uart_rx_filter <= uart_rx_filter - 1; 160 | end if; 161 | -- set the rx bit. 162 | if uart_rx_filter = 3 then 163 | uart_rx_bit <= '1'; 164 | elsif uart_rx_filter = 0 then 165 | uart_rx_bit <= '0'; 166 | end if; 167 | end if; 168 | end if; 169 | end if; 170 | end process rxd_filter; 171 | --------------------------------------------------------------------------- 172 | -- RX_BIT_SPACING 173 | --------------------------------------------------------------------------- 174 | rx_bit_spacing : process (clock) 175 | begin 176 | if rising_edge(clock) then 177 | uart_rx_bit_tick <= '0'; 178 | if rx_baud_tick = '1' then 179 | if uart_rx_bit_spacing = 15 then 180 | uart_rx_bit_tick <= '1'; 181 | uart_rx_bit_spacing <= (others => '0'); 182 | else 183 | uart_rx_bit_spacing <= uart_rx_bit_spacing + 1; 184 | end if; 185 | if uart_rx_state = rx_get_start_bit then 186 | uart_rx_bit_spacing <= (others => '0'); 187 | end if; 188 | end if; 189 | end if; 190 | end process rx_bit_spacing; 191 | --------------------------------------------------------------------------- 192 | -- UART_RECEIVE_DATA 193 | --------------------------------------------------------------------------- 194 | uart_receive_data : process(clock) 195 | begin 196 | if rising_edge(clock) then 197 | if reset = '1' then 198 | uart_rx_state <= rx_get_start_bit; 199 | uart_rx_data_vec <= (others => '0'); 200 | uart_rx_count <= (others => '0'); 201 | uart_rx_data_out_stb <= '0'; 202 | else 203 | uart_rx_data_out_stb <= '0'; 204 | case uart_rx_state is 205 | when rx_get_start_bit => 206 | if rx_baud_tick = '1' and uart_rx_bit = '0' then 207 | uart_rx_state <= rx_get_data; 208 | end if; 209 | when rx_get_data => 210 | if uart_rx_bit_tick = '1' then 211 | uart_rx_data_vec(uart_rx_data_vec'high) 212 | <= uart_rx_bit; 213 | uart_rx_data_vec( 214 | uart_rx_data_vec'high-1 downto 0 215 | ) <= uart_rx_data_vec( 216 | uart_rx_data_vec'high downto 1 217 | ); 218 | if uart_rx_count < 7 then 219 | uart_rx_count <= uart_rx_count + 1; 220 | else 221 | uart_rx_count <= (others => '0'); 222 | uart_rx_state <= rx_get_stop_bit; 223 | end if; 224 | end if; 225 | when rx_get_stop_bit => 226 | if uart_rx_bit_tick = '1' then 227 | if uart_rx_bit = '1' then 228 | uart_rx_state <= rx_get_start_bit; 229 | uart_rx_data_out_stb <= '1'; 230 | end if; 231 | end if; 232 | when others => 233 | uart_rx_state <= rx_get_start_bit; 234 | end case; 235 | end if; 236 | end if; 237 | end process uart_receive_data; 238 | --------------------------------------------------------------------------- 239 | -- TX_CLOCK_DIVIDER 240 | -- Generate baud ticks at the required rate based on the input clock 241 | -- frequency and baud rate 242 | --------------------------------------------------------------------------- 243 | tx_clock_divider : process (clock) 244 | begin 245 | if rising_edge (clock) then 246 | if reset = '1' then 247 | tx_baud_counter <= (others => '0'); 248 | tx_baud_tick <= '0'; 249 | else 250 | if tx_baud_counter = c_tx_div then 251 | tx_baud_counter <= (others => '0'); 252 | tx_baud_tick <= '1'; 253 | else 254 | tx_baud_counter <= tx_baud_counter + 1; 255 | tx_baud_tick <= '0'; 256 | end if; 257 | end if; 258 | end if; 259 | end process tx_clock_divider; 260 | --------------------------------------------------------------------------- 261 | -- UART_SEND_DATA 262 | -- Get data from data_stream_in and send it one bit at a time upon each 263 | -- baud tick. Send data lsb first. 264 | -- wait 1 tick, send start bit (0), send data 0-7, send stop bit (1) 265 | --------------------------------------------------------------------------- 266 | uart_send_data : process(clock) 267 | begin 268 | if rising_edge(clock) then 269 | if reset = '1' then 270 | uart_tx_data <= '1'; 271 | uart_tx_data_vec <= (others => '0'); 272 | uart_tx_count <= (others => '0'); 273 | uart_tx_state <= tx_send_start_bit; 274 | uart_rx_data_in_ack <= '0'; 275 | else 276 | uart_rx_data_in_ack <= '0'; 277 | case uart_tx_state is 278 | when tx_send_start_bit => 279 | if tx_baud_tick = '1' and data_stream_in_stb = '1' then 280 | uart_tx_data <= '0'; 281 | uart_tx_state <= tx_send_data; 282 | uart_tx_count <= (others => '0'); 283 | uart_rx_data_in_ack <= '1'; 284 | uart_tx_data_vec <= data_stream_in; 285 | end if; 286 | when tx_send_data => 287 | if tx_baud_tick = '1' then 288 | uart_tx_data <= uart_tx_data_vec(0); 289 | uart_tx_data_vec( 290 | uart_tx_data_vec'high-1 downto 0 291 | ) <= uart_tx_data_vec( 292 | uart_tx_data_vec'high downto 1 293 | ); 294 | if uart_tx_count < 7 then 295 | uart_tx_count <= uart_tx_count + 1; 296 | else 297 | uart_tx_count <= (others => '0'); 298 | uart_tx_state <= tx_send_stop_bit; 299 | end if; 300 | end if; 301 | when tx_send_stop_bit => 302 | if tx_baud_tick = '1' then 303 | uart_tx_data <= '1'; 304 | uart_tx_state <= tx_send_start_bit; 305 | end if; 306 | when others => 307 | uart_tx_data <= '1'; 308 | uart_tx_state <= tx_send_start_bit; 309 | end case; 310 | end if; 311 | end if; 312 | end process uart_send_data; 313 | end rtl; -------------------------------------------------------------------------------- /source/uart_unit_tests.py: -------------------------------------------------------------------------------- 1 | import random 2 | import os 3 | import re 4 | from chiptools.testing.testloader import ChipToolsTest 5 | import traceback 6 | 7 | base = os.path.dirname(__file__) 8 | 9 | 10 | class UartTestBase(ChipToolsTest): 11 | duration = 0 12 | generics = {} 13 | entity = 'tb_uart' 14 | library = 'lib_tb_uart' 15 | project = os.path.join(base, '..', 'uart.xml') 16 | 17 | def setUp(self): 18 | """Place any code that is required to prepare simulator inputs in this 19 | method.""" 20 | # Set the paths for the input and output files using the 21 | # 'simulation_root' attribute as the working directory 22 | self.input_path = os.path.join(self.simulation_root, 'input.txt') 23 | self.output_path = os.path.join(self.simulation_root, 'output.txt') 24 | 25 | def check_output(self, path, values): 26 | output_values = [] 27 | with open(path, 'r') as f: 28 | data = f.readlines() 29 | for valueIdx, value in enumerate(data): 30 | # testbench response 31 | output_values.append(int(value, 2)) # Binary to integer 32 | 33 | # Compare the expected result to what the Testbench returned: 34 | self.assertListEqual(output_values, values) 35 | 36 | def tearDown(self): 37 | # Remove files generated by the test 38 | os.remove(self.input_path) 39 | os.remove(self.output_path) 40 | 41 | def write_stimulus(self, path, values): 42 | # Write the values to the testbench input file 43 | with open(path, 'w') as f: 44 | for value in values: 45 | f.write('{0}\n'.format(bin(value)[2:].zfill(8))) 46 | 47 | def run_and_check( 48 | self, values, baud, local_clock, remote_clock, delay_ns 49 | ): 50 | """Prepare the simulation environment and run the simulation.""" 51 | self.generics = { 52 | 'baud': int(baud), 53 | 'remote_clock_hz': int(remote_clock), 54 | 'local_clock_hz': int(local_clock), 55 | } 56 | # Write the stimulus file to be used by the testbench 57 | self.write_stimulus(self.input_path, values) 58 | # Run the simulation 59 | return_code, stdout, stderr = self.simulate() 60 | self.assertEqual(return_code, 0) 61 | # Check output 62 | self.check_output(self.output_path, values) 63 | self.assertIsNone(re.search('.*Error:.*', stdout)) 64 | 65 | def generic_random_data_test( 66 | self, 67 | n, 68 | baud=115200, 69 | local_clock=100e6, 70 | remote_clock=100e6, 71 | delay_ns=0 72 | ): 73 | self.run_and_check( 74 | values=[random.randint(0, 2**8-1) for i in range(n)], 75 | baud=baud, 76 | local_clock=local_clock, 77 | remote_clock=remote_clock, 78 | delay_ns=delay_ns 79 | ) 80 | 81 | def generic_static_data_test( 82 | self, 83 | n, 84 | data, 85 | baud=115200, 86 | local_clock=100e6, 87 | remote_clock=100e6, 88 | delay_ns=0 89 | ): 90 | self.run_and_check( 91 | values=[data for i in range(n)], 92 | baud=baud, 93 | local_clock=local_clock, 94 | remote_clock=remote_clock, 95 | delay_ns=delay_ns 96 | ) 97 | 98 | 99 | class UartRandomDataTests(UartTestBase): 100 | 101 | def test_random_data_115200baud(self): 102 | """Check UART with a 115200 baud rate with 2000 random bytes.""" 103 | self.generic_random_data_test(2000) 104 | 105 | def test_random_data_230400baud(self): 106 | """Check UART with a 230400 baud rate with 2000 random bytes.""" 107 | self.generic_random_data_test(2000, baud=230400) 108 | 109 | def test_random_data_460800baud(self): 110 | """Check UART with a 460800 baud rate with 2000 random bytes.""" 111 | self.generic_random_data_test(2000, baud=460800) 112 | 113 | def test_random_data_921600baud(self): 114 | """Check UART with a 921600 baud rate with 2000 random bytes.""" 115 | self.generic_random_data_test(2000, baud=921600) 116 | 117 | def test_random_data_4800baud(self): 118 | """Check UART with a 4800 baud rate with 20 random bytes.""" 119 | self.generic_random_data_test(20, baud=4800) 120 | 121 | def test_random_data_9600baud(self): 122 | """Check UART with a 9600 baud rate with 20 random bytes.""" 123 | self.generic_random_data_test(20, baud=9600) 124 | 125 | def test_random_data_19200baud(self): 126 | """Check UART with a 19200 baud rate with 20 random bytes.""" 127 | self.generic_random_data_test(20, baud=19200) 128 | 129 | def test_random_data_38400baud(self): 130 | """Check UART with a 38400 baud rate with 20 random bytes.""" 131 | self.generic_random_data_test(20, baud=38400) 132 | 133 | def test_random_data_115200_baud_60MHz_local_32MHz_remote(self): 134 | """Check UART with a 60MHz local clock and a 32MHz remote clock.""" 135 | self.generic_random_data_test( 136 | 2500, 137 | baud=115200, 138 | local_clock=60e6, 139 | remote_clock=32e6 140 | ) 141 | 142 | def test_random_data_115200_baud_100MHz_local_125MHz_remote(self): 143 | """Check UART with a 100MHz local clock and a 125MHz remote clock.""" 144 | self.generic_random_data_test( 145 | 2500, 146 | baud=115200, 147 | local_clock=100e6, 148 | remote_clock=125e6 149 | ) 150 | 151 | def test_random_data_115200_baud_32MHz_local_125MHz_remote(self): 152 | """Check UART with a 32MHz local clock and a 125MHz remote clock.""" 153 | self.generic_random_data_test( 154 | 2500, 155 | baud=115200, 156 | local_clock=32e6, 157 | remote_clock=125e6 158 | ) 159 | 160 | def test_random_data_115200_baud_100MHz_local_32MHz_remote(self): 161 | """Check UART with a 100MHz local clock and a 32MHz remote clock.""" 162 | self.generic_random_data_test( 163 | 2500, 164 | baud=115200, 165 | local_clock=100e6, 166 | remote_clock=32e6 167 | ) 168 | 169 | def test_power_of_2_divisor_baud_115200_random_data(self): 170 | """Check UART when the RX and TX dividers are a power of 2""" 171 | self.generic_random_data_test( 172 | 2500, 173 | baud=115200, 174 | local_clock=117.9648e6, 175 | remote_clock=117.9648e6 176 | ) 177 | 178 | 179 | class UartStaticDataTests(UartTestBase): 180 | 181 | def test_static_0x00_data_921600_baud(self): 182 | """Check UART with a 921600 baud rate with 250 0x00 bytes""" 183 | self.generic_static_data_test(250, data=0x00, baud=921600) 184 | 185 | def test_static_0x55_data_921600_baud(self): 186 | """Check UART with a 921600 baud rate with 250 0x55 bytes""" 187 | self.generic_static_data_test(250, data=0x55, baud=921600) 188 | 189 | def test_static_0xAA_data_921600_baud(self): 190 | """Check UART with a 921600 baud rate with 250 0xAA bytes""" 191 | self.generic_static_data_test(250, data=0xAA, baud=921600) 192 | 193 | def test_static_0xFF_data_921600_baud(self): 194 | """Check UART with a 921600 baud rate with 250 0xFF bytes""" 195 | self.generic_static_data_test(250, data=0xFF, baud=921600) 196 | 197 | def test_static_0xFF_data_4800_baud(self): 198 | """Check UART with a 4800 baud rate with 1 0xFF byte""" 199 | self.generic_static_data_test(1, data=0xFF, baud=4800) 200 | 201 | def test_static_0xFF_data_9600_baud(self): 202 | """Check UART with a 9600 baud rate with 1 0xFF byte""" 203 | self.generic_static_data_test(1, data=0xFF, baud=9600) 204 | 205 | def test_static_0xFF_data_19200_baud(self): 206 | """Check UART with a 19200 baud rate with 1 0xFF byte""" 207 | self.generic_static_data_test(1, data=0xFF, baud=19200) 208 | 209 | def test_static_0xFF_data_38400_baud(self): 210 | """Check UART with a 38400 baud rate with 1 0xFF byte""" 211 | self.generic_static_data_test(1, data=0xFF, baud=38400) 212 | 213 | def test_static_0xAA_data_4800_baud(self): 214 | """Check UART with a 4800 baud rate with 1 0xAA byte""" 215 | self.generic_static_data_test(1, data=0xAA, baud=4800) 216 | 217 | def test_static_0xAA_data_9600_baud(self): 218 | """Check UART with a 9600 baud rate with 1 0xAA byte""" 219 | self.generic_static_data_test(1, data=0xAA, baud=9600) 220 | 221 | def test_static_0xAA_data_19200_baud(self): 222 | """Check UART with a 19200 baud rate with 1 0xAA byte""" 223 | self.generic_static_data_test(1, data=0xAA, baud=19200) 224 | 225 | def test_static_0xAA_data_38400_baud(self): 226 | """Check UART with a 38400 baud rate with 1 0xAA byte""" 227 | self.generic_static_data_test(1, data=0xAA, baud=38400) 228 | -------------------------------------------------------------------------------- /synthesis/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /uart.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------