Skip to content

Commit

Permalink
add vhdl uart example
Browse files Browse the repository at this point in the history
  • Loading branch information
michg committed Jan 12, 2021
1 parent 7f646b4 commit c1f4853
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 1 deletion.
3 changes: 2 additions & 1 deletion pysim/coroutines.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def send_byte(sig, ticksperbit, val):
for i in range(ticksperbit):
yield
for i in range(8):
sig.val = (val >> 1 ) & 1
sig.val = val & 1
val = val>>1
for j in range(ticksperbit):
yield
sig.val = 1
Expand Down
1 change: 1 addition & 0 deletions samples/uart/uart.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ghdl uart_rx.vhd uart_tx.vhd uart_top.vhd -e uart_top
66 changes: 66 additions & 0 deletions samples/uart/uart_rx.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
library ieee;
use ieee.std_logic_1164.all;

entity uart_rx is
generic (
C_BITS : integer := 8;
C_CYCLES_PER_BIT : integer := 104
);
port (
isl_clk : in std_logic;
isl_data : in std_logic;
oslv_data : out std_logic_vector(C_BITS-1 downto 0);
osl_valid : out std_logic
);
end entity uart_rx;

architecture rtl of uart_rx is
signal int_cycle_cnt : integer range 0 to C_CYCLES_PER_BIT-1 := 0;
signal int_bit_cnt : integer range 0 to C_BITS+1 := 0;

signal slv_data : std_logic_vector(C_BITS-1 downto 0) := (others => '0');
signal sl_valid : std_logic := '0';

type t_state is (IDLE, INIT, RECEIVE);
signal state : t_state;

begin
process(isl_clk)
begin
if rising_edge(isl_clk) then
case state is
when IDLE =>
sl_valid <= '0';
if isl_data = '0' then
-- wait for the start bit
state <= INIT;
end if;

when INIT =>
int_cycle_cnt <= C_CYCLES_PER_BIT / 2;
int_bit_cnt <= 0;
state <= RECEIVE;

when RECEIVE =>
if int_bit_cnt < C_BITS+1 then
if int_cycle_cnt < C_CYCLES_PER_BIT-1 then
int_cycle_cnt <= int_cycle_cnt+1;
else
-- receive data bits
int_cycle_cnt <= 0;
int_bit_cnt <= int_bit_cnt+1;
slv_data <= isl_data & slv_data(slv_data'LEFT downto 1);
end if;
elsif isl_data = '1' then
-- wait for the stop bit
sl_valid <= '1';
state <= IDLE;
end if;

end case;
end if;
end process;

oslv_data <= slv_data;
osl_valid <= sl_valid;
end architecture rtl;
49 changes: 49 additions & 0 deletions samples/uart/uart_top.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
library ieee;
use ieee.std_logic_1164.all;

entity uart_top is
generic (
C_BITS : integer := 8
);
port (
isl_clk : in std_logic;
isl_data : in std_logic;
osl_data : out std_logic;
osl_ready : out std_logic
);
end uart_top;

architecture behavioral of uart_top is
constant C_QUARTZ_FREQ : integer := 4; -- Hz
constant C_BAUDRATE : integer := 1; -- words / s
constant C_CYCLES_PER_BIT : integer := C_QUARTZ_FREQ / C_BAUDRATE;

signal sl_valid_out_tx : std_logic := '0';
signal slv_data_out_tx : std_logic_vector(C_BITS-1 downto 0) := (others => '0');

begin
i_uart_rx: entity work.uart_rx
generic map (
C_BITS => C_BITS,
C_CYCLES_PER_BIT => C_CYCLES_PER_BIT
)
port map (
isl_clk => isl_clk,
isl_data => isl_data,
oslv_data => slv_data_out_tx,
osl_valid => sl_valid_out_tx
);

i_uart_tx: entity work.uart_tx
generic map (
C_BITS => C_BITS,
C_CYCLES_PER_BIT => C_CYCLES_PER_BIT
)
port map (
isl_clk => isl_clk,
isl_valid => sl_valid_out_tx,
islv_data => slv_data_out_tx,
osl_data => osl_data,
osl_ready => osl_ready
);
end behavioral;
62 changes: 62 additions & 0 deletions samples/uart/uart_tx.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
library ieee;
use ieee.std_logic_1164.all;

entity uart_tx is
generic (
-- TODO: range in submodules is not yet supported by synthesis
-- it would be useful to limit between 5 to 8
C_BITS : integer := 8;
C_CYCLES_PER_BIT : integer := 104
);
port (
isl_clk : in std_logic;
isl_valid : in std_logic;
islv_data : in std_logic_vector(C_BITS-1 downto 0);
osl_ready : out std_logic;
osl_data : out std_logic
);
end entity uart_tx;

architecture rtl of uart_tx is
signal int_cycle_cnt : integer range 0 to C_CYCLES_PER_BIT-1 := 0;
signal int_bit_cnt : integer range 0 to C_BITS+2 := 0;

signal slv_data : std_logic_vector(C_BITS downto 0) := (others => '0');

type t_state is (IDLE, INIT, SEND);
signal state : t_state;

begin
process(isl_clk)
begin
if rising_edge(isl_clk) then
case state is
when IDLE =>
if isl_valid = '1' then
state <= INIT;
end if;

when INIT =>
int_cycle_cnt <= 0;
int_bit_cnt <= 0;
slv_data <= islv_data & '1';
state <= SEND;

when SEND =>
if int_cycle_cnt < C_CYCLES_PER_BIT-1 then
int_cycle_cnt <= int_cycle_cnt+1;
elsif int_bit_cnt < C_BITS+1 then
int_cycle_cnt <= 0;
int_bit_cnt <= int_bit_cnt+1;
slv_data <= '0' & slv_data(slv_data'LEFT downto 1);
else
state <= IDLE;
end if;

end case;
end if;
end process;

osl_ready <= '1' when state = IDLE else '0';
osl_data <= slv_data(0);
end architecture rtl;
12 changes: 12 additions & 0 deletions sim_uart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from tb import top
from pysim.sim import Signal, runsim
from pysim.coroutines import clock_coroutine, uart_coroutine

dut = top(True)
clk = Signal(dut, 'isl__clk')
rxd = Signal(dut, 'isl__data')
clk_co = clock_coroutine(clk, 1, 1, 400)
uart_co = uart_coroutine(rxd, 8, b"Hello!")
coros = [clk_co, uart_co]
runsim(dut, True, coros, 400)

0 comments on commit c1f4853

Please sign in to comment.