
************************************************************************
** ianjtag tools v1.0: inAccess Networks's JTAG tools
** (c) inAccess Networks, 2001
** Writen by: Nick Patavalis (npat@inaccessnetworks.com)
**            Dimitris Economou (decon@inaccessnetworks.com)
** Homepage: http://projects.inaccessnetworks.com/ianjtag
** Distributed under the terms of the GPL
************************************************************************

'ianjtag tools' is a collection of code and a set of tools for using
the JTAG interface (present in most modern processors) to perform
hardware testing operations, and for programming Flash Memory Devices
connected to the processor's bus. It is especially usefull in embeded
systems development projects for performing initial system tests and
for bootstraping the prototype systems. Ianjtag tools run on a 'host
system' (e.g. a desktop computer with Linux) and access the 'target
system' (e.g. the embeded system's CPU board) through a simple 5-lines
hardware interface. In the present implementation the host's parallel
port can be used as the hardware interface, though other arangements
can very easily be supported. Operations like these are believed to be
very system-dependent, and, to our knowledge, there is no other free
tool available to address these needs. 'ianjtag' takes a modular
approach to the problem and, though it currently supports the Intel
StrongArm SA-1110 as a target processor, and the Intel StrataFlash ICs
as flash memory devices, it can easily be extented to support any
other target hardware configuration by writing simple modules that can
be incorporated to the infrastructure.

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 prort, modules dependent to the target-processor
architecure, and modules dependent to the flash memory device in
use. By separating these dependencies it is possible to support a
variety of host and taget 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 automatically detect, and adapt itself to operate with,
any of the supported target systems.

************************************************************************
* 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 itroduction to the JTAG 'theory of
operation' is also available online:

  http://projects.inaccessnetworks.com/ianjtag/jtag-white-paper.html

************************************************************************
* Source code files and modules:
************************************************************************

jtag.c
jtag.h
    Low level jtag module.

    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 arangement. The code
    that handles the JTAG state-machine has no hardware or O/S
    dependency.  The low-level jtag module exports a very simple
    interface that gives its users the ability to perform JTAG cycles
    easily.

---

pjtag.h
    Processor Support Module (PSM) interface definition.

    The processor support modules 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).

pjtag_sa1110.h
pjtag_sa1110.c
    Processor support module for Intel StrongARM SA-1110.

---

fjtag.h
    Flash Support Module (FSM) interface definition.

    The flash support modules 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 irespective to the
    system's processor architecture.
    

fjtag_isf2x16.h
fjtag_isf2x16.c
    Flash support module for the Intel StrataFlash in 2x16bit 
    configuration.

---

ianjflash.c 
    Tool (application and user interface code) for programming flash
    memory devices. Uses the flash support module interface to perform
    the actual device operations, so it can support any system there
    is a PSM and an FSM for.

---

Makefile
    Simple GNU-Make 'Makefile' for building the 'ianjtag tools'. 
    Customize it according to your system requirements.

---

************************************************************************
* 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's infrastructure, or if you plan to port ianjtag to
use a different hardware interface or to run under a different host
system.

************************************************************************

**** Low-level JTAG module (files: jtag.h, jtag.c).
  - Low-level hardware I/O interface code.
  - Low-level JTAG state-machine hadling code.

This module can be thought to consist of these two parts: The
low-level hardware I/O interface code, and the low-level JTAG
state-machine handling code.

