| inAccess : IAN Projects | ianjtag |
Athens, 4 Dec 2001
Great care has been taken to separate and isolate the system
dependencies and encapsulate them in modules with generic
interfaces. "ianjtag tools" contains modules dependent to the
host-system and the hardware I/O interface used to access the target
processor's JTAG port, modules dependent to the target-processor's
architecture, and modules dependent to the flash memory device in
use. By separating these dependencies it is possible to support a
variety of host and target systems by augmenting the code with
additional modules, without requiring to rewrite
everything. Furthermore it makes it possible to have a single set of
tools that can, to some extent, automatically detect, and adapt itself
to operate with, any of the supported target systems.
Contains code for doing low-level hardware I/O (parallel port I/O
under Linux in the present implementation), and code for handling
the JTAG state-machine. The low-level I/O code is hardware and O/S
dependent, but, due to its small size and minimum complexity, it
can trivially be rewritten to support any arrangement. The code
that handles the JTAG state-machine has no hardware or O/S
dependencies. The low-level jtag module exports a very simple
interface that gives its users the ability to perform JTAG cycles
easily.
The processor support modules (one for each supported target
processor) hide the processor-specific JTAG complexities behind a
common processor-invariant interface, supporting operations like
pin-state (level) reading and setting, and various types of
bus-cycles. While in its present state the PSM interface supports
only a few operations ---mainly targeted at flash-memory
handling--- additional operations can be defined, and implemented,
if the need arises. Obviously not all PSM operations make sense
for all processor architectures, so each actual PSM is required to
implement only the relevant subset (e.g. the PSM for a 16bit
processor may not implement the 32bit-wide bus cycle operations,
and the PSM for a 32bit processor may not implement certain 16bit
bus cycles).
The flash support modules (one for each flash device type and
configuration) hide the device-specific flash programming
complexities behind a common device-invariant interface, by
exporting general purpose functions like 'read', 'write',
'verify', etc... Generally each Flash memory device and
configuration has its own FSM, but very similar devices (or small
variations in the configuration) may be supported by the same
module. The flash support modules use the PSM interface to perform
low-level processor-specific operations, so the same FSM can be
used to support a device and configuration irrespective to the
system's processor architecture.
These are the only functions you will need to rewrite in order to
support an different JTAG hardware interface, or a different host
system. The functions "io_access_on()" and
"io_access_off()" are privately called by
"jtag_init()", and are therefore more like "parts" of
"jtag_init()".
An example may clarify things. Assume you have three PSM modules each
exporting its own initialization function, say: "pjtag_sa1110_init",
"pjtag_mc860_init()", "pjtag_mk68k_init()". The way
to go is to call these functions in order until one call succeeds
like this:
The interface structure, which must be filled-in by every PSM init
function is defined in the file "pjtag.h", and goes like
this:
It is obvious that, as new processor types are supported (i.e. PSMs
are written for them), new methods will need to be defined, and the
existing PSMs will have to be updated to implement these new methods
(if possible). For example methods like 'flw16' will be needed if
16bit processors are to be supported, and these methods could possibly
also be implemented by the existing PSMs (but possibly not).
So if you write a PSM and in the process you define some new
methods, please send me your code (or even your suggestions for new
useful methods) in order to incorporate them in the next versions
of "ianjtag tools". This, of course, also stands for any new
PSM, or other additions to the code, even if they do not include
definitions of new methods
An example may clarify things. Assume you have three FSM modules each
exporting its own initialization function, say:
"pjtag_isf2x16_init()", "fjtag_if2x16_init()",
"pjtag_ibf2x16_init()". The way to go is to call these
functions one after the other until one call succeeds like this:
The parameter structure taken as argument by every FSM init function
is defined in "fjtag.h" like this:
The interface structure, which must be filled-in by every FSM init
function is defined in the file "pjtag.h", and goes like this:
The FSMs have some minor dependencies on the Unix time(2)
function, for calling the progress indicators at proper intervals,
and for timing timeouts. You may need to address them also, which
should normally be a trivial task (even if you have nothing like
time(2)).
The user-interface code (i.e. "ianjflash.c" and
"ianjpins.c") have plenty of Unix dependencies. If you are
porting to a different O/S, you will probably have to rewrite them
also.
If you are planning to support a new target system (i.e. new processor
architecture, or different flash-device) you have to:
Remember to send your additions and modifications back to me, so that
I can incorporate them in a future version of "ianjtag tools".
If you have any problem using or porting "ianjtag tools" don't
hesitate to contact me. My email address can be found at the top of
this document.
"ianjtag tools" 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Send any questions or suggestions about "ianjtag tools" to one of its
authors. The authors's names and addresses are at the top of this
page.
Please also send any modifications, additions, or corrections you have
made to the source-code, so that we can include them in future
versions.
We would also like to know you opinion about "ianjtag tools", and hear
about you experiences using, or extending it.
Building and using this code
A very simple "Makefile" is provided for this purpose, which is
thoroughly commented. You should have no problem making it work for
almost any Linux system. For other operating systems some
modifications will be required, not so much to the 'Makefile' (which
is fairly general) but to the system dependent portions of the
code. Anyway, "ianjtag tools" was written with portability in mind so
the task of porting it to a new (even very different) system should
not be really hard. Furthermore extensive and very detailed
documentation of the code's structure and operation is provided in
this file. Additional documentation can be found inside the
source-code itself in the form of comments. Some additional background
information in the form of an
introduction to JTAG and
theory of operation is also available.
Source code files and modules
"ianjtag tools" consists of several source-code files, all written in
the C programming language, and organized in modules as described in
this section.
Module interfaces
Follows a description, in some detail, of the interfaces exported by
each of the modules presented above. Read this if you plan to add
support for a different processor architecture, a different type of
flash-memory-device or configuration, if you plan to write a new tool
that uses "ianjtag tools"'s infrastructure, or if you plan to port
"ianjtag tools" to use a different hardware interface or to run on
a different host system.
Low-level JTAG module (files: jtag.h,
jtag.c)
This module can be thought to consist of these two parts:
The low-level hardware I/O interface code (files: jtag.h,
jtag.c)
It is dependent to the host-system and the JTAG hardware interface in
use. In the present implementation it works under Linux and uses the
host system's parallel-port as the JTAG hardware interface. The JTAG
interface requires five signal lines (four outputs, and one input, as
seen from the host system). These signals are connected to the
parallel port pins like this:
TCK <---- Pin 2 (Data 0)
TMS <---- Pin 3 (Data 1)
TDI <---- Pin 4 (Data 2)
TRST <---- Pin 5 (Data 3)
TDO ----> Pin 11 (Busy)
At the other end of the interface, the these signals are connected to
the target system processor's JTAG port, and some glue circuitry may
be required in the middle for voltage level adaptation, filtering,
etc. For example, in our systems the hardware interface looks like
this:
+------------+ +--------+ +-------+ +------+
| TCK<------+ Buff- +-------<2 | | |
| TARGET TMS<------+ ering +-------<3 | 25 | |
| JTAG TDI<------+ & +-------<4 DB25 |===//===| HOST |
| Port TRST<------+ Level +-------<5 | | |
| TDO>------+ Adapt. +------->11 | | |
+------------+ +--------+ +-------+ +------+
The low-level hardware I/O interface code provides these simple
functions, which you will need to re-code if you want to support a
different type of host-system or hardware interface:
* drive TCK high, and TDI and TMS to the given levels.
* drive TCK low, and keep TDI and TMS to the given levels.
* read, and return, the level of the TDO pin.
The low-level JTAG state-machine handling code (files:
jtag.h, jtag.c)
Other than calling the functions of the low-level hardware I/O code,
discussed above, the JTAG state-machine handling code has no other
host or target system dependencies, so there's probably no reason to
touch its implementation. You will, however, need to use
(call) the interface exported by this code in order to write a
Processor Support Module. JTAG state machine handling code's interface
consist of the following functions:
if input[] contains
{0,1,1,0,1,0,1,0,1,1,1,0,0,0,0,1,0,1}
- then jtag_fillword(input, 8, 8, 1)
will return 0x00000087
- then jtag_fillword(input, 8, 5, -1)
will return 0x00000015
*-> run test idle
--> select dr scan
--> select ir scan
--> capture ir
--> shift ir --> ...'irsz' times... --> shift ir
--> exit1 ir
--> update ir
--> run test idle ->*
This operation has the effect of writing a value to the JTAG
Instruction Register, and thus issuing a "JTAG command".
*-> run test idle
--> select dr scan
--> capture dr
--> shift dr --> ...'drsz' times... --> shift dr
--> exit1 dr
--> update dr
--> run test idle ->*
This operation has the effect of writing a value to the JTAG
Data Register, and, depending on the JTAG command previously
issued, setting the processor's output pins states, or reading
the processor's ID code.
*-> run test idle
--> select dr scan
--> select ir scan
--> capture ir
--> shift ir --> ...'irsz' times... --> shift ir
--> exit1 ir
--> update ir
--> select dr scan
--> capture dr
--> shift dr --> ...'drsz' times... --> shift dr
--> exit1 dr
--> update dr
--> run test idle ->*
Processor Support Modules (files: pjtag.h, pjtag_xxx.c,
pjtag_xxx.h)
Each processor support module exports a single function named
"pjtag_xxx_init()", where "xxx" refers to the
specific processor
supported by the module (e.g. "pjtag_sa1110_init()"). This
function
initializes the module and fills-in a "PSM interface structure", a
pointer to which is supplied by the caller. Subsequent accesses to the
module's services are performed only through this interface structure,
which has been initialized and contains PSM variables, pointers to PSM
variables, and function pointers. This initialization function is
defined as follows:
struct pjtag_if_s s;
do {
if ( pjtag_mc860_init(&s) >= 0)
break;
if ( pjtag_sa1110_init(&s) >= 0)
break;
if ( pjtag_mk68k_init(&s) >= 0)
break;
printf("Fuck! Processor not supported!\n");
exit(1);
} while(0);
Of course you can devise more clever ways to code this, like having an
array of pointers to initialization functions, and so on; but for our
little example this will do. Now, even if you don't know which
specific call succeeded (which you don't), you can access the module's
services through the "s" structure like this:
s->set_pins(dri, dro);
And that's the whole point of having the PSMs export only a single
init function each and providing the rest of their interfaces through
a structure filled-in by init: It is something like having a simple
application-level dynamic linking feature, or (if you 're into the OOP
stuff) like having some sort of poor man's dynamic polymorphism.
struct pjtag_if_s {
const char *name; /* processor name */
int irsz; /* JTAG instruction-register size */
int idrsz; /* JTAG id-register size */
int bsrsz; /* JTAG bsr-register size */
const char * const * bsr_names;
/* names of BSR cells */
const char *bsr_defaults;
/* safe defaults for BSR cells */
struct pjtag_cmds_s jtag_cmds;
/* codes for standard JTAG commands */
int databus_width;
/* width of processor's data bus */
int addrbus_width;
/* width of processor's address bus */
int *bsr_databus_in;
/* input-cell number for each databus bit */
int *bsr_databus_out;
/* output-cell number for each databus bit */
int *bsr_addrbus;
/* cell number for each databus line */
/* set and read all BSR cells */
void (*set)(unsigned char *, unsigned char *);
/* bus-cycles for flash devices */
void (*flw32)(unsigned long, unsigned long);
/* wr. a 32bit word */
void (*flw32n)(unsigned long *, unsigned long *, unsigned long);
/* wr. n 32bit words */
void (*flr32)(unsigned long, unsigned long *);
/* rd. a 32bit word */
void (*flr32n)(unsigned long *, unsigned long *, unsigned long);
/* rd. n 32bit words */
};
The stucture jtag_cmds_s contains codes (binary values) for
the standard JTAG commands like EXTEST, INTEST, etc. It is defined as
follows:
struct pjtag_cmds_s {
long extest;
long sample;
long clamp;
long highz;
long idcode;
long bypass;
};
Follows a description of the pjtag_if_s structure's
members. Succumbing to the OOP terminology, I will call the
non-callable members "attributes" and the callable members
"methods". Not all PSMs are required to support all the defined
methods. If a PSM wishes not to support a method (e.g. because it
makes no sense for the respective processor) it just initializes the
respective interface-structure member with 0 (NULL).
Flash Support Modules (files: fjtag.h, fjtag_xxx.c,
fjtag_xxx.h)
Each flash support module exports a single function named
"fjtag_xxx_init()", where "xxx" refers to the
specific flash memory device and configuration supported by the module
(e.g. "pjtag_isf2x16_init()" for an FSM that support Intel's
StrataFlash chips in 2x16 configuration). This function initializes
the module and fills-in an FSM interface structure, a pointer
to which is supplied by the caller. Subsequent accesses to the
module's services are performed only through this interface structure,
which has been initialized and contains FSM variables, pointers to FSM
variables, and function pointers. This initialization function is
defined as follows:
struct pjtag_if_s pjt;
struct fjtag_if_s s;
struct fjtag_param_s p;
p.pjtag_if = pjt; /* PSM already initialized */
p.base_addr = 0x0; /* device base address */
p.size = 0x0; /* find out yourself */
p.progindevery = 1; /* progress indicator update every 1 sec */
p.progindrng = 1000; /* progress indicator goes form 0 to 1000 */
p.progind = progind; /* progress indicator call-back */
do {
if ( fjtag_isf2x16_init(&s, &p) >= 0)
break;
if ( fjtag_if2x16_init(&s, &p) >= 0)
break;
if ( pjtag_ibf2x16_init(&s, &p) >= 0)
break;
printf("Fuck! Flash-device not supported!\n");
exit(1);
} while(0);
Of course you can devise more clever ways to code this, like having an
array of pointers to initialization functions, and so on; but for our
little example this will do. Now, even if you don't know which
specific call succeeded (which you don't), you can access the module's
services through the 's' structure like this:
s->write(buff, 0, len, 1, NULL);
And that's the whole point of having the FSMs export only a single
init function and providing the rest of their interfaces through a
structure filled-in by init: It is something like having a simple
application-level dynamic linking feature, or (if you 're into the OOP
stuff) like having some sort of poor man's dynamic polymorphism.
struct fjtag_param_s {
struct pjtag_if_s *pjtag_if;
unsigned long base_addr;
unsigned long size;
int progindevery;
unsigned long progindrng;
void (*progind)(void *, unsigned long, const char *);
};
Its members serve the following purposes:
struct fjtag_if_s {
const char *name; /* flash device name */
int blocksz; /* block size in bytes.
0 = variable-size blocks */
int blocknr; /* number of blocks */
int *errnop; /* current error-code (like errno(3)) */
const char *(*strerror)(int);
/* returns err msg (like strerror(3)) */
void (*read_mode)(void); /* force the device to read-mode */
int (*read)(void *, unsigned long, unsigned long, void *);
/* read n bytes from flash to buffer */
int (*write)(const void *, unsigned long, unsigned long,
int, void *); /* write n bytes from buffer to flash */
int (*verify)(const void *, unsigned long, unsigned long,
void *); /* compare n bytes of flash to buffer */
int (*erase)(unsigned long, unsigned long,
void *); /* erase given address range */
int (*blockerase)(int, int, void *);
/* erase given block range */
};
Follows a description of the structure's members. As before using the
OOP terminology, I will call the non-callable members "attributes" and
the callable members "methods".
Porting to different host-systems, supporting other hardware
interfaces, and supporting additional target systems
Re-write the following functions in "jtag.c" so that they can
work on
your system and support your hardware interface:
int jtag_init (void *opts);
static inline void rstp (void);
static inline int putp(int tdi, int tms);
The functions "io_access_on()", "io_access_off()",
and "locate_port()" (all in "jtag.c"), which are
only called by "jtag_init()" may no longer be necessary, so
you might want to remove them also.
Licensing
"ianjtag tools" copyright (c) 2001 inAccess Networks
Download
The project's web-page is at the following URL:
http://www.inaccessnetworks.com/projects/ianjtag/
From there you can download the
latest version or any other
versions available. As of this writing the latest
version is 1.1.
Changelog
There is also a ChangeLog file for "ianjtag
tools" automatically generated from the CVS commit comments.
Additional information