Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Example code for reading and writing data via BSCAN_SPARTAN6 with urJTAG and Python

1,156 views
Skip to first unread message

wzab

unread,
Aug 3, 2010, 3:48:24 PM8/3/10
to
This post contains the updated version of the code published in
news:slrnh1b52...@wzab.nasz.dom
(posted to alt.sources with the subject "Example code for reading and writing data via BSCAN_SPARTAN3 with urJTAG and Python")
The updated version works with SPARTAN6 chips, and has been tested with the SP601 Development Kit.
The code implementing the controller for internal parallel bus is available in
news:slrni5gr9...@wzab.nasz.dom

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.9).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh07772
# Made on 2010-08-03 21:38 CEST by <xl@wzab>.
# Source directory was `/tmp/bscan'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 3667 -rw-r--r-- bscan_cap_upd.vhd
# 2275 -rw-r--r-- bscan_top.vhd
# 724 -rw-r--r-- system.ucf
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir ;;
esac
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= bscan_cap_upd.vhd ==============
if test -f 'bscan_cap_upd.vhd' && test "$first_param" != -c; then
${echo} "x - SKIPPING bscan_cap_upd.vhd (file already exists)"
else
${echo} "x - extracting bscan_cap_upd.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'bscan_cap_upd.vhd' &&
-------------------------------------------------------------------------------
-- Title : bscan_cap_upd - sample interface to BSCAN_SPARTAN6 component
-- Project :
-------------------------------------------------------------------------------
-- File : bscan_cap_upd.vhd
-- Author : Wojciech M. Zabolotny
-- Company :
-- Created : 2009-05-20
-- Last update: 2010-08-03
-- Platform :
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: This implementation is based on the Figure 4 in the Xilinx
-- XAPP188 note (even though it is for BSCAN_SPARTAN2)
-- http://www.xilinx.com/support/documentation/application_notes/xapp188.pdf
-- Then it has been converted for the BSCAN_SPARTAN6, using info
-- found in: http://www.xilinx.com/support/documentation/sw_manuals/xilinx11/spartan6_hdl.pdf
-------------------------------------------------------------------------------
-- Copyright (c) 2009 Wojciech M. Zabolotny (wzab<at>ise.pw.edu.pl)
-- However this is PUBLIC DOMAIN code
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2009-05-21 1.0 wzab Created
-------------------------------------------------------------------------------
--
--
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
library work;
X
entity bscan_cap_upd is
X generic (
X DR_WIDTH : integer := 16);
X port (
X captured_data : in std_logic_vector(DR_WIDTH-1 downto 0);
X written_data : out std_logic_vector(DR_WIDTH-1 downto 0);
X wr_strobe : out std_logic
X );
end bscan_cap_upd;
X
architecture syn of bscan_cap_upd is
X
X component BSCAN_SPARTAN6
X generic (JTAG_CHAIN : integer);
X port (CAPTURE : out std_ulogic;
X DRCK : out std_ulogic;
X RESET : out std_ulogic;
X RUNTEST : out std_ulogic;
X SEL : out std_ulogic;
X SHIFT : out std_ulogic;
X TCK : out std_ulogic;
X TDI : out std_ulogic;
X TMS : out std_ulogic;
X UPDATE : out std_ulogic;
X TDO : in std_ulogic);
X end component;
X signal jt_shift, jt_tck, jt_update, jt_tdi, jt_tdo, jt_tms,
X jt_runtest, jt_drck,
X jt_capture, jt_sel, jt_reset, jt1, jt2, jt3 : std_ulogic := '0';
X signal dr : std_logic_vector(DR_WIDTH-1 downto 0);
X
X
begin
X
X BSCAN_SPARTAN6_1 : BSCAN_SPARTAN6
X generic map ( JTAG_CHAIN=>1)
X port map (
X CAPTURE => jt_CAPTURE,
X DRCK => jt_DRCK,
X RESET => jt_RESET,
X RUNTEST => jt_RUNTEST,
X SEL => jt_SEL,
X SHIFT => jt_SHIFT,
X TDI => jt_TDI,
X TCK => jt_TCK,
X TMS => jt_TMS,
X UPDATE => jt_UPDATE,
X TDO => jt_TDO);
X
X -- Load and shift data
X pjtag : process (jt_drck, jt_reset)
X begin -- process
X if jt_reset = '1' then
X dr <= (others => '0');
X elsif jt_drck'event and jt_drck = '1' then
X if jt_shift = '0' then
X dr <= captured_data;
X else
X dr(DR_WIDTH-1) <= jt_tdi;
X for i in 0 to DR_WIDTH-2 loop
X dr(i) <= dr(i+1);
X end loop; -- i
X end if;
X end if; -- jt_reset & jt_drck1
X end process pjtag;
X
X jt_TDO <= dr(0);
X
X pupd : process(jt_reset, jt_update)
X begin -- process
X if jt_reset = '1' then
X written_data <= (others => '1');
X elsif jt_update'event and jt_update = '1' then
X if jt_sel = '1' then
X written_data <= dr;
X end if;
X end if;
X end process pupd;
X
X wr_strobe <= jt_update and jt_sel;
X
end syn;
SHAR_EOF
(set 20 10 08 03 21 36 15 'bscan_cap_upd.vhd'
eval "${shar_touch}") && \
chmod 0644 'bscan_cap_upd.vhd'
if test $? -ne 0
then ${echo} "restore of bscan_cap_upd.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'bscan_cap_upd.vhd': 'MD5 check failed'
) << \SHAR_EOF
e7341d3769914ce63a01d5e94de09d94 bscan_cap_upd.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'bscan_cap_upd.vhd'` -ne 3667 && \
${echo} "restoration warning: size of 'bscan_cap_upd.vhd' is not 3667"
fi
fi
# ============= bscan_top.vhd ==============
if test -f 'bscan_top.vhd' && test "$first_param" != -c; then
${echo} "x - SKIPPING bscan_top.vhd (file already exists)"
else
${echo} "x - extracting bscan_top.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'bscan_top.vhd' &&
-------------------------------------------------------------------------------
-- Title : Demo code for SP601 - communication via JTAG with the user core
-- Project :
-------------------------------------------------------------------------------
-- File : bscan_top.vhd
-- Author : Wojciech M. Zabolotny <wz...@ise.pw.edu.pl>
-- Company :
-- Created : 2007-12-31
-- Last update: 2010-08-03
-- Platform :
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-- This code shows, how it is possible to communicate with the user's core
-- via JTAG interface (via BSCAN_SPARTAN6 component)
-------------------------------------------------------------------------------
-- Copyright (c) 2010
-- This is public domain code!!!
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2007-12-31 1.0 wzab Created
-------------------------------------------------------------------------------
X
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
X
entity lcd_test is
X
X port (
X led : out std_logic_vector(3 downto 0);
X switches : in std_logic_vector(3 downto 0);
X flash_oen : out std_logic;
X flash_wen : out std_logic;
X flash_cen : out std_logic);
X
end lcd_test;
X
architecture beh of lcd_test is
X
X component bscan_cap_upd
X generic (
X DR_WIDTH : integer);
X port (
X captured_data : in std_logic_vector(DR_WIDTH-1 downto 0);
X written_data : out std_logic_vector(DR_WIDTH-1 downto 0);
X wr_strobe : out std_logic);
X end component;
X
X signal captured_data : std_logic_vector(7 downto 0);
X signal written_data : std_logic_vector(7 downto 0);
X signal wr_strobe : std_logic;
X
begin -- beh
X
X flash_cen <= '1';
X flash_wen <= '1';
X flash_oen <= '1';
X
X captured_data(3 downto 0) <= switches;
X captured_data(7 downto 4) <= (others => '0');
X led <= written_data(3 downto 0);
X
X bscan_cap_upd_1 : bscan_cap_upd
X generic map (
X DR_WIDTH => 8)
X port map (
X captured_data => captured_data,
X written_data => written_data,
X wr_strobe => wr_strobe);
X
end beh;
SHAR_EOF
(set 20 10 08 03 21 37 57 'bscan_top.vhd'
eval "${shar_touch}") && \
chmod 0644 'bscan_top.vhd'
if test $? -ne 0
then ${echo} "restore of bscan_top.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'bscan_top.vhd': 'MD5 check failed'
) << \SHAR_EOF
f7f98f22704d402f81bb5ee993c5bb00 bscan_top.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'bscan_top.vhd'` -ne 2275 && \
${echo} "restoration warning: size of 'bscan_top.vhd' is not 2275"
fi
fi
# ============= system.ucf ==============
if test -f 'system.ucf' && test "$first_param" != -c; then
${echo} "x - SKIPPING system.ucf (file already exists)"
else
${echo} "x - extracting system.ucf (text)"
sed 's/^X//' << 'SHAR_EOF' > 'system.ucf' &&
X
Net led<0> LOC = E13 | IOSTANDARD = LVCMOS25;
Net led<1> LOC = C14 | IOSTANDARD = LVCMOS25;
Net led<2> LOC = C4 | IOSTANDARD = LVCMOS25;
Net led<3> LOC = A4 | IOSTANDARD = LVCMOS25;
X
Net switches<0> LOC = P4 | IOSTANDARD = LVCMOS18;
Net switches<1> LOC = F6 | IOSTANDARD = LVCMOS18;
Net switches<2> LOC = E4 | IOSTANDARD = LVCMOS18;
Net switches<3> LOC = F5 | IOSTANDARD = LVCMOS18;
X
X
Net flash_wen LOC=M16;
Net flash_wen SLEW = SLOW;
Net flash_wen DRIVE = 4;
Net flash_wen IOSTANDARD = LVCMOS25;
X
Net flash_oen LOC=L18;
Net flash_oen SLEW = SLOW;
Net flash_oen DRIVE = 4;
Net flash_oen IOSTANDARD = LVCMOS25;
X
Net flash_cen LOC=L17;
Net flash_cen SLEW = SLOW;
Net flash_cen DRIVE = 4;
Net flash_cen IOSTANDARD = LVCMOS25;
SHAR_EOF
(set 20 10 08 03 21 32 24 'system.ucf'
eval "${shar_touch}") && \
chmod 0644 'system.ucf'
if test $? -ne 0
then ${echo} "restore of system.ucf failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'system.ucf': 'MD5 check failed'
) << \SHAR_EOF
4a13afa1a156e63e415d334419f49fc4 system.ucf
SHAR_EOF
else
test `LC_ALL=C wc -c < 'system.ucf'` -ne 724 && \
${echo} "restoration warning: size of 'system.ucf' is not 724"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0

