From 2e5c4532450def61962d0298ab49e344b8db8013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= <tomasz.wlostowski@cern.ch> Date: Tue, 31 Jan 2012 16:04:40 +0100 Subject: [PATCH] wishbone: added Xilinx FPGA serial loader (wb_xilinx_fpga_loader) --- modules/wishbone/Manifest.py | 3 +- .../wb_xilinx_fpga_loader/Manifest.py | 5 + .../wb_xilinx_fpga_loader/build_wb.sh | 3 + .../wb_xilinx_fpga_loader.vhd | 363 ++++++++++++++++++ .../xloader_registers_pkg.vhd | 84 ++++ .../wb_xilinx_fpga_loader/xloader_wb.vhd | 329 ++++++++++++++++ .../wb_xilinx_fpga_loader/xloader_wb.wb | 152 ++++++++ .../xwb_xilinx_fpga_loader.vhd | 131 +++++++ 8 files changed, 1068 insertions(+), 2 deletions(-) create mode 100644 modules/wishbone/wb_xilinx_fpga_loader/Manifest.py create mode 100755 modules/wishbone/wb_xilinx_fpga_loader/build_wb.sh create mode 100644 modules/wishbone/wb_xilinx_fpga_loader/wb_xilinx_fpga_loader.vhd create mode 100644 modules/wishbone/wb_xilinx_fpga_loader/xloader_registers_pkg.vhd create mode 100644 modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.vhd create mode 100644 modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.wb create mode 100644 modules/wishbone/wb_xilinx_fpga_loader/xwb_xilinx_fpga_loader.vhd diff --git a/modules/wishbone/Manifest.py b/modules/wishbone/Manifest.py index c8ee88c..5468b7f 100644 --- a/modules/wishbone/Manifest.py +++ b/modules/wishbone/Manifest.py @@ -1,11 +1,9 @@ modules = { "local" : - [ "wb_async_bridge", "wb_onewire_master", "wb_i2c_master", "wb_bus_fanout", -# "wb_conmax", "wb_dpram", "wb_gpio_port", "wb_simple_timer", @@ -15,6 +13,7 @@ modules = { "local" : "wb_crossbar", "wb_lm32", "wb_slave_adapter", + "wb_xilinx_fpga_loader", "wbgen2" ]}; diff --git a/modules/wishbone/wb_xilinx_fpga_loader/Manifest.py b/modules/wishbone/wb_xilinx_fpga_loader/Manifest.py new file mode 100644 index 0000000..08062c9 --- /dev/null +++ b/modules/wishbone/wb_xilinx_fpga_loader/Manifest.py @@ -0,0 +1,5 @@ +files = [ +"wb_xilinx_fpga_loader.vhd", +"xwb_xilinx_fpga_loader.vhd", +"xloader_registers_pkg.vhd", +"xloader_wb.vhd"]; diff --git a/modules/wishbone/wb_xilinx_fpga_loader/build_wb.sh b/modules/wishbone/wb_xilinx_fpga_loader/build_wb.sh new file mode 100755 index 0000000..5d1d03f --- /dev/null +++ b/modules/wishbone/wb_xilinx_fpga_loader/build_wb.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +wbgen2 -V xloader_wb.vhd -H record -p xloader_registers_pkg.vhd -K ../../../sim/regs/xloader_regs.vh -s defines -C xloader_regs.h -D wb_xilinx_fpga_loader.html xloader_wb.wb \ No newline at end of file diff --git a/modules/wishbone/wb_xilinx_fpga_loader/wb_xilinx_fpga_loader.vhd b/modules/wishbone/wb_xilinx_fpga_loader/wb_xilinx_fpga_loader.vhd new file mode 100644 index 0000000..77938c4 --- /dev/null +++ b/modules/wishbone/wb_xilinx_fpga_loader/wb_xilinx_fpga_loader.vhd @@ -0,0 +1,363 @@ +------------------------------------------------------------------------------- +-- Title : Xilinx FPGA Loader +-- Project : General Cores Library +------------------------------------------------------------------------------- +-- File : wb_xilinx_fpga_loader.vhd +-- Author : Tomasz Włostowski +-- Company : CERN BE-CO-HT +-- Created : 2012-01-30 +-- Last update : 2012-01-30 +-- Platform : FPGA-generic +-- Standard : VHDL '93 +-- Dependencies : xldr_wbgen2_pkg, gencores_pkg, wbgen2_pkg, gc_sync_ffs +-- xloader_wb, wb_slave_adapter, wishbone_pkg +------------------------------------------------------------------------------- +-- Description: Wishbone compatible Xilinx serial port bitstream loader. +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2012 CERN +-- +-- This source file 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 version 2.1 of the License, or (at your option) any +-- later version. +-- +-- This source 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 Lesser General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Lesser General +-- Public License along with this source; if not, download it +-- from http://www.gnu.org/licenses/lgpl-2.1.html +-- +------------------------------------------------------------------------------- +-- Revisions : +-- Date Version Author Description +-- 2012-01-30 1.0 twlostow Created +------------------------------------------------------------------------------- + +library ieee; +use ieee.STD_LOGIC_1164.all; +use ieee.numeric_std.all; + +use work.gencores_pkg.all; +use work.wishbone_pkg.all; +use work.xldr_wbgen2_pkg.all; + +entity wb_xilinx_fpga_loader is + generic( + g_interface_mode : t_wishbone_interface_mode := CLASSIC; + g_address_granularity : t_wishbone_address_granularity := WORD + ); + port ( +-- system clock + clk_sys_i : in std_logic; +-- synchronous reset, active LOW + rst_n_i : in std_logic; + +-- Wishbone bus + wb_cyc_i : in std_logic; + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_adr_i : in std_logic_vector(c_wishbone_address_width - 1 downto 0); + wb_sel_i : in std_logic_vector((c_wishbone_data_width + 7) / 8 - 1 downto 0); + wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0); + wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0); + wb_ack_o : out std_logic; + wb_stall_o : out std_logic; + +-- Configuration clock (to pin CCLK) + xlx_cclk_o : out std_logic := '0'; +-- Data output (to pin D0/DIN) + xlx_din_o : out std_logic; +-- Program enable pin (active low, to pin PROG_B) + xlx_program_b_o : out std_logic := '1'; +-- Init ready pin (active low, to pin INIT_B) + xlx_init_b_i : in std_logic; +-- Configuration done pin (to pin DONE) + xlx_done_i : in std_logic; +-- FPGA suspend pin + xlx_suspend_o : out std_logic; + +-- FPGA mode select pin. Connect to M1..M0 pins of the FPGA or leave open if +-- the pins are hardwired on the PCB + xlx_m_o : out std_logic_vector(1 downto 0) + ); + +end wb_xilinx_fpga_loader; + +architecture behavioral of wb_xilinx_fpga_loader is + + component xloader_wb + port ( + rst_n_i : in std_logic; + wb_clk_i : in std_logic; + wb_addr_i : in std_logic_vector(1 downto 0); + wb_data_i : in std_logic_vector(31 downto 0); + wb_data_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + regs_i : in t_xldr_in_registers; + regs_o : out t_xldr_out_registers); + end component; + + type t_xloader_state is (IDLE, WAIT_INIT, WAIT_INIT2, READ_FIFO, READ_FIFO2, OUTPUT_BIT, CLOCK_EDGE, WAIT_DONE, EXTEND_PROG); + + signal state : t_xloader_state; + signal clk_div : unsigned(6 downto 0); + signal tick : std_logic; + signal init_b_synced : std_logic; + signal done_synced : std_logic; + signal timeout_counter : unsigned(20 downto 0); + signal wb_in : t_wishbone_master_out; + signal wb_out : t_wishbone_master_in; + signal regs_in : t_xldr_out_registers; + signal regs_out : t_xldr_in_registers; + + -- PROG_B assertion duration + constant c_MIN_PROG_DELAY : unsigned(timeout_counter'left downto 0) := to_unsigned(1000, timeout_counter'length); + + + -- PROG_B active to INIT_B active timeout + constant c_INIT_TIMEOUT : unsigned(timeout_counter'left downto 0) := to_unsigned(200000, timeout_counter'length); + + -- Last word written to DONE active timeout + constant c_DONE_TIMEOUT : unsigned(timeout_counter'left downto 0) := to_unsigned(200000, timeout_counter'length); + + signal d_data : std_logic_vector(31 downto 0); + signal d_size : std_logic_vector(1 downto 0); + signal d_last : std_logic; + + signal bit_counter : unsigned(4 downto 0); + +begin -- behavioral + + +-- Pipelined-classic adapter/converter + U_Adapter : wb_slave_adapter + generic map ( + g_master_use_struct => true, + g_master_mode => CLASSIC, + g_master_granularity => WORD, + g_slave_use_struct => false, + g_slave_mode => g_interface_mode, + g_slave_granularity => g_address_granularity) + port map ( + clk_sys_i => clk_sys_i, + rst_n_i => rst_n_i, + + sl_cyc_i => wb_cyc_i, + sl_stb_i => wb_stb_i, + sl_we_i => wb_we_i, + sl_adr_i => wb_adr_i, + sl_sel_i => wb_sel_i, + sl_dat_i => wb_dat_i, + sl_dat_o => wb_dat_o, + sl_ack_o => wb_ack_o, + sl_stall_o => wb_stall_o, + + master_i => wb_out, + master_o => wb_in); + + wb_out.err <= '0'; + wb_out.rty <= '0'; + wb_out.stall <= '0'; + wb_out.int <= '0'; + + xlx_m_o <= "11"; -- permamently select Passive serial + -- boot mode + + xlx_suspend_o <= '0'; -- suspend feature is not used + +-- Synchronization chains for async INIT_B and DONE inputs + U_Sync_INIT : gc_sync_ffs + generic map ( + g_sync_edge => "positive") + port map ( + clk_i => clk_sys_i, + rst_n_i => rst_n_i, + data_i => xlx_init_b_i, + synced_o => init_b_synced); + + U_Sync_DONE : gc_sync_ffs + generic map ( + g_sync_edge => "positive") + port map ( + clk_i => clk_sys_i, + rst_n_i => rst_n_i, + data_i => xlx_done_i, + synced_o => done_synced); + + -- Clock divider. Genrates a single-cycle pulse on "tick" signal every + -- CSR.CLKDIV system clock cycles. + p_divide_clock : process(clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if rst_n_i = '0' then + clk_div <= (others => '0'); + tick <= '0'; + else + if(clk_div = unsigned(regs_in.csr_clkdiv_o)) then + tick <= '1'; + clk_div <= (others => '0'); + else + tick <= '0'; + clk_div <= clk_div + 1; + end if; + end if; + end if; + end process; + + + p_main_fsm : process(clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if rst_n_i = '0' or regs_in.csr_swrst_o = '1' then + state <= IDLE; + xlx_program_b_o <= '1'; + xlx_cclk_o <= '0'; + xlx_din_o <= '0'; + timeout_counter <= (others => '0'); + + regs_out.csr_done_i <= '0'; + regs_out.csr_error_i <= '0'; + else + case state is + when IDLE => + + timeout_counter <= c_INIT_TIMEOUT; + if(regs_in.csr_start_o = '1') then + xlx_program_b_o <= '0'; + regs_out.csr_done_i <= '0'; + regs_out.csr_error_i <= '0'; + state <= EXTEND_PROG; + timeout_counter <= c_MIN_PROG_DELAY; + end if; + + when EXTEND_PROG => + timeout_counter <= timeout_counter-1; + + if(timeout_counter = 0) then + timeout_counter <= c_INIT_TIMEOUT; + state <= WAIT_INIT; + end if; + + when WAIT_INIT => + timeout_counter <= timeout_counter - 1; + + if(timeout_counter = 0) then + regs_out.csr_error_i <= '1'; + regs_out.csr_done_i <= '1'; + state <= IDLE; + end if; + + if (init_b_synced = '0') then + state <= WAIT_INIT2; + xlx_program_b_o <= '1'; + end if; + + when WAIT_INIT2 => + if (init_b_synced /= '0') then + state <= READ_FIFO; + end if; + + when READ_FIFO => + xlx_cclk_o <= '0'; + + if(regs_in.fifo_rd_empty_o = '0') then + state <= READ_FIFO2; + end if; + + when READ_FIFO2 => + + + -- handle byte swapping + if(regs_in.csr_msbf_o = '0') then + d_data(31 downto 24) <= regs_in.fifo_xdata_o(7 downto 0); + d_data(23 downto 16) <= regs_in.fifo_xdata_o(15 downto 8); + d_data(15 downto 8) <= regs_in.fifo_xdata_o(23 downto 16); + d_data(7 downto 0) <= regs_in.fifo_xdata_o(31 downto 24); -- little-endian + else + d_data <= regs_in.fifo_xdata_o; -- big-endian + end if; + + d_size <= regs_in.fifo_xsize_o; + d_last <= regs_in.fifo_xlast_o; + + if(tick = '1') then + state <= OUTPUT_BIT; + bit_counter <= unsigned(regs_in.fifo_xsize_o) & "111"; + end if; + + when OUTPUT_BIT => + if(tick = '1') then + xlx_din_o <= d_data(31); + xlx_cclk_o <= '0'; + d_data(d_data'left downto 1) <= d_data(d_data'left-1 downto 0); + state <= CLOCK_EDGE; + end if; + + when CLOCK_EDGE => + if(tick = '1') then + xlx_cclk_o <= '1'; + + bit_counter <= bit_counter - 1; + + if(bit_counter = 0) then + if(d_last = '1') then + state <= WAIT_DONE; + timeout_counter <= c_DONE_TIMEOUT; + else + state <= READ_FIFO; + end if; + else + state <= OUTPUT_BIT; + end if; + end if; + + + when WAIT_DONE => + if(done_synced = '1') then + state <= IDLE; + regs_out.csr_done_i <= '1'; + regs_out.csr_error_i <= '0'; + end if; + + timeout_counter <= timeout_counter - 1; + + if(timeout_counter = 0) then + state <= IDLE; + regs_out.csr_error_i <= '1'; + regs_out.csr_done_i <= '1'; + end if; + + end case; + end if; + end if; + end process; + + regs_out.csr_busy_i <= '0' when (state = IDLE) else '1'; + regs_out.fifo_rd_req_i <= '1' when ((regs_in.fifo_rd_empty_o = '0') and (state = IDLE or state = READ_FIFO)) else '0'; + + U_WB_SLAVE : xloader_wb + port map ( + rst_n_i => rst_n_i, + wb_clk_i => clk_sys_i, + wb_addr_i => wb_in.adr(1 downto 0), + wb_data_i => wb_in.dat(31 downto 0), + wb_data_o => wb_out.dat(31 downto 0), + wb_cyc_i => wb_in.cyc, + wb_sel_i => wb_in.sel(3 downto 0), + wb_stb_i => wb_in.stb, + wb_we_i => wb_in.we, + wb_ack_o => wb_out.ack, + regs_o => regs_in, + regs_i => regs_out); + +end behavioral; diff --git a/modules/wishbone/wb_xilinx_fpga_loader/xloader_registers_pkg.vhd b/modules/wishbone/wb_xilinx_fpga_loader/xloader_registers_pkg.vhd new file mode 100644 index 0000000..3dfd987 --- /dev/null +++ b/modules/wishbone/wb_xilinx_fpga_loader/xloader_registers_pkg.vhd @@ -0,0 +1,84 @@ +--------------------------------------------------------------------------------------- +-- Title : Wishbone slave core for Xilinx FPGA loader +--------------------------------------------------------------------------------------- +-- File : xloader_registers_pkg.vhd +-- Author : auto-generated by wbgen2 from xloader_wb.wb +-- Created : Tue Jan 31 15:31:31 2012 +-- Standard : VHDL'87 +--------------------------------------------------------------------------------------- +-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE xloader_wb.wb +-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY! +--------------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.wbgen2_pkg.all; + +package xldr_wbgen2_pkg is + + + -- Input registers (user design -> WB slave) + + type t_xldr_in_registers is record + csr_done_i : std_logic; + csr_error_i : std_logic; + csr_busy_i : std_logic; + fifo_rd_req_i : std_logic; + end record; + + constant c_xldr_in_registers_init_value: t_xldr_in_registers := ( + csr_done_i => '0', + csr_error_i => '0', + csr_busy_i => '0', + fifo_rd_req_i => '0' + ); + + -- Output registers (WB slave -> user design) + + type t_xldr_out_registers is record + csr_start_o : std_logic; + csr_msbf_o : std_logic; + csr_swrst_o : std_logic; + csr_clkdiv_o : std_logic_vector(5 downto 0); + fifo_rd_full_o : std_logic; + fifo_rd_empty_o : std_logic; + fifo_xsize_o : std_logic_vector(1 downto 0); + fifo_xlast_o : std_logic; + fifo_xdata_o : std_logic_vector(31 downto 0); + end record; + + constant c_xldr_out_registers_init_value: t_xldr_out_registers := ( + csr_start_o => '0', + csr_msbf_o => '0', + csr_swrst_o => '0', + csr_clkdiv_o => (others => '0'), + fifo_rd_full_o => '0', + fifo_rd_empty_o => '0', + fifo_xsize_o => (others => '0'), + fifo_xlast_o => '0', + fifo_xdata_o => (others => '0') + ); + function "or" (left, right: t_xldr_in_registers) return t_xldr_in_registers; + function f_x_to_zero (x:std_logic) return std_logic; +end package; + +package body xldr_wbgen2_pkg is +function f_x_to_zero (x:std_logic) return std_logic is +begin +if(x = 'X' or x = 'U') then +return '0'; +else +return x; +end if; +end function; +function "or" (left, right: t_xldr_in_registers) return t_xldr_in_registers is +variable tmp: t_xldr_in_registers; +begin +tmp.csr_done_i := left.csr_done_i or right.csr_done_i; +tmp.csr_error_i := left.csr_error_i or right.csr_error_i; +tmp.csr_busy_i := left.csr_busy_i or right.csr_busy_i; +tmp.fifo_rd_req_i := left.fifo_rd_req_i or right.fifo_rd_req_i; +return tmp; +end function; +end package body; diff --git a/modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.vhd b/modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.vhd new file mode 100644 index 0000000..aab91d0 --- /dev/null +++ b/modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.vhd @@ -0,0 +1,329 @@ +--------------------------------------------------------------------------------------- +-- Title : Wishbone slave core for Xilinx FPGA loader +--------------------------------------------------------------------------------------- +-- File : xloader_wb.vhd +-- Author : auto-generated by wbgen2 from xloader_wb.wb +-- Created : Tue Jan 31 15:31:31 2012 +-- Standard : VHDL'87 +--------------------------------------------------------------------------------------- +-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE xloader_wb.wb +-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY! +--------------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.wbgen2_pkg.all; + +use work.xldr_wbgen2_pkg.all; + + +entity xloader_wb is + port ( + rst_n_i : in std_logic; + wb_clk_i : in std_logic; + wb_addr_i : in std_logic_vector(1 downto 0); + wb_data_i : in std_logic_vector(31 downto 0); + wb_data_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + regs_i : in t_xldr_in_registers; + regs_o : out t_xldr_out_registers + ); +end xloader_wb; + +architecture syn of xloader_wb is + +signal xldr_csr_start_dly0 : std_logic ; +signal xldr_csr_start_int : std_logic ; +signal xldr_csr_msbf_int : std_logic ; +signal xldr_csr_swrst_dly0 : std_logic ; +signal xldr_csr_swrst_int : std_logic ; +signal xldr_csr_clkdiv_int : std_logic_vector(5 downto 0); +signal xldr_fifo_in_int : std_logic_vector(34 downto 0); +signal xldr_fifo_out_int : std_logic_vector(34 downto 0); +signal xldr_fifo_wrreq_int : std_logic ; +signal xldr_fifo_full_int : std_logic ; +signal xldr_fifo_empty_int : std_logic ; +signal xldr_fifo_usedw_int : std_logic_vector(7 downto 0); +signal ack_sreg : std_logic_vector(9 downto 0); +signal rddata_reg : std_logic_vector(31 downto 0); +signal wrdata_reg : std_logic_vector(31 downto 0); +signal bwsel_reg : std_logic_vector(3 downto 0); +signal rwaddr_reg : std_logic_vector(1 downto 0); +signal ack_in_progress : std_logic ; +signal wr_int : std_logic ; +signal rd_int : std_logic ; +signal bus_clock_int : std_logic ; +signal allones : std_logic_vector(31 downto 0); +signal allzeros : std_logic_vector(31 downto 0); + +begin +-- Some internal signals assignments. For (foreseen) compatibility with other bus standards. + wrdata_reg <= wb_data_i; + bwsel_reg <= wb_sel_i; + bus_clock_int <= wb_clk_i; + rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i)); + wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i); + allones <= (others => '1'); + allzeros <= (others => '0'); +-- +-- Main register bank access process. + process (bus_clock_int, rst_n_i) + begin + if (rst_n_i = '0') then + ack_sreg <= "0000000000"; + ack_in_progress <= '0'; + rddata_reg <= "00000000000000000000000000000000"; + xldr_csr_start_int <= '0'; + xldr_csr_msbf_int <= '0'; + xldr_csr_swrst_int <= '0'; + xldr_csr_clkdiv_int <= "000000"; + xldr_fifo_wrreq_int <= '0'; + elsif rising_edge(bus_clock_int) then +-- advance the ACK generator shift register + ack_sreg(8 downto 0) <= ack_sreg(9 downto 1); + ack_sreg(9) <= '0'; + if (ack_in_progress = '1') then + if (ack_sreg(0) = '1') then + xldr_csr_start_int <= '0'; + xldr_csr_swrst_int <= '0'; + xldr_fifo_wrreq_int <= '0'; + ack_in_progress <= '0'; + else + end if; + else + if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then + case rwaddr_reg(1 downto 0) is + when "00" => + if (wb_we_i = '1') then + xldr_csr_start_int <= wrdata_reg(0); + rddata_reg(0) <= 'X'; + rddata_reg(1) <= 'X'; + rddata_reg(2) <= 'X'; + rddata_reg(3) <= 'X'; + rddata_reg(4) <= 'X'; + xldr_csr_msbf_int <= wrdata_reg(4); + xldr_csr_swrst_int <= wrdata_reg(5); + rddata_reg(5) <= 'X'; + xldr_csr_clkdiv_int <= wrdata_reg(13 downto 8); + else + rddata_reg(0) <= 'X'; + rddata_reg(1) <= regs_i.csr_done_i; + rddata_reg(2) <= regs_i.csr_error_i; + rddata_reg(3) <= regs_i.csr_busy_i; + rddata_reg(4) <= xldr_csr_msbf_int; + rddata_reg(5) <= 'X'; + rddata_reg(13 downto 8) <= xldr_csr_clkdiv_int; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(2) <= '1'; + ack_in_progress <= '1'; + when "01" => + if (wb_we_i = '1') then + xldr_fifo_in_int(1 downto 0) <= wrdata_reg(1 downto 0); + xldr_fifo_in_int(2) <= wrdata_reg(2); + else + rddata_reg(0) <= 'X'; + rddata_reg(1) <= 'X'; + rddata_reg(2) <= 'X'; + rddata_reg(3) <= 'X'; + rddata_reg(4) <= 'X'; + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "10" => + if (wb_we_i = '1') then + xldr_fifo_in_int(34 downto 3) <= wrdata_reg(31 downto 0); + xldr_fifo_wrreq_int <= '1'; + else + rddata_reg(0) <= 'X'; + rddata_reg(1) <= 'X'; + rddata_reg(2) <= 'X'; + rddata_reg(3) <= 'X'; + rddata_reg(4) <= 'X'; + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "11" => + if (wb_we_i = '1') then + else + rddata_reg(16) <= xldr_fifo_full_int; + rddata_reg(17) <= xldr_fifo_empty_int; + rddata_reg(7 downto 0) <= xldr_fifo_usedw_int; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when others => +-- prevent the slave from hanging the bus on invalid address + ack_in_progress <= '1'; + ack_sreg(0) <= '1'; + end case; + end if; + end if; + end if; + end process; + + +-- Drive the data output bus + wb_data_o <= rddata_reg; +-- Start configuration + process (bus_clock_int, rst_n_i) + begin + if (rst_n_i = '0') then + xldr_csr_start_dly0 <= '0'; + regs_o.csr_start_o <= '0'; + elsif rising_edge(bus_clock_int) then + xldr_csr_start_dly0 <= xldr_csr_start_int; + regs_o.csr_start_o <= xldr_csr_start_int and (not xldr_csr_start_dly0); + end if; + end process; + + +-- Configuration done +-- Configuration error +-- Loader busy +-- Byte order select + regs_o.csr_msbf_o <= xldr_csr_msbf_int; +-- Software resest + process (bus_clock_int, rst_n_i) + begin + if (rst_n_i = '0') then + xldr_csr_swrst_dly0 <= '0'; + regs_o.csr_swrst_o <= '0'; + elsif rising_edge(bus_clock_int) then + xldr_csr_swrst_dly0 <= xldr_csr_swrst_int; + regs_o.csr_swrst_o <= xldr_csr_swrst_int and (not xldr_csr_swrst_dly0); + end if; + end process; + + +-- Serial clock divider + regs_o.csr_clkdiv_o <= xldr_csr_clkdiv_int; +-- extra code for reg/fifo/mem: Bitstream FIFO + regs_o.fifo_xsize_o <= xldr_fifo_out_int(1 downto 0); + regs_o.fifo_xlast_o <= xldr_fifo_out_int(2); + regs_o.fifo_xdata_o <= xldr_fifo_out_int(34 downto 3); + xldr_fifo_INST : wbgen2_fifo_sync + generic map ( + g_size => 256, + g_width => 35, + g_usedw_size => 8 + ) + port map ( + rd_req_i => regs_i.fifo_rd_req_i, + rd_full_o => regs_o.fifo_rd_full_o, + rd_empty_o => regs_o.fifo_rd_empty_o, + wr_full_o => xldr_fifo_full_int, + wr_empty_o => xldr_fifo_empty_int, + wr_usedw_o => xldr_fifo_usedw_int, + wr_req_i => xldr_fifo_wrreq_int, + clk_i => bus_clock_int, + wr_data_i => xldr_fifo_in_int, + rd_data_o => xldr_fifo_out_int + ); + +-- extra code for reg/fifo/mem: FIFO 'Bitstream FIFO' data input register 0 +-- extra code for reg/fifo/mem: FIFO 'Bitstream FIFO' data input register 1 + rwaddr_reg <= wb_addr_i; +-- ACK signal generation. Just pass the LSB of ACK counter. + wb_ack_o <= ack_sreg(0); +end syn; diff --git a/modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.wb b/modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.wb new file mode 100644 index 0000000..f6b3c7b --- /dev/null +++ b/modules/wishbone/wb_xilinx_fpga_loader/xloader_wb.wb @@ -0,0 +1,152 @@ +-- -*- Mode: LUA; tab-width: 2 -*- + +------------------------------------------------------------------------------- +-- Title : Xilinx FPGA Loader +-- Project : General Cores Library +------------------------------------------------------------------------------- +-- File : xloader_wb.wb +-- Author : Tomasz Włostowski +-- Company : CERN BE-CO-HT +-- Created : 2012-01-30 +-- Last update : 2012-01-30 +-- Standard : Lua 5.1 +-- Dependencies : wbgen2 ver 0.6+ +------------------------------------------------------------------------------- +-- Description: Wishbone register block definition for Xilinx FPGA loader core. +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2012 CERN +-- +-- This source file 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 version 2.1 of the License, or (at your option) any +-- later version. +-- +-- This source 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 Lesser General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Lesser General +-- Public License along with this source; if not, download it +-- from http://www.gnu.org/licenses/lgpl-2.1.html +-- +------------------------------------------------------------------------------- +-- Revisions : +-- Date Version Author Description +-- 2012-01-30 1.0 twlostow Created +------------------------------------------------------------------------------- + +peripheral { + name = "Xilinx FPGA loader"; + description = "A very simple serial firmware loader for Xilinx FPGAs. Programs the FPGA using serial slave mode method"; + prefix = "xldr"; + hdl_entity = "xloader_wb"; + + reg { + name = "Control/status register"; + prefix = "CSR"; + + field { + name = "Start configuration"; + description = "write 1: starts the configuration process.\ + write 0: no effect"; + + prefix = "START"; + type = MONOSTABLE; + }; + + field { + name = "Configuration done"; + description = "read 1: the bitstream has been loaded\ + read 0: configuration still in progress"; + prefix = "DONE"; + type = BIT; + access_bus = READ_ONLY; + access_dev = WRITE_ONLY; + }; + + field { + name = "Configuration error"; + description = "read 1: an error occured during the configuration (DONE/INIT_B timeout)\ + read 0: configuration was successful"; + prefix = "ERROR"; + type = BIT; + access_bus = READ_ONLY; + access_dev = WRITE_ONLY; + }; + + field { + name = "Loader busy"; + prefix = "BUSY"; + description = "read 1: the loader is busy (can't start configuration yet)\ + read 0: the loader is ready to re-configure the FPGA"; + type = BIT; + access_bus = READ_ONLY; + access_dev = WRITE_ONLY; + }; + + field { + name = "Byte order select"; + description = "write 1: MSB first (big endian host)\ + write 0: LSB first (little endian host)"; + prefix = "MSBF"; + type = BIT; + access_bus = READ_WRITE; + access_dev = READ_ONLY; + }; + + field { + name = "Software resest"; + description = "write 1: resets the loader core\ + write 0: no effect"; + prefix = "SWRST"; + type = MONOSTABLE; + }; + + field { + name = "Serial clock divider"; + description = "CCLK division ratio. CCLK frequency = F_sysclk / 2 / (CLKDIV + 1)"; + prefix = "CLKDIV"; + type = SLV; + align = 8; + size = 6; + access_bus = READ_WRITE; + access_dev =READ_ONLY; + }; + }; + + fifo_reg { + size = 256; + direction = BUS_TO_CORE; + prefix = "FIFO"; + name = "Bitstream FIFO"; + flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT}; + flags_dev = {FIFO_FULL, FIFO_EMPTY}; + + field { + description = "Number of bytes to send (0 = 1 byte .. 3 = full 32-bit word)"; + name = "Entry size"; + prefix = "XSIZE"; + size = 2; + type = SLV; + }; + + field { + description = "write 1: indicates the last word to be written to the FPGA"; + name = "Last xfer"; + prefix = "XLAST"; + type = BIT; + }; + + field { + description = "Subsequent words of the bitstream"; + name = "Data"; + prefix = "XDATA"; + size = 32; + type = SLV; + }; + }; +}; \ No newline at end of file diff --git a/modules/wishbone/wb_xilinx_fpga_loader/xwb_xilinx_fpga_loader.vhd b/modules/wishbone/wb_xilinx_fpga_loader/xwb_xilinx_fpga_loader.vhd new file mode 100644 index 0000000..539b4d3 --- /dev/null +++ b/modules/wishbone/wb_xilinx_fpga_loader/xwb_xilinx_fpga_loader.vhd @@ -0,0 +1,131 @@ +------------------------------------------------------------------------------- +-- Title : Xilinx FPGA Loader +-- Project : General Cores Library +------------------------------------------------------------------------------- +-- File : xwb_xilinx_fpga_loader.vhd +-- Author : Tomasz Włostowski +-- Company : CERN BE-CO-HT +-- Created : 2012-01-30 +-- Last update : 2012-01-30 +-- Platform : FPGA-generic +-- Standard : VHDL '93 +-- Dependencies : wishbone_pkg, wb_xilinx_fpga_loader +------------------------------------------------------------------------------- +-- Description: Wishbone compatible Xilinx serial port bitstream loader +-- (structized ports wrapper) +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2012 CERN +-- +-- This source file 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 version 2.1 of the License, or (at your option) any +-- later version. +-- +-- This source 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 Lesser General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Lesser General +-- Public License along with this source; if not, download it +-- from http://www.gnu.org/licenses/lgpl-2.1.html +-- +------------------------------------------------------------------------------- +-- Revisions : +-- Date Version Author Description +-- 2012-01-30 1.0 twlostow Created +------------------------------------------------------------------------------- + +library ieee; +use ieee.STD_LOGIC_1164.all; + +use work.wishbone_pkg.all; + +entity xwb_xilinx_fpga_loader is + + generic ( + g_interface_mode : t_wishbone_interface_mode := CLASSIC; + g_address_granularity : t_wishbone_address_granularity := WORD + ); + + port ( + clk_sys_i : in std_logic; + rst_n_i : in std_logic; + slave_i : in t_wishbone_slave_in; + slave_o : out t_wishbone_slave_out; + desc_o : out t_wishbone_device_descriptor; + + xlx_cclk_o : out std_logic := '0'; + xlx_din_o : out std_logic; + xlx_program_b_o : out std_logic := '1'; + xlx_init_b_i : in std_logic; + xlx_done_i : in std_logic; + xlx_suspend_o : out std_logic; + + xlx_m_o : out std_logic_vector(1 downto 0) + ); + +end xwb_xilinx_fpga_loader; + +architecture rtl of xwb_xilinx_fpga_loader is + + component wb_xilinx_fpga_loader + generic ( + g_interface_mode : t_wishbone_interface_mode; + g_address_granularity : t_wishbone_address_granularity); + port ( + clk_sys_i : in std_logic; + rst_n_i : in std_logic; + wb_cyc_i : in std_logic; + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_adr_i : in std_logic_vector(c_wishbone_address_width - 1 downto 0); + wb_sel_i : in std_logic_vector((c_wishbone_data_width + 7) / 8 - 1 downto 0); + wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0); + wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0); + wb_ack_o : out std_logic; + wb_stall_o : out std_logic; + xlx_cclk_o : out std_logic := '0'; + xlx_din_o : out std_logic; + xlx_program_b_o : out std_logic := '1'; + xlx_init_b_i : in std_logic; + xlx_done_i : in std_logic; + xlx_suspend_o : out std_logic; + xlx_m_o : out std_logic_vector(1 downto 0)); + end component; + +begin -- rtl + + + U_Wrapped_XLDR : wb_xilinx_fpga_loader + generic map ( + g_address_granularity => g_address_granularity, + g_interface_mode => g_interface_mode) + port map ( + clk_sys_i => clk_sys_i, + rst_n_i => rst_n_i, + wb_cyc_i => slave_i.cyc, + wb_stb_i => slave_i.stb, + wb_we_i => slave_i.we, + wb_adr_i => slave_i.adr, + wb_sel_i => slave_i.sel, + wb_dat_i => slave_i.dat, + wb_dat_o => slave_o.dat, + wb_ack_o => slave_o.ack, + wb_stall_o => slave_o.stall, + + xlx_cclk_o => xlx_cclk_o, + xlx_din_o => xlx_din_o, + xlx_program_b_o => xlx_program_b_o, + xlx_init_b_i => xlx_init_b_i, + xlx_done_i => xlx_done_i, + xlx_suspend_o => xlx_suspend_o, + xlx_m_o => xlx_m_o); + + slave_o.int <= '0'; + slave_o.err <= '0'; + slave_o.rty <= '0'; +end rtl; -- GitLab