Browse Source

Add uart_loop design to test gatemate fifo & ram primitives

main
T. Meissner 1 year ago
parent
commit
3cfa3cc72e
11 changed files with 1070 additions and 37 deletions
  1. +32
    -32
      lib/rtl_components.vhd
  2. +386
    -4
      lib/user_components.vhd
  3. +126
    -0
      uart_loop/rtl/uart_loop.vhd
  4. +105
    -0
      uart_loop/rtl/uart_rx.vhd
  5. +102
    -0
      uart_loop/rtl/uart_tx.vhd
  6. +30
    -0
      uart_loop/sim/Makefile
  7. +96
    -0
      uart_loop/sim/tb_uart_loop.vhd
  8. +51
    -0
      uart_loop/syn/Makefile
  9. +125
    -0
      uart_loop/syn/tb_uart_loop.v
  10. +16
    -0
      uart_loop/syn/uart_loop.ccf
  11. +1
    -1
      uart_reg/syn/uart_reg.ccf

+ 32
- 32
lib/rtl_components.vhd View File

@ -129,30 +129,23 @@ package components is
component CC_FIFO_40K
generic (
-- Location format: D(0..N-1)X(0..3)Y(0..7) or UNPLACED
LOC : string := "UNPLACED";
-- Offset configuration
ALMOST_FULL_OFFSET : std_logic_vector (12 downto 0) := (others => '0');
ALMOST_EMPTY_OFFSET : std_logic_vector (12 downto 0) := (others => '0');
-- Port Widths
A_WIDTH : natural := 0;
B_WIDTH : natural := 0;
-- RAM and Write Modes
RAM_MODE : string := "SDP"; -- "TPD" or "SDP"
FIFO_MODE : string := "SYNC"; -- "ASYNC" or "SYNC"
-- Inverting Control Pins
A_CLK_INV : std_logic := '0';
B_CLK_INV : std_logic := '0';
A_EN_INV : std_logic := '0';
B_EN_INV : std_logic := '0';
A_WE_INV : std_logic := '0';
B_WE_INV : std_logic := '0';
-- Output Register
A_DO_REG : std_logic := '0';
B_DO_REG : std_logic := '0';
-- Error Checking and Correction
A_ECC_EN : std_logic := '0';
B_ECC_EN : std_logic := '0'
LOC : string := "UNPLACED"; -- Location format: D(0..N-1)X(0..3)Y(0..7) or UNPLACED
ALMOST_FULL_OFFSET : std_logic_vector (12 downto 0) := (others => '0'); -- Almost full offset
ALMOST_EMPTY_OFFSET : std_logic_vector (12 downto 0) := (others => '0'); -- Almost empty offset
A_WIDTH : natural := 0; -- Port A Width
B_WIDTH : natural := 0; -- Port B Width
RAM_MODE : string := "SDP"; -- RAM mode: "TPD" or "SDP"
FIFO_MODE : string := "SYNC"; -- Write mode: "ASYNC" or "SYNC"
A_CLK_INV : std_logic := '0'; -- Inverting Control Pins
B_CLK_INV : std_logic := '0'; -- Inverting Control Pins
A_EN_INV : std_logic := '0'; -- Inverting Control Pins
B_EN_INV : std_logic := '0'; -- Inverting Control Pins
A_WE_INV : std_logic := '0'; -- Inverting Control Pins
B_WE_INV : std_logic := '0'; -- Inverting Control Pins
A_DO_REG : std_logic := '0'; -- Port A Output Register
B_DO_REG : std_logic := '0'; -- Port B Output Register
A_ECC_EN : std_logic := '0'; -- Port A Error Checking and Correction
B_ECC_EN : std_logic := '0' -- Port B Error Checking and Correction
);
port (
A_ECC_1B_ERR : out std_logic;
@ -179,14 +172,14 @@ package components is
F_ALMOST_FULL_OFFSET : in std_logic_vector(12 downto 0);
F_ALMOST_EMPTY_OFFSET : in std_logic_vector(12 downto 0);
-- FIFO status signals
F_FULL : out std_logic;
F_EMPTY : out std_logic;
F_ALMOST_FULL : out std_logic;
F_ALMOST_EMPTY: out std_logic;
F_RD_ERROR : out std_logic;
F_WR_ERROR : out std_logic;
F_RD_PTR : out std_logic_vector(15 downto 0);
F_WR_PTR : out std_logic_vector(15 downto 0)
F_FULL : out std_logic;
F_EMPTY : out std_logic;
F_ALMOST_FULL : out std_logic;
F_ALMOST_EMPTY : out std_logic;
F_RD_ERROR : out std_logic;
F_WR_ERROR : out std_logic;
F_RD_PTR : out std_logic_vector(15 downto 0);
F_WR_PTR : out std_logic_vector(15 downto 0)
);
end component;
@ -196,5 +189,12 @@ package components is
);
end component;
component CC_BUFG
port (
I : in std_logic;
O : out std_logic
);
end component;
end package components;