Wojciech M. Zabolotny

unread,
Aug 3, 2010, 3:56:50 PM8/3/10
to
The previous post didn't contain the Python code adjusted for SP601.

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.9).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#

lock_dir=_sh08061
# Made on 2010-08-03 21:54 CEST by <xl@wzab>.
# Source directory was `/home/xl/ise_projects/Spartan6/jtag_bus1/python'.


#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------

# 1874 -rw-r--r-- bscan_test.py

# ============= bscan_test.py ==============
if test -f 'bscan_test.py' && test "$first_param" != -c; then
${echo} "x - SKIPPING bscan_test.py (file already exists)"
else
${echo} "x - extracting bscan_test.py (text)"
sed 's/^X//' << 'SHAR_EOF' > 'bscan_test.py' &&
#!/usr/bin/python
import pexpect
import re
import time
import os
class urjtag:
X def __init__(self):
X self.p=pexpect.spawn("urjtag")
X self.p.expect("jtag>")
X self.af=re.compile("(.*\r\n)*")
X def cmd(self,line):
X self.p.sendline(line)
X self.p.expect_exact("jtag>")
X if self.p.before.find("Error:")>=0:
X #res=-1
X raise("error")
X elif self.p.before.find("Unknown")>=0 or \
X self.p.before.find("unknown")>=0:
X #res=-2
X raise ("unknown command or syntax error")
X return self.p.before
X def send_dr(self,dr_as_str):
X w=u.cmd("dr "+dr_as_str+":: shift dr :: dr")
X #print w
X g=self.af.search(w)
X return int(g.group(1).strip(), base=2)
X #int(, base=2)
X
X
u=urjtag()
u.cmd("cable xpc_ext")
s=u.cmd("detect")
#Here we parse the output of the "detect" command,
#Building the list of the parts
parts=[]
finder=re.compile(r'.*Part\((?P<num>.*?)\):\s*(?P<name>\S*)', re.M)
start=0
while True:
X rs=finder.search(s,start)
X if not rs:
X break
X # We have found a new part, add it to the list of parts
X parts.append((rs.group('num'),rs.group('name')))
X start=rs.span()[1]
# OK, so we set all the parts except the xc6slx16-csg324 in the BYPASS
# mode
for p in parts:
X if p[1]=="xc6slx16-csg324":
X u.cmd("part "+p[0])
X u.cmd("register UR 8")
X # In fact 17 was sufficient, but either urJTAG or XPCU didn't work correctly
X # for instruction register length equal to 17!
X u.cmd("instruction USER1 000010 UR")
X u.cmd("instruction USER1")
X u.cmd("shift ir")
X print "found!!!"
X else:
X u.cmd("part "+p[0])
X u.cmd("instruction BYPASS")
X u.cmd("shift ir")
X
LEDS="00000001"
while True:
X tt= u.send_dr(LEDS)
X print(hex(tt))
X LEDS=(LEDS+"0")
X if LEDS[0]=="1":
X LEDS="00000001"
X else:
X LEDS=LEDS[1:]
X
X
SHAR_EOF
(set 20 10 08 03 16 55 19 'bscan_test.py'


eval "${shar_touch}") && \

