2016-04-16 22:56:42 +02:00
|
|
|
--
|
|
|
|
-- Synthesizable design for testing the sine / cosine function core.
|
|
|
|
--
|
|
|
|
-- Copyright 2016 Joris van Rantwijk
|
|
|
|
--
|
|
|
|
-- This design is free software; you can redistribute it and/or
|
|
|
|
-- modify it under the terms of the GNU Lesser General Public
|
|
|
|
-- License as published by the Free Software Foundation; either
|
|
|
|
--
|
2016-04-21 22:20:32 +02:00
|
|
|
--
|
|
|
|
-- Test driver for sine / cosine core, communicates via serial port.
|
|
|
|
--
|
|
|
|
-- Send 6 bytes { 0x41 0x42 phase(7:0) phase(15:8) phase(23:16) phase(31:24) }
|
|
|
|
-- to calculate sine and cosine of phase on the 18-bit / 20-bit core.
|
|
|
|
--
|
|
|
|
-- Send 6 bytes { 0x41 0x43 phase(7:0) phase(15:8) phase(23:16) phase(31:24) }
|
|
|
|
-- to calculate sine and cosine of phase on the 24-bit / 26-bit core.
|
|
|
|
--
|
|
|
|
-- In both cases, test driver replies with 8 bytes
|
|
|
|
-- { sin(7:0) sin(15:8) sin(23:16) sin(31:24)
|
|
|
|
-- cos(7:0) cos(15:8) cos(23:16) cos(31:24 }
|
|
|
|
--
|
|
|
|
-- Send 2 bytes { 0x41 0x44 } to start clock-enable modulation.
|
|
|
|
-- Send 3 bytes { 0x41 0x45 } to stop clock-enable modulation.
|
|
|
|
--
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
library ieee;
|
|
|
|
use ieee.std_logic_1164.all;
|
|
|
|
use ieee.numeric_std.all;
|
|
|
|
|
|
|
|
entity test_sincos_serial is
|
|
|
|
|
|
|
|
generic (
|
|
|
|
-- Clock frequency divider from system clock to serial bitrate.
|
|
|
|
-- bitrate = system_clock_frequency / serial_bitrate_divider
|
2016-04-21 22:20:32 +02:00
|
|
|
serial_bitrate_divider: integer range 10 to 8192 );
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
port (
|
|
|
|
-- System clock, active on rising edge.
|
|
|
|
clk: in std_logic;
|
|
|
|
|
|
|
|
-- Synchronous reset, active high.
|
|
|
|
rst: in std_logic;
|
|
|
|
|
|
|
|
-- Serial RX input.
|
|
|
|
ser_rx: in std_logic;
|
|
|
|
|
|
|
|
-- Serial TX output.
|
2016-04-21 22:20:32 +02:00
|
|
|
ser_tx: out std_logic;
|
|
|
|
|
|
|
|
-- Status signals.
|
|
|
|
stat_ready: out std_logic;
|
|
|
|
stat_calc: out std_logic;
|
|
|
|
stat_clkmod: out std_logic;
|
|
|
|
stat_txser: out std_logic );
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
end entity;
|
|
|
|
|
|
|
|
architecture rtl of test_sincos_serial is
|
|
|
|
|
2016-04-21 22:20:32 +02:00
|
|
|
constant core1_latency: integer := 6;
|
|
|
|
constant core2_latency: integer := 9;
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
signal r_clk_en: std_logic;
|
|
|
|
signal r_in_phase: unsigned(31 downto 0);
|
|
|
|
signal s_gen1_out_sin: signed(17 downto 0);
|
|
|
|
signal s_gen1_out_cos: signed(17 downto 0);
|
|
|
|
signal s_gen2_out_sin: signed(23 downto 0);
|
|
|
|
signal s_gen2_out_cos: signed(23 downto 0);
|
|
|
|
|
|
|
|
signal r_tst_start: std_logic;
|
2016-04-21 22:20:32 +02:00
|
|
|
signal r_tst_coresel: std_logic;
|
2016-04-21 00:43:35 +02:00
|
|
|
signal r_tst_in_phase: std_logic_vector(31 downto 0);
|
|
|
|
signal r_tst_out_sin: std_logic_vector(31 downto 0);
|
|
|
|
signal r_tst_out_cos: std_logic_vector(31 downto 0);
|
2016-04-16 22:56:42 +02:00
|
|
|
signal r_tst_busy: std_logic;
|
|
|
|
signal r_tst_cyclecnt: unsigned(3 downto 0);
|
|
|
|
|
|
|
|
signal r_clkmod: std_logic;
|
|
|
|
signal r_clkmod_cnt: unsigned(3 downto 0);
|
|
|
|
signal r_clkmod_tmp: std_logic;
|
|
|
|
|
2016-04-19 21:02:14 +02:00
|
|
|
signal r_ctl_state: std_logic_vector(3 downto 0);
|
|
|
|
|
2016-04-16 22:56:42 +02:00
|
|
|
signal r_ser_rx_strobe: std_logic;
|
|
|
|
signal r_ser_rx_byte: std_logic_vector(7 downto 0);
|
2016-04-18 21:14:31 +02:00
|
|
|
signal r_ser_rx_glitch: std_logic_vector(7 downto 0);
|
|
|
|
signal r_ser_rx_bit: std_logic;
|
|
|
|
signal r_ser_rx_timer: unsigned(12 downto 0);
|
|
|
|
signal r_ser_rx_timeout: std_logic;
|
2016-04-21 00:43:35 +02:00
|
|
|
signal r_ser_rx_state: std_logic_vector(1 downto 0);
|
2016-04-18 21:14:31 +02:00
|
|
|
signal r_ser_rx_shift: std_logic_vector(8 downto 0);
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
signal r_ser_tx_strobe: std_logic;
|
|
|
|
signal r_ser_tx_busy: std_logic;
|
|
|
|
signal r_ser_tx_byte: std_logic_vector(7 downto 0);
|
2016-04-18 21:14:31 +02:00
|
|
|
signal r_ser_tx_bit: std_logic;
|
|
|
|
signal r_ser_tx_timer: unsigned(12 downto 0);
|
|
|
|
signal r_ser_tx_timeout: std_logic;
|
|
|
|
signal r_ser_tx_bitcnt: unsigned(3 downto 0);
|
|
|
|
signal r_ser_tx_shift: std_logic_vector(7 downto 0);
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
-- Instantiate 18-bit sin/cos core.
|
2016-04-21 22:20:32 +02:00
|
|
|
gen1: entity work.sincos_gen_d18_p20
|
|
|
|
port map (
|
|
|
|
clk => clk,
|
|
|
|
clk_en => r_clk_en,
|
|
|
|
in_phase => r_in_phase(19 downto 0),
|
|
|
|
out_sin => s_gen1_out_sin,
|
|
|
|
out_cos => s_gen1_out_cos );
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
-- Instantiate 24-bit sin/cos core.
|
2016-04-21 22:20:32 +02:00
|
|
|
gen2: entity work.sincos_gen_d24_p26
|
|
|
|
port map (
|
|
|
|
clk => clk,
|
|
|
|
clk_en => r_clk_en,
|
|
|
|
in_phase => r_in_phase(25 downto 0),
|
|
|
|
out_sin => s_gen2_out_sin,
|
|
|
|
out_cos => s_gen2_out_cos );
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
-- Synchronous process.
|
|
|
|
-- State machine for interface to design under test.
|
|
|
|
process (clk) is
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
|
|
|
if r_clk_en = '1' then
|
|
|
|
r_tst_cyclecnt <= r_tst_cyclecnt + 1;
|
|
|
|
r_in_phase <= (others => '0');
|
|
|
|
end if;
|
|
|
|
|
2016-04-21 22:20:32 +02:00
|
|
|
if r_tst_busy = '1' and r_tst_coresel = '0' and
|
|
|
|
r_tst_cyclecnt = core1_latency then
|
|
|
|
r_tst_busy <= '0';
|
|
|
|
r_tst_out_sin <= std_logic_vector(resize(s_gen1_out_sin, 32));
|
|
|
|
r_tst_out_cos <= std_logic_vector(resize(s_gen1_out_cos, 32));
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_tst_busy = '1' and r_tst_coresel = '1' and
|
|
|
|
r_tst_cyclecnt = core2_latency then
|
2016-04-16 22:56:42 +02:00
|
|
|
r_tst_busy <= '0';
|
2016-04-21 22:20:32 +02:00
|
|
|
r_tst_out_sin <= std_logic_vector(resize(s_gen2_out_sin, 32));
|
|
|
|
r_tst_out_cos <= std_logic_vector(resize(s_gen2_out_cos, 32));
|
2016-04-16 22:56:42 +02:00
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_tst_start = '1' and r_tst_busy = '0' then
|
|
|
|
r_tst_busy <= '1';
|
2016-04-21 00:43:35 +02:00
|
|
|
r_in_phase <= unsigned(r_tst_in_phase);
|
2016-04-16 22:56:42 +02:00
|
|
|
r_tst_cyclecnt <= (others => '0');
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if rst = '1' then
|
|
|
|
r_tst_busy <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
end process;
|
|
|
|
|
|
|
|
-- Synchronous process.
|
|
|
|
-- Drive clk_en signal (continuous or modulated).
|
|
|
|
process (clk) is
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
2016-04-19 21:02:14 +02:00
|
|
|
if r_clkmod = '0' then
|
2016-04-16 22:56:42 +02:00
|
|
|
-- Clock-enable modulation disabled.
|
|
|
|
r_clk_en <= '1';
|
|
|
|
else
|
|
|
|
-- Clock-enable modulation active.
|
|
|
|
r_clk_en <= r_clkmod_tmp;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- Make r_clkmod_tmp high on 5 out of 16 cycles.
|
|
|
|
if r_clkmod_cnt = 1 or r_clkmod_cnt = 4 or r_clkmod_cnt = 5 or
|
|
|
|
r_clkmod_cnt = 7 or r_clkmod_cnt = 12 then
|
|
|
|
r_clkmod_tmp <= '1';
|
|
|
|
else
|
|
|
|
r_clkmod_tmp <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
r_clkmod_cnt <= r_clkmod_cnt + 1;
|
|
|
|
|
|
|
|
if rst = '1' then
|
|
|
|
r_clkmod_cnt <= (others => '0');
|
|
|
|
r_clkmod_tmp <= '0';
|
|
|
|
r_clk_en <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
end process;
|
|
|
|
|
2016-04-19 21:02:14 +02:00
|
|
|
-- Synchronous process.
|
|
|
|
-- Byte-level serial protocol.
|
|
|
|
process (clk) is
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
|
|
|
r_ser_tx_strobe <= '0';
|
|
|
|
r_tst_start <= '0';
|
|
|
|
|
|
|
|
if r_ctl_state = "0000" and
|
|
|
|
r_ser_rx_strobe = '1' and r_ser_rx_byte = x"41" then
|
|
|
|
r_ctl_state <= "0001";
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "0001" and r_ser_rx_strobe = '1' then
|
|
|
|
if r_ser_rx_byte = x"42" then
|
|
|
|
r_ctl_state <= "0010";
|
2016-04-21 22:20:32 +02:00
|
|
|
r_tst_coresel <= '0';
|
2016-04-19 21:02:14 +02:00
|
|
|
elsif r_ser_rx_byte = x"43" then
|
2016-04-21 22:20:32 +02:00
|
|
|
r_ctl_state <= "0010";
|
|
|
|
r_tst_coresel <= '1';
|
|
|
|
elsif r_ser_rx_byte = x"44" then
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ctl_state <= "0000";
|
|
|
|
r_clkmod <= '1';
|
2016-04-21 22:20:32 +02:00
|
|
|
elsif r_ser_rx_byte = x"45" then
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ctl_state <= "0000";
|
|
|
|
r_clkmod <= '0';
|
|
|
|
else
|
|
|
|
r_ctl_state <= "0000";
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "0010" and r_ser_rx_strobe = '1' then
|
|
|
|
r_ctl_state <= "0011";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_tst_in_phase <= r_ser_rx_byte & r_tst_in_phase(31 downto 8);
|
2016-04-19 21:02:14 +02:00
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "0011" and r_ser_rx_strobe = '1' then
|
|
|
|
r_ctl_state <= "0100";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_tst_in_phase <= r_ser_rx_byte & r_tst_in_phase(31 downto 8);
|
2016-04-19 21:02:14 +02:00
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "0100" and r_ser_rx_strobe = '1' then
|
|
|
|
r_ctl_state <= "0101";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_tst_in_phase <= r_ser_rx_byte & r_tst_in_phase(31 downto 8);
|
2016-04-19 21:02:14 +02:00
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "0101" and r_ser_rx_strobe = '1' then
|
|
|
|
r_ctl_state <= "0110";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_tst_in_phase <= r_ser_rx_byte & r_tst_in_phase(31 downto 8);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_tst_start <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "0110" and r_tst_start = '0' and r_tst_busy = '0' then
|
|
|
|
r_ctl_state <= "0111";
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "0111" and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "1000";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_sin(7 downto 0);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "1000" and r_ser_tx_strobe = '0' and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "1001";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_sin(15 downto 8);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "1001" and r_ser_tx_strobe = '0' and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "1010";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_sin(23 downto 16);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "1010" and r_ser_tx_strobe = '0' and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "1011";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_sin(31 downto 24);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "1011" and r_ser_tx_strobe = '0' and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "1100";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_cos(7 downto 0);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "1100" and r_ser_tx_strobe = '0' and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "1101";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_cos(15 downto 8);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "1101" and r_ser_tx_strobe = '0' and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "1110";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_cos(23 downto 16);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ctl_state = "1110" and r_ser_tx_strobe = '0' and r_ser_tx_busy = '0' then
|
|
|
|
r_ctl_state <= "0000";
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_byte <= r_tst_out_cos(31 downto 24);
|
2016-04-19 21:02:14 +02:00
|
|
|
r_ser_tx_strobe <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- Synchronous reset.
|
|
|
|
if rst = '1' then
|
|
|
|
r_ctl_state <= "0000";
|
|
|
|
r_clkmod <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
end process;
|
2016-04-16 22:56:42 +02:00
|
|
|
|
2016-04-21 22:20:32 +02:00
|
|
|
-- Synchronous process.
|
|
|
|
-- Drive status output signals.
|
|
|
|
process (clk) is
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
|
|
|
if r_ctl_state = "0000" then
|
|
|
|
stat_ready <= '1';
|
|
|
|
else
|
|
|
|
stat_ready <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
stat_calc <= r_tst_busy;
|
|
|
|
stat_clkmod <= r_clkmod;
|
|
|
|
stat_txser <= r_ser_tx_busy;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
end process;
|
|
|
|
|
2016-04-18 21:14:31 +02:00
|
|
|
-- Synchronous process.
|
|
|
|
-- Serial port RX machine.
|
|
|
|
process (clk) is
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
|
|
|
-- Default.
|
|
|
|
r_ser_rx_strobe <= '0';
|
|
|
|
|
|
|
|
-- Deglitch filter.
|
|
|
|
r_ser_rx_glitch <= r_ser_rx_glitch(6 downto 0) & ser_rx;
|
|
|
|
if r_ser_rx_glitch(7 downto 1) = "0000000" then
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_rx_bit <= '0';
|
2016-04-18 21:14:31 +02:00
|
|
|
elsif r_ser_rx_glitch(7 downto 1) = "1111111" then
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_rx_bit <= '1';
|
2016-04-18 21:14:31 +02:00
|
|
|
end if;
|
|
|
|
|
|
|
|
-- Bit timer.
|
|
|
|
r_ser_rx_timer <= r_ser_rx_timer - 1;
|
|
|
|
if r_ser_rx_timer = 0 then
|
|
|
|
r_ser_rx_timeout <= '1';
|
|
|
|
else
|
|
|
|
r_ser_rx_timeout <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- RX state machine.
|
|
|
|
if r_ser_rx_state = "00" then
|
|
|
|
-- Wait for idle level.
|
|
|
|
if r_ser_rx_bit = '1' then
|
|
|
|
r_ser_rx_state <= "01";
|
|
|
|
end if;
|
|
|
|
elsif r_ser_rx_state = "01" then
|
|
|
|
-- Wait for start of byte.
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_rx_timer <= to_unsigned(serial_bitrate_divider / 2 - 2, r_ser_rx_timer'length);
|
2016-04-18 21:14:31 +02:00
|
|
|
r_ser_rx_timeout <= '0';
|
|
|
|
if r_ser_rx_bit = '0' then
|
|
|
|
r_ser_rx_state <= "10";
|
|
|
|
end if;
|
|
|
|
elsif r_ser_rx_state = "10" then
|
2016-04-21 22:20:32 +02:00
|
|
|
-- Check start bit.
|
|
|
|
r_ser_rx_shift(7 downto 0) <= (others => '1');
|
|
|
|
r_ser_rx_shift(8) <= '0';
|
|
|
|
if r_ser_rx_timeout = '1' then
|
|
|
|
if r_ser_rx_bit = '0' then
|
|
|
|
r_ser_rx_state <= "11";
|
|
|
|
else
|
|
|
|
r_ser_rx_state <= "00";
|
|
|
|
end if;
|
|
|
|
r_ser_rx_timer <= to_unsigned(serial_bitrate_divider - 2, r_ser_rx_timer'length);
|
|
|
|
end if;
|
|
|
|
elsif r_ser_rx_state = "11" then
|
2016-04-18 21:14:31 +02:00
|
|
|
-- Wait for data bit.
|
|
|
|
if r_ser_rx_timeout = '1' then
|
|
|
|
r_ser_rx_shift <= r_ser_rx_bit & r_ser_rx_shift(8 downto 1);
|
2016-04-21 22:20:32 +02:00
|
|
|
if r_ser_rx_shift(0) = '0' then
|
2016-04-18 21:14:31 +02:00
|
|
|
-- Reached end of byte.
|
|
|
|
if r_ser_rx_bit = '1' then
|
|
|
|
-- Got valid stop bit.
|
2016-04-21 22:20:32 +02:00
|
|
|
r_ser_rx_byte <= r_ser_rx_shift(8 downto 1);
|
2016-04-18 21:14:31 +02:00
|
|
|
r_ser_rx_strobe <= '1';
|
|
|
|
r_ser_rx_state <= "01";
|
|
|
|
else
|
|
|
|
-- Got invalid stop bit.
|
|
|
|
r_ser_rx_state <= "00";
|
|
|
|
end if;
|
|
|
|
end if;
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_rx_timer <= to_unsigned(serial_bitrate_divider - 2, r_ser_rx_timer'length);
|
2016-04-18 21:14:31 +02:00
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- Synchronous reset.
|
|
|
|
if rst = '1' then
|
|
|
|
r_ser_rx_state <= "00";
|
|
|
|
r_ser_rx_strobe <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
end process;
|
|
|
|
|
|
|
|
-- Synchronous process.
|
|
|
|
-- Serial port TX machine.
|
|
|
|
process (clk) is
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
|
|
|
-- Drive output register.
|
|
|
|
ser_tx <= r_ser_tx_bit;
|
|
|
|
|
|
|
|
-- Bit timer.
|
|
|
|
r_ser_tx_timer <= r_ser_tx_timer - 1;
|
|
|
|
if r_ser_tx_timer = 0 then
|
|
|
|
r_ser_tx_timeout <= '1';
|
|
|
|
else
|
|
|
|
r_ser_tx_timeout <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
if r_ser_tx_busy = '0' then
|
|
|
|
|
|
|
|
-- Wait for start of byte.
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_timer <= to_unsigned(serial_bitrate_divider - 2, r_ser_tx_timer'length);
|
2016-04-18 21:14:31 +02:00
|
|
|
r_ser_tx_timeout <= '0';
|
|
|
|
r_ser_tx_shift <= r_ser_tx_byte;
|
|
|
|
r_ser_tx_bitcnt <= to_unsigned(9, 4);
|
|
|
|
if r_ser_tx_strobe = '1' then
|
|
|
|
-- Start new byte.
|
|
|
|
r_ser_tx_bit <= '0';
|
|
|
|
r_ser_tx_busy <= '1';
|
|
|
|
end if;
|
|
|
|
|
2016-04-21 00:43:35 +02:00
|
|
|
elsif r_ser_tx_busy = '1' and r_ser_tx_timeout = '1' then
|
2016-04-18 21:14:31 +02:00
|
|
|
|
|
|
|
-- Send next bit.
|
|
|
|
r_ser_tx_bit <= r_ser_tx_shift(0);
|
|
|
|
r_ser_tx_shift <= "1" & r_ser_tx_shift(7 downto 1);
|
|
|
|
r_ser_tx_bitcnt <= r_ser_tx_bitcnt - 1;
|
2016-04-21 00:43:35 +02:00
|
|
|
r_ser_tx_timer <= to_unsigned(serial_bitrate_divider - 2, r_ser_tx_timer'length);
|
2016-04-18 21:14:31 +02:00
|
|
|
if r_ser_tx_bitcnt = 0 then
|
|
|
|
-- Just completed stop bit.
|
|
|
|
r_ser_tx_busy <= '0';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- Synchronous reset.
|
|
|
|
if rst = '1' then
|
|
|
|
r_ser_tx_busy <= '0';
|
|
|
|
r_ser_tx_bit <= '1';
|
|
|
|
end if;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
end process;
|
2016-04-16 22:56:42 +02:00
|
|
|
|
|
|
|
end architecture;
|