+ 386
- 4
lib/user_components.vhd View File

@ -1,13 +1,14 @@
library ieee ;
use ieee.std_logic_1164.all;
-- Async reset synchronizer circuit inspired from
-- Chris Cummings SNUG 2002 paper
-- Synchronous Resets? Asynchronous Resets?
-- I am so confused!
-- How will I ever know which to use?
library ieee ;
use ieee.std_logic_1164.all;
entity reset_sync is
generic (
POLARITY : std_logic := '0'
@ -38,3 +39,384 @@ begin
rst_o <= s_rst_d(1);
end architecture;
-- Async reset synchronizer circuit inspired from
-- Chris Cummings SNUG 2002 paper
-- Synchronous Resets? Asynchronous Resets?
-- I am so confused!
-- How will I ever know which to use?
library ieee ;
use ieee.std_logic_1164.all;
entity reset_sync_slv is
generic (
POLARITY : std_logic := '0'
);
port (
clk_i : in std_logic;
rst_i : in std_logic_vector;
rst_o : out std_logic_vector
);
end entity;
architecture sim of reset_sync_slv is
begin
GEN : for i in rst_i'range generate
signal s_rst_d : std_logic_vector(1 downto 0);
begin
process (clk_i, rst_i(i)) is
begin
if (rst_i(i) = POLARITY) then
s_rst_d <= (others => POLARITY);
elsif (rising_edge(clk_i)) then
s_rst_d <= s_rst_d(0) & not POLARITY;
end if;
end process;
rst_o(i) <= s_rst_d(1);
end generate;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fifo is
generic (
DEPTH : positive := 16;
WIDTH : positive := 16
);
port (
rst_n_i : in std_logic;
clk_i : in std_logic;
-- write
wen_i : in std_logic;
din_i : in std_logic_vector(WIDTH-1 downto 0);
full_o : out std_logic;
werror_o : out std_logic;
-- read
ren_i : in std_logic;
dout_o : out std_logic_vector(WIDTH-1 downto 0);
empty_o : out std_logic;
rerror_o : out std_logic
);
end entity fifo;
architecture rtl of fifo is
subtype t_fifo_pnt is natural range 0 to DEPTH-1;
signal s_write_pnt : t_fifo_pnt;
signal s_read_pnt : t_fifo_pnt;
type t_fifo_mem is array (t_fifo_pnt'low to t_fifo_pnt'high) of std_logic_vector(din_i'range);
signal s_fifo_mem : t_fifo_mem;
signal s_almost_full : boolean;
signal s_almost_empty : boolean;
function incr_pnt (data : t_fifo_pnt) return t_fifo_pnt is
begin
if (data = t_fifo_mem'high) then
return 0;
end if;
return data + 1;
end function incr_pnt;
begin
s_almost_full <= (s_write_pnt = s_read_pnt - 1) or
(s_write_pnt = t_fifo_mem'high and s_read_pnt = t_fifo_mem'low);
s_almost_empty <= (s_read_pnt = s_write_pnt - 1) or
(s_read_pnt = t_fifo_mem'high and s_write_pnt = t_fifo_mem'low);
WriteP : process (rst_n_i, clk_i) is
begin
if (not rst_n_i) then
s_write_pnt <= 0;
werror_o <= '0';
elsif (rising_edge(clk_i)) then
werror_o <= Wen_i and Full_o;
if (Wen_i = '1' and Full_o = '0') then
s_fifo_mem(s_write_pnt) <= Din_i;
s_write_pnt <= incr_pnt(s_write_pnt);
end if;
end if;
end process WriteP;
ReadP : process (rst_n_i, clk_i) is
begin
if (not rst_n_i) then
s_read_pnt <= 0;
rerror_o <= '0';
elsif (rising_edge(clk_i)) then
rerror_o <= Ren_i and Empty_o;
if (Ren_i = '1' and Empty_o = '0') then
Dout_o <= s_fifo_mem(s_read_pnt);
s_read_pnt <= incr_pnt(s_read_pnt);
end if;
end if;
end process ReadP;
FlagsP : process (rst_n_i, clk_i) is
begin
if (rst_n_i = '0') then
Full_o <= '0';
Empty_o <= '1';
elsif (rising_edge(clk_i)) then
if (Wen_i = '1') then
if (Ren_i = '0' and s_almost_full) then
Full_o <= '1';
end if;
Empty_o <= '0';
end if;
if (Ren_i = '1') then
if (Wen_i = '0' and s_almost_empty) then
Empty_o <= '1';
end if;
Full_o <= '0';
end if;
end if;
end process FlagsP;
end architecture;
-- Synchronous AXI stream FIFO based on generic fifo
-- component. Configurable depth and width.
library ieee ;
use ieee.std_logic_1164.all;
library gatemate;
use gatemate.components.all;
entity axis_fifo is
generic (
DEPTH : positive := 8;
WIDTH : positive := 8
);
port (
-- global
rst_n_i : in std_logic;
clk_i : in std_logic;
-- axis in
tdata_i : in std_logic_vector(WIDTH-1 downto 0);
tvalid_i : in std_logic;
tready_o : out std_logic;
-- axis aout
tdata_o : out std_logic_vector(WIDTH-1 downto 0);
tvalid_o : out std_logic;
tready_i : in std_logic
);
end entity;
architecture rtl of axis_fifo is
signal s_fifo_wen : std_logic;
signal s_fifo_ren : std_logic;
signal s_fifo_empty : std_logic;
signal s_fifo_full : std_logic;
signal s_fwft_empty : std_logic;
signal s_ren : std_logic;
begin
fifo : entity work.fifo
generic map (
DEPTH => DEPTH,
WIDTH => WIDTH
)
port map (
rst_n_i => rst_n_i,
clk_i => clk_i,
-- write
wen_i => s_fifo_wen,
din_i => tdata_i,
full_o => s_fifo_full,
werror_o => open,
-- read
ren_i => s_fifo_ren,
dout_o => tdata_o,
empty_o => s_fifo_empty,
rerror_o => open
);
-- FWFT logic
process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_fwft_empty <= '1';
elsif (rising_edge(clk_i)) then
if (s_fifo_ren) then
s_fwft_empty <= '0';
elsif (s_ren) then
s_fwft_empty <= '1';
end if;
end if;
end process;
s_fifo_ren <= not s_fifo_empty and (s_fwft_empty or s_ren);
-- AXIS logic
s_fifo_wen <= tvalid_i and not s_fifo_full;
s_ren <= tready_i and not s_fwft_empty;
tready_o <= not s_fifo_full;
tvalid_o <= not s_fwft_empty;
end architecture;
-- Synchronous AXI stream FIFO based on GateMate CC_FIFO_40K
-- primitive
library ieee ;
use ieee.std_logic_1164.all;
library gatemate;
use gatemate.components.all;
entity axis_fifo_gm is
generic (
WIDTH : positive := 8
);
port (
-- global
rst_n_i : in std_logic;
clk_i : in std_logic;
-- axis in
tdata_i : in std_logic_vector(WIDTH-1 downto 0);
tvalid_i : in std_logic;
tready_o : out std_logic;
-- axis aout
tdata_o : out std_logic_vector(WIDTH-1 downto 0);
tvalid_o : out std_logic;
tready_i : in std_logic
);
end entity;
architecture rtl of axis_fifo_gm is
signal s_fifo_wen : std_logic;
signal s_fifo_ren : std_logic;
signal s_fifo_empty : std_logic;
signal s_fifo_full : std_logic;
signal s_fwft_empty : std_logic;
signal s_ren : std_logic;
signal s_fifo_a_en : std_logic;
signal s_fifo_b_en : std_logic;
signal s_fifo_b_we : std_logic;
signal s_fifo_din : std_logic_vector(79 downto 0);
signal s_fifo_dout : std_logic_vector(79 downto 0);
begin
-- CC_FIFO_40K instance (512x80)
fifo : CC_FIFO_40K
generic map (
LOC => "UNPLACED",
ALMOST_FULL_OFFSET => (others => '0'),
ALMOST_EMPTY_OFFSET => (others => '0'),
A_WIDTH => WIDTH, -- 1..80
B_WIDTH => WIDTH, -- 1..80
RAM_MODE => "SDP",
FIFO_MODE => "SYNC",
A_CLK_INV => '0',
B_CLK_INV => '0',
A_EN_INV => '0',
B_EN_INV => '0',
A_WE_INV => '0',
B_WE_INV => '0',
A_DO_REG => '0',
B_DO_REG => '0',
A_ECC_EN => '0',
B_ECC_EN => '0'
)
port map(
A_ECC_1B_ERR => open,
B_ECC_1B_ERR => open,
A_ECC_2B_ERR => open,
B_ECC_2B_ERR => open,
-- FIFO pop port
A_DO => s_fifo_dout(39 downto 0),
B_DO => s_fifo_dout(79 downto 40),
A_CLK => clk_i,
A_EN => s_fifo_a_en,
-- FIFO push port
A_DI => s_fifo_din(39 downto 0),
B_DI => s_fifo_din(79 downto 40),
A_BM => (others => '1'),
B_BM => (others => '1'),
B_CLK => clk_i,
B_EN => s_fifo_b_en,
B_WE => s_fifo_b_we,
-- FIFO control
F_RST_N => rst_n_i,
F_ALMOST_FULL_OFFSET => (others => '0'),
F_ALMOST_EMPTY_OFFSET => (others => '0'),
-- FIFO status signals
F_FULL => s_fifo_full,
F_EMPTY => s_fifo_empty,
F_ALMOST_FULL => open,
F_ALMOST_EMPTY => open,
F_RD_ERROR => open,
F_WR_ERROR => open,
F_RD_PTR => open,
F_WR_PTR => open
);
s_fifo_b_en <= s_fifo_wen;
s_fifo_b_we <= s_fifo_wen;
s_fifo_a_en <= s_fifo_ren;
-- FWFT logic
process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_fwft_empty <= '1';
elsif (rising_edge(clk_i)) then
if (s_fifo_ren) then
s_fwft_empty <= '0';
elsif (s_ren) then
s_fwft_empty <= '1';
end if;
end if;
end process;
s_fifo_ren <= not s_fifo_empty and (s_fwft_empty or s_ren);
-- AXIS logic
s_fifo_wen <= tvalid_i and not s_fifo_full;
s_ren <= tready_i and not s_fwft_empty;
tready_o <= not s_fifo_full;
s_fifo_din(tdata_i'range) <= tdata_i;
tvalid_o <= not s_fwft_empty;
tdata_o <= s_fifo_dout(tdata_o'range);
end architecture;

+ 126
- 0
uart_loop/rtl/uart_loop.vhd View File

@ -0,0 +1,126 @@
-- This design implements a register file which can
-- be accessed by an UART with 9600 baud
--
-- See into uart_ctrl.vhd for documentation of the protocol
-- used to read / write the register file.
library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library gatemate;
use gatemate.components.all;
entity uart_loop is
port (
clk_i : in std_logic; -- 10 MHz clock
rst_n_i : in std_logic; -- SW3 button
uart_rx_i : in std_logic; -- PMODA IO3
uart_tx_o : out std_logic -- PMODA IO5
);
end entity uart_loop;
architecture rtl of uart_loop is
signal s_pll_clk : std_logic;
signal s_pll_lock : std_logic;
signal s_rst_n : std_logic;
signal s_cfg_end : std_logic;
signal s_uart_rx_tdata : std_logic_vector(7 downto 0);
signal s_uart_rx_tvalid : std_logic;
signal s_uart_rx_tready : std_logic;
signal s_uart_tx_tdata : std_logic_vector(7 downto 0);
signal s_uart_tx_tvalid : std_logic;
signal s_uart_tx_tready : std_logic;
begin
pll : CC_PLL
generic map (
REF_CLK => "10",
OUT_CLK => "1",
PERF_MD => "ECONOMY"
)
port map (
CLK_REF => clk_i,
CLK_FEEDBACK => '0',
USR_CLK_REF => '0',
USR_LOCKED_STDY_RST => '0',
USR_PLL_LOCKED_STDY => open,
USR_PLL_LOCKED => s_pll_lock,
CLK270 => open,
CLK180 => open,
CLK0 => s_pll_clk,
CLK90 => open,
CLK_REF_OUT => open
);
cfg_end_inst : CC_CFG_END
port map (
CFG_END => s_cfg_end
);
uart_rx : entity work.uart_rx
generic map (
CLK_DIV => 104
)
port map (
-- globals
rst_n_i => s_rst_n,
clk_i => s_pll_clk,
-- axis user interface
tdata_o => s_uart_rx_tdata,
tvalid_o => s_uart_rx_tvalid,
tready_i => s_uart_rx_tready,
-- uart interface
rx_i => uart_rx_i
);
axis_fifo : entity work.axis_fifo
generic map (
DEPTH => 64,
WIDTH => 8
)
port map (
-- globals
rst_n_i => s_rst_n,
clk_i => s_pll_clk,
-- uart rx interface
tdata_i => s_uart_rx_tdata,
tvalid_i => s_uart_rx_tvalid,
tready_o => s_uart_rx_tready,
-- uart tx interface
tdata_o => s_uart_tx_tdata,
tvalid_o => s_uart_tx_tvalid,
tready_i => s_uart_tx_tready
);
-- s_uart_tx_tdata <= s_uart_rx_tdata;
-- s_uart_tx_tvalid <= s_uart_rx_tvalid;
-- s_uart_rx_tready <= s_uart_tx_tready;
uart_tx : entity work.uart_tx
generic map (
CLK_DIV => 104
)
port map (
-- globals
rst_n_i => s_rst_n,
clk_i => s_pll_clk,
-- axis user interface
tdata_i => s_uart_tx_tdata,
tvalid_i => s_uart_tx_tvalid,
tready_o => s_uart_tx_tready,
-- uart interface
tx_o => uart_tx_o
);
s_rst_n <= rst_n_i and s_pll_lock and s_cfg_end;
end architecture;

+ 105
- 0
uart_loop/rtl/uart_rx.vhd View File

@ -0,0 +1,105 @@
-- Copyright (c) 2022 by Torsten Meissner
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- https://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity uart_rx is
generic (
CLK_DIV : natural := 10
);
port (
-- globals
rst_n_i : in std_logic;
clk_i : in std_logic;
-- axis user interface
tdata_o : out std_logic_vector(7 downto 0);
tvalid_o : out std_logic;
tready_i : in std_logic;
-- uart interface
rx_i : in std_logic
);
end entity uart_rx;
architecture rtl of uart_rx is
type t_uart_state is (IDLE, RECEIVE, VALID);
signal s_uart_state : t_uart_state;
signal s_clk_en : std_logic;
signal s_clk_cnt : natural range 0 to CLK_DIV-1;
signal s_bit_cnt : natural range 0 to tdata_o'length+1;
signal s_rx_d : std_logic_vector(3 downto 0);
begin
ClkDivP : process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_clk_cnt <= CLK_DIV-1;
elsif (rising_edge(clk_i)) then
if (s_uart_state = IDLE) then
s_clk_cnt <= CLK_DIV-2;
elsif (s_uart_state = RECEIVE) then
if (s_clk_cnt = 0) then
s_clk_cnt <= CLK_DIV-1;
else
s_clk_cnt <= s_clk_cnt - 1;
end if;
end if;
end if;
end process ClkDivP;
s_clk_en <= '1' when s_uart_state = RECEIVE and s_clk_cnt = CLK_DIV/2-1 else '0';
RxP : process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_uart_state <= IDLE;
tdata_o <= (others => '0');
s_rx_d <= x"1";
s_bit_cnt <= 0;
elsif (rising_edge(clk_i)) then
s_rx_d <= s_rx_d(2 downto 0) & rx_i;
FsmL : case s_uart_state is
when IDLE =>
s_bit_cnt <= tdata_o'length+1;
if (s_rx_d = "1000") then
s_uart_state <= RECEIVE;
end if;
when RECEIVE =>
if (s_clk_en) then
if (s_bit_cnt = 0) then
s_uart_state <= VALID;
else
tdata_o <= s_rx_d(3) & tdata_o(tdata_o'length-1 downto 1);
s_bit_cnt <= s_bit_cnt - 1;
end if;
end if;
when VALID =>
if (tready_i) then
s_uart_state <= IDLE;
end if;
end case;
end if;
end process RxP;
tvalid_o <= '1' when s_uart_state = VALID else '0';
end architecture rtl;

+ 102
- 0
uart_loop/rtl/uart_tx.vhd View File

@ -0,0 +1,102 @@
-- Copyright (c) 2022 by Torsten Meissner
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- https://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity uart_tx is
generic (
CLK_DIV : natural := 10
);
port (
-- globals
rst_n_i : in std_logic;
clk_i : in std_logic;
-- axis user interface
tdata_i : in std_logic_vector(7 downto 0);
tvalid_i : in std_logic;
tready_o : out std_logic;
-- uart interface
tx_o : out std_logic
);
end entity uart_tx;
architecture rtl of uart_tx is
type t_uart_state is (IDLE, SEND);
signal s_uart_state : t_uart_state;
signal s_data : std_logic_vector(tdata_i'length+1 downto 0);
signal s_clk_cnt : natural range 0 to CLK_DIV-1;
signal s_clk_en : std_logic;
signal s_bit_cnt : natural range 0 to s_data'length-1;
begin
ClkDivP : process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_clk_cnt <= CLK_DIV-1;
elsif (rising_edge(clk_i)) then
if (s_uart_state = IDLE) then
s_clk_cnt <= CLK_DIV-2;
elsif (s_uart_state = SEND) then
if (s_clk_cnt = 0) then
s_clk_cnt <= CLK_DIV-1;
else
s_clk_cnt <= s_clk_cnt - 1;
end if;
end if;
end if;
end process ClkDivP;
s_clk_en <= '1' when s_uart_state = SEND and s_clk_cnt = 0 else '0';
TxP : process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_uart_state <= IDLE;
s_data <= (0 => '1', others => '0');
s_bit_cnt <= 0;
elsif (rising_edge(clk_i)) then
FsmL : case s_uart_state is
when IDLE =>
s_bit_cnt <= s_data'length-1;
if (tvalid_i) then
s_data <= '1' & tdata_i & '0';
s_uart_state <= SEND;
end if;
when SEND =>
if (s_clk_en) then
s_data <= '1' & s_data(s_data'length-1 downto 1);
if (s_bit_cnt = 0) then
s_uart_state <= IDLE;
else
s_bit_cnt <= s_bit_cnt - 1;
end if;
end if;
end case;
end if;
end process TxP;
tready_o <= '1' when s_uart_state = IDLE else '0';
tx_o <= s_data(0);
end architecture rtl;

+ 30
- 0
uart_loop/sim/Makefile View File

@ -0,0 +1,30 @@
DESIGN_NAME := uart_loop
LIB_SRC := ../../lib/rtl_components.vhd ../../lib/sim_components.vhd
RTL_SRC := ../../lib/user_components.vhd ../rtl/uart_tx.vhd ../rtl/uart_rx.vhd ../rtl/${DESIGN_NAME}.vhd
SIM_SRC := tb_${DESIGN_NAME}.vhd
SIM_FLAGS := --std=08 -fpsl --workdir=work
.PHONY: all compile sim clean
all: sim
compile: tb_${DESIGN_NAME}
tb_${DESIGN_NAME}: ${LIB_SRC} ${RTL_SRC} ${SIM_SRC}
mkdir -p work
@echo "Analyze gatemate library ..."
ghdl -a ${SIM_FLAGS} --work=gatemate ${LIB_SRC}
@echo "Analyze testbench & design ..."
ghdl -a ${SIM_FLAGS} -Pwork ${RTL_SRC} ${SIM_SRC}
@echo "Elaborate testbench & design ..."
ghdl -e ${SIM_FLAGS} -Pwork $@
sim: tb_${DESIGN_NAME}
@echo "Run testbench ..."
ghdl -r ${SIM_FLAGS} -Pwork tb_${DESIGN_NAME} --assert-level=error
work:
mkdir $@
clean:
@echo "Cleaning simulation files ..."
rm -rf tb_${DESIGN_NAME} *.o work/

+ 96
- 0
uart_loop/sim/tb_uart_loop.vhd View File

@ -0,0 +1,96 @@
library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.all;
entity tb_uart_loop is
end entity tb_uart_loop;
architecture sim of tb_uart_loop is
signal s_clk : std_logic := '1';
signal s_rst_n : std_logic := '0';
signal s_uart_rx : std_logic := '1';
signal s_uart_tx : std_logic;
constant c_baudrate : natural := 9600;
constant c_period_ns : time := 1000000000 / c_baudrate * ns;
procedure uart_send ( data : in std_logic_vector(7 downto 0);
signal tx : out std_logic) is
begin
report "UART send: 0x" & to_hstring(data);
tx <= '0';
wait for c_period_ns;
for i in 0 to 7 loop
tx <= data(i);
wait for c_period_ns;
end loop;
tx <= '1';
wait for c_period_ns;
end procedure;
procedure uart_recv ( data : out std_logic_vector(7 downto 0);
signal rx : in std_logic) is
begin
wait until not rx;
wait for c_period_ns; -- Skip start bit
wait for c_period_ns/2;
for i in 0 to 7 loop
data(i) := rx;
wait for c_period_ns;
end loop;
report "UART recv: 0x" & to_hstring(data);
end procedure;
begin
dut : entity work.uart_loop
port map (
clk_i => s_clk,
rst_n_i => s_rst_n,
uart_rx_i => s_uart_rx,
uart_tx_o => s_uart_tx
);
s_rst_n <= '1' after 120 ns;
s_clk <= not s_clk after 50 ns;
SendP : process is
variable v_data : std_logic_vector(7 downto 0);
begin
wait until s_rst_n;
wait until rising_edge(s_clk);
wait for 200 us;
-- First read all registers
for i in 0 to 255 loop
v_data := std_logic_vector(to_unsigned(i, 8));
uart_send(v_data, s_uart_rx);
end loop;
wait;
end process;
ReceiveP : process is
variable v_exp : std_logic_vector(7 downto 0);
variable v_data : std_logic_vector(7 downto 0);
begin
wait until s_rst_n;
wait until rising_edge(s_clk);
-- First read all registers
for i in 0 to 255 loop
v_exp := std_logic_vector(to_unsigned(i, 8));
uart_recv(v_data, s_uart_tx);
assert v_data = v_exp
report "UART receive error, got 0x" & to_hstring(v_data) & ", expected 0x" & to_hstring(v_exp)
severity failure;
end loop;
wait for 200 us;
report "Simulation finished :-)";
stop(0);
end process;
end architecture;

+ 51
- 0
uart_loop/syn/Makefile View File

@ -0,0 +1,51 @@
DESIGN_NAME := uart_loop
WORK_FILES := ../../lib/user_components.vhd ../rtl/uart_tx.vhd ../rtl/uart_rx.vhd ../rtl/${DESIGN_NAME}.vhd
GM_FILES := ../../lib/rtl_components.vhd
GHDL_FLAGS := --std=08 --workdir=build -Pbuild
YOSYSPIPE := -nomx8 -retime -nobram
# ATTENTION: -luttree option seems to mis-synthesize the design, broken with synth_gatemate?
PNRFLAGS := -om 2
PNRTOOL := $(shell which p_r)
.PHONY: all syn imp prog syn_sim imp_sim
all: imp
syn: ${DESIGN_NAME}.v
imp: ${DESIGN_NAME}.bit
build/work-obj08.cf: ${WORK_FILES} build/gatemate-obj08.cf
ghdl -a ${GHDL_FLAGS} --work=work ${WORK_FILES}
build/gatemate-obj08.cf: ${GM_FILES}
mkdir -p build
ghdl -a ${GHDL_FLAGS} --work=gatemate ${GM_FILES}
# Synthesis target for implementation
${DESIGN_NAME}.v: build/work-obj08.cf
yosys -m ghdl -p 'ghdl ${GHDL_FLAGS} --warn-no-binding --no-formal ${DESIGN_NAME}; synth_gatemate -top $(DESIGN_NAME) ${YOSYSPIPE} -vlog $@' \
2>&1 | tee build/yosys-report.txt
# Implementation target for FPGA
${DESIGN_NAME}.bit: ${DESIGN_NAME}.v ${DESIGN_NAME}.ccf
cd build && \
${PNRTOOL} -i ../${DESIGN_NAME}.v -o $@ --ccf ../${DESIGN_NAME}.ccf $(PNRFLAGS) \
2>&1 | tee p_r-report.txt && \
mv ${DESIGN_NAME}*.bit ../$@
# Post-synthesis simulation target
syn_sim: ${DESIGN_NAME}.v
iverilog -g2012 -o tb_${DESIGN_NAME}_syn.vvp ${DESIGN_NAME}.v tb_${DESIGN_NAME}.v /usr/local/share/yosys/gatemate/cells_sim.v
vvp -N tb_${DESIGN_NAME}_syn.vvp -fst
# Post-implementation simulation target
imp_sim: ${DESIGN_NAME}.bit
iverilog -g2012 -o tb_${DESIGN_NAME}_imp.vvp build/${DESIGN_NAME}_00.v tb_${DESIGN_NAME}.v /opt/cc-toolchain-linux/bin/p_r/cpelib.v
vvp -N tb_${DESIGN_NAME}_imp.vvp -fst
# FPGA FW load per JTAG
prog: ${DESIGN_NAME}.bit
openFPGALoader -b gatemate_evb_jtag $<
clean :
echo "# Cleaning files"
rm -rf build ${DESIGN_NAME}.v ${DESIGN_NAME}_sim.v ${DESIGN_NAME}.vhd ${DESIGN_NAME}.bit *.vvp *.fst

+ 125
- 0
uart_loop/syn/tb_uart_loop.v View File

@ -0,0 +1,125 @@
`timescale 1 ns/10 ps // time-unit = 1 ns, precision = 10 ps
// simplified CC_PLL model
module CC_PLL #(
parameter REF_CLK = "", // e.g. "10.0"
parameter OUT_CLK = "", // e.g. "50.0"
parameter PERF_MD = "", // LOWPOWER, ECONOMY, SPEED
parameter LOW_JITTER = 1,
parameter CI_FILTER_CONST = 2,
parameter CP_FILTER_CONST = 4
)(
input CLK_REF, CLK_FEEDBACK, USR_CLK_REF,
input USR_LOCKED_STDY_RST, USR_SET_SEL,
output USR_PLL_LOCKED_STDY, USR_PLL_LOCKED,
output CLK270, CLK180, CLK90, CLK0, CLK_REF_OUT
);
reg r_pll_clk;
reg r_user_pll_locked;
// OUT_FREQ = 1 MHz
integer clk_half_period = 500;
initial begin
r_pll_clk = 1'b0;
r_user_pll_locked = 1'b1;
end
always #clk_half_period r_pll_clk = ~r_pll_clk;
assign CLK0 = r_pll_clk;
assign USR_PLL_LOCKED = r_user_pll_locked;
endmodule
// simplified CC_CFG_END model
module CC_CFG_END (
output CFG_END
);
assign CFG_END = 1'b1;
endmodule
module tb_uart_loop;
// DUT in/out
reg clk = 1'b0;
reg rst_n = 1'b1;
reg uart_rx;
wire uart_tx;
// Testbench variables
reg [7:0] tx_data = 8'h0;
reg [7:0] rx_data = 8'h0;
// Testbench 1/2 clock period
localparam clk_half_period = 50;
// UART period calculation (9600 baud)
localparam uart_bit_period = 1000000000 / 9600;
localparam uart_bit_half_period = uart_bit_period/2;
uart_loop UUT (.clk_i(clk), .rst_n_i(rst_n), .uart_rx_i(uart_rx), .uart_tx_o(uart_tx));
// set dumpfile
initial begin
$dumpfile ("tb_uart_loop.fst");
$dumpvars (0, tb_uart_loop);
end
// Setup simulation
initial begin
uart_rx = 1'b1;
#1 rst_n = 1'b0;
#120 rst_n = 1'b1;
end
// Generate 10 mhz clock
always #clk_half_period clk = !clk;
// Stimuli generator
initial
forever @(posedge rst_n) begin
uart_rx = 1'b1;
#uart_bit_period;
for (integer tx = 0; tx < 32; tx = tx + 1) begin
tx_data = tx;
$display ("UART send: 0x%h", tx_data);
uart_rx = 1'b0;
#uart_bit_period;
for (integer i = 0; i < 7; i = i + 1) begin
uart_rx = tx_data[i];
#uart_bit_period;
end
uart_rx = 1'b1;
#uart_bit_period;
#uart_bit_period
#uart_bit_period;
end
end
// Checker
initial begin
@(posedge rst_n)
for (reg [7:0] rx = 0; rx < 32; rx = rx + 1) begin
@(negedge uart_tx)
#uart_bit_period;
#uart_bit_half_period;
for (integer i = 0; i < 7; i = i + 1) begin
rx_data[i] = uart_tx;
#uart_bit_period;
end
assert (rx_data == rx)
$display("UART recv: 0x%h", rx_data);
else
$warning("UART receive error, got 0x%h, expected 0x%h", rx_data, rx);
end
$display ("UART tests finished");
$finish;
end
endmodule

+ 16
- 0
uart_loop/syn/uart_loop.ccf View File

@ -0,0 +1,16 @@
# Configuration for the Gatemate eval board
Pin_in "clk_i" Loc = "IO_SB_A8" | SCHMITT_TRIGGER=true;
Pin_in "rst_n_i" Loc = "IO_EB_B0"; # SW3
Pin_in "uart_rx_i" Loc = "IO_NB_A1"; # PMODA IO3
Pin_out "uart_tx_o" Loc = "IO_NB_A0"; # PMODA IO1
Pin_out "debug_o[0]" Loc = "IO_NB_A4";
Pin_out "debug_o[1]" Loc = "IO_NB_A5";
Pin_out "debug_o[2]" Loc = "IO_NB_A6";
Pin_out "debug_o[3]" Loc = "IO_NB_A7";
Pin_out "debug_o[4]" Loc = "IO_NB_B4";
Pin_out "debug_o[5]" Loc = "IO_NB_B5";
Pin_out "debug_o[6]" Loc = "IO_NB_B6";
Pin_out "debug_o[7]" Loc = "IO_NB_B7";

+ 1
- 1
uart_reg/syn/uart_reg.ccf View File

@ -4,7 +4,7 @@ Pin_in "clk_i" Loc = "IO_SB_A8" | SCHMITT_TRIGGER=true;
Pin_in "rst_n_i" Loc = "IO_EB_B0"; # SW3
Pin_in "uart_rx_i" Loc = "IO_NB_A1"; # PMODA IO3
Pin_out "uart_tx_o" Loc = "IO_NB_A2"; # PMODA IO5
Pin_out "uart_tx_o" Loc = "IO_NB_A0"; # PMODA IO1
Pin_out "debug_o[0]" Loc = "IO_NB_A4";
Pin_out "debug_o[1]" Loc = "IO_NB_A5";


Loading…
Cancel
Save