** The low-level hardware I/O interface code (file: 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
parallel-port as the JTAG hardware interface. The JTAG interface
requires four signal lines (three outputs, and one input, as seen from
the host system).  These signals are connected to the parrallel 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, 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:

  Prototype:
    int jtag_init (void *opts);
  File:
    jtag.c, jtag.h
  Description:
    Initialize the host system's JTAG hardware I/O interface.
  Arguments:
    - opts - interface options which are dependent on the 
    interface type. NULL MUST work on the most common cases.
    In the present implementation 'opts' is a pointer to an
    array of (unsigned long) I/O address. These addresses will
    by tried-out in order as parralel prots until one succeeds.
  Returns:
    non-negative on success.
    negative on error.
  Notes:
    This function is exported by the low-level JTAG module, and
    called by the user to initalize the interface. Aclually it is
    the only function exported by the low-level hardware I/O code.

  ----------

  Prototype:
    static inline void rstp (void);
  File:
    jtag.c
  Description:
    Aply a reset pulse on the TRST, JTAG reset line.
  Notes:
    A reset pulse is generating by driving and holding the line
    down for a few mico-seconds and the driving it up again.
    Though this function is not typically exported (and therefore not
    called by the "user"), it is called by the low-level JTAG 
    state machine handling code.

  ----------

  Prototype:
    static inline int putp(int tdi, int tms);
  File:
    jtag.c
  Description:
    Drive the TDI and TMS JTAG input lines to the given levels, while
    pulsing the TCK line. Read the level of the TDO output line.
  Arguments:
    - tdi - 0 or 1. Level to drive the TDI line at.
    - tdo - 0 or 1. Level to drive the TMS line at.
  Returns:
    - int - 0 or 1. Level of the TDO JTAG output line.
  Notes:
    The sequence goes like this:
      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.

  ----------

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()".

** The low-level JTAG state-machine handling code (file: jtag.h
   jtag.c).

Other than calling the fuctions 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.

  Prototype:
    unsigned long jtag_fillword(unsigned char *input, 
                                int from, int len, int skip)
  File:
    jtag.c, jtag.h
  Description:
    Stuffs values from an unsigned-char array in an unsigned long 
    (word), interpeting each array element as a bit-value.
  Arguments:
    - input - unsigned char array. Each element must be either 
    1 or 0.
    - from - start stuffing from this array ellement
    - len - stuff this many elements
    - skip - stuff every 'skip' element. a negative skip will force
    the function to stuff backwards
  Returns:
    - unsigned long - the stuffed word.
  Notes:
    You can better understand this function by example:
      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

  ----------

  Prototype:
    void jtag_reset (void);
  Description:
    Reset the target system's JTAG machine, in the most low-level 
    (powerfull) way, e.g. by pulsing the TRST JTAG pin.

  ----------  

  Prototype:
    void jtag_test_logic_reset (void);
  Description:
    Bring the target system's JTAG state machine to the "test logic 
    reset" state.

  ----------

  Prototype:
    void jtag_run_test_idle (void);
  Description:
    Bring the target system's JTAG state machine to the "run test
    idle" state. On its way there tha stame machine will pass from 
    the "test logic reset" state, thus reseting the interface

  ----------  

  Prototype:
    void jtag_do_ir_path (register unsigned long iri,
                          register unsigned long *iro, 
                          register int irsz);
  Description:
    Perform an IR 'state path cycle', starting from the "run test
    idle" state and ending at the "run test idle" state. The following
    state-path is traversed: 
      *-> 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 writting a value to the JTAG
    Instruction Register, and thus issuing a JTAG command.
  Arguments:
    - iri - Intruction Register in. One bit from this (starting with 
    the LSB) will be shifted-in the JTAG Instruction Register every 
    time the 'shift ir' state is entered.
    - iro - Instruction Register out. Will be filled (LSB first) with 
    the bits shifted-out from the JTAG Instruction Register,  every 
    time the 'shift ir' state is left.
    - irsz - Instruction register size. the number of bits to shift in
    and out of the JTAG IR.
  Notes:
    Think of this operation as writting a value to the JTAG 
    Instruction Registed, while reading-back its pevious contents.
    In this sense 'iri' is the value to be written, 'iro' is the value
    previously held by the Instruction Register, and 'irsz' is the
    width of the Instruction Register in bits.

  ----------

  Prototype:
    void jtag_do_dr_path (register unsigned char *dri,
                          register unsigned char *dro, 
                          register int drsz);
  Description:
    Perform an DR 'state path cycle', starting from the "run test
    idle" state and ending at the "run test idle" state. The following
    state-path is traversed: 
      *-> 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 writting 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.
  Arguments:
    - dri - Data Register in. Every element must have a value of
    either 1 or 0. One element of this array (interpreted as a
    bit-value, and starting with the dri[0]) will be shifted-in 
    the JTAG Data Register every time the 'shift dr' state is entered.
    - dro - Data Register out. Each element (starting with dro[0])
    will be filled with the bit shifted-out from the JTAG Data Register, 
    every time the 'shift dr' state is left.
    - drsz - Data register size in bits. The number of bits to shift 
    in and out of the JTAG DR.
  Notes:
    Think of this operation as writting a value to the JTAG 
    Data Registed, while reading-back its pevious contents.
    In this sense 'dri' contains the value to be written, 'dro' is
    filled with the value previously held by the Data Register, 
    and 'drsz' is the width of the Data Register in bits.

  ----------

  Prototype:
    void jtag_do_ir_dr_path (register unsigned long iri, 
                             register unsigned long *iro, 
                             register int irsz,
                             register unsigned char *dri, 
                             register unsigned char *dro, 
                             register int drsz);
  Description:
    Perform an IR 'state path cycle', followed by a DR 'state path
    cycle' starting from the "run test idle" state and ending at the 
    "run test idle" state. The following state-path is traversed: 
      *-> 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 ->*
  Arguments:
    - iri - Intruction Register in. One bit from this (starting with 
    the LSB) will be shifted-in the JTAG Instruction Register every 
    time the 'shift ir' state is entered.
    - iro - Instruction Register out. Will be filled (LSB first) with 
    the bits shifted-out from the JTAG Instruction Register every 
    time the 'shift ir' state is left.
    - irsz - Instruction register size. The number of bits to shift in
    and out of the JTAG IR.
    - dri - Data Register in. Every element must have a value of
    either 1 or 0. One element of this array (interpreted as a
    bit-value, and starting with dri[0]) will be shifted-in the 
    JTAG Data Register every time the 'shift dr' state is entered.
    - dro - Data Register out. Each element (starting with dro[0])
    will be filled with the bit shifted-out from the JTAG Data Register 
    every time the 'shift dr' state is left.
    - drsz - Data register size in bits. The number of bits to shift 
    in and out of the JTAG DR.
  Notes:
    Think of this operation as a "jtag_do_ir_path()" imediatelly 
    followed by a "jtag_do_dr_path()"

  ----------

  Constants / Macros:
    JTAG_CMD_*
  Description:
    Macros (constants) defining the most common JTAG instructions. 
    These are the values that should be written to the JTAG
    Instruction Register (using "jtag_do_ir_path()") in order to have
    the target's JTAG module perform the respective operation.
  Specifics:
    JTAG_CMD_EXTEST - External Test instruction
    JTAG_CMD_SAMPLE - Sample/Preload instruction
    JTAG_CMD_CLAMP  - Clamp instruction
    JTAG_CMD_HIGHZ  - HighZ instruction
    JTAG_CMD_IDCODE - Read processor's ID code instruction
    JTAG_CMD_BYPASS - Bypass instruction

************************************************************************

**** Processor Support Module (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 insteface structure', a
pointer to which is supplied by the caller. Subsequent accesses to the
module's services are performed only through this interface stucture,
which has been initialized and contains variables, pointers to PSM
variables, and function pointers. This initialization function is
defined as follows:

  Prototype:
    int pjtag_xxx_init (struct pjtag_if_s *s);
  Description:
    Detects the processor by reading its JTAG ID code, and initializes 
    the processor support module. If the processor is not supported 
    the function returns something negative.
  Arguments:
    - s - this structured is filled-in by this function, and 
    subsequently serves as the access point to the services of 
    the PSM
  Returns:
    non-negative, if the processor was detected and mached and the
    module was initalized successfully; negative otherwise.
  Notes:
    PSM users are supposed to call the "pjtag_xxx_init()" functions for
    every available PSM one after the other, until a call returns 
    a non-negative value, which means that the processor has been 
    detected and can be supported. From there-on the 's' structure 
    can be used to access the services of the PSM regardless of 
    which PSM this is.

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:
    
    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 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.

The interface structure, which must be filled-in by every PSM init
function is defined in the file "pjtag.h", and goes like this:

  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 */

      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 */
};

Follows a description of the 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-stucture member with 0 (NULL).

  Attribute:
    const char *name;
  Descrption:
    Name-string of the detected processor

  ----------

  Attribute:
    int irsz;
  Descrption:
    Width (in bits) of the processor's JTAG IR register

  ----------

  Attribute:
    int idrsz;
  Descrption:
    Width (in bits) of the processor's JTAG ID register

  ----------

  Attribute:
    int bsrsz;
  Descrption:
    Width (in bits) of the processor's JTAG BSR register

  ----------

  Attribute:
    const char * const * bsr_names; 
  Description:
    Array of name-string, one for each BSR cell.
  Notes:
    bsr_names[10], contains (a pointer to) the name-string 
    of the tenth cell of the processor's BSR.

  ----------

  Attribute:
    const char * bsr_defaults; 
  Description:
    Array of safe default values, one for each BSR cell.
  Notes:
    bsr_defaults[10], contains a safe default value (either 1 or 0) 
    for the tenth cell of the processor's BSR.

  ----------

  Attribute:
    int addrbus_width;
  Descrption:
    Width (in bits) of the processor's address bus

  ----------

  Attribute:
    int databus_width;
  Descrption:
    Width (in bits) of the processor's data bus

  ----------

  Attribute:
    int *bsr_databus_in;
  Descrption:
    Array containing the BSR input-cell numbers coresponding to 
    each of the processor's databus lines.
  Notes:
    bsr_databus_in[10] contains the BSR input-cell number for the
    tenth data-bus line (starting form 0), i.e. for D10. Since the
    databus is allways bidirectional, there are two BSR cells 
    corresponding to each databus line; one input cell and one output
    cell

  ----------

  Attribute:
    int *bsr_databus_out;
  Descrption:
    Array containing the BSR ouput-cell numbers coresponding to 
    each of the processor's databus lines.
  Notes:
    bsr_databus_out[10] contains the BSR output-cell number for the
    tenth data-bus line (starting form 0), i.e. for D10. Since the
    databus is allways bidirectional, there are two BSR cells 
    corresponding to each databus line; one input cell and one output
    cell

  ----------

  Attribute:
    int *bsr_addrbus;
  Descrption:
    Array containing the BSR cell numbers coresponding to each of 
    the processor's addressbus lines.
  Notes:
    bsr_addrbus[10] contains the BSR cell number for the
    tenth address-bus line (starting form 0), i.e. for A10.

  ----------

  Method:
    void set_pins (unsigned char *dri, unsigned char *dro);
  Description:
    Sets all the processor's pins (i.e. BSR cells) to the given
    states and 'returns' the previous pin states.
  Arguments:
    - dri - input argument. Each element of this array contains the
    state of the respective BSR cell (either 1 or 0), and therefore 
    the pin-state to be set
    - dro - output argument. Each element of this array will be filled
    with the state (either 1 or 0) the repective BSR cell had, before
    setting the new pin states
  Notes:
    'dri' must contain 'bsrsz' (see attributes above) elements, and
    the 'dro' array must be long enough to keep 'bsrsz' elements

  ----------

  Method:
    void flw32 (unsigned long address, unsigned long data);
  Description:
    Perform a 32bit-wide write-cycle on the give address, with the
    the given data. The cycle will be good for non-brush-write flash 
    devices.
  Arguments:
    - address - address to perform the write on
    - data - data to be written
  Notes:
    The least significan byte of data will be written on the 'address'
    byte, while the most significant byte will be written on the
    'address+3' byte (i.e. little-endian arrangement), regardless of 
    the underline hardware (i.e. if the hardware is big-endian, this
    function must perform the conversion itself)

  ----------

  Method:
    void flw32n (unsigned long *address, unsigned long *data, 
                 unsigned long len);
  Description:
    Perform a 'len' 32bit-wide write-cycles on the give addresses, 
    with the the given data. The cycles will be good for 
    non-brush-write flash devices. data[0] will be written on
    address[0], and data[len-1] will be written on address[len-1]
  Arguments:
    - address - array of addresses to perform the writes on
    - data - array of data to be written
  Notes:
    The least significan byte of data[n] will be written on the 
    'address[n]' byte, while the most significant byte will be written 
    on the 'address[n]+3' byte (i.e. little-endian arrangement), 
    regardless of the underline hardware (i.e. if the hardware is 
    big-endian, this function must perform the conversion itself)

  ----------

  Method:
    void flr32 (unsigned long address, unsigned long *data);
  Description:
    Perform a 32bit-wide read-cycle on the give address. The cycle 
    will be good for non-brush-read flash devices.
  Arguments:
    - address - address to perform the read from
    - data - data read will be stored here
  Notes:
    The contents of the 'address' byte will be stored in the least
    significant byte of 'data', while the contnents of the 'address+3' 
    byte will be stored in the most significant byte of 'data' (i.e. 
    little-endian arrangement), regardless of the underlying hardware 
    (i.e. if the hardware is big-endian, this function must perform 
    the conversion itself)

  ----------

  Method:
    void flr32n (unsigned long *address, unsigned long *data,
                 unsigned long len);
  Description:
    Perform 'len' 32bit-wide read-cycles on the give addresses. 
    The cycles will be good for non-brush-read flash devices. 
  Arguments:
    - address - addresses to perform the read from
    - data - data read will be stored here. Data read from 'address[0]'
    will be stored in 'data[0]', while data read from 'address[len -1]'
    will be stored in 'data[len - 1]'
  Notes:
    The contents of the 'address' byte will be stored in the least
    significant byte of 'data', while the contnents of the 'address+3' 
    byte will be stored in the most significant byte of 'data' (i.e. 
    little-endian arrangement), regardless of the underlying hardware 
    (i.e. if the hardware is big-endian, this function must perform 
    the conversion itself)

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
** usefull methods) in order to incorporate them in the next versions
** of the '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

