tiny-xo2-uart-loader/top.vhd

207 lines
6.6 KiB
VHDL

-------------------------------------------------------------------------------
-- Title : MachXO2 Serial Configuration
-- Project : tiny-xo2
-------------------------------------------------------------------------------
-- File : top.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Company :
-- Created : 2017-11-21
-- Last update: 2017-11-23
-- Platform :
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2017 GPLv2
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity config_top is
generic (
CLKDIV : integer := 10);
port (
clk : in std_logic; -- input clock 12 MHz
dts : in std_logic; -- DTS Strobe signal
rst_out : out std_logic;
uart_tx : out std_logic; -- UART TX
uart_rx : in std_logic); -- UART RX
end entity config_top;
architecture RTL of config_top is
type fsm_state_t is (IDLE, CMD, EXEC, REPLY, HANG);
----------------- RESET LOGIC ------------------------------
signal dts_sync : std_logic_vector(2 downto 0) := (others => '0');
signal rst : std_logic; -- reset (high active)
----------------- UART RX ----------------------------------
signal data_rx : std_logic_vector(7 downto 0);
signal byte_ready_rx : std_logic;
signal error_rx : std_logic;
----------------- UART TX ----------------------------------
signal data_tx : std_logic_vector(7 downto 0);
signal byte_ready_tx : std_logic;
signal busy_tx : std_logic;
signal config_busy : std_logic := '1'; -- indicates that the core is in configuration/waiting mode
-- and the user logic has to stay in reset
signal config_active : std_logic := '1'; -- configuration FSM active
---------------------------- Wishbone Bus -------------------------------------
signal wb_cyc : std_logic;
signal wb_stb : std_logic;
signal wb_we : std_logic;
signal wb_adr : std_logic_vector(7 downto 0);
signal wb_dat_in : std_logic_vector(7 downto 0);
signal wb_dat_out : std_logic_vector(7 downto 0);
signal wb_ack : std_logic;
-------------------------------- State machine -----------------------------------
signal state : fsm_state_t;
signal reply_is_error : std_logic;
signal bytecounter : integer range 0 to 3 := 0;
begin -- architecture RTL
-----------------------------------------------------------------------------
------------------------------ Wishbone EFB for Config ----------------------
-----------------------------------------------------------------------------
efb_ufr_1 : entity work.efb_ufr
port map (
wb_clk_i => clk,
wb_rst_i => rst,
wb_cyc_i => wb_cyc,
wb_stb_i => wb_stb,
wb_we_i => wb_we,
wb_adr_i => wb_adr,
wb_dat_i => wb_dat_in,
wb_dat_o => wb_dat_out,
wb_ack_o => wb_ack,
wbc_ufm_irq => open);
uart_rx_1 : entity work.uart_rx
port map (
clk => clk,
rst => rst,
data => data_rx,
byte_ready => byte_ready_rx,
error => error_rx,
ckDiv => CLKDIV,
parityEnable => '1',
parityOdd => '0',
twoStopBits => '0',
rx => uart_rx);
uart_tx_1 : entity work.uart_tx
port map (
clk => clk,
rst => rst,
data => data_tx,
byte_ready => byte_ready_tx,
busy => busy_tx,
ckDiv => CLKDIV,
parityEnable => '1',
parityOdd => '0',
twoStopBits => '0',
tx => uart_tx);
-- set config_busy on reset and wait 0.25s. If FSM is not active
-- deassert config_busy
timeout_counter_busy_gen : process(clk, rst) is
variable cnt : integer range 0 to 3000000 := 3000000; -- 0.25 sec counter
begin
if rst = '1' then
cnt := 3000000;
config_busy <= '1';
elsif rising_edge(clk) then
config_busy <= '1';
if cnt /= 0 then
cnt := cnt - 1
else
if config_active = '0' then
config_busy <= '0';
end if;
end if;
end if;
end process timeout_counter_busy_gen;
-- Generate reset pulse on rising edge of dts input
reset_gen : process(clk) is
begin
if rising_edge(clk) then
rst <= '0';
dts_sync <= dts_sync(1 downto 0) & dts; -- Shif register (sync and edge detect)
if (dts_sync(2 downto 1) = "01") then -- rising edge of DTS
rst <= '1';
end if;
end if;
end process reset_gen;
-- hold user logic in reset until config finished or timeout
user_logic_reset_gen : process(clk, rst) is
begin
if rst = '1' then
rst_out <= '1';
elsif rising_edge(clk) then
if config_busy = '0' then
rst_out <= '0';
end if;
end if;
end process user_logic_reset_gen;
controlFSM : process (clk, rst) is
begin -- process controlFSM
if rst = '1' then
state <= IDLE;
config_active <= '0';
bytecounter <= 0;
reply_is_error <= '0';
-- Wishbone
wb_cyc <= '0';
wb_stb <= '0';
wb_adr <= (others => '0');
wb_dat_in <= (others => '0');
-- UART TX
data_tx <= (others => '0');
byte_ready_tx <= '0';
elsif rising_edge(clk) then
case state is
when IDLE =>
if byte_ready_rx = '1' and data_rx = x"D5" then -- Serial byte received. Is it the preambel?
state <= CMD;
bytecounter <= 0;
end if;
when CMD =>
if byte_ready_rx = '1' then
-- TODO: Byte received. Do something
end if;
when EXEC =>
null; -- TODO: handle Wishbone communication
when REPLY =>
-- TODO: if reply_is_error = '1' then: wait for response that
-- indicates that the error is handled. Then switch back to command
-- mode. Else; Just wait for response to be sent.
null;
when HANG =>
state <= HANG; -- End of FSM. Only way out is a reset
end case;
end if;
end process controlFSM;
------ Asynchronous output assignments ---------------
end architecture RTL;