merged branches/jmem to trunk

git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1071 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Arnim Läuger 17 years ago
parent ac1e1e553c
commit 0b588bae64

@ -1,3 +1,8 @@
2008-02-21 Arnim Laeuger <arniml@users.sourceforge.net>
* src/bus/fjmem.c: merged branches/jmem to trunk
-> added fjmem bus driver
2008-02-20 Arnim Laeuger <arniml@users.sourceforge.net>
* data/Makefile.am (nobase_dist_pkgdata_DATA): added bsdl/STD_1149_1_2001

@ -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;

@ -37,6 +37,7 @@ libbus_a_SOURCES = \
bf548_ezkit.c \
bf561_ezkit.c \
ixp425.c \
fjmem.c \
lh7a400.c \
mpc824x.c \
mpc5200.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,

@ -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;

@ -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…
Cancel
Save