chmod 0644 'bscan_test.py'


if test $? -ne 0

then ${echo} "restore of bscan_test.py failed"


fi
if ${md5check}
then (

${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'bscan_test.py': 'MD5 check failed'
) << \SHAR_EOF
bc69399b4e02704b0176f331a6d66054 bscan_test.py
SHAR_EOF
else
test `LC_ALL=C wc -c < 'bscan_test.py'` -ne 1874 && \
${echo} "restoration warning: size of 'bscan_test.py' is not 1874"

Wojciech M. Zabolotny

unread,
May 17, 2015, 10:48:46 AM5/17/15
to
Hi,

I needed to adjust my old codes used to control the FPGAs via JTAG with UrJTAG, to
work with the newer Family 7 chips.

Additionally I have modified the Python script so, that it makes use of the UrJTAG
Python bindings. This resulted in significant speed improvement, comparing with
the old code, based on pexpect package.

Please note, that you may need to add support for you chip to UrJTAG, e.g.
as described in https://sourceforge.net/p/urjtag/mailman/message/34120063/

I hope that this codes may be useful for you.
They are provided as PUBLIC DOMAIN, without any warranty.

With best regards,
Wojtek

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.14).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh22703
# Made on 2015-05-17 16:38 CEST by <wzab@wzdell>.
# Source directory was '/tmp/nnnnn'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 3595 -rw-r--r-- bscan_top.vhd
# 2225 -rw-r--r-- jtag_bus3_new.py
# 9639 -rw-r--r-- jtag_bus_ctl_3.vhd
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false

