merged branches/jmem to trunk
git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1071 b68d4a1b-bc3d-0410-92ed-d4ac073336b7master
parent
ac1e1e553c
commit
0b588bae64
@ -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 <arniml@users.sourceforge.net>, 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;
|
@ -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 <arniml@users.sourceforge.net>, 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;
|
@ -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 <arniml@users.sourceforge.net>, 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;
|
@ -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 <arniml@users.sourceforge.net>, 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;
|
@ -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 <arniml@users.sourceforge.net>, 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;
|
@ -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 <arniml@users.sourceforge.net>, 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;
|
@ -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;
|
@ -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 <arniml@users.sourceforge.net>, 2008.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <part.h>
|
||||
#include <bus.h>
|
||||
#include <chain.h>
|
||||
#include <jtag.h>
|
||||
#include <buses.h>
|
||||
#include <cmd.h>
|
||||
#include <tap.h>
|
||||
|
||||
|
||||
#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=<USERx 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:
|
||||
*/
|
Loading…
Reference in New Issue