diff --git a/lib/uart/juart_rx.vhd b/lib/uart/juart_rx.vhd new file mode 100644 index 0000000..ca6e337 --- /dev/null +++ b/lib/uart/juart_rx.vhd @@ -0,0 +1,188 @@ +-- UART Receiver +-- +-- Version : 1.00 +-- Version Date : 15 December 2016 +-- +------------------------------------------------------------------------------------ +-- +-- Library declarations +-- +-- The Unisim Library is used to define Xilinx primitives. It is also used during +-- simulation. The source can be viewed at %XILINX%\vhdl\src\unisims\unisim_VCOMP.vhd +-- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; +-- +------------------------------------------------------------------------------------ +-- +-- Main Entity +-- +entity juart_rx is + Port ( serial_in : in std_logic; + data_out : out unsigned(7 downto 0); + data_strobe : out std_logic; + en_16_x_baud : in std_logic; + clk : in std_logic; + rst : in std_logic); + end juart_rx; +-- +------------------------------------------------------------------------------------ +-- +-- Start of Main Architecture +-- +architecture behavior of juart_rx is +-- +------------------------------------------------------------------------------------ +-- +------------------------------------------------------------------------------------ +-- +-- Signals used +-- +------------------------------------------------------------------------------------ +-- +signal bit_count_rst : std_logic; +signal bit_count : natural range 0 to 15; +signal data_valid : std_logic; +signal shiftreg_en : std_logic; +signal shiftreg : unsigned (7 downto 0); +signal sample_count_rst : std_logic; +signal sample_count : unsigned (15 downto 0); +signal idle_count : natural range 0 to 15; +signal is_idle : std_logic; +signal bit_sample : std_logic; + +type state_t is (idle, wait_start, start, shift, stop); + +signal state : state_t; +signal state_next : state_t; +-- +-- +begin + +bit_sample <= sample_count(8); +is_idle <= '1' when idle_count = 0 else '0'; + +data_out_reg: +process(clk) +begin + if rising_edge(clk) then + data_strobe <= '0'; + if data_valid = '1' then + data_out <= shiftreg; + data_strobe <= '1'; + end if; + end if; +end process; + +proc_state_next: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + state <= idle; + else + state <= state_next; + end if; + end if; +end process; + +statemachine: +process(state, is_idle, bit_count, bit_sample, serial_in) +begin + state_next <= state; + sample_count_rst <= '1'; + bit_count_rst <= '1'; + shiftreg_en <= '0'; + data_valid <= '0'; + + case state is + when idle => + if is_idle = '1' then + state_next <= wait_start; + end if; + when wait_start => + if serial_in = '0' then + sample_count_rst <= '0'; + state_next <= start; + end if; + when start => + sample_count_rst <= '0'; + if bit_sample = '1' then + state_next <= shift; + end if; + when shift => + shiftreg_en <= '1'; + sample_count_rst <= '0'; + bit_count_rst <= '0'; + if bit_count = 8 then + state_next <= stop; + end if; + when stop => + state_next <= idle; + data_valid <= '1'; + + when others => + state_next <= idle; + end case; +end process; + +shift_register: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + shiftreg <= (others => '0'); + elsif shiftreg_en = '1' and bit_sample = '1' then + shiftreg <= shiftreg(shiftreg'left-1 downto 0) & serial_in; + end if; + end if; +end process; + +sample_counter: +process(clk) +begin + if rising_edge(clk) then + if sample_count_rst = '1' then + sample_count <= (sample_count'left downto 1 => '0') & '1'; + elsif en_16_x_baud = '1' then + sample_count <= sample_count(sample_count'left-1 downto 0) & sample_count(sample_count'left); + end if; + end if; +end process; + +bit_counter: +process(clk) +begin + if rising_edge(clk) then + if bit_count_rst = '1' then + bit_count <= 0; + elsif bit_count /= 15 and bit_sample = '1' then + bit_count <= bit_count + 1; + end if; + end if; +end process; + +idle_detector: +process(clk) +begin + if rising_edge(clk) then + if serial_in = '0' then + idle_count <= 15; + elsif idle_count /= 0 then + idle_count <= idle_count - 1; + else + idle_count <= 15; + end if; + end if; +end process; + +end behavior; + +------------------------------------------------------------------------------------ +-- +-- END OF FILE +-- +------------------------------------------------------------------------------------ + + diff --git a/lib/uart/juart_tx.vhd b/lib/uart/juart_tx.vhd new file mode 100644 index 0000000..b2d369f --- /dev/null +++ b/lib/uart/juart_tx.vhd @@ -0,0 +1,124 @@ +-- UART Transmitter +-- +-- Version : 1.00 +-- Version Date : 15 December 2016 +-- +------------------------------------------------------------------------------------ +-- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; +-- +------------------------------------------------------------------------------------ +-- +-- Main Entity +-- +entity juart_tx is + Port ( data_in : in unsigned(7 downto 0); + send_character : in std_logic; + en_16_x_baud : in std_logic; + serial_out : out std_logic; + Tx_complete : out std_logic; + clk : in std_logic; + rst : in std_logic + ); + end juart_tx; +-- +------------------------------------------------------------------------------------ +-- +-- Start of Main Architecture +-- +architecture behavior of juart_tx is +-- +------------------------------------------------------------------------------------ +-- +------------------------------------------------------------------------------------ +-- +-- Signals used +-- +------------------------------------------------------------------------------------ +-- +signal dinreg : unsigned (7 downto 0); +signal shiftreg : unsigned (9 downto 0); +signal busy : std_logic; +signal start : std_logic; +signal shift_enable : std_logic; +signal shift_enable_count : unsigned (3 downto 0); +signal bit_count : unsigned (3 downto 0); + +-- +-- +begin +serial_out <= shiftreg(shiftreg'left); +Tx_complete <= not busy; + +shift_enable_counter: +process(clk) +begin + if rising_edge(clk) then + shift_enable <= '0'; + if rst = '1' then + shift_enable_count <= (others => '1'); + elsif en_16_x_baud = '1' then + if shift_enable_count = 0 then + shift_enable <= '1'; + shift_enable_count <= (others => '1'); + else + shift_enable_count <= shift_enable_count - 1; + end if; + end if; + end if; +end process; + +bit_counter: +process(clk) +begin + if rising_edge(clk) then + if start = '1' then + bit_count <= to_unsigned(shiftreg'length-1, bit_count'length); + elsif shift_enable = '1' then + if not (bit_count = 0) then + bit_count <= bit_count - 1; + end if; + end if; + end if; +end process; + +transmit: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + shiftreg <= (others => '1'); + busy <= '0'; + start <= '0'; + elsif busy = '0' then + if send_character = '1' then + busy <= '1'; + start <= '1'; + dinreg <= data_in; + end if; + elsif shift_enable = '1' then + if start = '1' then + start <= '0'; + shiftreg <= '0' & dinreg & '1'; + elsif bit_count /= 0 then + shiftreg <= shiftreg(shiftreg'left-1 downto 0) & '1'; + if bit_count = 1 then + busy <= '0'; + end if; + + end if; + end if; + end if; +end process; + +end behavior; + +------------------------------------------------------------------------------------ +-- +-- END OF FILE +-- +------------------------------------------------------------------------------------ + + diff --git a/lib/uart/sim/tb_juart_rx.fdo b/lib/uart/sim/tb_juart_rx.fdo new file mode 100644 index 0000000..10889a5 --- /dev/null +++ b/lib/uart/sim/tb_juart_rx.fdo @@ -0,0 +1,14 @@ +## NOTE: Do not edit this file. +## + +vlib work +vcom -explicit -93 "../juart_rx.vhd" +vcom -explicit -93 "../tb_juart_rx.vhd" + +#restart -force +vsim -t 1ps -lib work tb_juart_rx +do {tb_juart_rx.wdo} +view wave +view structure +view signals +run 6.0us diff --git a/lib/uart/sim/tb_juart_rx.wdo b/lib/uart/sim/tb_juart_rx.wdo new file mode 100644 index 0000000..6b6c661 --- /dev/null +++ b/lib/uart/sim/tb_juart_rx.wdo @@ -0,0 +1,37 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -format Logic /tb_juart_rx/rst +add wave -noupdate -format Logic /tb_juart_rx/clk +add wave -noupdate -format Logic /tb_juart_rx/en_16_x_baud +add wave -noupdate -format Logic /tb_juart_rx/serial_in +add wave -noupdate -format Logic /tb_juart_rx/data_strobe +add wave -noupdate -format Literal -radix hexadecimal /tb_juart_rx/data_reg +add wave -noupdate -divider {JUART RX} +add wave -noupdate -format Logic /tb_juart_rx/inst_juart_rx/bit_sample +add wave -noupdate -format Literal -radix unsigned /tb_juart_rx/inst_juart_rx/bit_count +add wave -noupdate -format Literal -radix unsigned /tb_juart_rx/inst_juart_rx/shiftreg +add wave -noupdate -format Literal /tb_juart_rx/inst_juart_rx/sample_count +add wave -noupdate -format Logic /tb_juart_rx/inst_juart_rx/is_idle +add wave -noupdate -format Literal /tb_juart_rx/inst_juart_rx/state +add wave -noupdate -format Literal /tb_juart_rx/inst_juart_rx/state_next +add wave -noupdate -format Literal /tb_juart_rx/inst_juart_rx/idle_count +add wave -noupdate -format Logic /tb_juart_rx/inst_juart_rx/bit_count_rst +add wave -noupdate -format Logic /tb_juart_rx/inst_juart_rx/sample_count_rst +add wave -noupdate -format Logic /tb_juart_rx/inst_juart_rx/data_strobe +add wave -noupdate -format Literal -radix hexadecimal /tb_juart_rx/data_out +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {362114 ps} 0} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +update +WaveRestoreZoom {0 ps} {6300 ns} diff --git a/lib/uart/sim/tb_juart_tx.fdo b/lib/uart/sim/tb_juart_tx.fdo new file mode 100644 index 0000000..9f76a06 --- /dev/null +++ b/lib/uart/sim/tb_juart_tx.fdo @@ -0,0 +1,14 @@ +## NOTE: Do not edit this file. +## + +vlib work +vcom -explicit -93 "../juart_tx.vhd" +vcom -explicit -93 "../tb_juart_tx.vhd" + +#restart -force +vsim -t 1ps -lib work tb_juart_tx +do {tb_juart_tx.wdo} +view wave +view structure +view signals +run 6.0us diff --git a/lib/uart/sim/tb_juart_tx.wdo b/lib/uart/sim/tb_juart_tx.wdo new file mode 100644 index 0000000..bc05d8f --- /dev/null +++ b/lib/uart/sim/tb_juart_tx.wdo @@ -0,0 +1,33 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -format Logic /tb_juart_tx/rst +add wave -noupdate -format Logic /tb_juart_tx/clk +add wave -noupdate -format Logic /tb_juart_tx/en_16_x_baud +add wave -noupdate -format Logic /tb_juart_tx/send_character +add wave -noupdate -format Logic /tb_juart_tx/serial_out +add wave -noupdate -format Logic /tb_juart_tx/tx_complete +add wave -noupdate -format Literal -radix hexadecimal /tb_juart_tx/data_in +add wave -noupdate -divider JUART_TX +add wave -noupdate -format Literal -radix hexadecimal /tb_juart_tx/inst_juart_tx/shiftreg +add wave -noupdate -format Literal -radix hexadecimal /tb_juart_tx/inst_juart_tx/dinreg +add wave -noupdate -format Logic /tb_juart_tx/inst_juart_tx/start +add wave -noupdate -format Logic /tb_juart_tx/inst_juart_tx/busy +add wave -noupdate -format Logic /tb_juart_tx/inst_juart_tx/shift_enable +add wave -noupdate -format Literal -radix unsigned /tb_juart_tx/inst_juart_tx/shift_enable_count +add wave -noupdate -format Literal -radix unsigned /tb_juart_tx/inst_juart_tx/bit_count +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {40000 ps} 0} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +update +WaveRestoreZoom {0 ps} {2100 ns} diff --git a/lib/uart/tb_juart_rx.vhd b/lib/uart/tb_juart_rx.vhd new file mode 100644 index 0000000..b2811e0 --- /dev/null +++ b/lib/uart/tb_juart_rx.vhd @@ -0,0 +1,104 @@ +------------------------------------------------------------------------- +-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL +-- This file: cpu_embedded using cpu_core and rom +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +entity tb_juart_rx is +end; + +architecture behave of tb_juart_rx is + + -- Number of user data words for simulation + constant CLK_PERIOD : time := 10 ns; + + signal rst : std_logic := '1'; + signal clk : std_logic := '1'; + signal en_16_x_baud : std_logic := '1'; + signal serial_in : std_logic := '1'; + signal data_strobe : std_logic; + signal data_out : unsigned(7 downto 0); + signal serial_word : unsigned(7 downto 0) := X"AA"; + + signal data_reg : unsigned(7 downto 0); +begin + +inst_juart_rx : entity work.juart_rx + PORT MAP + ( + rst => rst, + clk => clk, + en_16_x_baud => en_16_x_baud, + data_strobe => data_strobe, + data_out => data_out, + serial_in => serial_in + ); + + +CLK_GEN: process + begin + wait for CLK_PERIOD/2; + clk <= not clk; + end process; + +PROC_DATAREG: process + begin + wait until rising_edge(clk) and data_strobe = '1'; + data_reg <= data_out; + end process; + +------------------------------------------------------------------------------------------ + +STIMULUS: process + + + begin + + wait for 3*CLK_PERIOD; + rst <= '0'; + + serial_word <= X"AA"; + wait for 16*CLK_PERIOD; + serial_in <= '0'; + wait for 16*CLK_PERIOD; + for i in serial_word'length-1 downto 0 loop + serial_in <= serial_word(i); + wait for 16*CLK_PERIOD; + end loop; + serial_in <= '1'; + wait for 16*CLK_PERIOD; + serial_word <= X"55"; + serial_in <= '0'; + wait for 16*CLK_PERIOD; + + for i in serial_word'length-1 downto 0 loop + serial_in <= serial_word(i); + wait for 16*CLK_PERIOD; + end loop; + serial_in <= '1'; + wait; + + end process; + +end architecture behave; diff --git a/lib/uart/tb_juart_tx.vhd b/lib/uart/tb_juart_tx.vhd new file mode 100644 index 0000000..cc11f9d --- /dev/null +++ b/lib/uart/tb_juart_tx.vhd @@ -0,0 +1,96 @@ +------------------------------------------------------------------------- +-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL +-- This file: cpu_embedded using cpu_core and rom +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.ALL; + +entity tb_juart_tx is +end; + +architecture behave of tb_juart_tx is + + -- Number of user data words for simulation + constant CLK_PERIOD : time := 10 ns; + + signal rst : std_logic := '1'; + signal clk : std_logic := '1'; + signal en_16_x_baud : std_logic := '1'; + signal send_character : std_logic := '0'; + signal serial_out : std_logic; + signal Tx_complete : std_logic; + signal data_in : unsigned(7 downto 0) := (others => '0'); + +begin + +inst_juart_tx : entity work.juart_tx + PORT MAP + ( + rst => rst, + clk => clk, + en_16_x_baud => en_16_x_baud, + send_character => send_character, + Tx_complete => Tx_complete, + data_in => data_in, + serial_out => serial_out + ); + + +CLK_GEN: process + begin + wait for CLK_PERIOD/2; + clk <= not clk; + end process; + +------------------------------------------------------------------------------------------ + +STIMULUS: process + + + begin + + wait for 3*CLK_PERIOD; + rst <= '0'; + wait for 3*CLK_PERIOD; + wait until rising_edge(clk); + data_in <= X"A5"; + wait until rising_edge(clk) and Tx_complete = '1'; + send_character <= '1'; + wait until rising_edge(clk) and Tx_complete = '0'; + send_character <= '0'; + wait until rising_edge(clk) and Tx_complete = '1'; + data_in <= X"AA"; + wait until rising_edge(clk) and Tx_complete = '1'; + send_character <= '1'; + wait until rising_edge(clk) and Tx_complete = '0'; + send_character <= '0'; + data_in <= X"55"; + wait until rising_edge(clk) and Tx_complete = '1'; + send_character <= '1'; + wait until rising_edge(clk) and Tx_complete = '0'; + send_character <= '0'; + wait; + + end process; + +end architecture behave;