for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done

if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done

if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
# ============= bscan_top.vhd ==============
if test -n "${keep_file}" && test -f 'bscan_top.vhd'
then
${echo} "x - SKIPPING bscan_top.vhd (file already exists)"

else
${echo} "x - extracting bscan_top.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'bscan_top.vhd' &&
-------------------------------------------------------------------------------
-- Title : JTAG<->BUS controller demo for Kintex 7
-- Project :
-------------------------------------------------------------------------------
-- File : bscan_top.vhd
-- Author : Wojciech M. Zabolotny <wz...@ise.pw.edu.pl>
-- Company :
-- Created : 2007-12-31
-- Last update: 2015-05-17
-- Platform :
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-- This file implements a simple entity with JTAG driven internal bus
-- allowing to control LEDs, set two registers
-- and to read results of simple arithmetical operations
-- No switches were available on the AFCK test board, so this functionality
-- has been removed, but it is trivial to add it back.
-------------------------------------------------------------------------------
-- Copyright (c) 2015
-- This is public domain code!!!
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-08-03 1.0 wzab Created
-------------------------------------------------------------------------------
X
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
X
entity lcd_test is
X
X port (
X led : out std_logic_vector(2 downto 0)
X );
X
end lcd_test;
X
architecture beh of lcd_test is
X
X component jtag_bus_ctl
X generic (
X d_width : integer;
X a_width : integer);
X port (
X din : in std_logic_vector((d_width-1) downto 0);
X dout : out std_logic_vector((d_width-1) downto 0);
X addr : out std_logic_vector((a_width-1) downto 0);
X nwr : out std_logic;
X nrd : out std_logic);
X end component;
X
X signal arg1, arg2, res1 : unsigned(7 downto 0);
X signal res2 : unsigned(15 downto 0);
X signal inputs, din, dout : std_logic_vector(7 downto 0);
X signal addr : std_logic_vector(3 downto 0);
X signal leds : std_logic_vector(2 downto 0);
X signal nwr, nrd, rst_n : std_logic;
X
begin -- beh
X
X rst_n <= '1'; -- no reset, but you can provide one
X
X jtag_bus_ctl_1 : jtag_bus_ctl
X generic map (
X d_width => 8,
X a_width => 4)
X port map (
X din => din,
X dout => dout,
X addr => addr,
X nwr => nwr,
X nrd => nrd);
X
X -- Reading buttons, switches and registers
X process (addr, arg1, arg2, inputs, leds, res1, res2)
X begin -- process
X case addr is
X when x"1" => din <= std_logic_vector(arg1);
X when x"2" => din <= std_logic_vector(arg2);
X when x"3" => din <= '0' & leds & '0' & leds;
X when x"4" => din <= x"a3";
X when x"5" => din <= std_logic_vector(res1);
X when x"6" => din <= std_logic_vector(res2(7 downto 0));
X when x"7" => din <= std_logic_vector(res2(15 downto 8));
X when others => null;
X end case;
X end process;
X
X -- Writing to registers
X p1 : process (nwr, rst_n)
X begin -- process p1
X if rst_n = '0' then -- asynchronous reset (active low)
X arg1 <= (others => '0');
X arg2 <= (others => '0');
X leds <= (others => '0');
X elsif nwr'event and nwr = '1' then -- rising clock edge
X case addr is
X when x"1" => arg1 <= unsigned(dout);
X when x"2" => arg2 <= unsigned(dout);
X when x"3" => leds <= dout(2 downto 0);
X when others => null;
X end case;
X end if;
X end process p1;
X
X res1 <= arg1+arg2;
X res2 <= arg1*arg2;
X inputs <= x"72";
X led <= leds;
end beh;
SHAR_EOF
(set 20 15 05 17 16 23 54 'bscan_top.vhd'
eval "${shar_touch}") && \
chmod 0644 'bscan_top.vhd'
if test $? -ne 0
then ${echo} "restore of bscan_top.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'bscan_top.vhd': 'MD5 check failed'
) << \SHAR_EOF
a4e60a0ffacd44def6502b6b5fc0e051 bscan_top.vhd
SHAR_EOF

