[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [avr-gcc-list] r-engineering the JTAG-ICE protocol

From: J.C. Wren
Subject: RE: [avr-gcc-list] r-engineering the JTAG-ICE protocol
Date: Sat, 5 Oct 2002 16:59:24 -0400

        JTAG is pretty trivial.  I have written Linux based JTAG programming 
for the 386EX, Cygnal 80C51Fxxx family, and the Lattice MACH parts.

        That being said, while the TAP state machines are trivial, the trick is
knowing what the part wants for JTAG commands.  Intel, Cygnal and Lattice
document the majority of commands.  Cygnal in particular has some private
commands for debugging that they won't release, but since I was only
concerned about programming and ID'ing parts in a manufacturing environment,
this wasn't much of an issue.

        Speed comparisons:  My 386EX has 4MB FLASH of which 64K is initially
programmed with a small monitor.  The FLASH is programmed by generating bus
read and write cycles to it.  This means clocking in 201 bits to set the
address, data and control lines up.  The write strobe is generated to the
FLASH externally to speed up the process.

        To program a block looks like the code below (about half the code is
omitted for handling odd length data).  So to program each word, we have to
write an 0xAA to address 0x555, 0x55 to address 0x2AA, 0xA0 to address 0x555
(all this to unlock and enable writing), followed by writing the word to the
address we want to program.  You can see this involves lots of clocking.  A
minimum of 804 bits (closer to 850, really) to program one 16 bit word.

        To program 64K takes about 24 second to erase, and 370 seconds to 
Processor speed has some effect, but surprisingly little.  A 300Mhz IBM
laptop takes about 4 seconds longer than a 1.4Ghz Athlon.  Now, where a hge
speed difference came in was going from the on-motherboard parallel port on
the Athlon to a PCI card based parallel port.  The write line of the FLASH
is connected to the /STROBE line of the parallel port in during programming
(otherwise, we'd have to generate the -WR cycle in JTAG, which would add
another 402 bits, or about 30% more time).  The actual -WR duration only
needs to be 200ns.  The on-motherboard -STROBE duration is about 200us.  The
PCI card parallel port is about 50us.  I saved nearly 130 seconds of
programming time with the PCI card vs the on-motherboard parallel port.

        My thoughts:  Parallel is the way to go for speed.  Parallel sucks, tho.
Serial is much easier to work with, and although being deleted from "MS
retarded ideas 2000" laptops (yet they still leave a big honking 25 pin
connector for a parallel port.  Morons...), although could be getting scare.
However, transition from serial to USB is not to difficult with some of the
chips available from companies like FTDI.

        Programming speed will be directly determined by how long the JTAG
sequences are.  I haven't read the docs, but I can be pretty sure that since
the part doesn't have 133 pins, it won't be 201 bits long.  And perhaps like
the Cygnal, there may be some short-form programming instructions that don't
require as many bits to be setup.  Maybe something like 32 bits per byte to
be programmed, or even less if there's some sort of automatic address
incrementing available.  I'd be a little more surprised about that, since
JTAG features take die space, and most companies would rather allocate as
little as possible for functionality intended to be used one time (I mean,
would you really rather have more RAM, or more capable JTAG?  Especially if
you're using SPI to program?)

        These are just some random thoughts and experiences I've had doing JTAG
programming.  I've also designed I2C to JTAG devices for IBM servers.  Once
you get the manufacturers JTAG instruction set, it goes pretty fast.  Oh,
and TI has a GREAT little DOS based tool for understanding JTAG.  It lets
you play with the TAP state machine, and has 2 virtual devices you can
manipulate through JTAG.  It's a great way to get an introduction to it, if
you don't understand the other presentations, or you're intimidated by JTAG.
I don't have a URL, but it's not too hard to find on the site.


**   Code example.
int FLASH_AMD_ProgramBlock (unsigned int baseaddr, unsigned int addr,
unsigned char *data, int len)
   unsigned int oddLength = len & 0x01;

   for (len /= 2; len > 0; len--, addr++)
      unsigned int word;

      word  = *data++;
      word |= (*data++ << 8);

      i386_WriteCycle (baseaddr + 0x555, 0xaa);    // Cycle 1
      i386_WriteCycle (baseaddr + 0x2aa, 0x55);    // Cycle 2
      i386_WriteCycle (baseaddr + 0x555, 0xa0);    // Cycle 3
      i386_WriteCycle (addr, word);                // Cycle 4

      if (!gNoPoll && !FLASH_AMD_Poll (addr, word))
         printf ("Error programming at FLASH address %08x\n", addr);
         return (FALSE);
   return TRUE;

void i386_WriteCycle (unsigned int address, unsigned int data)
   PJTAGData P = PinState;

   i386_Set_Data (P, data);         // Output data on bus
   i386_Set_Address (P, address);   // Output address
   P [RD * 2 + 1]  = 1;             // RD#=High Data
   P [WR * 2 + 1]  = 0;             // WR#=Low Data
   JTAG_DR_Scan (P, LEN_BSR, 0);    // Clock it out
   JTAG_Strobe_WE ();               // Strobe the WE# line

void JTAG_DR_Scan (char *dat, int num_bits, int replace)
   int i;

   JTAG_TMS_Clk (1);
   JTAG_TMS_Clk (0);
   JTAG_TMS_Clk (0);

   for (i = 0; i < num_bits; i++, dat++)
      JTAG_TDI (*dat);           // shift DR, LSB-first

      if (replace)
         *dat = JTAG_TDO ();

      if (i == (num_bits - 1))
         JTAG_TMS (1);           // move to Exit1_DR state

      JTAG_StrobeTCK ();

   JTAG_TMS_Clk (1);
   JTAG_TMS_Clk (0);

static __inline void JTAG_TMS_Clk (int state)
   outb ((gLptData = (state ? (gLptData | IO_TMS) : (gLptData & ~IO_TMS))),
gPort + PA_TMS);
   outb (gLptData |=  IO_TCK, gPort + PA_TCK);
   outb (gLptData &= ~IO_TCK, gPort + PA_TCK);

static __inline void JTAG_StrobeTCK (void)
   outb (gLptData |=  IO_TCK, gPort + PA_TCK);
   outb (gLptData &= ~IO_TCK, gPort + PA_TCK);

void JTAG_Strobe_WE (void)
   outb (gLptCtrl | IO_STB, gPort + PA_STB);
   outb (gLptCtrl, gPort + PA_STB);

avr-gcc-list at http://avr1.org

reply via email to

[Prev in Thread] Current Thread [Next in Thread]