From 0b588bae6477f4548102e7856b8f1d67f8a5e6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnim=20L=C3=A4uger?= Date: Thu, 21 Feb 2008 20:34:04 +0000 Subject: [PATCH] merged branches/jmem to trunk git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1071 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- jtag/ChangeLog | 5 + .../fjmem/fjmem_config_pack_cyclone-p.vhd | 85 ++ .../fjmem/fjmem_config_pack_spartan3-p.vhd | 85 ++ jtag/extra/fjmem/fjmem_core.vhd | 318 ++++++++ jtag/extra/fjmem/fjmem_cyclone.vhd | 499 ++++++++++++ jtag/extra/fjmem/fjmem_pack-p.vhd | 66 ++ jtag/extra/fjmem/fjmem_spartan3.vhd | 597 ++++++++++++++ jtag/extra/fjmem/generic_ram_ena.vhd | 99 +++ jtag/src/bus/Makefile.am | 1 + jtag/src/bus/buses.c | 1 + jtag/src/bus/buses.h | 1 + jtag/src/bus/fjmem.c | 730 ++++++++++++++++++ 12 files changed, 2487 insertions(+) create mode 100644 jtag/extra/fjmem/fjmem_config_pack_cyclone-p.vhd create mode 100644 jtag/extra/fjmem/fjmem_config_pack_spartan3-p.vhd create mode 100644 jtag/extra/fjmem/fjmem_core.vhd create mode 100644 jtag/extra/fjmem/fjmem_cyclone.vhd create mode 100644 jtag/extra/fjmem/fjmem_pack-p.vhd create mode 100644 jtag/extra/fjmem/fjmem_spartan3.vhd create mode 100644 jtag/extra/fjmem/generic_ram_ena.vhd create mode 100644 jtag/src/bus/fjmem.c diff --git a/jtag/ChangeLog b/jtag/ChangeLog index 8f397572..a8a500f2 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -1,3 +1,8 @@ +2008-02-21 Arnim Laeuger + + * src/bus/fjmem.c: merged branches/jmem to trunk + -> added fjmem bus driver + 2008-02-20 Arnim Laeuger * data/Makefile.am (nobase_dist_pkgdata_DATA): added bsdl/STD_1149_1_2001 diff --git a/jtag/extra/fjmem/fjmem_config_pack_cyclone-p.vhd b/jtag/extra/fjmem/fjmem_config_pack_cyclone-p.vhd new file mode 100644 index 00000000..1ddddfea --- /dev/null +++ b/jtag/extra/fjmem/fjmem_config_pack_cyclone-p.vhd @@ -0,0 +1,85 @@ +------------------------------------------------------------------------------- +-- +-- $Id$ +-- +-- 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 2 +-- 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, write to the Free Software +-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +-- +-- Written by Arnim Laeuger , 2008. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +package fjmem_config_pack is + + ----------------------------------------------------------------------------- + -- Specify the active levels of trst_i, shift_i and res_i + -- + constant trst_act_level_c : std_logic := '1'; + constant shift_act_level_c : std_logic := '1'; + constant res_act_level_c : std_logic := '1'; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Adapt the number of used blocks and the number of bits that are + -- required for the block field (2 ** num_block_field_c >= num_blocks_c) + -- + -- number of used blocks + constant num_blocks_c : natural := 4; + -- number of bits for block field + constant num_block_field_c : natural := 2; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Don't change the array type + -- + type block_desc_t is + record + addr_width : natural; + data_width : natural; + end record; + type block_array_t is array (natural range 0 to num_blocks_c-1) of block_desc_t; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Fill in the array for all your used blocks + -- + constant blocks_c : block_array_t := + ((addr_width => 18, -- block #0 + data_width => 16), + (addr_width => 18, -- block #1 + data_width => 16), + (addr_width => 19, -- block #2 + data_width => 8), + (addr_width => 8, -- block #3 + data_width => 8) + ); + -- + -- And specify the maximum address and data width + -- + constant max_addr_width_c : natural := 19; + constant max_data_width_c : natural := 16; + -- + ----------------------------------------------------------------------------- + +end; diff --git a/jtag/extra/fjmem/fjmem_config_pack_spartan3-p.vhd b/jtag/extra/fjmem/fjmem_config_pack_spartan3-p.vhd new file mode 100644 index 00000000..499e6c19 --- /dev/null +++ b/jtag/extra/fjmem/fjmem_config_pack_spartan3-p.vhd @@ -0,0 +1,85 @@ +------------------------------------------------------------------------------- +-- +-- $Id$ +-- +-- 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 2 +-- 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, write to the Free Software +-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +-- +-- Written by Arnim Laeuger , 2008. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +package fjmem_config_pack is + + ----------------------------------------------------------------------------- + -- Specify the active levels of trst_i, shift_i and res_i + -- + constant trst_act_level_c : std_logic := '1'; + constant shift_act_level_c : std_logic := '1'; + constant res_act_level_c : std_logic := '1'; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Adapt the number of used blocks and the number of bits that are + -- required for the block field (2 ** num_block_field_c >= num_blocks_c) + -- + -- number of used blocks + constant num_blocks_c : natural := 4; + -- number of bits for block field + constant num_block_field_c : natural := 2; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Don't change the array type + -- + type block_desc_t is + record + addr_width : natural; + data_width : natural; + end record; + type block_array_t is array (natural range 0 to num_blocks_c-1) of block_desc_t; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Fill in the array for all your used blocks + -- + constant blocks_c : block_array_t := + ((addr_width => 24, -- block #0, FLASH + data_width => 16), + (addr_width => 18, -- block #1, RAM0 + data_width => 16), + (addr_width => 18, -- block #2, RAM1 + data_width => 16), + (addr_width => 8, -- block #3, embedded RAM + data_width => 8) + ); + -- + -- And specify the maximum address and data width + -- + constant max_addr_width_c : natural := 24; + constant max_data_width_c : natural := 16; + -- + ----------------------------------------------------------------------------- + +end; diff --git a/jtag/extra/fjmem/fjmem_core.vhd b/jtag/extra/fjmem/fjmem_core.vhd new file mode 100644 index 00000000..4b6fb9fe --- /dev/null +++ b/jtag/extra/fjmem/fjmem_core.vhd @@ -0,0 +1,318 @@ +------------------------------------------------------------------------------- +-- +-- $Id$ +-- +-- jmem_core - a generic interface module for accessing on-chip and off-chip +-- memory and peripherals +-- +-- For host software support visit +-- http://urjtag.org/ +-- +-- 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 2 +-- 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, write to the Free Software +-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +-- +-- Written by Arnim Laeuger , 2008. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.fjmem_config_pack.all; +use work.fjmem_pack.all; + +entity fjmem_core is + + port ( + -- JTAG Interface --------------------------------------------------------- + clkdr_i : in std_logic; + trst_i : in std_logic; + shift_i : in std_logic; + update_i : in std_logic; + tdi_i : in std_logic; + tdo_o : out std_logic; + -- Memory Interface ------------------------------------------------------- + clk_i : in std_logic; + res_i : in std_logic; + strobe_o : out std_logic; + read_o : out std_logic; + write_o : out std_logic; + ack_i : in std_logic; + cs_o : out std_logic_vector(num_blocks_c-1 downto 0); + addr_o : out std_logic_vector(max_addr_width_c-1 downto 0); + din_i : in std_logic_vector(max_data_width_c-1 downto 0); + dout_o : out std_logic_vector(max_data_width_c-1 downto 0) + ); + +end fjmem_core; + + +library ieee; +use ieee.numeric_std.all; + +architecture rtl of fjmem_core is + + signal trst_s : boolean; + signal shift_en_s, + capture_en_s : boolean; + + signal shift_q : std_logic_vector(shift_range_t); + signal update_q : std_logic_vector(shift_range_t); + + signal res_s : boolean; + + signal din_q : std_logic_vector(data_range_t); + signal ack_q, + ack_for_shift_q : std_logic; + + signal instr_q : std_logic_vector(instr_range_t); + signal block_q : std_logic_vector(block_range_t); + signal strobe_toggle_q : std_logic; + signal addr_q : std_logic_vector(addr_range_t); + signal dout_q : std_logic_vector(data_range_t); + + signal strobe_sync_q : std_logic_vector(1 downto 0); + signal strobe_edge_q : std_logic; + +begin + + ----------------------------------------------------------------------------- + -- Mapping of input signals to internal flags + ----------------------------------------------------------------------------- + trst_s <= trst_i = trst_act_level_c; + shift_en_s <= shift_i = shift_act_level_c; + capture_en_s <= shift_i /= shift_act_level_c; + + res_s <= res_i = res_act_level_c; + + + ----------------------------------------------------------------------------- + -- Process shift + -- + -- Purpose: + -- Implements the shift register between tdi_i and tdo_o. + -- + -- Instruction are handled as follows. + -- read : + -- write : + -- detect : a dedicated pattern is captured that allows that marks the + -- variable length fields: + -- * block field marked with '1' + -- * address field marked with '0' + -- * data field marked with '1' + -- This allows the host software to detect how these fields are + -- located inside the bit stream (total length of bitstream has + -- been determined previously). + -- query : Based on the shifted block number, the used bits in the + -- address and data field are marked with '1'. This reports the + -- specific addr and data widths of the specified block. + -- + shift: process (trst_s, clkdr_i) + variable addr_width_v, + data_width_v : natural; + variable idx_v : natural; + begin + if trst_s then + shift_q <= (others => '0'); + + elsif rising_edge(clkdr_i) then + if shift_en_s then + -- shift mode + shift_q(shift_width_c-2 downto 0) <= shift_q(shift_width_c-1 downto 1); + shift_q(shift_width_c-1) <= tdi_i; + + else + -- capture mode + idx_v := to_integer(unsigned(shift_q(block_range_t))); + if idx_v < num_blocks_c then + addr_width_v := blocks_c(idx_v).addr_width; + data_width_v := blocks_c(idx_v).data_width; + else + addr_width_v := 0; + data_width_v := 0; + end if; + + case instr_q is + when instr_read_c => + shift_q(instr_range_t) <= instr_q; + shift_q(shift_ack_pos_c) <= ack_for_shift_q; + shift_q(data_range_t) <= din_q; + + when instr_write_c => + shift_q(instr_range_t) <= instr_q; + + when instr_idle_c => + shift_q <= (others => '0'); + + when instr_detect_c => + shift_q <= (others => '0'); + shift_q(instr_range_t) <= instr_q; + -- mark block field with '1' + shift_q(block_range_t) <= (others => '1'); + -- mark address field with '0' + shift_q(addr_range_t) <= (others => '0'); + -- mark data field with '1' + shift_q(data_range_t) <= (others => '1'); + + when instr_query_c => + if idx_v < num_blocks_c then + shift_q <= (others => '0'); + -- mark used address bits of this block in the address field with '1' + for idx in addr_range_t loop + if idx < shift_addr_pos_c + addr_width_v then + shift_q(idx) <= '1'; + end if; + end loop; + -- mark used data bits of this block in the data field '1' + for idx in data_range_t loop + if idx < shift_data_pos_c + data_width_v then + shift_q(idx) <= '1'; + end if; + end loop; + else + -- unused block + shift_q <= (others => '0'); + end if; + shift_q(instr_range_t) <= instr_q; + + when others => + shift_q <= (others => '-'); + shift_q(instr_range_t) <= instr_q; + end case; + + end if; + end if; + end process shift; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process din + -- + -- Purpose: + -- Stores the provided data at din_i for later capture. + -- The ack_i input is stored in a two-stage pipeline to allow din_q to + -- settle before ack is actually detected in the clkdr clock domain. + -- + din: process (res_s, clk_i) + begin + if res_s then + din_q <= (others => '0'); + ack_q <= '0'; + ack_for_shift_q <= '0'; + + elsif rising_edge(clk_i) then + if ack_i = '1' then + din_q <= din_i; + ack_q <= '1'; + end if; + ack_for_shift_q <= ack_q; + + if ack_for_shift_q = '1' then + -- reset for the moment, functionality not yet complete + ack_q <= '0'; + end if; + + end if; + end process din; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process dout + -- + -- Purpose: + -- Stores the updated block, instruction, address and data fields. + -- + dout: process (trst_s, update_i) + begin + if trst_s then + instr_q <= instr_idle_c; + block_q <= (others => '0'); + addr_q <= (others => '0'); + dout_q <= (others => '0'); + strobe_toggle_q <= '0'; + + elsif rising_edge(update_i) then + instr_q <= shift_q(instr_range_t); + block_q <= shift_q(block_range_t); + addr_q <= shift_q(addr_range_t); + dout_q <= shift_q(data_range_t); + + strobe_toggle_q <= not strobe_toggle_q; + + end if; + end process dout; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process strobe_sync + -- + -- Purpose: + -- Implements the synchronizer for the strobe signal from clkdr_i to + -- clk_i domain. This is a toggle synchronizer. + -- + strobe_sync: process (res_s, clk_i) + begin + if res_s then + strobe_sync_q <= (others => '0'); + strobe_edge_q <= '0'; + + elsif rising_edge(clk_i) then + strobe_sync_q(1) <= strobe_toggle_q; + strobe_sync_q(0) <= strobe_sync_q(1); + + strobe_edge_q <= strobe_sync_q(0); + end if; + end process strobe_sync; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process cs_gen + -- + -- Purpose: + -- Generates the cs_o output vector. + -- + cs_gen: process (block_q) + begin + for idx in 0 to num_blocks_c-1 loop + if idx = to_integer(unsigned(block_q)) then + cs_o(idx) <= '1'; + else + cs_o(idx) <= '0'; + end if; + end loop; + end process cs_gen; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Output mapping + ----------------------------------------------------------------------------- + tdo_o <= shift_q(0); + strobe_o <= strobe_sync_q(0) xor strobe_edge_q; + read_o <= '1' when instr_q = instr_read_c else '0'; + write_o <= '1' when instr_q = instr_write_c else '0'; + addr_o <= addr_q; + dout_o <= dout_q; + +end rtl; diff --git a/jtag/extra/fjmem/fjmem_cyclone.vhd b/jtag/extra/fjmem/fjmem_cyclone.vhd new file mode 100644 index 00000000..4f9166d2 --- /dev/null +++ b/jtag/extra/fjmem/fjmem_cyclone.vhd @@ -0,0 +1,499 @@ +------------------------------------------------------------------------------- +-- +-- $Id$ +-- +-- 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 2 +-- 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, write to the Free Software +-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +-- +-- Written by Arnim Laeuger , 2008. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity fjmem_cyclone is + + port ( + altera_reserved_tck : in std_logic; + altera_reserved_tms : in std_logic; + altera_reserved_tdi : in std_logic; + altera_reserved_tdo : out std_logic; + ext_clk_i : in std_logic; + wd_o : out std_logic; + rgb_r_o : out std_logic_vector( 2 downto 0); + rgb_g_o : out std_logic_vector( 2 downto 0); + rgb_b_o : out std_logic_vector( 2 downto 0); + comp_sync_n_o : out std_logic; + audio_l_o : out std_logic; + audio_r_o : out std_logic; + audio_o : out std_logic_vector( 7 downto 0); + pad_clk_o : out std_logic; + pad_latch_o : out std_logic; + pad_data_i : in std_logic_vector( 1 downto 0); + rxd_i : in std_logic; + txd_o : out std_logic; + cts_i : in std_logic; + rts_o : out std_logic; + rama_a_o : out std_logic_vector(17 downto 0); + rama_d_b : inout std_logic_vector(15 downto 0); + rama_cs_n_o : out std_logic; + rama_oe_n_o : out std_logic; + rama_we_n_o : out std_logic; + rama_lb_n_o : out std_logic; + rama_ub_n_o : out std_logic; + ramb_a_o : out std_logic_vector(17 downto 0); + ramb_d_b : inout std_logic_vector(15 downto 0); + ramb_cs_n_o : out std_logic; + ramb_oe_n_o : out std_logic; + ramb_we_n_o : out std_logic; + ramb_lb_n_o : out std_logic; + ramb_ub_n_o : out std_logic; + fl_a_o : out std_logic_vector(18 downto 0); + fl_d_b : inout std_logic_vector( 7 downto 0); + fl_we_n_o : out std_logic; + fl_oe_n_o : out std_logic; + fl_cs_n_o : out std_logic; + fl_cs2_n_o : out std_logic; + fl_rdy_i : in std_logic + ); + +end fjmem_cyclone; + + +library ieee; +use ieee.numeric_std.all; + +use work.fjmem_config_pack.all; + +architecture struct of fjmem_cyclone is + + component fjmem_core + port ( + clkdr_i : in std_logic; + trst_i : in std_logic; + shift_i : in std_logic; + update_i : in std_logic; + tdi_i : in std_logic; + tdo_o : out std_logic; + clk_i : in std_logic; + res_i : in std_logic; + strobe_o : out std_logic; + read_o : out std_logic; + write_o : out std_logic; + ack_i : in std_logic; + cs_o : out std_logic_vector(num_blocks_c-1 downto 0); + addr_o : out std_logic_vector(max_addr_width_c-1 downto 0); + din_i : in std_logic_vector(max_data_width_c-1 downto 0); + dout_o : out std_logic_vector(max_data_width_c-1 downto 0) + ); + end component; + + component cyclone_jtag + port ( + tms : in std_logic; + tck : in std_logic; + tdi : in std_logic; + tdo : out std_logic; + tmsutap : out std_logic; + tckutap : out std_logic; + tdiutap : out std_logic; + tdouser : in std_logic; + shiftuser : out std_logic; + clkdruser : out std_logic; + updateuser : out std_logic; + runidleuser : out std_logic; + usr1user : out std_logic + ); + end component; + + component generic_ram_ena + generic ( + addr_width_g : integer := 10; + data_width_g : integer := 8 + ); + port ( + clk_i : in std_logic; + a_i : in std_logic_vector(addr_width_g-1 downto 0); + we_i : in std_logic; + ena_i : in std_logic; + d_i : in std_logic_vector(data_width_g-1 downto 0); + d_o : out std_logic_vector(data_width_g-1 downto 0) + ); + end component; + + signal tdi_s, + tdo_s : std_logic; + signal clkdr_s, + trst_s, + shift_s, + update_s : std_logic; + + signal addr_s : std_logic_vector(max_addr_width_c-1 downto 0); + signal din_s, + dout_s : std_logic_vector(max_data_width_c-1 downto 0); + + signal res_s : std_logic; + + signal read_s, + write_s, + strobe_s : std_logic; + signal cs_s : std_logic_vector(3 downto 0); + signal ack_q : std_logic; + + type state_t is (IDLE, + READ_WAIT, + WRITE_DRIVE, + WRITE_WAIT, + WRITE_FINISH); + signal state_q : state_t; + + signal cnt_q : unsigned(1 downto 0); + + signal rama_cs_n_q, + rama_oe_n_q, + rama_we_n_q, + rama_lb_n_q, + rama_ub_n_q, + rama_d_en_q : std_logic; + signal ramb_cs_n_q, + ramb_oe_n_q, + ramb_we_n_q, + ramb_lb_n_q, + ramb_ub_n_q, + ramb_d_en_q : std_logic; + signal fl_cs_n_q, + fl_oe_n_q, + fl_we_n_q, + fl_d_en_q : std_logic; + + signal en_emb_rams_s : std_logic; + signal d_from_emb_ram_s : std_logic_vector(7 downto 0); + +begin + + res_s <= '0'; + + + cyclone_jtag_b : cyclone_jtag + port map ( + tms => altera_reserved_tms, + tck => altera_reserved_tck, + tdi => altera_reserved_tdi, + tdo => altera_reserved_tdo, + tmsutap => open, + tckutap => open, + tdiutap => tdi_s, + tdouser => tdo_s, + shiftuser => shift_s, + clkdruser => clkdr_s, + updateuser => update_s, + runidleuser => open, --trst_s, + usr1user => open + ); + trst_s <= '0'; + + + fjmem_core_b : fjmem_core + port map ( + clkdr_i => clkdr_s, + trst_i => trst_s, + shift_i => shift_s, + update_i => update_s, + tdi_i => tdi_s, + tdo_o => tdo_s, + clk_i => ext_clk_i, + res_i => res_s, + strobe_o => strobe_s, + read_o => read_s, + write_o => write_s, + ack_i => ack_q, + cs_o => cs_s, + addr_o => addr_s, + din_i => din_s, + dout_o => dout_s + ); + wd_o <= '0'; + + + ----------------------------------------------------------------------------- + -- Process mem_ctrl + -- + -- Purpose: + -- Handles access to external memory. + -- + mem_ctrl: process (res_s, ext_clk_i) + begin + if res_s = '1' then + -- RAMA + rama_cs_n_q <= '1'; + rama_oe_n_q <= '1'; + rama_we_n_q <= '1'; + rama_lb_n_q <= '1'; + rama_ub_n_q <= '1'; + rama_d_en_q <= '0'; + -- RAMB + ramb_cs_n_q <= '1'; + ramb_oe_n_q <= '1'; + ramb_we_n_q <= '1'; + ramb_lb_n_q <= '1'; + ramb_ub_n_q <= '1'; + ramb_d_en_q <= '0'; + -- Flash + fl_cs_n_q <= '1'; + fl_oe_n_q <= '1'; + fl_we_n_q <= '1'; + fl_d_en_q <= '0'; + + ack_q <= '0'; + + state_q <= IDLE; + cnt_q <= (others => '0'); + + elsif rising_edge(ext_clk_i) then + case state_q is + when IDLE => + if strobe_s = '1' then + if write_s = '1' then + state_q <= WRITE_DRIVE; + else + state_q <= READ_WAIT; + ack_q <= '1'; + end if; + + case cs_s is + -- RAMA + when "0001" => + rama_cs_n_q <= '0'; + rama_lb_n_q <= '0'; + rama_ub_n_q <= '0'; + if read_s = '1' then + rama_oe_n_q <= '0'; + end if; + if write_s = '1' then + rama_d_en_q <= '1'; + end if; + + -- RAMB + when "0010" => + ramb_cs_n_q <= '0'; + ramb_lb_n_q <= '0'; + ramb_ub_n_q <= '0'; + if read_s = '1' then + ramb_oe_n_q <= '0'; + end if; + if write_s = '1' then + ramb_d_en_q <= '1'; + end if; + + -- Flash + when "0100" => + fl_cs_n_q <= '0'; + if read_s = '1' then + fl_oe_n_q <= '0'; + -- start counter on read + cnt_q <= (others => '1'); + end if; + if write_s = '1' then + fl_d_en_q <= '1'; + end if; + + -- unimlemented / invalid + when others => + null; + + end case; + end if; + + when READ_WAIT => + if cnt_q = 0 then + state_q <= IDLE; + ack_q <= '0'; + + -- disable all memories + rama_cs_n_q <= '1'; + rama_oe_n_q <= '1'; + rama_lb_n_q <= '1'; + rama_ub_n_q <= '1'; + ramb_cs_n_q <= '1'; + ramb_oe_n_q <= '1'; + ramb_lb_n_q <= '1'; + ramb_ub_n_q <= '1'; + fl_cs_n_q <= '1'; + fl_oe_n_q <= '1'; + end if; + + when WRITE_DRIVE => + state_q <= WRITE_WAIT; + + -- output drivers are active during this state + -- thus we can activate the write impulse at the end + case cs_s is + when "0001" => + rama_we_n_q <= '0'; + when "0010" => + ramb_we_n_q <= '0'; + when "0100" => + fl_we_n_q <= '0'; + -- start counter + cnt_q <= (others => '1'); + when others => + null; + end case; + + when WRITE_WAIT => + if cnt_q = 0 then + state_q <= WRITE_FINISH; + ack_q <= '0'; + + -- disable write signals + rama_we_n_q <= '1'; + ramb_we_n_q <= '1'; + fl_we_n_q <= '1'; + end if; + + when WRITE_FINISH => + state_q <= IDLE; + + -- disable output enables + rama_d_en_q <= '0'; + ramb_d_en_q <= '0'; + fl_d_en_q <= '0'; + -- disable all memories + rama_cs_n_q <= '1'; + rama_oe_n_q <= '1'; + rama_lb_n_q <= '1'; + rama_ub_n_q <= '1'; + ramb_cs_n_q <= '1'; + ramb_oe_n_q <= '1'; + ramb_lb_n_q <= '1'; + ramb_ub_n_q <= '1'; + fl_cs_n_q <= '1'; + fl_oe_n_q <= '1'; + + when others => + state_q <= IDLE; + + end case; + + if cnt_q /= 0 then + cnt_q <= cnt_q - 1; + end if; + + end if; + end process mem_ctrl; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- An embedded RAM + ----------------------------------------------------------------------------- + en_emb_rams_s <= cs_s(3) and strobe_s; + -- + emb_ram_b : generic_ram_ena + generic map ( + addr_width_g => 8, + data_width_g => 8 + ) + port map ( + clk_i => ext_clk_i, + a_i => addr_s(7 downto 0), + we_i => write_s, + ena_i => en_emb_rams_s, + d_i => dout_s(7 downto 0), + d_o => d_from_emb_ram_s + ); + + + ----------------------------------------------------------------------------- + -- Process read_mux + -- + -- Purpose: + -- Read multiplexer from memory to jop_core. + -- + read_mux: process (cs_s, + rama_d_b, ramb_d_b, fl_d_b, + d_from_emb_ram_s) + variable din_v : std_logic_vector(din_s'range); + begin + din_v := (others => '0'); + + if cs_s(0) = '1' then + din_v := din_v or rama_d_b; + end if; + if cs_s(1) = '1' then + din_v := din_v or ramb_d_b; + end if; + if cs_s(2) = '1' then + din_v(7 downto 0) := din_v(7 downto 0) or fl_d_b; + end if; + if cs_s(3) = '1' then + din_v(7 downto 0) := din_v(7 downto 0) or d_from_emb_ram_s; + end if; + + din_s <= din_v; + end process read_mux; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- JOP pin defaults + ----------------------------------------------------------------------------- + -- UART + txd_o <= '1'; + rts_o <= '1'; + -- RAMA + rama_a_o <= addr_s(17 downto 0); + rama_d_b <= dout_s + when rama_d_en_q = '1' else + (others => 'Z'); + rama_cs_n_o <= rama_cs_n_q; + rama_oe_n_o <= rama_oe_n_q; + rama_we_n_o <= rama_we_n_q; + rama_lb_n_o <= rama_lb_n_q; + rama_ub_n_o <= rama_ub_n_q; + -- RAMB + ramb_a_o <= addr_s(17 downto 0); + ramb_d_b <= dout_s + when ramb_d_en_q = '1' else + (others => 'Z'); + ramb_cs_n_o <= ramb_cs_n_q; + ramb_oe_n_o <= ramb_oe_n_q; + ramb_we_n_o <= ramb_we_n_q; + ramb_lb_n_o <= ramb_lb_n_q; + ramb_ub_n_o <= ramb_ub_n_q; + -- Flash + fl_a_o <= addr_s(18 downto 0); + fl_d_b <= dout_s(7 downto 0) + when fl_d_en_q = '1' else + (others => 'Z'); + fl_we_n_o <= fl_we_n_q; + fl_oe_n_o <= fl_oe_n_q; + fl_cs_n_o <= fl_cs_n_q; + fl_cs2_n_o <= '1'; + -- Misc + rgb_r_o <= (others => '0'); + rgb_g_o <= (others => '0'); + rgb_b_o <= (others => '0'); + comp_sync_n_o <= '0'; + audio_l_o <= '0'; + audio_r_o <= '0'; + audio_o <= (others => '0'); + pad_clk_o <= '0'; + pad_latch_o <= '0'; + +end struct; diff --git a/jtag/extra/fjmem/fjmem_pack-p.vhd b/jtag/extra/fjmem/fjmem_pack-p.vhd new file mode 100644 index 00000000..6d072c19 --- /dev/null +++ b/jtag/extra/fjmem/fjmem_pack-p.vhd @@ -0,0 +1,66 @@ +------------------------------------------------------------------------------- +-- +-- $Id$ +-- +-- 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 2 +-- 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, write to the Free Software +-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +-- +-- Written by Arnim Laeuger , 2008. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.fjmem_config_pack.all; + +package fjmem_pack is + + ----------------------------------------------------------------------------- + -- Constants that build the shift register + -- + constant shift_instr_pos_c : natural := 0; + constant shift_instr_width_c : natural := 3; + constant shift_ack_pos_c : natural := shift_instr_pos_c + shift_instr_width_c; + constant shift_ack_width_c : natural := 1; + constant shift_block_pos_c : natural := shift_ack_pos_c + shift_ack_width_c; + constant shift_block_width_c : natural := num_block_field_c; + constant shift_addr_pos_c : natural := shift_block_pos_c + shift_block_width_c; + constant shift_addr_width_c : natural := max_addr_width_c; + constant shift_data_pos_c : natural := shift_addr_pos_c + shift_addr_width_c; + constant shift_data_width_c : natural := max_data_width_c; + constant shift_width_c : natural := shift_data_pos_c + shift_data_width_c; + -- + subtype instr_range_t is natural range shift_instr_width_c-1 downto 0; + subtype block_range_t is natural range shift_block_pos_c+shift_block_width_c-1 downto shift_block_pos_c; + subtype addr_range_t is natural range shift_addr_pos_c+shift_addr_width_c-1 downto shift_addr_pos_c; + subtype data_range_t is natural range shift_data_pos_c+shift_data_width_c-1 downto shift_data_pos_c; + subtype shift_range_t is natural range shift_width_c-1 downto 0; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Instruction constants + -- + constant instr_idle_c : std_logic_vector(instr_range_t) := "000"; + constant instr_detect_c : std_logic_vector(instr_range_t) := "111"; + constant instr_query_c : std_logic_vector(instr_range_t) := "110"; + constant instr_read_c : std_logic_vector(instr_range_t) := "001"; + constant instr_write_c : std_logic_vector(instr_range_t) := "010"; + -- + ----------------------------------------------------------------------------- + +end; diff --git a/jtag/extra/fjmem/fjmem_spartan3.vhd b/jtag/extra/fjmem/fjmem_spartan3.vhd new file mode 100644 index 00000000..ca89fd30 --- /dev/null +++ b/jtag/extra/fjmem/fjmem_spartan3.vhd @@ -0,0 +1,597 @@ +------------------------------------------------------------------------------- +-- +-- $Id$ +-- +-- 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 2 +-- 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, write to the Free Software +-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +-- +-- Written by Arnim Laeuger , 2008. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity fjmem_spartan3 is + + port ( + -- Zefant-DDR FPGA Module Peripherals ----------------------------------- + -- Clock oscillator + osc1 : in std_logic; + + -- Flash Memory + fl_a : out std_logic_vector(24 downto 0); + fl_d : inout std_logic_vector(15 downto 0); + fl_ce_n : out std_logic; + fl_oe_n : out std_logic; + fl_we_n : out std_logic; + fl_byte_n : out std_logic; + fl_rp_n : out std_logic; + fl_sts : in std_logic; + + -- FPGA dedicated/dual purpose pins + fpga_cs_b : inout std_logic; + fpga_dout_busy : inout std_logic; + fpga_init_b : inout std_logic; + fpga_rdwr_b : inout std_logic; + + fpga_cpld_io : inout std_logic_vector(7 downto 0); + + -- SRAM 0 + sr0_a : out std_logic_vector(17 downto 0); + sr0_d : inout std_logic_vector(15 downto 0); + sr0_ce_n : out std_logic; + sr0_lb_n : out std_logic; + sr0_oe_n : out std_logic; + sr0_ub_n : out std_logic; + sr0_we_n : out std_logic; + -- SRAM 1 + sr1_a : out std_logic_vector(17 downto 0); + sr1_d : inout std_logic_vector(15 downto 0); + sr1_ce_n : out std_logic; + sr1_lb_n : out std_logic; + sr1_oe_n : out std_logic; + sr1_ub_n : out std_logic; + sr1_we_n : out std_logic; + + -- Zefant-XS3 Baseboard Peripherals ----------------------------------- + -- EEPROM + ee_cs_n : out std_logic; + ee_sck : out std_logic; + ee_si : out std_logic; + ee_so : in std_logic; + + -- User Interface + button : in std_logic_vector(5 downto 0); + led : out std_logic_vector(5 downto 0); + + -- Audio Codec + aud_sdata_in : in std_logic; + aud_sdata_out : out std_logic; + aud_bit_clk : in std_logic; + aud_cin : out std_logic; + aud_reset_n : out std_logic; + aud_sync : out std_logic; + + -- Video DAC + vid_blank : out std_logic; + vid_clk : out std_logic; + vid_r : out std_logic_vector(7 downto 0); + vid_g : out std_logic_vector(7 downto 0); + vid_b : out std_logic_vector(7 downto 0); + vid_hsync : out std_logic; + vid_psave_n : out std_logic; + vid_sync_n : out std_logic; + vid_vsync : out std_logic; + + -- Extension Connectors + x301 : inout std_logic_vector(19 downto 2); + x303 : inout std_logic_vector(30 downto 1); + + -- RS 232 + rs232_rxd : in std_logic_vector(1 downto 0); + rs232_txd : out std_logic_vector(1 downto 0); + rs232_cts : in std_logic_vector(1 downto 0); + rs232_rts : out std_logic_vector(1 downto 0); + + -- USB + usb_rcv : in std_logic; + usb_vp : in std_logic; + usb_vm : in std_logic; + usb_vbus : in std_logic; + usb_oe_n : out std_logic; + usb_softcon : out std_logic; + usb_suspnd : out std_logic; + usb_vmo : out std_logic; + usb_vpo : out std_logic + ); + +end fjmem_spartan3; + + +library ieee; +use ieee.numeric_std.all; + +use work.fjmem_config_pack.all; + +architecture struct of fjmem_spartan3 is + + component fjmem_core + port ( + clkdr_i : in std_logic; + trst_i : in std_logic; + shift_i : in std_logic; + update_i : in std_logic; + tdi_i : in std_logic; + tdo_o : out std_logic; + clk_i : in std_logic; + res_i : in std_logic; + strobe_o : out std_logic; + read_o : out std_logic; + write_o : out std_logic; + ack_i : in std_logic; + cs_o : out std_logic_vector(num_blocks_c-1 downto 0); + addr_o : out std_logic_vector(max_addr_width_c-1 downto 0); + din_i : in std_logic_vector(max_data_width_c-1 downto 0); + dout_o : out std_logic_vector(max_data_width_c-1 downto 0) + ); + end component; + + component BSCAN_SPARTAN3 + port ( + CAPTURE : out std_ulogic := 'H'; + DRCK1 : out std_ulogic := 'L'; + DRCK2 : out std_ulogic := 'L'; + RESET : out std_ulogic := 'L'; + SEL1 : out std_ulogic := 'L'; + SEL2 : out std_ulogic := 'L'; + SHIFT : out std_ulogic := 'L'; + TDI : out std_ulogic := 'L'; + UPDATE : out std_ulogic := 'L'; + TDO1 : in std_ulogic := 'X'; + TDO2 : in std_ulogic := 'X' + ); + end component; + + + component generic_ram_ena + generic ( + addr_width_g : integer := 10; + data_width_g : integer := 8 + ); + port ( + clk_i : in std_logic; + a_i : in std_logic_vector(addr_width_g-1 downto 0); + we_i : in std_logic; + ena_i : in std_logic; + d_i : in std_logic_vector(data_width_g-1 downto 0); + d_o : out std_logic_vector(data_width_g-1 downto 0) + ); + end component; + + signal tdi_s, + tdo_s : std_logic; + signal clkdr_s, + trst_s, + shift_s, + update_s : std_logic; + + signal addr_s : std_logic_vector(max_addr_width_c-1 downto 0); + signal din_s, + dout_s : std_logic_vector(max_data_width_c-1 downto 0); + + signal res_s : std_logic; + + signal read_s, + write_s, + strobe_s : std_logic; + signal cs_s : std_logic_vector(3 downto 0); + signal ack_q : std_logic; + + type state_t is (IDLE, + READ_WAIT, + WRITE_DRIVE, + WRITE_WAIT, + WRITE_FINISH); + signal state_q : state_t; + + signal cnt_q : unsigned(2 downto 0); + + signal fl_ce_n_q, + fl_oe_n_q, + fl_we_n_q, + fl_d_en_q : std_logic; + signal sr0_ce_n_q, + sr0_oe_n_q, + sr0_we_n_q, + sr0_lb_n_q, + sr0_ub_n_q, + sr0_d_en_q : std_logic; + signal sr1_ce_n_q, + sr1_oe_n_q, + sr1_we_n_q, + sr1_lb_n_q, + sr1_ub_n_q, + sr1_d_en_q : std_logic; + + signal en_emb_rams_s : std_logic; + signal d_from_emb_ram_s : std_logic_vector(7 downto 0); + + signal vss_s : std_logic; + +begin + + vss_s <= '0'; + res_s <= '0'; + + + bscan_spartan3_b : BSCAN_SPARTAN3 + port map ( + CAPTURE => open, + DRCK1 => clkdr_s, + DRCK2 => open, + RESET => open, --trst_s, + SEL1 => open, + SEL2 => open, + SHIFT => shift_s, + TDI => tdi_s, + UPDATE => update_s, + TDO1 => tdo_s, + TDO2 => vss_s + ); + trst_s <= '0'; + + + fjmem_core_b : fjmem_core + port map ( + clkdr_i => clkdr_s, + trst_i => trst_s, + shift_i => shift_s, + update_i => update_s, + tdi_i => tdi_s, + tdo_o => tdo_s, + clk_i => osc1, + res_i => res_s, + strobe_o => strobe_s, + read_o => read_s, + write_o => write_s, + ack_i => ack_q, + cs_o => cs_s, + addr_o => addr_s, + din_i => din_s, + dout_o => dout_s + ); + + + ----------------------------------------------------------------------------- + -- Process mem_ctrl + -- + -- Purpose: + -- Handles access to external memory. + -- + mem_ctrl: process (res_s, osc1) + begin + if res_s = '1' then + -- Flash + fl_ce_n_q <= '1'; + fl_oe_n_q <= '1'; + fl_we_n_q <= '1'; + fl_d_en_q <= '0'; + -- RAM0 + sr0_ce_n_q <= '1'; + sr0_oe_n_q <= '1'; + sr0_we_n_q <= '1'; + sr0_lb_n_q <= '1'; + sr0_ub_n_q <= '1'; + sr0_d_en_q <= '0'; + -- RAM1 + sr1_ce_n_q <= '1'; + sr1_oe_n_q <= '1'; + sr1_we_n_q <= '1'; + sr1_lb_n_q <= '1'; + sr1_ub_n_q <= '1'; + sr1_d_en_q <= '0'; + + ack_q <= '0'; + + state_q <= IDLE; + cnt_q <= (others => '0'); + + elsif rising_edge(osc1) then + case state_q is + when IDLE => + if strobe_s = '1' then + if write_s = '1' then + state_q <= WRITE_DRIVE; + else + state_q <= READ_WAIT; + ack_q <= '1'; + end if; + + case cs_s is + -- Flash + when "0001" => + fl_ce_n_q <= '0'; + if read_s = '1' then + fl_oe_n_q <= '0'; + -- start counter on read + cnt_q <= (others => '1'); + end if; + if write_s = '1' then + fl_d_en_q <= '1'; + end if; + + -- RAM0 + when "0010" => + sr0_ce_n_q <= '0'; + sr0_lb_n_q <= '0'; + sr0_ub_n_q <= '0'; + if read_s = '1' then + sr0_oe_n_q <= '0'; + -- start counter on read + cnt_q <= (others => '1'); + end if; + if write_s = '1' then + sr0_d_en_q <= '1'; + end if; + + -- RAM1 + when "0100" => + sr1_ce_n_q <= '0'; + sr1_lb_n_q <= '0'; + sr1_ub_n_q <= '0'; + if read_s = '1' then + sr1_oe_n_q <= '0'; + -- start counter on read + cnt_q <= (others => '1'); + end if; + if write_s = '1' then + sr1_d_en_q <= '1'; + end if; + + -- unimlemented / invalid + when others => + null; + + end case; + end if; + + when READ_WAIT => + if cnt_q = 0 then + state_q <= IDLE; + ack_q <= '0'; + + -- disable all memories + fl_ce_n_q <= '1'; + fl_oe_n_q <= '1'; + sr0_ce_n_q <= '1'; + sr0_oe_n_q <= '1'; + sr0_lb_n_q <= '1'; + sr0_ub_n_q <= '1'; + sr1_ce_n_q <= '1'; + sr1_oe_n_q <= '1'; + sr1_lb_n_q <= '1'; + sr1_ub_n_q <= '1'; + end if; + + when WRITE_DRIVE => + state_q <= WRITE_WAIT; + + -- output drivers are active during this state + -- thus we can activate the write impulse at the end + case cs_s is + when "0001" => + fl_we_n_q <= '0'; + -- start counter + cnt_q <= (others => '1'); + when "0010" => + sr0_we_n_q <= '0'; + -- start counter + cnt_q <= (others => '1'); + when "0100" => + sr1_we_n_q <= '0'; + -- start counter + cnt_q <= (others => '1'); + when others => + null; + end case; + + when WRITE_WAIT => + if cnt_q = 0 then + state_q <= WRITE_FINISH; + ack_q <= '0'; + + -- disable write signals + fl_we_n_q <= '1'; + sr0_we_n_q <= '1'; + sr1_we_n_q <= '1'; + end if; + + when WRITE_FINISH => + state_q <= IDLE; + + -- disable output enables + fl_d_en_q <= '0'; + sr0_d_en_q <= '0'; + sr1_d_en_q <= '0'; + -- disable all memories + fl_ce_n_q <= '1'; + fl_oe_n_q <= '1'; + sr0_ce_n_q <= '1'; + sr0_oe_n_q <= '1'; + sr0_lb_n_q <= '1'; + sr0_ub_n_q <= '1'; + sr1_ce_n_q <= '1'; + sr1_oe_n_q <= '1'; + sr1_lb_n_q <= '1'; + sr1_ub_n_q <= '1'; + + when others => + state_q <= IDLE; + + end case; + + if cnt_q /= 0 then + cnt_q <= cnt_q - 1; + end if; + + end if; + end process mem_ctrl; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- An embedded RAM + ----------------------------------------------------------------------------- + en_emb_rams_s <= cs_s(3) and strobe_s; + -- + emb_ram_b : generic_ram_ena + generic map ( + addr_width_g => 8, + data_width_g => 8 + ) + port map ( + clk_i => osc1, + a_i => addr_s(7 downto 0), + we_i => write_s, + ena_i => en_emb_rams_s, + d_i => dout_s(7 downto 0), + d_o => d_from_emb_ram_s + ); + + + ----------------------------------------------------------------------------- + -- Process read_mux + -- + -- Purpose: + -- Read multiplexer from memory to jop_core. + -- + read_mux: process (cs_s, + fl_d, sr0_d, sr1_d, + d_from_emb_ram_s) + variable din_v : std_logic_vector(din_s'range); + begin + din_v := (others => '0'); + + if cs_s(0) = '1' then + din_v := din_v or fl_d; + end if; + if cs_s(1) = '1' then + din_v := din_v or sr0_d; + end if; + if cs_s(2) = '1' then + din_v := din_v or sr1_d; + end if; + if cs_s(3) = '1' then + din_v(7 downto 0) := din_v(7 downto 0) or d_from_emb_ram_s; + end if; + + din_s <= din_v; + end process read_mux; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Pin defaults + ----------------------------------------------------------------------------- + -- Flash Memory ------------------------------------------------------------- + fl_addr: process (addr_s) + begin + fl_a <= (others => '0'); + fl_a(24 downto 1) <= addr_s; + end process fl_addr; + fl_d <= dout_s + when fl_d_en_q = '1' else + (others => 'Z'); + fl_ce_n <= fl_ce_n_q; + fl_oe_n <= fl_oe_n_q; + fl_we_n <= fl_we_n_q; + fl_byte_n <= '1'; + fl_rp_n <= '1'; + + fpga_cs_b <= 'Z'; + fpga_dout_busy <= 'Z'; + fpga_init_b <= 'Z'; + fpga_rdwr_b <= 'Z'; + + fpga_cpld_io(7 downto 2) <= (others => 'Z'); + +-- cpld_clk <= '0'; + -- same pin assigned clkd_clk <=> x303(30) + x303(30) <= '0'; + + -- SRAMs in SO-DIMM Socket -------------------------------------------------- + sr0_a <= addr_s(17 downto 0); + sr0_d <= dout_s + when sr0_d_en_q = '1' else + (others => 'Z'); + sr0_ce_n <= sr0_ce_n_q; + sr0_lb_n <= sr0_lb_n_q; + sr0_oe_n <= sr0_oe_n_q; + sr0_ub_n <= sr0_ub_n_q; + sr0_we_n <= sr0_we_n_q; + sr1_a <= addr_s(17 downto 0); + sr1_d <= dout_s + when sr1_d_en_q = '1' else + (others => 'Z'); + sr1_ce_n <= sr1_ce_n_q; + sr1_lb_n <= sr1_lb_n_q; + sr1_oe_n <= sr1_oe_n_q; + sr1_ub_n <= sr1_ub_n_q; + sr1_we_n <= sr1_we_n_q; + + -- Baseboard EEPROM --------------------------------------------------------- + ee_cs_n <= '1'; + ee_sck <= '0'; + ee_si <= '0'; + + -- User Interface ----------------------------------------------------------- + led <= (others => '0'); + + -- Audio Codec -------------------------------------------------------------- + aud_sdata_out <= '0'; + aud_cin <= '0'; + aud_reset_n <= '0'; + aud_sync <= '0'; + + -- Video DAC ---------------------------------------------------------------- + vid_blank <= '1'; + vid_clk <= '0'; + vid_r <= (others => '0'); + vid_g <= (others => '0'); + vid_b <= (others => '0'); + vid_hsync <= '0'; + vid_psave_n <= '1'; + vid_sync_n <= '0'; + vid_vsync <= '0'; + + -- Extension Connectors ----------------------------------------------------- + x301 <= (others => 'Z'); + x303 <= (others => 'Z'); + + -- RS 232 ------------------------------------------------------------------- + rs232_txd <= (others => '1'); + rs232_rts <= (others => '1'); + + -- USB ---------------------------------------------------------------------- + usb_oe_n <= '1'; + usb_softcon <= '0'; + usb_suspnd <= '1'; + usb_vmo <= '0'; + usb_vpo <= '1'; + +end struct; diff --git a/jtag/extra/fjmem/generic_ram_ena.vhd b/jtag/extra/fjmem/generic_ram_ena.vhd new file mode 100644 index 00000000..bb9d9c53 --- /dev/null +++ b/jtag/extra/fjmem/generic_ram_ena.vhd @@ -0,0 +1,99 @@ +------------------------------------------------------------------------------- +-- +-- Parametrizable, generic RAM with enable. +-- +-- $Id$ +-- +-- Copyright (c) 2006 Arnim Laeuger (arniml@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t48/ +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity generic_ram_ena is + + generic ( + addr_width_g : integer := 10; + data_width_g : integer := 8 + ); + port ( + clk_i : in std_logic; + a_i : in std_logic_vector(addr_width_g-1 downto 0); + we_i : in std_logic; + ena_i : in std_logic; + d_i : in std_logic_vector(data_width_g-1 downto 0); + d_o : out std_logic_vector(data_width_g-1 downto 0) + ); + +end generic_ram_ena; + + +library ieee; +use ieee.numeric_std.all; + +architecture rtl of generic_ram_ena is + + type mem_t is array (natural range 0 to 2**addr_width_g-1) of + std_logic_vector(d_i'range); + signal mem_q : mem_t + -- pragma translate_off + := (others => (others => '0')) + -- pragma translate_on + ; + signal a_q : std_logic_vector(a_i'range); + +begin + + mem: process (clk_i) + begin + + if clk_i'event and clk_i = '1' then + if ena_i = '1' then + if we_i = '1' then + mem_q(to_integer(unsigned(a_i))) <= d_i; + end if; + + a_q <= a_i; + end if; + + d_o <= mem_q(to_integer(unsigned(a_i))); + end if; + end process mem; + +end rtl; diff --git a/jtag/src/bus/Makefile.am b/jtag/src/bus/Makefile.am index 84ca55cc..940e9d4a 100644 --- a/jtag/src/bus/Makefile.am +++ b/jtag/src/bus/Makefile.am @@ -37,6 +37,7 @@ libbus_a_SOURCES = \ bf548_ezkit.c \ bf561_ezkit.c \ ixp425.c \ + fjmem.c \ lh7a400.c \ mpc824x.c \ mpc5200.c \ diff --git a/jtag/src/bus/buses.c b/jtag/src/bus/buses.c index d140abf0..02bc04c7 100644 --- a/jtag/src/bus/buses.c +++ b/jtag/src/bus/buses.c @@ -39,6 +39,7 @@ const bus_driver_t *bus_drivers[] = { &bf537_ezkit_bus, &bf561_ezkit_bus, &ixp425_bus, + &fjmem_bus, &lh7a400_bus, &mpc824x_bus, &mpc5200_bus, diff --git a/jtag/src/bus/buses.h b/jtag/src/bus/buses.h index 08cf3c89..3051e767 100644 --- a/jtag/src/bus/buses.h +++ b/jtag/src/bus/buses.h @@ -34,6 +34,7 @@ extern const bus_driver_t bf537_stamp_bus; extern const bus_driver_t bf537_ezkit_bus; extern const bus_driver_t bf561_ezkit_bus; extern const bus_driver_t ixp425_bus; +extern const bus_driver_t fjmem_bus; extern const bus_driver_t lh7a400_bus; extern const bus_driver_t mpc824x_bus; extern const bus_driver_t mpc5200_bus; diff --git a/jtag/src/bus/fjmem.c b/jtag/src/bus/fjmem.c new file mode 100644 index 00000000..0f6f1e67 --- /dev/null +++ b/jtag/src/bus/fjmem.c @@ -0,0 +1,730 @@ +/* + * $Id$ + * + * Bus driver for the FPGA JTAG memory (fjmem) design. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Arnim Laeuger , 2008. + * + */ + +#include "sysdep.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#undef DEBUG + +#define FJMEM_INST_NAME "FJMEM_INST" +#define FJMEM_REG_NAME "FJMEM_REG" +#define FJMEM_MAX_REG_LEN 2048 + +struct block_param { + struct block_param *next; + uint16_t num; + uint32_t start, end; + uint16_t addr_width; + uint16_t data_width; + uint8_t ashift; +}; +typedef struct block_param block_param_t; + +struct block_desc { + uint16_t reg_len; + uint16_t instr_pos; + uint16_t block_pos; + uint16_t block_len; + uint16_t addr_pos; + uint16_t addr_len; + uint16_t data_pos; + uint16_t data_len; + block_param_t *blocks; +}; +typedef struct block_desc block_desc_t; + +typedef struct { + chain_t *chain; + part_t *part; + uint32_t last_addr; + data_register *fjmem_reg; + block_desc_t block_desc; +} bus_params_t; + + +#define CHAIN ((bus_params_t *) bus->params)->chain +#define PART ((bus_params_t *) bus->params)->part +#define LAST_ADDR ((bus_params_t *) bus->params)->last_addr +#define FJMEM_REG ((bus_params_t *) bus->params)->fjmem_reg +#define BLOCK_DESC ((bus_params_t *) bus->params)->block_desc + +static void +setup_address( bus_t *bus, uint32_t a, block_param_t *block ) +{ + data_register *dr = FJMEM_REG; + block_desc_t *bd = &(BLOCK_DESC); + int idx; + uint16_t num = block->num; + + LAST_ADDR = a; + + /* correct address for > 8 bit data widths */ + a >>= block->ashift; + + /* set block number */ + for (idx = 0; idx < bd->block_len; idx++) { + dr->in->data[bd->block_pos + idx] = num & 1; + num >>= 1; + } + + /* set address */ + for (idx = 0; idx < block->addr_width; idx++) { + dr->in->data[bd->addr_pos + idx] = a & 1; + a >>= 1; + } +} + + +static void +setup_data( bus_t *bus, uint32_t d, block_param_t *block ) +{ + data_register *dr = FJMEM_REG; + block_desc_t *bd = &(BLOCK_DESC); + int idx; + + /* set data */ + for (idx = 0; idx < block->data_width; idx++) { + dr->in->data[bd->data_pos + idx] = d & 1; + d >>= 1; + } +} + + +static int block_bus_area( bus_t *bus, uint32_t adr, bus_area_t *area, block_param_t **bl_match ); + + +/* *************************************************************************** + * fjmem_bus_printinfo + * ***************************************************************************/ +static void +fjmem_bus_printinfo( bus_t *bus ) +{ + int i; + + for (i = 0; i < CHAIN->parts->len; i++) + if (PART == CHAIN->parts->parts[i]) + break; + printf( _("fjmem FPGA bus driver via USER register (JTAG part No. %d)\n"), i ); +} + + +/* *************************************************************************** + * fjmem_bus_prepare + * ***************************************************************************/ +static void +fjmem_bus_prepare( bus_t *bus ) +{ + part_t *p = PART; + chain_t *chain = CHAIN; + + /* ensure FJMEM_INST is active */ + part_set_instruction( p, FJMEM_INST_NAME ); + chain_shift_instructions( chain ); +} + + +/* *************************************************************************** + * fjmem_bus_read_start + * ***************************************************************************/ +static void +fjmem_bus_read_start( bus_t *bus, uint32_t adr ) +{ + chain_t *chain = CHAIN; + block_desc_t *bd = &(BLOCK_DESC); + data_register *dr = FJMEM_REG; + bus_area_t area; + block_param_t *block; + + block_bus_area( bus, adr, &area, &block ); + if (!block) { + printf( _("Address out of range\n") ); + LAST_ADDR = adr; + return; + } + + setup_address( bus, adr, block ); + + /* select read instruction */ + dr->in->data[bd->instr_pos+0] = 1; + dr->in->data[bd->instr_pos+1] = 0; + dr->in->data[bd->instr_pos+2] = 0; + + chain_shift_data_registers( chain, 0 ); +} + + +/* *************************************************************************** + * fjmem_bus_read_next + * ***************************************************************************/ +static uint32_t +fjmem_bus_read_next( bus_t *bus, uint32_t adr ) +{ + chain_t *chain = CHAIN; + block_desc_t *bd = &(BLOCK_DESC); + data_register *dr = FJMEM_REG; + uint32_t d; + bus_area_t area; + block_param_t *block; + int idx; + + block_bus_area( bus, adr, &area, &block ); + if (!block) { + printf( _("Address out of range\n") ); + LAST_ADDR = adr; + return 0; + } + + setup_address( bus, adr, block ); + chain_shift_data_registers( chain, 1 ); + + /* extract data from TDO stream */ + d = 0; + for (idx = 0; idx < block->data_width; idx++) + if (dr->out->data[bd->data_pos + idx]) + d |= 1 << idx; + + return d; +} + + +/* *************************************************************************** + * fjmem_bus_read_end + * ***************************************************************************/ +static uint32_t +fjmem_bus_read_end( bus_t *bus ) +{ + chain_t *chain = CHAIN; + block_desc_t *bd = &(BLOCK_DESC); + data_register *dr = FJMEM_REG; + uint32_t d; + bus_area_t area; + block_param_t *block; + int idx; + + block_bus_area( bus, LAST_ADDR, &area, &block ); + if (!block) { + printf( _("Address out of range\n") ); + return 0; + } + + /* prepare idle instruction to disable any spurious unintentional reads */ + dr->in->data[bd->instr_pos+0] = 0; + dr->in->data[bd->instr_pos+1] = 0; + dr->in->data[bd->instr_pos+2] = 0; + + chain_shift_data_registers( chain, 1 ); + + /* extract data from TDO stream */ + d = 0; + for (idx = 0; idx < block->data_width; idx++) + if (dr->out->data[bd->data_pos + idx]) + d |= 1 << idx; + + return d; +} + + +/* *************************************************************************** + * fjmem_bus_read + * ***************************************************************************/ +static uint32_t +fjmem_bus_read( bus_t *bus, uint32_t adr ) +{ + fjmem_bus_read_start( bus, adr ); + return fjmem_bus_read_end( bus ); +} + + +/* *************************************************************************** + * fjmem_bus_write + * ***************************************************************************/ +static void +fjmem_bus_write( bus_t *bus, uint32_t adr, uint32_t data ) +{ + chain_t *chain = CHAIN; + block_desc_t *bd = &(BLOCK_DESC); + data_register *dr = FJMEM_REG; + bus_area_t area; + block_param_t *block; + + block_bus_area( bus, adr, &area, &block ); + if (!block) { + printf( _("Address out of range\n") ); + return; + } + + setup_address( bus, adr, block ); + setup_data( bus, data, block ); + + /* select write instruction */ + dr->in->data[bd->instr_pos+0] = 0; + dr->in->data[bd->instr_pos+1] = 1; + dr->in->data[bd->instr_pos+2] = 0; + + chain_shift_data_registers( chain, 0 ); +} + + +/* *************************************************************************** + * jopcyc_bus_area + * ***************************************************************************/ + +static int +block_bus_area( bus_t *bus, uint32_t adr, bus_area_t *area, block_param_t **bl_match ) +{ + block_param_t *bl = BLOCK_DESC.blocks; + uint32_t prev_start; + + *bl_match = NULL; + + /* run through all detected/queried blocks and check if adr falls into + one of their ranges */ + prev_start = 0; + while (bl) { + if ((bl->start <= adr) && (bl->end >= adr)) { + /* adr lies inside a matching block range */ + area->description = NULL; + area->start = bl->start; + area->length = bl->end - bl->start + 1; + area->width = bl->data_width; + *bl_match = bl; + prev_start = area->start; + } else if (((prev_start > adr) || (prev_start == 0)) && (bl->end < adr)) { + /* a gap between blocks */ + area->description = "Dummy"; + area->start = bl->end + 1; + area->length = prev_start > 0 ? prev_start - (bl->end+1) : UINT64_C(0x100000000); + area->width = 0; + *bl_match = NULL; + prev_start = area->start; + } else + prev_start = bl->start; + + bl = bl->next; + } + + return 0; +} + + +static int +fjmem_bus_area( bus_t *bus, uint32_t adr, bus_area_t *area ) +{ + block_param_t *bl; + + return block_bus_area( bus, adr, area, &bl ); +} + + +static void +fjmem_free_blocks( block_param_t *bl ) +{ + if (bl) { + fjmem_free_blocks( bl->next ); + free( bl ); + } +} + +static void +fjmem_bus_free( bus_t *bus ) +{ + data_register *dr = FJMEM_REG; + + /* fill all fields with '0' + -> prepare idle instruction for next startup/detect */ + part_set_instruction( PART, FJMEM_INST_NAME ); + chain_shift_instructions( CHAIN ); + + register_fill( dr->in, 0 ); + chain_shift_data_registers( CHAIN, 0 ); + + fjmem_free_blocks( BLOCK_DESC.blocks ); + BLOCK_DESC.blocks = NULL; + free( bus->params ); + free( bus ); +} + +static int +fjmem_detect_reg_len( chain_t *chain, part_t *part, char *opcode ) +{ + data_register *dr; + instruction *i; + int l, fjmem_reg_len; + char *tdo_bit; + + /* build register FJMEM_REG with length of 1 bit*/ + dr = data_register_alloc( FJMEM_REG_NAME, 1 ); + if (!dr) { + printf( _("out of memory\n") ); + return 0; + } + + dr->next = part->data_registers; + part->data_registers = dr; + + /* build instruction FJMEM_INST with code given by command line parameter + that maps to FJMEM_REG */ + if (strlen( opcode ) != part->instruction_length) { + printf( _("invalid instruction length\n") ); + return 0; + } + i = instruction_alloc( FJMEM_INST_NAME, part->instruction_length, opcode ); + if (!i) { + printf( _("out of memory\n") ); + return 0; + } + i->next = part->instructions; + part->instructions = i; + i->data_register = dr; + + /* force jtag reset on all parts of the chain + -> they're in BYPASS mode now */ + chain_set_trst( chain, 0 ); + chain_set_trst( chain, 1 ); + tap_reset( chain ); + + /* flood all BYPASS registers with 0 for the following detection */ + register_fill( dr->in, 0); + tap_capture_dr( chain ); + for (l = 0; l < chain->parts->len; l++) + tap_shift_register( chain, dr->in, NULL, EXITMODE_SHIFT ); + /* shift once more and return to idle state */ + tap_shift_register( chain, dr->in, NULL, EXITMODE_IDLE ); + + /* set the FJMEM_INST instruction and activate it */ + part_set_instruction( part, FJMEM_INST_NAME ); + chain_shift_instructions( chain ); + + /* now detect the register length of FJMEM_REG: + shift 1s through the data register until they appear at TDO + NB: We don't shift only through the FJMEM_REG but also through the + registers of all other parts in the chain. They're set to + BYPASS hopefully. */ + fjmem_reg_len = 0; + register_fill( dr->in, 1); + register_fill( dr->out, 0); + tdo_bit = dr->out->data; + + tap_capture_dr( chain ); + /* read current TDO and then shift once */ + tap_shift_register( chain, dr->in, dr->out, EXITMODE_SHIFT ); + register_get_string( dr->out ); + while ((tdo_bit[0] == 0) && (fjmem_reg_len < FJMEM_MAX_REG_LEN)) { + /* read current TDO and then shift once */ + tap_shift_register( chain, dr->in, dr->out, EXITMODE_SHIFT ); + tdo_bit = dr->out->data; + fjmem_reg_len++; + } + /* consider BYPASS register of other parts in the chain */ + fjmem_reg_len -= chain->parts->len - 1; + /* shift once more and return to idle state */ + tap_shift_register( chain, dr->in, NULL, EXITMODE_IDLE ); +#ifdef DEBUG + printf("FJMEM data register length: %d\n", fjmem_reg_len); +#endif + + return fjmem_reg_len < FJMEM_MAX_REG_LEN ? fjmem_reg_len : -1; +} + +static int +fjmem_detect_fields( chain_t *chain, part_t *part, bus_t *bus ) +{ + block_desc_t *bd = &(BLOCK_DESC); + data_register *dr = FJMEM_REG; + int idx; +#ifdef DEBUG + const char *reg_string; +#endif + + /* set safe defaults */ + bd->block_len = 0; + bd->addr_pos = 0; + bd->addr_len = 0; + bd->data_pos = 0; + bd->data_len = 0; + + /* extend FJMEM_REG to finally detected size */ + if (dr->in) + free( dr->in ); + if ((dr->in = register_alloc( bd->reg_len )) == NULL) { + printf( _("out of memory\n") ); + return 0; + } + if (dr->out) + free( dr->out ); + if ((dr->out = register_alloc( bd->reg_len )) == NULL) { + printf( _("out of memory\n") ); + return 0; + } + + /* The detect instruction (all-1) has been shifted into FJMEM_REG + previously, with the next shift we will read the field marker + pattern. + Shift in the query for block 0, will be used lateron. */ + register_fill( dr->in, 0 ); + /* enter query instruction: 110 */ + dr->in->data[bd->instr_pos+1] = 1; + dr->in->data[bd->instr_pos+2] = 1; + + /* shift register */ + chain_shift_data_registers( chain, 1 ); + + /* and examine output from field detect */ +#ifdef DEBUG + reg_string = register_get_string( dr->out ); + printf("captured: %s\n", reg_string); +#endif + /* scan block field */ + idx = bd->block_pos; + while (dr->out->data[idx] && (idx < dr->out->len)) + idx++; + bd->block_len = idx - bd->block_pos; + /* scan address field */ + bd->addr_pos = idx; + while ((dr->out->data[idx] == 0) && (idx < dr->out->len)) + idx++; + bd->addr_len = idx - bd->addr_pos; + /* scan data field */ + bd->data_pos = idx; + while (dr->out->data[idx] && (idx < dr->out->len)) + idx++; + bd->data_len = idx - bd->data_pos; + +#ifdef DEBUG + printf("block pos: %d, len: %d\n", bd->block_pos, bd->block_len); + printf("addr pos: %d, len: %d\n", bd->addr_pos, bd->addr_len); + printf("data pos: %d, len: %d\n", bd->data_pos, bd->data_len); +#endif + + if ((bd->block_len > 0) && + (bd->addr_len > 0) && + (bd->data_len > 0)) + return 1; + else + return 0; +} + +static int +fjmem_query_blocks( chain_t *chain, part_t *part, bus_t *bus ) +{ + block_desc_t *bd = &(BLOCK_DESC); + data_register *dr = FJMEM_REG; + int max_block_num, block_num; + int failed = 0; +#ifdef DEBUG + const char *reg_string; +#endif + + /* the current block number is 0, it has been requested by the previous + shift during fjmem_detect_fields */ + max_block_num = (1 << bd->block_len) - 1; + for (block_num = 0; block_num <= max_block_num; block_num++) { + int next_block_num = block_num + 1; + int idx; + int addr_len, data_len; + + /* prepare the next query before shifting the data register */ + for (idx = 0; idx < bd->block_len; idx++) { + dr->in->data[bd->block_pos + idx] = next_block_num & 1; + next_block_num >>= 1; + } + chain_shift_data_registers( chain, 1 ); + + /* and examine output from block query */ +#ifdef DEBUG + reg_string = register_get_string( dr->out ); + printf("captured: %s\n", reg_string); +#endif + + /* extract address field length */ + for (addr_len = 0; addr_len < bd->addr_len; addr_len++) + if (dr->out->data[bd->addr_pos + addr_len] == 0) + break; + + /* extract data field length */ + for (data_len = 0; data_len < bd->data_len; data_len++) + if (dr->out->data[bd->data_pos + data_len] == 0) + break; + + /* it's a valid block only if address field and data field are + both larger than 0 */ + if ((addr_len > 0) && (data_len > 0)) { + block_param_t *bl; + int nbytes; + + if ((bl = (block_param_t *)malloc( sizeof( block_param_t ) )) == NULL) { + printf( _("out of memory\n") ); + failed |= 1; + break; + } + + bl->next = bd->blocks; + bl->num = block_num; + bl->addr_width = addr_len; + bl->data_width = data_len; + bd->blocks = bl; + + /* determine address shift, depends on data width */ + nbytes = data_len / 8; + if (data_len % 8) + nbytes++; + + bl->ashift = 0; + while (nbytes != 1) { + bl->ashift++; + nbytes >>= 1; + } + + /* determine start address of this block */ + if (bl->next == NULL) + bl->start = 0; + else { + if ((bl->addr_width << bl->ashift) <= (bl->next->addr_width << bl->next->ashift)) { + bl->start = bl->next->start + (1 << (bl->next->addr_width + bl->next->ashift)); + } else { + uint32_t mask = 1 << (bl->addr_width + bl->ashift); + bl->start = bl->next->start & ~(mask - 1); + bl->start += mask; + } + } + /* and fill in end address of this block */ + bl->end = bl->start + (1 << (bl->addr_width + bl->ashift)) - 1; + +#ifdef DEBUG + printf("block # %d\n", block_num); + printf(" start 0x%08x\n", bl->start); + printf(" end 0x%08x\n", bl->end); + printf(" addr len %d\n", bl->addr_width); + printf(" data len %d\n", bl->data_width); +#endif + } + } + + return failed ? 0 : 1; +} + +static bus_t * +fjmem_bus_new( char *params[] ) +{ + bus_t *bus = NULL; + int failed = 0; + char param[16], value[16]; + part_t *part; + int fjmem_reg_len; + + if (!chain || !chain->parts || chain->parts->len <= chain->active_part || chain->active_part < 0) + return NULL; + + if (chain->active_part >= chain->parts->len) { + printf( _("%s: no active part\n"), "fjmem" ); + return NULL; + } + part = chain->parts->parts[chain->active_part]; + + if ( cmd_params(params) != 3 ) { + printf( _("Parameter for instruction code missing.\n") ); + return NULL; + } + sscanf( params[2], "%[^=]%*c%s", param, value ); + if (strcasecmp( param, "opcode" ) == 0) { + block_desc_t *bd; + + fjmem_reg_len = fjmem_detect_reg_len( chain, part, value ); + if (fjmem_reg_len <= 0) + return NULL; + + bus = malloc( sizeof (bus_t) ); + if (!bus) + return NULL; + + bus->driver = &fjmem_bus; + bus->params = malloc( sizeof (bus_params_t) ); + if (!bus->params) { + free( bus ); + return NULL; + } + + CHAIN = chain; + PART = chain->parts->parts[chain->active_part]; + FJMEM_REG = part_find_data_register( PART, FJMEM_REG_NAME ); + bd = &(BLOCK_DESC); + bd->blocks = NULL; + bd->reg_len = fjmem_reg_len; + bd->instr_pos = 0; + bd->block_pos = bd->instr_pos + 4; /* 3 bits for instruction field, 1 bit ack field */ + + if (fjmem_detect_fields( chain, part, bus ) > 0) { + if (fjmem_query_blocks( chain, part, bus ) > 0) { + } else + failed |= 1; + } else + failed |= 1; + + if (failed) { + free( bus->params ); + free( bus ); + return NULL; + } + } + + return bus; +} + +const bus_driver_t fjmem_bus = { + "fjmem", + N_("FPGA JTAG memory bus driver via USER register, requires parameters:\n" + " opcode="), + fjmem_bus_new, + fjmem_bus_free, + fjmem_bus_printinfo, + fjmem_bus_prepare, + fjmem_bus_area, + fjmem_bus_read_start, + fjmem_bus_read_next, + fjmem_bus_read_end, + fjmem_bus_read, + fjmem_bus_write, + NULL +}; + + +/* + Local Variables: + mode:C + tab-width:2 + indent-tabs-mode:t + End: +*/