else
test `LC_ALL=C wc -c < 'bscan_top.vhd'` -ne 3595 && \
${echo} "restoration warning: size of 'bscan_top.vhd' is not 3595"
fi
fi
# ============= jtag_bus3_new.py ==============
if test -n "${keep_file}" && test -f 'jtag_bus3_new.py'
then
${echo} "x - SKIPPING jtag_bus3_new.py (file already exists)"

else
${echo} "x - extracting jtag_bus3_new.py (text)"
sed 's/^X//' << 'SHAR_EOF' > 'jtag_bus3_new.py' &&
#!/usr/bin/python
import rlcompleter
import readline
readline.parse_and_bind("tab: complete")
import os
#histfile=os.path.join(os.environ["HOME"],".pyhist.cb")
histfile="./.pyhist_1"
try:
X readline.read_history_file(histfile)
except IOError:
X pass
import atexit
atexit.register(readline.write_history_file, histfile)
del os, histfile
X
import urjtag
import re
import time
X
# Utility function used to convert
# an integer into n-digit binary number
def uint2bin(val,ndigits):
X res=""
X i=ndigits
X while i:
X if val & 1:
X res='1'+res
X else:
X res='0'+res
X val>>=1
X i-=1
X return res
X
# Class jtag_bus provide the real communication with the controller
# The constructor accepts: name of the cable, name of the part,
# number of the part in the chain (in the case if we have two or more
# identical chips in the chain), width of the address bus
# and width of the data bus.
class jtag_bus:
X def __init__(self,cable,partid,index,a_width,d_width):
X self.u=urjtag.chain()
X self.u.cable(cable)
X #u.cable("DLC5 ppdev /dev/parport0")
X self.u.tap_detect()
X self.m_width=max(a_width,d_width)
X self.mask=(1<<self.m_width)-1
X #Now we find the part we want to control
X for i in range(0,self.u.len()):
X self.u.part(i)
X if self.u.partid(i)== partid and index==1:
X self.u.add_register("BAR",self.m_width+2)
X self.u.add_instruction("BUSACC","000010","BAR")
X self.u.set_instruction("BUSACC")
X self.u.shift_ir()
X self.part_nr = i
X else:
X self.u.set_instruction("BYPASS")
X self.u.shift_ir()
X if self.u.partid(i)==partid:
X index -= 1
X def jt_write(self,address,data):
X self.u.set_dr_in((3 << self.m_width) | (address & self.mask))
X self.u.shift_dr()
X self.u.set_dr_in(data & self.mask)
X self.u.shift_dr()
X def jt_read(self,address):
X self.u.set_dr_in((2 << self.m_width) | (address & self.mask))
X self.u.shift_dr()
X self.u.set_dr_in(0)
X self.u.shift_dr()
X return self.u.get_dr_out()
X
#build the controller interface object
#How we can find the partid for our chip???
jb=jtag_bus("xpc_ext",0x43651093,1,4,8)
X
SHAR_EOF
(set 20 15 05 17 16 30 05 'jtag_bus3_new.py'
eval "${shar_touch}") && \
chmod 0644 'jtag_bus3_new.py'
if test $? -ne 0
then ${echo} "restore of jtag_bus3_new.py failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'jtag_bus3_new.py': 'MD5 check failed'
) << \SHAR_EOF
8e427a001e27e7d7e2772580e48882b9 jtag_bus3_new.py
SHAR_EOF

else
test `LC_ALL=C wc -c < 'jtag_bus3_new.py'` -ne 2225 && \
${echo} "restoration warning: size of 'jtag_bus3_new.py' is not 2225"
fi
fi
# ============= jtag_bus_ctl_3.vhd ==============
if test -n "${keep_file}" && test -f 'jtag_bus_ctl_3.vhd'
then
${echo} "x - SKIPPING jtag_bus_ctl_3.vhd (file already exists)"

