--! uart control unit
|
--! uart control unit
|
library IEEE;
|
library IEEE;
|
use IEEE.STD_LOGIC_1164.ALL;
|
use IEEE.STD_LOGIC_1164.ALL;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
|
|
--! Use CPU Definitions package
|
--! Use CPU Definitions package
|
use work.pkgDefinitions.all;
|
use work.pkgDefinitions.all;
|
|
|
entity uart_control is
|
entity uart_control is
|
Port ( rst : in std_logic; -- Global reset
|
Port ( rst : in std_logic; -- Global reset
|
clk : in std_logic; -- Global clock
|
clk : in std_logic; -- Global clock
|
WE : in std_logic; -- Write enable
|
WE : in std_logic; -- Write enable
|
reg_addr : in std_logic_vector (1 downto 0); -- Register address
|
reg_addr : in std_logic_vector (1 downto 0); -- Register address
|
start : in std_logic; -- Start (Strobe)
|
start : in std_logic; -- Start (Strobe)
|
done : out std_logic; -- Done (ACK)
|
done : out std_logic; -- Done (ACK)
|
DAT_I : in std_logic_vector ((nBitsLarge-1) downto 0); -- Data Input (Wishbone)
|
DAT_I : in std_logic_vector ((nBitsLarge-1) downto 0); -- Data Input (Wishbone)
|
DAT_O : out std_logic_vector ((nBitsLarge-1) downto 0); -- Data output (Wishbone)
|
DAT_O : out std_logic_vector ((nBitsLarge-1) downto 0); -- Data output (Wishbone)
|
baud_wait : out std_logic_vector ((nBitsLarge-1) downto 0); -- Signal to control the baud rate frequency
|
baud_wait : out std_logic_vector ((nBitsLarge-1) downto 0); -- Signal to control the baud rate frequency
|
data_byte_tx : out std_logic_vector((nBits-1) downto 0); -- 1 Byte to be send to serial_transmitter
|
data_byte_tx : out std_logic_vector((nBits-1) downto 0); -- 1 Byte to be send to serial_transmitter
|
data_byte_rx : in std_logic_vector((nBits-1) downto 0); -- 1 Byte to be received by serial_receiver
|
data_byte_rx : in std_logic_vector((nBits-1) downto 0); -- 1 Byte to be received by serial_receiver
|
tx_data_sent : in std_logic; -- Signal comming from serial_transmitter
|
tx_data_sent : in std_logic; -- Signal comming from serial_transmitter
|
tx_start : out std_logic; -- Signal to start sending serial data...
|
tx_start : out std_logic; -- Signal to start sending serial data...
|
rst_comm_blocks : out std_logic; -- Reset Communication blocks
|
rst_comm_blocks : out std_logic; -- Reset Communication blocks
|
rx_data_ready : in std_logic); -- Signal comming from serial_receiver
|
rx_data_ready : in std_logic); -- Signal comming from serial_receiver
|
end uart_control;
|
end uart_control;
|
|
|
architecture Behavioral of uart_control is
|
architecture Behavioral of uart_control is
|
signal config_clk : std_logic_vector((nBitsLarge-1) downto 0);
|
signal config_clk : std_logic_vector((nBitsLarge-1) downto 0);
|
signal config_baud : std_logic_vector((nBitsLarge-1) downto 0);
|
signal config_baud : std_logic_vector((nBitsLarge-1) downto 0);
|
signal received_byte : std_logic_vector((nBits-1) downto 0);
|
signal received_byte : std_logic_vector((nBits-1) downto 0);
|
signal byte_to_transmit : std_logic_vector((nBits-1) downto 0);
|
signal byte_to_transmit : std_logic_vector((nBits-1) downto 0);
|
|
|
signal sigDivRst : std_logic;
|
signal sigDivRst : std_logic;
|
signal sigDivDone : std_logic;
|
signal sigDivDone : std_logic;
|
signal sigDivQuotient : std_logic_vector((nBitsLarge-1) downto 0);
|
signal sigDivQuotient : std_logic_vector((nBitsLarge-1) downto 0);
|
signal sigDivNumerator : std_logic_vector((nBitsLarge-1) downto 0);
|
signal sigDivNumerator : std_logic_vector((nBitsLarge-1) downto 0);
|
signal sigDivDividend : std_logic_vector((nBitsLarge-1) downto 0);
|
signal sigDivDividend : std_logic_vector((nBitsLarge-1) downto 0);
|
|
|
-- Signals used to control the configuration
|
-- Signals used to control the configuration
|
signal startConfigBaud : std_logic;
|
signal startConfigBaud : std_logic;
|
signal startConfigClk : std_logic;
|
signal startConfigClk : std_logic;
|
signal startDataSend : std_logic;
|
signal startDataSend : std_logic;
|
signal commBlocksInitiated : std_logic;
|
signal commBlocksInitiated : std_logic;
|
signal doneWriteReg : std_logic;
|
|
signal startReadReg : std_logic;
|
signal startReadReg : std_logic;
|
signal alreadyConfBaud : std_logic;
|
signal alreadyConfBaud : std_logic;
|
signal alreadyConfClk : std_logic;
|
signal alreadyConfClk : std_logic;
|
|
|
-- Divisor component
|
-- Divisor component
|
component divisor is
|
component divisor is
|
Port ( rst : in STD_LOGIC;
|
Port ( rst : in STD_LOGIC;
|
clk : in STD_LOGIC;
|
clk : in STD_LOGIC;
|
quotient : out STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
quotient : out STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
reminder : out STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
reminder : out STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
numerator : in STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
numerator : in STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
divident : in STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
divident : in STD_LOGIC_VECTOR ((nBitsLarge-1) downto 0);
|
done : out STD_LOGIC);
|
done : out STD_LOGIC);
|
end component;
|
end component;
|
|
|
begin
|
begin
|
-- Instantiate block for calculate division
|
-- Instantiate block for calculate division
|
uDiv : divisor port map (
|
uDiv : divisor port map (
|
rst => sigDivRst,
|
rst => sigDivRst,
|
clk => clk,
|
clk => clk,
|
quotient => sigDivQuotient,
|
quotient => sigDivQuotient,
|
reminder => open, -- Indicates that this port will not be connected to anything
|
reminder => open, -- Indicates that this port will not be connected to anything
|
numerator => sigDivNumerator,
|
numerator => sigDivNumerator,
|
divident => sigDivDividend,
|
divident => sigDivDividend,
|
done => sigDivDone
|
done => sigDivDone
|
);
|
);
|
|
|
-- Process to handle the of writting the registers
|
-- Process to handle the of writting the registers
|
process (clk)
|
process (clk)
|
begin
|
begin
|
-- On the wishbone specification we should handle the reset synchronously
|
-- On the wishbone specification we should handle the reset synchronously
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if rst = '1' then
|
if rst = '1' then
|
config_clk <= (others => '0');
|
config_clk <= (others => '0');
|
config_baud <= (others => '0');
|
config_baud <= (others => '0');
|
byte_to_transmit <= (others => '0');
|
byte_to_transmit <= (others => '0');
|
startConfigBaud <= '0';
|
startConfigBaud <= '0';
|
startConfigClk <= '0';
|
startConfigClk <= '0';
|
startDataSend <= '0';
|
startDataSend <= '0';
|
doneWriteReg <= '0';
|
|
alreadyConfClk <= '0';
|
alreadyConfClk <= '0';
|
alreadyConfBaud <= '0';
|
alreadyConfBaud <= '0';
|
elsif (WE and start) = '1' then
|
elsif (WE and start) = '1' then
|
case reg_addr is
|
case reg_addr is
|
when "00" =>
|
when "00" =>
|
config_clk <= DAT_I;
|
config_clk <= DAT_I;
|
startConfigClk <= '1';
|
startConfigClk <= '1';
|
startDataSend <= '0';
|
startDataSend <= '0';
|
startConfigBaud <= '0';
|
startConfigBaud <= '0';
|
alreadyConfClk <= '1';
|
alreadyConfClk <= '1';
|
when "01" =>
|
when "01" =>
|
config_baud <= DAT_I;
|
config_baud <= DAT_I;
|
startConfigBaud <= '1';
|
startConfigBaud <= '1';
|
startDataSend <= '0';
|
startDataSend <= '0';
|
startConfigClk <= '0';
|
startConfigClk <= '0';
|
alreadyConfBaud <= '1';
|
alreadyConfBaud <= '1';
|
when "10" =>
|
when "10" =>
|
-- If we have an overrun, discard the byte
|
|
byte_to_transmit <= DAT_I((nBits-1) downto 0);
|
byte_to_transmit <= DAT_I((nBits-1) downto 0);
|
startConfigBaud <= '0';
|
startConfigBaud <= '0';
|
startConfigClk <= '0';
|
startConfigClk <= '0';
|
startDataSend <= '1';
|
startDataSend <= '1';
|
when others =>
|
when others =>
|
startConfigBaud <= '0';
|
startConfigBaud <= '0';
|
startConfigClk <= '0';
|
startConfigClk <= '0';
|
startDataSend <= '0';
|
startDataSend <= '0';
|
end case;
|
end case;
|
|
else
|
|
startDataSend <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Process to handle the reading of registers
|
-- Process to handle the reading of registers
|
process (clk)
|
process (clk)
|
begin
|
begin
|
-- On the wishbone specification we should handle the reset synchronously
|
-- On the wishbone specification we should handle the reset synchronously
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if rst = '1' then
|
if rst = '1' then
|
DAT_O <= (others => 'Z');
|
DAT_O <= (others => 'Z');
|
startReadReg <= '0';
|
startReadReg <= '0';
|
elsif ((WE = '0') and (start = '1')) then
|
elsif ((WE = '0') and (start = '1')) then
|
startReadReg <= '1';
|
startReadReg <= '1';
|
case reg_addr is
|
case reg_addr is
|
when "00" =>
|
when "00" =>
|
DAT_O <= config_clk;
|
DAT_O <= config_clk;
|
when "01" =>
|
when "01" =>
|
DAT_O <= config_baud;
|
DAT_O <= config_baud;
|
when "10" =>
|
when "10" =>
|
DAT_O <= conv_std_logic_vector(0, (nBitsLarge-nBits)) & byte_to_transmit;
|
DAT_O <= conv_std_logic_vector(0, (nBitsLarge-nBits)) & byte_to_transmit;
|
when "11" =>
|
when "11" =>
|
DAT_O <= conv_std_logic_vector(0, (nBitsLarge-nBits)) & received_byte;
|
DAT_O <= conv_std_logic_vector(0, (nBitsLarge-nBits)) & received_byte;
|
when others =>
|
when others =>
|
null;
|
null;
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Process that stores the data that comes from the serial receiver block
|
-- Process that stores the data that comes from the serial receiver block
|
process (rx_data_ready)
|
process (rx_data_ready)
|
begin
|
begin
|
if rising_edge(rx_data_ready) then
|
if rising_edge(rx_data_ready) then
|
received_byte <= data_byte_rx;
|
received_byte <= data_byte_rx;
|
else
|
else
|
received_byte <= received_byte;
|
received_byte <= received_byte;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Process to send data over the serial transmitter
|
-- Process to send data over the serial transmitter
|
process (clk)
|
process (clk)
|
variable cont_steps : integer range 0 to 3;
|
variable sendDataStates : sendByte;
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if (rst = '1') then
|
if (rst = '1') then
|
cont_steps := 0;
|
sendDataStates := idle;
|
else
|
else
|
|
case sendDataStates is
|
|
when idle =>
|
if commBlocksInitiated = '1' and startDataSend = '1' then
|
if commBlocksInitiated = '1' and startDataSend = '1' then
|
case cont_steps is
|
sendDataStates := prepare_byte;
|
when 0 =>
|
end if;
|
|
|
|
when prepare_byte =>
|
data_byte_tx <= byte_to_transmit;
|
data_byte_tx <= byte_to_transmit;
|
tx_start <= '0';
|
tx_start <= '0';
|
when 1 =>
|
sendDataStates := start_sending;
|
|
|
|
when start_sending =>
|
tx_start <= '1';
|
tx_start <= '1';
|
when others =>
|
sendDataStates := wait_completion;
|
null;
|
|
end case;
|
when wait_completion =>
|
if cont_steps < 3 then
|
if tx_data_sent = '1' then
|
cont_steps := cont_steps + 1;
|
sendDataStates := idle;
|
else
|
|
cont_steps := 3;
|
|
end if;
|
|
end if;
|
end if;
|
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Process to send the ACK signal, remember that optimally this ACK should be as fast as possible
|
-- Process to send the ACK signal, remember that optimally this ACK should be as fast as possible
|
-- to avoid locking the bus, on this case if you send a more bytes then you can transmit the ideal
|
-- to avoid locking the bus, on this case if you send a more bytes then you can transmit the ideal
|
-- is to create an error flag to indicate overrun.
|
-- is to create an error flag to indicate overrun.
|
-- On this case on any attempt of reading or writting on registers we will be lock on 1 cycle
|
-- On this case on any attempt of reading or writting on registers we will be lock on 1 cycle
|
process (clk, rst, startConfigBaud, startConfigClk, startDataSend, startReadReg )
|
process (clk, rst, startConfigBaud, startConfigClk, startDataSend, startReadReg )
|
variable joinSignal : std_logic_vector(3 downto 0);
|
variable joinSignal : std_logic_vector(3 downto 0);
|
variable cont_steps : integer range 0 to 3;
|
variable cont_steps : integer range 0 to 3;
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if rst = '1' then
|
if rst = '1' then
|
done <= '1';
|
done <= '1';
|
cont_steps := 0;
|
cont_steps := 0;
|
else
|
else
|
joinSignal := startConfigBaud & startConfigClk & startDataSend & startReadReg;
|
joinSignal := startConfigBaud & startConfigClk & startDataSend & startReadReg;
|
if (joinSignal = "0000") then
|
if (joinSignal = "0000") then
|
done <= '1';
|
done <= '1';
|
else
|
else
|
case cont_steps is
|
case cont_steps is
|
when 0 =>
|
when 0 =>
|
if start = '1' then
|
if start = '1' then
|
done <= '0';
|
done <= '0';
|
end if;
|
end if;
|
when others =>
|
when others =>
|
done <= '1';
|
done <= '1';
|
end case;
|
end case;
|
|
|
if cont_steps < 2 then
|
if cont_steps < 2 then
|
cont_steps := cont_steps + 1;
|
cont_steps := cont_steps + 1;
|
else
|
else
|
cont_steps := 0;
|
cont_steps := 0;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Process to calculate the amount of cycles to wait (clock_speed / desired_baud), and initiate the board
|
-- Process to calculate the amount of cycles to wait (clock_speed / desired_baud), and initiate the board
|
process (startConfigBaud,startConfigClk, clk)
|
process (alreadyConfClk,alreadyConfBaud, clk)
|
variable cont_steps : integer range 0 to 3;
|
variable cont_steps : integer range 0 to 3;
|
begin
|
begin
|
if (alreadyConfClk and alreadyConfBaud) = '0' then
|
if (alreadyConfClk and alreadyConfBaud) = '0' then
|
sigDivRst <= '1';
|
sigDivRst <= '1';
|
cont_steps := 0;
|
cont_steps := 0;
|
baud_wait <= (others => '0');
|
baud_wait <= (others => '0');
|
commBlocksInitiated <= '0';
|
commBlocksInitiated <= '0';
|
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
if cont_steps < 3 then
|
if cont_steps < 3 then
|
cont_steps := cont_steps + 1;
|
cont_steps := cont_steps + 1;
|
else
|
else
|
cont_steps := 3;
|
cont_steps := 3;
|
end if;
|
end if;
|
|
|
case cont_steps is
|
case cont_steps is
|
when 1 =>
|
when 1 =>
|
sigDivNumerator <= config_clk;
|
sigDivNumerator <= config_clk;
|
sigDivDividend <= config_baud;
|
sigDivDividend <= config_baud;
|
sigDivRst <= '1';
|
sigDivRst <= '1';
|
when 2 =>
|
when 2 =>
|
sigDivRst <= '0';
|
sigDivRst <= '0';
|
when others =>
|
when others =>
|
null;
|
null;
|
end case;
|
end case;
|
|
|
-- Enable the communication block when the baud is calculated
|
-- Enable the communication block when the baud is calculated
|
if sigDivDone = '1' then
|
if sigDivDone = '1' then
|
rst_comm_blocks <= '0';
|
rst_comm_blocks <= '0';
|
baud_wait <= sigDivQuotient;
|
baud_wait <= sigDivQuotient;
|
commBlocksInitiated <= '1';
|
commBlocksInitiated <= '1';
|
else
|
else
|
baud_wait <= (others => '0');
|
baud_wait <= (others => '0');
|
rst_comm_blocks <= '1';
|
rst_comm_blocks <= '1';
|
commBlocksInitiated <= '0';
|
commBlocksInitiated <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
end Behavioral;
|
end Behavioral;
|
|
|
|
|