************************************************************************

**** Flash Support Module (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 insteface structure', a pointer to
which is supplied by the caller. Subsequent accesses to the module's
services are performed only through this interface stucture, which has
been initialized and contains variables, pointers to FSM variables,
and function pointers. This initialization function is defined as
follows:

  Prototype:
    int fjtag_xxx_init (struct fjtag_if_s *s, struct fjtag_param_s *p);
  Description:
    Detects the flash-device in use by reading its ID code, and 
    initializes the flash support module. If the flash-device is 
    not supported the function returns something negative.
  Arguments:
    - s - this structured is filled-in by this function, and 
    subsequently serves as the access point to the services of 
    the FSM
    - p - this structure contain device specifications that cannot be
    determined by querying the device (e.g. memory size, or base
    address) and  parameters that affect the module's behavior.
  Returns:
    non-negative, if the flash-device was detected and mached and the
    module was initalized successfully; negative otherwise.
  Notes:
    FSM users are supposed to call the "fjtag_xxx_init()" functions for
    every available FSM one after the other, until a call returns 
    a non-negative value, which means that the flash-device has been 
    detected and can be supported. From there-on the 's' structure 
    can be used to access the services of the FSM regardless of 
    which FSM this is.

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 in order until one call succeeds like this:
    
    struct pjtag_if_s pjt;
    struct fjtag_if_s s;
    struct fjtag_param_s p;

    p.pjtag_if = pjt;    /* PSM allready 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 callback */

    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.

The parameter structure taken as argument by every FSM init function
is defined in "fjtag.h" like this:

  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:

  Member:
    struct pjtag_if_s *pjtag_if;
  Description:
    Pointer to the PSM interface structure.
  Notes:
    FSMs, obviously communicate with the flash-devices by calling
    PSM functions. So in order to initialize and use an FSM you have
    allready initialized a PSM.

  ----------

  Member:
    unsigned long base_addr;
  Description:
    Flash memory device base address

  ----------
 
  Member:
    size
  Description:
    Flash memory device size (capacity) in bytes. 
  Notes:
    If set to zero the FSM will try to figure it out by itself, 
    probably making some assumptions (like that you have only one 
    bank of ICs)

  ----------

  Member:
    int progindevery
  Description:
    Progress indicator callback will be called every this many
    seconds

  ----------  

  Member:
    int progindrng
  Description:
    Progress indication will run in the range form 0 to 'progindrng'

  ----------

  Member:
    void progind (void *arg, unsigned long p, const char *t);
  Description:
    Progress indicator callback. This function will be called every
    time a progress indication update must be performed (i.e. every
    'progindevery' seconds)
  Arguments:
    - arg - Given to the FSM methods as argument, and passed through 
    to progress indicator callback. Not interpreted or used by the 
    FSM
    - p - position. How far has the process progressed. Ranges form 0
    to 'progindrng' (see member above)
    - t - operation title. Some processes may perform more than one
    lengthy operations. These operations are progress-indicated
    independently. This argument allows the progress indicator
    callback to print a subtitle or something coresponding to 
    the current operation:
  Notes:
    It is guaranteed by the FSM that the progress indicator callback,
    will either not be called at all, or called at least twice: once 
    with p=0 and once with p='progindrng'.

The interface structure, which must be filled-in by every FSM init
function is defined in the file "pjtag.h", and goes like this:

  struct fjtag_if_s {
      const char *name;          /* flash device name */
      int blocksz;               /* block size in bytes. 
                                    0 = varible-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".

  Attribute:
    const char *name;
  Descrption:
    Name-string of the detected flash device

  ----------

  Attribute:
    int blocksz;
  Description:
    Size of the flash device's blocks in bytes
  Notes:
    If the device has variable-sized blocks, 'blocksz' reads as 0
    and a new method for reporting the block sizes is required. 
    If you write an FSM for such a device, please let me know 
    how you delt with this.

  ----------

  Attribute:
    int blocknr;
  Description:
    Number of blocks in the device

  ----------

  Attribute:
    int *errnop;
  Description:
    Pointer to the last error-code raised by the FSM, like errno(3)

  ----------

  Method:
    const char *strerror(int errnum);
  Description:
    Returns the error-string associated with an error code,
    like strerror(3)
  Arguments:
    - errnum - error-code to return the error-string of.
  Returns:
    - const char * - the error string associated with the error 
    code.

  ----------

  Method:
    void read_mode (void);
  Description:
    Force the device to read-mode, no matter what mode the device is
    currently in

  ----------

  Method:
    int read (void *buff, unsigned long addr, unsigned long len, 
              void *progindA);
  Description:
    Read 'len' bytes from the device, starting a address 'addr' and
    store them in 'buff'.
  Arguments:
    - buff - pointer to buffer to store the data read into
    - addr - address to start reading from
    - len - number of bytes to read
    - progindA - argument passed-through to the progress indicator
  Returns:
    On success return non-negative. On error return negative and
    sets the 'errno' variable (accessed through the 'errnop'
    attribute) accordingly

  ----------

  Method:
    int write (void *buff, unsigned long addr, unsigned long len, 
               int verify, void *progindA);
  Description:
    Write 'len' bytes to the device, starting a address 'addr'. The
    bytes to be written are taken from 'buff'.
  Arguments:
    - buff - pointer to the buffer where the bytes to be written 
    are stored
    - addr - address to start writting to
    - len - number of bytes to write
    - verify - if non-zero verification will also be performed while
    writting
    - progindA - argument passed-through to the progress indicator
  Returns:
    On success return non-negative. On error return negative and
    sets the 'errno' variable (accessed through the 'errnop'
    attribute) accordingly

  ----------

  Method:
    int verify (void *buff, unsigned long addr, unsigned long len, 
                void *progindA);
  Description:
    Verify (compare expecting to find equal) 'len' bytes read from 
    the device starting at address 'addr', against the contents of
    'buff'.
  Arguments:
    - buff - pointer to the buffer keeping the data to verify against
    - addr - address to start reading form
    - len - number of bytes to read and verify
    - progindA - argument passed-through to the progress indicator
  Returns:
    On success return non-negative. On error return negative and
    sets the 'errno' variable (accessed through the 'errnop'
    attribute) accordingly

  ----------

  Method:
    int erase (unsigned long addr, unsigned long len, void *progindA);
  Description:
    Erase 'len' bytes starting form 'addr'
  Arguments:
    - addr - address to start erasing from
    - len - number of bytes to erase
    - progindA - argument passed-through to the progress indicator
  Returns:
    On success return non-negative. On error return negative and
    sets the 'errno' variable (accessed through the 'errnop'
    attribute) accordingly

  ----------

  Method:
    int blockerase (int start, int nblocks, void *progindA);
  Description:
    Erase 'nblocks' blocks starting form block 'start'
  Arguments:
    - start - first block to erase (blocks are counted starting 
    form 0)
    - nblocks - number of blocsk to erase
    - progindA - argument passed-through to the progress indicator
  Returns:
    On success return non-negative. On error return negative and
    sets the 'errno' variable (accessed through the 'errnop'
    attribute) accordingly


************************************************************************
* Supporting a different host-system, hardware interface, or 
* 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);

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.

The FSMs have some minor dependencies on the Unix time(2) function,
for calling the progress indicators at propper intervals, and for
timing timeouts. You may need to address them also, which should
normaly 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: 
  
  - Write a new Processor Support Module. Start by copying the
    'pjtag_sa1110.c' and 'pjtag_sa1110.h' files and modify them to
    suit your needs. You processor support module must provide the
    interface defined in 'pjtag.h', as discussed above.

  - Write a new Flash Support Module. Start by copying the
    'fjtag_isf2x16.c' and 'fjtag_isf2x16.h' files and modify them to
    suit your needs. You flash support module must provide the
    interface defined in 'fjtag.h', as discussed above.

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 in the header of
this document.

Share and enjoy!

npat.