else
${echo} "x - extracting jtag_bus_ctl_3.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'jtag_bus_ctl_3.vhd' &&
-------------------------------------------------------------------------------
-- Title : jtag_bus_ctl - interface between the JTAG and internal bus
-- adapted for Kintex 7
-- Project :
-------------------------------------------------------------------------------
-- File : jtag_bus_ctl.vhd
-- Author : Wojciech M. Zabolotny
-- License : PUBLIC DOMAIN
-- Company :
-- Created : 2009-10-13
-- Last update: 2015-05-17
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: This is implementation of the bus controller for Xilinx FPGAs
-- allowing you to access the internal bus via JTAG
-- The internal bus uses:
-- addr(a_width-1 downto 0) - address lines
-- dout(d_width-1 downto 0) - data to be written to register
-- on the internal bus
-- din(d_width-1 downto 0) - data read from the register on
-- on the internal bus
-- nrd - asynchronous read strobe
-- nwr - asynchronous write strobe
--
-- This implementation uses one JTAG instruction:
-- USER1 - dr length: max(2+a_width,1+d_width)
-- data transferred for this instruction may be:
-- (xxx: optional filler)
-- 10_xxx_address - READ command with address
-- 11_xxx_address - WRITE command with address
-- 00_xxx_data - DATA word to be written or dummy data in case
-- of read access - no change of address
-- THIS WORD MAY BE USED AFTER THE READ COMMAND
-- TO READ THE DATA WITHOUT ISSUING A NEW COMMAND
-- 01_xxx_data - DATA word to be written or dummy data in case
-- of read access - the access address gets
-- incremented afterwards!
--
-- Due to the way the JTAG works, the read data are transferred
-- when next command or data word is shifted through the dr register.
--
-- It is perfectly OK to issue the READ command, and then WRITE command
-- The read data will be transferred when WRITE command is transmitted.
--
-- The write command must be followed by the data command (you may
-- issue a few data commands in sequence generating a few writes
-- to the same address - useful for bit-banging procedures).
--
-- If you want to read data without issuing the next command - send
-- the DATA word 00_??? after the READ command. Please note, that
-- multiple DATA 00_??? words after the READ command do not allow
-- you to perform multiple reads! The first DATA word cancells
-- the READ mode to NOOP mode.
-- If you want to read the same address multiple times - you should
-- issue multiple READ commands with the same address (it does not
-- affects performance, as you always have to send new word to receive
-- the data)
--
-- If you want to read a few consecutive registers, then you
-- should issue the READ command with the address of the first
-- register, then multiple 01_???? DATA words to read data and
-- increase address, and finally 00_???? DATA word to receive
-- the value read from the last register without triggering a new
-- read operation.
--
-- If you want to write data to a few consecutive registers, then
-- you should issue the WRITE command with the address of the first
-- register and then multiple 01_???? DATA words. The last one
-- may be the 00_???? DATA word, but this is not necessary.
--
-- The strobes nrd and nwr are generated from the TAP controller states
-- so the JTAG frequency affects the length ofread/write pulses
-------------------------------------------------------------------------------
-- Copyright (c) 2009 Wojciech M. Zabolotny (wzab<at>ise.pw.edu.pl)
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2009-10-13 1.0 wzab Created
-------------------------------------------------------------------------------
--
-- This program is PUBLIC DOMAIN code
-- You can do with it whatever you want, however NO WARRANTY of ANY KIND
-- is provided
--
--
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
library work;
X
entity jtag_bus_ctl is
X generic (
X d_width : integer := 8;
X a_width : integer := 8);
X port (
X din : in std_logic_vector((d_width-1) downto 0);
X dout : out std_logic_vector((d_width-1) downto 0);
X addr : out std_logic_vector((a_width-1) downto 0);
X nwr : out std_logic;
X nrd : out std_logic
X );
end jtag_bus_ctl;
X
architecture syn of jtag_bus_ctl is
X
X component BSCANE2
X generic (
X JTAG_CHAIN : integer);
X port (
X CAPTURE : out std_ulogic;
X DRCK : out std_ulogic;
X RESET : out std_ulogic;
X RUNTEST : out std_ulogic;
X SEL : out std_ulogic;
X SHIFT : out std_ulogic;
X TCK : out std_ulogic;
X TDI : out std_ulogic;
X TMS : out std_ulogic;
X UPDATE : out std_ulogic;
X TDO : in std_ulogic);
X end component;
X
X signal jt_shift, jt_update, jt_tdi, jt_tdo, jt_tck, jt_tms, jt_drck,
X jt_capture, jt_sel, jt_reset : std_ulogic; -- := '0';
X
X function maximum(L, R : integer) return integer is
X begin
X if L > R then
X return L;
X else
X return R;
X end if;
X end;
X
X constant DR_SHIFT_LEN : integer := maximum(a_width+2, d_width+2);
X -- Register storing the access address and mode (read/write)
X signal dr_shift : std_logic_vector(DR_SHIFT_LEN-1 downto 0) := (others => '0');
X signal write_addr, read_addr : std_logic_vector(a_width-1 downto 0);
X -- Register storing the data
X signal write_cmd, read_cmd : std_logic := '0';
X
begin
X
X BSCANE2_1 : BSCANE2
X generic map (
X JTAG_CHAIN => 1)
X port map (
X CAPTURE => jt_CAPTURE,
X DRCK => jt_DRCK,
X RESET => jt_RESET,
X SEL => jt_SEL,
X SHIFT => jt_SHIFT,
X TCK => jt_TCK,
X TDI => jt_TDI,
X TMS => jt_TMS,
X UPDATE => jt_UPDATE,
X TDO => jt_TDO);
X
X
X -- Generate the read strobe for external bus
X nrd <= '0' when jt_capture = '1' and jt_sel = '1' and read_cmd = '1' else '1';
X -- Generate the write strobe for the external bus - when write_cmd, and this
X -- is the data word
X nwr <= '0' when jt_update = '1' and jt_sel = '1' and
X write_cmd = '1' and dr_shift(DR_SHIFT_LEN-1) = '0' else '1';
X
X dout <= dr_shift(d_width-1 downto 0);
X addr <= write_addr when write_cmd = '1' else read_addr;
X
X -- Load and shift data to dr_addr_and_mode register
X pjtag1 : process (jt_drck, jt_reset)
X begin -- process
X if jt_reset = '1' then
X dr_shift <= (others => '0');
X elsif jt_drck'event and jt_drck = '1' then -- falling clock edge - state
X if jt_shift = '0' then
X if read_cmd = '1' then
X -- Read the data
X dr_shift(d_width-1 downto 0) <= din;
X end if;
X else
X -- Transfer the read_addr to the write_addr
X -- this is necessary to avoid updating the write_addr
X -- at the begining or end of the write cycle in the autoincrement mode
X write_addr <= read_addr;
X -- Shift the register
X dr_shift(DR_SHIFT_LEN-1) <= jt_tdi;
X for i in 0 to DR_SHIFT_LEN-2 loop
X dr_shift(i) <= dr_shift(i+1);
X end loop; -- i
X end if;
X end if;
X end process pjtag1;
X
X pupd1a : process(jt_reset, jt_update)
X begin -- process
X if jt_reset = '1' then
X elsif jt_update'event and jt_update = '1' then
X if jt_sel = '1' then
X if dr_shift(DR_SHIFT_LEN-1 downto DR_SHIFT_LEN-2) = "10" then
X read_cmd <= '1';
X write_cmd <= '0';
X read_addr <= dr_shift(a_width-1 downto 0);
X elsif dr_shift(DR_SHIFT_LEN-1 downto DR_SHIFT_LEN-2) = "11" then
X -- Write access
X read_cmd <= '0';
X write_cmd <= '1'; -- We PREPARE to write
X read_addr <= dr_shift(a_width-1 downto 0);
X -- we can not write the write_addr here
X -- It will be updated from the read_addr in another process
X -- this is needed to implement the autoincrement mode!
X elsif dr_shift(DR_SHIFT_LEN-1 downto DR_SHIFT_LEN-2) = "00" then
X -- Data
X read_cmd <= '0'; -- Block further READs
X else
X -- "01" - This is the autoincrement mode! we should increment
X -- the address, but the write cycle is still active!
X -- to avoid problems with the hold time we update now only the read address
X read_addr <= write_addr+1;
X -- the write address will be updated later, when shifting the next word
X end if;
X end if;
X end if;
X end process pupd1a;
X
X -- No update process is needed! Our controller just generates the nwr pulse
X -- for internal logic
X
-- pupd1b : process(jt_reset, jt_update)
-- begin -- process
-- if jt_reset = '1' then
-- null;
-- elsif jt_update'event and jt_update = '0' then
-- if jt_sel1 = '1' then
-- null;
-- end if;
-- end if;
-- end process pupd1b;
X
X jt_TDO <= dr_shift(0);
end syn;
SHAR_EOF
(set 20 15 05 17 16 23 55 'jtag_bus_ctl_3.vhd'
eval "${shar_touch}") && \
chmod 0644 'jtag_bus_ctl_3.vhd'
if test $? -ne 0
then ${echo} "restore of jtag_bus_ctl_3.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'jtag_bus_ctl_3.vhd': 'MD5 check failed'
) << \SHAR_EOF
d90604d203f96e7d6f61fc8a5cd5876d jtag_bus_ctl_3.vhd
SHAR_EOF

else
test `LC_ALL=C wc -c < 'jtag_bus_ctl_3.vhd'` -ne 9639 && \
${echo} "restoration warning: size of 'jtag_bus_ctl_3.vhd' is not 9639"

wza...@gmail.com

unread,
Dec 20, 2018, 5:54:38 PM12/20/18
to
Below is the simple Tcl code that provides communication with the jtag_bus_ctl_3.vhd via Tcl script in Vivado instead of Python & UrJtag:

=======================================================
# Script prepared by Wojciech M. Zabolotny (wzab<at>ise.pw.edu.pl)
# to drive the jtag_bus_ctl.vhd core (published in the
# https://groups.google.com/d/msg/alt.sources/Rh5yEuF2YGE/rAzJMOFDNz8J
# thread on alt.sources usenet group
#


# Set two constants below according to the address and data width
# in the instantiated controller
set d_width 8
set a_width 8

set ad_width [ expr max($d_width, $a_width)]
set s_width [ expr $ad_width + 2 ]
set a_mask [ expr ( 1 << $a_width) - 1 ]
set d_mask [ expr ( 1 << $d_width) - 1 ]

proc bus_init { } {
close_hw
catch open_hw
catch {connect_hw_server -url localhost:3121}
# You may need to adjust the lines below!
set JTAG */xilinx_tcf/Xilinx/*
current_hw_target [get_hw_targets $JTAG]
open_hw_target -jtag_mode 1
get_hw_devices
run_state_hw_jtag reset
run_state_hw_jtag idle
# The length of the shift should correspond to the length of the instruction register of your FPGA
# The shifted value should correspond to the USER command, that selects
# your BSCANE2 as the data register
scan_ir_hw_jtag 6 -tdi 02
}

proc bus_write { address value } {
global ad_width
global s_width
global a_mask
global d_mask
set shval [ expr ( 3 << $ad_width ) | ( $address & $a_mask ) ]
scan_dr_hw_jtag $s_width -tdi [format %x $shval]
set shval [ expr ( 0 << $ad_width ) | ( $value & $d_mask ) ]
scan_dr_hw_jtag $s_width -tdi [format %x $shval]
}

proc bus_read { address } {
global ad_width
global s_width
global a_mask
global d_mask
set shval [ expr ( 2 << $ad_width ) | ( $address & $a_mask ) ]
scan_dr_hw_jtag $s_width -tdi [format %x $shval]
set shval [ scan_dr_hw_jtag $s_width -tdi 0x0 ]
set shval [expr 0x$shval & $d_mask ]
return $shval
}
=======================================================

wza...@gmail.com

unread,
Dec 20, 2018, 6:49:37 PM12/20/18
to
Here is the Tcl code that communicates with the jtag_bus_ctl_3.vhd via Tcl script in Vivado instead of Python & UrJtag, and provides TCP server.
Therefore you can control you bus from application written in other languages, like C or Python. Please note, that this is a "quick&dirty" solution, so there is almost no error handling.

You can start the server by:
vivado -mode tcl -source jtag_bus_ctrl.tcl

The server listens on port 9900 and understands simple commands:
wr address value
rd address
quit

To quickly check it, you may connect to it from netcat (you can see the format of responses):
nc localhost 9900

and enter commands:

$ nc localhost 9900
JTAG Bus Server 1.0
rd 1
value 35
rd 2
value 43
wr 2 73
OK
rd 1
value 35
rd 2
value 73
quit

This is a free, PUBLIC DOMAIN code, so you use it on your own risk!

=========== Source of the Tcl script ==================
proc srv_proc {channel clientaddr clientport} {
puts $channel "JTAG Bus Server 1.0"
flush $channel
puts "Connection from $clientaddr registered"
while { true } {
set cmdline [gets $channel]
lassign $cmdline cmd addr val
switch $cmd {
quit {
break
}
rd {
#puts "Reading from $addr"
set val [ bus_read $addr ]
puts $channel "value $val"
flush $channel
}
wr {
#puts "writing $val to $addr"
bus_write $addr $val
puts $channel "OK"
flush $channel
}
}
}
close $channel
}

bus_init
socket -server srv_proc 9900
vwait forever
=======================================================
0 new messages